]>
Commit | Line | Data |
---|---|---|
9d4f5623 PM |
1 | /* |
2 | * BGP Peer Attribute Unit Tests | |
3 | * Copyright (C) 2018 Pascal Mathis | |
4 | * | |
5 | * This program is free software; you can redistribute it and/or modify it | |
6 | * under the terms of the GNU General Public License as published by the Free | |
7 | * Software Foundation; either version 2 of the License, or (at your option) | |
8 | * any later version. | |
9 | * | |
10 | * This program is distributed in the hope that it will be useful, but WITHOUT | |
11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
13 | * more details. | |
14 | * | |
15 | * You should have received a copy of the GNU General Public License along | |
16 | * with this program; see the file COPYING; if not, write to the Free Software | |
17 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | |
18 | */ | |
19 | #include <zebra.h> | |
20 | ||
21 | #include "memory.h" | |
22 | #include "plist.h" | |
23 | #include "bgpd/bgpd.h" | |
24 | #include "bgpd/bgp_attr.h" | |
25 | #include "bgpd/bgp_regex.h" | |
26 | #include "bgpd/bgp_clist.h" | |
27 | #include "bgpd/bgp_dump.h" | |
28 | #include "bgpd/bgp_filter.h" | |
29 | #include "bgpd/bgp_route.h" | |
30 | #include "bgpd/bgp_vty.h" | |
31 | #include "bgpd/bgp_zebra.h" | |
32 | ||
33 | #ifdef ENABLE_BGP_VNC | |
34 | #include "bgpd/rfapi/rfapi_backend.h" | |
35 | #endif | |
36 | ||
4c391142 PM |
37 | #define OUT_SYMBOL_INFO "\u25ba" |
38 | #define OUT_SYMBOL_OK "\u2714" | |
39 | #define OUT_SYMBOL_NOK "\u2716" | |
40 | ||
41 | #define TEST_ASSERT(T, C) \ | |
42 | do { \ | |
43 | if ((T)->state != TEST_SUCCESS || (C)) \ | |
44 | break; \ | |
45 | (T)->state = TEST_ASSERT_ERROR; \ | |
46 | (T)->error = str_printf("assertion failed: %s (%s:%d)", (#C), \ | |
47 | __FILE__, __LINE__); \ | |
48 | } while (0) | |
49 | ||
50 | #define TEST_ASSERT_EQ(T, A, B) \ | |
51 | do { \ | |
52 | if ((T)->state != TEST_SUCCESS || ((A) == (B))) \ | |
53 | break; \ | |
54 | (T)->state = TEST_ASSERT_ERROR; \ | |
55 | (T)->error = str_printf( \ | |
56 | "assertion failed: %s[%d] == [%d]%s (%s:%d)", (#A), \ | |
57 | (A), (B), (#B), __FILE__, __LINE__); \ | |
58 | } while (0) | |
59 | ||
60 | #define TEST_HANDLER_MAX 5 | |
61 | #define TEST_HANDLER(name) _test_handler_##name | |
62 | #define TEST_HANDLER_DECL(name) \ | |
63 | static void _test_handler_##name( \ | |
64 | struct test *test, struct test_peer_attr *pa, \ | |
65 | struct peer *peer, struct peer *group, bool peer_set, \ | |
66 | bool group_set) | |
67 | ||
68 | #define TEST_ATTR_HANDLER_DECL(name, attr, pval, gval) \ | |
69 | TEST_HANDLER_DECL(name) \ | |
70 | { \ | |
71 | if (peer_set) \ | |
72 | TEST_ASSERT_EQ(test, peer->attr, (pval)); \ | |
73 | else if (peer_group_active(peer) && group_set) \ | |
74 | TEST_ASSERT_EQ(test, peer->attr, (gval)); \ | |
75 | if (group_set) \ | |
76 | TEST_ASSERT_EQ(test, group->attr, (gval)); \ | |
77 | } \ | |
78 | TEST_HANDLER_DECL(name) | |
79 | ||
80 | #define TEST_STR_ATTR_HANDLER_DECL(name, attr, pval, gval) \ | |
81 | TEST_HANDLER_DECL(name) \ | |
82 | { \ | |
83 | if (peer_set) { \ | |
84 | TEST_ASSERT(test, peer->attr != NULL); \ | |
85 | TEST_ASSERT(test, !strcmp(peer->attr, (pval))); \ | |
86 | } else if (peer_group_active(peer) && group_set) { \ | |
87 | TEST_ASSERT(test, peer->attr != NULL); \ | |
88 | TEST_ASSERT(test, !strcmp(peer->attr, (gval))); \ | |
89 | } \ | |
90 | if (group_set) { \ | |
91 | TEST_ASSERT(test, group->attr != NULL); \ | |
92 | TEST_ASSERT(test, !strcmp(group->attr, (gval))); \ | |
93 | } \ | |
94 | } \ | |
95 | TEST_HANDLER_DECL(name) | |
96 | ||
97 | #define TEST_SU_ATTR_HANDLER_DECL(name, attr, pval, gval) \ | |
98 | TEST_HANDLER_DECL(name) \ | |
99 | { \ | |
100 | union sockunion su; \ | |
101 | if (peer_set) { \ | |
102 | str2sockunion(pval, &su); \ | |
103 | TEST_ASSERT(test, !sockunion_cmp(peer->attr, &su)); \ | |
104 | } else if (peer_group_active(peer) && group_set) { \ | |
105 | str2sockunion(gval, &su); \ | |
106 | TEST_ASSERT(test, !sockunion_cmp(group->attr, &su)); \ | |
107 | } \ | |
108 | if (group_set) { \ | |
109 | str2sockunion(gval, &su); \ | |
110 | TEST_ASSERT(test, !sockunion_cmp(group->attr, &su)); \ | |
111 | } \ | |
112 | } \ | |
113 | TEST_HANDLER_DECL(name) | |
114 | ||
9d4f5623 PM |
115 | /* Required variables to link in libbgp */ |
116 | struct zebra_privs_t bgpd_privs = {0}; | |
cf9ac8bf | 117 | struct thread_master *master; |
9d4f5623 PM |
118 | |
119 | enum test_state { | |
120 | TEST_SUCCESS, | |
598a3d42 | 121 | TEST_SKIPPING, |
9d4f5623 PM |
122 | TEST_COMMAND_ERROR, |
123 | TEST_CONFIG_ERROR, | |
124 | TEST_ASSERT_ERROR, | |
598a3d42 | 125 | TEST_CUSTOM_ERROR, |
9d4f5623 PM |
126 | TEST_INTERNAL_ERROR, |
127 | }; | |
128 | ||
598a3d42 PM |
129 | enum test_peer_attr_type { |
130 | PEER_AT_AF_FLAG = 0, | |
131 | PEER_AT_AF_FILTER = 1, | |
132 | PEER_AT_AF_CUSTOM = 2, | |
133 | PEER_AT_GLOBAL_FLAG = 3, | |
134 | PEER_AT_GLOBAL_CUSTOM = 4 | |
135 | }; | |
136 | ||
9d4f5623 PM |
137 | struct test { |
138 | enum test_state state; | |
139 | char *desc; | |
140 | char *error; | |
141 | struct list *log; | |
142 | ||
143 | struct vty *vty; | |
144 | struct bgp *bgp; | |
145 | struct peer *peer; | |
146 | struct peer_group *group; | |
e7103a96 PM |
147 | |
148 | struct { | |
149 | bool use_ibgp; | |
150 | bool use_iface_peer; | |
151 | } o; | |
9d4f5623 PM |
152 | }; |
153 | ||
154 | struct test_config { | |
155 | int local_asn; | |
156 | int peer_asn; | |
157 | const char *peer_address; | |
9fb964de | 158 | const char *peer_interface; |
9d4f5623 PM |
159 | const char *peer_group; |
160 | }; | |
161 | ||
162 | struct test_peer_family { | |
163 | afi_t afi; | |
164 | safi_t safi; | |
165 | }; | |
166 | ||
167 | struct test_peer_attr { | |
168 | const char *cmd; | |
169 | const char *peer_cmd; | |
170 | const char *group_cmd; | |
171 | ||
598a3d42 | 172 | enum test_peer_attr_type type; |
9d4f5623 PM |
173 | union { |
174 | uint32_t flag; | |
175 | struct { | |
176 | uint32_t flag; | |
177 | size_t direct; | |
178 | } filter; | |
179 | } u; | |
180 | struct { | |
9fb964de PM |
181 | bool invert_peer; |
182 | bool invert_group; | |
9d4f5623 | 183 | bool use_ibgp; |
9fb964de | 184 | bool use_iface_peer; |
598a3d42 | 185 | bool skip_xfer_cases; |
9d4f5623 PM |
186 | } o; |
187 | ||
188 | afi_t afi; | |
189 | safi_t safi; | |
190 | struct test_peer_family families[AFI_MAX * SAFI_MAX]; | |
598a3d42 | 191 | |
4c391142 PM |
192 | void (*handlers[TEST_HANDLER_MAX])(struct test *test, |
193 | struct test_peer_attr *pa, | |
194 | struct peer *peer, | |
195 | struct peer *group, bool peer_set, | |
196 | bool group_set); | |
9d4f5623 PM |
197 | }; |
198 | ||
9d4f5623 PM |
199 | static struct test_config cfg = { |
200 | .local_asn = 100, | |
201 | .peer_asn = 200, | |
202 | .peer_address = "1.1.1.1", | |
9fb964de | 203 | .peer_interface = "IP-TEST", |
9d4f5623 PM |
204 | .peer_group = "PG-TEST", |
205 | }; | |
206 | ||
f9067479 PM |
207 | static struct test_peer_family test_default_families[] = { |
208 | {.afi = AFI_IP, .safi = SAFI_UNICAST}, | |
209 | {.afi = AFI_IP, .safi = SAFI_MULTICAST}, | |
210 | {.afi = AFI_IP6, .safi = SAFI_UNICAST}, | |
211 | {.afi = AFI_IP6, .safi = SAFI_MULTICAST}, | |
212 | }; | |
213 | ||
598a3d42 PM |
214 | static char *str_vprintf(const char *fmt, va_list ap) |
215 | { | |
216 | int ret; | |
217 | int buf_size = 0; | |
218 | char *buf = NULL; | |
219 | va_list apc; | |
220 | ||
221 | while (1) { | |
222 | va_copy(apc, ap); | |
223 | ret = vsnprintf(buf, buf_size, fmt, apc); | |
224 | va_end(apc); | |
225 | ||
226 | if (ret >= 0 && ret < buf_size) | |
227 | break; | |
228 | ||
229 | if (ret >= 0) | |
230 | buf_size = ret + 1; | |
231 | else | |
232 | buf_size *= 2; | |
233 | ||
234 | buf = XREALLOC(MTYPE_TMP, buf, buf_size); | |
235 | } | |
236 | ||
237 | return buf; | |
238 | } | |
239 | ||
240 | static char *str_printf(const char *fmt, ...) | |
241 | { | |
242 | char *buf; | |
243 | va_list ap; | |
244 | ||
245 | va_start(ap, fmt); | |
246 | buf = str_vprintf(fmt, ap); | |
247 | va_end(ap); | |
248 | ||
249 | return buf; | |
250 | } | |
251 | ||
4c391142 PM |
252 | TEST_ATTR_HANDLER_DECL(advertisement_interval, v_routeadv, 10, 20); |
253 | TEST_STR_ATTR_HANDLER_DECL(password, password, "FRR-Peer", "FRR-Group"); | |
254 | TEST_ATTR_HANDLER_DECL(local_as, change_local_as, 1, 2); | |
255 | TEST_ATTR_HANDLER_DECL(timers_1, keepalive, 10, 20); | |
256 | TEST_ATTR_HANDLER_DECL(timers_2, holdtime, 30, 60); | |
257 | TEST_SU_ATTR_HANDLER_DECL(update_source_su, update_source, "255.255.255.1", | |
258 | "255.255.255.2"); | |
259 | TEST_STR_ATTR_HANDLER_DECL(update_source_if, update_if, "IF-PEER", "IF-GROUP"); | |
260 | ||
261 | TEST_ATTR_HANDLER_DECL(allowas_in, allowas_in[pa->afi][pa->safi], 1, 2); | |
262 | TEST_STR_ATTR_HANDLER_DECL(default_originate_route_map, | |
263 | default_rmap[pa->afi][pa->safi].name, "RM-PEER", | |
264 | "RM-GROUP"); | |
265 | TEST_STR_ATTR_HANDLER_DECL( | |
266 | distribute_list, | |
267 | filter[pa->afi][pa->safi].dlist[pa->u.filter.direct].name, "DL-PEER", | |
268 | "DL-GROUP"); | |
269 | TEST_STR_ATTR_HANDLER_DECL( | |
270 | filter_list, filter[pa->afi][pa->safi].aslist[pa->u.filter.direct].name, | |
271 | "FL-PEER", "FL-GROUP"); | |
272 | TEST_ATTR_HANDLER_DECL(maximum_prefix, pmax[pa->afi][pa->safi], 10, 20); | |
273 | TEST_ATTR_HANDLER_DECL(maximum_prefix_threshold, | |
274 | pmax_threshold[pa->afi][pa->safi], 1, 2); | |
275 | TEST_ATTR_HANDLER_DECL(maximum_prefix_restart, pmax_restart[pa->afi][pa->safi], | |
276 | 100, 200); | |
277 | TEST_STR_ATTR_HANDLER_DECL( | |
278 | prefix_list, filter[pa->afi][pa->safi].plist[pa->u.filter.direct].name, | |
279 | "PL-PEER", "PL-GROUP"); | |
280 | TEST_STR_ATTR_HANDLER_DECL( | |
281 | route_map, filter[pa->afi][pa->safi].map[pa->u.filter.direct].name, | |
282 | "RM-PEER", "RM-GROUP"); | |
283 | TEST_STR_ATTR_HANDLER_DECL(unsuppress_map, filter[pa->afi][pa->safi].usmap.name, | |
284 | "UM-PEER", "UM-GROUP"); | |
285 | TEST_ATTR_HANDLER_DECL(weight, weight[pa->afi][pa->safi], 100, 200); | |
286 | ||
9d4f5623 PM |
287 | /* clang-format off */ |
288 | static struct test_peer_attr test_peer_attrs[] = { | |
9fb964de | 289 | /* Peer Attributes */ |
598a3d42 PM |
290 | { |
291 | .cmd = "advertisement-interval", | |
292 | .peer_cmd = "advertisement-interval 10", | |
293 | .group_cmd = "advertisement-interval 20", | |
b90a8e13 PM |
294 | .u.flag = PEER_FLAG_ROUTEADV, |
295 | .type = PEER_AT_GLOBAL_FLAG, | |
4c391142 | 296 | .handlers[0] = TEST_HANDLER(advertisement_interval), |
598a3d42 | 297 | }, |
9fb964de PM |
298 | { |
299 | .cmd = "capability dynamic", | |
300 | .u.flag = PEER_FLAG_DYNAMIC_CAPABILITY, | |
301 | .type = PEER_AT_GLOBAL_FLAG, | |
302 | }, | |
303 | { | |
304 | .cmd = "capability extended-nexthop", | |
305 | .u.flag = PEER_FLAG_CAPABILITY_ENHE, | |
306 | .type = PEER_AT_GLOBAL_FLAG, | |
307 | }, | |
308 | { | |
309 | .cmd = "capability extended-nexthop", | |
310 | .u.flag = PEER_FLAG_CAPABILITY_ENHE, | |
311 | .type = PEER_AT_GLOBAL_FLAG, | |
312 | .o.invert_peer = true, | |
313 | .o.use_iface_peer = true, | |
314 | }, | |
a14810f4 PM |
315 | { |
316 | .cmd = "description", | |
317 | .peer_cmd = "description FRR Peer", | |
318 | .group_cmd = "description FRR Group", | |
319 | .type = PEER_AT_GLOBAL_CUSTOM, | |
320 | }, | |
9fb964de PM |
321 | { |
322 | .cmd = "disable-connected-check", | |
323 | .u.flag = PEER_FLAG_DISABLE_CONNECTED_CHECK, | |
324 | .type = PEER_AT_GLOBAL_FLAG, | |
325 | }, | |
326 | { | |
327 | .cmd = "dont-capability-negotiate", | |
328 | .u.flag = PEER_FLAG_DONT_CAPABILITY, | |
329 | .type = PEER_AT_GLOBAL_FLAG, | |
330 | }, | |
331 | { | |
332 | .cmd = "enforce-first-as", | |
333 | .u.flag = PEER_FLAG_ENFORCE_FIRST_AS, | |
334 | .type = PEER_AT_GLOBAL_FLAG, | |
335 | }, | |
a14810f4 PM |
336 | { |
337 | .cmd = "local-as", | |
338 | .peer_cmd = "local-as 1", | |
339 | .group_cmd = "local-as 2", | |
4c391142 PM |
340 | .u.flag = PEER_FLAG_LOCAL_AS, |
341 | .type = PEER_AT_GLOBAL_FLAG, | |
342 | .handlers[0] = TEST_HANDLER(local_as), | |
a14810f4 PM |
343 | }, |
344 | { | |
345 | .cmd = "local-as 1 no-prepend", | |
4c391142 | 346 | .u.flag = PEER_FLAG_LOCAL_AS | PEER_FLAG_LOCAL_AS_NO_PREPEND, |
a14810f4 PM |
347 | .type = PEER_AT_GLOBAL_FLAG, |
348 | }, | |
349 | { | |
350 | .cmd = "local-as 1 no-prepend replace-as", | |
4c391142 | 351 | .u.flag = PEER_FLAG_LOCAL_AS | PEER_FLAG_LOCAL_AS_REPLACE_AS, |
a14810f4 PM |
352 | .type = PEER_AT_GLOBAL_FLAG, |
353 | }, | |
9fb964de PM |
354 | { |
355 | .cmd = "override-capability", | |
356 | .u.flag = PEER_FLAG_OVERRIDE_CAPABILITY, | |
357 | .type = PEER_AT_GLOBAL_FLAG, | |
358 | }, | |
359 | { | |
360 | .cmd = "passive", | |
361 | .u.flag = PEER_FLAG_PASSIVE, | |
362 | .type = PEER_AT_GLOBAL_FLAG, | |
363 | }, | |
a14810f4 PM |
364 | { |
365 | .cmd = "password", | |
366 | .peer_cmd = "password FRR-Peer", | |
367 | .group_cmd = "password FRR-Group", | |
4c391142 PM |
368 | .u.flag = PEER_FLAG_PASSWORD, |
369 | .type = PEER_AT_GLOBAL_FLAG, | |
370 | .handlers[0] = TEST_HANDLER(password), | |
a14810f4 | 371 | }, |
9fb964de PM |
372 | { |
373 | .cmd = "shutdown", | |
374 | .u.flag = PEER_FLAG_SHUTDOWN, | |
375 | .type = PEER_AT_GLOBAL_FLAG, | |
376 | }, | |
377 | { | |
378 | .cmd = "strict-capability-match", | |
379 | .u.flag = PEER_FLAG_STRICT_CAP_MATCH, | |
380 | .type = PEER_AT_GLOBAL_FLAG, | |
381 | }, | |
b90a8e13 PM |
382 | { |
383 | .cmd = "timers", | |
384 | .peer_cmd = "timers 10 30", | |
385 | .group_cmd = "timers 20 60", | |
386 | .u.flag = PEER_FLAG_TIMER, | |
387 | .type = PEER_AT_GLOBAL_FLAG, | |
4c391142 PM |
388 | .handlers[0] = TEST_HANDLER(timers_1), |
389 | .handlers[1] = TEST_HANDLER(timers_2), | |
b90a8e13 PM |
390 | }, |
391 | { | |
392 | .cmd = "timers connect", | |
393 | .peer_cmd = "timers connect 10", | |
394 | .group_cmd = "timers connect 20", | |
395 | .u.flag = PEER_FLAG_TIMER_CONNECT, | |
396 | .type = PEER_AT_GLOBAL_FLAG, | |
397 | }, | |
a14810f4 PM |
398 | { |
399 | .cmd = "update-source", | |
400 | .peer_cmd = "update-source 255.255.255.1", | |
401 | .group_cmd = "update-source 255.255.255.2", | |
4c391142 PM |
402 | .u.flag = PEER_FLAG_UPDATE_SOURCE, |
403 | .type = PEER_AT_GLOBAL_FLAG, | |
404 | .handlers[0] = TEST_HANDLER(update_source_su), | |
a14810f4 PM |
405 | }, |
406 | { | |
407 | .cmd = "update-source", | |
4c391142 PM |
408 | .peer_cmd = "update-source IF-PEER", |
409 | .group_cmd = "update-source IF-GROUP", | |
410 | .u.flag = PEER_FLAG_UPDATE_SOURCE, | |
411 | .type = PEER_AT_GLOBAL_FLAG, | |
412 | .handlers[0] = TEST_HANDLER(update_source_if), | |
a14810f4 | 413 | }, |
9fb964de PM |
414 | |
415 | /* Address Family Attributes */ | |
9d4f5623 PM |
416 | { |
417 | .cmd = "addpath-tx-all-paths", | |
418 | .u.flag = PEER_FLAG_ADDPATH_TX_ALL_PATHS, | |
9d4f5623 PM |
419 | }, |
420 | { | |
421 | .cmd = "addpath-tx-bestpath-per-AS", | |
422 | .u.flag = PEER_FLAG_ADDPATH_TX_BESTPATH_PER_AS, | |
9d4f5623 PM |
423 | }, |
424 | { | |
425 | .cmd = "allowas-in", | |
426 | .peer_cmd = "allowas-in 1", | |
427 | .group_cmd = "allowas-in 2", | |
428 | .u.flag = PEER_FLAG_ALLOWAS_IN, | |
4c391142 | 429 | .handlers[0] = TEST_HANDLER(allowas_in), |
9d4f5623 PM |
430 | }, |
431 | { | |
432 | .cmd = "allowas-in origin", | |
433 | .u.flag = PEER_FLAG_ALLOWAS_IN_ORIGIN, | |
9d4f5623 PM |
434 | }, |
435 | { | |
436 | .cmd = "as-override", | |
437 | .u.flag = PEER_FLAG_AS_OVERRIDE, | |
9d4f5623 PM |
438 | }, |
439 | { | |
440 | .cmd = "attribute-unchanged as-path", | |
441 | .u.flag = PEER_FLAG_AS_PATH_UNCHANGED, | |
9d4f5623 PM |
442 | }, |
443 | { | |
444 | .cmd = "attribute-unchanged next-hop", | |
445 | .u.flag = PEER_FLAG_NEXTHOP_UNCHANGED, | |
9d4f5623 PM |
446 | }, |
447 | { | |
448 | .cmd = "attribute-unchanged med", | |
449 | .u.flag = PEER_FLAG_MED_UNCHANGED, | |
9d4f5623 PM |
450 | }, |
451 | { | |
452 | .cmd = "attribute-unchanged as-path next-hop", | |
453 | .u.flag = PEER_FLAG_AS_PATH_UNCHANGED | |
454 | | PEER_FLAG_NEXTHOP_UNCHANGED, | |
9d4f5623 PM |
455 | }, |
456 | { | |
457 | .cmd = "attribute-unchanged as-path med", | |
458 | .u.flag = PEER_FLAG_AS_PATH_UNCHANGED | |
459 | | PEER_FLAG_MED_UNCHANGED, | |
9d4f5623 PM |
460 | }, |
461 | { | |
462 | .cmd = "attribute-unchanged as-path next-hop med", | |
463 | .u.flag = PEER_FLAG_AS_PATH_UNCHANGED | |
464 | | PEER_FLAG_NEXTHOP_UNCHANGED | |
465 | | PEER_FLAG_MED_UNCHANGED, | |
9d4f5623 PM |
466 | }, |
467 | { | |
468 | .cmd = "capability orf prefix-list send", | |
469 | .u.flag = PEER_FLAG_ORF_PREFIX_SM, | |
9d4f5623 PM |
470 | }, |
471 | { | |
472 | .cmd = "capability orf prefix-list receive", | |
473 | .u.flag = PEER_FLAG_ORF_PREFIX_RM, | |
9d4f5623 PM |
474 | }, |
475 | { | |
476 | .cmd = "capability orf prefix-list both", | |
477 | .u.flag = PEER_FLAG_ORF_PREFIX_SM | PEER_FLAG_ORF_PREFIX_RM, | |
9d4f5623 PM |
478 | }, |
479 | { | |
480 | .cmd = "default-originate", | |
481 | .u.flag = PEER_FLAG_DEFAULT_ORIGINATE, | |
9d4f5623 PM |
482 | }, |
483 | { | |
484 | .cmd = "default-originate route-map", | |
485 | .peer_cmd = "default-originate route-map RM-PEER", | |
486 | .group_cmd = "default-originate route-map RM-GROUP", | |
487 | .u.flag = PEER_FLAG_DEFAULT_ORIGINATE, | |
4c391142 | 488 | .handlers[0] = TEST_HANDLER(default_originate_route_map), |
9d4f5623 | 489 | }, |
e7103a96 PM |
490 | { |
491 | .cmd = "distribute-list", | |
4c391142 PM |
492 | .peer_cmd = "distribute-list DL-PEER in", |
493 | .group_cmd = "distribute-list DL-GROUP in", | |
e7103a96 PM |
494 | .type = PEER_AT_AF_FILTER, |
495 | .u.filter.flag = PEER_FT_DISTRIBUTE_LIST, | |
496 | .u.filter.direct = FILTER_IN, | |
4c391142 | 497 | .handlers[0] = TEST_HANDLER(distribute_list), |
e7103a96 PM |
498 | }, |
499 | { | |
500 | .cmd = "distribute-list", | |
4c391142 PM |
501 | .peer_cmd = "distribute-list DL-PEER out", |
502 | .group_cmd = "distribute-list DL-GROUP out", | |
e7103a96 PM |
503 | .type = PEER_AT_AF_FILTER, |
504 | .u.filter.flag = PEER_FT_DISTRIBUTE_LIST, | |
505 | .u.filter.direct = FILTER_OUT, | |
4c391142 | 506 | .handlers[0] = TEST_HANDLER(distribute_list), |
e7103a96 | 507 | }, |
9d4f5623 PM |
508 | { |
509 | .cmd = "filter-list", | |
510 | .peer_cmd = "filter-list FL-PEER in", | |
511 | .group_cmd = "filter-list FL-GROUP in", | |
512 | .type = PEER_AT_AF_FILTER, | |
513 | .u.filter.flag = PEER_FT_FILTER_LIST, | |
514 | .u.filter.direct = FILTER_IN, | |
4c391142 | 515 | .handlers[0] = TEST_HANDLER(filter_list), |
9d4f5623 PM |
516 | }, |
517 | { | |
518 | .cmd = "filter-list", | |
519 | .peer_cmd = "filter-list FL-PEER out", | |
520 | .group_cmd = "filter-list FL-GROUP out", | |
521 | .type = PEER_AT_AF_FILTER, | |
522 | .u.filter.flag = PEER_FT_FILTER_LIST, | |
523 | .u.filter.direct = FILTER_OUT, | |
4c391142 | 524 | .handlers[0] = TEST_HANDLER(filter_list), |
9d4f5623 PM |
525 | }, |
526 | { | |
527 | .cmd = "maximum-prefix", | |
528 | .peer_cmd = "maximum-prefix 10", | |
529 | .group_cmd = "maximum-prefix 20", | |
530 | .u.flag = PEER_FLAG_MAX_PREFIX, | |
4c391142 | 531 | .handlers[0] = TEST_HANDLER(maximum_prefix), |
9d4f5623 PM |
532 | }, |
533 | { | |
534 | .cmd = "maximum-prefix", | |
535 | .peer_cmd = "maximum-prefix 10 restart 100", | |
536 | .group_cmd = "maximum-prefix 20 restart 200", | |
537 | .u.flag = PEER_FLAG_MAX_PREFIX, | |
4c391142 PM |
538 | .handlers[0] = TEST_HANDLER(maximum_prefix), |
539 | .handlers[1] = TEST_HANDLER(maximum_prefix_restart), | |
9d4f5623 PM |
540 | }, |
541 | { | |
542 | .cmd = "maximum-prefix", | |
543 | .peer_cmd = "maximum-prefix 10 1 restart 100", | |
544 | .group_cmd = "maximum-prefix 20 2 restart 200", | |
545 | .u.flag = PEER_FLAG_MAX_PREFIX, | |
4c391142 PM |
546 | .handlers[0] = TEST_HANDLER(maximum_prefix), |
547 | .handlers[1] = TEST_HANDLER(maximum_prefix_threshold), | |
548 | .handlers[2] = TEST_HANDLER(maximum_prefix_restart), | |
9d4f5623 PM |
549 | }, |
550 | { | |
551 | .cmd = "maximum-prefix", | |
552 | .peer_cmd = "maximum-prefix 10 warning-only", | |
553 | .group_cmd = "maximum-prefix 20 warning-only", | |
554 | .u.flag = PEER_FLAG_MAX_PREFIX | PEER_FLAG_MAX_PREFIX_WARNING, | |
4c391142 | 555 | .handlers[0] = TEST_HANDLER(maximum_prefix), |
9d4f5623 PM |
556 | }, |
557 | { | |
558 | .cmd = "maximum-prefix", | |
559 | .peer_cmd = "maximum-prefix 10 1 warning-only", | |
560 | .group_cmd = "maximum-prefix 20 2 warning-only", | |
561 | .u.flag = PEER_FLAG_MAX_PREFIX | PEER_FLAG_MAX_PREFIX_WARNING, | |
4c391142 PM |
562 | .handlers[0] = TEST_HANDLER(maximum_prefix), |
563 | .handlers[1] = TEST_HANDLER(maximum_prefix_threshold), | |
9d4f5623 PM |
564 | }, |
565 | { | |
566 | .cmd = "next-hop-self", | |
567 | .u.flag = PEER_FLAG_NEXTHOP_SELF, | |
9d4f5623 PM |
568 | }, |
569 | { | |
570 | .cmd = "next-hop-self force", | |
571 | .u.flag = PEER_FLAG_FORCE_NEXTHOP_SELF, | |
9d4f5623 PM |
572 | }, |
573 | { | |
574 | .cmd = "prefix-list", | |
575 | .peer_cmd = "prefix-list PL-PEER in", | |
576 | .group_cmd = "prefix-list PL-GROUP in", | |
577 | .type = PEER_AT_AF_FILTER, | |
578 | .u.filter.flag = PEER_FT_PREFIX_LIST, | |
579 | .u.filter.direct = FILTER_IN, | |
4c391142 | 580 | .handlers[0] = TEST_HANDLER(prefix_list), |
9d4f5623 PM |
581 | }, |
582 | { | |
583 | .cmd = "prefix-list", | |
584 | .peer_cmd = "prefix-list PL-PEER out", | |
585 | .group_cmd = "prefix-list PL-GROUP out", | |
586 | .type = PEER_AT_AF_FILTER, | |
587 | .u.filter.flag = PEER_FT_PREFIX_LIST, | |
588 | .u.filter.direct = FILTER_OUT, | |
4c391142 | 589 | .handlers[0] = TEST_HANDLER(prefix_list), |
9d4f5623 PM |
590 | }, |
591 | { | |
592 | .cmd = "remove-private-AS", | |
593 | .u.flag = PEER_FLAG_REMOVE_PRIVATE_AS, | |
9d4f5623 PM |
594 | }, |
595 | { | |
596 | .cmd = "remove-private-AS all", | |
597 | .u.flag = PEER_FLAG_REMOVE_PRIVATE_AS | |
598 | | PEER_FLAG_REMOVE_PRIVATE_AS_ALL, | |
9d4f5623 PM |
599 | }, |
600 | { | |
601 | .cmd = "remove-private-AS replace-AS", | |
602 | .u.flag = PEER_FLAG_REMOVE_PRIVATE_AS | |
603 | | PEER_FLAG_REMOVE_PRIVATE_AS_REPLACE, | |
9d4f5623 PM |
604 | }, |
605 | { | |
606 | .cmd = "remove-private-AS all replace-AS", | |
607 | .u.flag = PEER_FLAG_REMOVE_PRIVATE_AS_ALL_REPLACE, | |
9d4f5623 PM |
608 | }, |
609 | { | |
610 | .cmd = "route-map", | |
611 | .peer_cmd = "route-map RM-PEER in", | |
612 | .group_cmd = "route-map RM-GROUP in", | |
613 | .type = PEER_AT_AF_FILTER, | |
614 | .u.filter.flag = PEER_FT_ROUTE_MAP, | |
615 | .u.filter.direct = FILTER_IN, | |
4c391142 | 616 | .handlers[0] = TEST_HANDLER(route_map), |
9d4f5623 PM |
617 | }, |
618 | { | |
619 | .cmd = "route-map", | |
620 | .peer_cmd = "route-map RM-PEER out", | |
621 | .group_cmd = "route-map RM-GROUP out", | |
622 | .type = PEER_AT_AF_FILTER, | |
623 | .u.filter.flag = PEER_FT_ROUTE_MAP, | |
624 | .u.filter.direct = FILTER_OUT, | |
4c391142 | 625 | .handlers[0] = TEST_HANDLER(route_map), |
9d4f5623 PM |
626 | }, |
627 | { | |
628 | .cmd = "route-reflector-client", | |
629 | .u.flag = PEER_FLAG_REFLECTOR_CLIENT, | |
630 | .o.use_ibgp = true, | |
598a3d42 | 631 | .o.skip_xfer_cases = true, |
9d4f5623 PM |
632 | }, |
633 | { | |
634 | .cmd = "route-server-client", | |
635 | .u.flag = PEER_FLAG_RSERVER_CLIENT, | |
9d4f5623 PM |
636 | }, |
637 | { | |
638 | .cmd = "send-community", | |
639 | .u.flag = PEER_FLAG_SEND_COMMUNITY, | |
9fb964de PM |
640 | .o.invert_peer = true, |
641 | .o.invert_group = true, | |
9d4f5623 PM |
642 | }, |
643 | { | |
644 | .cmd = "send-community extended", | |
645 | .u.flag = PEER_FLAG_SEND_EXT_COMMUNITY, | |
9fb964de PM |
646 | .o.invert_peer = true, |
647 | .o.invert_group = true, | |
9d4f5623 PM |
648 | }, |
649 | { | |
650 | .cmd = "send-community large", | |
651 | .u.flag = PEER_FLAG_SEND_LARGE_COMMUNITY, | |
9fb964de PM |
652 | .o.invert_peer = true, |
653 | .o.invert_group = true, | |
9d4f5623 PM |
654 | }, |
655 | { | |
656 | .cmd = "soft-reconfiguration inbound", | |
657 | .u.flag = PEER_FLAG_SOFT_RECONFIG, | |
9d4f5623 PM |
658 | }, |
659 | { | |
660 | .cmd = "unsuppress-map", | |
661 | .peer_cmd = "unsuppress-map UM-PEER", | |
662 | .group_cmd = "unsuppress-map UM-GROUP", | |
663 | .type = PEER_AT_AF_FILTER, | |
664 | .u.filter.flag = PEER_FT_UNSUPPRESS_MAP, | |
665 | .u.filter.direct = 0, | |
4c391142 | 666 | .handlers[0] = TEST_HANDLER(unsuppress_map), |
9d4f5623 PM |
667 | }, |
668 | { | |
669 | .cmd = "weight", | |
670 | .peer_cmd = "weight 100", | |
671 | .group_cmd = "weight 200", | |
672 | .u.flag = PEER_FLAG_WEIGHT, | |
4c391142 | 673 | .handlers[0] = TEST_HANDLER(weight), |
9d4f5623 PM |
674 | }, |
675 | {NULL} | |
676 | }; | |
677 | /* clang-format on */ | |
678 | ||
9d4f5623 PM |
679 | static const char *str_from_afi(afi_t afi) |
680 | { | |
681 | switch (afi) { | |
682 | case AFI_IP: | |
683 | return "ipv4"; | |
684 | case AFI_IP6: | |
685 | return "ipv6"; | |
686 | default: | |
687 | return "<unknown AFI>"; | |
688 | } | |
689 | } | |
690 | ||
691 | static const char *str_from_safi(safi_t safi) | |
692 | { | |
693 | switch (safi) { | |
694 | case SAFI_UNICAST: | |
695 | return "unicast"; | |
696 | case SAFI_MULTICAST: | |
697 | return "multicast"; | |
9d4f5623 PM |
698 | default: |
699 | return "<unknown SAFI>"; | |
700 | } | |
701 | } | |
702 | ||
598a3d42 PM |
703 | static const char *str_from_attr_type(enum test_peer_attr_type at) |
704 | { | |
705 | switch (at) { | |
706 | case PEER_AT_GLOBAL_FLAG: | |
707 | return "peer-flag"; | |
708 | case PEER_AT_AF_FLAG: | |
709 | return "af-flag"; | |
710 | case PEER_AT_AF_FILTER: | |
711 | return "af-filter"; | |
712 | case PEER_AT_GLOBAL_CUSTOM: | |
713 | case PEER_AT_AF_CUSTOM: | |
714 | return "custom"; | |
715 | default: | |
716 | return NULL; | |
717 | } | |
718 | } | |
719 | ||
b90a8e13 PM |
720 | static bool is_attr_type_global(enum test_peer_attr_type at) |
721 | { | |
722 | return at == PEER_AT_GLOBAL_FLAG || at == PEER_AT_GLOBAL_CUSTOM; | |
723 | } | |
724 | ||
9fb964de PM |
725 | static void test_log(struct test *test, const char *fmt, ...) |
726 | { | |
727 | va_list ap; | |
728 | ||
729 | /* Skip logging if test instance has previously failed. */ | |
730 | if (test->state != TEST_SUCCESS) | |
731 | return; | |
732 | ||
733 | /* Store formatted log message. */ | |
734 | va_start(ap, fmt); | |
735 | listnode_add(test->log, str_vprintf(fmt, ap)); | |
736 | va_end(ap); | |
737 | } | |
738 | ||
9d4f5623 PM |
739 | static void test_execute(struct test *test, const char *fmt, ...) |
740 | { | |
741 | int ret; | |
742 | char *cmd; | |
743 | va_list ap; | |
744 | vector vline; | |
745 | ||
746 | /* Skip execution if test instance has previously failed. */ | |
747 | if (test->state != TEST_SUCCESS) | |
748 | return; | |
749 | ||
750 | /* Format command string with variadic arguments. */ | |
751 | va_start(ap, fmt); | |
752 | cmd = str_vprintf(fmt, ap); | |
753 | va_end(ap); | |
754 | if (!cmd) { | |
755 | test->state = TEST_INTERNAL_ERROR; | |
756 | test->error = | |
757 | str_printf("could not format command string [%s]", fmt); | |
758 | return; | |
759 | } | |
760 | ||
761 | /* Tokenize formatted command string. */ | |
762 | vline = cmd_make_strvec(cmd); | |
763 | if (vline == NULL) { | |
764 | test->state = TEST_INTERNAL_ERROR; | |
765 | test->error = str_printf( | |
766 | "tokenizing command string [%s] returned empty result", | |
767 | cmd); | |
768 | XFREE(MTYPE_TMP, cmd); | |
769 | ||
770 | return; | |
771 | } | |
772 | ||
773 | /* Execute command (non-strict). */ | |
774 | ret = cmd_execute_command(vline, test->vty, NULL, 0); | |
775 | if (ret != CMD_SUCCESS) { | |
776 | test->state = TEST_COMMAND_ERROR; | |
777 | test->error = str_printf( | |
778 | "execution of command [%s] has failed with code [%d]", | |
779 | cmd, ret); | |
780 | } | |
781 | ||
cf9ac8bf | 782 | /* Free memory. */ |
9d4f5623 PM |
783 | cmd_free_strvec(vline); |
784 | XFREE(MTYPE_TMP, cmd); | |
9d4f5623 PM |
785 | } |
786 | ||
787 | static void test_config(struct test *test, const char *fmt, bool invert, | |
788 | va_list ap) | |
789 | { | |
790 | char *matcher; | |
791 | char *config; | |
792 | bool matched; | |
793 | va_list apc; | |
794 | ||
795 | /* Skip execution if test instance has previously failed. */ | |
796 | if (test->state != TEST_SUCCESS) | |
797 | return; | |
798 | ||
799 | /* Format matcher string with variadic arguments. */ | |
800 | va_copy(apc, ap); | |
801 | matcher = str_vprintf(fmt, apc); | |
802 | va_end(apc); | |
803 | if (!matcher) { | |
804 | test->state = TEST_INTERNAL_ERROR; | |
805 | test->error = | |
806 | str_printf("could not format matcher string [%s]", fmt); | |
807 | return; | |
808 | } | |
809 | ||
810 | /* Fetch BGP configuration into buffer. */ | |
811 | bgp_config_write(test->vty); | |
812 | config = buffer_getstr(test->vty->obuf); | |
813 | buffer_reset(test->vty->obuf); | |
814 | ||
815 | /* Match config against matcher. */ | |
816 | matched = !!strstr(config, matcher); | |
817 | if (!matched && !invert) { | |
818 | test->state = TEST_CONFIG_ERROR; | |
819 | test->error = str_printf("expected config [%s] to be present", | |
820 | matcher); | |
821 | } else if (matched && invert) { | |
822 | test->state = TEST_CONFIG_ERROR; | |
823 | test->error = str_printf("expected config [%s] to be absent", | |
824 | matcher); | |
825 | } | |
826 | ||
827 | /* Free memory and return. */ | |
828 | XFREE(MTYPE_TMP, matcher); | |
829 | XFREE(MTYPE_TMP, config); | |
9d4f5623 PM |
830 | } |
831 | ||
832 | static void test_config_present(struct test *test, const char *fmt, ...) | |
833 | { | |
834 | va_list ap; | |
835 | ||
836 | va_start(ap, fmt); | |
837 | test_config(test, fmt, false, ap); | |
838 | va_end(ap); | |
839 | } | |
840 | ||
841 | static void test_config_absent(struct test *test, const char *fmt, ...) | |
842 | { | |
843 | va_list ap; | |
844 | ||
845 | va_start(ap, fmt); | |
846 | test_config(test, fmt, true, ap); | |
847 | va_end(ap); | |
848 | } | |
849 | ||
e7103a96 | 850 | static void test_initialize(struct test *test) |
9d4f5623 | 851 | { |
9d4f5623 PM |
852 | union sockunion su; |
853 | ||
598a3d42 PM |
854 | /* Skip execution if test instance has previously failed. */ |
855 | if (test->state != TEST_SUCCESS) | |
856 | return; | |
857 | ||
e7103a96 PM |
858 | /* Log message about (re)-initialization */ |
859 | test_log(test, "prepare: %sinitialize bgp test environment", | |
860 | test->bgp ? "re-" : ""); | |
9d4f5623 PM |
861 | |
862 | /* Attempt gracefully to purge previous BGP configuration. */ | |
863 | test_execute(test, "no router bgp"); | |
864 | test->state = TEST_SUCCESS; | |
865 | ||
866 | /* Initialize BGP test environment. */ | |
867 | test_execute(test, "router bgp %d", cfg.local_asn); | |
868 | test_execute(test, "no bgp default ipv4-unicast"); | |
869 | test_execute(test, "neighbor %s peer-group", cfg.peer_group); | |
e7103a96 | 870 | if (test->o.use_iface_peer) { |
9fb964de PM |
871 | test_execute(test, "neighbor %s interface", cfg.peer_interface); |
872 | test_execute(test, "neighbor %s remote-as %d", | |
873 | cfg.peer_interface, | |
e7103a96 | 874 | test->o.use_ibgp ? cfg.local_asn : cfg.peer_asn); |
9fb964de PM |
875 | } else { |
876 | test_execute(test, "neighbor %s remote-as %d", cfg.peer_address, | |
e7103a96 | 877 | test->o.use_ibgp ? cfg.local_asn : cfg.peer_asn); |
9fb964de PM |
878 | } |
879 | ||
9d4f5623 | 880 | if (test->state != TEST_SUCCESS) |
e7103a96 | 881 | return; |
9d4f5623 PM |
882 | |
883 | /* Fetch default BGP instance. */ | |
884 | test->bgp = bgp_get_default(); | |
885 | if (!test->bgp) { | |
886 | test->state = TEST_INTERNAL_ERROR; | |
887 | test->error = | |
888 | str_printf("could not retrieve default bgp instance"); | |
e7103a96 | 889 | return; |
9d4f5623 PM |
890 | } |
891 | ||
892 | /* Fetch peer instance. */ | |
e7103a96 | 893 | if (test->o.use_iface_peer) { |
9fb964de PM |
894 | test->peer = |
895 | peer_lookup_by_conf_if(test->bgp, cfg.peer_interface); | |
896 | } else { | |
897 | str2sockunion(cfg.peer_address, &su); | |
898 | test->peer = peer_lookup(test->bgp, &su); | |
899 | } | |
9d4f5623 PM |
900 | if (!test->peer) { |
901 | test->state = TEST_INTERNAL_ERROR; | |
902 | test->error = str_printf( | |
903 | "could not retrieve instance of bgp peer [%s]", | |
904 | cfg.peer_address); | |
e7103a96 | 905 | return; |
9d4f5623 PM |
906 | } |
907 | ||
908 | /* Fetch peer-group instance. */ | |
909 | test->group = peer_group_lookup(test->bgp, cfg.peer_group); | |
910 | if (!test->group) { | |
911 | test->state = TEST_INTERNAL_ERROR; | |
912 | test->error = str_printf( | |
913 | "could not retrieve instance of bgp peer-group [%s]", | |
914 | cfg.peer_group); | |
e7103a96 | 915 | return; |
9d4f5623 | 916 | } |
e7103a96 PM |
917 | } |
918 | ||
919 | static struct test *test_new(const char *desc, bool use_ibgp, | |
920 | bool use_iface_peer) | |
921 | { | |
922 | struct test *test; | |
923 | ||
924 | test = XCALLOC(MTYPE_TMP, sizeof(struct test)); | |
925 | test->state = TEST_SUCCESS; | |
926 | test->desc = XSTRDUP(MTYPE_TMP, desc); | |
927 | test->log = list_new(); | |
928 | test->o.use_ibgp = use_ibgp; | |
929 | test->o.use_iface_peer = use_iface_peer; | |
930 | ||
931 | test->vty = vty_new(); | |
932 | test->vty->type = VTY_TERM; | |
933 | test->vty->node = CONFIG_NODE; | |
934 | ||
935 | test_initialize(test); | |
9d4f5623 PM |
936 | |
937 | return test; | |
938 | }; | |
939 | ||
9d4f5623 PM |
940 | static void test_finish(struct test *test) |
941 | { | |
942 | char *msg; | |
943 | struct listnode *node, *nnode; | |
944 | ||
945 | /* Print test output header. */ | |
946 | printf("%s [test] %s\n", | |
947 | (test->state == TEST_SUCCESS) ? OUT_SYMBOL_OK : OUT_SYMBOL_NOK, | |
948 | test->desc); | |
949 | ||
950 | /* Print test log messages. */ | |
951 | for (ALL_LIST_ELEMENTS(test->log, node, nnode, msg)) { | |
952 | printf("%s %s\n", OUT_SYMBOL_INFO, msg); | |
953 | XFREE(MTYPE_TMP, msg); | |
954 | } | |
955 | ||
956 | /* Print test error message if available. */ | |
957 | if (test->state != TEST_SUCCESS && test->error) | |
958 | printf("%s error: %s\n", OUT_SYMBOL_INFO, test->error); | |
959 | ||
960 | /* Print machine-readable result of test. */ | |
961 | printf("%s\n", test->state == TEST_SUCCESS ? "OK" : "failed"); | |
962 | ||
963 | /* Cleanup allocated memory. */ | |
964 | if (test->vty) { | |
965 | vty_close(test->vty); | |
966 | test->vty = NULL; | |
967 | } | |
968 | if (test->log) | |
6a154c88 | 969 | list_delete(&test->log); |
9d4f5623 PM |
970 | if (test->desc) |
971 | XFREE(MTYPE_TMP, test->desc); | |
972 | if (test->error) | |
973 | XFREE(MTYPE_TMP, test->error); | |
974 | XFREE(MTYPE_TMP, test); | |
975 | } | |
976 | ||
598a3d42 PM |
977 | static void test_peer_flags(struct test *test, struct test_peer_attr *pa, |
978 | struct peer *peer, bool exp_val, bool exp_ovrd) | |
f9067479 PM |
979 | { |
980 | bool exp_inv, cur_val, cur_ovrd, cur_inv; | |
981 | ||
9fb964de PM |
982 | /* Skip execution if test instance has previously failed. */ |
983 | if (test->state != TEST_SUCCESS) | |
984 | return; | |
985 | ||
986 | /* Detect if flag is meant to be inverted. */ | |
987 | if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) | |
598a3d42 | 988 | exp_inv = pa->o.invert_group; |
9fb964de | 989 | else |
598a3d42 | 990 | exp_inv = pa->o.invert_peer; |
9fb964de PM |
991 | |
992 | /* Flip expected value if flag is inverted. */ | |
f9067479 PM |
993 | exp_val ^= exp_inv; |
994 | ||
995 | /* Fetch current state of value, override and invert flags. */ | |
598a3d42 PM |
996 | if (pa->type == PEER_AT_GLOBAL_FLAG) { |
997 | cur_val = !!CHECK_FLAG(peer->flags, pa->u.flag); | |
998 | cur_ovrd = !!CHECK_FLAG(peer->flags_override, pa->u.flag); | |
999 | cur_inv = !!CHECK_FLAG(peer->flags_invert, pa->u.flag); | |
1000 | } else /* if (pa->type == PEER_AT_AF_FLAG) */ { | |
1001 | cur_val = !!CHECK_FLAG(peer->af_flags[pa->afi][pa->safi], | |
1002 | pa->u.flag); | |
9fb964de | 1003 | cur_ovrd = !!CHECK_FLAG( |
598a3d42 PM |
1004 | peer->af_flags_override[pa->afi][pa->safi], pa->u.flag); |
1005 | cur_inv = !!CHECK_FLAG(peer->af_flags_invert[pa->afi][pa->safi], | |
1006 | pa->u.flag); | |
9fb964de | 1007 | } |
f9067479 PM |
1008 | |
1009 | /* Assert expected flag states. */ | |
1010 | TEST_ASSERT_EQ(test, cur_val, exp_val); | |
1011 | TEST_ASSERT_EQ(test, cur_ovrd, exp_ovrd); | |
1012 | TEST_ASSERT_EQ(test, cur_inv, exp_inv); | |
1013 | } | |
1014 | ||
598a3d42 PM |
1015 | static void test_af_filter(struct test *test, struct test_peer_attr *pa, |
1016 | struct peer *peer, bool exp_state, bool exp_ovrd) | |
f9067479 PM |
1017 | { |
1018 | bool cur_ovrd; | |
1019 | struct bgp_filter *filter; | |
1020 | ||
9fb964de PM |
1021 | /* Skip execution if test instance has previously failed. */ |
1022 | if (test->state != TEST_SUCCESS) | |
1023 | return; | |
1024 | ||
f9067479 | 1025 | /* Fetch and assert current state of override flag. */ |
598a3d42 PM |
1026 | cur_ovrd = !!CHECK_FLAG( |
1027 | peer->filter_override[pa->afi][pa->safi][pa->u.filter.direct], | |
1028 | pa->u.filter.flag); | |
f9067479 PM |
1029 | |
1030 | TEST_ASSERT_EQ(test, cur_ovrd, exp_ovrd); | |
1031 | ||
1032 | /* Assert that map/list matches expected state (set/unset). */ | |
598a3d42 | 1033 | filter = &peer->filter[pa->afi][pa->safi]; |
f9067479 | 1034 | |
598a3d42 | 1035 | switch (pa->u.filter.flag) { |
f9067479 PM |
1036 | case PEER_FT_DISTRIBUTE_LIST: |
1037 | TEST_ASSERT_EQ(test, | |
598a3d42 | 1038 | !!(filter->dlist[pa->u.filter.direct].name), |
f9067479 PM |
1039 | exp_state); |
1040 | break; | |
1041 | case PEER_FT_FILTER_LIST: | |
1042 | TEST_ASSERT_EQ(test, | |
598a3d42 | 1043 | !!(filter->aslist[pa->u.filter.direct].name), |
f9067479 PM |
1044 | exp_state); |
1045 | break; | |
1046 | case PEER_FT_PREFIX_LIST: | |
1047 | TEST_ASSERT_EQ(test, | |
598a3d42 | 1048 | !!(filter->plist[pa->u.filter.direct].name), |
f9067479 PM |
1049 | exp_state); |
1050 | break; | |
1051 | case PEER_FT_ROUTE_MAP: | |
598a3d42 | 1052 | TEST_ASSERT_EQ(test, !!(filter->map[pa->u.filter.direct].name), |
f9067479 PM |
1053 | exp_state); |
1054 | break; | |
1055 | case PEER_FT_UNSUPPRESS_MAP: | |
1056 | TEST_ASSERT_EQ(test, !!(filter->usmap.name), exp_state); | |
1057 | break; | |
1058 | } | |
1059 | } | |
1060 | ||
598a3d42 PM |
1061 | static void test_custom(struct test *test, struct test_peer_attr *pa, |
1062 | struct peer *peer, struct peer *group, bool peer_set, | |
1063 | bool group_set) | |
1064 | { | |
4c391142 | 1065 | int i; |
598a3d42 PM |
1066 | char *handler_error; |
1067 | ||
4c391142 PM |
1068 | for (i = 0; i < TEST_HANDLER_MAX; i++) { |
1069 | /* Skip execution if test instance has previously failed. */ | |
1070 | if (test->state != TEST_SUCCESS) | |
1071 | return; | |
1072 | ||
1073 | /* Skip further execution if handler is undefined. */ | |
1074 | if (!pa->handlers[i]) | |
1075 | return; | |
1076 | ||
1077 | /* Execute custom handler. */ | |
1078 | pa->handlers[i](test, pa, peer, group, peer_set, group_set); | |
1079 | if (test->state != TEST_SUCCESS) { | |
1080 | test->state = TEST_CUSTOM_ERROR; | |
1081 | handler_error = test->error; | |
1082 | test->error = str_printf("custom handler failed: %s", | |
1083 | handler_error); | |
1084 | XFREE(MTYPE_TMP, handler_error); | |
1085 | } | |
598a3d42 PM |
1086 | } |
1087 | } | |
1088 | ||
1089 | ||
1090 | static void test_process(struct test *test, struct test_peer_attr *pa, | |
1091 | struct peer *peer, struct peer *group, bool peer_set, | |
1092 | bool group_set) | |
1093 | { | |
1094 | switch (pa->type) { | |
1095 | case PEER_AT_GLOBAL_FLAG: | |
1096 | case PEER_AT_AF_FLAG: | |
4c391142 PM |
1097 | test_peer_flags( |
1098 | test, pa, peer, | |
1099 | peer_set || (peer_group_active(peer) && group_set), | |
1100 | peer_set); | |
598a3d42 PM |
1101 | test_peer_flags(test, pa, group, group_set, false); |
1102 | break; | |
1103 | ||
1104 | case PEER_AT_AF_FILTER: | |
4c391142 PM |
1105 | test_af_filter( |
1106 | test, pa, peer, | |
1107 | peer_set || (peer_group_active(peer) && group_set), | |
1108 | peer_set); | |
598a3d42 PM |
1109 | test_af_filter(test, pa, group, group_set, false); |
1110 | break; | |
1111 | ||
1112 | case PEER_AT_GLOBAL_CUSTOM: | |
1113 | case PEER_AT_AF_CUSTOM: | |
1114 | /* | |
1115 | * Do nothing here - a custom handler can be executed, but this | |
1116 | * is not required. This will allow defining peer attributes | |
1117 | * which shall not be checked for flag/filter/other internal | |
1118 | * states. | |
1119 | */ | |
1120 | break; | |
1121 | ||
1122 | default: | |
1123 | test->state = TEST_INTERNAL_ERROR; | |
1124 | test->error = | |
1125 | str_printf("invalid attribute type: %d", pa->type); | |
1126 | break; | |
1127 | } | |
1128 | ||
1129 | /* Attempt to call a custom handler if set for further processing. */ | |
1130 | test_custom(test, pa, peer, group, peer_set, group_set); | |
1131 | } | |
1132 | ||
9d4f5623 PM |
1133 | static void test_peer_attr(struct test *test, struct test_peer_attr *pa) |
1134 | { | |
1135 | int tc = 1; | |
f9067479 | 1136 | const char *type; |
9fb964de PM |
1137 | const char *ecp = pa->o.invert_peer ? "no " : ""; |
1138 | const char *dcp = pa->o.invert_peer ? "" : "no "; | |
1139 | const char *ecg = pa->o.invert_group ? "no " : ""; | |
1140 | const char *dcg = pa->o.invert_group ? "" : "no "; | |
9d4f5623 PM |
1141 | const char *peer_cmd = pa->peer_cmd ?: pa->cmd; |
1142 | const char *group_cmd = pa->group_cmd ?: pa->cmd; | |
1143 | struct peer *p = test->peer; | |
1144 | struct peer_group *g = test->group; | |
1145 | ||
598a3d42 PM |
1146 | /* Determine type and if test is address-family relevant */ |
1147 | type = str_from_attr_type(pa->type); | |
1148 | if (!type) { | |
9fb964de PM |
1149 | test->state = TEST_INTERNAL_ERROR; |
1150 | test->error = | |
1151 | str_printf("invalid attribute type: %d", pa->type); | |
1152 | return; | |
1153 | } | |
f9067479 | 1154 | |
4c391142 PM |
1155 | /* |
1156 | * ===================================================================== | |
1157 | * Test Case Suite 1: Config persistence after adding peer to group | |
1158 | * | |
1159 | * Example: If a peer attribute has value [1] and a group attribute has | |
1160 | * value [2], the peer attribute value should be persisted when the peer | |
1161 | * gets added to the peer-group. | |
1162 | * | |
1163 | * This test suite is meant to test the group2peer functions which can | |
1164 | * be found inside bgpd/bgpd.c, which are related to initial peer-group | |
1165 | * inheritance. | |
1166 | * ===================================================================== | |
1167 | */ | |
1168 | ||
e7103a96 | 1169 | /* Test Preparation: Switch and activate address-family. */ |
b90a8e13 | 1170 | if (!is_attr_type_global(pa->type)) { |
e7103a96 PM |
1171 | test_log(test, "prepare: switch address-family to [%s]", |
1172 | afi_safi_print(pa->afi, pa->safi)); | |
1173 | test_execute(test, "address-family %s %s", | |
1174 | str_from_afi(pa->afi), str_from_safi(pa->safi)); | |
1175 | test_execute(test, "neighbor %s activate", g->name); | |
1176 | test_execute(test, "neighbor %s activate", p->host); | |
1177 | } | |
1178 | ||
598a3d42 PM |
1179 | /* Skip peer-group to peer transfer test cases if requested. */ |
1180 | if (pa->o.skip_xfer_cases && test->state == TEST_SUCCESS) | |
1181 | test->state = TEST_SKIPPING; | |
1182 | ||
e7103a96 PM |
1183 | /* Test Case: Set flag on BGP peer. */ |
1184 | test_log(test, "case %02d: set %s [%s] on [%s]", tc++, type, peer_cmd, | |
1185 | p->host); | |
1186 | test_execute(test, "%sneighbor %s %s", ecp, p->host, peer_cmd); | |
1187 | test_config_present(test, "%sneighbor %s %s", ecp, p->host, peer_cmd); | |
1188 | test_config_absent(test, "neighbor %s %s", g->name, pa->cmd); | |
598a3d42 | 1189 | test_process(test, pa, p, g->conf, true, false); |
e7103a96 PM |
1190 | |
1191 | /* Test Case: Set flag on BGP peer-group. */ | |
1192 | test_log(test, "case %02d: set %s [%s] on [%s]", tc++, type, group_cmd, | |
1193 | g->name); | |
1194 | test_execute(test, "%sneighbor %s %s", ecg, g->name, group_cmd); | |
1195 | test_config_present(test, "%sneighbor %s %s", ecp, p->host, peer_cmd); | |
1196 | test_config_present(test, "%sneighbor %s %s", ecg, g->name, group_cmd); | |
598a3d42 | 1197 | test_process(test, pa, p, g->conf, true, true); |
e7103a96 PM |
1198 | |
1199 | /* Test Case: Add BGP peer to peer-group. */ | |
1200 | test_log(test, "case %02d: add peer [%s] to group [%s]", tc++, p->host, | |
1201 | g->name); | |
1202 | test_execute(test, "neighbor %s peer-group %s", p->host, g->name); | |
1203 | test_config_present(test, "neighbor %s %speer-group %s", p->host, | |
1204 | p->conf_if ? "interface " : "", g->name); | |
1205 | test_config_present(test, "%sneighbor %s %s", ecp, p->host, peer_cmd); | |
1206 | test_config_present(test, "%sneighbor %s %s", ecg, g->name, group_cmd); | |
598a3d42 | 1207 | test_process(test, pa, p, g->conf, true, true); |
e7103a96 PM |
1208 | |
1209 | /* Test Case: Unset flag on BGP peer-group. */ | |
1210 | test_log(test, "case %02d: unset %s [%s] on [%s]", tc++, type, | |
1211 | group_cmd, g->name); | |
1212 | test_execute(test, "%sneighbor %s %s", dcg, g->name, group_cmd); | |
1213 | test_config_present(test, "%sneighbor %s %s", ecp, p->host, peer_cmd); | |
1214 | test_config_absent(test, "neighbor %s %s", g->name, pa->cmd); | |
598a3d42 PM |
1215 | test_process(test, pa, p, g->conf, true, false); |
1216 | ||
4c391142 PM |
1217 | /* |
1218 | * ===================================================================== | |
1219 | * Test Case Suite 2: Config inheritance after adding peer to group | |
1220 | * | |
1221 | * Example: If a peer attribute has not been set and a group attribute | |
1222 | * has a value of [2], the group attribute should be inherited to the | |
1223 | * peer without flagging the newly set value as overridden. | |
1224 | * | |
1225 | * This test suite is meant to test the group2peer functions which can | |
1226 | * be found inside bgpd/bgpd.c, which are related to initial peer-group | |
1227 | * inheritance. | |
1228 | * ===================================================================== | |
1229 | */ | |
1230 | ||
1231 | /* Test Preparation: Re-initialize test environment. */ | |
1232 | test_initialize(test); | |
1233 | p = test->peer; | |
1234 | g = test->group; | |
1235 | ||
1236 | /* Test Preparation: Switch and activate address-family. */ | |
1237 | if (!is_attr_type_global(pa->type)) { | |
1238 | test_log(test, "prepare: switch address-family to [%s]", | |
1239 | afi_safi_print(pa->afi, pa->safi)); | |
1240 | test_execute(test, "address-family %s %s", | |
1241 | str_from_afi(pa->afi), str_from_safi(pa->safi)); | |
1242 | test_execute(test, "neighbor %s activate", g->name); | |
1243 | test_execute(test, "neighbor %s activate", p->host); | |
1244 | } | |
1245 | ||
1246 | /* Test Case: Set flag on BGP peer-group. */ | |
1247 | test_log(test, "case %02d: set %s [%s] on [%s]", tc++, type, group_cmd, | |
1248 | g->name); | |
1249 | test_execute(test, "%sneighbor %s %s", ecg, g->name, group_cmd); | |
1250 | test_config_absent(test, "neighbor %s %s", p->host, pa->cmd); | |
1251 | test_config_present(test, "%sneighbor %s %s", ecg, g->name, group_cmd); | |
1252 | test_process(test, pa, p, g->conf, false, true); | |
1253 | ||
1254 | /* Test Case: Add BGP peer to peer-group. */ | |
1255 | test_log(test, "case %02d: add peer [%s] to group [%s]", tc++, p->host, | |
1256 | g->name); | |
1257 | test_execute(test, "neighbor %s peer-group %s", p->host, g->name); | |
1258 | test_config_present(test, "neighbor %s %speer-group %s", p->host, | |
1259 | p->conf_if ? "interface " : "", g->name); | |
1260 | test_config_absent(test, "neighbor %s %s", p->host, pa->cmd); | |
1261 | test_config_present(test, "%sneighbor %s %s", ecg, g->name, group_cmd); | |
1262 | test_process(test, pa, p, g->conf, false, true); | |
1263 | ||
598a3d42 PM |
1264 | /* Stop skipping test cases if previously enabled. */ |
1265 | if (pa->o.skip_xfer_cases && test->state == TEST_SKIPPING) | |
1266 | test->state = TEST_SUCCESS; | |
e7103a96 | 1267 | |
4c391142 PM |
1268 | /* |
1269 | * ===================================================================== | |
1270 | * Test Case Suite 3: Miscellaneous flag checks | |
1271 | * | |
1272 | * This test suite does not focus on initial peer-group inheritance and | |
1273 | * instead executes various different commands to set/unset attributes | |
1274 | * on both peer- and group-level. These checks should always be executed | |
1275 | * and must pass. | |
1276 | * ===================================================================== | |
1277 | */ | |
1278 | ||
e7103a96 PM |
1279 | /* Test Preparation: Re-initialize test environment. */ |
1280 | test_initialize(test); | |
1281 | p = test->peer; | |
1282 | g = test->group; | |
1283 | ||
1284 | /* Test Preparation: Switch and activate address-family. */ | |
b90a8e13 | 1285 | if (!is_attr_type_global(pa->type)) { |
9d4f5623 PM |
1286 | test_log(test, "prepare: switch address-family to [%s]", |
1287 | afi_safi_print(pa->afi, pa->safi)); | |
1288 | test_execute(test, "address-family %s %s", | |
1289 | str_from_afi(pa->afi), str_from_safi(pa->safi)); | |
e7103a96 PM |
1290 | test_execute(test, "neighbor %s activate", g->name); |
1291 | test_execute(test, "neighbor %s activate", p->host); | |
9d4f5623 PM |
1292 | } |
1293 | ||
1294 | /* Test Case: Set flag on BGP peer. */ | |
f9067479 | 1295 | test_log(test, "case %02d: set %s [%s] on [%s]", tc++, type, peer_cmd, |
9d4f5623 | 1296 | p->host); |
9fb964de PM |
1297 | test_execute(test, "%sneighbor %s %s", ecp, p->host, peer_cmd); |
1298 | test_config_present(test, "%sneighbor %s %s", ecp, p->host, peer_cmd); | |
9d4f5623 | 1299 | test_config_absent(test, "neighbor %s %s", g->name, pa->cmd); |
598a3d42 | 1300 | test_process(test, pa, p, g->conf, true, false); |
9d4f5623 PM |
1301 | |
1302 | /* Test Case: Add BGP peer to peer-group. */ | |
1303 | test_log(test, "case %02d: add peer [%s] to group [%s]", tc++, p->host, | |
1304 | g->name); | |
1305 | test_execute(test, "neighbor %s peer-group %s", p->host, g->name); | |
9fb964de PM |
1306 | test_config_present(test, "neighbor %s %speer-group %s", p->host, |
1307 | p->conf_if ? "interface " : "", g->name); | |
1308 | test_config_present(test, "%sneighbor %s %s", ecp, p->host, peer_cmd); | |
9d4f5623 | 1309 | test_config_absent(test, "neighbor %s %s", g->name, pa->cmd); |
598a3d42 | 1310 | test_process(test, pa, p, g->conf, true, false); |
9d4f5623 PM |
1311 | |
1312 | /* Test Case: Re-add BGP peer to peer-group. */ | |
1313 | test_log(test, "case %02d: re-add peer [%s] to group [%s]", tc++, | |
1314 | p->host, g->name); | |
1315 | test_execute(test, "neighbor %s peer-group %s", p->host, g->name); | |
9fb964de PM |
1316 | test_config_present(test, "neighbor %s %speer-group %s", p->host, |
1317 | p->conf_if ? "interface " : "", g->name); | |
1318 | test_config_present(test, "%sneighbor %s %s", ecp, p->host, peer_cmd); | |
9d4f5623 | 1319 | test_config_absent(test, "neighbor %s %s", g->name, pa->cmd); |
598a3d42 | 1320 | test_process(test, pa, p, g->conf, true, false); |
9d4f5623 PM |
1321 | |
1322 | /* Test Case: Set flag on BGP peer-group. */ | |
f9067479 | 1323 | test_log(test, "case %02d: set %s [%s] on [%s]", tc++, type, group_cmd, |
9d4f5623 | 1324 | g->name); |
9fb964de PM |
1325 | test_execute(test, "%sneighbor %s %s", ecg, g->name, group_cmd); |
1326 | test_config_present(test, "%sneighbor %s %s", ecp, p->host, peer_cmd); | |
1327 | test_config_present(test, "%sneighbor %s %s", ecg, g->name, group_cmd); | |
598a3d42 | 1328 | test_process(test, pa, p, g->conf, true, true); |
9d4f5623 PM |
1329 | |
1330 | /* Test Case: Unset flag on BGP peer-group. */ | |
f9067479 PM |
1331 | test_log(test, "case %02d: unset %s [%s] on [%s]", tc++, type, |
1332 | group_cmd, g->name); | |
9fb964de PM |
1333 | test_execute(test, "%sneighbor %s %s", dcg, g->name, group_cmd); |
1334 | test_config_present(test, "%sneighbor %s %s", ecp, p->host, peer_cmd); | |
9d4f5623 | 1335 | test_config_absent(test, "neighbor %s %s", g->name, pa->cmd); |
598a3d42 | 1336 | test_process(test, pa, p, g->conf, true, false); |
9d4f5623 PM |
1337 | |
1338 | /* Test Case: Set flag on BGP peer-group. */ | |
f9067479 | 1339 | test_log(test, "case %02d: set %s [%s] on [%s]", tc++, type, group_cmd, |
9d4f5623 | 1340 | g->name); |
9fb964de PM |
1341 | test_execute(test, "%sneighbor %s %s", ecg, g->name, group_cmd); |
1342 | test_config_present(test, "%sneighbor %s %s", ecp, p->host, peer_cmd); | |
1343 | test_config_present(test, "%sneighbor %s %s", ecg, g->name, group_cmd); | |
598a3d42 | 1344 | test_process(test, pa, p, g->conf, true, true); |
9d4f5623 PM |
1345 | |
1346 | /* Test Case: Re-set flag on BGP peer. */ | |
f9067479 PM |
1347 | test_log(test, "case %02d: re-set %s [%s] on [%s]", tc++, type, |
1348 | peer_cmd, p->host); | |
9fb964de PM |
1349 | test_execute(test, "%sneighbor %s %s", ecp, p->host, peer_cmd); |
1350 | test_config_present(test, "%sneighbor %s %s", ecp, p->host, peer_cmd); | |
1351 | test_config_present(test, "%sneighbor %s %s", ecg, g->name, group_cmd); | |
598a3d42 | 1352 | test_process(test, pa, p, g->conf, true, true); |
9d4f5623 PM |
1353 | |
1354 | /* Test Case: Unset flag on BGP peer. */ | |
f9067479 | 1355 | test_log(test, "case %02d: unset %s [%s] on [%s]", tc++, type, peer_cmd, |
9d4f5623 | 1356 | p->host); |
9fb964de | 1357 | test_execute(test, "%sneighbor %s %s", dcp, p->host, peer_cmd); |
9d4f5623 | 1358 | test_config_absent(test, "neighbor %s %s", p->host, pa->cmd); |
9fb964de | 1359 | test_config_present(test, "%sneighbor %s %s", ecg, g->name, group_cmd); |
598a3d42 | 1360 | test_process(test, pa, p, g->conf, false, true); |
9d4f5623 PM |
1361 | |
1362 | /* Test Case: Unset flag on BGP peer-group. */ | |
f9067479 PM |
1363 | test_log(test, "case %02d: unset %s [%s] on [%s]", tc++, type, |
1364 | group_cmd, g->name); | |
9fb964de | 1365 | test_execute(test, "%sneighbor %s %s", dcg, g->name, group_cmd); |
9d4f5623 PM |
1366 | test_config_absent(test, "neighbor %s %s", p->host, pa->cmd); |
1367 | test_config_absent(test, "neighbor %s %s", g->name, pa->cmd); | |
598a3d42 | 1368 | test_process(test, pa, p, g->conf, false, false); |
9d4f5623 PM |
1369 | |
1370 | /* Test Case: Set flag on BGP peer. */ | |
f9067479 | 1371 | test_log(test, "case %02d: set %s [%s] on [%s]", tc++, type, peer_cmd, |
9d4f5623 | 1372 | p->host); |
9fb964de PM |
1373 | test_execute(test, "%sneighbor %s %s", ecp, p->host, peer_cmd); |
1374 | test_config_present(test, "%sneighbor %s %s", ecp, p->host, peer_cmd); | |
9d4f5623 | 1375 | test_config_absent(test, "neighbor %s %s", g->name, pa->cmd); |
598a3d42 | 1376 | test_process(test, pa, p, g->conf, true, false); |
9d4f5623 PM |
1377 | } |
1378 | ||
cf9ac8bf | 1379 | static void bgp_startup(void) |
9d4f5623 PM |
1380 | { |
1381 | cmd_init(1); | |
1382 | openzlog("testbgpd", "NONE", 0, LOG_CONS | LOG_NDELAY | LOG_PID, | |
1383 | LOG_DAEMON); | |
1384 | zprivs_preinit(&bgpd_privs); | |
1385 | zprivs_init(&bgpd_privs); | |
1c2facd1 RW |
1386 | yang_init(); |
1387 | nb_init(NULL, 0); | |
9d4f5623 PM |
1388 | |
1389 | master = thread_master_create(NULL); | |
1390 | bgp_master_init(master); | |
1391 | bgp_option_set(BGP_OPT_NO_LISTEN); | |
ecbc5a37 | 1392 | vrf_init(NULL, NULL, NULL, NULL, NULL); |
20ae4acd | 1393 | bgp_init(0); |
9d4f5623 PM |
1394 | bgp_pthreads_run(); |
1395 | } | |
1396 | ||
cf9ac8bf | 1397 | static void bgp_shutdown(void) |
9d4f5623 PM |
1398 | { |
1399 | struct bgp *bgp; | |
1400 | struct listnode *node, *nnode; | |
1401 | ||
1402 | bgp_terminate(); | |
1403 | bgp_close(); | |
1404 | for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) | |
1405 | bgp_delete(bgp); | |
1406 | bgp_dump_finish(); | |
1407 | bgp_route_finish(); | |
1408 | bgp_route_map_terminate(); | |
1409 | bgp_attr_finish(); | |
1410 | bgp_pthreads_finish(); | |
1411 | access_list_add_hook(NULL); | |
1412 | access_list_delete_hook(NULL); | |
1413 | access_list_reset(); | |
1414 | as_list_add_hook(NULL); | |
1415 | as_list_delete_hook(NULL); | |
1416 | bgp_filter_reset(); | |
1417 | prefix_list_add_hook(NULL); | |
1418 | prefix_list_delete_hook(NULL); | |
1419 | prefix_list_reset(); | |
1420 | community_list_terminate(bgp_clist); | |
1421 | vrf_terminate(); | |
1422 | #ifdef ENABLE_BGP_VNC | |
1423 | vnc_zebra_destroy(); | |
1424 | #endif | |
1425 | bgp_zebra_destroy(); | |
1426 | ||
1427 | bf_free(bm->rd_idspace); | |
6a154c88 | 1428 | list_delete(&bm->bgp); |
9d4f5623 PM |
1429 | memset(bm, 0, sizeof(*bm)); |
1430 | ||
1431 | vty_terminate(); | |
1432 | cmd_terminate(); | |
1c2facd1 RW |
1433 | nb_terminate(); |
1434 | yang_terminate(); | |
9d4f5623 PM |
1435 | zprivs_terminate(&bgpd_privs); |
1436 | thread_master_free(master); | |
1437 | master = NULL; | |
1438 | closezlog(); | |
1439 | } | |
1440 | ||
1441 | int main(void) | |
1442 | { | |
1443 | int i, ii; | |
1444 | struct list *pa_list; | |
1445 | struct test_peer_attr *pa, *pac; | |
1446 | struct listnode *node, *nnode; | |
1447 | ||
1448 | bgp_startup(); | |
1449 | ||
1450 | pa_list = list_new(); | |
1451 | i = 0; | |
1452 | while (test_peer_attrs[i].cmd) { | |
1453 | pa = &test_peer_attrs[i++]; | |
1454 | ||
f9067479 | 1455 | /* Just copy the peer attribute structure for global flags. */ |
b90a8e13 | 1456 | if (is_attr_type_global(pa->type)) { |
f9067479 PM |
1457 | pac = XMALLOC(MTYPE_TMP, sizeof(struct test_peer_attr)); |
1458 | memcpy(pac, pa, sizeof(struct test_peer_attr)); | |
1459 | listnode_add(pa_list, pac); | |
1460 | continue; | |
1461 | } | |
9d4f5623 | 1462 | |
f9067479 PM |
1463 | /* Fallback to default families if not specified. */ |
1464 | if (!pa->families[0].afi && !pa->families[0].safi) | |
1465 | memcpy(&pa->families, test_default_families, | |
1466 | sizeof(test_default_families)); | |
9d4f5623 | 1467 | |
f9067479 PM |
1468 | /* Add peer attribute definition for each address family. */ |
1469 | ii = 0; | |
1470 | while (pa->families[ii].afi && pa->families[ii].safi) { | |
9d4f5623 PM |
1471 | pac = XMALLOC(MTYPE_TMP, sizeof(struct test_peer_attr)); |
1472 | memcpy(pac, pa, sizeof(struct test_peer_attr)); | |
f9067479 PM |
1473 | |
1474 | pac->afi = pa->families[ii].afi; | |
1475 | pac->safi = pa->families[ii].safi; | |
9d4f5623 | 1476 | listnode_add(pa_list, pac); |
f9067479 PM |
1477 | |
1478 | ii++; | |
9d4f5623 PM |
1479 | } |
1480 | } | |
1481 | ||
1482 | for (ALL_LIST_ELEMENTS(pa_list, node, nnode, pa)) { | |
1483 | char *desc; | |
1484 | struct test *test; | |
1485 | ||
1486 | /* Build test description string. */ | |
1487 | if (pa->afi && pa->safi) | |
1488 | desc = str_printf("peer\\%s-%s\\%s", | |
1489 | str_from_afi(pa->afi), | |
1490 | str_from_safi(pa->safi), pa->cmd); | |
1491 | else | |
1492 | desc = str_printf("peer\\%s", pa->cmd); | |
1493 | ||
1494 | /* Initialize new test instance. */ | |
9fb964de | 1495 | test = test_new(desc, pa->o.use_ibgp, pa->o.use_iface_peer); |
9d4f5623 PM |
1496 | XFREE(MTYPE_TMP, desc); |
1497 | ||
1498 | /* Execute tests and finish test instance. */ | |
1499 | test_peer_attr(test, pa); | |
1500 | test_finish(test); | |
1501 | ||
1502 | /* Print empty line as spacer. */ | |
1503 | printf("\n"); | |
1504 | ||
1505 | /* Free memory used for peer-attr declaration. */ | |
1506 | XFREE(MTYPE_TMP, pa); | |
1507 | } | |
1508 | ||
6a154c88 | 1509 | list_delete(&pa_list); |
9d4f5623 PM |
1510 | bgp_shutdown(); |
1511 | ||
1512 | return 0; | |
1513 | } |