xref: /openbsd-src/usr.sbin/bgpctl/bgpctl.c (revision c7e8ea31cd41a963f06f0a8ba93948b06aa6b4a4)
1 /*	$OpenBSD: bgpctl.c,v 1.199 2017/08/10 14:22:59 benno Exp $ */
2 
3 /*
4  * Copyright (c) 2003 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 OR PROFITS, WHETHER IN AN
17  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19  */
20 
21 #include <sys/types.h>
22 #include <sys/socket.h>
23 #include <sys/stat.h>
24 #include <sys/un.h>
25 #include <net/if.h>
26 #include <net/if_media.h>
27 #include <net/if_types.h>
28 
29 #include <err.h>
30 #include <errno.h>
31 #include <fcntl.h>
32 #include <netdb.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <unistd.h>
37 #include <util.h>
38 
39 #include "bgpd.h"
40 #include "session.h"
41 #include "rde.h"
42 #include "parser.h"
43 #include "irrfilter.h"
44 #include "mrtparser.h"
45 
46 enum neighbor_views {
47 	NV_DEFAULT,
48 	NV_TIMERS
49 };
50 
51 int		 main(int, char *[]);
52 char		*fmt_peer(const char *, const struct bgpd_addr *, int, int);
53 void		 show_summary_head(void);
54 int		 show_summary_msg(struct imsg *, int);
55 int		 show_summary_terse_msg(struct imsg *, int);
56 int		 show_neighbor_terse(struct imsg *);
57 int		 show_neighbor_msg(struct imsg *, enum neighbor_views);
58 void		 print_neighbor_capa_mp(struct peer *);
59 void		 print_neighbor_capa_restart(struct peer *);
60 void		 print_neighbor_msgstats(struct peer *);
61 void		 print_timer(const char *, time_t);
62 static char	*fmt_timeframe(time_t t);
63 static char	*fmt_timeframe_core(time_t t);
64 void		 show_fib_head(void);
65 void		 show_fib_tables_head(void);
66 void		 show_network_head(void);
67 void		 show_fib_flags(u_int16_t);
68 int		 show_fib_msg(struct imsg *);
69 void		 show_nexthop_head(void);
70 int		 show_nexthop_msg(struct imsg *);
71 void		 show_interface_head(void);
72 uint64_t	 ift2ifm(uint8_t);
73 const char *	 get_media_descr(uint64_t);
74 const char *	 get_linkstate(uint8_t, int);
75 const char *	 get_baudrate(u_int64_t, char *);
76 int		 show_interface_msg(struct imsg *);
77 void		 show_rib_summary_head(void);
78 void		 print_prefix(struct bgpd_addr *, u_int8_t, u_int8_t);
79 const char *	 print_origin(u_int8_t, int);
80 void		 print_flags(u_int8_t, int);
81 int		 show_rib_summary_msg(struct imsg *);
82 int		 show_rib_detail_msg(struct imsg *, int);
83 void		 show_rib_brief(struct ctl_show_rib *, u_char *);
84 void		 show_rib_detail(struct ctl_show_rib *, u_char *, int);
85 void		 show_attr(void *, u_int16_t);
86 void		 show_community(u_char *, u_int16_t);
87 void		 show_large_community(u_char *, u_int16_t);
88 void		 show_ext_community(u_char *, u_int16_t);
89 char		*fmt_mem(int64_t);
90 int		 show_rib_memory_msg(struct imsg *);
91 void		 send_filterset(struct imsgbuf *, struct filter_set_head *);
92 const char	*get_errstr(u_int8_t, u_int8_t);
93 int		 show_result(struct imsg *);
94 void		 show_mrt_dump(struct mrt_rib *, struct mrt_peer *, void *);
95 void		 network_mrt_dump(struct mrt_rib *, struct mrt_peer *, void *);
96 void		 show_mrt_state(struct mrt_bgp_state *, void *);
97 void		 show_mrt_msg(struct mrt_bgp_msg *, void *);
98 void		 mrt_to_bgpd_addr(union mrt_addr *, struct bgpd_addr *);
99 const char	*msg_type(u_int8_t);
100 void		 network_bulk(struct parse_result *);
101 const char	*print_auth_method(enum auth_method);
102 
103 struct imsgbuf	*ibuf;
104 struct mrt_parser show_mrt = { show_mrt_dump, show_mrt_state, show_mrt_msg };
105 struct mrt_parser net_mrt = { network_mrt_dump, NULL, NULL };
106 
107 __dead void
108 usage(void)
109 {
110 	extern char	*__progname;
111 
112 	fprintf(stderr, "usage: %s [-n] [-s socket] command [argument ...]\n",
113 	    __progname);
114 	exit(1);
115 }
116 
117 int
118 main(int argc, char *argv[])
119 {
120 	struct sockaddr_un	 sun;
121 	int			 fd, n, done, ch, nodescr = 0, verbose = 0, r;
122 	struct imsg		 imsg;
123 	struct network_config	 net;
124 	struct parse_result	*res;
125 	struct ctl_neighbor	 neighbor;
126 	struct ctl_show_rib_request	ribreq;
127 	char			*sockname;
128 	enum imsg_type		 type;
129 
130 	r = getrtable();
131 	if (asprintf(&sockname, "%s.%d", SOCKET_NAME, r) == -1)
132 		err(1, "asprintf");
133 
134 	if (pledge("stdio rpath wpath cpath unix inet dns", NULL) == -1)
135 		err(1, "pledge");
136 
137 	while ((ch = getopt(argc, argv, "ns:")) != -1) {
138 		switch (ch) {
139 		case 'n':
140 			if (++nodescr > 1)
141 				usage();
142 			break;
143 		case 's':
144 			sockname = optarg;
145 			break;
146 		default:
147 			usage();
148 			/* NOTREACHED */
149 		}
150 	}
151 	argc -= optind;
152 	argv += optind;
153 
154 	if ((res = parse(argc, argv)) == NULL)
155 		exit(1);
156 
157 	if (res->action == IRRFILTER) {
158 		if (!(res->flags & (F_IPV4|F_IPV6)))
159 			res->flags |= (F_IPV4|F_IPV6);
160 		irr_main(res->as.as, res->flags, res->irr_outdir);
161 	}
162 
163 	if (pledge("stdio rpath wpath unix", NULL) == -1)
164 		err(1, "pledge");
165 
166 	memcpy(&neighbor.addr, &res->peeraddr, sizeof(neighbor.addr));
167 	strlcpy(neighbor.descr, res->peerdesc, sizeof(neighbor.descr));
168 	strlcpy(neighbor.shutcomm, res->shutcomm, sizeof(neighbor.shutcomm));
169 
170 	if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
171 		err(1, "control_init: socket");
172 
173 	bzero(&sun, sizeof(sun));
174 	sun.sun_family = AF_UNIX;
175 	if (strlcpy(sun.sun_path, sockname, sizeof(sun.sun_path)) >=
176 	    sizeof(sun.sun_path))
177 		errx(1, "socket name too long");
178 	if (connect(fd, (struct sockaddr *)&sun, sizeof(sun)) == -1)
179 		err(1, "connect: %s", sockname);
180 
181 	if (pledge("stdio rpath wpath", NULL) == -1)
182 		err(1, "pledge");
183 
184 	if ((ibuf = malloc(sizeof(struct imsgbuf))) == NULL)
185 		err(1, NULL);
186 	imsg_init(ibuf, fd);
187 	done = 0;
188 
189 	switch (res->action) {
190 	case NONE:
191 	case IRRFILTER:
192 		usage();
193 		/* NOTREACHED */
194 	case SHOW:
195 	case SHOW_SUMMARY:
196 		imsg_compose(ibuf, IMSG_CTL_SHOW_NEIGHBOR, 0, 0, -1, NULL, 0);
197 		show_summary_head();
198 		break;
199 	case SHOW_SUMMARY_TERSE:
200 		imsg_compose(ibuf, IMSG_CTL_SHOW_TERSE, 0, 0, -1, NULL, 0);
201 		break;
202 	case SHOW_FIB:
203 		if (!res->addr.aid) {
204 			struct ibuf	*msg;
205 			sa_family_t	 af;
206 
207 			af = aid2af(res->aid);
208 			if ((msg = imsg_create(ibuf, IMSG_CTL_KROUTE,
209 			    res->rtableid, 0, sizeof(res->flags) +
210 			    sizeof(af))) == NULL)
211 				errx(1, "imsg_create failure");
212 			if (imsg_add(msg, &res->flags, sizeof(res->flags)) ==
213 			    -1 ||
214 			    imsg_add(msg, &af, sizeof(af)) == -1)
215 				errx(1, "imsg_add failure");
216 			imsg_close(ibuf, msg);
217 		} else
218 			imsg_compose(ibuf, IMSG_CTL_KROUTE_ADDR, res->rtableid,
219 			    0, -1, &res->addr, sizeof(res->addr));
220 		show_fib_head();
221 		break;
222 	case SHOW_FIB_TABLES:
223 		imsg_compose(ibuf, IMSG_CTL_SHOW_FIB_TABLES, 0, 0, -1, NULL, 0);
224 		show_fib_tables_head();
225 		break;
226 	case SHOW_NEXTHOP:
227 		imsg_compose(ibuf, IMSG_CTL_SHOW_NEXTHOP, res->rtableid, 0, -1,
228 		    NULL, 0);
229 		show_nexthop_head();
230 		break;
231 	case SHOW_INTERFACE:
232 		imsg_compose(ibuf, IMSG_CTL_SHOW_INTERFACE, 0, 0, -1, NULL, 0);
233 		show_interface_head();
234 		break;
235 	case SHOW_NEIGHBOR:
236 	case SHOW_NEIGHBOR_TIMERS:
237 	case SHOW_NEIGHBOR_TERSE:
238 		neighbor.show_timers = (res->action == SHOW_NEIGHBOR_TIMERS);
239 		if (res->peeraddr.aid || res->peerdesc[0])
240 			imsg_compose(ibuf, IMSG_CTL_SHOW_NEIGHBOR, 0, 0, -1,
241 			    &neighbor, sizeof(neighbor));
242 		else
243 			imsg_compose(ibuf, IMSG_CTL_SHOW_NEIGHBOR, 0, 0, -1,
244 			    NULL, 0);
245 		break;
246 	case SHOW_RIB:
247 		bzero(&ribreq, sizeof(ribreq));
248 		type = IMSG_CTL_SHOW_RIB;
249 		if (res->as.type != AS_NONE) {
250 			ribreq.as = res->as;
251 			type = IMSG_CTL_SHOW_RIB_AS;
252 		}
253 		if (res->addr.aid) {
254 			ribreq.prefix = res->addr;
255 			ribreq.prefixlen = res->prefixlen;
256 			type = IMSG_CTL_SHOW_RIB_PREFIX;
257 		}
258 		if (res->community.as != COMMUNITY_UNSET &&
259 		    res->community.type != COMMUNITY_UNSET) {
260 			ribreq.community = res->community;
261 			type = IMSG_CTL_SHOW_RIB_COMMUNITY;
262 		}
263 		if (res->extcommunity.flags == EXT_COMMUNITY_FLAG_VALID) {
264 			ribreq.extcommunity = res->extcommunity;
265 			type = IMSG_CTL_SHOW_RIB_EXTCOMMUNITY;
266 		}
267 		if (res->large_community.as != COMMUNITY_UNSET &&
268 		    res->large_community.ld1 != COMMUNITY_UNSET &&
269 		    res->large_community.ld2 != COMMUNITY_UNSET) {
270 			ribreq.large_community = res->large_community;
271 			type = IMSG_CTL_SHOW_RIB_LARGECOMMUNITY;
272 		}
273 		ribreq.neighbor = neighbor;
274 		strlcpy(ribreq.rib, res->rib, sizeof(ribreq.rib));
275 		ribreq.aid = res->aid;
276 		ribreq.flags = res->flags;
277 		imsg_compose(ibuf, type, 0, 0, -1, &ribreq, sizeof(ribreq));
278 		if (!(res->flags & F_CTL_DETAIL))
279 			show_rib_summary_head();
280 		break;
281 	case SHOW_MRT:
282 		close(fd);
283 		bzero(&ribreq, sizeof(ribreq));
284 		if (res->as.type != AS_NONE)
285 			ribreq.as = res->as;
286 		if (res->addr.aid) {
287 			ribreq.prefix = res->addr;
288 			ribreq.prefixlen = res->prefixlen;
289 		}
290 		if (res->community.as != COMMUNITY_UNSET &&
291 		    res->community.type != COMMUNITY_UNSET)
292 			ribreq.community = res->community;
293 		if (res->large_community.as != COMMUNITY_UNSET &&
294 		    res->large_community.ld1 != COMMUNITY_UNSET &&
295 		    res->large_community.ld2 != COMMUNITY_UNSET)
296 			ribreq.large_community = res->large_community;
297 		/* XXX extended communities missing? */
298 		ribreq.neighbor = neighbor;
299 		ribreq.aid = res->aid;
300 		ribreq.flags = res->flags;
301 		show_mrt.arg = &ribreq;
302 		if (!(res->flags & F_CTL_DETAIL))
303 			show_rib_summary_head();
304 		mrt_parse(res->mrtfd, &show_mrt, 1);
305 		exit(0);
306 	case SHOW_RIB_MEM:
307 		imsg_compose(ibuf, IMSG_CTL_SHOW_RIB_MEM, 0, 0, -1, NULL, 0);
308 		break;
309 	case RELOAD:
310 		imsg_compose(ibuf, IMSG_CTL_RELOAD, 0, 0, -1, NULL, 0);
311 		printf("reload request sent.\n");
312 		break;
313 	case FIB:
314 		errx(1, "action==FIB");
315 		break;
316 	case FIB_COUPLE:
317 		imsg_compose(ibuf, IMSG_CTL_FIB_COUPLE, res->rtableid, 0, -1,
318 		    NULL, 0);
319 		printf("couple request sent.\n");
320 		done = 1;
321 		break;
322 	case FIB_DECOUPLE:
323 		imsg_compose(ibuf, IMSG_CTL_FIB_DECOUPLE, res->rtableid, 0, -1,
324 		    NULL, 0);
325 		printf("decouple request sent.\n");
326 		done = 1;
327 		break;
328 	case NEIGHBOR:
329 		errx(1, "action==NEIGHBOR");
330 		break;
331 	case NEIGHBOR_UP:
332 		imsg_compose(ibuf, IMSG_CTL_NEIGHBOR_UP, 0, 0, -1,
333 		    &neighbor, sizeof(neighbor));
334 		break;
335 	case NEIGHBOR_DOWN:
336 		imsg_compose(ibuf, IMSG_CTL_NEIGHBOR_DOWN, 0, 0, -1,
337 		    &neighbor, sizeof(neighbor));
338 		break;
339 	case NEIGHBOR_CLEAR:
340 		imsg_compose(ibuf, IMSG_CTL_NEIGHBOR_CLEAR, 0, 0, -1,
341 		    &neighbor, sizeof(neighbor));
342 		break;
343 	case NEIGHBOR_RREFRESH:
344 		imsg_compose(ibuf, IMSG_CTL_NEIGHBOR_RREFRESH, 0, 0, -1,
345 		    &neighbor, sizeof(neighbor));
346 		break;
347 	case NEIGHBOR_DESTROY:
348 		imsg_compose(ibuf, IMSG_CTL_NEIGHBOR_DESTROY, 0, 0, -1,
349 		    &neighbor, sizeof(neighbor));
350 		break;
351 	case NETWORK_BULK_ADD:
352 	case NETWORK_BULK_REMOVE:
353 		network_bulk(res);
354 		printf("requests sent.\n");
355 		done = 1;
356 		break;
357 	case NETWORK_ADD:
358 	case NETWORK_REMOVE:
359 		bzero(&net, sizeof(net));
360 		net.prefix = res->addr;
361 		net.prefixlen = res->prefixlen;
362 		/* attribute sets are not supported */
363 		if (res->action == NETWORK_ADD) {
364 			imsg_compose(ibuf, IMSG_NETWORK_ADD, 0, 0, -1,
365 			    &net, sizeof(net));
366 			send_filterset(ibuf, &res->set);
367 			imsg_compose(ibuf, IMSG_NETWORK_DONE, 0, 0, -1,
368 			    NULL, 0);
369 		} else
370 			imsg_compose(ibuf, IMSG_NETWORK_REMOVE, 0, 0, -1,
371 			    &net, sizeof(net));
372 		printf("request sent.\n");
373 		done = 1;
374 		break;
375 	case NETWORK_FLUSH:
376 		imsg_compose(ibuf, IMSG_NETWORK_FLUSH, 0, 0, -1, NULL, 0);
377 		printf("request sent.\n");
378 		done = 1;
379 		break;
380 	case NETWORK_SHOW:
381 		bzero(&ribreq, sizeof(ribreq));
382 		ribreq.aid = res->aid;
383 		strlcpy(ribreq.rib, res->rib, sizeof(ribreq.rib));
384 		imsg_compose(ibuf, IMSG_CTL_SHOW_NETWORK, 0, 0, -1,
385 		    &ribreq, sizeof(ribreq));
386 		show_network_head();
387 		break;
388 	case NETWORK_MRT:
389 		bzero(&ribreq, sizeof(ribreq));
390 		if (res->as.type != AS_NONE)
391 			ribreq.as = res->as;
392 		if (res->addr.aid) {
393 			ribreq.prefix = res->addr;
394 			ribreq.prefixlen = res->prefixlen;
395 		}
396 		if (res->community.as != COMMUNITY_UNSET &&
397 		    res->community.type != COMMUNITY_UNSET)
398 			ribreq.community = res->community;
399 		if (res->large_community.as != COMMUNITY_UNSET &&
400 		    res->large_community.ld1 != COMMUNITY_UNSET &&
401 		    res->large_community.ld2 != COMMUNITY_UNSET)
402 			ribreq.large_community = res->large_community;
403 		/* XXX ext communities missing? */
404 		ribreq.neighbor = neighbor;
405 		ribreq.aid = res->aid;
406 		ribreq.flags = res->flags;
407 		net_mrt.arg = &ribreq;
408 		mrt_parse(res->mrtfd, &net_mrt, 1);
409 		done = 1;
410 		break;
411 	case LOG_VERBOSE:
412 		verbose = 1;
413 		/* FALLTHROUGH */
414 	case LOG_BRIEF:
415 		imsg_compose(ibuf, IMSG_CTL_LOG_VERBOSE, 0, 0, -1,
416 		    &verbose, sizeof(verbose));
417 		printf("logging request sent.\n");
418 		done = 1;
419 		break;
420 	}
421 
422 	while (ibuf->w.queued)
423 		if (msgbuf_write(&ibuf->w) <= 0 && errno != EAGAIN)
424 			err(1, "write error");
425 
426 	while (!done) {
427 		if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN)
428 			err(1, "imsg_read error");
429 		if (n == 0)
430 			errx(1, "pipe closed");
431 
432 		while (!done) {
433 			if ((n = imsg_get(ibuf, &imsg)) == -1)
434 				err(1, "imsg_get error");
435 			if (n == 0)
436 				break;
437 
438 			if (imsg.hdr.type == IMSG_CTL_RESULT) {
439 				done = show_result(&imsg);
440 				imsg_free(&imsg);
441 				continue;
442 			}
443 
444 			switch (res->action) {
445 			case SHOW:
446 			case SHOW_SUMMARY:
447 				done = show_summary_msg(&imsg, nodescr);
448 				break;
449 			case SHOW_SUMMARY_TERSE:
450 				done = show_summary_terse_msg(&imsg, nodescr);
451 				break;
452 			case SHOW_FIB:
453 			case SHOW_FIB_TABLES:
454 			case NETWORK_SHOW:
455 				done = show_fib_msg(&imsg);
456 				break;
457 			case SHOW_NEXTHOP:
458 				done = show_nexthop_msg(&imsg);
459 				break;
460 			case SHOW_INTERFACE:
461 				done = show_interface_msg(&imsg);
462 				break;
463 			case SHOW_NEIGHBOR:
464 				done = show_neighbor_msg(&imsg, NV_DEFAULT);
465 				break;
466 			case SHOW_NEIGHBOR_TIMERS:
467 				done = show_neighbor_msg(&imsg, NV_TIMERS);
468 				break;
469 			case SHOW_NEIGHBOR_TERSE:
470 				done = show_neighbor_terse(&imsg);
471 				break;
472 			case SHOW_RIB:
473 				if (res->flags & F_CTL_DETAIL)
474 					done = show_rib_detail_msg(&imsg,
475 					    nodescr);
476 				else
477 					done = show_rib_summary_msg(&imsg);
478 				break;
479 			case SHOW_RIB_MEM:
480 				done = show_rib_memory_msg(&imsg);
481 				break;
482 			case NEIGHBOR:
483 			case NEIGHBOR_UP:
484 			case NEIGHBOR_DOWN:
485 			case NEIGHBOR_CLEAR:
486 			case NEIGHBOR_RREFRESH:
487 			case NEIGHBOR_DESTROY:
488 			case NONE:
489 			case RELOAD:
490 			case FIB:
491 			case FIB_COUPLE:
492 			case FIB_DECOUPLE:
493 			case NETWORK_ADD:
494 			case NETWORK_REMOVE:
495 			case NETWORK_FLUSH:
496 			case NETWORK_BULK_ADD:
497 			case NETWORK_BULK_REMOVE:
498 			case IRRFILTER:
499 			case LOG_VERBOSE:
500 			case LOG_BRIEF:
501 			case SHOW_MRT:
502 			case NETWORK_MRT:
503 				break;
504 			}
505 			imsg_free(&imsg);
506 		}
507 	}
508 	close(fd);
509 	free(ibuf);
510 
511 	exit(0);
512 }
513 
514 char *
515 fmt_peer(const char *descr, const struct bgpd_addr *remote_addr,
516     int masklen, int nodescr)
517 {
518 	const char	*ip;
519 	char		*p;
520 
521 	if (descr[0] && !nodescr) {
522 		if ((p = strdup(descr)) == NULL)
523 			err(1, NULL);
524 		return (p);
525 	}
526 
527 	ip = log_addr(remote_addr);
528 	if (masklen != -1 && ((remote_addr->aid == AID_INET && masklen != 32) ||
529 	    (remote_addr->aid == AID_INET6 && masklen != 128))) {
530 		if (asprintf(&p, "%s/%u", ip, masklen) == -1)
531 			err(1, NULL);
532 	} else {
533 		if ((p = strdup(ip)) == NULL)
534 			err(1, NULL);
535 	}
536 
537 	return (p);
538 }
539 
540 void
541 show_summary_head(void)
542 {
543 	printf("%-20s %8s %10s %10s %5s %-8s %s\n", "Neighbor", "AS",
544 	    "MsgRcvd", "MsgSent", "OutQ", "Up/Down", "State/PrfRcvd");
545 }
546 
547 int
548 show_summary_msg(struct imsg *imsg, int nodescr)
549 {
550 	struct peer		*p;
551 	char			*s;
552 	const char		*a;
553 	size_t			alen;
554 
555 	switch (imsg->hdr.type) {
556 	case IMSG_CTL_SHOW_NEIGHBOR:
557 		p = imsg->data;
558 		s = fmt_peer(p->conf.descr, &p->conf.remote_addr,
559 		    p->conf.remote_masklen, nodescr);
560 
561 		a = log_as(p->conf.remote_as);
562 		alen = strlen(a);
563 		/* max displayed lenght of the peers name is 28 */
564 		if (alen < 28) {
565 			if (strlen(s) > 28 - alen)
566 				s[28 - alen] = 0;
567 		} else
568 			alen = 0;
569 
570 		printf("%-*s %s %10llu %10llu %5u %-8s ",
571 		    (28 - (int)alen), s, a,
572 		    p->stats.msg_rcvd_open + p->stats.msg_rcvd_notification +
573 		    p->stats.msg_rcvd_update + p->stats.msg_rcvd_keepalive +
574 		    p->stats.msg_rcvd_rrefresh,
575 		    p->stats.msg_sent_open + p->stats.msg_sent_notification +
576 		    p->stats.msg_sent_update + p->stats.msg_sent_keepalive +
577 		    p->stats.msg_sent_rrefresh,
578 		    p->wbuf.queued,
579 		    fmt_timeframe(p->stats.last_updown));
580 		if (p->state == STATE_ESTABLISHED) {
581 			printf("%6u", p->stats.prefix_cnt);
582 			if (p->conf.max_prefix != 0)
583 				printf("/%u", p->conf.max_prefix);
584 		} else if (p->conf.template)
585 			printf("Template");
586 		else
587 			printf("%s", statenames[p->state]);
588 		printf("\n");
589 		free(s);
590 		break;
591 	case IMSG_CTL_END:
592 		return (1);
593 	default:
594 		break;
595 	}
596 
597 	return (0);
598 }
599 
600 int
601 show_summary_terse_msg(struct imsg *imsg, int nodescr)
602 {
603 	struct peer		*p;
604 	char			*s;
605 
606 	switch (imsg->hdr.type) {
607 	case IMSG_CTL_SHOW_NEIGHBOR:
608 		p = imsg->data;
609 		s = fmt_peer(p->conf.descr, &p->conf.remote_addr,
610 		    p->conf.remote_masklen, nodescr);
611 		printf("%s %s %s\n", s, log_as(p->conf.remote_as),
612 		    p->conf.template ? "Template" : statenames[p->state]);
613 		free(s);
614 		break;
615 	case IMSG_CTL_END:
616 		return (1);
617 	default:
618 		break;
619 	}
620 
621 	return (0);
622 }
623 
624 int
625 show_neighbor_terse(struct imsg *imsg)
626 {
627 	struct peer		*p;
628 
629 	switch (imsg->hdr.type) {
630 	case IMSG_CTL_SHOW_NEIGHBOR:
631 		p = imsg->data;
632 		printf("%llu %llu %llu %llu %llu %llu %llu "
633 		    "%llu %llu %llu %u %u %llu %llu %llu %llu\n",
634 		    p->stats.msg_sent_open, p->stats.msg_rcvd_open,
635 		    p->stats.msg_sent_notification,
636 		    p->stats.msg_rcvd_notification,
637 		    p->stats.msg_sent_update, p->stats.msg_rcvd_update,
638 		    p->stats.msg_sent_keepalive, p->stats.msg_rcvd_keepalive,
639 		    p->stats.msg_sent_rrefresh, p->stats.msg_rcvd_rrefresh,
640 		    p->stats.prefix_cnt, p->conf.max_prefix,
641 		    p->stats.prefix_sent_update, p->stats.prefix_rcvd_update,
642 		    p->stats.prefix_sent_withdraw,
643 		    p->stats.prefix_rcvd_withdraw);
644 		break;
645 	case IMSG_CTL_END:
646 		return (1);
647 	default:
648 		break;
649 	}
650 
651 	return (0);
652 }
653 
654 const char *
655 print_auth_method(enum auth_method method)
656 {
657 	switch (method) {
658 	case AUTH_MD5SIG:
659 		return ", using md5sig";
660 	case AUTH_IPSEC_MANUAL_ESP:
661 		return ", using ipsec manual esp";
662 	case AUTH_IPSEC_MANUAL_AH:
663 		return ", using ipsec manual ah";
664 	case AUTH_IPSEC_IKE_ESP:
665 		return ", using ipsec ike esp";
666 	case AUTH_IPSEC_IKE_AH:
667 		return ", using ipsec ike ah";
668 	case AUTH_NONE:	/* FALLTHROUGH */
669 	default:
670 		return "";
671 	}
672 }
673 
674 int
675 show_neighbor_msg(struct imsg *imsg, enum neighbor_views nv)
676 {
677 	struct peer		*p;
678 	struct ctl_timer	*t;
679 	struct in_addr		 ina;
680 	char			 buf[NI_MAXHOST], pbuf[NI_MAXSERV], *s;
681 	int			 hascapamp = 0;
682 	u_int8_t		 i;
683 
684 	switch (imsg->hdr.type) {
685 	case IMSG_CTL_SHOW_NEIGHBOR:
686 		p = imsg->data;
687 		if ((p->conf.remote_addr.aid == AID_INET &&
688 		    p->conf.remote_masklen != 32) ||
689 		    (p->conf.remote_addr.aid == AID_INET6 &&
690 		    p->conf.remote_masklen != 128)) {
691 			if (asprintf(&s, "%s/%u",
692 			    log_addr(&p->conf.remote_addr),
693 			    p->conf.remote_masklen) == -1)
694 				err(1, NULL);
695 		} else
696 			if ((s = strdup(log_addr(&p->conf.remote_addr))) ==
697 			    NULL)
698 				err(1, "strdup");
699 
700 		ina.s_addr = p->remote_bgpid;
701 		printf("BGP neighbor is %s, ", s);
702 		free(s);
703 		if (p->conf.remote_as == 0 && p->conf.template)
704 			printf("remote AS: accept any");
705 		else
706 			printf("remote AS %s", log_as(p->conf.remote_as));
707 		if (p->conf.template)
708 			printf(", Template");
709 		if (p->template)
710 			printf(", Cloned");
711 		if (p->conf.passive)
712 			printf(", Passive");
713 		if (p->conf.ebgp && p->conf.distance > 1)
714 			printf(", Multihop (%u)", (int)p->conf.distance);
715 		printf("\n");
716 		if (p->conf.descr[0])
717 			printf(" Description: %s\n", p->conf.descr);
718 		if (p->conf.max_prefix) {
719 			printf(" Max-prefix: %u", p->conf.max_prefix);
720 			if (p->conf.max_prefix_restart)
721 				printf(" (restart %u)",
722 				    p->conf.max_prefix_restart);
723 			printf("\n");
724 		}
725 		printf("  BGP version 4, remote router-id %s",
726 		    inet_ntoa(ina));
727 		printf("%s\n", print_auth_method(p->auth.method));
728 		printf("  BGP state = %s", statenames[p->state]);
729 		if (p->conf.down) {
730 			printf(", marked down");
731 			if (*(p->conf.shutcomm)) {
732 				printf(" with shutdown reason \"%s\"",
733 				    log_shutcomm(p->conf.shutcomm));
734 			}
735 		}
736 		if (p->stats.last_updown != 0)
737 			printf(", %s for %s",
738 			    p->state == STATE_ESTABLISHED ? "up" : "down",
739 			    fmt_timeframe(p->stats.last_updown));
740 		printf("\n");
741 		printf("  Last read %s, holdtime %us, keepalive interval %us\n",
742 		    fmt_timeframe(p->stats.last_read),
743 		    p->holdtime, p->holdtime/3);
744 		for (i = 0; i < AID_MAX; i++)
745 			if (p->capa.peer.mp[i])
746 				hascapamp = 1;
747 		if (hascapamp || p->capa.peer.refresh ||
748 		    p->capa.peer.grestart.restart || p->capa.peer.as4byte) {
749 			printf("  Neighbor capabilities:\n");
750 			if (hascapamp) {
751 				printf("    Multiprotocol extensions: ");
752 				print_neighbor_capa_mp(p);
753 				printf("\n");
754 			}
755 			if (p->capa.peer.refresh)
756 				printf("    Route Refresh\n");
757 			if (p->capa.peer.grestart.restart) {
758 				printf("    Graceful Restart");
759 				print_neighbor_capa_restart(p);
760 				printf("\n");
761 			}
762 			if (p->capa.peer.as4byte)
763 				printf("    4-byte AS numbers\n");
764 		}
765 		printf("\n");
766 		if (nv == NV_TIMERS)
767 			break;
768 		print_neighbor_msgstats(p);
769 		printf("\n");
770 		if (*(p->stats.last_shutcomm)) {
771 			printf("  Last received shutdown reason: \"%s\"\n",
772 			    log_shutcomm(p->stats.last_shutcomm));
773 		}
774 		if (p->state == STATE_IDLE) {
775 			static const char	*errstr;
776 
777 			errstr = get_errstr(p->stats.last_sent_errcode,
778 			    p->stats.last_sent_suberr);
779 			if (errstr)
780 				printf("  Last error: %s\n\n", errstr);
781 		} else {
782 			if (getnameinfo((struct sockaddr *)&p->sa_local,
783 			    (socklen_t)p->sa_local.ss_len,
784 			    buf, sizeof(buf), pbuf, sizeof(pbuf),
785 			    NI_NUMERICHOST | NI_NUMERICSERV)) {
786 				strlcpy(buf, "(unknown)", sizeof(buf));
787 				strlcpy(pbuf, "", sizeof(pbuf));
788 			}
789 			printf("  Local host:  %20s, Local port:  %5s\n", buf,
790 			    pbuf);
791 
792 			if (getnameinfo((struct sockaddr *)&p->sa_remote,
793 			    (socklen_t)p->sa_remote.ss_len,
794 			    buf, sizeof(buf), pbuf, sizeof(pbuf),
795 			    NI_NUMERICHOST | NI_NUMERICSERV)) {
796 				strlcpy(buf, "(unknown)", sizeof(buf));
797 				strlcpy(pbuf, "", sizeof(pbuf));
798 			}
799 			printf("  Remote host: %20s, Remote port: %5s\n", buf,
800 			    pbuf);
801 			printf("\n");
802 		}
803 		break;
804 	case IMSG_CTL_SHOW_TIMER:
805 		t = imsg->data;
806 		if (t->type > 0 && t->type < Timer_Max)
807 			print_timer(timernames[t->type], t->val);
808 		break;
809 	case IMSG_CTL_END:
810 		return (1);
811 		break;
812 	default:
813 		break;
814 	}
815 
816 	return (0);
817 }
818 
819 void
820 print_neighbor_capa_mp(struct peer *p)
821 {
822 	int		comma;
823 	u_int8_t	i;
824 
825 	for (i = 0, comma = 0; i < AID_MAX; i++)
826 		if (p->capa.peer.mp[i]) {
827 			printf("%s%s", comma ? ", " : "", aid2str(i));
828 			comma = 1;
829 		}
830 }
831 
832 void
833 print_neighbor_capa_restart(struct peer *p)
834 {
835 	int		comma;
836 	u_int8_t	i;
837 
838 	if (p->capa.peer.grestart.timeout)
839 		printf(": Timeout: %d, ", p->capa.peer.grestart.timeout);
840 	for (i = 0, comma = 0; i < AID_MAX; i++)
841 		if (p->capa.peer.grestart.flags[i] & CAPA_GR_PRESENT) {
842 			if (!comma &&
843 			    p->capa.peer.grestart.flags[i] & CAPA_GR_RESTART)
844 				printf("restarted, ");
845 			if (comma)
846 				printf(", ");
847 			printf("%s", aid2str(i));
848 			if (p->capa.peer.grestart.flags[i] & CAPA_GR_FORWARD)
849 				printf(" (preserved)");
850 			comma = 1;
851 		}
852 }
853 
854 void
855 print_neighbor_msgstats(struct peer *p)
856 {
857 	printf("  Message statistics:\n");
858 	printf("  %-15s %-10s %-10s\n", "", "Sent", "Received");
859 	printf("  %-15s %10llu %10llu\n", "Opens",
860 	    p->stats.msg_sent_open, p->stats.msg_rcvd_open);
861 	printf("  %-15s %10llu %10llu\n", "Notifications",
862 	    p->stats.msg_sent_notification, p->stats.msg_rcvd_notification);
863 	printf("  %-15s %10llu %10llu\n", "Updates",
864 	    p->stats.msg_sent_update, p->stats.msg_rcvd_update);
865 	printf("  %-15s %10llu %10llu\n", "Keepalives",
866 	    p->stats.msg_sent_keepalive, p->stats.msg_rcvd_keepalive);
867 	printf("  %-15s %10llu %10llu\n", "Route Refresh",
868 	    p->stats.msg_sent_rrefresh, p->stats.msg_rcvd_rrefresh);
869 	printf("  %-15s %10llu %10llu\n\n", "Total",
870 	    p->stats.msg_sent_open + p->stats.msg_sent_notification +
871 	    p->stats.msg_sent_update + p->stats.msg_sent_keepalive +
872 	    p->stats.msg_sent_rrefresh,
873 	    p->stats.msg_rcvd_open + p->stats.msg_rcvd_notification +
874 	    p->stats.msg_rcvd_update + p->stats.msg_rcvd_keepalive +
875 	    p->stats.msg_rcvd_rrefresh);
876 	printf("  Update statistics:\n");
877 	printf("  %-15s %-10s %-10s\n", "", "Sent", "Received");
878 	printf("  %-15s %10llu %10llu\n", "Updates",
879 	    p->stats.prefix_sent_update, p->stats.prefix_rcvd_update);
880 	printf("  %-15s %10llu %10llu\n", "Withdraws",
881 	    p->stats.prefix_sent_withdraw, p->stats.prefix_rcvd_withdraw);
882 	printf("  %-15s %10llu %10llu\n", "End-of-Rib",
883 	    p->stats.prefix_sent_eor, p->stats.prefix_rcvd_eor);
884 }
885 
886 void
887 print_timer(const char *name, time_t d)
888 {
889 	printf("  %-20s ", name);
890 
891 	if (d <= 0)
892 		printf("%-20s\n", "due");
893 	else
894 		printf("due in %-13s\n", fmt_timeframe_core(d));
895 }
896 
897 #define TF_BUFS	8
898 #define TF_LEN	9
899 
900 static char *
901 fmt_timeframe(time_t t)
902 {
903 	if (t == 0)
904 		return ("Never");
905 	else
906 		return (fmt_timeframe_core(time(NULL) - t));
907 }
908 
909 static char *
910 fmt_timeframe_core(time_t t)
911 {
912 	char		*buf;
913 	static char	 tfbuf[TF_BUFS][TF_LEN];	/* ring buffer */
914 	static int	 idx = 0;
915 	unsigned int	 sec, min, hrs, day;
916 	unsigned long long	week;
917 
918 	buf = tfbuf[idx++];
919 	if (idx == TF_BUFS)
920 		idx = 0;
921 
922 	week = t;
923 
924 	sec = week % 60;
925 	week /= 60;
926 	min = week % 60;
927 	week /= 60;
928 	hrs = week % 24;
929 	week /= 24;
930 	day = week % 7;
931 	week /= 7;
932 
933 	if (week > 0)
934 		snprintf(buf, TF_LEN, "%02lluw%01ud%02uh", week, day, hrs);
935 	else if (day > 0)
936 		snprintf(buf, TF_LEN, "%01ud%02uh%02um", day, hrs, min);
937 	else
938 		snprintf(buf, TF_LEN, "%02u:%02u:%02u", hrs, min, sec);
939 
940 	return (buf);
941 }
942 
943 void
944 show_fib_head(void)
945 {
946 	printf("flags: "
947 	    "* = valid, B = BGP, C = Connected, S = Static, D = Dynamic\n");
948 	printf("       "
949 	    "N = BGP Nexthop reachable via this route R = redistributed\n");
950 	printf("       r = reject route, b = blackhole route\n\n");
951 	printf("flags prio destination          gateway\n");
952 }
953 
954 void
955 show_fib_tables_head(void)
956 {
957 	printf("%-5s %-20s %-8s\n", "Table", "Description", "State");
958 }
959 
960 void
961 show_network_head(void)
962 {
963 	printf("flags: S = Static\n");
964 	printf("flags destination\n");
965 }
966 
967 void
968 show_fib_flags(u_int16_t flags)
969 {
970 	if (flags & F_DOWN)
971 		printf(" ");
972 	else
973 		printf("*");
974 
975 	if (flags & F_BGPD_INSERTED)
976 		printf("B");
977 	else if (flags & F_CONNECTED)
978 		printf("C");
979 	else if (flags & F_STATIC)
980 		printf("S");
981 	else if (flags & F_DYNAMIC)
982 		printf("D");
983 	else
984 		printf(" ");
985 
986 	if (flags & F_NEXTHOP)
987 		printf("N");
988 	else
989 		printf(" ");
990 
991 	if (flags & F_REDISTRIBUTED)
992 		printf("R");
993 	else
994 		printf(" ");
995 
996 	if (flags & F_REJECT && flags & F_BLACKHOLE)
997 		printf("f");
998 	else if (flags & F_REJECT)
999 		printf("r");
1000 	else if (flags & F_BLACKHOLE)
1001 		printf("b");
1002 	else
1003 		printf(" ");
1004 
1005 	printf(" ");
1006 }
1007 
1008 int
1009 show_fib_msg(struct imsg *imsg)
1010 {
1011 	struct kroute_full	*kf;
1012 	struct ktable		*kt;
1013 	char			*p;
1014 
1015 	switch (imsg->hdr.type) {
1016 	case IMSG_CTL_KROUTE:
1017 	case IMSG_CTL_SHOW_NETWORK:
1018 		if (imsg->hdr.len < IMSG_HEADER_SIZE + sizeof(*kf))
1019 			errx(1, "wrong imsg len");
1020 		kf = imsg->data;
1021 
1022 		show_fib_flags(kf->flags);
1023 
1024 		if (asprintf(&p, "%s/%u", log_addr(&kf->prefix),
1025 		    kf->prefixlen) == -1)
1026 			err(1, NULL);
1027 		printf("%4i %-20s ", kf->priority, p);
1028 		free(p);
1029 
1030 		if (kf->flags & F_CONNECTED)
1031 			printf("link#%u", kf->ifindex);
1032 		else
1033 			printf("%s", log_addr(&kf->nexthop));
1034 		printf("\n");
1035 
1036 		break;
1037 	case IMSG_CTL_SHOW_FIB_TABLES:
1038 		if (imsg->hdr.len < IMSG_HEADER_SIZE + sizeof(*kt))
1039 			errx(1, "wrong imsg len");
1040 		kt = imsg->data;
1041 
1042 		printf("%5i %-20s %-8s%s\n", kt->rtableid, kt->descr,
1043 		    kt->fib_sync ? "coupled" : "decoupled",
1044 		    kt->fib_sync != kt->fib_conf ? "*" : "");
1045 
1046 		break;
1047 	case IMSG_CTL_END:
1048 		return (1);
1049 	default:
1050 		break;
1051 	}
1052 
1053 	return (0);
1054 }
1055 
1056 void
1057 show_nexthop_head(void)
1058 {
1059 	printf("Flags: * = nexthop valid\n");
1060 	printf("\n  %-15s %-19s%-4s %-15s %-20s\n", "Nexthop", "Route",
1061 	     "Prio", "Gateway", "Iface");
1062 }
1063 
1064 int
1065 show_nexthop_msg(struct imsg *imsg)
1066 {
1067 	struct ctl_show_nexthop	*p;
1068 	struct kroute		*k;
1069 	struct kroute6		*k6;
1070 	char			*s;
1071 
1072 	switch (imsg->hdr.type) {
1073 	case IMSG_CTL_SHOW_NEXTHOP:
1074 		p = imsg->data;
1075 		printf("%s %-15s ", p->valid ? "*" : " ", log_addr(&p->addr));
1076 		if (!p->krvalid) {
1077 			printf("\n");
1078 			return (0);
1079 		}
1080 		switch (p->addr.aid) {
1081 		case AID_INET:
1082 			k = &p->kr.kr4;
1083 			if (asprintf(&s, "%s/%u", inet_ntoa(k->prefix),
1084 			    k->prefixlen) == -1)
1085 				err(1, NULL);
1086 			printf("%-20s", s);
1087 			free(s);
1088 			printf("%3i %-15s ", k->priority,
1089 			    k->flags & F_CONNECTED ? "connected" :
1090 			    inet_ntoa(k->nexthop));
1091 			break;
1092 		case AID_INET6:
1093 			k6 = &p->kr.kr6;
1094 			if (asprintf(&s, "%s/%u", log_in6addr(&k6->prefix),
1095 			    k6->prefixlen) == -1)
1096 				err(1, NULL);
1097 			printf("%-20s", s);
1098 			free(s);
1099 			printf("%3i %-15s ", k6->priority,
1100 			    k6->flags & F_CONNECTED ? "connected" :
1101 			    log_in6addr(&k6->nexthop));
1102 			break;
1103 		default:
1104 			printf("unknown address family\n");
1105 			return (0);
1106 		}
1107 		if (p->kif.ifname[0]) {
1108 			char *s1;
1109 			if (p->kif.baudrate) {
1110 				if (asprintf(&s1, ", %s",
1111 				    get_baudrate(p->kif.baudrate,
1112 				    "bps")) == -1)
1113 					err(1, NULL);
1114 			} else if (asprintf(&s1, ", %s", get_linkstate(
1115 			    p->kif.if_type, p->kif.link_state)) == -1)
1116 					err(1, NULL);
1117 			if (asprintf(&s, "%s (%s%s)", p->kif.ifname,
1118 			    p->kif.flags & IFF_UP ? "UP" : "DOWN", s1) == -1)
1119 				err(1, NULL);
1120 			printf("%-15s", s);
1121 			free(s1);
1122 			free(s);
1123 		}
1124 		printf("\n");
1125 		break;
1126 	case IMSG_CTL_END:
1127 		return (1);
1128 		break;
1129 	default:
1130 		break;
1131 	}
1132 
1133 	return (0);
1134 }
1135 
1136 
1137 void
1138 show_interface_head(void)
1139 {
1140 	printf("%-15s%-15s%-15s%s\n", "Interface", "Nexthop state", "Flags",
1141 	    "Link state");
1142 }
1143 
1144 const struct if_status_description
1145 		if_status_descriptions[] = LINK_STATE_DESCRIPTIONS;
1146 const struct ifmedia_description
1147 		ifm_type_descriptions[] = IFM_TYPE_DESCRIPTIONS;
1148 
1149 uint64_t
1150 ift2ifm(uint8_t if_type)
1151 {
1152 	switch (if_type) {
1153 	case IFT_ETHER:
1154 		return (IFM_ETHER);
1155 	case IFT_FDDI:
1156 		return (IFM_FDDI);
1157 	case IFT_CARP:
1158 		return (IFM_CARP);
1159 	case IFT_IEEE80211:
1160 		return (IFM_IEEE80211);
1161 	default:
1162 		return (0);
1163 	}
1164 }
1165 
1166 const char *
1167 get_media_descr(uint64_t media_type)
1168 {
1169 	const struct ifmedia_description	*p;
1170 
1171 	for (p = ifm_type_descriptions; p->ifmt_string != NULL; p++)
1172 		if (media_type == p->ifmt_word)
1173 			return (p->ifmt_string);
1174 
1175 	return ("unknown media");
1176 }
1177 
1178 const char *
1179 get_linkstate(uint8_t if_type, int link_state)
1180 {
1181 	const struct if_status_description *p;
1182 	static char buf[8];
1183 
1184 	for (p = if_status_descriptions; p->ifs_string != NULL; p++) {
1185 		if (LINK_STATE_DESC_MATCH(p, if_type, link_state))
1186 			return (p->ifs_string);
1187 	}
1188 	snprintf(buf, sizeof(buf), "[#%d]", link_state);
1189 	return (buf);
1190 }
1191 
1192 const char *
1193 get_baudrate(u_int64_t baudrate, char *unit)
1194 {
1195 	static char bbuf[16];
1196 
1197 	if (baudrate > IF_Gbps(1))
1198 		snprintf(bbuf, sizeof(bbuf), "%llu G%s",
1199 		    baudrate / IF_Gbps(1), unit);
1200 	else if (baudrate > IF_Mbps(1))
1201 		snprintf(bbuf, sizeof(bbuf), "%llu M%s",
1202 		    baudrate / IF_Mbps(1), unit);
1203 	else if (baudrate > IF_Kbps(1))
1204 		snprintf(bbuf, sizeof(bbuf), "%llu K%s",
1205 		    baudrate / IF_Kbps(1), unit);
1206 	else
1207 		snprintf(bbuf, sizeof(bbuf), "%llu %s",
1208 		    baudrate, unit);
1209 
1210 	return (bbuf);
1211 }
1212 
1213 int
1214 show_interface_msg(struct imsg *imsg)
1215 {
1216 	struct kif	*k;
1217 	uint64_t	 ifms_type;
1218 
1219 	switch (imsg->hdr.type) {
1220 	case IMSG_CTL_SHOW_INTERFACE:
1221 		k = imsg->data;
1222 		printf("%-15s", k->ifname);
1223 		printf("%-15s", k->nh_reachable ? "ok" : "invalid");
1224 		printf("%-15s", k->flags & IFF_UP ? "UP" : "");
1225 
1226 		if ((ifms_type = ift2ifm(k->if_type)) != 0)
1227 			printf("%s, ", get_media_descr(ifms_type));
1228 
1229 		printf("%s", get_linkstate(k->if_type, k->link_state));
1230 
1231 		if (k->link_state != LINK_STATE_DOWN && k->baudrate > 0)
1232 			printf(", %s", get_baudrate(k->baudrate, "Bit/s"));
1233 		printf("\n");
1234 		break;
1235 	case IMSG_CTL_END:
1236 		return (1);
1237 		break;
1238 	default:
1239 		break;
1240 	}
1241 
1242 	return (0);
1243 }
1244 
1245 void
1246 show_rib_summary_head(void)
1247 {
1248 	printf("flags: * = Valid, > = Selected, I = via IBGP, A = Announced, "
1249 	    "S = Stale\n");
1250 	printf("origin: i = IGP, e = EGP, ? = Incomplete\n\n");
1251 	printf("%-5s %-20s %-15s  %5s %5s %s\n", "flags", "destination",
1252 	    "gateway", "lpref", "med", "aspath origin");
1253 }
1254 
1255 void
1256 print_prefix(struct bgpd_addr *prefix, u_int8_t prefixlen, u_int8_t flags)
1257 {
1258 	char			*p;
1259 
1260 	print_flags(flags, 1);
1261 	if (asprintf(&p, "%s/%u", log_addr(prefix), prefixlen) == -1)
1262 		err(1, NULL);
1263 	printf("%-20s", p);
1264 	free(p);
1265 }
1266 
1267 const char *
1268 print_origin(u_int8_t origin, int sum)
1269 {
1270 	switch (origin) {
1271 	case ORIGIN_IGP:
1272 		return (sum ? "i" : "IGP");
1273 	case ORIGIN_EGP:
1274 		return (sum ? "e" : "EGP");
1275 	case ORIGIN_INCOMPLETE:
1276 		return (sum ? "?" : "incomplete");
1277 	default:
1278 		return (sum ? "X" : "bad origin");
1279 	}
1280 }
1281 
1282 void
1283 print_flags(u_int8_t flags, int sum)
1284 {
1285 	char	 flagstr[5];
1286 	char	*p = flagstr;
1287 
1288 	if (sum) {
1289 		if (flags & F_PREF_ANNOUNCE)
1290 			*p++ = 'A';
1291 		if (flags & F_PREF_INTERNAL)
1292 			*p++ = 'I';
1293 		if (flags & F_PREF_STALE)
1294 			*p++ = 'S';
1295 		if (flags & F_PREF_ELIGIBLE)
1296 			*p++ = '*';
1297 		if (flags & F_PREF_ACTIVE)
1298 			*p++ = '>';
1299 		*p = '\0';
1300 		printf("%-5s ", flagstr);
1301 	} else {
1302 		if (flags & F_PREF_INTERNAL)
1303 			printf("internal");
1304 		else
1305 			printf("external");
1306 		if (flags & F_PREF_STALE)
1307 			printf(", stale");
1308 		if (flags & F_PREF_ELIGIBLE)
1309 			printf(", valid");
1310 		if (flags & F_PREF_ACTIVE)
1311 			printf(", best");
1312 		if (flags & F_PREF_ANNOUNCE)
1313 			printf(", announced");
1314 	}
1315 }
1316 
1317 int
1318 show_rib_summary_msg(struct imsg *imsg)
1319 {
1320 	struct ctl_show_rib	 rib;
1321 	u_char			*asdata;
1322 
1323 	switch (imsg->hdr.type) {
1324 	case IMSG_CTL_SHOW_RIB:
1325 		memcpy(&rib, imsg->data, sizeof(rib));
1326 		asdata = imsg->data;
1327 		asdata += sizeof(struct ctl_show_rib);
1328 		show_rib_brief(&rib, asdata);
1329 		break;
1330 	case IMSG_CTL_END:
1331 		return (1);
1332 	default:
1333 		break;
1334 	}
1335 
1336 	return (0);
1337 }
1338 
1339 int
1340 show_rib_detail_msg(struct imsg *imsg, int nodescr)
1341 {
1342 	struct ctl_show_rib	 rib;
1343 	u_char			*asdata;
1344 	u_int16_t		 ilen;
1345 
1346 	switch (imsg->hdr.type) {
1347 	case IMSG_CTL_SHOW_RIB:
1348 		memcpy(&rib, imsg->data, sizeof(rib));
1349 		asdata = imsg->data;
1350 		asdata += sizeof(struct ctl_show_rib);
1351 		show_rib_detail(&rib, asdata, nodescr);
1352 		break;
1353 	case IMSG_CTL_SHOW_RIB_ATTR:
1354 		ilen = imsg->hdr.len - IMSG_HEADER_SIZE;
1355 		if (ilen < 3)
1356 			errx(1, "bad IMSG_CTL_SHOW_RIB_ATTR received");
1357 		show_attr(imsg->data, ilen);
1358 		break;
1359 	case IMSG_CTL_END:
1360 		printf("\n");
1361 		return (1);
1362 	default:
1363 		break;
1364 	}
1365 
1366 	return (0);
1367 }
1368 
1369 void
1370 show_rib_brief(struct ctl_show_rib *r, u_char *asdata)
1371 {
1372 	char			*aspath;
1373 
1374 	print_prefix(&r->prefix, r->prefixlen, r->flags);
1375 	printf(" %-15s ", log_addr(&r->exit_nexthop));
1376 	printf(" %5u %5u ", r->local_pref, r->med);
1377 
1378 	if (aspath_asprint(&aspath, asdata, r->aspath_len) == -1)
1379 		err(1, NULL);
1380 	if (strlen(aspath) > 0)
1381 		printf("%s ", aspath);
1382 	free(aspath);
1383 
1384 	printf("%s\n", print_origin(r->origin, 1));
1385 }
1386 
1387 void
1388 show_rib_detail(struct ctl_show_rib *r, u_char *asdata, int nodescr)
1389 {
1390 	struct in_addr		 id;
1391 	char			*aspath, *s;
1392 	time_t			 now;
1393 
1394 	printf("\nBGP routing table entry for %s/%u\n",
1395 	    log_addr(&r->prefix), r->prefixlen);
1396 
1397 	if (aspath_asprint(&aspath, asdata, r->aspath_len) == -1)
1398 		err(1, NULL);
1399 	if (strlen(aspath) > 0)
1400 		printf("    %s\n", aspath);
1401 	free(aspath);
1402 
1403 	s = fmt_peer(r->descr, &r->remote_addr, -1, nodescr);
1404 	printf("    Nexthop %s ", log_addr(&r->exit_nexthop));
1405 	printf("(via %s) from %s (", log_addr(&r->true_nexthop), s);
1406 	free(s);
1407 	id.s_addr = htonl(r->remote_id);
1408 	printf("%s)\n", inet_ntoa(id));
1409 
1410 	printf("    Origin %s, metric %u, localpref %u, weight %u, ",
1411 	    print_origin(r->origin, 0), r->med, r->local_pref, r->weight);
1412 	print_flags(r->flags, 0);
1413 
1414 	now = time(NULL);
1415 	if (now > r->lastchange)
1416 		now -= r->lastchange;
1417 	else
1418 		now = 0;
1419 
1420 	printf("\n    Last update: %s ago\n", fmt_timeframe_core(now));
1421 }
1422 
1423 void
1424 show_attr(void *b, u_int16_t len)
1425 {
1426 	char		*data = b;
1427 	struct in_addr	 id;
1428 	u_int32_t	 as;
1429 	u_int16_t	 alen, ioff;
1430 	u_int8_t	 flags, type;
1431 	int		 i;
1432 
1433 	if (len < 3)
1434 		errx(1, "show_attr: too short bgp attr");
1435 
1436 	flags = data[0];
1437 	type = data[1];
1438 
1439 	/* get the attribute length */
1440 	if (flags & ATTR_EXTLEN) {
1441 		if (len < 4)
1442 			errx(1, "show_attr: too short bgp attr");
1443 		memcpy(&alen, data+2, sizeof(u_int16_t));
1444 		alen = ntohs(alen);
1445 		data += 4;
1446 		len -= 4;
1447 	} else {
1448 		alen = (u_char)data[2];
1449 		data += 3;
1450 		len -= 3;
1451 	}
1452 
1453 	/* bad imsg len how can that happen!? */
1454 	if (alen > len)
1455 		errx(1, "show_attr: bad length");
1456 
1457 	switch (type) {
1458 	case ATTR_COMMUNITIES:
1459 		printf("    Communities: ");
1460 		show_community(data, alen);
1461 		printf("\n");
1462 		break;
1463 	case ATTR_LARGE_COMMUNITIES:
1464 		printf("    Large Communities: ");
1465 		show_large_community(data, alen);
1466 		printf("\n");
1467 		break;
1468 	case ATTR_AGGREGATOR:
1469 		memcpy(&as, data, sizeof(as));
1470 		memcpy(&id, data + sizeof(as), sizeof(id));
1471 		printf("    Aggregator: %s [%s]\n",
1472 		    log_as(ntohl(as)), inet_ntoa(id));
1473 		break;
1474 	case ATTR_ORIGINATOR_ID:
1475 		memcpy(&id, data, sizeof(id));
1476 		printf("    Originator Id: %s\n", inet_ntoa(id));
1477 		break;
1478 	case ATTR_CLUSTER_LIST:
1479 		printf("    Cluster ID List:");
1480 		for (ioff = 0; ioff + sizeof(id) <= alen;
1481 		    ioff += sizeof(id)) {
1482 			memcpy(&id, data + ioff, sizeof(id));
1483 			printf(" %s", inet_ntoa(id));
1484 		}
1485 		printf("\n");
1486 		break;
1487 	case ATTR_EXT_COMMUNITIES:
1488 		printf("    Ext. communities: ");
1489 		show_ext_community(data, alen);
1490 		printf("\n");
1491 		break;
1492 	case ATTR_ATOMIC_AGGREGATE:
1493 		/* ignore */
1494 		break;
1495 	default:
1496 		/* ignore unknown attributes */
1497 		printf("    Unknown Attribute #%u", type);
1498 		if (flags) {
1499 			printf(" flags [");
1500 			if (flags & ATTR_OPTIONAL)
1501 				printf("O");
1502 			if (flags & ATTR_TRANSITIVE)
1503 				printf("T");
1504 			if (flags & ATTR_PARTIAL)
1505 				printf("P");
1506 			printf("]");
1507 		}
1508 		printf(" len %u", alen);
1509 		if (alen) {
1510 			printf(":");
1511 			for (i=0; i < alen; i++)
1512 				printf(" %02x", *(data+i) & 0xFF);
1513 		}
1514 		printf("\n");
1515 		break;
1516 	}
1517 }
1518 
1519 void
1520 show_community(u_char *data, u_int16_t len)
1521 {
1522 	u_int16_t	a, v;
1523 	u_int16_t	i;
1524 
1525 	if (len & 0x3)
1526 		return;
1527 
1528 	for (i = 0; i < len; i += 4) {
1529 		memcpy(&a, data + i, sizeof(a));
1530 		memcpy(&v, data + i + 2, sizeof(v));
1531 		a = ntohs(a);
1532 		v = ntohs(v);
1533 		if (a == COMMUNITY_WELLKNOWN)
1534 			switch (v) {
1535 			case COMMUNITY_GRACEFUL_SHUTDOWN:
1536 				printf("GRACEFUL_SHUTDOWN");
1537 				break;
1538 			case COMMUNITY_NO_EXPORT:
1539 				printf("NO_EXPORT");
1540 				break;
1541 			case COMMUNITY_NO_ADVERTISE:
1542 				printf("NO_ADVERTISE");
1543 				break;
1544 			case COMMUNITY_NO_EXPSUBCONFED:
1545 				printf("NO_EXPORT_SUBCONFED");
1546 				break;
1547 			case COMMUNITY_NO_PEER:
1548 				printf("NO_PEER");
1549 				break;
1550 			case COMMUNITY_BLACKHOLE:
1551 				printf("BLACKHOLE");
1552 				break;
1553 			default:
1554 				printf("%hu:%hu", a, v);
1555 				break;
1556 			}
1557 		else
1558 			printf("%hu:%hu", a, v);
1559 
1560 		if (i + 4 < len)
1561 			printf(" ");
1562 	}
1563 }
1564 
1565 void
1566 show_large_community(u_char *data, u_int16_t len)
1567 {
1568 	u_int32_t	a, l1, l2;
1569 	u_int16_t	i;
1570 
1571 	if (len % 12)
1572 		return;
1573 
1574 	for (i = 0; i < len; i += 12) {
1575 		memcpy(&a, data + i, sizeof(a));
1576 		memcpy(&l1, data + i + 4, sizeof(l1));
1577 		memcpy(&l2, data + i + 8, sizeof(l2));
1578 		a = ntohl(a);
1579 		l1 = ntohl(l1);
1580 		l2 = ntohl(l2);
1581 		printf("%u:%u:%u", a, l1, l2);
1582 
1583 		if (i + 12 < len)
1584 			printf(" ");
1585 	}
1586 }
1587 
1588 void
1589 show_ext_community(u_char *data, u_int16_t len)
1590 {
1591 	u_int64_t	ext;
1592 	struct in_addr	ip;
1593 	u_int32_t	as4, u32;
1594 	u_int16_t	i, as2, u16;
1595 	u_int8_t	type, subtype;
1596 
1597 	if (len & 0x7)
1598 		return;
1599 
1600 	for (i = 0; i < len; i += 8) {
1601 		type = data[i];
1602 		subtype = data[i + 1];
1603 
1604 		printf("%s ", log_ext_subtype(type, subtype));
1605 
1606 		switch (type) {
1607 		case EXT_COMMUNITY_TRANS_TWO_AS:
1608 			memcpy(&as2, data + i + 2, sizeof(as2));
1609 			memcpy(&u32, data + i + 4, sizeof(u32));
1610 			printf("%s:%u", log_as(ntohs(as2)), ntohl(u32));
1611 			break;
1612 		case EXT_COMMUNITY_TRANS_IPV4:
1613 			memcpy(&ip, data + i + 2, sizeof(ip));
1614 			memcpy(&u16, data + i + 6, sizeof(u16));
1615 			printf("%s:%hu", inet_ntoa(ip), ntohs(u16));
1616 			break;
1617 		case EXT_COMMUNITY_TRANS_FOUR_AS:
1618 			memcpy(&as4, data + i + 2, sizeof(as4));
1619 			memcpy(&u16, data + i + 6, sizeof(u16));
1620 			printf("%s:%hu", log_as(ntohl(as4)), ntohs(u16));
1621 			break;
1622 		case EXT_COMMUNITY_TRANS_OPAQUE:
1623 		case EXT_COMMUNITY_TRANS_EVPN:
1624 			memcpy(&ext, data + i, sizeof(ext));
1625 			ext = betoh64(ext) & 0xffffffffffffLL;
1626 			printf("0x%llx", ext);
1627 			break;
1628 		case EXT_COMMUNITY_NON_TRANS_OPAQUE:
1629 			memcpy(&ext, data + i, sizeof(ext));
1630 			ext = betoh64(ext) & 0xffffffffffffLL;
1631 			switch (ext) {
1632 			case EXT_COMMUNITY_OVS_VALID:
1633 				printf("valid ");
1634 				break;
1635 			case EXT_COMMUNITY_OVS_NOTFOUND:
1636 				printf("not-found ");
1637 				break;
1638 			case EXT_COMMUNITY_OVS_INVALID:
1639 				printf("invalid ");
1640 				break;
1641 			default:
1642 				printf("0x%llx ", ext);
1643 				break;
1644 			}
1645 			break;
1646 		default:
1647 			memcpy(&ext, data + i, sizeof(ext));
1648 			printf("0x%llx", betoh64(ext));
1649 		}
1650 		if (i + 8 < len)
1651 			printf(", ");
1652 	}
1653 }
1654 
1655 char *
1656 fmt_mem(int64_t num)
1657 {
1658 	static char	buf[16];
1659 
1660 	if (fmt_scaled(num, buf) == -1)
1661 		snprintf(buf, sizeof(buf), "%lldB", (long long)num);
1662 
1663 	return (buf);
1664 }
1665 
1666 size_t  pt_sizes[AID_MAX] = AID_PTSIZE;
1667 
1668 int
1669 show_rib_memory_msg(struct imsg *imsg)
1670 {
1671 	struct rde_memstats	stats;
1672 	size_t			pts = 0;
1673 	int			i;
1674 
1675 	switch (imsg->hdr.type) {
1676 	case IMSG_CTL_SHOW_RIB_MEM:
1677 		memcpy(&stats, imsg->data, sizeof(stats));
1678 		printf("RDE memory statistics\n");
1679 		for (i = 0; i < AID_MAX; i++) {
1680 			if (stats.pt_cnt[i] == 0)
1681 				continue;
1682 			pts += stats.pt_cnt[i] * pt_sizes[i];
1683 			printf("%10lld %s network entries using %s of memory\n",
1684 			    (long long)stats.pt_cnt[i], aid_vals[i].name,
1685 			    fmt_mem(stats.pt_cnt[i] * pt_sizes[i]));
1686 		}
1687 		printf("%10lld rib entries using %s of memory\n",
1688 		    (long long)stats.rib_cnt, fmt_mem(stats.rib_cnt *
1689 		    sizeof(struct rib_entry)));
1690 		printf("%10lld prefix entries using %s of memory\n",
1691 		    (long long)stats.prefix_cnt, fmt_mem(stats.prefix_cnt *
1692 		    sizeof(struct prefix)));
1693 		printf("%10lld BGP path attribute entries using %s of memory\n",
1694 		    (long long)stats.path_cnt, fmt_mem(stats.path_cnt *
1695 		    sizeof(struct rde_aspath)));
1696 		printf("%10lld BGP AS-PATH attribute entries using "
1697 		    "%s of memory,\n\t   and holding %lld references\n",
1698 		    (long long)stats.aspath_cnt, fmt_mem(stats.aspath_size),
1699 		    (long long)stats.aspath_refs);
1700 		printf("%10lld BGP attributes entries using %s of memory\n",
1701 		    (long long)stats.attr_cnt, fmt_mem(stats.attr_cnt *
1702 		    sizeof(struct attr)));
1703 		printf("\t   and holding %lld references\n",
1704 		    (long long)stats.attr_refs);
1705 		printf("%10lld BGP attributes using %s of memory\n",
1706 		    (long long)stats.attr_dcnt, fmt_mem(stats.attr_data));
1707 		printf("RIB using %s of memory\n", fmt_mem(pts +
1708 		    stats.prefix_cnt * sizeof(struct prefix) +
1709 		    stats.rib_cnt * sizeof(struct rib_entry) +
1710 		    stats.path_cnt * sizeof(struct rde_aspath) +
1711 		    stats.aspath_size + stats.attr_cnt * sizeof(struct attr) +
1712 		    stats.attr_data));
1713 		break;
1714 	default:
1715 		break;
1716 	}
1717 
1718 	return (1);
1719 }
1720 
1721 void
1722 send_filterset(struct imsgbuf *i, struct filter_set_head *set)
1723 {
1724 	struct filter_set	*s;
1725 
1726 	while ((s = TAILQ_FIRST(set)) != NULL) {
1727 		imsg_compose(i, IMSG_FILTER_SET, 0, 0, -1, s,
1728 		    sizeof(struct filter_set));
1729 		TAILQ_REMOVE(set, s, entry);
1730 		free(s);
1731 	}
1732 }
1733 
1734 const char *
1735 get_errstr(u_int8_t errcode, u_int8_t subcode)
1736 {
1737 	static const char	*errstr = NULL;
1738 
1739 	if (errcode && errcode < sizeof(errnames)/sizeof(char *))
1740 		errstr = errnames[errcode];
1741 
1742 	switch (errcode) {
1743 	case ERR_HEADER:
1744 		if (subcode &&
1745 		    subcode < sizeof(suberr_header_names)/sizeof(char *))
1746 			errstr = suberr_header_names[subcode];
1747 		break;
1748 	case ERR_OPEN:
1749 		if (subcode &&
1750 		    subcode < sizeof(suberr_open_names)/sizeof(char *))
1751 			errstr = suberr_open_names[subcode];
1752 		break;
1753 	case ERR_UPDATE:
1754 		if (subcode &&
1755 		    subcode < sizeof(suberr_update_names)/sizeof(char *))
1756 			errstr = suberr_update_names[subcode];
1757 		break;
1758 	case ERR_HOLDTIMEREXPIRED:
1759 	case ERR_FSM:
1760 	case ERR_CEASE:
1761 		break;
1762 	default:
1763 		return ("unknown error code");
1764 	}
1765 
1766 	return (errstr);
1767 }
1768 
1769 int
1770 show_result(struct imsg *imsg)
1771 {
1772 	u_int	rescode;
1773 
1774 	if (imsg->hdr.len != IMSG_HEADER_SIZE + sizeof(rescode))
1775 		errx(1, "got IMSG_CTL_RESULT with wrong len");
1776 	memcpy(&rescode, imsg->data, sizeof(rescode));
1777 
1778 	if (rescode == 0)
1779 		printf("request processed\n");
1780 	else {
1781 		if (rescode >
1782 		    sizeof(ctl_res_strerror)/sizeof(ctl_res_strerror[0]))
1783 			printf("unknown result error code %u\n", rescode);
1784 		else
1785 			printf("%s\n", ctl_res_strerror[rescode]);
1786 	}
1787 
1788 	return (1);
1789 }
1790 
1791 void
1792 network_bulk(struct parse_result *res)
1793 {
1794 	struct network_config net;
1795 	struct filter_set *s = NULL;
1796 	struct bgpd_addr h;
1797 	char *b, *buf, *lbuf;
1798 	size_t slen;
1799 	u_int8_t len;
1800 	FILE *f;
1801 
1802 	if ((f = fdopen(STDIN_FILENO, "r")) != NULL) {
1803 		while ((buf = fgetln(f, &slen))) {
1804 			lbuf = NULL;
1805 			if (buf[slen - 1] == '\n')
1806 				buf[slen - 1] = '\0';
1807 			else {
1808 				if ((lbuf = malloc(slen + 1)) == NULL)
1809 					err(1, NULL);
1810 				memcpy(lbuf, buf, slen);
1811 				lbuf[slen] = '\0';
1812 				buf = lbuf;
1813 			}
1814 
1815 			while ((b = strsep(&buf, " \t")) != NULL) {
1816 				/* Don't process commented entries */
1817 				if (strchr(b, '#') != NULL)
1818 					break;
1819 				bzero(&net, sizeof(net));
1820 				parse_prefix(b, strlen(b), &h, &len);
1821 				net.prefix = h;
1822 				net.prefixlen = len;
1823 
1824 				if (res->action == NETWORK_BULK_ADD) {
1825 					imsg_compose(ibuf, IMSG_NETWORK_ADD,
1826 					    0, 0, -1, &net, sizeof(net));
1827 					TAILQ_FOREACH(s, &res->set, entry) {
1828 						imsg_compose(ibuf,
1829 						    IMSG_FILTER_SET,
1830 						    0, 0, -1, s, sizeof(*s));
1831 					}
1832 					imsg_compose(ibuf, IMSG_NETWORK_DONE,
1833 					    0, 0, -1, NULL, 0);
1834 				} else
1835 					imsg_compose(ibuf, IMSG_NETWORK_REMOVE,
1836 					     0, 0, -1, &net, sizeof(net));
1837 			}
1838 			free(lbuf);
1839 		}
1840 		fclose(f);
1841 	} else {
1842 		err(1, "Failed to open stdin\n");
1843 	}
1844 }
1845 
1846 void
1847 show_mrt_dump(struct mrt_rib *mr, struct mrt_peer *mp, void *arg)
1848 {
1849 	struct ctl_show_rib		 ctl;
1850 	struct ctl_show_rib_request	*req = arg;
1851 	struct mrt_rib_entry		*mre;
1852 	u_int16_t			 i, j;
1853 
1854 	for (i = 0; i < mr->nentries; i++) {
1855 		mre = &mr->entries[i];
1856 		bzero(&ctl, sizeof(ctl));
1857 		mrt_to_bgpd_addr(&mr->prefix, &ctl.prefix);
1858 		ctl.prefixlen = mr->prefixlen;
1859 		ctl.lastchange = mre->originated;
1860 		mrt_to_bgpd_addr(&mre->nexthop, &ctl.true_nexthop);
1861 		mrt_to_bgpd_addr(&mre->nexthop, &ctl.exit_nexthop);
1862 		ctl.origin = mre->origin;
1863 		ctl.local_pref = mre->local_pref;
1864 		ctl.med = mre->med;
1865 		/* weight is not part of the mrt dump so it can't be set */
1866 		ctl.aspath_len = mre->aspath_len;
1867 
1868 		if (mre->peer_idx < mp->npeers) {
1869 			mrt_to_bgpd_addr(&mp->peers[mre->peer_idx].addr,
1870 			    &ctl.remote_addr);
1871 			ctl.remote_id = mp->peers[mre->peer_idx].bgp_id;
1872 		}
1873 
1874 		/* filter by neighbor */
1875 		if (req->neighbor.addr.aid != AID_UNSPEC &&
1876 		    memcmp(&req->neighbor.addr, &ctl.remote_addr,
1877 		    sizeof(ctl.remote_addr)) != 0)
1878 			continue;
1879 		/* filter by AF */
1880 		if (req->aid && req->aid != ctl.prefix.aid)
1881 			return;
1882 		/* filter by prefix */
1883 		if (req->prefix.aid != AID_UNSPEC) {
1884 			if (!prefix_compare(&req->prefix, &ctl.prefix,
1885 			    req->prefixlen)) {
1886 				if (req->flags & F_LONGER) {
1887 					if (req->prefixlen > ctl.prefixlen)
1888 						return;
1889 				} else if (req->prefixlen != ctl.prefixlen)
1890 					return;
1891 			} else
1892 				return;
1893 		}
1894 		/* filter by AS */
1895 		if (req->as.type != AS_NONE &&
1896 		   !aspath_match(mre->aspath, mre->aspath_len,
1897 		   &req->as, req->as.as))
1898 			continue;
1899 
1900 		if (req->flags & F_CTL_DETAIL) {
1901 			show_rib_detail(&ctl, mre->aspath, 1);
1902 			for (j = 0; j < mre->nattrs; j++)
1903 				show_attr(mre->attrs[j].attr,
1904 					mre->attrs[j].attr_len);
1905 		} else
1906 			show_rib_brief(&ctl, mre->aspath);
1907 	}
1908 }
1909 
1910 void
1911 network_mrt_dump(struct mrt_rib *mr, struct mrt_peer *mp, void *arg)
1912 {
1913 	struct ctl_show_rib		 ctl;
1914 	struct network_config		 net;
1915 	struct ctl_show_rib_request	*req = arg;
1916 	struct mrt_rib_entry		*mre;
1917 	struct ibuf			*msg;
1918 	u_int16_t			 i, j;
1919 
1920 	for (i = 0; i < mr->nentries; i++) {
1921 		mre = &mr->entries[i];
1922 		bzero(&ctl, sizeof(ctl));
1923 		mrt_to_bgpd_addr(&mr->prefix, &ctl.prefix);
1924 		ctl.prefixlen = mr->prefixlen;
1925 		ctl.lastchange = mre->originated;
1926 		mrt_to_bgpd_addr(&mre->nexthop, &ctl.true_nexthop);
1927 		mrt_to_bgpd_addr(&mre->nexthop, &ctl.exit_nexthop);
1928 		ctl.origin = mre->origin;
1929 		ctl.local_pref = mre->local_pref;
1930 		ctl.med = mre->med;
1931 		ctl.aspath_len = mre->aspath_len;
1932 
1933 		if (mre->peer_idx < mp->npeers) {
1934 			mrt_to_bgpd_addr(&mp->peers[mre->peer_idx].addr,
1935 			    &ctl.remote_addr);
1936 			ctl.remote_id = mp->peers[mre->peer_idx].bgp_id;
1937 		}
1938 
1939 		/* filter by neighbor */
1940 		if (req->neighbor.addr.aid != AID_UNSPEC &&
1941 		    memcmp(&req->neighbor.addr, &ctl.remote_addr,
1942 		    sizeof(ctl.remote_addr)) != 0)
1943 			continue;
1944 		/* filter by AF */
1945 		if (req->aid && req->aid != ctl.prefix.aid)
1946 			return;
1947 		/* filter by prefix */
1948 		if (req->prefix.aid != AID_UNSPEC) {
1949 			if (!prefix_compare(&req->prefix, &ctl.prefix,
1950 			    req->prefixlen)) {
1951 				if (req->flags & F_LONGER) {
1952 					if (req->prefixlen > ctl.prefixlen)
1953 						return;
1954 				} else if (req->prefixlen != ctl.prefixlen)
1955 					return;
1956 			} else
1957 				return;
1958 		}
1959 		/* filter by AS */
1960 		if (req->as.type != AS_NONE &&
1961 		   !aspath_match(mre->aspath, mre->aspath_len,
1962 		   &req->as, req->as.as))
1963 			continue;
1964 
1965 		bzero(&net, sizeof(net));
1966 		net.prefix = ctl.prefix;
1967 		net.prefixlen = ctl.prefixlen;
1968 		net.type = NETWORK_MRTCLONE;
1969 		/* XXX rtableid */
1970 
1971 		imsg_compose(ibuf, IMSG_NETWORK_ADD, 0, 0, -1,
1972 		    &net, sizeof(net));
1973 		if ((msg = imsg_create(ibuf, IMSG_NETWORK_ASPATH,
1974 		    0, 0, sizeof(ctl) + mre->aspath_len)) == NULL)
1975 			errx(1, "imsg_create failure");
1976 		if (imsg_add(msg, &ctl, sizeof(ctl)) == -1 ||
1977 		    imsg_add(msg, mre->aspath, mre->aspath_len) == -1)
1978 			errx(1, "imsg_add failure");
1979 		imsg_close(ibuf, msg);
1980 		for (j = 0; j < mre->nattrs; j++)
1981 			imsg_compose(ibuf, IMSG_NETWORK_ATTR, 0, 0, -1,
1982 			    mre->attrs[j].attr, mre->attrs[j].attr_len);
1983 		imsg_compose(ibuf, IMSG_NETWORK_DONE, 0, 0, -1, NULL, 0);
1984 
1985 		while (ibuf->w.queued) {
1986 			if (msgbuf_write(&ibuf->w) <= 0 && errno != EAGAIN)
1987 				err(1, "write error");
1988 		}
1989 	}
1990 }
1991 
1992 void
1993 show_mrt_state(struct mrt_bgp_state *ms, void *arg)
1994 {
1995 	struct bgpd_addr src, dst;
1996 
1997 	mrt_to_bgpd_addr(&ms->src, &src);
1998 	mrt_to_bgpd_addr(&ms->dst, &dst);
1999 	printf("%s[%u] -> ", log_addr(&src), ms->src_as);
2000 	printf("%s[%u]: %s -> %s\n", log_addr(&dst), ms->dst_as,
2001 	    statenames[ms->old_state], statenames[ms->new_state]);
2002 }
2003 
2004 void
2005 show_mrt_msg(struct mrt_bgp_msg *mm, void *arg)
2006 {
2007 	struct bgpd_addr src, dst;
2008 
2009 	mrt_to_bgpd_addr(&mm->src, &src);
2010 	mrt_to_bgpd_addr(&mm->dst, &dst);
2011 	printf("%s[%u] -> ", log_addr(&src), mm->src_as);
2012 	printf("%s[%u]: size %u\n", log_addr(&dst), mm->dst_as, mm->msg_len);
2013 }
2014 
2015 void
2016 mrt_to_bgpd_addr(union mrt_addr *ma, struct bgpd_addr *ba)
2017 {
2018 	switch (ma->sa.sa_family) {
2019 	case AF_INET:
2020 	case AF_INET6:
2021 		sa2addr(&ma->sa, ba);
2022 		break;
2023 	case AF_VPNv4:
2024 		bzero(ba, sizeof(*ba));
2025 		ba->aid = AID_VPN_IPv4;
2026 		ba->vpn4.rd = ma->svpn4.sv_rd;
2027 		ba->vpn4.addr.s_addr = ma->svpn4.sv_addr.s_addr;
2028 		memcpy(ba->vpn4.labelstack, ma->svpn4.sv_label,
2029 		    sizeof(ba->vpn4.labelstack));
2030 		break;
2031 	}
2032 }
2033 
2034 const char *
2035 msg_type(u_int8_t type)
2036 {
2037 	if (type >= sizeof(msgtypenames)/sizeof(msgtypenames[0]))
2038 		return "BAD";
2039 	return (msgtypenames[type]);
2040 }
2041