You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

rspamd_radix_test.c 6.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  1. /*-
  2. * Copyright 2016 Vsevolod Stakhov
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #include "config.h"
  17. #include "rspamd.h"
  18. #include "radix.h"
  19. #include "ottery.h"
  20. const gsize max_elts = 50 * 1024;
  21. const gint lookup_cycles = 1 * 1024;
  22. const uint masks[] = {
  23. 8,
  24. 16,
  25. 24,
  26. 32,
  27. 27,
  28. 29,
  29. 19,
  30. 13,
  31. 22
  32. };
  33. struct _tv {
  34. const char *ip;
  35. const char *nip;
  36. const char *m;
  37. guint32 mask;
  38. guint8 *addr;
  39. guint8 *naddr;
  40. gsize len;
  41. } test_vec[] = {
  42. {"192.168.1.1", "192.168.1.2", "32", 0, 0, 0, 0},
  43. {"192.168.1.0", "192.168.2.1", "24", 0, 0, 0, 0},
  44. {"192.0.0.0", "193.167.2.1", "8", 0, 0, 0, 0},
  45. {"172.0.0.0", "171.16.1.0", "8", 0, 0, 0, 0},
  46. {"172.16.0.1", "127.0.0.1", "16", 0, 0, 0, 0},
  47. {"172.17.1.0", "10.0.0.1", "27", 0, 0, 0, 0},
  48. {"172.17.1.1", "0.0.0.1", "32", 0, 0, 0, 0},
  49. /* Some bad data known to cause problem in the past */
  50. {"191.245.170.246", NULL, "19", 0, 0, 0, 0},
  51. {"227.88.150.170", NULL, "23", 0, 0, 0, 0},
  52. {"105.225.182.92", NULL, "24", 0, 0, 0, 0},
  53. {"223.167.155.240", NULL, "29", 0, 0, 0, 0},
  54. {"125.241.220.172", NULL, "2", 0, 0, 0, 0},
  55. /* Mask = 0 */
  56. {"143.105.181.13", NULL, "8", 0, 0, 0, 0},
  57. {"113.241.233.86", NULL, "26", 0, 0, 0, 0},
  58. {"185.187.122.222", NULL, "8", 0, 0, 0, 0},
  59. {"109.206.26.202", NULL, "12", 0, 0, 0, 0},
  60. {"130.244.233.150", NULL, "0", 0, 0, 0, 0},
  61. /* Close ip addresses */
  62. {"1.2.3.1", NULL, "32", 0, 0, 0, 0},
  63. {"1.2.3.2", NULL, "32", 0, 0, 0, 0},
  64. {"1.2.3.3", NULL, "32", 0, 0, 0, 0},
  65. {"1.2.3.4", NULL, "32", 0, 0, 0, 0},
  66. {NULL, NULL, NULL, 0, 0, 0, 0}
  67. };
  68. static void
  69. rspamd_radix_text_vec (void)
  70. {
  71. radix_compressed_t *tree = radix_create_compressed ();
  72. struct _tv *t = &test_vec[0];
  73. struct in_addr ina;
  74. struct in6_addr in6a;
  75. gulong i, val;
  76. while (t->ip != NULL) {
  77. t->addr = g_malloc (sizeof (in6a));
  78. t->naddr = g_malloc (sizeof (in6a));
  79. if (inet_pton (AF_INET, t->ip, &ina) == 1) {
  80. memcpy (t->addr, &ina, sizeof (ina));
  81. t->len = sizeof (ina);
  82. }
  83. else if (inet_pton (AF_INET6, t->ip, &in6a) == 1) {
  84. memcpy (t->addr, &in6a, sizeof (in6a));
  85. t->len = sizeof (in6a);
  86. }
  87. else {
  88. g_assert (0);
  89. }
  90. if (t->nip) {
  91. if (inet_pton (AF_INET, t->nip, &ina) == 1) {
  92. memcpy (t->naddr, &ina, sizeof (ina));
  93. }
  94. else if (inet_pton (AF_INET6, t->nip, &in6a) == 1) {
  95. memcpy (t->naddr, &in6a, sizeof (in6a));
  96. }
  97. else {
  98. g_assert (0);
  99. }
  100. }
  101. t->mask = t->len * NBBY - strtoul (t->m, NULL, 10);
  102. t ++;
  103. }
  104. t = &test_vec[0];
  105. i = 0;
  106. while (t->ip != NULL) {
  107. radix_insert_compressed (tree, t->addr, t->len, t->mask, ++i);
  108. t ++;
  109. }
  110. i = 0;
  111. t = &test_vec[0];
  112. while (t->ip != NULL) {
  113. val = radix_find_compressed (tree, t->addr, t->len);
  114. g_assert (val == ++i);
  115. //g_assert (val != RADIX_NO_VALUE);
  116. if (t->nip != NULL) {
  117. val = radix_find_compressed (tree, t->naddr, t->len);
  118. g_assert (val != i);
  119. }
  120. t ++;
  121. }
  122. radix_destroy_compressed (tree);
  123. }
  124. void
  125. rspamd_radix_test_func (void)
  126. {
  127. #if 0
  128. radix_tree_t *tree = radix_tree_create ();
  129. #endif
  130. radix_compressed_t *comp_tree = radix_create_compressed ();
  131. struct {
  132. guint32 addr;
  133. guint32 mask;
  134. guint8 addr6[16];
  135. guint32 mask6;
  136. } *addrs;
  137. gsize nelts, i;
  138. gint lc;
  139. gboolean all_good = TRUE;
  140. gdouble ts1, ts2;
  141. double diff;
  142. /* Test suite for the compressed trie */
  143. rspamd_radix_text_vec ();
  144. nelts = max_elts;
  145. /* First of all we generate many elements and push them to the array */
  146. addrs = g_malloc (nelts * sizeof (addrs[0]));
  147. for (i = 0; i < nelts; i ++) {
  148. addrs[i].addr = ottery_rand_uint32 ();
  149. addrs[i].mask = masks[ottery_rand_range(G_N_ELEMENTS (masks) - 1)];
  150. ottery_rand_bytes (addrs[i].addr6, sizeof(addrs[i].addr6));
  151. addrs[i].mask6 = ottery_rand_range(128);
  152. }
  153. #if 0
  154. msg_info ("old radix performance (%z elts)", nelts);
  155. ts1 = rspamd_get_ticks ();
  156. for (i = 0; i < nelts; i ++) {
  157. guint32 mask = G_MAXUINT32 << (32 - addrs[i].mask);
  158. radix32tree_insert (tree, addrs[i].addr, mask, 1);
  159. }
  160. ts2 = rspamd_get_ticks ();
  161. diff = (ts2 - ts1) * 1000.0;
  162. msg_info ("Added %z elements in %.6f ms", nelts, diff);
  163. ts1 = rspamd_get_ticks ();
  164. for (lc = 0; lc < lookup_cycles; lc ++) {
  165. for (i = 0; i < nelts; i ++) {
  166. g_assert (radix32tree_find (tree, addrs[i].addr) != RADIX_NO_VALUE);
  167. }
  168. }
  169. ts2 = rspamd_get_ticks ();
  170. diff = (ts2 - ts1) * 1000.0;
  171. msg_info ("Checked %z elements in %.6f ms", nelts, diff);
  172. ts1 = rspamd_get_ticks ();
  173. for (i = 0; i < nelts; i ++) {
  174. radix32tree_delete (tree, addrs[i].addr, addrs[i].mask);
  175. }
  176. ts2 = rspamd_get_ticks ();
  177. diff = (ts2 - ts1) * 1000.;
  178. msg_info ("Deleted %z elements in %.6f ms", nelts, diff);
  179. radix_tree_free (tree);
  180. #endif
  181. msg_info ("new radix performance (%z elts)", nelts);
  182. ts1 = rspamd_get_ticks ();
  183. for (i = 0; i < nelts; i ++) {
  184. radix_insert_compressed (comp_tree, addrs[i].addr6, sizeof (addrs[i].addr6),
  185. 128 - addrs[i].mask6, i);
  186. }
  187. ts2 = rspamd_get_ticks ();
  188. diff = (ts2 - ts1) * 1000.0;
  189. msg_info ("Added %z elements in %.6f ms", nelts, diff);
  190. ts1 = rspamd_get_ticks ();
  191. for (lc = 0; lc < lookup_cycles; lc ++) {
  192. for (i = 0; i < nelts; i ++) {
  193. if (radix_find_compressed (comp_tree, addrs[i].addr6, sizeof (addrs[i].addr6))
  194. == RADIX_NO_VALUE) {
  195. all_good = FALSE;
  196. }
  197. }
  198. }
  199. #if 1
  200. if (!all_good) {
  201. for (i = 0; i < nelts; i ++) {
  202. /* Used to write bad random vector */
  203. char ipbuf[INET6_ADDRSTRLEN + 1];
  204. inet_ntop(AF_INET6, addrs[i].addr6, ipbuf, sizeof(ipbuf));
  205. msg_info("{\"%s\", NULL, \"%ud\", 0, 0, 0, 0},",
  206. ipbuf,
  207. addrs[i].mask6);
  208. }
  209. }
  210. #endif
  211. g_assert (all_good);
  212. ts2 = rspamd_get_ticks ();
  213. diff = (ts2 - ts1) * 1000.0;
  214. msg_info ("Checked %z elements in %.6f ms", nelts, diff);
  215. radix_destroy_compressed (comp_tree);
  216. g_free (addrs);
  217. }