]>
git.proxmox.com Git - mirror_frr.git/blob - tests/lib/test_srcdest_table.c
2 * Test srcdest table for correctness.
4 * Copyright (C) 2017 by David Lamparter & Christian Franke,
5 * Open Source Routing / NetDEF Inc.
7 * This file is part of FreeRangeRouting (FRR)
9 * FRR is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU General Public License as published by the
11 * Free Software Foundation; either version 2, or (at your option) any
14 * FRR is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
19 * You should have received a copy of the GNU General Public License along
20 * with this program; see the file COPYING; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
30 #include "srcdest_table.h"
33 /* Copied from ripngd/ripng_nexthop.h - maybe the whole s6_addr32 thing
34 * should be added by autoconf if not present?
38 /* Some SunOS define s6_addr32 only to kernel */
39 #define s6_addr32 _S6_un._S6_u32
41 #define s6_addr32 __u6_addr.__u6_addr32
45 struct thread_master
*master
;
47 /* This structure is copied from lib/srcdest_table.c to which it is
48 * private as far as other parts of Quagga are concerned.
52 /* must be first in structure for casting to/from route_node */
55 struct route_table
*src_table
;
60 struct route_table
*table
;
65 format_srcdest(const struct prefix_ipv6
*dst_p
,
66 const struct prefix_ipv6
*src_p
)
73 prefix2str((const struct prefix
*)dst_p
, dst_str
, sizeof(dst_str
));
74 if (src_p
&& src_p
->prefixlen
)
75 prefix2str((const struct prefix
*)src_p
, src_str
, sizeof(src_str
));
79 ec
= asprintf(&rv
, "%s%s%s", dst_str
,
80 (src_str
[0] != '\0') ? " from " : "",
87 static unsigned int log_key(void *data
)
89 struct prefix
*hash_entry
= data
;
90 struct prefix_ipv6
*dst_p
= (struct prefix_ipv6
*) &hash_entry
[0];
91 struct prefix_ipv6
*src_p
= (struct prefix_ipv6
*) &hash_entry
[1];
92 unsigned int hash
= 0;
95 hash
= (hash
* 33) ^ (unsigned int)dst_p
->prefixlen
;
96 for (i
= 0; i
< 4; i
++)
97 hash
= (hash
* 33) ^ (unsigned int)dst_p
->prefix
.s6_addr32
[i
];
99 hash
= (hash
* 33) ^ (unsigned int)src_p
->prefixlen
;
100 if (src_p
->prefixlen
)
101 for (i
= 0; i
< 4; i
++)
102 hash
= (hash
* 33) ^ (unsigned int)src_p
->prefix
.s6_addr32
[i
];
108 log_cmp(const void *a
, const void *b
)
110 if (a
== NULL
&& b
!= NULL
)
112 if (b
== NULL
&& a
!= NULL
)
115 return !memcmp(a
, b
, 2 * sizeof(struct prefix
));
121 XFREE(MTYPE_TMP
, data
);
125 log_alloc(void *data
)
127 void *rv
= XMALLOC(MTYPE_TMP
, 2 * sizeof(struct prefix
));
128 memcpy(rv
, data
, 2 * sizeof(struct prefix
));
132 static struct test_state
*
135 struct test_state
*rv
;
137 rv
= XCALLOC(MTYPE_TMP
, sizeof(*rv
));
140 rv
->table
= srcdest_table_init();
143 rv
->log
= hash_create(log_key
, log_cmp
, NULL
);
148 test_state_free(struct test_state
*test
)
150 route_table_finish(test
->table
);
151 hash_clean(test
->log
, log_free
);
152 hash_free(test
->log
);
153 XFREE(MTYPE_TMP
, test
);
157 test_state_add_route(struct test_state
*test
,
158 struct prefix_ipv6
*dst_p
,
159 struct prefix_ipv6
*src_p
)
161 struct route_node
*rn
= srcdest_rnode_get(
162 test
->table
, (struct prefix
*)dst_p
, src_p
164 struct prefix hash_entry
[2];
166 memset(hash_entry
, 0, sizeof(hash_entry
));
167 memcpy(&hash_entry
[0], dst_p
, sizeof(*dst_p
));
168 memcpy(&hash_entry
[1], src_p
, sizeof(*src_p
));
171 route_unlock_node(rn
);
172 assert(hash_lookup(test
->log
, hash_entry
) != NULL
);
175 assert(hash_lookup(test
->log
, hash_entry
) == NULL
);
178 rn
->info
= (void*) 0xdeadbeef;
179 hash_get(test
->log
, hash_entry
, log_alloc
);
183 test_state_del_route(struct test_state
*test
,
184 struct prefix_ipv6
*dst_p
,
185 struct prefix_ipv6
*src_p
)
187 struct route_node
*rn
= srcdest_rnode_lookup(
188 test
->table
, (struct prefix
*)dst_p
, src_p
190 struct prefix hash_entry
[2];
192 memset(hash_entry
, 0, sizeof(hash_entry
));
193 memcpy(&hash_entry
[0], dst_p
, sizeof(*dst_p
));
194 memcpy(&hash_entry
[1], src_p
, sizeof(*src_p
));
197 assert(!hash_lookup(test
->log
, hash_entry
));
201 assert(rn
->info
== (void*)0xdeadbeef);
203 route_unlock_node(rn
);
204 route_unlock_node(rn
);
206 struct prefix
*hash_entry_intern
= hash_release(test
->log
, hash_entry
);
207 assert(hash_entry_intern
!= NULL
);
208 XFREE(MTYPE_TMP
, hash_entry_intern
);
212 verify_log(struct hash_backet
* backet
, void *arg
)
214 struct test_state
*test
= arg
;
215 struct prefix
*hash_entry
= backet
->data
;
216 struct prefix
*dst_p
= &hash_entry
[0];
217 struct prefix_ipv6
*src_p
= (struct prefix_ipv6
*)&hash_entry
[1];
218 struct route_node
*rn
= srcdest_rnode_lookup(test
->table
, dst_p
, src_p
);
221 assert(rn
->info
== (void*)0xdeadbeef);
223 route_unlock_node(rn
);
227 dump_log(struct hash_backet
* backet
, void *arg
)
229 struct prefix
*hash_entry
= backet
->data
;
230 struct prefix_ipv6
*dst_p
= (struct prefix_ipv6
*)&hash_entry
[0];
231 struct prefix_ipv6
*src_p
= (struct prefix_ipv6
*)&hash_entry
[1];
232 char *route_id
= format_srcdest(dst_p
, src_p
);
234 fprintf(stderr
, " %s\n", route_id
);
239 test_dump(struct test_state
*test
)
241 fprintf(stderr
, "Contents of hash table:\n");
242 hash_iterate(test
->log
, dump_log
, test
);
243 fprintf(stderr
, "\n");
247 test_failed(struct test_state
*test
, const char *message
,
248 struct prefix_ipv6
*dst_p
, struct prefix_ipv6
*src_p
)
250 char *route_id
= format_srcdest(dst_p
, src_p
);
252 fprintf(stderr
, "Test failed. Error: %s\n", message
);
253 fprintf(stderr
, "Route in question: %s\n", route_id
);
261 test_state_verify(struct test_state
*test
)
263 struct route_node
*rn
;
264 struct prefix hash_entry
[2];
266 memset(hash_entry
, 0, sizeof(hash_entry
));
268 /* Verify that there are no elements in the table which have never
270 for (rn
= route_top(test
->table
); rn
; rn
= srcdest_route_next(rn
))
272 struct prefix_ipv6
*dst_p
, *src_p
;
274 /* While we are iterating, we hold a lock on the current route_node,
275 * so all the lock counts we check for take that into account; in idle
276 * state all the numbers will be exactly one less.
278 * Also this makes quite some assumptions based on the current
279 * implementation details of route_table and srcdest_table - another
280 * valid implementation might trigger assertions here.
283 if (rnode_is_dstnode(rn
))
285 struct srcdest_rnode
*srn
= (struct srcdest_rnode
*)rn
;
286 unsigned int expected_lock
= 1; /* We are in the loop */
288 if (rn
->info
!= NULL
) /* The route node is not internal */
290 if (srn
->src_table
!= NULL
) /* There's a source table associated with rn */
293 if (rn
->lock
!= expected_lock
)
294 test_failed(test
, "Dest rnode lock count doesn't match expected count!",
295 (struct prefix_ipv6
*)&rn
->p
, NULL
);
299 unsigned int expected_lock
= 1; /* We are in the loop */
301 if (rn
->info
!= NULL
) /* The route node is not internal */
304 if (rn
->lock
!= expected_lock
)
306 struct prefix_ipv6
*dst_p
, *src_p
;
307 srcdest_rnode_prefixes(rn
, (struct prefix
**)&dst_p
,
308 (struct prefix
**)&src_p
);
310 test_failed(test
, "Src rnode lock count doesn't match expected count!",
318 assert(rn
->info
== (void*)0xdeadbeef);
320 srcdest_rnode_prefixes(rn
, (struct prefix
**)&dst_p
, (struct prefix
**)&src_p
);
321 memcpy(&hash_entry
[0], dst_p
, sizeof(*dst_p
));
323 memcpy(&hash_entry
[1], src_p
, sizeof(*src_p
));
325 memset(&hash_entry
[1], 0, sizeof(hash_entry
[1]));
327 if (hash_lookup(test
->log
, hash_entry
) == NULL
)
328 test_failed(test
, "Route is missing in hash", dst_p
, src_p
);
331 /* Verify that all added elements are still in the table */
332 hash_iterate(test
->log
, verify_log
, test
);
336 get_rand_prefix(struct prng
*prng
, struct prefix_ipv6
*p
)
340 memset(p
, 0, sizeof(*p
));
342 for (i
= 0; i
< 4; i
++)
343 p
->prefix
.s6_addr32
[i
] = prng_rand(prng
);
344 p
->prefixlen
= prng_rand(prng
) % 129;
345 p
->family
= AF_INET6
;
347 apply_mask((struct prefix
*)p
);
351 get_rand_prefix_pair(struct prng
*prng
, struct prefix_ipv6
*dst_p
,
352 struct prefix_ipv6
*src_p
)
354 get_rand_prefix(prng
, dst_p
);
355 if ((prng_rand(prng
) % 4) == 0)
357 get_rand_prefix(prng
, src_p
);
358 if (src_p
->prefixlen
)
362 memset(src_p
, 0, sizeof(*src_p
));
366 test_state_add_rand_route(struct test_state
*test
,
369 struct prefix_ipv6 dst_p
, src_p
;
371 get_rand_prefix_pair(prng
, &dst_p
, &src_p
);
372 test_state_add_route(test
, &dst_p
, &src_p
);
376 test_state_del_rand_route(struct test_state
*test
,
379 struct prefix_ipv6 dst_p
, src_p
;
381 get_rand_prefix_pair(prng
, &dst_p
, &src_p
);
382 test_state_del_route(test
, &dst_p
, &src_p
);
386 test_state_del_one_route(struct test_state
*test
,
389 unsigned int which_route
= prng_rand(prng
) % test
->log
->count
;
390 struct route_node
*rn
;
391 struct prefix
*dst_p
, *src_p
;
392 struct prefix_ipv6 dst6_p
, src6_p
;
394 for (rn
= route_top(test
->table
); rn
; rn
= srcdest_route_next(rn
))
399 route_unlock_node(rn
);
406 srcdest_rnode_prefixes(rn
, &dst_p
, &src_p
);
407 memcpy(&dst6_p
, dst_p
, sizeof(dst6_p
));
409 memcpy(&src6_p
, src_p
, sizeof(src6_p
));
411 memset(&src6_p
, 0, sizeof(src6_p
));
413 test_state_del_route(test
, &dst6_p
, &src6_p
);
419 struct test_state
*test
= test_state_new();
420 struct prng
*prng
= prng_new(0);
423 for (i
= 0; i
< 1000; i
++)
425 switch (prng_rand(prng
) % 10)
432 test_state_add_rand_route(test
, prng
);
437 test_state_del_one_route(test
, prng
);
441 test_state_del_rand_route(test
, prng
);
444 test_state_verify(test
);
448 test_state_free(test
);
451 int main(int argc
, char *argv
[])
454 printf("PRNG Test successful.\n");