xref: /openbsd/usr.sbin/bgpd/printconf.c (revision 097a140d)
1 /*	$OpenBSD: printconf.c,v 1.147 2021/03/02 09:45:07 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(u_int8_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(u_int8_t);
40 void		 print_network(struct network_config *, const char *);
41 void		 print_as_sets(struct as_set_head *);
42 void		 print_prefixsets(struct prefixset_head *);
43 void		 print_originsets(struct prefixset_head *);
44 void		 print_roa(struct roa_tree *);
45 void		 print_rtrs(struct rtr_config_head *);
46 void		 print_peer(struct peer_config *, struct bgpd_config *,
47 		    const char *);
48 const char	*print_auth_alg(u_int8_t);
49 const char	*print_enc_alg(u_int8_t);
50 void		 print_announce(struct peer_config *, const char *);
51 void		 print_as(struct filter_rule *);
52 void		 print_rule(struct bgpd_config *, struct filter_rule *);
53 const char	*mrt_type(enum mrt_type);
54 void		 print_mrt(struct bgpd_config *, u_int32_t, u_int32_t,
55 		    const char *, const char *);
56 void		 print_groups(struct bgpd_config *);
57 int		 peer_compare(const void *, const void *);
58 
59 void
60 print_prefix(struct filter_prefix *p)
61 {
62 	u_int8_t max_len = 0;
63 
64 	switch (p->addr.aid) {
65 	case AID_INET:
66 	case AID_VPN_IPv4:
67 		max_len = 32;
68 		break;
69 	case AID_INET6:
70 	case AID_VPN_IPv6:
71 		max_len = 128;
72 		break;
73 	case AID_UNSPEC:
74 		/* no prefix to print */
75 		return;
76 	}
77 
78 	printf("%s/%u", log_addr(&p->addr), p->len);
79 
80 	switch (p->op) {
81 	case OP_NONE:
82 		break;
83 	case OP_NE:
84 		printf(" prefixlen != %u", p->len_min);
85 		break;
86 	case OP_XRANGE:
87 		printf(" prefixlen %u >< %u ", p->len_min, p->len_max);
88 		break;
89 	case OP_RANGE:
90 		if (p->len_min == p->len_max && p->len != p->len_min)
91 			printf(" prefixlen = %u", p->len_min);
92 		else if (p->len == p->len_min && p->len_max == max_len)
93 			printf(" or-longer");
94 		else if (p->len == p->len_min && p->len != p->len_max)
95 			printf(" maxlen %u", p->len_max);
96 		else if (p->len_max == max_len)
97 			printf(" prefixlen >= %u", p->len_min);
98 		else
99 			printf(" prefixlen %u - %u", p->len_min, p->len_max);
100 		break;
101 	default:
102 		printf(" prefixlen %u ??? %u", p->len_min, p->len_max);
103 		break;
104 	}
105 }
106 
107 const char *
108 community_type(struct community *c)
109 {
110 	switch ((u_int8_t)c->flags) {
111 	case COMMUNITY_TYPE_BASIC:
112 		return "community";
113 	case COMMUNITY_TYPE_LARGE:
114 		return "large-community";
115 	case COMMUNITY_TYPE_EXT:
116 		return "ext-community";
117 	default:
118 		return "???";
119 	}
120 }
121 
122 void
123 print_community(struct community *c)
124 {
125 	struct in_addr addr;
126 	short type;
127 	u_int8_t subtype;
128 
129 	switch ((u_int8_t)c->flags) {
130 	case COMMUNITY_TYPE_BASIC:
131 		switch ((c->flags >> 8) & 0xff) {
132 		case COMMUNITY_ANY:
133 			printf("*:");
134 			break;
135 		case COMMUNITY_NEIGHBOR_AS:
136 			printf("neighbor-as:");
137 			break;
138 		case COMMUNITY_LOCAL_AS:
139 			printf("local-as:");
140 			break;
141 		default:
142 			printf("%u:", c->data1);
143 			break;
144 		}
145 		switch ((c->flags >> 16) & 0xff) {
146 		case COMMUNITY_ANY:
147 			printf("* ");
148 			break;
149 		case COMMUNITY_NEIGHBOR_AS:
150 			printf("neighbor-as ");
151 			break;
152 		case COMMUNITY_LOCAL_AS:
153 			printf("local-as ");
154 			break;
155 		default:
156 			printf("%u ", c->data2);
157 			break;
158 		}
159 		break;
160 	case COMMUNITY_TYPE_LARGE:
161 		switch ((c->flags >> 8) & 0xff) {
162 		case COMMUNITY_ANY:
163 			printf("*:");
164 			break;
165 		case COMMUNITY_NEIGHBOR_AS:
166 			printf("neighbor-as:");
167 			break;
168 		case COMMUNITY_LOCAL_AS:
169 			printf("local-as:");
170 			break;
171 		default:
172 			printf("%u:", c->data1);
173 			break;
174 		}
175 		switch ((c->flags >> 16) & 0xff) {
176 		case COMMUNITY_ANY:
177 			printf("*:");
178 			break;
179 		case COMMUNITY_NEIGHBOR_AS:
180 			printf("neighbor-as:");
181 			break;
182 		case COMMUNITY_LOCAL_AS:
183 			printf("local-as:");
184 			break;
185 		default:
186 			printf("%u:", c->data2);
187 			break;
188 		}
189 		switch ((c->flags >> 24) & 0xff) {
190 		case COMMUNITY_ANY:
191 			printf("* ");
192 			break;
193 		case COMMUNITY_NEIGHBOR_AS:
194 			printf("neighbor-as ");
195 			break;
196 		case COMMUNITY_LOCAL_AS:
197 			printf("local-as ");
198 			break;
199 		default:
200 			printf("%u ", c->data3);
201 			break;
202 		}
203 		break;
204 	case COMMUNITY_TYPE_EXT:
205 		if ((c->flags >> 24 & 0xff) == COMMUNITY_ANY) {
206 			printf("* * ");
207 			break;
208 		}
209 		type = (int32_t)c->data3 >> 8;
210 		subtype = c->data3;
211 		printf("%s ", log_ext_subtype(type, subtype));
212 		if ((c->flags >> 8 & 0xff) == COMMUNITY_ANY) {
213 			printf("* ");
214 			break;
215 		}
216 
217 		switch (type) {
218 		case EXT_COMMUNITY_TRANS_TWO_AS:
219 		case EXT_COMMUNITY_TRANS_FOUR_AS:
220 			if ((c->flags >> 8 & 0xff) == COMMUNITY_NEIGHBOR_AS)
221 				printf("neighbor-as:");
222 			else if ((c->flags >> 8 & 0xff) == COMMUNITY_LOCAL_AS)
223 				printf("local-as:");
224 			else
225 				printf("%s:", log_as(c->data1));
226 			break;
227 		case EXT_COMMUNITY_TRANS_IPV4:
228 			addr.s_addr = htonl(c->data1);
229 			printf("%s:", inet_ntoa(addr));
230 			break;
231 		}
232 
233 		switch (type) {
234 		case EXT_COMMUNITY_TRANS_TWO_AS:
235 		case EXT_COMMUNITY_TRANS_FOUR_AS:
236 		case EXT_COMMUNITY_TRANS_IPV4:
237 			if ((c->flags >> 16 & 0xff) == COMMUNITY_ANY)
238 				printf("* ");
239 			else if ((c->flags >> 16 & 0xff) ==
240 			    COMMUNITY_NEIGHBOR_AS)
241 				printf("neighbor-as ");
242 			else if ((c->flags >> 16 & 0xff) == COMMUNITY_LOCAL_AS)
243 				printf("local-as ");
244 			else
245 				printf("%u ", c->data2);
246 			break;
247 		case EXT_COMMUNITY_NON_TRANS_OPAQUE:
248 			if (subtype == EXT_COMMUNITY_SUBTYPE_OVS) {
249 				switch (c->data2) {
250 				case EXT_COMMUNITY_OVS_VALID:
251 					printf("valid ");
252 					break;
253 				case EXT_COMMUNITY_OVS_NOTFOUND:
254 					printf("not-found ");
255 					break;
256 				case EXT_COMMUNITY_OVS_INVALID:
257 					printf("invalid ");
258 					break;
259 				}
260 				break;
261 			}
262 			printf("0x%x%08x ", c->data1 & 0xffff, c->data2);
263 			break;
264 		case EXT_COMMUNITY_TRANS_OPAQUE:
265 		case EXT_COMMUNITY_TRANS_EVPN:
266 		default:
267 			printf("0x%x%08x ", c->data1 & 0xffff, c->data2);
268 			break;
269 		}
270 	}
271 }
272 
273 void
274 print_origin(u_int8_t o)
275 {
276 	if (o == ORIGIN_IGP)
277 		printf("igp ");
278 	else if (o == ORIGIN_EGP)
279 		printf("egp ");
280 	else if (o == ORIGIN_INCOMPLETE)
281 		printf("incomplete ");
282 	else
283 		printf("%u ", o);
284 }
285 
286 void
287 print_set(struct filter_set_head *set)
288 {
289 	struct filter_set	*s;
290 
291 	if (TAILQ_EMPTY(set))
292 		return;
293 
294 	printf("set { ");
295 	TAILQ_FOREACH(s, set, entry) {
296 		switch (s->type) {
297 		case ACTION_SET_LOCALPREF:
298 			printf("localpref %u ", s->action.metric);
299 			break;
300 		case ACTION_SET_RELATIVE_LOCALPREF:
301 			printf("localpref %+d ", s->action.relative);
302 			break;
303 		case ACTION_SET_MED:
304 			printf("metric %u ", s->action.metric);
305 			break;
306 		case ACTION_SET_RELATIVE_MED:
307 			printf("metric %+d ", s->action.relative);
308 			break;
309 		case ACTION_SET_WEIGHT:
310 			printf("weight %u ", s->action.metric);
311 			break;
312 		case ACTION_SET_RELATIVE_WEIGHT:
313 			printf("weight %+d ", s->action.relative);
314 			break;
315 		case ACTION_SET_NEXTHOP:
316 			printf("nexthop %s ", log_addr(&s->action.nexthop));
317 			break;
318 		case ACTION_SET_NEXTHOP_REJECT:
319 			printf("nexthop reject ");
320 			break;
321 		case ACTION_SET_NEXTHOP_BLACKHOLE:
322 			printf("nexthop blackhole ");
323 			break;
324 		case ACTION_SET_NEXTHOP_NOMODIFY:
325 			printf("nexthop no-modify ");
326 			break;
327 		case ACTION_SET_NEXTHOP_SELF:
328 			printf("nexthop self ");
329 			break;
330 		case ACTION_SET_PREPEND_SELF:
331 			printf("prepend-self %u ", s->action.prepend);
332 			break;
333 		case ACTION_SET_PREPEND_PEER:
334 			printf("prepend-neighbor %u ", s->action.prepend);
335 			break;
336 		case ACTION_SET_AS_OVERRIDE:
337 			printf("as-override ");
338 			break;
339 		case ACTION_DEL_COMMUNITY:
340 			printf("%s delete ",
341 			    community_type(&s->action.community));
342 			print_community(&s->action.community);
343 			break;
344 		case ACTION_SET_COMMUNITY:
345 			printf("%s ", community_type(&s->action.community));
346 			print_community(&s->action.community);
347 			break;
348 		case ACTION_PFTABLE:
349 			printf("pftable %s ", s->action.pftable);
350 			break;
351 		case ACTION_RTLABEL:
352 			printf("rtlabel %s ", s->action.rtlabel);
353 			break;
354 		case ACTION_SET_ORIGIN:
355 			printf("origin ");
356 			print_origin(s->action.origin);
357 			break;
358 		case ACTION_RTLABEL_ID:
359 		case ACTION_PFTABLE_ID:
360 		case ACTION_SET_NEXTHOP_REF:
361 			/* not possible */
362 			printf("king bula saiz: config broken");
363 			break;
364 		}
365 	}
366 	printf("}");
367 }
368 
369 void
370 print_mainconf(struct bgpd_config *conf)
371 {
372 	struct in_addr		 ina;
373 	struct listen_addr	*la;
374 
375 	printf("AS %s", log_as(conf->as));
376 	if (conf->as > USHRT_MAX && conf->short_as != AS_TRANS)
377 		printf(" %u", conf->short_as);
378 	ina.s_addr = conf->bgpid;
379 	printf("\nrouter-id %s\n", inet_ntoa(ina));
380 
381 	printf("socket \"%s\"\n", conf->csock);
382 	if (conf->rcsock)
383 		printf("socket \"%s\" restricted\n", conf->rcsock);
384 	if (conf->holdtime != INTERVAL_HOLD)
385 		printf("holdtime %u\n", conf->holdtime);
386 	if (conf->min_holdtime != MIN_HOLDTIME)
387 		printf("holdtime min %u\n", conf->min_holdtime);
388 	if (conf->connectretry != INTERVAL_CONNECTRETRY)
389 		printf("connect-retry %u\n", conf->connectretry);
390 
391 	if (conf->flags & BGPD_FLAG_DECISION_ROUTEAGE)
392 		printf("rde route-age evaluate\n");
393 	if (conf->flags & BGPD_FLAG_DECISION_MED_ALWAYS)
394 		printf("rde med compare always\n");
395 	if (conf->flags & BGPD_FLAG_DECISION_ALL_PATHS)
396 		printf("rde evaluate all\n");
397 
398 	if (conf->flags & BGPD_FLAG_NO_AS_SET)
399 		printf("reject as-set yes\n");
400 
401 	if (conf->log & BGPD_LOG_UPDATES)
402 		printf("log updates\n");
403 
404 	TAILQ_FOREACH(la, conf->listen_addrs, entry)
405 		printf("listen on %s\n",
406 		    log_sockaddr((struct sockaddr *)&la->sa, la->sa_len));
407 
408 	if (conf->flags & BGPD_FLAG_NEXTHOP_BGP)
409 		printf("nexthop qualify via bgp\n");
410 	if (conf->flags & BGPD_FLAG_NEXTHOP_DEFAULT)
411 		printf("nexthop qualify via default\n");
412 	if (conf->fib_priority != RTP_BGP)
413 		printf("fib-priority %hhu\n", conf->fib_priority);
414 	printf("\n");
415 }
416 
417 void
418 print_l3vpn_targets(struct filter_set_head *set, const char *tgt)
419 {
420 	struct filter_set	*s;
421 	TAILQ_FOREACH(s, set, entry) {
422 		printf("\t%s ", tgt);
423 		print_community(&s->action.community);
424 		printf("\n");
425 	}
426 }
427 
428 void
429 print_l3vpn(struct l3vpn *vpn)
430 {
431 	struct network *n;
432 
433 	printf("vpn \"%s\" on %s {\n", vpn->descr, vpn->ifmpe);
434 	printf("\t%s\n", log_rd(vpn->rd));
435 
436 	print_l3vpn_targets(&vpn->export, "export-target");
437 	print_l3vpn_targets(&vpn->import, "import-target");
438 
439 	if (vpn->flags & F_RIB_NOFIBSYNC)
440 		printf("\tfib-update no\n");
441 	else
442 		printf("\tfib-update yes\n");
443 
444 	TAILQ_FOREACH(n, &vpn->net_l, entry)
445 		print_network(&n->net, "\t");
446 
447 	printf("}\n");
448 }
449 
450 const char *
451 print_af(u_int8_t aid)
452 {
453 	/*
454 	 * Hack around the fact that aid2str() will return "IPv4 unicast"
455 	 * for AID_INET. AID_INET and AID_INET6 need special handling and
456 	 * the other AID should never end up here (at least for now).
457 	 */
458 	if (aid == AID_INET)
459 		return ("inet");
460 	if (aid == AID_INET6)
461 		return ("inet6");
462 	return (aid2str(aid));
463 }
464 
465 void
466 print_network(struct network_config *n, const char *c)
467 {
468 	switch (n->type) {
469 	case NETWORK_STATIC:
470 		printf("%snetwork %s static", c, print_af(n->prefix.aid));
471 		break;
472 	case NETWORK_CONNECTED:
473 		printf("%snetwork %s connected", c, print_af(n->prefix.aid));
474 		break;
475 	case NETWORK_RTLABEL:
476 		printf("%snetwork %s rtlabel \"%s\"", c,
477 		    print_af(n->prefix.aid), rtlabel_id2name(n->rtlabel));
478 		break;
479 	case NETWORK_PRIORITY:
480 		printf("%snetwork %s priority %d", c,
481 		    print_af(n->prefix.aid), n->priority);
482 		break;
483 	case NETWORK_PREFIXSET:
484 		printf("%snetwork prefix-set %s", c, n->psname);
485 		break;
486 	default:
487 		printf("%snetwork %s/%u", c, log_addr(&n->prefix),
488 		    n->prefixlen);
489 		break;
490 	}
491 	if (!TAILQ_EMPTY(&n->attrset))
492 		printf(" ");
493 	print_set(&n->attrset);
494 	printf("\n");
495 }
496 
497 void
498 print_as_sets(struct as_set_head *as_sets)
499 {
500 	struct as_set *aset;
501 	u_int32_t *as;
502 	size_t i, n;
503 	int len;
504 
505 	SIMPLEQ_FOREACH(aset, as_sets, entry) {
506 		printf("as-set \"%s\" {\n\t", aset->name);
507 		as = set_get(aset->set, &n);
508 		for (i = 0, len = 8; i < n; i++) {
509 			if (len > 72) {
510 				printf("\n\t");
511 				len = 8;
512 			}
513 			len += printf("%u ", as[i]);
514 		}
515 		printf("\n}\n\n");
516 	}
517 }
518 
519 void
520 print_prefixsets(struct prefixset_head *psh)
521 {
522 	struct prefixset	*ps;
523 	struct prefixset_item	*psi;
524 
525 	SIMPLEQ_FOREACH(ps, psh, entry) {
526 		int count = 0;
527 		printf("prefix-set \"%s\" {", ps->name);
528 		RB_FOREACH(psi, prefixset_tree, &ps->psitems) {
529 			if (count++ % 2 == 0)
530 				printf("\n\t");
531 			else
532 				printf(", ");
533 			print_prefix(&psi->p);
534 		}
535 		printf("\n}\n\n");
536 	}
537 }
538 
539 void
540 print_originsets(struct prefixset_head *psh)
541 {
542 	struct prefixset	*ps;
543 	struct roa		*roa;
544 	struct bgpd_addr	 addr;
545 
546 	SIMPLEQ_FOREACH(ps, psh, entry) {
547 		printf("origin-set \"%s\" {", ps->name);
548 		RB_FOREACH(roa, roa_tree, &ps->roaitems) {
549 			printf("\n\t");
550 			addr.aid = roa->aid;
551 			addr.v6 = roa->prefix.inet6;
552 			printf("%s/%u", log_addr(&addr), roa->prefixlen);
553 			if (roa->prefixlen != roa->maxlen)
554 				printf(" maxlen %u", roa->maxlen);
555 			printf(" source-as %u", roa->asnum);
556 		}
557 		printf("\n}\n\n");
558 	}
559 }
560 
561 void
562 print_roa(struct roa_tree *r)
563 {
564 	struct roa	*roa;
565 	struct bgpd_addr addr;
566 
567 	if (RB_EMPTY(r))
568 		return;
569 
570 	printf("roa-set {");
571 	RB_FOREACH(roa, roa_tree, r) {
572 		printf("\n\t");
573 		addr.aid = roa->aid;
574 		addr.v6 = roa->prefix.inet6;
575 		printf("%s/%u", log_addr(&addr), roa->prefixlen);
576 		if (roa->prefixlen != roa->maxlen)
577 			printf(" maxlen %u", roa->maxlen);
578 		printf(" source-as %u", roa->asnum);
579 	}
580 	printf("\n}\n\n");
581 }
582 
583 void
584 print_rtrs(struct rtr_config_head *rh)
585 {
586 	struct rtr_config *r;
587 
588 	SIMPLEQ_FOREACH(r, rh, entry) {
589 		printf("rtr %s {\n", log_addr(&r->remote_addr));
590 		printf("\tdescr \"%s\"\n", r->descr);
591 		printf("\tport %u\n", r->remote_port);
592 		if (r->local_addr.aid != AID_UNSPEC)
593 			printf("local-addr %s\n", log_addr(&r->local_addr));
594 		printf("}\n\n");
595 	}
596 }
597 
598 void
599 print_peer(struct peer_config *p, struct bgpd_config *conf, const char *c)
600 {
601 	char		*method;
602 	struct in_addr	 ina;
603 
604 	if ((p->remote_addr.aid == AID_INET && p->remote_masklen != 32) ||
605 	    (p->remote_addr.aid == AID_INET6 && p->remote_masklen != 128))
606 		printf("%sneighbor %s/%u {\n", c, log_addr(&p->remote_addr),
607 		    p->remote_masklen);
608 	else
609 		printf("%sneighbor %s {\n", c, log_addr(&p->remote_addr));
610 	if (p->descr[0])
611 		printf("%s\tdescr \"%s\"\n", c, p->descr);
612 	if (p->rib[0])
613 		printf("%s\trib \"%s\"\n", c, p->rib);
614 	if (p->remote_as)
615 		printf("%s\tremote-as %s\n", c, log_as(p->remote_as));
616 	if (p->local_as != conf->as) {
617 		printf("%s\tlocal-as %s", c, log_as(p->local_as));
618 		if (p->local_as > USHRT_MAX && p->local_short_as != AS_TRANS)
619 			printf(" %u", p->local_short_as);
620 		printf("\n");
621 	}
622 	if (p->down)
623 		printf("%s\tdown\n", c);
624 	if (p->distance > 1)
625 		printf("%s\tmultihop %u\n", c, p->distance);
626 	if (p->passive)
627 		printf("%s\tpassive\n", c);
628 	if (p->local_addr_v4.aid)
629 		printf("%s\tlocal-address %s\n", c,
630 		   log_addr(&p->local_addr_v4));
631 	if (p->local_addr_v6.aid)
632 		printf("%s\tlocal-address %s\n", c,
633 		   log_addr(&p->local_addr_v6));
634 	if (p->max_prefix) {
635 		printf("%s\tmax-prefix %u", c, p->max_prefix);
636 		if (p->max_prefix_restart)
637 			printf(" restart %u", p->max_prefix_restart);
638 		printf("\n");
639 	}
640 	if (p->max_out_prefix) {
641 		printf("%s\tmax-prefix %u out", c, p->max_out_prefix);
642 		if (p->max_out_prefix_restart)
643 			printf(" restart %u", p->max_out_prefix_restart);
644 		printf("\n");
645 	}
646 	if (p->holdtime)
647 		printf("%s\tholdtime %u\n", c, p->holdtime);
648 	if (p->min_holdtime)
649 		printf("%s\tholdtime min %u\n", c, p->min_holdtime);
650 	if (p->announce_capa == 0)
651 		printf("%s\tannounce capabilities no\n", c);
652 	if (p->capabilities.refresh == 0)
653 		printf("%s\tannounce refresh no\n", c);
654 	if (p->capabilities.grestart.restart == 0)
655 		printf("%s\tannounce restart no\n", c);
656 	if (p->capabilities.as4byte == 0)
657 		printf("%s\tannounce as4byte no\n", c);
658 	if (p->export_type == EXPORT_NONE)
659 		printf("%s\texport none\n", c);
660 	else if (p->export_type == EXPORT_DEFAULT_ROUTE)
661 		printf("%s\texport default-route\n", c);
662 	if (p->enforce_as == ENFORCE_AS_ON)
663 		printf("%s\tenforce neighbor-as yes\n", c);
664 	else
665 		printf("%s\tenforce neighbor-as no\n", c);
666 	if (p->enforce_local_as == ENFORCE_AS_ON)
667 		printf("%s\tenforce local-as yes\n", c);
668 	else
669 		printf("%s\tenforce local-as no\n", c);
670 	if (p->reflector_client) {
671 		if (conf->clusterid == 0)
672 			printf("%s\troute-reflector\n", c);
673 		else {
674 			ina.s_addr = conf->clusterid;
675 			printf("%s\troute-reflector %s\n", c,
676 			    inet_ntoa(ina));
677 		}
678 	}
679 	if (p->demote_group[0])
680 		printf("%s\tdemote %s\n", c, p->demote_group);
681 	if (p->if_depend[0])
682 		printf("%s\tdepend on \"%s\"\n", c, p->if_depend);
683 	if (p->flags & PEERFLAG_TRANS_AS)
684 		printf("%s\ttransparent-as yes\n", c);
685 
686 	if (conf->flags & BGPD_FLAG_DECISION_ALL_PATHS) {
687 		if (!(p->flags & PEERFLAG_EVALUATE_ALL))
688 			printf("%s\trde evaluate default\n", c);
689 	} else {
690 		if (p->flags & PEERFLAG_EVALUATE_ALL)
691 			printf("%s\trde evaluate all\n", c);
692 	}
693 
694 	if (conf->flags & BGPD_FLAG_NO_AS_SET) {
695 		if (!(p->flags & PEERFLAG_NO_AS_SET))
696 			printf("%s\treject as-set no\n", c);
697 	} else {
698 		if (p->flags & PEERFLAG_NO_AS_SET)
699 			printf("%s\treject as-set yes\n", c);
700 	}
701 
702 	if (p->flags & PEERFLAG_LOG_UPDATES)
703 		printf("%s\tlog updates\n", c);
704 
705 	if (p->auth.method == AUTH_MD5SIG)
706 		printf("%s\ttcp md5sig\n", c);
707 	else if (p->auth.method == AUTH_IPSEC_MANUAL_ESP ||
708 	    p->auth.method == AUTH_IPSEC_MANUAL_AH) {
709 		if (p->auth.method == AUTH_IPSEC_MANUAL_ESP)
710 			method = "esp";
711 		else
712 			method = "ah";
713 
714 		printf("%s\tipsec %s in spi %u %s XXXXXX", c, method,
715 		    p->auth.spi_in, print_auth_alg(p->auth.auth_alg_in));
716 		if (p->auth.enc_alg_in)
717 			printf(" %s XXXXXX", print_enc_alg(p->auth.enc_alg_in));
718 		printf("\n");
719 
720 		printf("%s\tipsec %s out spi %u %s XXXXXX", c, method,
721 		    p->auth.spi_out, print_auth_alg(p->auth.auth_alg_out));
722 		if (p->auth.enc_alg_out)
723 			printf(" %s XXXXXX",
724 			    print_enc_alg(p->auth.enc_alg_out));
725 		printf("\n");
726 	} else if (p->auth.method == AUTH_IPSEC_IKE_AH)
727 		printf("%s\tipsec ah ike\n", c);
728 	else if (p->auth.method == AUTH_IPSEC_IKE_ESP)
729 		printf("%s\tipsec esp ike\n", c);
730 
731 	if (p->ttlsec)
732 		printf("%s\tttl-security yes\n", c);
733 
734 	print_announce(p, c);
735 
736 	print_mrt(conf, p->id, p->groupid, c, "\t");
737 
738 	printf("%s}\n", c);
739 }
740 
741 const char *
742 print_auth_alg(u_int8_t alg)
743 {
744 	switch (alg) {
745 	case SADB_AALG_SHA1HMAC:
746 		return ("sha1");
747 	case SADB_AALG_MD5HMAC:
748 		return ("md5");
749 	default:
750 		return ("???");
751 	}
752 }
753 
754 const char *
755 print_enc_alg(u_int8_t alg)
756 {
757 	switch (alg) {
758 	case SADB_EALG_3DESCBC:
759 		return ("3des");
760 	case SADB_X_EALG_AES:
761 		return ("aes");
762 	default:
763 		return ("???");
764 	}
765 }
766 
767 void
768 print_announce(struct peer_config *p, const char *c)
769 {
770 	u_int8_t	aid;
771 
772 	for (aid = 0; aid < AID_MAX; aid++)
773 		if (p->capabilities.mp[aid])
774 			printf("%s\tannounce %s\n", c, aid2str(aid));
775 }
776 
777 void
778 print_as(struct filter_rule *r)
779 {
780 	if (r->match.as.flags & AS_FLAG_AS_SET_NAME) {
781 		printf("as-set \"%s\" ", r->match.as.name);
782 		return;
783 	}
784 	switch (r->match.as.op) {
785 	case OP_RANGE:
786 		printf("%s - ", log_as(r->match.as.as_min));
787 		printf("%s ", log_as(r->match.as.as_max));
788 		break;
789 	case OP_XRANGE:
790 		printf("%s >< ", log_as(r->match.as.as_min));
791 		printf("%s ", log_as(r->match.as.as_max));
792 		break;
793 	case OP_NE:
794 		printf("!= %s ", log_as(r->match.as.as_min));
795 		break;
796 	default:
797 		printf("%s ", log_as(r->match.as.as_min));
798 		break;
799 	}
800 }
801 
802 void
803 print_rule(struct bgpd_config *conf, struct filter_rule *r)
804 {
805 	struct peer *p;
806 	int i;
807 
808 	if (r->action == ACTION_ALLOW)
809 		printf("allow ");
810 	else if (r->action == ACTION_DENY)
811 		printf("deny ");
812 	else
813 		printf("match ");
814 	if (r->quick)
815 		printf("quick ");
816 
817 	if (r->rib[0])
818 		printf("rib %s ", r->rib);
819 
820 	if (r->dir == DIR_IN)
821 		printf("from ");
822 	else if (r->dir == DIR_OUT)
823 		printf("to ");
824 	else
825 		printf("eeeeeeeps. ");
826 
827 	if (r->peer.peerid) {
828 		RB_FOREACH(p, peer_head, &conf->peers)
829 			if (p->conf.id == r->peer.peerid)
830 				break;
831 		if (p == NULL)
832 			printf("? ");
833 		else
834 			printf("%s ", log_addr(&p->conf.remote_addr));
835 	} else if (r->peer.groupid) {
836 		RB_FOREACH(p, peer_head, &conf->peers)
837 			if (p->conf.groupid == r->peer.groupid)
838 				break;
839 		if (p == NULL)
840 			printf("group ? ");
841 		else
842 			printf("group \"%s\" ", p->conf.group);
843 	} else if (r->peer.remote_as) {
844 		printf("AS %s ", log_as(r->peer.remote_as));
845 	} else if (r->peer.ebgp) {
846 		printf("ebgp ");
847 	} else if (r->peer.ibgp) {
848 		printf("ibgp ");
849 	} else
850 		printf("any ");
851 
852 	if (r->match.ovs.is_set) {
853 		switch (r->match.ovs.validity) {
854 		case ROA_VALID:
855 			printf("ovs valid ");
856 			break;
857 		case ROA_INVALID:
858 			printf("ovs invalid ");
859 			break;
860 		case ROA_NOTFOUND:
861 			printf("ovs not-found ");
862 			break;
863 		default:
864 			printf("ovs ??? %d ??? ", r->match.ovs.validity);
865 		}
866 	}
867 
868 	if (r->match.prefix.addr.aid != AID_UNSPEC) {
869 		printf("prefix ");
870 		print_prefix(&r->match.prefix);
871 		printf(" ");
872 	}
873 
874 	if (r->match.prefixset.name[0] != '\0')
875 		printf("prefix-set \"%s\" ", r->match.prefixset.name);
876 	if (r->match.prefixset.flags & PREFIXSET_FLAG_LONGER)
877 		printf("or-longer ");
878 
879 	if (r->match.originset.name[0] != '\0')
880 		printf("origin-set \"%s\" ", r->match.originset.name);
881 
882 	if (r->match.nexthop.flags) {
883 		if (r->match.nexthop.flags == FILTER_NEXTHOP_NEIGHBOR)
884 			printf("nexthop neighbor ");
885 		else
886 			printf("nexthop %s ", log_addr(&r->match.nexthop.addr));
887 	}
888 
889 	if (r->match.as.type) {
890 		if (r->match.as.type == AS_ALL)
891 			printf("AS ");
892 		else if (r->match.as.type == AS_SOURCE)
893 			printf("source-as ");
894 		else if (r->match.as.type == AS_TRANSIT)
895 			printf("transit-as ");
896 		else if (r->match.as.type == AS_PEER)
897 			printf("peer-as ");
898 		else
899 			printf("unfluffy-as ");
900 		print_as(r);
901 	}
902 
903 	if (r->match.aslen.type) {
904 		printf("%s %u ", r->match.aslen.type == ASLEN_MAX ?
905 		    "max-as-len" : "max-as-seq", r->match.aslen.aslen);
906 	}
907 
908 	for (i = 0; i < MAX_COMM_MATCH; i++) {
909 		struct community *c = &r->match.community[i];
910 		if (c->flags != 0) {
911 			printf("%s ", community_type(c));
912 			print_community(c);
913 		}
914 	}
915 
916 	print_set(&r->set);
917 
918 	printf("\n");
919 }
920 
921 const char *
922 mrt_type(enum mrt_type t)
923 {
924 	switch (t) {
925 	case MRT_NONE:
926 		break;
927 	case MRT_TABLE_DUMP:
928 		return "table";
929 	case MRT_TABLE_DUMP_MP:
930 		return "table-mp";
931 	case MRT_TABLE_DUMP_V2:
932 		return "table-v2";
933 	case MRT_ALL_IN:
934 		return "all in";
935 	case MRT_ALL_OUT:
936 		return "all out";
937 	case MRT_UPDATE_IN:
938 		return "updates in";
939 	case MRT_UPDATE_OUT:
940 		return "updates out";
941 	}
942 	return "unfluffy MRT";
943 }
944 
945 void
946 print_mrt(struct bgpd_config *conf, u_int32_t pid, u_int32_t gid,
947     const char *prep, const char *prep2)
948 {
949 	struct mrt	*m;
950 
951 	if (conf->mrt == NULL)
952 		return;
953 
954 	LIST_FOREACH(m, conf->mrt, entry)
955 		if ((gid != 0 && m->group_id == gid) ||
956 		    (m->peer_id == pid && m->group_id == gid)) {
957 			printf("%s%sdump ", prep, prep2);
958 			if (m->rib[0])
959 				printf("rib %s ", m->rib);
960 			printf("%s \"%s\"", mrt_type(m->type),
961 			    MRT2MC(m)->name);
962 			if (MRT2MC(m)->ReopenTimerInterval == 0)
963 				printf("\n");
964 			else
965 				printf(" %d\n", MRT2MC(m)->ReopenTimerInterval);
966 		}
967 	if (!LIST_EMPTY(conf->mrt))
968 		printf("\n");
969 }
970 
971 void
972 print_groups(struct bgpd_config *conf)
973 {
974 	struct peer_config	**peerlist;
975 	struct peer		 *p;
976 	u_int			  peer_cnt, i;
977 	u_int32_t		  prev_groupid;
978 	const char		 *tab	= "\t";
979 	const char		 *nada	= "";
980 	const char		 *c;
981 
982 	peer_cnt = 0;
983 	RB_FOREACH(p, peer_head, &conf->peers)
984 		peer_cnt++;
985 
986 	if ((peerlist = calloc(peer_cnt, sizeof(struct peer_config *))) == NULL)
987 		fatal("print_groups calloc");
988 
989 	i = 0;
990 	RB_FOREACH(p, peer_head, &conf->peers)
991 		peerlist[i++] = &p->conf;
992 
993 	qsort(peerlist, peer_cnt, sizeof(struct peer_config *), peer_compare);
994 
995 	prev_groupid = 0;
996 	for (i = 0; i < peer_cnt; i++) {
997 		if (peerlist[i]->groupid) {
998 			c = tab;
999 			if (peerlist[i]->groupid != prev_groupid) {
1000 				if (prev_groupid)
1001 					printf("}\n\n");
1002 				printf("group \"%s\" {\n", peerlist[i]->group);
1003 				prev_groupid = peerlist[i]->groupid;
1004 			}
1005 		} else
1006 			c = nada;
1007 
1008 		print_peer(peerlist[i], conf, c);
1009 	}
1010 
1011 	if (prev_groupid)
1012 		printf("}\n\n");
1013 
1014 	free(peerlist);
1015 }
1016 
1017 int
1018 peer_compare(const void *aa, const void *bb)
1019 {
1020 	const struct peer_config * const *a;
1021 	const struct peer_config * const *b;
1022 
1023 	a = aa;
1024 	b = bb;
1025 
1026 	return ((*a)->groupid - (*b)->groupid);
1027 }
1028 
1029 void
1030 print_config(struct bgpd_config *conf, struct rib_names *rib_l)
1031 {
1032 	struct filter_rule	*r;
1033 	struct network		*n;
1034 	struct rde_rib		*rr;
1035 	struct l3vpn		*vpn;
1036 
1037 	print_mainconf(conf);
1038 	print_rtrs(&conf->rtrs);
1039 	print_roa(&conf->roa);
1040 	print_as_sets(&conf->as_sets);
1041 	print_prefixsets(&conf->prefixsets);
1042 	print_originsets(&conf->originsets);
1043 	TAILQ_FOREACH(n, &conf->networks, entry)
1044 		print_network(&n->net, "");
1045 	if (!SIMPLEQ_EMPTY(&conf->l3vpns))
1046 		printf("\n");
1047 	SIMPLEQ_FOREACH(vpn, &conf->l3vpns, entry)
1048 		print_l3vpn(vpn);
1049 	printf("\n");
1050 	SIMPLEQ_FOREACH(rr, rib_l, entry) {
1051 		if (rr->flags & F_RIB_NOEVALUATE)
1052 			printf("rde rib %s no evaluate\n", rr->name);
1053 		else if (rr->flags & F_RIB_NOFIB)
1054 			printf("rde rib %s\n", rr->name);
1055 		else
1056 			printf("rde rib %s rtable %u fib-update %s\n", rr->name,
1057 			    rr->rtableid, rr->flags & F_RIB_NOFIBSYNC ?
1058 			    "no" : "yes");
1059 	}
1060 	printf("\n");
1061 	print_mrt(conf, 0, 0, "", "");
1062 	print_groups(conf);
1063 	TAILQ_FOREACH(r, conf->filters, entry)
1064 		print_rule(conf, r);
1065 }
1066