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