#include "trie.h" #define RULE_NOT_FOUND -1 #define GET_BIT(key, bit) ( ( key.s[ bit / 16 ] & (1u << (15 - bit % 16)) ) != 0 ) trie_node_t create_node() { trie_node_t ret = calloc(1, sizeof(struct trie_node)); /* sets null childs and invalid */ return ret; } trie_holder_t create_holder() { trie_holder_t ret = malloc(sizeof(struct trie_holder)); ret->_size = 0; ret->_root = create_node(); return ret; } int destory_holder(struct trie_holder* t) { destory_node(t->_root); free(t); return 1; } int destory_node(struct trie_node* n) { int ret = 0; if (!n) return ret; ret = destory_node(n->_l) + destory_node(n->_r); free(n); return ret; } int trie_insert(trie_holder_t t, ipv6_t key, int val, int mask) { trie_node_t iter = t->_root; trie_node_t* next = &t->_root; int i; for (i = 0; i < mask; ++i) { if (!*(next = GET_BIT(key, i) ? &iter->_l : &iter->_r)) *next = create_node(); iter = *next; } if (iter->_rule_valid == VALID_RULE) { printf("WARNING: conflicting rule %x:%x:%x:%x:%x:%x:%x:%x", key.s[0], key.s[1], key.s[2], key.s[3], key.s[4], key.s[5], key.s[6], key.s[7]); printf("/%d %d\n", mask, val); return 0; } iter->_rule_valid = VALID_RULE; iter->_rule = val; return ++t->_size;; } int trie_search(trie_holder_t t, ipv6_t key) { trie_node_t iter = t->_root; trie_node_t next; int i = 0; int ret = RULE_NOT_FOUND; for (;i < 128; ++i) { if (iter->_rule_valid) ret = iter->_rule; if (!(next = GET_BIT(key, i) ? iter->_l : iter->_r)) break; iter = next; } return ret; } /*--------------------------------------------------------------------------------*/ /* TESTING */ /*--------------------------------------------------------------------------------*/ #include #define RULES_FILE "../data/routing-data" #define TEST_FILE "../data/test-data" #define TEST_ROWS 5721 #define READ_MODE "r" int parse_line(ipv6_t* key, int* val, int* mask, FILE* f) { /*! assumes only good input */ memset(key, 0, sizeof(ipv6_t)); fscanf(f, "%hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx", &key->s[0], &key->s[1], &key->s[2], &key->s[3], &key->s[4], &key->s[5], &key->s[6], &key->s[7]); if (feof(f)) return 0; /* ends with newline */ while (fgetc(f) != '/'); fscanf(f, "%d %d", mask, val); return !feof(f); } int load_input(trie_holder_t t) { int val; int mask; ipv6_t key; FILE* f; int cnt = 0; if (!(f = fopen(RULES_FILE, READ_MODE))) { puts("cant open input file"); exit(1); } while (parse_line(&key, &val, &mask, f)) { trie_insert(t, key, val, mask); ++cnt; } fclose(f); return cnt; } int load_tests(ipv6_t** rips, int** rref) { ipv6_t* ips; int* ref; int row; FILE* f; if (!(f = fopen( TEST_FILE, READ_MODE ))) { puts("cant open test file"); exit(1); } ips = calloc( TEST_ROWS, sizeof(ipv6_t) ); ref = calloc( TEST_ROWS, sizeof(int) ); for (row = 0; row < TEST_ROWS; ++ row) { fscanf(f, "%hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx", &ips[row].s[0], &ips[row].s[1], &ips[row].s[2], &ips[row].s[3], &ips[row].s[4], &ips[row].s[5], &ips[row].s[6], &ips[row].s[7]); while (fgetc(f) != ' '); fscanf(f, "%d", &(ref[row])); } fclose(f); *rips = ips; *rref = ref; return TEST_ROWS; } int fire_tests(trie_holder_t t, ipv6_t* ips, int* ref, int num_tests ) { int row; int wrong = 0; for (row = 0; row < TEST_ROWS; ++ row) { if (trie_search(t, ips[row]) != ref[row]) { printf("ref: %d got: %d @ %d\n", ref[row], trie_search(t, ips[row]), row ); ++wrong; } } free(ips); free(ref); return wrong; } int main() { ipv6_t* ips; int* ref; trie_holder_t t = create_holder(); printf("Loaded %d rules\n", load_input(t) ); printf("Loaded %d tests\n", load_tests(&ips, &ref) ); printf("%d tests wrong\n", fire_tests(t, ips, ref, TEST_ROWS) ); destory_holder(t); return 0; }