{"action":"created","comment":{"url":"https://api.github.com/repos/AltraMayor/gatekeeper/pulls/comments/90182420","pull_request_review_id":10703871,"id":90182420,"diff_hunk":"@@ -0,0 +1,463 @@\n+/*\n+ * Gatekeeper - DoS protection system.\n+ * Copyright (C) 2016 Digirati LTDA.\n+ *\n+ * This program is free software: you can redistribute it and/or modify\n+ * it under the terms of the GNU General Public License as published by\n+ * the Free Software Foundation, either version 3 of the License, or\n+ * (at your option) any later version.\n+ *\n+ * This program is distributed in the hope that it will be useful,\n+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\n+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n+ * GNU General Public License for more details.\n+ *\n+ * You should have received a copy of the GNU General Public License\n+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n+ */\n+\n+#include <stdbool.h>\n+\n+#include <rte_hash.h>\n+#include <rte_malloc.h>\n+\n+#include \"gatekeeper_net.h\"\n+#include \"cache.h\"\n+\n+enum lls_cache_op {\n+\t/* Add an entry to the cache. */\n+\tLLS_CACHE_ADD,\n+\t/* Increment the refcnt of a cache entry. */\n+\tLLS_CACHE_INC,\n+\t/* Decrement the refcnt of a cache entry. */\n+\tLLS_CACHE_DEC,\n+};\n+\n+struct lls_cache_req {\n+\t/* Entry to be stored. */\n+\tstruct lls_cache_entry *entry;\n+\n+\t/* Operation of this request. */\n+\tenum lls_cache_op      op;\n+\n+\t/*\n+\t * IP address for a new entry (or key for the hash).\n+\t *\n+\t * NOTE\n+\t *\tThis is a variable-length field.\n+\t */\n+\tconst void             *ip_key[0];\n+};\n+\n+#ifdef RTE_MACHINE_CPUFLAG_SSE4_2\n+#include <rte_hash_crc.h>\n+#define DEFAULT_HASH_FUNC       rte_hash_crc\n+#else\n+#include <rte_jhash.h>\n+#define DEFAULT_HASH_FUNC       rte_jhash\n+#endif\n+\n+/*\n+ * Number of entries that a LLS cache can hold.\n+ * This is also the number of entries stored in\n+ * a mempool, which performs best when the size\n+ * is a power of 2 minus 1.\n+ */\n+#define LLS_CACHE_ENTRIES\t\t1023\n+/*\n+ * Size of mempool cache for LLS cache entries.\n+ * This should be a divisor of LLS_CACHE_ENTRIES.\n+ */\n+#define LLS_ENTRIES_MP_CACHE_SIZE\t77\n+\n+/* XXX Sample parameters, need to be tested for better performance. */\n+#define LLS_CACHE_BURST_SIZE\t\t32\n+\n+void\n+lls_cache_dump(struct lls_cache *cache)\n+{\n+\tuint32_t iter = 0;\n+\tint32_t index;\n+\tconst void *ip_key;\n+\tvoid *data;\n+\n+\tif (cache == NULL) {\n+\t\tRTE_LOG(ERR, GATEKEEPER, \"lls: %s: %s cache not instantiated\\n\",\n+\t\t\t__func__, cache->name);\n+\t\treturn;\n+\t}\n+\n+\tRTE_LOG(INFO, GATEKEEPER, \"LLS cache (%s)\\n=====================\\n\",\n+\t\tcache->name);\n+\tindex = rte_hash_iterate(cache->hash, &ip_key, &data, &iter);\n+\twhile (index >= 0) {\n+\t\tcache->print_entry(cache, ip_key, cache->data[index]);\n+\t\tindex = rte_hash_iterate(cache->hash, &ip_key, &data, &iter);\n+\t}\n+}\n+\n+static void\n+__lls_cache_add(struct lls_cache *cache, const void *ip_key,\n+\tstruct lls_cache_entry *entry)\n+{\n+\tint32_t ret = rte_hash_add_key(cache->hash, ip_key);\n+\tif (ret == -EINVAL) {\n+\t\tRTE_LOG(ERR, HASH, \"Invalid params, %s entry not added\\n\",\n+\t\t\tcache->name);\n+\t\trte_mempool_put(cache->entry_pool, entry);\n+\t} else if (ret == -ENOSPC) {\n+\t\tRTE_LOG(ERR, HASH, \"No space in cache, %s entry not added\\n\",\n+\t\t\tcache->name);\n+\t\trte_mempool_put(cache->entry_pool, entry);\n+\t} else {\n+\t\t/*\n+\t\t * Replace any existing entry. Note that this cannot\n+\t\t * be a placeholder entry replacing another placeholder\n+\t\t * entry, because the new placeholder entry would have\n+\t\t * been recognized as not needed in __lls_cache_refcnt().\n+\t\t *\n+\t\t * Therefore, it's OK just to take the refcnt from any\n+\t\t * existing entry.\n+\t\t */\n+\t\tstruct lls_cache_entry *old_entry = cache->data[ret];\n+\t\tcache->data[ret] = entry;\n+\t\tif (old_entry != NULL) {\n+\t\t\tentry->refcnt = old_entry->refcnt;\n+\t\t\trte_mempool_put(cache->entry_pool, old_entry);\n+\t\t}\n+\t}\n+}\n+\n+static void\n+__lls_cache_del(struct lls_cache *cache, const void *ip_key)\n+{\n+\tint32_t ret = rte_hash_del_key(cache->hash, ip_key);\n+\tif (ret == -ENOENT)\n+\t\tRTE_LOG(ERR, HASH, \"No entry found, %s entry not deleted\\n\",\n+\t\t\tcache->name);\n+\telse if (ret == -EINVAL)\n+\t\tRTE_LOG(ERR, HASH, \"Invalid params, %s entry not deleted\\n\",\n+\t\t\tcache->name);\n+\telse {\n+\t\tif (cache->data[ret]->refcnt > 0) {\n+\t\t\tRTE_LOG(ERR, GATEKEEPER,\n+\t\t\t\t\"Positive interest, %s entry not deleted\\n\",\n+\t\t\t\tcache->name);\n+\t\t} else {\n+\t\t\trte_mempool_put(cache->entry_pool, cache->data[ret]);\n+\t\t\tcache->data[ret] = NULL;\n+\t\t}\n+\t}\n+}\n+\n+static void\n+__lls_cache_refcnt(struct lls_cache *cache, const void *ip_key,\n+\tstruct lls_cache_entry *entry, enum lls_cache_op op)\n+{\n+\tint ret = rte_hash_lookup(cache->hash, ip_key);\n+\tif (ret == -ENOENT) {\n+\t\tif (op == LLS_CACHE_INC) {\n+\t\t\t/* Add placeholder entry and try to resolve it. */\n+\t\t\t__lls_cache_add(cache, ip_key, entry);\n+\t\t\tcache->xmit_req(entry->port_id, ip_key, NULL);\n+\t\t\tret = 0;\n+\t\t} else\n+\t\t\tRTE_LOG(ERR, GATEKEEPER,\n+\t\t\t\t\"lls: no such entry in %s cache to decrement refcnt\\n\",\n+\t\t\t\tcache->name);\n+\t} else if (ret == -EINVAL) {\n+\t\trte_mempool_put(cache->entry_pool, entry);\n+\t\tRTE_LOG(ERR, GATEKEEPER,\n+\t\t\t\"lls: invalid parameters for %s cache in %s\\n\",\n+\t\t\tcache->name, __func__);\n+\t} else {\n+\t\t/* Placeholder entry was not needed. */\n+\t\trte_mempool_put(cache->entry_pool, entry);\n+\t\tif (op == LLS_CACHE_INC)\n+\t\t\tcache->data[ret]->refcnt++;\n+\t\telse\n+\t\t\tcache->data[ret]->refcnt--;\n+\t}\n+}\n+\n+unsigned int\n+lls_cache_writer(struct lls_cache *cache)\n+{\n+\tstruct lls_cache_req *reqs[LLS_CACHE_BURST_SIZE];\n+\tunsigned int count = mb_dequeue_burst(&cache->mb,\n+\t\t(void **)reqs, LLS_CACHE_BURST_SIZE);\n+\tunsigned int i;\n+\n+\tif (likely(count == 0))\n+\t\treturn 0;\n+\n+\tfor (i = 0; i < count; i++) {\n+\t\tswitch (reqs[i]->op) {\n+\t\tcase LLS_CACHE_ADD:\n+\t\t\t__lls_cache_add(cache, reqs[i]->ip_key,\n+\t\t\t\treqs[i]->entry);\n+\t\t\tbreak;\n+\t\tcase LLS_CACHE_INC:\n+\t\t\t/* FALLTHROUGH */\n+\t\tcase LLS_CACHE_DEC:\n+\t\t\t__lls_cache_refcnt(cache, reqs[i]->ip_key,\n+\t\t\t\treqs[i]->entry, reqs[i]->op);\n+\t\t\tbreak;\n+\t\tdefault:\n+\t\t\tRTE_LOG(ERR, GATEKEEPER,\n+\t\t\t\t\"lls: unrecognized %s cache opcode (%d)\\n\",\n+\t\t\t\tcache->name, reqs[i]->op);\n+\t\t\tbreak;\n+\t\t}\n+\t\tmb_free_entry(&cache->mb, reqs[i]);\n+\t}\n+\n+\tif (DEBUG_LLS_CACHE)\n+\t\tlls_cache_dump(cache);\n+\n+\treturn count;\n+}\n+\n+int\n+lls_cache_get(struct lls_cache *cache, const void *ip_key,\n+\tstruct ether_addr *eth_addr)\n+{\n+\tint ret;\n+\n+\tif (cache == NULL) {\n+\t\tRTE_LOG(ERR, GATEKEEPER, \"lls: %s: %s cache not instantiated\\n\",\n+\t\t\t__func__, cache->name);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tret = rte_hash_lookup(cache->hash, ip_key);\n+\tif (ret == -ENOENT) {\n+\t\tRTE_LOG(ERR, GATEKEEPER,\n+\t\t\t\"lls: %s: cannot find entry in %s cache\\n\",\n+\t\t\t__func__, cache->name);\n+\t} else if (ret == -EINVAL) {\n+\t\tRTE_LOG(ERR, GATEKEEPER,\n+\t\t\t\"lls: %s: invalid params to lookup entry in %s cache\\n\",\n+\t\t\t__func__, cache->name);\n+\t} else {\n+\t\tstruct lls_cache_entry *lls_entry = cache->data[ret];\n+\t\t/* A block has expressed interest, but no resolution exists. */\n+\t\tif (!lls_entry->valid)\n+\t\t\treturn -ENOENT;\n+\t\tether_addr_copy(&lls_entry->ha, eth_addr);\n+\t\tret = 0;\n+\t}\n+\treturn ret;\n+}\n+\n+int\n+lls_cache_refcnt(struct lls_cache *cache, const void *ip_key, uint8_t port_id,\n+\tint inc_refcnt)\n+{\n+\tstruct lls_cache_entry *lls_entry;\n+\tstruct lls_cache_req *req;\n+\tint ret;\n+\n+\tif (cache == NULL) {\n+\t\tRTE_LOG(ERR, GATEKEEPER, \"lls: %s: %s cache not instantiated\\n\",\n+\t\t\t__func__, cache->name);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\treq = mb_alloc_entry(&cache->mb);\n+\tif (req == NULL) {\n+\t\treturn -1;\n+\t}\n+\n+\t/* Allocate entry in case this is a new entry. */\n+\tret = rte_mempool_get(cache->entry_pool, (void **)&lls_entry);\n+\tif (ret == -ENOENT) {\n+\t\tmb_free_entry(&cache->mb, req);\n+\t\tRTE_LOG(ERR, MEMPOOL,\n+\t\t\t\"No memory for new entry, %s entry not added\\n\",\n+\t\t\tcache->name);\n+\t\treturn ret;\n+\t}\n+\n+\t/*\n+\t * If no existing entry is found, this one will be used as\n+\t * a placeholder that's waiting for resolution. Otherwise,\n+\t * this will eventually be discarded.\n+\t */\n+\tlls_entry->ts = time(NULL);\n+\tlls_entry->port_id = port_id;\n+\tlls_entry->stale = false;\n+\tlls_entry->valid = false;\n+\tlls_entry->refcnt = 1;\n+\n+\treq->entry = lls_entry;\n+\treq->op = inc_refcnt ? LLS_CACHE_INC : LLS_CACHE_DEC;\n+\tmemcpy(req->ip_key, ip_key, cache->key_len);\n+\treturn mb_send_entry(&cache->mb, req);\n+}\n+\n+int\n+lls_cache_add(struct lls_cache *cache, const void *ip_key,\n+\tconst struct ether_addr *ha, uint8_t port_id)\n+{\n+\tstruct lls_cache_entry *lls_entry;\n+\tstruct lls_cache_req *req;\n+\tint ret;\n+\n+\tif (cache == NULL) {\n+\t\tRTE_LOG(ERR, GATEKEEPER, \"lls: %s: %s cache not instantiated\\n\",\n+\t\t\t__func__, cache->name);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\treq = mb_alloc_entry(&cache->mb);\n+\tif (req == NULL) {","path":"lls/cache.c","position":null,"original_position":314,"commit_id":"2f3c56d0249da22eb0a138bf8ef20ff37dd6fcb2","original_commit_id":"1db68d04c62be7dba6a57622ba37edb0c4b1306d","user":{"login":"cjdoucette","id":1501593,"avatar_url":"https://avatars.githubusercontent.com/u/1501593?v=3","gravatar_id":"","url":"https://api.github.com/users/cjdoucette","html_url":"https://github.com/cjdoucette","followers_url":"https://api.github.com/users/cjdoucette/followers","following_url":"https://api.github.com/users/cjdoucette/following{/other_user}","gists_url":"https://api.github.com/users/cjdoucette/gists{/gist_id}","starred_url":"https://api.github.com/users/cjdoucette/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/cjdoucette/subscriptions","organizations_url":"https://api.github.com/users/cjdoucette/orgs","repos_url":"https://api.github.com/users/cjdoucette/repos","events_url":"https://api.github.com/users/cjdoucette/events{/privacy}","received_events_url":"https://api.github.com/users/cjdoucette/received_events","type":"User","site_admin":false},"body":"Removed.","created_at":"2016-11-30T07:46:43Z","updated_at":"2016-11-30T07:46:43Z","html_url":"https://github.com/AltraMayor/gatekeeper/pull/10#discussion_r90182420","pull_request_url":"https://api.github.com/repos/AltraMayor/gatekeeper/pulls/10","_links":{"self":{"href":"https://api.github.com/repos/AltraMayor/gatekeeper/pulls/comments/90182420"},"html":{"href":"https://github.com/AltraMayor/gatekeeper/pull/10#discussion_r90182420"},"pull_request":{"href":"https://api.github.com/repos/AltraMayor/gatekeeper/pulls/10"}}},"pull_request":{"url":"https://api.github.com/repos/AltraMayor/gatekeeper/pulls/10","id":95641909,"html_url":"https://github.com/AltraMayor/gatekeeper/pull/10","diff_url":"https://github.com/AltraMayor/gatekeeper/pull/10.diff","patch_url":"https://github.com/AltraMayor/gatekeeper/pull/10.patch","issue_url":"https://api.github.com/repos/AltraMayor/gatekeeper/issues/10","number":10,"state":"open","locked":false,"title":"add LLS cache and ARP","user":{"login":"cjdoucette","id":1501593,"avatar_url":"https://avatars.githubusercontent.com/u/1501593?v=3","gravatar_id":"","url":"https://api.github.com/users/cjdoucette","html_url":"https://github.com/cjdoucette","followers_url":"https://api.github.com/users/cjdoucette/followers","following_url":"https://api.github.com/users/cjdoucette/following{/other_user}","gists_url":"https://api.github.com/users/cjdoucette/gists{/gist_id}","starred_url":"https://api.github.com/users/cjdoucette/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/cjdoucette/subscriptions","organizations_url":"https://api.github.com/users/cjdoucette/orgs","repos_url":"https://api.github.com/users/cjdoucette/repos","events_url":"https://api.github.com/users/cjdoucette/events{/privacy}","received_events_url":"https://api.github.com/users/cjdoucette/received_events","type":"User","site_admin":false},"body":"The patch **lls: add initialization and cache** creates the basic shape of the LLS block and creates a resolution cache. The patch **lls: add ARP processing and cache** instantiates one of those caches for ARP entries and adds the ability to send/receive ARP packets.","created_at":"2016-11-29T07:52:10Z","updated_at":"2016-11-30T07:46:43Z","closed_at":null,"merged_at":null,"merge_commit_sha":"df28b6354d013c0bc3d171661ed5941596c225ed","assignee":null,"assignees":[],"milestone":null,"commits_url":"https://api.github.com/repos/AltraMayor/gatekeeper/pulls/10/commits","review_comments_url":"https://api.github.com/repos/AltraMayor/gatekeeper/pulls/10/comments","review_comment_url":"https://api.github.com/repos/AltraMayor/gatekeeper/pulls/comments{/number}","comments_url":"https://api.github.com/repos/AltraMayor/gatekeeper/issues/10/comments","statuses_url":"https://api.github.com/repos/AltraMayor/gatekeeper/statuses/2f3c56d0249da22eb0a138bf8ef20ff37dd6fcb2","head":{"label":"cjdoucette:arp","ref":"arp","sha":"2f3c56d0249da22eb0a138bf8ef20ff37dd6fcb2","user":{"login":"cjdoucette","id":1501593,"avatar_url":"https://avatars.githubusercontent.com/u/1501593?v=3","gravatar_id":"","url":"https://api.github.com/users/cjdoucette","html_url":"https://github.com/cjdoucette","followers_url":"https://api.github.com/users/cjdoucette/followers","following_url":"https://api.github.com/users/cjdoucette/following{/other_user}","gists_url":"https://api.github.com/users/cjdoucette/gists{/gist_id}","starred_url":"https://api.github.com/users/cjdoucette/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/cjdoucette/subscriptions","organizations_url":"https://api.github.com/users/cjdoucette/orgs","repos_url":"https://api.github.com/users/cjdoucette/repos","events_url":"https://api.github.com/users/cjdoucette/events{/privacy}","received_events_url":"https://api.github.com/users/cjdoucette/received_events","type":"User","site_admin":false},"repo":{"id":66696649,"name":"gatekeeper","full_name":"cjdoucette/gatekeeper","owner":{"login":"cjdoucette","id":1501593,"avatar_url":"https://avatars.githubusercontent.com/u/1501593?v=3","gravatar_id":"","url":"https://api.github.com/users/cjdoucette","html_url":"https://github.com/cjdoucette","followers_url":"https://api.github.com/users/cjdoucette/followers","following_url":"https://api.github.com/users/cjdoucette/following{/other_user}","gists_url":"https://api.github.com/users/cjdoucette/gists{/gist_id}","starred_url":"https://api.github.com/users/cjdoucette/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/cjdoucette/subscriptions","organizations_url":"https://api.github.com/users/cjdoucette/orgs","repos_url":"https://api.github.com/users/cjdoucette/repos","events_url":"https://api.github.com/users/cjdoucette/events{/privacy}","received_events_url":"https://api.github.com/users/cjdoucette/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/cjdoucette/gatekeeper","description":"First open source DoS protection system","fork":true,"url":"https://api.github.com/repos/cjdoucette/gatekeeper","forks_url":"https://api.github.com/repos/cjdoucette/gatekeeper/forks","keys_url":"https://api.github.com/repos/cjdoucette/gatekeeper/keys{/key_id}","collaborators_url":"https://api.github.com/repos/cjdoucette/gatekeeper/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/cjdoucette/gatekeeper/teams","hooks_url":"https://api.github.com/repos/cjdoucette/gatekeeper/hooks","issue_events_url":"https://api.github.com/repos/cjdoucette/gatekeeper/issues/events{/number}","events_url":"https://api.github.com/repos/cjdoucette/gatekeeper/events","assignees_url":"https://api.github.com/repos/cjdoucette/gatekeeper/assignees{/user}","branches_url":"https://api.github.com/repos/cjdoucette/gatekeeper/branches{/branch}","tags_url":"https://api.github.com/repos/cjdoucette/gatekeeper/tags","blobs_url":"https://api.github.com/repos/cjdoucette/gatekeeper/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/cjdoucette/gatekeeper/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/cjdoucette/gatekeeper/git/refs{/sha}","trees_url":"https://api.github.com/repos/cjdoucette/gatekeeper/git/trees{/sha}","statuses_url":"https://api.github.com/repos/cjdoucette/gatekeeper/statuses/{sha}","languages_url":"https://api.github.com/repos/cjdoucette/gatekeeper/languages","stargazers_url":"https://api.github.com/repos/cjdoucette/gatekeeper/stargazers","contributors_url":"https://api.github.com/repos/cjdoucette/gatekeeper/contributors","subscribers_url":"https://api.github.com/repos/cjdoucette/gatekeeper/subscribers","subscription_url":"https://api.github.com/repos/cjdoucette/gatekeeper/subscription","commits_url":"https://api.github.com/repos/cjdoucette/gatekeeper/commits{/sha}","git_commits_url":"https://api.github.com/repos/cjdoucette/gatekeeper/git/commits{/sha}","comments_url":"https://api.github.com/repos/cjdoucette/gatekeeper/comments{/number}","issue_comment_url":"https://api.github.com/repos/cjdoucette/gatekeeper/issues/comments{/number}","contents_url":"https://api.github.com/repos/cjdoucette/gatekeeper/contents/{+path}","compare_url":"https://api.github.com/repos/cjdoucette/gatekeeper/compare/{base}...{head}","merges_url":"https://api.github.com/repos/cjdoucette/gatekeeper/merges","archive_url":"https://api.github.com/repos/cjdoucette/gatekeeper/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/cjdoucette/gatekeeper/downloads","issues_url":"https://api.github.com/repos/cjdoucette/gatekeeper/issues{/number}","pulls_url":"https://api.github.com/repos/cjdoucette/gatekeeper/pulls{/number}","milestones_url":"https://api.github.com/repos/cjdoucette/gatekeeper/milestones{/number}","notifications_url":"https://api.github.com/repos/cjdoucette/gatekeeper/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/cjdoucette/gatekeeper/labels{/name}","releases_url":"https://api.github.com/repos/cjdoucette/gatekeeper/releases{/id}","deployments_url":"https://api.github.com/repos/cjdoucette/gatekeeper/deployments","created_at":"2016-08-27T04:52:32Z","updated_at":"2016-08-30T05:50:38Z","pushed_at":"2016-11-30T07:33:37Z","git_url":"git://github.com/cjdoucette/gatekeeper.git","ssh_url":"git@github.com:cjdoucette/gatekeeper.git","clone_url":"https://github.com/cjdoucette/gatekeeper.git","svn_url":"https://github.com/cjdoucette/gatekeeper","homepage":"","size":192,"stargazers_count":0,"watchers_count":0,"language":"C","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"AltraMayor:master","ref":"master","sha":"9fe2e90083773dc550855cc7e061816dbd59cbd7","user":{"login":"AltraMayor","id":727014,"avatar_url":"https://avatars.githubusercontent.com/u/727014?v=3","gravatar_id":"","url":"https://api.github.com/users/AltraMayor","html_url":"https://github.com/AltraMayor","followers_url":"https://api.github.com/users/AltraMayor/followers","following_url":"https://api.github.com/users/AltraMayor/following{/other_user}","gists_url":"https://api.github.com/users/AltraMayor/gists{/gist_id}","starred_url":"https://api.github.com/users/AltraMayor/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/AltraMayor/subscriptions","organizations_url":"https://api.github.com/users/AltraMayor/orgs","repos_url":"https://api.github.com/users/AltraMayor/repos","events_url":"https://api.github.com/users/AltraMayor/events{/privacy}","received_events_url":"https://api.github.com/users/AltraMayor/received_events","type":"User","site_admin":false},"repo":{"id":62745741,"name":"gatekeeper","full_name":"AltraMayor/gatekeeper","owner":{"login":"AltraMayor","id":727014,"avatar_url":"https://avatars.githubusercontent.com/u/727014?v=3","gravatar_id":"","url":"https://api.github.com/users/AltraMayor","html_url":"https://github.com/AltraMayor","followers_url":"https://api.github.com/users/AltraMayor/followers","following_url":"https://api.github.com/users/AltraMayor/following{/other_user}","gists_url":"https://api.github.com/users/AltraMayor/gists{/gist_id}","starred_url":"https://api.github.com/users/AltraMayor/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/AltraMayor/subscriptions","organizations_url":"https://api.github.com/users/AltraMayor/orgs","repos_url":"https://api.github.com/users/AltraMayor/repos","events_url":"https://api.github.com/users/AltraMayor/events{/privacy}","received_events_url":"https://api.github.com/users/AltraMayor/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/AltraMayor/gatekeeper","description":"First open source DDoS protection system","fork":false,"url":"https://api.github.com/repos/AltraMayor/gatekeeper","forks_url":"https://api.github.com/repos/AltraMayor/gatekeeper/forks","keys_url":"https://api.github.com/repos/AltraMayor/gatekeeper/keys{/key_id}","collaborators_url":"https://api.github.com/repos/AltraMayor/gatekeeper/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/AltraMayor/gatekeeper/teams","hooks_url":"https://api.github.com/repos/AltraMayor/gatekeeper/hooks","issue_events_url":"https://api.github.com/repos/AltraMayor/gatekeeper/issues/events{/number}","events_url":"https://api.github.com/repos/AltraMayor/gatekeeper/events","assignees_url":"https://api.github.com/repos/AltraMayor/gatekeeper/assignees{/user}","branches_url":"https://api.github.com/repos/AltraMayor/gatekeeper/branches{/branch}","tags_url":"https://api.github.com/repos/AltraMayor/gatekeeper/tags","blobs_url":"https://api.github.com/repos/AltraMayor/gatekeeper/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/AltraMayor/gatekeeper/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/AltraMayor/gatekeeper/git/refs{/sha}","trees_url":"https://api.github.com/repos/AltraMayor/gatekeeper/git/trees{/sha}","statuses_url":"https://api.github.com/repos/AltraMayor/gatekeeper/statuses/{sha}","languages_url":"https://api.github.com/repos/AltraMayor/gatekeeper/languages","stargazers_url":"https://api.github.com/repos/AltraMayor/gatekeeper/stargazers","contributors_url":"https://api.github.com/repos/AltraMayor/gatekeeper/contributors","subscribers_url":"https://api.github.com/repos/AltraMayor/gatekeeper/subscribers","subscription_url":"https://api.github.com/repos/AltraMayor/gatekeeper/subscription","commits_url":"https://api.github.com/repos/AltraMayor/gatekeeper/commits{/sha}","git_commits_url":"https://api.github.com/repos/AltraMayor/gatekeeper/git/commits{/sha}","comments_url":"https://api.github.com/repos/AltraMayor/gatekeeper/comments{/number}","issue_comment_url":"https://api.github.com/repos/AltraMayor/gatekeeper/issues/comments{/number}","contents_url":"https://api.github.com/repos/AltraMayor/gatekeeper/contents/{+path}","compare_url":"https://api.github.com/repos/AltraMayor/gatekeeper/compare/{base}...{head}","merges_url":"https://api.github.com/repos/AltraMayor/gatekeeper/merges","archive_url":"https://api.github.com/repos/AltraMayor/gatekeeper/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/AltraMayor/gatekeeper/downloads","issues_url":"https://api.github.com/repos/AltraMayor/gatekeeper/issues{/number}","pulls_url":"https://api.github.com/repos/AltraMayor/gatekeeper/pulls{/number}","milestones_url":"https://api.github.com/repos/AltraMayor/gatekeeper/milestones{/number}","notifications_url":"https://api.github.com/repos/AltraMayor/gatekeeper/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/AltraMayor/gatekeeper/labels{/name}","releases_url":"https://api.github.com/repos/AltraMayor/gatekeeper/releases{/id}","deployments_url":"https://api.github.com/repos/AltraMayor/gatekeeper/deployments","created_at":"2016-07-06T18:53:45Z","updated_at":"2016-11-04T13:44:41Z","pushed_at":"2016-11-30T07:33:37Z","git_url":"git://github.com/AltraMayor/gatekeeper.git","ssh_url":"git@github.com:AltraMayor/gatekeeper.git","clone_url":"https://github.com/AltraMayor/gatekeeper.git","svn_url":"https://github.com/AltraMayor/gatekeeper","homepage":"","size":107,"stargazers_count":3,"watchers_count":3,"language":"C","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":3,"mirror_url":null,"open_issues_count":1,"forks":3,"open_issues":1,"watchers":3,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/AltraMayor/gatekeeper/pulls/10"},"html":{"href":"https://github.com/AltraMayor/gatekeeper/pull/10"},"issue":{"href":"https://api.github.com/repos/AltraMayor/gatekeeper/issues/10"},"comments":{"href":"https://api.github.com/repos/AltraMayor/gatekeeper/issues/10/comments"},"review_comments":{"href":"https://api.github.com/repos/AltraMayor/gatekeeper/pulls/10/comments"},"review_comment":{"href":"https://api.github.com/repos/AltraMayor/gatekeeper/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/AltraMayor/gatekeeper/pulls/10/commits"},"statuses":{"href":"https://api.github.com/repos/AltraMayor/gatekeeper/statuses/2f3c56d0249da22eb0a138bf8ef20ff37dd6fcb2"}}}}
{"actor":{"display_login":"cjdoucette"}}