File: | src/usr.sbin/bgpd/printconf.c |
Warning: | line 1189, column 17 Use of memory allocated with size zero |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* $OpenBSD: printconf.c,v 1.169 2024/01/10 13:31:09 claudio Exp $ */ | |||
2 | ||||
3 | /* | |||
4 | * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> | |||
5 | * Copyright (c) 2016 Job Snijders <job@instituut.net> | |||
6 | * Copyright (c) 2016 Peter Hessler <phessler@openbsd.org> | |||
7 | * | |||
8 | * Permission to use, copy, modify, and distribute this software for any | |||
9 | * purpose with or without fee is hereby granted, provided that the above | |||
10 | * copyright notice and this permission notice appear in all copies. | |||
11 | * | |||
12 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |||
13 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||
14 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |||
15 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||
16 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA, PROFITS OR MIND, WHETHER IN | |||
17 | * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT | |||
18 | * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
19 | */ | |||
20 | ||||
21 | #include <limits.h> | |||
22 | #include <stdio.h> | |||
23 | #include <stdlib.h> | |||
24 | #include <string.h> | |||
25 | ||||
26 | #include "bgpd.h" | |||
27 | #include "session.h" | |||
28 | #include "rde.h" | |||
29 | #include "log.h" | |||
30 | ||||
31 | void print_prefix(struct filter_prefix *p); | |||
32 | const char *community_type(struct community *c); | |||
33 | void print_community(struct community *c); | |||
34 | void print_origin(uint8_t); | |||
35 | void print_set(struct filter_set_head *); | |||
36 | void print_mainconf(struct bgpd_config *); | |||
37 | void print_l3vpn_targets(struct filter_set_head *, const char *); | |||
38 | void print_l3vpn(struct l3vpn *); | |||
39 | const char *print_af(uint8_t); | |||
40 | void print_network(struct network_config *, const char *); | |||
41 | void print_flowspec(struct flowspec_config *, const char *); | |||
42 | void print_as_sets(struct as_set_head *); | |||
43 | void print_prefixsets(struct prefixset_head *); | |||
44 | void print_originsets(struct prefixset_head *); | |||
45 | void print_roa(struct roa_tree *); | |||
46 | void print_aspa(struct aspa_tree *); | |||
47 | void print_rtrs(struct rtr_config_head *); | |||
48 | void print_peer(struct peer_config *, struct bgpd_config *, | |||
49 | const char *); | |||
50 | const char *print_auth_alg(enum auth_alg); | |||
51 | const char *print_enc_alg(enum auth_enc_alg); | |||
52 | void print_announce(struct peer_config *, const char *); | |||
53 | void print_as(struct filter_rule *); | |||
54 | void print_rule(struct bgpd_config *, struct filter_rule *); | |||
55 | const char *mrt_type(enum mrt_type); | |||
56 | void print_mrt(struct bgpd_config *, uint32_t, uint32_t, | |||
57 | const char *, const char *); | |||
58 | void print_groups(struct bgpd_config *); | |||
59 | int peer_compare(const void *, const void *); | |||
60 | ||||
61 | void | |||
62 | print_prefix(struct filter_prefix *p) | |||
63 | { | |||
64 | uint8_t max_len = 0; | |||
65 | ||||
66 | switch (p->addr.aid) { | |||
67 | case AID_INET1: | |||
68 | case AID_VPN_IPv43: | |||
69 | max_len = 32; | |||
70 | break; | |||
71 | case AID_INET62: | |||
72 | case AID_VPN_IPv64: | |||
73 | max_len = 128; | |||
74 | break; | |||
75 | case AID_UNSPEC0: | |||
76 | /* no prefix to print */ | |||
77 | return; | |||
78 | } | |||
79 | ||||
80 | printf("%s/%u", log_addr(&p->addr), p->len); | |||
81 | ||||
82 | switch (p->op) { | |||
83 | case OP_NONE: | |||
84 | break; | |||
85 | case OP_NE: | |||
86 | printf(" prefixlen != %u", p->len_min); | |||
87 | break; | |||
88 | case OP_XRANGE: | |||
89 | printf(" prefixlen %u >< %u ", p->len_min, p->len_max); | |||
90 | break; | |||
91 | case OP_RANGE: | |||
92 | if (p->len_min == p->len_max && p->len != p->len_min) | |||
93 | printf(" prefixlen = %u", p->len_min); | |||
94 | else if (p->len == p->len_min && p->len_max == max_len) | |||
95 | printf(" or-longer"); | |||
96 | else if (p->len == p->len_min && p->len != p->len_max) | |||
97 | printf(" maxlen %u", p->len_max); | |||
98 | else if (p->len_max == max_len) | |||
99 | printf(" prefixlen >= %u", p->len_min); | |||
100 | else | |||
101 | printf(" prefixlen %u - %u", p->len_min, p->len_max); | |||
102 | break; | |||
103 | default: | |||
104 | printf(" prefixlen %u ??? %u", p->len_min, p->len_max); | |||
105 | break; | |||
106 | } | |||
107 | } | |||
108 | ||||
109 | const char * | |||
110 | community_type(struct community *c) | |||
111 | { | |||
112 | switch ((uint8_t)c->flags) { | |||
113 | case COMMUNITY_TYPE_BASIC8: | |||
114 | return "community"; | |||
115 | case COMMUNITY_TYPE_LARGE32: | |||
116 | return "large-community"; | |||
117 | case COMMUNITY_TYPE_EXT16: | |||
118 | return "ext-community"; | |||
119 | default: | |||
120 | return "???"; | |||
121 | } | |||
122 | } | |||
123 | ||||
124 | void | |||
125 | print_community(struct community *c) | |||
126 | { | |||
127 | struct in_addr addr; | |||
128 | int type; | |||
129 | uint8_t subtype; | |||
130 | ||||
131 | switch ((uint8_t)c->flags) { | |||
132 | case COMMUNITY_TYPE_BASIC8: | |||
133 | switch ((c->flags >> 8) & 0xff) { | |||
134 | case COMMUNITY_ANY1: | |||
135 | printf("*:"); | |||
136 | break; | |||
137 | case COMMUNITY_NEIGHBOR_AS2: | |||
138 | printf("neighbor-as:"); | |||
139 | break; | |||
140 | case COMMUNITY_LOCAL_AS3: | |||
141 | printf("local-as:"); | |||
142 | break; | |||
143 | default: | |||
144 | printf("%u:", c->data1); | |||
145 | break; | |||
146 | } | |||
147 | switch ((c->flags >> 16) & 0xff) { | |||
148 | case COMMUNITY_ANY1: | |||
149 | printf("* "); | |||
150 | break; | |||
151 | case COMMUNITY_NEIGHBOR_AS2: | |||
152 | printf("neighbor-as "); | |||
153 | break; | |||
154 | case COMMUNITY_LOCAL_AS3: | |||
155 | printf("local-as "); | |||
156 | break; | |||
157 | default: | |||
158 | printf("%u ", c->data2); | |||
159 | break; | |||
160 | } | |||
161 | break; | |||
162 | case COMMUNITY_TYPE_LARGE32: | |||
163 | switch ((c->flags >> 8) & 0xff) { | |||
164 | case COMMUNITY_ANY1: | |||
165 | printf("*:"); | |||
166 | break; | |||
167 | case COMMUNITY_NEIGHBOR_AS2: | |||
168 | printf("neighbor-as:"); | |||
169 | break; | |||
170 | case COMMUNITY_LOCAL_AS3: | |||
171 | printf("local-as:"); | |||
172 | break; | |||
173 | default: | |||
174 | printf("%u:", c->data1); | |||
175 | break; | |||
176 | } | |||
177 | switch ((c->flags >> 16) & 0xff) { | |||
178 | case COMMUNITY_ANY1: | |||
179 | printf("*:"); | |||
180 | break; | |||
181 | case COMMUNITY_NEIGHBOR_AS2: | |||
182 | printf("neighbor-as:"); | |||
183 | break; | |||
184 | case COMMUNITY_LOCAL_AS3: | |||
185 | printf("local-as:"); | |||
186 | break; | |||
187 | default: | |||
188 | printf("%u:", c->data2); | |||
189 | break; | |||
190 | } | |||
191 | switch ((c->flags >> 24) & 0xff) { | |||
192 | case COMMUNITY_ANY1: | |||
193 | printf("* "); | |||
194 | break; | |||
195 | case COMMUNITY_NEIGHBOR_AS2: | |||
196 | printf("neighbor-as "); | |||
197 | break; | |||
198 | case COMMUNITY_LOCAL_AS3: | |||
199 | printf("local-as "); | |||
200 | break; | |||
201 | default: | |||
202 | printf("%u ", c->data3); | |||
203 | break; | |||
204 | } | |||
205 | break; | |||
206 | case COMMUNITY_TYPE_EXT16: | |||
207 | if ((c->flags >> 24 & 0xff) == COMMUNITY_ANY1) { | |||
208 | printf("* * "); | |||
209 | break; | |||
210 | } | |||
211 | type = (int32_t)c->data3 >> 8; | |||
212 | subtype = c->data3; | |||
213 | printf("%s ", log_ext_subtype(type, subtype)); | |||
214 | if ((c->flags >> 8 & 0xff) == COMMUNITY_ANY1) { | |||
215 | printf("* "); | |||
216 | break; | |||
217 | } | |||
218 | ||||
219 | switch (type) { | |||
220 | case EXT_COMMUNITY_TRANS_TWO_AS0x00: | |||
221 | case EXT_COMMUNITY_TRANS_FOUR_AS0x02: | |||
222 | case EXT_COMMUNITY_GEN_TWO_AS0x80: | |||
223 | case EXT_COMMUNITY_GEN_FOUR_AS0x82: | |||
224 | if ((c->flags >> 8 & 0xff) == COMMUNITY_NEIGHBOR_AS2) | |||
225 | printf("neighbor-as:"); | |||
226 | else if ((c->flags >> 8 & 0xff) == COMMUNITY_LOCAL_AS3) | |||
227 | printf("local-as:"); | |||
228 | else | |||
229 | printf("%s:", log_as(c->data1)); | |||
230 | break; | |||
231 | case EXT_COMMUNITY_TRANS_IPV40x01: | |||
232 | case EXT_COMMUNITY_GEN_IPV40x81: | |||
233 | addr.s_addr = htonl(c->data1)(__uint32_t)(__builtin_constant_p(c->data1) ? (__uint32_t) (((__uint32_t)(c->data1) & 0xff) << 24 | ((__uint32_t )(c->data1) & 0xff00) << 8 | ((__uint32_t)(c-> data1) & 0xff0000) >> 8 | ((__uint32_t)(c->data1 ) & 0xff000000) >> 24) : __swap32md(c->data1)); | |||
234 | printf("%s:", inet_ntoa(addr)); | |||
235 | break; | |||
236 | } | |||
237 | ||||
238 | switch (type) { | |||
239 | case EXT_COMMUNITY_TRANS_TWO_AS0x00: | |||
240 | case EXT_COMMUNITY_TRANS_FOUR_AS0x02: | |||
241 | case EXT_COMMUNITY_TRANS_IPV40x01: | |||
242 | case EXT_COMMUNITY_GEN_TWO_AS0x80: | |||
243 | case EXT_COMMUNITY_GEN_FOUR_AS0x82: | |||
244 | case EXT_COMMUNITY_GEN_IPV40x81: | |||
245 | if ((c->flags >> 16 & 0xff) == COMMUNITY_ANY1) | |||
246 | printf("* "); | |||
247 | else if ((c->flags >> 16 & 0xff) == | |||
248 | COMMUNITY_NEIGHBOR_AS2) | |||
249 | printf("neighbor-as "); | |||
250 | else if ((c->flags >> 16 & 0xff) == COMMUNITY_LOCAL_AS3) | |||
251 | printf("local-as "); | |||
252 | else | |||
253 | printf("%u ", c->data2); | |||
254 | break; | |||
255 | case EXT_COMMUNITY_NON_TRANS_OPAQUE0x43: | |||
256 | if (subtype == EXT_COMMUNITY_SUBTYPE_OVS0) { | |||
257 | switch (c->data2) { | |||
258 | case EXT_COMMUNITY_OVS_VALID0: | |||
259 | printf("valid "); | |||
260 | break; | |||
261 | case EXT_COMMUNITY_OVS_NOTFOUND1: | |||
262 | printf("not-found "); | |||
263 | break; | |||
264 | case EXT_COMMUNITY_OVS_INVALID2: | |||
265 | printf("invalid "); | |||
266 | break; | |||
267 | } | |||
268 | break; | |||
269 | } | |||
270 | printf("0x%x%08x ", c->data1 & 0xffff, c->data2); | |||
271 | break; | |||
272 | case EXT_COMMUNITY_TRANS_OPAQUE0x03: | |||
273 | case EXT_COMMUNITY_TRANS_EVPN0x06: | |||
274 | default: | |||
275 | printf("0x%x%08x ", c->data1 & 0xffff, c->data2); | |||
276 | break; | |||
277 | } | |||
278 | } | |||
279 | } | |||
280 | ||||
281 | void | |||
282 | print_origin(uint8_t o) | |||
283 | { | |||
284 | if (o == ORIGIN_IGP0) | |||
285 | printf("igp "); | |||
286 | else if (o == ORIGIN_EGP1) | |||
287 | printf("egp "); | |||
288 | else if (o == ORIGIN_INCOMPLETE2) | |||
289 | printf("incomplete "); | |||
290 | else | |||
291 | printf("%u ", o); | |||
292 | } | |||
293 | ||||
294 | void | |||
295 | print_set(struct filter_set_head *set) | |||
296 | { | |||
297 | struct filter_set *s; | |||
298 | ||||
299 | if (TAILQ_EMPTY(set)(((set)->tqh_first) == ((void *)0))) | |||
300 | return; | |||
301 | ||||
302 | printf("set { "); | |||
303 | TAILQ_FOREACH(s, set, entry)for((s) = ((set)->tqh_first); (s) != ((void *)0); (s) = (( s)->entry.tqe_next)) { | |||
304 | switch (s->type) { | |||
305 | case ACTION_SET_LOCALPREF: | |||
306 | printf("localpref %u ", s->action.metric); | |||
307 | break; | |||
308 | case ACTION_SET_RELATIVE_LOCALPREF: | |||
309 | printf("localpref %+d ", s->action.relative); | |||
310 | break; | |||
311 | case ACTION_SET_MED: | |||
312 | printf("metric %u ", s->action.metric); | |||
313 | break; | |||
314 | case ACTION_SET_RELATIVE_MED: | |||
315 | printf("metric %+d ", s->action.relative); | |||
316 | break; | |||
317 | case ACTION_SET_WEIGHT: | |||
318 | printf("weight %u ", s->action.metric); | |||
319 | break; | |||
320 | case ACTION_SET_RELATIVE_WEIGHT: | |||
321 | printf("weight %+d ", s->action.relative); | |||
322 | break; | |||
323 | case ACTION_SET_NEXTHOP: | |||
324 | printf("nexthop %s ", log_addr(&s->action.nexthop)); | |||
325 | break; | |||
326 | case ACTION_SET_NEXTHOP_REJECT: | |||
327 | printf("nexthop reject "); | |||
328 | break; | |||
329 | case ACTION_SET_NEXTHOP_BLACKHOLE: | |||
330 | printf("nexthop blackhole "); | |||
331 | break; | |||
332 | case ACTION_SET_NEXTHOP_NOMODIFY: | |||
333 | printf("nexthop no-modify "); | |||
334 | break; | |||
335 | case ACTION_SET_NEXTHOP_SELF: | |||
336 | printf("nexthop self "); | |||
337 | break; | |||
338 | case ACTION_SET_PREPEND_SELF: | |||
339 | printf("prepend-self %u ", s->action.prepend); | |||
340 | break; | |||
341 | case ACTION_SET_PREPEND_PEER: | |||
342 | printf("prepend-neighbor %u ", s->action.prepend); | |||
343 | break; | |||
344 | case ACTION_SET_AS_OVERRIDE: | |||
345 | printf("as-override "); | |||
346 | break; | |||
347 | case ACTION_DEL_COMMUNITY: | |||
348 | printf("%s delete ", | |||
349 | community_type(&s->action.community)); | |||
350 | print_community(&s->action.community); | |||
351 | break; | |||
352 | case ACTION_SET_COMMUNITY: | |||
353 | printf("%s ", community_type(&s->action.community)); | |||
354 | print_community(&s->action.community); | |||
355 | break; | |||
356 | case ACTION_PFTABLE: | |||
357 | printf("pftable %s ", s->action.pftable); | |||
358 | break; | |||
359 | case ACTION_RTLABEL: | |||
360 | printf("rtlabel %s ", s->action.rtlabel); | |||
361 | break; | |||
362 | case ACTION_SET_ORIGIN: | |||
363 | printf("origin "); | |||
364 | print_origin(s->action.origin); | |||
365 | break; | |||
366 | case ACTION_RTLABEL_ID: | |||
367 | case ACTION_PFTABLE_ID: | |||
368 | case ACTION_SET_NEXTHOP_REF: | |||
369 | /* not possible */ | |||
370 | printf("king bula saiz: config broken"); | |||
371 | break; | |||
372 | } | |||
373 | } | |||
374 | printf("}"); | |||
375 | } | |||
376 | ||||
377 | void | |||
378 | print_mainconf(struct bgpd_config *conf) | |||
379 | { | |||
380 | struct in_addr ina; | |||
381 | struct listen_addr *la; | |||
382 | ||||
383 | printf("AS %s", log_as(conf->as)); | |||
384 | if (conf->as > USHRT_MAX0xffff && conf->short_as != AS_TRANS23456) | |||
385 | printf(" %u", conf->short_as); | |||
386 | ina.s_addr = conf->bgpid; | |||
387 | printf("\nrouter-id %s\n", inet_ntoa(ina)); | |||
388 | ||||
389 | printf("socket \"%s\"\n", conf->csock); | |||
390 | if (conf->rcsock) | |||
391 | printf("socket \"%s\" restricted\n", conf->rcsock); | |||
392 | if (conf->holdtime != INTERVAL_HOLD90) | |||
393 | printf("holdtime %u\n", conf->holdtime); | |||
394 | if (conf->min_holdtime != MIN_HOLDTIME3) | |||
395 | printf("holdtime min %u\n", conf->min_holdtime); | |||
396 | if (conf->connectretry != INTERVAL_CONNECTRETRY120) | |||
397 | printf("connect-retry %u\n", conf->connectretry); | |||
398 | ||||
399 | if (conf->flags & BGPD_FLAG_DECISION_ROUTEAGE0x0100) | |||
400 | printf("rde route-age evaluate\n"); | |||
401 | if (conf->flags & BGPD_FLAG_DECISION_MED_ALWAYS0x0400) | |||
402 | printf("rde med compare always\n"); | |||
403 | if (conf->flags & BGPD_FLAG_DECISION_ALL_PATHS0x0800) | |||
404 | printf("rde evaluate all\n"); | |||
405 | ||||
406 | if (conf->flags & BGPD_FLAG_NO_AS_SET0x1000) | |||
407 | printf("reject as-set yes\n"); | |||
408 | ||||
409 | if (conf->log & BGPD_LOG_UPDATES0x0001) | |||
410 | printf("log updates\n"); | |||
411 | ||||
412 | TAILQ_FOREACH(la, conf->listen_addrs, entry)for((la) = ((conf->listen_addrs)->tqh_first); (la) != ( (void *)0); (la) = ((la)->entry.tqe_next)) { | |||
413 | struct bgpd_addr addr; | |||
414 | uint16_t port; | |||
415 | ||||
416 | sa2addr((struct sockaddr *)&la->sa, &addr, &port); | |||
417 | printf("listen on %s", | |||
418 | log_sockaddr((struct sockaddr *)&la->sa, la->sa_len)); | |||
419 | if (port != BGP_PORT179) | |||
420 | printf(" port %hu", port); | |||
421 | printf("\n"); | |||
422 | } | |||
423 | ||||
424 | if (conf->flags & BGPD_FLAG_NEXTHOP_BGP0x0010) | |||
425 | printf("nexthop qualify via bgp\n"); | |||
426 | if (conf->flags & BGPD_FLAG_NEXTHOP_DEFAULT0x0020) | |||
427 | printf("nexthop qualify via default\n"); | |||
428 | if (conf->fib_priority != kr_default_prio()) | |||
429 | printf("fib-priority %hhu\n", conf->fib_priority); | |||
430 | printf("\n"); | |||
431 | } | |||
432 | ||||
433 | void | |||
434 | print_l3vpn_targets(struct filter_set_head *set, const char *tgt) | |||
435 | { | |||
436 | struct filter_set *s; | |||
437 | TAILQ_FOREACH(s, set, entry)for((s) = ((set)->tqh_first); (s) != ((void *)0); (s) = (( s)->entry.tqe_next)) { | |||
438 | printf("\t%s ", tgt); | |||
439 | print_community(&s->action.community); | |||
440 | printf("\n"); | |||
441 | } | |||
442 | } | |||
443 | ||||
444 | void | |||
445 | print_l3vpn(struct l3vpn *vpn) | |||
446 | { | |||
447 | struct network *n; | |||
448 | ||||
449 | printf("vpn \"%s\" on %s {\n", vpn->descr, vpn->ifmpe); | |||
450 | printf("\t%s\n", log_rd(vpn->rd)); | |||
451 | ||||
452 | print_l3vpn_targets(&vpn->export, "export-target"); | |||
453 | print_l3vpn_targets(&vpn->import, "import-target"); | |||
454 | ||||
455 | if (vpn->flags & F_RIB_NOFIBSYNC0x0008) | |||
456 | printf("\tfib-update no\n"); | |||
457 | else | |||
458 | printf("\tfib-update yes\n"); | |||
459 | ||||
460 | TAILQ_FOREACH(n, &vpn->net_l, entry)for((n) = ((&vpn->net_l)->tqh_first); (n) != ((void *)0); (n) = ((n)->entry.tqe_next)) | |||
461 | print_network(&n->net, "\t"); | |||
462 | ||||
463 | printf("}\n"); | |||
464 | } | |||
465 | ||||
466 | const char * | |||
467 | print_af(uint8_t aid) | |||
468 | { | |||
469 | /* | |||
470 | * Hack around the fact that aid2str() will return "IPv4 unicast" | |||
471 | * for AID_INET. AID_INET, AID_INET6 and the flowspec AID need | |||
472 | * special handling and the other AID should never end up here. | |||
473 | */ | |||
474 | if (aid == AID_INET1 || aid == AID_FLOWSPECv45) | |||
475 | return ("inet"); | |||
476 | if (aid == AID_INET62 || aid == AID_FLOWSPECv66) | |||
477 | return ("inet6"); | |||
478 | return (aid2str(aid)); | |||
479 | } | |||
480 | ||||
481 | void | |||
482 | print_network(struct network_config *n, const char *c) | |||
483 | { | |||
484 | switch (n->type) { | |||
485 | case NETWORK_STATIC: | |||
486 | printf("%snetwork %s static", c, print_af(n->prefix.aid)); | |||
487 | break; | |||
488 | case NETWORK_CONNECTED: | |||
489 | printf("%snetwork %s connected", c, print_af(n->prefix.aid)); | |||
490 | break; | |||
491 | case NETWORK_RTLABEL: | |||
492 | printf("%snetwork %s rtlabel \"%s\"", c, | |||
493 | print_af(n->prefix.aid), rtlabel_id2name(n->rtlabel)); | |||
494 | break; | |||
495 | case NETWORK_PRIORITY: | |||
496 | printf("%snetwork %s priority %d", c, | |||
497 | print_af(n->prefix.aid), n->priority); | |||
498 | break; | |||
499 | case NETWORK_PREFIXSET: | |||
500 | printf("%snetwork prefix-set %s", c, n->psname); | |||
501 | break; | |||
502 | default: | |||
503 | printf("%snetwork %s/%u", c, log_addr(&n->prefix), | |||
504 | n->prefixlen); | |||
505 | break; | |||
506 | } | |||
507 | if (!TAILQ_EMPTY(&n->attrset)(((&n->attrset)->tqh_first) == ((void *)0))) | |||
508 | printf(" "); | |||
509 | print_set(&n->attrset); | |||
510 | printf("\n"); | |||
511 | } | |||
512 | ||||
513 | static void | |||
514 | print_flowspec_list(struct flowspec *f, int type, int is_v6) | |||
515 | { | |||
516 | const uint8_t *comp; | |||
517 | const char *fmt; | |||
518 | int complen, off = 0; | |||
519 | ||||
520 | if (flowspec_get_component(f->data, f->len, type, is_v6, | |||
521 | &comp, &complen) != 1) | |||
522 | return; | |||
523 | ||||
524 | printf("%s ", flowspec_fmt_label(type)); | |||
525 | fmt = flowspec_fmt_num_op(comp, complen, &off); | |||
526 | if (off == -1) { | |||
527 | printf("%s ", fmt); | |||
528 | } else { | |||
529 | printf("{ %s ", fmt); | |||
530 | do { | |||
531 | fmt = flowspec_fmt_num_op(comp, complen, &off); | |||
532 | printf("%s ", fmt); | |||
533 | } while (off != -1); | |||
534 | printf("} "); | |||
535 | } | |||
536 | } | |||
537 | ||||
538 | static void | |||
539 | print_flowspec_flags(struct flowspec *f, int type, int is_v6) | |||
540 | { | |||
541 | const uint8_t *comp; | |||
542 | const char *fmt, *flags; | |||
543 | int complen, off = 0; | |||
544 | ||||
545 | switch (type) { | |||
546 | case FLOWSPEC_TYPE_TCP_FLAGS9: | |||
547 | flags = FLOWSPEC_TCP_FLAG_STRING"FSRPAUEW"; | |||
548 | break; | |||
549 | case FLOWSPEC_TYPE_FRAG12: | |||
550 | if (!is_v6) | |||
551 | flags = FLOWSPEC_FRAG_STRING4"DIFL"; | |||
552 | else | |||
553 | flags = FLOWSPEC_FRAG_STRING6" IFL"; | |||
554 | break; | |||
555 | default: | |||
556 | printf("??? "); | |||
557 | return; | |||
558 | } | |||
559 | ||||
560 | if (flowspec_get_component(f->data, f->len, type, is_v6, | |||
561 | &comp, &complen) != 1) | |||
562 | return; | |||
563 | ||||
564 | printf("%s ", flowspec_fmt_label(type)); | |||
565 | ||||
566 | fmt = flowspec_fmt_bin_op(comp, complen, &off, flags); | |||
567 | if (off == -1) { | |||
568 | printf("%s ", fmt); | |||
569 | } else { | |||
570 | printf("{ %s ", fmt); | |||
571 | do { | |||
572 | fmt = flowspec_fmt_bin_op(comp, complen, &off, flags); | |||
573 | printf("%s ", fmt); | |||
574 | } while (off != -1); | |||
575 | printf("} "); | |||
576 | } | |||
577 | } | |||
578 | ||||
579 | static void | |||
580 | print_flowspec_addr(struct flowspec *f, int type, int is_v6) | |||
581 | { | |||
582 | struct bgpd_addr addr; | |||
583 | uint8_t plen; | |||
584 | ||||
585 | flowspec_get_addr(f->data, f->len, type, is_v6, &addr, &plen, NULL((void *)0)); | |||
586 | if (plen == 0) | |||
587 | printf("%s any ", flowspec_fmt_label(type)); | |||
588 | else | |||
589 | printf("%s %s/%u ", flowspec_fmt_label(type), | |||
590 | log_addr(&addr), plen); | |||
591 | } | |||
592 | ||||
593 | void | |||
594 | print_flowspec(struct flowspec_config *fconf, const char *c) | |||
595 | { | |||
596 | struct flowspec *f = fconf->flow; | |||
597 | int is_v6 = (f->aid == AID_FLOWSPECv66); | |||
598 | ||||
599 | printf("%sflowspec %s ", c, print_af(f->aid)); | |||
600 | ||||
601 | print_flowspec_list(f, FLOWSPEC_TYPE_PROTO3, is_v6); | |||
602 | ||||
603 | print_flowspec_addr(f, FLOWSPEC_TYPE_SOURCE2, is_v6); | |||
604 | print_flowspec_list(f, FLOWSPEC_TYPE_SRC_PORT6, is_v6); | |||
605 | ||||
606 | print_flowspec_addr(f, FLOWSPEC_TYPE_DEST1, is_v6); | |||
607 | print_flowspec_list(f, FLOWSPEC_TYPE_DST_PORT5, is_v6); | |||
608 | ||||
609 | print_flowspec_list(f, FLOWSPEC_TYPE_DSCP11, is_v6); | |||
610 | print_flowspec_list(f, FLOWSPEC_TYPE_PKT_LEN10, is_v6); | |||
611 | print_flowspec_flags(f, FLOWSPEC_TYPE_TCP_FLAGS9, is_v6); | |||
612 | print_flowspec_flags(f, FLOWSPEC_TYPE_FRAG12, is_v6); | |||
613 | ||||
614 | /* TODO: fixup the code handling to be like in the parser */ | |||
615 | print_flowspec_list(f, FLOWSPEC_TYPE_ICMP_TYPE7, is_v6); | |||
616 | print_flowspec_list(f, FLOWSPEC_TYPE_ICMP_CODE8, is_v6); | |||
617 | ||||
618 | print_set(&fconf->attrset); | |||
619 | printf("\n"); | |||
620 | } | |||
621 | ||||
622 | void | |||
623 | print_as_sets(struct as_set_head *as_sets) | |||
624 | { | |||
625 | struct as_set *aset; | |||
626 | uint32_t *as; | |||
627 | size_t i, n; | |||
628 | int len; | |||
629 | ||||
630 | SIMPLEQ_FOREACH(aset, as_sets, entry)for((aset) = ((as_sets)->sqh_first); (aset) != ((void *)0) ; (aset) = ((aset)->entry.sqe_next)) { | |||
631 | printf("as-set \"%s\" {\n\t", aset->name); | |||
632 | as = set_get(aset->set, &n); | |||
633 | for (i = 0, len = 8; i < n; i++) { | |||
634 | if (len > 72) { | |||
635 | printf("\n\t"); | |||
636 | len = 8; | |||
637 | } | |||
638 | len += printf("%u ", as[i]); | |||
639 | } | |||
640 | printf("\n}\n\n"); | |||
641 | } | |||
642 | } | |||
643 | ||||
644 | void | |||
645 | print_prefixsets(struct prefixset_head *psh) | |||
646 | { | |||
647 | struct prefixset *ps; | |||
648 | struct prefixset_item *psi; | |||
649 | ||||
650 | SIMPLEQ_FOREACH(ps, psh, entry)for((ps) = ((psh)->sqh_first); (ps) != ((void *)0); (ps) = ((ps)->entry.sqe_next)) { | |||
651 | int count = 0; | |||
652 | printf("prefix-set \"%s\" {", ps->name); | |||
653 | RB_FOREACH(psi, prefixset_tree, &ps->psitems)for ((psi) = prefixset_tree_RB_MINMAX(&ps->psitems, -1 ); (psi) != ((void *)0); (psi) = prefixset_tree_RB_NEXT(psi)) { | |||
654 | if (count++ % 2 == 0) | |||
655 | printf("\n\t"); | |||
656 | else | |||
657 | printf(", "); | |||
658 | print_prefix(&psi->p); | |||
659 | } | |||
660 | printf("\n}\n\n"); | |||
661 | } | |||
662 | } | |||
663 | ||||
664 | void | |||
665 | print_originsets(struct prefixset_head *psh) | |||
666 | { | |||
667 | struct prefixset *ps; | |||
668 | struct roa *roa; | |||
669 | struct bgpd_addr addr; | |||
670 | ||||
671 | SIMPLEQ_FOREACH(ps, psh, entry)for((ps) = ((psh)->sqh_first); (ps) != ((void *)0); (ps) = ((ps)->entry.sqe_next)) { | |||
672 | printf("origin-set \"%s\" {", ps->name); | |||
673 | RB_FOREACH(roa, roa_tree, &ps->roaitems)for ((roa) = roa_tree_RB_MINMAX(&ps->roaitems, -1); (roa ) != ((void *)0); (roa) = roa_tree_RB_NEXT(roa)) { | |||
674 | printf("\n\t"); | |||
675 | addr.aid = roa->aid; | |||
676 | addr.v6ba.v6 = roa->prefix.inet6; | |||
677 | printf("%s/%u", log_addr(&addr), roa->prefixlen); | |||
678 | if (roa->prefixlen != roa->maxlen) | |||
679 | printf(" maxlen %u", roa->maxlen); | |||
680 | printf(" source-as %u", roa->asnum); | |||
681 | } | |||
682 | printf("\n}\n\n"); | |||
683 | } | |||
684 | } | |||
685 | ||||
686 | void | |||
687 | print_roa(struct roa_tree *r) | |||
688 | { | |||
689 | struct roa *roa; | |||
690 | ||||
691 | if (RB_EMPTY(r)((r)->rbh_root == ((void *)0))) | |||
692 | return; | |||
693 | ||||
694 | printf("roa-set {"); | |||
695 | RB_FOREACH(roa, roa_tree, r)for ((roa) = roa_tree_RB_MINMAX(r, -1); (roa) != ((void *)0); (roa) = roa_tree_RB_NEXT(roa)) { | |||
696 | printf("\n\t%s", log_roa(roa)); | |||
697 | } | |||
698 | printf("\n}\n\n"); | |||
699 | } | |||
700 | ||||
701 | void | |||
702 | print_aspa(struct aspa_tree *a) | |||
703 | { | |||
704 | struct aspa_set *aspa; | |||
705 | ||||
706 | if (RB_EMPTY(a)((a)->rbh_root == ((void *)0))) | |||
707 | return; | |||
708 | ||||
709 | printf("aspa-set {"); | |||
710 | RB_FOREACH(aspa, aspa_tree, a)for ((aspa) = aspa_tree_RB_MINMAX(a, -1); (aspa) != ((void *) 0); (aspa) = aspa_tree_RB_NEXT(aspa)) { | |||
711 | printf("\n\t%s", log_aspa(aspa)); | |||
712 | } | |||
713 | printf("\n}\n\n"); | |||
714 | } | |||
715 | ||||
716 | void | |||
717 | print_rtrs(struct rtr_config_head *rh) | |||
718 | { | |||
719 | struct rtr_config *r; | |||
720 | ||||
721 | SIMPLEQ_FOREACH(r, rh, entry)for((r) = ((rh)->sqh_first); (r) != ((void *)0); (r) = ((r )->entry.sqe_next)) { | |||
722 | printf("rtr %s {\n", log_addr(&r->remote_addr)); | |||
723 | printf("\tdescr \"%s\"\n", r->descr); | |||
724 | printf("\tport %u\n", r->remote_port); | |||
725 | if (r->local_addr.aid != AID_UNSPEC0) | |||
726 | printf("local-addr %s\n", log_addr(&r->local_addr)); | |||
727 | printf("}\n\n"); | |||
728 | } | |||
729 | } | |||
730 | ||||
731 | void | |||
732 | print_peer(struct peer_config *p, struct bgpd_config *conf, const char *c) | |||
733 | { | |||
734 | char *method; | |||
735 | struct in_addr ina; | |||
736 | ||||
737 | if ((p->remote_addr.aid == AID_INET1 && p->remote_masklen != 32) || | |||
738 | (p->remote_addr.aid == AID_INET62 && p->remote_masklen != 128)) | |||
739 | printf("%sneighbor %s/%u {\n", c, log_addr(&p->remote_addr), | |||
740 | p->remote_masklen); | |||
741 | else | |||
742 | printf("%sneighbor %s {\n", c, log_addr(&p->remote_addr)); | |||
743 | if (p->descr[0]) | |||
744 | printf("%s\tdescr \"%s\"\n", c, p->descr); | |||
745 | if (p->rib[0]) | |||
746 | printf("%s\trib \"%s\"\n", c, p->rib); | |||
747 | if (p->remote_as) | |||
748 | printf("%s\tremote-as %s\n", c, log_as(p->remote_as)); | |||
749 | if (p->local_as != conf->as) { | |||
750 | printf("%s\tlocal-as %s", c, log_as(p->local_as)); | |||
751 | if (p->local_as > USHRT_MAX0xffff && p->local_short_as != AS_TRANS23456) | |||
752 | printf(" %u", p->local_short_as); | |||
753 | printf("\n"); | |||
754 | } | |||
755 | if (p->down) | |||
756 | printf("%s\tdown\n", c); | |||
757 | if (p->distance > 1) | |||
758 | printf("%s\tmultihop %u\n", c, p->distance); | |||
759 | if (p->passive) | |||
760 | printf("%s\tpassive\n", c); | |||
761 | if (p->local_addr_v4.aid) | |||
762 | printf("%s\tlocal-address %s\n", c, | |||
763 | log_addr(&p->local_addr_v4)); | |||
764 | if (p->local_addr_v6.aid) | |||
765 | printf("%s\tlocal-address %s\n", c, | |||
766 | log_addr(&p->local_addr_v6)); | |||
767 | if (p->remote_port != BGP_PORT179) | |||
768 | printf("%s\tport %hu\n", c, p->remote_port); | |||
769 | if (p->role != ROLE_NONE) | |||
770 | printf("%s\trole %s\n", c, log_policy(p->role)); | |||
771 | if (p->max_prefix) { | |||
772 | printf("%s\tmax-prefix %u", c, p->max_prefix); | |||
773 | if (p->max_prefix_restart) | |||
774 | printf(" restart %u", p->max_prefix_restart); | |||
775 | printf("\n"); | |||
776 | } | |||
777 | if (p->max_out_prefix) { | |||
778 | printf("%s\tmax-prefix %u out", c, p->max_out_prefix); | |||
779 | if (p->max_out_prefix_restart) | |||
780 | printf(" restart %u", p->max_out_prefix_restart); | |||
781 | printf("\n"); | |||
782 | } | |||
783 | if (p->holdtime) | |||
784 | printf("%s\tholdtime %u\n", c, p->holdtime); | |||
785 | if (p->min_holdtime) | |||
786 | printf("%s\tholdtime min %u\n", c, p->min_holdtime); | |||
787 | if (p->export_type == EXPORT_NONE) | |||
788 | printf("%s\texport none\n", c); | |||
789 | else if (p->export_type == EXPORT_DEFAULT_ROUTE) | |||
790 | printf("%s\texport default-route\n", c); | |||
791 | if (p->enforce_as == ENFORCE_AS_ON) | |||
792 | printf("%s\tenforce neighbor-as yes\n", c); | |||
793 | else | |||
794 | printf("%s\tenforce neighbor-as no\n", c); | |||
795 | if (p->enforce_local_as == ENFORCE_AS_ON) | |||
796 | printf("%s\tenforce local-as yes\n", c); | |||
797 | else | |||
798 | printf("%s\tenforce local-as no\n", c); | |||
799 | if (p->reflector_client) { | |||
800 | if (conf->clusterid == 0) | |||
801 | printf("%s\troute-reflector\n", c); | |||
802 | else { | |||
803 | ina.s_addr = conf->clusterid; | |||
804 | printf("%s\troute-reflector %s\n", c, | |||
805 | inet_ntoa(ina)); | |||
806 | } | |||
807 | } | |||
808 | if (p->demote_group[0]) | |||
809 | printf("%s\tdemote %s\n", c, p->demote_group); | |||
810 | if (p->if_depend[0]) | |||
811 | printf("%s\tdepend on \"%s\"\n", c, p->if_depend); | |||
812 | if (p->flags & PEERFLAG_TRANS_AS0x01) | |||
813 | printf("%s\ttransparent-as yes\n", c); | |||
814 | ||||
815 | if (conf->flags & BGPD_FLAG_DECISION_ALL_PATHS0x0800) { | |||
816 | if (!(p->flags & PEERFLAG_EVALUATE_ALL0x04)) | |||
817 | printf("%s\trde evaluate default\n", c); | |||
818 | } else { | |||
819 | if (p->flags & PEERFLAG_EVALUATE_ALL0x04) | |||
820 | printf("%s\trde evaluate all\n", c); | |||
821 | } | |||
822 | ||||
823 | if (conf->flags & BGPD_FLAG_NO_AS_SET0x1000) { | |||
824 | if (!(p->flags & PEERFLAG_NO_AS_SET0x08)) | |||
825 | printf("%s\treject as-set no\n", c); | |||
826 | } else { | |||
827 | if (p->flags & PEERFLAG_NO_AS_SET0x08) | |||
828 | printf("%s\treject as-set yes\n", c); | |||
829 | } | |||
830 | ||||
831 | if (p->flags & PEERFLAG_LOG_UPDATES0x02) | |||
832 | printf("%s\tlog updates\n", c); | |||
833 | ||||
834 | if (p->auth.method == AUTH_MD5SIG) | |||
835 | printf("%s\ttcp md5sig\n", c); | |||
836 | else if (p->auth.method == AUTH_IPSEC_MANUAL_ESP || | |||
837 | p->auth.method == AUTH_IPSEC_MANUAL_AH) { | |||
838 | if (p->auth.method == AUTH_IPSEC_MANUAL_ESP) | |||
839 | method = "esp"; | |||
840 | else | |||
841 | method = "ah"; | |||
842 | ||||
843 | printf("%s\tipsec %s in spi %u %s XXXXXX", c, method, | |||
844 | p->auth.spi_in, print_auth_alg(p->auth.auth_alg_in)); | |||
845 | if (p->auth.enc_alg_in) | |||
846 | printf(" %s XXXXXX", print_enc_alg(p->auth.enc_alg_in)); | |||
847 | printf("\n"); | |||
848 | ||||
849 | printf("%s\tipsec %s out spi %u %s XXXXXX", c, method, | |||
850 | p->auth.spi_out, print_auth_alg(p->auth.auth_alg_out)); | |||
851 | if (p->auth.enc_alg_out) | |||
852 | printf(" %s XXXXXX", | |||
853 | print_enc_alg(p->auth.enc_alg_out)); | |||
854 | printf("\n"); | |||
855 | } else if (p->auth.method == AUTH_IPSEC_IKE_AH) | |||
856 | printf("%s\tipsec ah ike\n", c); | |||
857 | else if (p->auth.method == AUTH_IPSEC_IKE_ESP) | |||
858 | printf("%s\tipsec esp ike\n", c); | |||
859 | ||||
860 | if (p->ttlsec) | |||
861 | printf("%s\tttl-security yes\n", c); | |||
862 | ||||
863 | print_announce(p, c); | |||
864 | ||||
865 | print_mrt(conf, p->id, p->groupid, c, "\t"); | |||
866 | ||||
867 | printf("%s}\n", c); | |||
868 | } | |||
869 | ||||
870 | const char * | |||
871 | print_auth_alg(enum auth_alg alg) | |||
872 | { | |||
873 | switch (alg) { | |||
874 | case AUTH_AALG_SHA1HMAC: | |||
875 | return ("sha1"); | |||
876 | case AUTH_AALG_MD5HMAC: | |||
877 | return ("md5"); | |||
878 | default: | |||
879 | return ("???"); | |||
880 | } | |||
881 | } | |||
882 | ||||
883 | const char * | |||
884 | print_enc_alg(enum auth_enc_alg alg) | |||
885 | { | |||
886 | switch (alg) { | |||
887 | case AUTH_EALG_3DESCBC: | |||
888 | return ("3des"); | |||
889 | case AUTH_EALG_AES: | |||
890 | return ("aes"); | |||
891 | default: | |||
892 | return ("???"); | |||
893 | } | |||
894 | } | |||
895 | ||||
896 | static const char * | |||
897 | print_addpath_mode(enum addpath_mode mode) | |||
898 | { | |||
899 | switch (mode) { | |||
900 | case ADDPATH_EVAL_NONE: | |||
901 | return "none"; | |||
902 | case ADDPATH_EVAL_BEST: | |||
903 | return "best"; | |||
904 | case ADDPATH_EVAL_ECMP: | |||
905 | return "ecmp"; | |||
906 | case ADDPATH_EVAL_AS_WIDE: | |||
907 | return "as-wide-best"; | |||
908 | case ADDPATH_EVAL_ALL: | |||
909 | return "all"; | |||
910 | default: | |||
911 | return "???"; | |||
912 | } | |||
913 | } | |||
914 | ||||
915 | void | |||
916 | print_announce(struct peer_config *p, const char *c) | |||
917 | { | |||
918 | uint8_t aid; | |||
919 | ||||
920 | if (p->announce_capa == 0) | |||
921 | printf("%s\tannounce capabilities no\n", c); | |||
922 | ||||
923 | for (aid = 0; aid < AID_MAX7; aid++) | |||
924 | if (p->capabilities.mp[aid]) | |||
925 | printf("%s\tannounce %s\n", c, aid2str(aid)); | |||
926 | ||||
927 | if (p->capabilities.refresh == 0) | |||
928 | printf("%s\tannounce refresh no\n", c); | |||
929 | if (p->capabilities.enhanced_rr == 1) | |||
930 | printf("%s\tannounce enhanced refresh yes\n", c); | |||
931 | if (p->capabilities.grestart.restart == 0) | |||
932 | printf("%s\tannounce restart no\n", c); | |||
933 | if (p->capabilities.as4byte == 0) | |||
934 | printf("%s\tannounce as4byte no\n", c); | |||
935 | if (p->capabilities.add_path[0] & CAPA_AP_RECV0x01) | |||
936 | printf("%s\tannounce add-path recv yes\n", c); | |||
937 | if (p->capabilities.add_path[0] & CAPA_AP_SEND0x02) { | |||
938 | printf("%s\tannounce add-path send %s", c, | |||
939 | print_addpath_mode(p->eval.mode)); | |||
940 | if (p->eval.extrapaths != 0) | |||
941 | printf(" plus %d", p->eval.extrapaths); | |||
942 | if (p->eval.maxpaths != 0) | |||
943 | printf(" max %d", p->eval.maxpaths); | |||
944 | printf("\n"); | |||
945 | } | |||
946 | if (p->capabilities.policy) { | |||
947 | printf("%s\tannounce policy %s\n", c, | |||
948 | p->capabilities.policy == 2 ? "enforce" : "yes"); | |||
949 | } | |||
950 | } | |||
951 | ||||
952 | void | |||
953 | print_as(struct filter_rule *r) | |||
954 | { | |||
955 | if (r->match.as.flags & AS_FLAG_AS_SET_NAME0x02) { | |||
956 | printf("as-set \"%s\" ", r->match.as.name); | |||
957 | return; | |||
958 | } | |||
959 | switch (r->match.as.op) { | |||
960 | case OP_RANGE: | |||
961 | printf("%s - ", log_as(r->match.as.as_min)); | |||
962 | printf("%s ", log_as(r->match.as.as_max)); | |||
963 | break; | |||
964 | case OP_XRANGE: | |||
965 | printf("%s >< ", log_as(r->match.as.as_min)); | |||
966 | printf("%s ", log_as(r->match.as.as_max)); | |||
967 | break; | |||
968 | case OP_NE: | |||
969 | printf("!= %s ", log_as(r->match.as.as_min)); | |||
970 | break; | |||
971 | default: | |||
972 | printf("%s ", log_as(r->match.as.as_min)); | |||
973 | break; | |||
974 | } | |||
975 | } | |||
976 | ||||
977 | void | |||
978 | print_rule(struct bgpd_config *conf, struct filter_rule *r) | |||
979 | { | |||
980 | struct peer *p; | |||
981 | int i; | |||
982 | ||||
983 | if (r->action == ACTION_ALLOW) | |||
984 | printf("allow "); | |||
985 | else if (r->action == ACTION_DENY) | |||
986 | printf("deny "); | |||
987 | else | |||
988 | printf("match "); | |||
989 | if (r->quick) | |||
990 | printf("quick "); | |||
991 | ||||
992 | if (r->rib[0]) | |||
993 | printf("rib %s ", r->rib); | |||
994 | ||||
995 | if (r->dir == DIR_IN) | |||
996 | printf("from "); | |||
997 | else if (r->dir == DIR_OUT) | |||
998 | printf("to "); | |||
999 | else | |||
1000 | printf("eeeeeeeps. "); | |||
1001 | ||||
1002 | if (r->peer.peerid) { | |||
1003 | RB_FOREACH(p, peer_head, &conf->peers)for ((p) = peer_head_RB_MINMAX(&conf->peers, -1); (p) != ((void *)0); (p) = peer_head_RB_NEXT(p)) | |||
1004 | if (p->conf.id == r->peer.peerid) | |||
1005 | break; | |||
1006 | if (p == NULL((void *)0)) | |||
1007 | printf("? "); | |||
1008 | else | |||
1009 | printf("%s ", log_addr(&p->conf.remote_addr)); | |||
1010 | } else if (r->peer.groupid) { | |||
1011 | RB_FOREACH(p, peer_head, &conf->peers)for ((p) = peer_head_RB_MINMAX(&conf->peers, -1); (p) != ((void *)0); (p) = peer_head_RB_NEXT(p)) | |||
1012 | if (p->conf.groupid == r->peer.groupid) | |||
1013 | break; | |||
1014 | if (p == NULL((void *)0)) | |||
1015 | printf("group ? "); | |||
1016 | else | |||
1017 | printf("group \"%s\" ", p->conf.group); | |||
1018 | } else if (r->peer.remote_as) { | |||
1019 | printf("AS %s ", log_as(r->peer.remote_as)); | |||
1020 | } else if (r->peer.ebgp) { | |||
1021 | printf("ebgp "); | |||
1022 | } else if (r->peer.ibgp) { | |||
1023 | printf("ibgp "); | |||
1024 | } else | |||
1025 | printf("any "); | |||
1026 | ||||
1027 | if (r->match.ovs.is_set) { | |||
1028 | switch (r->match.ovs.validity) { | |||
1029 | case ROA_VALID0x2: | |||
1030 | printf("ovs valid "); | |||
1031 | break; | |||
1032 | case ROA_INVALID0x1: | |||
1033 | printf("ovs invalid "); | |||
1034 | break; | |||
1035 | case ROA_NOTFOUND0x0: | |||
1036 | printf("ovs not-found "); | |||
1037 | break; | |||
1038 | default: | |||
1039 | printf("ovs ??? %d ??? ", r->match.ovs.validity); | |||
1040 | } | |||
1041 | } | |||
1042 | ||||
1043 | if (r->match.avs.is_set) { | |||
1044 | switch (r->match.avs.validity) { | |||
1045 | case ASPA_VALID0x02: | |||
1046 | printf("avs valid "); | |||
1047 | break; | |||
1048 | case ASPA_INVALID0x01: | |||
1049 | printf("avs invalid "); | |||
1050 | break; | |||
1051 | case ASPA_UNKNOWN0x00: | |||
1052 | printf("avs unknown "); | |||
1053 | break; | |||
1054 | default: | |||
1055 | printf("avs ??? %d ??? ", r->match.avs.validity); | |||
1056 | } | |||
1057 | } | |||
1058 | ||||
1059 | if (r->match.prefix.addr.aid != AID_UNSPEC0) { | |||
1060 | printf("prefix "); | |||
1061 | print_prefix(&r->match.prefix); | |||
1062 | printf(" "); | |||
1063 | } | |||
1064 | ||||
1065 | if (r->match.prefixset.name[0] != '\0') | |||
1066 | printf("prefix-set \"%s\" ", r->match.prefixset.name); | |||
1067 | if (r->match.prefixset.flags & PREFIXSET_FLAG_LONGER0x08) | |||
1068 | printf("or-longer "); | |||
1069 | ||||
1070 | if (r->match.originset.name[0] != '\0') | |||
1071 | printf("origin-set \"%s\" ", r->match.originset.name); | |||
1072 | ||||
1073 | if (r->match.nexthop.flags) { | |||
1074 | if (r->match.nexthop.flags == FILTER_NEXTHOP_NEIGHBOR2) | |||
1075 | printf("nexthop neighbor "); | |||
1076 | else | |||
1077 | printf("nexthop %s ", log_addr(&r->match.nexthop.addr)); | |||
1078 | } | |||
1079 | ||||
1080 | if (r->match.as.type) { | |||
1081 | if (r->match.as.type == AS_ALL) | |||
1082 | printf("AS "); | |||
1083 | else if (r->match.as.type == AS_SOURCE) | |||
1084 | printf("source-as "); | |||
1085 | else if (r->match.as.type == AS_TRANSIT) | |||
1086 | printf("transit-as "); | |||
1087 | else if (r->match.as.type == AS_PEER) | |||
1088 | printf("peer-as "); | |||
1089 | else | |||
1090 | printf("unfluffy-as "); | |||
1091 | print_as(r); | |||
1092 | } | |||
1093 | ||||
1094 | if (r->match.aslen.type) { | |||
1095 | printf("%s %u ", r->match.aslen.type == ASLEN_MAX ? | |||
1096 | "max-as-len" : "max-as-seq", r->match.aslen.aslen); | |||
1097 | } | |||
1098 | ||||
1099 | for (i = 0; i < MAX_COMM_MATCH3; i++) { | |||
1100 | struct community *c = &r->match.community[i]; | |||
1101 | if (c->flags != 0) { | |||
1102 | printf("%s ", community_type(c)); | |||
1103 | print_community(c); | |||
1104 | } | |||
1105 | } | |||
1106 | ||||
1107 | if (r->match.maxcomm != 0) | |||
1108 | printf("max-communities %d ", r->match.maxcomm - 1); | |||
1109 | if (r->match.maxextcomm != 0) | |||
1110 | printf("max-ext-communities %d ", r->match.maxextcomm - 1); | |||
1111 | if (r->match.maxlargecomm != 0) | |||
1112 | printf("max-large-communities %d ", r->match.maxlargecomm - 1); | |||
1113 | ||||
1114 | print_set(&r->set); | |||
1115 | ||||
1116 | printf("\n"); | |||
1117 | } | |||
1118 | ||||
1119 | const char * | |||
1120 | mrt_type(enum mrt_type t) | |||
1121 | { | |||
1122 | switch (t) { | |||
1123 | case MRT_NONE: | |||
1124 | break; | |||
1125 | case MRT_TABLE_DUMP: | |||
1126 | return "table"; | |||
1127 | case MRT_TABLE_DUMP_MP: | |||
1128 | return "table-mp"; | |||
1129 | case MRT_TABLE_DUMP_V2: | |||
1130 | return "table-v2"; | |||
1131 | case MRT_ALL_IN: | |||
1132 | return "all in"; | |||
1133 | case MRT_ALL_OUT: | |||
1134 | return "all out"; | |||
1135 | case MRT_UPDATE_IN: | |||
1136 | return "updates in"; | |||
1137 | case MRT_UPDATE_OUT: | |||
1138 | return "updates out"; | |||
1139 | } | |||
1140 | return "unfluffy MRT"; | |||
1141 | } | |||
1142 | ||||
1143 | void | |||
1144 | print_mrt(struct bgpd_config *conf, uint32_t pid, uint32_t gid, | |||
1145 | const char *prep, const char *prep2) | |||
1146 | { | |||
1147 | struct mrt *m; | |||
1148 | ||||
1149 | if (conf->mrt == NULL((void *)0)) | |||
1150 | return; | |||
1151 | ||||
1152 | LIST_FOREACH(m, conf->mrt, entry)for((m) = ((conf->mrt)->lh_first); (m)!= ((void *)0); ( m) = ((m)->entry.le_next)) | |||
1153 | if ((gid != 0 && m->group_id == gid) || | |||
1154 | (m->peer_id == pid && m->group_id == gid)) { | |||
1155 | printf("%s%sdump ", prep, prep2); | |||
1156 | if (m->rib[0]) | |||
1157 | printf("rib %s ", m->rib); | |||
1158 | printf("%s \"%s\"", mrt_type(m->type), | |||
1159 | MRT2MC(m)((struct mrt_config *)(m))->name); | |||
1160 | if (MRT2MC(m)((struct mrt_config *)(m))->ReopenTimerInterval == 0) | |||
1161 | printf("\n"); | |||
1162 | else | |||
1163 | printf(" %d\n", MRT2MC(m)((struct mrt_config *)(m))->ReopenTimerInterval); | |||
1164 | } | |||
1165 | if (!LIST_EMPTY(conf->mrt)(((conf->mrt)->lh_first) == ((void *)0))) | |||
1166 | printf("\n"); | |||
1167 | } | |||
1168 | ||||
1169 | void | |||
1170 | print_groups(struct bgpd_config *conf) | |||
1171 | { | |||
1172 | struct peer_config **peerlist; | |||
1173 | struct peer *p; | |||
1174 | u_int peer_cnt, i; | |||
1175 | uint32_t prev_groupid; | |||
1176 | const char *tab = "\t"; | |||
1177 | const char *nada = ""; | |||
1178 | const char *c; | |||
1179 | ||||
1180 | peer_cnt = 0; | |||
1181 | RB_FOREACH(p, peer_head, &conf->peers)for ((p) = peer_head_RB_MINMAX(&conf->peers, -1); (p) != ((void *)0); (p) = peer_head_RB_NEXT(p)) | |||
1182 | peer_cnt++; | |||
1183 | ||||
1184 | if ((peerlist = calloc(peer_cnt, sizeof(struct peer_config *))) == NULL((void *)0)) | |||
1185 | fatal("print_groups calloc"); | |||
1186 | ||||
1187 | i = 0; | |||
1188 | RB_FOREACH(p, peer_head, &conf->peers)for ((p) = peer_head_RB_MINMAX(&conf->peers, -1); (p) != ((void *)0); (p) = peer_head_RB_NEXT(p)) | |||
1189 | peerlist[i++] = &p->conf; | |||
| ||||
1190 | ||||
1191 | qsort(peerlist, peer_cnt, sizeof(struct peer_config *), peer_compare); | |||
1192 | ||||
1193 | prev_groupid = 0; | |||
1194 | for (i = 0; i < peer_cnt; i++) { | |||
1195 | if (peerlist[i]->groupid) { | |||
1196 | c = tab; | |||
1197 | if (peerlist[i]->groupid != prev_groupid) { | |||
1198 | if (prev_groupid) | |||
1199 | printf("}\n\n"); | |||
1200 | printf("group \"%s\" {\n", peerlist[i]->group); | |||
1201 | prev_groupid = peerlist[i]->groupid; | |||
1202 | } | |||
1203 | } else | |||
1204 | c = nada; | |||
1205 | ||||
1206 | print_peer(peerlist[i], conf, c); | |||
1207 | } | |||
1208 | ||||
1209 | if (prev_groupid) | |||
1210 | printf("}\n\n"); | |||
1211 | ||||
1212 | free(peerlist); | |||
1213 | } | |||
1214 | ||||
1215 | int | |||
1216 | peer_compare(const void *aa, const void *bb) | |||
1217 | { | |||
1218 | const struct peer_config * const *a; | |||
1219 | const struct peer_config * const *b; | |||
1220 | ||||
1221 | a = aa; | |||
1222 | b = bb; | |||
1223 | ||||
1224 | return ((*a)->groupid - (*b)->groupid); | |||
1225 | } | |||
1226 | ||||
1227 | void | |||
1228 | print_config(struct bgpd_config *conf, struct rib_names *rib_l) | |||
1229 | { | |||
1230 | struct filter_rule *r; | |||
1231 | struct network *n; | |||
1232 | struct flowspec_config *f; | |||
1233 | struct rde_rib *rr; | |||
1234 | struct l3vpn *vpn; | |||
1235 | ||||
1236 | print_mainconf(conf); | |||
1237 | print_rtrs(&conf->rtrs); | |||
1238 | print_roa(&conf->roa); | |||
1239 | print_aspa(&conf->aspa); | |||
1240 | print_as_sets(&conf->as_sets); | |||
1241 | print_prefixsets(&conf->prefixsets); | |||
1242 | print_originsets(&conf->originsets); | |||
1243 | TAILQ_FOREACH(n, &conf->networks, entry)for((n) = ((&conf->networks)->tqh_first); (n) != (( void *)0); (n) = ((n)->entry.tqe_next)) | |||
| ||||
1244 | print_network(&n->net, ""); | |||
1245 | RB_FOREACH(f, flowspec_tree, &conf->flowspecs)for ((f) = flowspec_tree_RB_MINMAX(&conf->flowspecs, - 1); (f) != ((void *)0); (f) = flowspec_tree_RB_NEXT(f)) | |||
1246 | print_flowspec(f, ""); | |||
1247 | if (!SIMPLEQ_EMPTY(&conf->l3vpns)(((&conf->l3vpns)->sqh_first) == ((void *)0))) | |||
1248 | printf("\n"); | |||
1249 | SIMPLEQ_FOREACH(vpn, &conf->l3vpns, entry)for((vpn) = ((&conf->l3vpns)->sqh_first); (vpn) != ( (void *)0); (vpn) = ((vpn)->entry.sqe_next)) | |||
1250 | print_l3vpn(vpn); | |||
1251 | printf("\n"); | |||
1252 | SIMPLEQ_FOREACH(rr, rib_l, entry)for((rr) = ((rib_l)->sqh_first); (rr) != ((void *)0); (rr) = ((rr)->entry.sqe_next)) { | |||
1253 | if (rr->flags & F_RIB_NOEVALUATE0x0002) | |||
1254 | printf("rde rib %s no evaluate\n", rr->name); | |||
1255 | else if (rr->flags & F_RIB_NOFIB0x0004) | |||
1256 | printf("rde rib %s\n", rr->name); | |||
1257 | else | |||
1258 | printf("rde rib %s rtable %u fib-update %s\n", rr->name, | |||
1259 | rr->rtableid, rr->flags & F_RIB_NOFIBSYNC0x0008 ? | |||
1260 | "no" : "yes"); | |||
1261 | } | |||
1262 | printf("\n"); | |||
1263 | print_mrt(conf, 0, 0, "", ""); | |||
1264 | print_groups(conf); | |||
1265 | TAILQ_FOREACH(r, conf->filters, entry)for((r) = ((conf->filters)->tqh_first); (r) != ((void * )0); (r) = ((r)->entry.tqe_next)) | |||
1266 | print_rule(conf, r); | |||
1267 | } |