diff --git a/radix/radix.c b/radix/radix.c index 2f30653..1c93fbc 100644 --- a/radix/radix.c +++ b/radix/radix.c @@ -1,32 +1,35 @@ #include "radix.h" -#define GET_BIT(key, bit) ( ( key.s[ bit / 16 ] & (1u << (15 - bit % 16)) ) != 0 ) +#define GET_BIT(key, mask) ( ((key[0] & mask[0]) | (key[1] & mask[1])) != 0 ) +#define SHIFT_MASK(mask) mask[0] >>= 1, mask[1] = (mask[1] >> 1) || !(mask[0]) -radix_node_t create_node(ipv6_t key, unsigned end_bit, unsigned rule) { - radix_node_t ret = calloc(1, sizeof(struct radix_node)); - ret->_ip = key; - ret->_ip_end_bit = end_bit; - ret->_rule_valid = VALID_RULE; - ret->_rule = rule; +int radix_insert(radix_holder_t, record_t); +int radix_search(radix_holder_t, record_t); + +radix_holder_t create_holder() { + radix_holder_t ret = calloc(1, sizeof(struct radix_holder)); + return ret; +} + +radix_node_t create_node(record_t record) { + radix_node_t ret = malloc(sizeof(struct radix_node)); + record->_valid = VALID_RULE; + memcpy(&ret->_data, record, sizeof(struct routing_record)); + ret->_l = ret->_r = NULL; return ret; } static radix_node_t clone_node(radix_node_t n) { - radix_node_t ret = calloc(1, sizeof(struct radix_node)); + radix_node_t ret = malloc(sizeof(struct radix_node)); memcpy(ret, n, sizeof(struct radix_node)); return ret; } static void split_node(radix_node_t n, unsigned bit) { radix_node_t tmp = clone_node(n); - n->_ip_end_bit = bit; + n->_data._mask = bit; n->_l = n->_r = tmp; - n->_rule_valid = INVALID_RULE; -} - -radix_holder_t create_holder() { - radix_holder_t ret = calloc(1, sizeof(struct radix_holder)); - return ret; + n->_data._valid = INVALID_RULE; } int destory_holder(struct radix_holder* t) { @@ -43,74 +46,79 @@ int destory_node(struct radix_node* n) { return ret; } -int radix_insert(radix_holder_t t, ipv6_t key, int val, int mask) { +int radix_insert(radix_holder_t t, record_t /*restrict*/ r) { unsigned char b; - int ibit; + unsigned char ibit = 0; + unsigned long mask[2] = {0x01ul << 63, 0x00}; radix_node_t node = t->_root; radix_node_t* next = &t->_root; - if (!t->_root) { - t->_root = create_node(key, mask, val); + r->_valid = INVALID_RULE; + + if (!node) { + t->_root = create_node(r); return t->_size = 1; } - - for (ibit = 0; ibit < mask; ++ibit) { - b = GET_BIT(key, ibit); - if (ibit >= node->_ip_end_bit) { /* node key ends */ + /*todo zkontrolovat mezni hodnoty, masku 128 a tak.. */ + for (ibit = 0; ibit < r->_mask; ++ibit, SHIFT_MASK(mask)) { + b = GET_BIT(r->_ip, mask); + if (ibit == node->_data._mask) { /* node ends */ next = b ? &node->_l : &node->_r; - if (!*next) { - *next = create_node(key, mask, val); + if (!*next) { /* add child */ + *next = create_node(r); + ++t->_size; return 1; } - + node = *next; continue; } - if (b == GET_BIT(node->_ip, ibit)) /* bit match */ - continue; - - next = b ? &node->_l : &node->_r; - if (*next && ibit == mask - 1) { /* last bit mismatch */ - node = *next; - continue; - } - - split_node(node, ibit); /* split node */ - *next = create_node(key, mask, val); + if (b != GET_BIT(node->_data._ip, mask)) {/* bit differs -> split node */ + split_node(node, ibit); + next = b ? &node->_l : &node->_r; /* new node */ + *next = create_node(r); + + ++t->_size; + return 1; + } + } + + /* insert before */ + if (node->_data._mask > r->_mask) { + split_node(node, ibit); + b = GET_BIT(node->_data._ip, mask); + next = b ? &node->_r : &node->_l; + *next = NULL; + + r->_valid = VALID_RULE; + memcpy(&node->_data, r, sizeof(struct routing_record)); ++t->_size; return 1; } - + /* exact match */ - if (node->_rule_valid && node->_ip_end_bit == mask) { - 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; + if (node->_data._mask == r->_mask && ibit == r->_mask) { + if (node->_data._valid) + return 0; + /* make valid */ + node->_data._valid = VALID_RULE; + node->_data._rule = r->_rule; + ++t->_size; + return 1; } - /* match with lower mask */ - if (node->_rule_valid) { - split_node(node, ibit); - - b = GET_BIT(node->_ip, ibit + 1); - next = b ? &node->_r : &node->_l; - *next = NULL; - } - - node->_rule_valid = VALID_RULE; - node->_rule = val; - return 1; + + printf("!!!!!!!!!!!!!!\n"); + return 0; } -int radix_search(radix_holder_t t, ipv6_t key) { - unsigned char b; +int radix_search(radix_holder_t t, record_t r) { + int ret = INVALID_RULE; + /* radix_node_t iter = t->_root; int ibit = 0; if (!iter) @@ -123,13 +131,14 @@ int radix_search(radix_holder_t t, ipv6_t key) { b == GET_BIT(iter->_ip, ibit)) continue; - if (ibit == iter->_ip_end_bit) /* set result if full match */ + if (ibit == iter->_ip_end_bit) // set result if full match ret = iter->_rule_valid ? iter->_rule : ret; iter = b ? iter->_l : iter->_r; if (!iter) return ret; } + */ return ret; } @@ -139,30 +148,68 @@ int radix_search(radix_holder_t t, ipv6_t key) { /* TESTING */ /*--------------------------------------------------------------------------------*/ #include +#include #define RULES_FILE "../data/routing-data" #define TEST_FILE "../data/test-data" -#define TEST_ROWS 5527 +#define TEST_ROWS 0 /*66319*/ #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)); +int parse_line(FILE* f, record_t r) { + int ikey, jkey; + unsigned long key[2] = {0,0}; + struct in6_addr addr; + char ipv6_cidr[50]; + char *separator; - 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 (fgets(ipv6_cidr, sizeof(ipv6_cidr), f) == NULL) { + if (!feof(f)) + printf("error reading\n"); + return 0; + } - if (feof(f)) return 0; /* ends with newline */ - while (fgetc(f) != '/'); + ipv6_cidr[strcspn(ipv6_cidr, "\n")] = 0; + separator = strchr(ipv6_cidr, '/'); + if (!separator) { + printf("invalid CIDR notation\n"); + return 1; + } + + *separator++ = '\0'; + r->_mask = atoi(separator); - fscanf(f, "%d %d", mask, val); + separator = strchr(separator, ' '); + r->_rule = atoi(++separator); + + if (r->_mask < 0 || r->_mask > 128) { + printf("invalid prefix length\n"); + return 1; + } + + if (r->_rule < 0 || r->_rule > 65536) { + printf("invalid pop\n"); + return 1; + } + + if (inet_pton(AF_INET6, ipv6_cidr, &addr) != 1) { + printf("%s invalid address\n", ipv6_cidr); + return 0; + } + + for (ikey = 0; ikey < 2; ++ikey) { + for (jkey = 0; jkey < 8; ++jkey) { + key[ikey] = (key[ikey] << 8) | addr.__in6_u.__u6_addr8[jkey + (ikey * 8)]; + } + } + + r->_ip[0] = key[0]; + r->_ip[1] = key[1]; + r->_valid = VALID_RULE; return !feof(f); } int load_input(radix_holder_t t) { - int val; - int mask; - ipv6_t key; + struct routing_record r; FILE* f; int cnt = 0; @@ -171,68 +218,77 @@ int load_input(radix_holder_t t) { exit(1); } - while (parse_line(&key, &val, &mask, f)) { - cnt += radix_insert(t, key, val, mask); + while (parse_line(f, &r)) { + if (radix_insert(t, &r)) + ++cnt; + else + printf("WARNING: conflicting insert\n"); } fclose(f); return cnt; } -int load_tests(ipv6_t** rips, int** rref) { - ipv6_t* ips; +int load_tests(unsigned long** subnets, int** rref) { + /* + unsigned long* ips; int* ref; int row; FILE* f; - + struct routing_record r; + if (!(f = fopen( TEST_FILE, READ_MODE ))) { puts("cant open test file"); exit(1); } - ips = calloc( TEST_ROWS, sizeof(ipv6_t) ); + ips = calloc( TEST_ROWS, sizeof(unsigned long) ); 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])); + parse_line(f, &r); + ips[row] = r._ip; + ref[row] = r._rule; } fclose(f); - - *rips = ips; + + *subnets = ips; *rref = ref; + */ return TEST_ROWS; } -int fire_tests(radix_holder_t t, ipv6_t* ips, int* ref, int num_tests ) { +int fire_tests(radix_holder_t t, unsigned long* subnets, int* ref, int num_tests ) { + /* int row; int wrong = 0; - + struct routing_record r; + for (row = 0; row < TEST_ROWS; ++ row) { - if (radix_search(t, ips[row]) != ref[row]) { - printf("ref: %d got: %d @ %d\n", ref[row], radix_search(t, ips[row]), row ); + r._ip = subnets[row]; + r._ip = subnets[row+1]; + radix_search(t, &r); + if ( !r._valid || r._rule != ref[row]) { + printf("ref: %d got: %d @ %d\n", ref[row], r._rule, row ); ++wrong; } } - - free(ips); + + free(subnets); free(ref); return wrong; + */ + return 0; } int main() { - ipv6_t* ips; + unsigned long* subnets; int* ref; radix_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) ); + printf("Loaded %d tests\n", load_tests(&subnets, &ref) ); + printf("%d tests wrong\n", fire_tests(t, subnets, ref, TEST_ROWS) ); destory_holder(t); return 0;