]> git.proxmox.com Git - mirror_frr.git/blame - tests/lib/test_nexthop_iter.c
*: make consistent & update GPLv2 file headers
[mirror_frr.git] / tests / lib / test_nexthop_iter.c
CommitLineData
fa713d9e
CF
1/*
2 * Recursive Nexthop Iterator test.
3 * This tests the ALL_NEXTHOPS_RO macro.
4 *
5 * Copyright (C) 2012 by Open Source Routing.
6 * Copyright (C) 2012 by Internet Systems Consortium, Inc. ("ISC")
7 *
8 * This file is part of Quagga
9 *
10 * Quagga is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License as published by the
12 * Free Software Foundation; either version 2, or (at your option) any
13 * later version.
14 *
15 * Quagga is distributed in the hope that it will be useful, but
16 * WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * General Public License for more details.
19 *
896014f4
DL
20 * You should have received a copy of the GNU General Public License along
21 * with this program; see the file COPYING; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
fa713d9e
CF
23 */
24
25#include <zebra.h>
26#include "zebra/rib.h"
27#include "prng.h"
28
29struct thread_master *master;
30static int verbose;
31
32static void
33str_append(char **buf, const char *repr)
34{
35 if (*buf)
36 {
37 *buf = realloc(*buf, strlen(*buf) + strlen(repr) + 1);
38 assert(*buf);
39 strncpy((*buf) + strlen(*buf), repr, strlen(repr) + 1);
40 }
41 else
42 {
43 *buf = strdup(repr);
44 assert(*buf);
45 }
46}
47
48static void
49str_appendf(char **buf, const char *format, ...)
50{
51 va_list ap;
52 int rv;
53 char *pbuf;
54
55 va_start(ap, format);
56 rv = vasprintf(&pbuf, format, ap);
57 va_end(ap);
58 assert(rv >= 0);
59
60 str_append(buf, pbuf);
61 free(pbuf);
62}
63
64/* This structure contains a nexthop chain
65 * and its expected representation */
66struct nexthop_chain
67{
68 /* Head of the chain */
69 struct nexthop *head;
70 /* Last nexthop in top chain */
71 struct nexthop *current_top;
72 /* Last nexthop in current recursive chain */
73 struct nexthop *current_recursive;
74 /* Expected string representation. */
75 char *repr;
76};
77
78static struct nexthop_chain*
79nexthop_chain_new(void)
80{
81 struct nexthop_chain *rv;
82
83 rv = calloc(sizeof(*rv), 1);
84 assert(rv);
85 return rv;
86}
87
88static void
89nexthop_chain_add_top(struct nexthop_chain *nc)
90{
91 struct nexthop *nh;
92
93 nh = calloc(sizeof(*nh), 1);
94 assert(nh);
95
96 if (nc->head)
97 {
98 nc->current_top->next = nh;
99 nh->prev = nc->current_top;
100 nc->current_top = nh;
101 }
102 else
103 {
104 nc->head = nc->current_top = nh;
105 }
106 nc->current_recursive = NULL;
107 str_appendf(&nc->repr, "%p\n", nh);
108}
109
110static void
111nexthop_chain_add_recursive(struct nexthop_chain *nc)
112{
113 struct nexthop *nh;
114
115 nh = calloc(sizeof(*nh), 1);
116 assert(nh);
117
118 assert(nc->current_top);
119 if (nc->current_recursive)
120 {
121 nc->current_recursive->next = nh;
122 nh->prev = nc->current_recursive;
123 nc->current_recursive = nh;
124 }
125 else
126 {
127 SET_FLAG(nc->current_top->flags, NEXTHOP_FLAG_RECURSIVE);
128 nc->current_top->resolved = nh;
129 nc->current_recursive = nh;
130 }
131 str_appendf(&nc->repr, " %p\n", nh);
132}
133
134static void
135nexthop_chain_clear(struct nexthop_chain *nc)
136{
137 struct nexthop *tcur, *tnext;
138
139 for (tcur = nc->head; tcur; tcur = tnext)
140 {
141 tnext = tcur->next;
142 if (CHECK_FLAG(tcur->flags, NEXTHOP_FLAG_RECURSIVE))
143 {
144 struct nexthop *rcur, *rnext;
145 for (rcur = tcur->resolved; rcur; rcur = rnext)
146 {
147 rnext = rcur->next;
148 free(rcur);
149 }
150 }
151 free(tcur);
152 }
153 nc->head = nc->current_top = nc->current_recursive = NULL;
154 free(nc->repr);
155 nc->repr = NULL;
156}
157
158static void
159nexthop_chain_free(struct nexthop_chain *nc)
160{
161 if (!nc)
162 return;
163 nexthop_chain_clear(nc);
164 free(nc);
165}
166
167/* This function builds a string representation of
168 * the nexthop chain using the ALL_NEXTHOPS_RO macro.
169 * It verifies that the ALL_NEXTHOPS_RO macro iterated
170 * correctly over the nexthop chain by comparing the
171 * generated representation with the expected representation.
172 */
173static void
174nexthop_chain_verify_iter(struct nexthop_chain *nc)
175{
176 struct nexthop *nh, *tnh;
177 int recursing;
178 char *repr = NULL;
179
180 for (ALL_NEXTHOPS_RO(nc->head, nh, tnh, recursing))
181 {
182 if (recursing)
183 str_appendf(&repr, " %p\n", nh);
184 else
185 str_appendf(&repr, "%p\n", nh);
186 }
187
188 if (repr && verbose)
189 printf("===\n%s", repr);
190 assert((!repr && !nc->repr) || (repr && nc->repr && !strcmp(repr, nc->repr)));
191 free(repr);
192}
193
194/* This test run builds a simple nexthop chain
195 * with some recursive nexthops and verifies that
196 * the iterator works correctly in each stage along
197 * the way.
198 */
199static void
200test_run_first(void)
201{
202 struct nexthop_chain *nc;
203
204 nc = nexthop_chain_new();
205 nexthop_chain_verify_iter(nc);
206
207 nexthop_chain_add_top(nc);
208 nexthop_chain_verify_iter(nc);
209
210 nexthop_chain_add_top(nc);
211 nexthop_chain_verify_iter(nc);
212
213 nexthop_chain_add_recursive(nc);
214 nexthop_chain_verify_iter(nc);
215
216 nexthop_chain_add_recursive(nc);
217 nexthop_chain_verify_iter(nc);
218
219 nexthop_chain_add_top(nc);
220 nexthop_chain_verify_iter(nc);
221
222 nexthop_chain_add_top(nc);
223 nexthop_chain_verify_iter(nc);
224
225 nexthop_chain_add_top(nc);
226 nexthop_chain_verify_iter(nc);
227
228 nexthop_chain_add_recursive(nc);
229 nexthop_chain_verify_iter(nc);
230
231 nexthop_chain_add_recursive(nc);
232 nexthop_chain_verify_iter(nc);
233
234 nexthop_chain_add_recursive(nc);
235 nexthop_chain_verify_iter(nc);
236
237 nexthop_chain_free(nc);
238}
239
240/* This test run builds numerous random
241 * nexthop chain configurations and verifies
242 * that the iterator correctly progresses
243 * through each. */
244static void
245test_run_prng(void)
246{
247 struct nexthop_chain *nc;
248 struct prng *prng;
249 int i;
250
251 nc = nexthop_chain_new();
252 prng = prng_new(0);
253
254 for (i = 0; i < 1000000; i++)
255 {
256 switch (prng_rand(prng) % 10)
257 {
258 case 0:
259 nexthop_chain_clear(nc);
260 break;
261 case 1:
262 case 2:
263 case 3:
264 case 4:
265 case 5:
266 nexthop_chain_add_top(nc);
267 break;
268 case 6:
269 case 7:
270 case 8:
271 case 9:
272 if (nc->current_top)
273 nexthop_chain_add_recursive(nc);
274 break;
275 }
276 nexthop_chain_verify_iter(nc);
277 }
278 nexthop_chain_free(nc);
279 prng_free(prng);
280}
281
282int main(int argc, char **argv)
283{
284 if (argc >= 2 && !strcmp("-v", argv[1]))
285 verbose = 1;
286 test_run_first();
287 printf("Simple test passed.\n");
288 test_run_prng();
289 printf("PRNG test passed.\n");
290}