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