static int geo_parse_cidr(geo_t *g, char *cidr, char *value) { struct in_addr in; int i; uint32_t addr; uint32_t mask; uint32_t ip_addr; uint32_t old; if (strcmp(cidr, "default") == 0) { if (inet_aton(value, &in) == 0) { return -1; } ip_addr = ntohl(in.s_addr); addr = 0; mask = 0; } else if (strcmp(cidr, "delete") == 0) { if (parse_cidr(value, &addr, &mask) != 0) { return -1; } if (radix32tree_delete(g->u.tree, addr, mask) != 0) { return -1; } return 0; } if (parse_cidr(cidr, &addr, &mask) != 0) { return -1; } if (inet_aton(value, &in) == 0) { return -1; } ip_addr = ntohl(in.s_addr); /* Retry 3 times */ for (i = 3; i; --i) { if (radix32tree_insert(g->u.tree, addr, mask, ip_addr) == 0) { return 0; } old = radix32tree_find(g->u.tree, addr & mask); /* TODO log */ if (radix32tree_delete(g->u.tree, addr, mask) != 0) { return -1; } } return -1; }
uint32_t geo_get(geo_t *g, uint32_t ip) { uint32_t ret = INVALID_IP_ADDR; if (g->geo_mode == GEO_RANGE) { return range_get(g->u.range, ip); } else if (g->geo_mode == GEO_CIDR) { if ((ret = radix32tree_find(g->u.tree, ip)) == RADIX_NO_VALUE) { return INVALID_IP_ADDR; } return ret; } else { assert(0); } return ret; }
void rspamd_radix_test_func (void) { #if 0 radix_tree_t *tree = radix_tree_create (); #endif radix_compressed_t *comp_tree = radix_create_compressed (); struct { guint32 addr; guint32 mask; guint8 addr6[16]; guint32 mask6; } *addrs; gsize nelts, i; gint lc; gboolean all_good = TRUE; gdouble ts1, ts2; double diff; /* Test suite for the compressed trie */ rspamd_radix_text_vec (); nelts = max_elts; /* First of all we generate many elements and push them to the array */ addrs = g_malloc (nelts * sizeof (addrs[0])); for (i = 0; i < nelts; i ++) { addrs[i].addr = ottery_rand_uint32 (); addrs[i].mask = masks[ottery_rand_range(G_N_ELEMENTS (masks) - 1)]; ottery_rand_bytes (addrs[i].addr6, sizeof(addrs[i].addr6)); addrs[i].mask6 = ottery_rand_range(128); } #if 0 msg_info ("old radix performance (%z elts)", nelts); ts1 = rspamd_get_ticks (); for (i = 0; i < nelts; i ++) { guint32 mask = G_MAXUINT32 << (32 - addrs[i].mask); radix32tree_insert (tree, addrs[i].addr, mask, 1); } ts2 = rspamd_get_ticks (); diff = (ts2 - ts1) * 1000.0; msg_info ("Added %z elements in %.6f ms", nelts, diff); ts1 = rspamd_get_ticks (); for (lc = 0; lc < lookup_cycles; lc ++) { for (i = 0; i < nelts; i ++) { g_assert (radix32tree_find (tree, addrs[i].addr) != RADIX_NO_VALUE); } } ts2 = rspamd_get_ticks (); diff = (ts2 - ts1) * 1000.0; msg_info ("Checked %z elements in %.6f ms", nelts, diff); ts1 = rspamd_get_ticks (); for (i = 0; i < nelts; i ++) { radix32tree_delete (tree, addrs[i].addr, addrs[i].mask); } ts2 = rspamd_get_ticks (); diff = (ts2 - ts1) * 1000.; msg_info ("Deleted %z elements in %.6f ms", nelts, diff); radix_tree_free (tree); #endif msg_info ("new radix performance (%z elts)", nelts); ts1 = rspamd_get_ticks (); for (i = 0; i < nelts; i ++) { radix_insert_compressed (comp_tree, addrs[i].addr6, sizeof (addrs[i].addr6), 128 - addrs[i].mask6, i); } ts2 = rspamd_get_ticks (); diff = (ts2 - ts1) * 1000.0; msg_info ("Added %z elements in %.6f ms", nelts, diff); ts1 = rspamd_get_ticks (); for (lc = 0; lc < lookup_cycles; lc ++) { for (i = 0; i < nelts; i ++) { if (radix_find_compressed (comp_tree, addrs[i].addr6, sizeof (addrs[i].addr6)) == RADIX_NO_VALUE) { all_good = FALSE; } } } #if 1 if (!all_good) { for (i = 0; i < nelts; i ++) { /* Used to write bad random vector */ char ipbuf[INET6_ADDRSTRLEN + 1]; inet_ntop(AF_INET6, addrs[i].addr6, ipbuf, sizeof(ipbuf)); msg_info("{\"%s\", NULL, \"%ud\", 0, 0, 0, 0},", ipbuf, addrs[i].mask6); } } #endif g_assert (all_good); ts2 = rspamd_get_ticks (); diff = (ts2 - ts1) * 1000.0; msg_info ("Checked %z elements in %.6f ms", nelts, diff); radix_destroy_compressed (comp_tree); g_free (addrs); }