#include "radix.h" #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]) 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 = 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->_data._mask = bit; n->_l = n->_r = tmp; n->_data._valid = INVALID_RULE; } int destory_holder(struct radix_holder* t) { destory_node(t->_root); free(t); return 1; } int destory_node(struct radix_node* n) { int ret = 0; if (!n) return ret; ret = destory_node(n->_l) + destory_node(n->_r); free(n); return ret; } int radix_insert(radix_holder_t t, record_t /*restrict*/ r) { unsigned char b; unsigned char ibit = 0; unsigned long mask[2] = {0x01ul << 63, 0x00}; radix_node_t node = t->_root; radix_node_t* next = &t->_root; r->_valid = INVALID_RULE; if (!node) { t->_root = create_node(r); return t->_size = 1; } /*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) { /* add child */ *next = create_node(r); ++t->_size; return 1; } node = *next; continue; } 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->_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; } printf("!!!!!!!!!!!!!!\n"); return 0; } 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) return INVALID_RULE; for (;ibit < 128; ++ibit) { b = GET_BIT(key, ibit); if (ibit < iter->_ip_end_bit && b == GET_BIT(iter->_ip, ibit)) continue; 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; } /*--------------------------------------------------------------------------------*/ /* TESTING */ /*--------------------------------------------------------------------------------*/ #include #include #define RULES_FILE "../data/routing-data" #define TEST_FILE "../data/test-data" #define TEST_ROWS 0 /*66319*/ #define READ_MODE "r" 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; if (fgets(ipv6_cidr, sizeof(ipv6_cidr), f) == NULL) { if (!feof(f)) printf("error reading\n"); return 0; } 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); 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) { struct routing_record r; FILE* f; int cnt = 0; if (!(f = fopen(RULES_FILE, READ_MODE))) { puts("cant open input file"); exit(1); } while (parse_line(f, &r)) { if (radix_insert(t, &r)) ++cnt; else printf("WARNING: conflicting insert\n"); } fclose(f); return cnt; } 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(unsigned long) ); ref = calloc( TEST_ROWS, sizeof(int) ); for (row = 0; row < TEST_ROWS; ++ row) { parse_line(f, &r); ips[row] = r._ip; ref[row] = r._rule; } fclose(f); *subnets = ips; *rref = ref; */ return TEST_ROWS; } 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) { 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(subnets); free(ref); return wrong; */ return 0; } int main() { 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(&subnets, &ref) ); printf("%d tests wrong\n", fire_tests(t, subnets, ref, TEST_ROWS) ); destory_holder(t); return 0; }