]>
git.proxmox.com Git - mirror_frr.git/blob - tests/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
20 * along with FRR; see the file COPYING. If not, write to the Free
21 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
31 #include "srcdest_table.h"
34 /* Copied from ripngd/ripng_nexthop.h - maybe the whole s6_addr32 thing
35 * should be added by autoconf if not present?
39 /* Some SunOS define s6_addr32 only to kernel */
40 #define s6_addr32 _S6_un._S6_u32
42 #define s6_addr32 __u6_addr.__u6_addr32
46 struct thread_master
*master
;
48 /* This structure is copied from lib/srcdest_table.c to which it is
49 * private as far as other parts of Quagga are concerned.
53 /* must be first in structure for casting to/from route_node */
56 struct route_table
*src_table
;
61 struct route_table
*table
;
66 format_srcdest(const struct prefix_ipv6
*dst_p
,
67 const struct prefix_ipv6
*src_p
)
74 prefix2str((const struct prefix
*)dst_p
, dst_str
, sizeof(dst_str
));
75 if (src_p
&& src_p
->prefixlen
)
76 prefix2str((const struct prefix
*)src_p
, src_str
, sizeof(src_str
));
80 ec
= asprintf(&rv
, "%s%s%s", dst_str
,
81 (src_str
[0] != '\0') ? " from " : "",
88 static unsigned int log_key(void *data
)
90 struct prefix
*hash_entry
= data
;
91 struct prefix_ipv6
*dst_p
= (struct prefix_ipv6
*) &hash_entry
[0];
92 struct prefix_ipv6
*src_p
= (struct prefix_ipv6
*) &hash_entry
[1];
93 unsigned int hash
= 0;
96 hash
= (hash
* 33) ^ (unsigned int)dst_p
->prefixlen
;
97 for (i
= 0; i
< 4; i
++)
98 hash
= (hash
* 33) ^ (unsigned int)dst_p
->prefix
.s6_addr32
[i
];
100 hash
= (hash
* 33) ^ (unsigned int)src_p
->prefixlen
;
101 if (src_p
->prefixlen
)
102 for (i
= 0; i
< 4; i
++)
103 hash
= (hash
* 33) ^ (unsigned int)src_p
->prefix
.s6_addr32
[i
];
109 log_cmp(const void *a
, const void *b
)
111 if (a
== NULL
&& b
!= NULL
)
113 if (b
== NULL
&& a
!= NULL
)
116 return !memcmp(a
, b
, 2 * sizeof(struct prefix
));
122 XFREE(MTYPE_TMP
, data
);
126 log_alloc(void *data
)
128 void *rv
= XMALLOC(MTYPE_TMP
, 2 * sizeof(struct prefix
));
129 memcpy(rv
, data
, 2 * sizeof(struct prefix
));
133 static struct test_state
*
136 struct test_state
*rv
;
138 rv
= XCALLOC(MTYPE_TMP
, sizeof(*rv
));
141 rv
->table
= srcdest_table_init();
144 rv
->log
= hash_create(log_key
, log_cmp
);
149 test_state_free(struct test_state
*test
)
151 route_table_finish(test
->table
);
152 hash_clean(test
->log
, log_free
);
153 hash_free(test
->log
);
154 XFREE(MTYPE_TMP
, test
);
158 test_state_add_route(struct test_state
*test
,
159 struct prefix_ipv6
*dst_p
,
160 struct prefix_ipv6
*src_p
)
162 struct route_node
*rn
= srcdest_rnode_get(
163 test
->table
, (struct prefix
*)dst_p
, src_p
165 struct prefix hash_entry
[2];
167 memset(hash_entry
, 0, sizeof(hash_entry
));
168 memcpy(&hash_entry
[0], dst_p
, sizeof(*dst_p
));
169 memcpy(&hash_entry
[1], src_p
, sizeof(*src_p
));
172 route_unlock_node(rn
);
173 assert(hash_lookup(test
->log
, hash_entry
) != NULL
);
176 assert(hash_lookup(test
->log
, hash_entry
) == NULL
);
179 rn
->info
= (void*) 0xdeadbeef;
180 hash_get(test
->log
, hash_entry
, log_alloc
);
184 test_state_del_route(struct test_state
*test
,
185 struct prefix_ipv6
*dst_p
,
186 struct prefix_ipv6
*src_p
)
188 struct route_node
*rn
= srcdest_rnode_lookup(
189 test
->table
, (struct prefix
*)dst_p
, src_p
191 struct prefix hash_entry
[2];
193 memset(hash_entry
, 0, sizeof(hash_entry
));
194 memcpy(&hash_entry
[0], dst_p
, sizeof(*dst_p
));
195 memcpy(&hash_entry
[1], src_p
, sizeof(*src_p
));
198 assert(!hash_lookup(test
->log
, hash_entry
));
202 assert(rn
->info
== (void*)0xdeadbeef);
204 route_unlock_node(rn
);
205 route_unlock_node(rn
);
207 struct prefix
*hash_entry_intern
= hash_release(test
->log
, hash_entry
);
208 assert(hash_entry_intern
!= NULL
);
209 XFREE(MTYPE_TMP
, hash_entry_intern
);
213 verify_log(struct hash_backet
* backet
, void *arg
)
215 struct test_state
*test
= arg
;
216 struct prefix
*hash_entry
= backet
->data
;
217 struct prefix
*dst_p
= &hash_entry
[0];
218 struct prefix_ipv6
*src_p
= (struct prefix_ipv6
*)&hash_entry
[1];
219 struct route_node
*rn
= srcdest_rnode_lookup(test
->table
, dst_p
, src_p
);
222 assert(rn
->info
== (void*)0xdeadbeef);
224 route_unlock_node(rn
);
228 dump_log(struct hash_backet
* backet
, void *arg
)
230 struct prefix
*hash_entry
= backet
->data
;
231 struct prefix_ipv6
*dst_p
= (struct prefix_ipv6
*)&hash_entry
[0];
232 struct prefix_ipv6
*src_p
= (struct prefix_ipv6
*)&hash_entry
[1];
233 char *route_id
= format_srcdest(dst_p
, src_p
);
235 fprintf(stderr
, " %s\n", route_id
);
240 test_dump(struct test_state
*test
)
242 fprintf(stderr
, "Contents of hash table:\n");
243 hash_iterate(test
->log
, dump_log
, test
);
244 fprintf(stderr
, "\n");
248 test_failed(struct test_state
*test
, const char *message
,
249 struct prefix_ipv6
*dst_p
, struct prefix_ipv6
*src_p
)
251 char *route_id
= format_srcdest(dst_p
, src_p
);
253 fprintf(stderr
, "Test failed. Error: %s\n", message
);
254 fprintf(stderr
, "Route in question: %s\n", route_id
);
262 test_state_verify(struct test_state
*test
)
264 struct route_node
*rn
;
265 struct prefix hash_entry
[2];
267 memset(hash_entry
, 0, sizeof(hash_entry
));
269 /* Verify that there are no elements in the table which have never
271 for (rn
= route_top(test
->table
); rn
; rn
= srcdest_route_next(rn
))
273 struct prefix_ipv6
*dst_p
, *src_p
;
275 /* While we are iterating, we hold a lock on the current route_node,
276 * so all the lock counts we check for take that into account; in idle
277 * state all the numbers will be exactly one less.
279 * Also this makes quite some assumptions based on the current
280 * implementation details of route_table and srcdest_table - another
281 * valid implementation might trigger assertions here.
284 if (rnode_is_dstnode(rn
))
286 struct srcdest_rnode
*srn
= (struct srcdest_rnode
*)rn
;
287 unsigned int expected_lock
= 1; /* We are in the loop */
289 if (rn
->info
!= NULL
) /* The route node is not internal */
291 if (srn
->src_table
!= NULL
) /* There's a source table associated with rn */
294 if (rn
->lock
!= expected_lock
)
295 test_failed(test
, "Dest rnode lock count doesn't match expected count!",
296 (struct prefix_ipv6
*)&rn
->p
, NULL
);
300 unsigned int expected_lock
= 1; /* We are in the loop */
302 if (rn
->info
!= NULL
) /* The route node is not internal */
305 if (rn
->lock
!= expected_lock
)
307 struct prefix_ipv6
*dst_p
, *src_p
;
308 srcdest_rnode_prefixes(rn
, (struct prefix
**)&dst_p
,
309 (struct prefix
**)&src_p
);
311 test_failed(test
, "Src rnode lock count doesn't match expected count!",
319 assert(rn
->info
== (void*)0xdeadbeef);
321 srcdest_rnode_prefixes(rn
, (struct prefix
**)&dst_p
, (struct prefix
**)&src_p
);
322 memcpy(&hash_entry
[0], dst_p
, sizeof(*dst_p
));
324 memcpy(&hash_entry
[1], src_p
, sizeof(*src_p
));
326 memset(&hash_entry
[1], 0, sizeof(hash_entry
[1]));
328 if (hash_lookup(test
->log
, hash_entry
) == NULL
)
329 test_failed(test
, "Route is missing in hash", dst_p
, src_p
);
332 /* Verify that all added elements are still in the table */
333 hash_iterate(test
->log
, verify_log
, test
);
337 get_rand_prefix(struct prng
*prng
, struct prefix_ipv6
*p
)
341 memset(p
, 0, sizeof(*p
));
343 for (i
= 0; i
< 4; i
++)
344 p
->prefix
.s6_addr32
[i
] = prng_rand(prng
);
345 p
->prefixlen
= prng_rand(prng
) % 129;
346 p
->family
= AF_INET6
;
348 apply_mask((struct prefix
*)p
);
352 get_rand_prefix_pair(struct prng
*prng
, struct prefix_ipv6
*dst_p
,
353 struct prefix_ipv6
*src_p
)
355 get_rand_prefix(prng
, dst_p
);
356 if ((prng_rand(prng
) % 4) == 0)
358 get_rand_prefix(prng
, src_p
);
359 if (src_p
->prefixlen
)
363 memset(src_p
, 0, sizeof(*src_p
));
367 test_state_add_rand_route(struct test_state
*test
,
370 struct prefix_ipv6 dst_p
, src_p
;
372 get_rand_prefix_pair(prng
, &dst_p
, &src_p
);
373 test_state_add_route(test
, &dst_p
, &src_p
);
377 test_state_del_rand_route(struct test_state
*test
,
380 struct prefix_ipv6 dst_p
, src_p
;
382 get_rand_prefix_pair(prng
, &dst_p
, &src_p
);
383 test_state_del_route(test
, &dst_p
, &src_p
);
387 test_state_del_one_route(struct test_state
*test
,
390 unsigned int which_route
= prng_rand(prng
) % test
->log
->count
;
391 struct route_node
*rn
;
392 struct prefix
*dst_p
, *src_p
;
393 struct prefix_ipv6 dst6_p
, src6_p
;
395 for (rn
= route_top(test
->table
); rn
; rn
= srcdest_route_next(rn
))
400 route_unlock_node(rn
);
407 srcdest_rnode_prefixes(rn
, &dst_p
, &src_p
);
408 memcpy(&dst6_p
, dst_p
, sizeof(dst6_p
));
410 memcpy(&src6_p
, src_p
, sizeof(src6_p
));
412 memset(&src6_p
, 0, sizeof(src6_p
));
414 test_state_del_route(test
, &dst6_p
, &src6_p
);
420 struct test_state
*test
= test_state_new();
421 struct prng
*prng
= prng_new(0);
424 for (i
= 0; i
< 1000; i
++)
426 switch (prng_rand(prng
) % 10)
433 test_state_add_rand_route(test
, prng
);
438 test_state_del_one_route(test
, prng
);
442 test_state_del_rand_route(test
, prng
);
445 test_state_verify(test
);
449 test_state_free(test
);
452 int main(int argc
, char *argv
[])
455 printf("PRNG Test successful.\n");