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