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