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.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253
  1. /* Copyright (c) 2014, Vsevolod Stakhov
  2. * All rights reserved.
  3. *
  4. * Redistribution and use in source and binary forms, with or without
  5. * modification, are permitted provided that the following conditions are met:
  6. * * Redistributions of source code must retain the above copyright
  7. * notice, this list of conditions and the following disclaimer.
  8. * * Redistributions in binary form must reproduce the above copyright
  9. * notice, this list of conditions and the following disclaimer in the
  10. * documentation and/or other materials provided with the distribution.
  11. *
  12. * THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY
  13. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  14. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  15. * DISCLAIMED. IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY
  16. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  17. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  18. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  19. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  20. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  21. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  22. */
  23. #include "config.h"
  24. #include "rspamd.h"
  25. #include "radix.h"
  26. #include "ottery.h"
  27. const gsize max_elts = 50 * 1024;
  28. const gint lookup_cycles = 1 * 1024;
  29. const uint masks[] = {
  30. 8,
  31. 16,
  32. 24,
  33. 32,
  34. 27,
  35. 29,
  36. 19,
  37. 13,
  38. 22
  39. };
  40. struct _tv {
  41. const char *ip;
  42. const char *nip;
  43. const char *m;
  44. guint32 mask;
  45. guint8 *addr;
  46. guint8 *naddr;
  47. gsize len;
  48. } test_vec[] = {
  49. {"192.168.1.1", "192.168.1.2", "32", 0, 0, 0, 0},
  50. {"192.168.1.0", "192.168.2.1", "24", 0, 0, 0, 0},
  51. {"192.0.0.0", "193.167.2.1", "8", 0, 0, 0, 0},
  52. {"172.0.0.0", "171.16.1.0", "8", 0, 0, 0, 0},
  53. {"172.16.0.1", "127.0.0.1", "16", 0, 0, 0, 0},
  54. {"172.17.1.0", "10.0.0.1", "27", 0, 0, 0, 0},
  55. {"172.17.1.1", "0.0.0.1", "32", 0, 0, 0, 0},
  56. /* Some bad data known to cause problem in the past */
  57. {"191.245.170.246", NULL, "19", 0, 0, 0, 0},
  58. {"227.88.150.170", NULL, "23", 0, 0, 0, 0},
  59. {"105.225.182.92", NULL, "24", 0, 0, 0, 0},
  60. {"223.167.155.240", NULL, "29", 0, 0, 0, 0},
  61. {"125.241.220.172", NULL, "2", 0, 0, 0, 0},
  62. /* Mask = 0 */
  63. {"143.105.181.13", NULL, "8", 0, 0, 0, 0},
  64. {"113.241.233.86", NULL, "26", 0, 0, 0, 0},
  65. {"185.187.122.222", NULL, "8", 0, 0, 0, 0},
  66. {"109.206.26.202", NULL, "12", 0, 0, 0, 0},
  67. {"130.244.233.150", NULL, "0", 0, 0, 0, 0},
  68. /* Close ip addresses */
  69. {"1.2.3.1", NULL, "32", 0, 0, 0, 0},
  70. {"1.2.3.2", NULL, "32", 0, 0, 0, 0},
  71. {"1.2.3.3", NULL, "32", 0, 0, 0, 0},
  72. {"1.2.3.4", NULL, "32", 0, 0, 0, 0},
  73. {NULL, NULL, NULL, 0, 0, 0, 0}
  74. };
  75. static void
  76. rspamd_radix_text_vec (void)
  77. {
  78. radix_compressed_t *tree = radix_create_compressed ();
  79. struct _tv *t = &test_vec[0];
  80. struct in_addr ina;
  81. struct in6_addr in6a;
  82. gulong i, val;
  83. while (t->ip != NULL) {
  84. t->addr = g_malloc (sizeof (in6a));
  85. t->naddr = g_malloc (sizeof (in6a));
  86. if (inet_pton (AF_INET, t->ip, &ina) == 1) {
  87. memcpy (t->addr, &ina, sizeof (ina));
  88. t->len = sizeof (ina);
  89. }
  90. else if (inet_pton (AF_INET6, t->ip, &in6a) == 1) {
  91. memcpy (t->addr, &in6a, sizeof (in6a));
  92. t->len = sizeof (in6a);
  93. }
  94. else {
  95. g_assert (0);
  96. }
  97. if (t->nip) {
  98. if (inet_pton (AF_INET, t->nip, &ina) == 1) {
  99. memcpy (t->naddr, &ina, sizeof (ina));
  100. }
  101. else if (inet_pton (AF_INET6, t->nip, &in6a) == 1) {
  102. memcpy (t->naddr, &in6a, sizeof (in6a));
  103. }
  104. else {
  105. g_assert (0);
  106. }
  107. }
  108. t->mask = t->len * NBBY - strtoul (t->m, NULL, 10);
  109. t ++;
  110. }
  111. t = &test_vec[0];
  112. i = 0;
  113. while (t->ip != NULL) {
  114. radix_insert_compressed (tree, t->addr, t->len, t->mask, ++i);
  115. t ++;
  116. }
  117. i = 0;
  118. t = &test_vec[0];
  119. while (t->ip != NULL) {
  120. val = radix_find_compressed (tree, t->addr, t->len);
  121. g_assert (val == ++i);
  122. //g_assert (val != RADIX_NO_VALUE);
  123. if (t->nip != NULL) {
  124. val = radix_find_compressed (tree, t->naddr, t->len);
  125. g_assert (val != i);
  126. }
  127. t ++;
  128. }
  129. radix_destroy_compressed (tree);
  130. }
  131. void
  132. rspamd_radix_test_func (void)
  133. {
  134. #if 0
  135. radix_tree_t *tree = radix_tree_create ();
  136. #endif
  137. radix_compressed_t *comp_tree = radix_create_compressed ();
  138. struct {
  139. guint32 addr;
  140. guint32 mask;
  141. guint8 addr6[16];
  142. guint32 mask6;
  143. } *addrs;
  144. gsize nelts, i;
  145. gint lc;
  146. gboolean all_good = TRUE;
  147. gdouble ts1, ts2;
  148. double diff;
  149. /* Test suite for the compressed trie */
  150. rspamd_radix_text_vec ();
  151. nelts = max_elts;
  152. /* First of all we generate many elements and push them to the array */
  153. addrs = g_malloc (nelts * sizeof (addrs[0]));
  154. for (i = 0; i < nelts; i ++) {
  155. addrs[i].addr = ottery_rand_uint32 ();
  156. addrs[i].mask = masks[ottery_rand_range(G_N_ELEMENTS (masks) - 1)];
  157. ottery_rand_bytes (addrs[i].addr6, sizeof(addrs[i].addr6));
  158. addrs[i].mask6 = ottery_rand_range(128);
  159. }
  160. #if 0
  161. msg_info ("old radix performance (%z elts)", nelts);
  162. ts1 = rspamd_get_ticks ();
  163. for (i = 0; i < nelts; i ++) {
  164. guint32 mask = G_MAXUINT32 << (32 - addrs[i].mask);
  165. radix32tree_insert (tree, addrs[i].addr, mask, 1);
  166. }
  167. ts2 = rspamd_get_ticks ();
  168. diff = (ts2 - ts1) * 1000.0;
  169. msg_info ("Added %z elements in %.6f ms", nelts, diff);
  170. ts1 = rspamd_get_ticks ();
  171. for (lc = 0; lc < lookup_cycles; lc ++) {
  172. for (i = 0; i < nelts; i ++) {
  173. g_assert (radix32tree_find (tree, addrs[i].addr) != RADIX_NO_VALUE);
  174. }
  175. }
  176. ts2 = rspamd_get_ticks ();
  177. diff = (ts2 - ts1) * 1000.0;
  178. msg_info ("Checked %z elements in %.6f ms", nelts, diff);
  179. ts1 = rspamd_get_ticks ();
  180. for (i = 0; i < nelts; i ++) {
  181. radix32tree_delete (tree, addrs[i].addr, addrs[i].mask);
  182. }
  183. ts2 = rspamd_get_ticks ();
  184. diff = (ts2 - ts1) * 1000.;
  185. msg_info ("Deleted %z elements in %.6f ms", nelts, diff);
  186. radix_tree_free (tree);
  187. #endif
  188. msg_info ("new radix performance (%z elts)", nelts);
  189. ts1 = rspamd_get_ticks ();
  190. for (i = 0; i < nelts; i ++) {
  191. radix_insert_compressed (comp_tree, addrs[i].addr6, sizeof (addrs[i].addr6),
  192. 128 - addrs[i].mask6, i);
  193. }
  194. ts2 = rspamd_get_ticks ();
  195. diff = (ts2 - ts1) * 1000.0;
  196. msg_info ("Added %z elements in %.6f ms", nelts, diff);
  197. ts1 = rspamd_get_ticks ();
  198. for (lc = 0; lc < lookup_cycles; lc ++) {
  199. for (i = 0; i < nelts; i ++) {
  200. if (radix_find_compressed (comp_tree, addrs[i].addr6, sizeof (addrs[i].addr6))
  201. == RADIX_NO_VALUE) {
  202. all_good = FALSE;
  203. }
  204. }
  205. }
  206. #if 1
  207. if (!all_good) {
  208. for (i = 0; i < nelts; i ++) {
  209. /* Used to write bad random vector */
  210. char ipbuf[INET6_ADDRSTRLEN + 1];
  211. inet_ntop(AF_INET6, addrs[i].addr6, ipbuf, sizeof(ipbuf));
  212. msg_info("{\"%s\", NULL, \"%ud\", 0, 0, 0, 0},",
  213. ipbuf,
  214. addrs[i].mask6);
  215. }
  216. }
  217. #endif
  218. g_assert (all_good);
  219. ts2 = rspamd_get_ticks ();
  220. diff = (ts2 - ts1) * 1000.0;
  221. msg_info ("Checked %z elements in %.6f ms", nelts, diff);
  222. radix_destroy_compressed (comp_tree);
  223. g_free (addrs);
  224. }