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