xref: /openbsd-src/usr.sbin/bgpctl/bgpctl.c (revision 2b0358df1d88d06ef4139321dd05bd5e05d91eaf)
1 /*	$OpenBSD: bgpctl.c,v 1.138 2009/02/01 17:21:21 sobrado 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 
41 enum neighbor_views {
42 	NV_DEFAULT,
43 	NV_TIMERS
44 };
45 
46 int		 main(int, char *[]);
47 char		*fmt_peer(const char *, const struct bgpd_addr *, int, int);
48 void		 show_summary_head(void);
49 int		 show_summary_msg(struct imsg *, int);
50 int		 show_summary_terse_msg(struct imsg *, int);
51 int		 show_neighbor_terse(struct imsg *);
52 int		 show_neighbor_msg(struct imsg *, enum neighbor_views);
53 void		 print_neighbor_capa_mp_safi(u_int8_t);
54 void		 print_neighbor_msgstats(struct peer *);
55 void		 print_timer(const char *, time_t);
56 static char	*fmt_timeframe(time_t t);
57 static char	*fmt_timeframe_core(time_t t);
58 void		 show_fib_head(void);
59 void		 show_network_head(void);
60 void		 show_fib_flags(u_int16_t);
61 int		 show_fib_msg(struct imsg *);
62 void		 show_nexthop_head(void);
63 int		 show_nexthop_msg(struct imsg *);
64 void		 show_interface_head(void);
65 int		 ift2ifm(int);
66 const char *	 get_media_descr(int);
67 const char *	 get_linkstate(int, int);
68 void		 print_baudrate(u_int64_t);
69 int		 show_interface_msg(struct imsg *);
70 void		 show_rib_summary_head(void);
71 void		 print_prefix(struct bgpd_addr *, u_int8_t, u_int8_t);
72 const char *	 print_origin(u_int8_t, int);
73 void		 print_flags(u_int8_t, int);
74 int		 show_rib_summary_msg(struct imsg *);
75 int		 show_rib_detail_msg(struct imsg *, int);
76 void		 show_community(u_char *, u_int16_t);
77 const char	*get_ext_subtype(u_int8_t);
78 void		 show_ext_community(u_char *, u_int16_t);
79 char		*fmt_mem(int64_t);
80 int		 show_rib_memory_msg(struct imsg *);
81 void		 send_filterset(struct imsgbuf *, struct filter_set_head *);
82 static const char	*get_errstr(u_int8_t, u_int8_t);
83 int		 show_result(struct imsg *);
84 
85 struct imsgbuf	*ibuf;
86 
87 __dead void
88 usage(void)
89 {
90 	extern char	*__progname;
91 
92 	fprintf(stderr, "usage: %s [-n] [-s socket] command [argument ...]\n",
93 	    __progname);
94 	exit(1);
95 }
96 
97 int
98 main(int argc, char *argv[])
99 {
100 	struct sockaddr_un	 sun;
101 	int			 fd, n, done, ch, nodescr = 0;
102 	struct imsg		 imsg;
103 	struct network_config	 net;
104 	struct parse_result	*res;
105 	struct ctl_neighbor	 neighbor;
106 	struct ctl_show_rib_request	ribreq;
107 	char			*sockname;
108 	enum imsg_type		 type;
109 
110 	sockname = SOCKET_NAME;
111 	while ((ch = getopt(argc, argv, "ns:")) != -1) {
112 		switch (ch) {
113 		case 'n':
114 			if (++nodescr > 1)
115 				usage();
116 			break;
117 		case 's':
118 			sockname = optarg;
119 			break;
120 		default:
121 			usage();
122 			/* NOTREACHED */
123 		}
124 	}
125 	argc -= optind;
126 	argv += optind;
127 
128 	if ((res = parse(argc, argv)) == NULL)
129 		exit(1);
130 
131 	if (res->action == IRRFILTER)
132 		irr_main(res->as.as, res->flags, res->irr_outdir);
133 
134 	memcpy(&neighbor.addr, &res->peeraddr, sizeof(neighbor.addr));
135 	strlcpy(neighbor.descr, res->peerdesc, sizeof(neighbor.descr));
136 
137 	if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
138 		err(1, "control_init: socket");
139 
140 	bzero(&sun, sizeof(sun));
141 	sun.sun_family = AF_UNIX;
142 	if (strlcpy(sun.sun_path, sockname, sizeof(sun.sun_path)) >=
143 	    sizeof(sun.sun_path))
144 		errx(1, "socket name too long");
145 	if (connect(fd, (struct sockaddr *)&sun, sizeof(sun)) == -1)
146 		err(1, "connect: %s", sockname);
147 
148 	if ((ibuf = malloc(sizeof(struct imsgbuf))) == NULL)
149 		err(1, NULL);
150 	imsg_init(ibuf, fd);
151 	done = 0;
152 
153 	switch (res->action) {
154 	case NONE:
155 	case IRRFILTER:
156 		usage();
157 		/* not reached */
158 	case SHOW:
159 	case SHOW_SUMMARY:
160 		imsg_compose(ibuf, IMSG_CTL_SHOW_NEIGHBOR, 0, 0, -1, NULL, 0);
161 		show_summary_head();
162 		break;
163 	case SHOW_SUMMARY_TERSE:
164 		imsg_compose(ibuf, IMSG_CTL_SHOW_TERSE, 0, 0, -1, NULL, 0);
165 		break;
166 	case SHOW_FIB:
167 		if (!res->addr.af) {
168 			struct buf	*msg;
169 
170 			if ((msg = imsg_create(ibuf, IMSG_CTL_KROUTE, 0, 0,
171 			    sizeof(res->flags) + sizeof(res->af))) == NULL)
172 				errx(1, "imsg_create failure");
173 			if (imsg_add(msg, &res->flags, sizeof(res->flags)) ==
174 			    -1 ||
175 			    imsg_add(msg, &res->af, sizeof(res->af)) == -1)
176 				errx(1, "imsg_add failure");
177 			if (imsg_close(ibuf, msg) < 0)
178 				errx(1, "imsg_close error");
179 		} else
180 			imsg_compose(ibuf, IMSG_CTL_KROUTE_ADDR, 0, 0, -1,
181 			    &res->addr, sizeof(res->addr));
182 		show_fib_head();
183 		break;
184 	case SHOW_NEXTHOP:
185 		imsg_compose(ibuf, IMSG_CTL_SHOW_NEXTHOP, 0, 0, -1, NULL, 0);
186 		show_nexthop_head();
187 		break;
188 	case SHOW_INTERFACE:
189 		imsg_compose(ibuf, IMSG_CTL_SHOW_INTERFACE, 0, 0, -1, NULL, 0);
190 		show_interface_head();
191 		break;
192 	case SHOW_NEIGHBOR:
193 	case SHOW_NEIGHBOR_TIMERS:
194 	case SHOW_NEIGHBOR_TERSE:
195 		neighbor.show_timers = (res->action == SHOW_NEIGHBOR_TIMERS);
196 		if (res->peeraddr.af || res->peerdesc[0])
197 			imsg_compose(ibuf, IMSG_CTL_SHOW_NEIGHBOR, 0, 0, -1,
198 			    &neighbor, sizeof(neighbor));
199 		else
200 			imsg_compose(ibuf, IMSG_CTL_SHOW_NEIGHBOR, 0, 0, -1,
201 			    NULL, 0);
202 		break;
203 	case SHOW_RIB:
204 		bzero(&ribreq, sizeof(ribreq));
205 		type = IMSG_CTL_SHOW_RIB;
206 		if (res->as.type != AS_NONE) {
207 			memcpy(&ribreq.as, &res->as, sizeof(res->as));
208 			type = IMSG_CTL_SHOW_RIB_AS;
209 		}
210 		if (res->addr.af) {
211 			memcpy(&ribreq.prefix, &res->addr, sizeof(res->addr));
212 			ribreq.prefixlen = res->prefixlen;
213 			type = IMSG_CTL_SHOW_RIB_PREFIX;
214 		}
215 		if (res->community.as != COMMUNITY_UNSET &&
216 		    res->community.type != COMMUNITY_UNSET) {
217 			memcpy(&ribreq.community, &res->community,
218 			    sizeof(res->community));
219 			type = IMSG_CTL_SHOW_RIB_COMMUNITY;
220 		}
221 		memcpy(&ribreq.neighbor, &neighbor,
222 		    sizeof(ribreq.neighbor));
223 		ribreq.af = res->af;
224 		ribreq.flags = res->flags;
225 		imsg_compose(ibuf, type, 0, 0, -1, &ribreq, sizeof(ribreq));
226 		if (!(res->flags & F_CTL_DETAIL))
227 			show_rib_summary_head();
228 		break;
229 	case SHOW_RIB_MEM:
230 		imsg_compose(ibuf, IMSG_CTL_SHOW_RIB_MEM, 0, 0, -1, NULL, 0);
231 		break;
232 	case RELOAD:
233 		imsg_compose(ibuf, IMSG_CTL_RELOAD, 0, 0, -1, NULL, 0);
234 		printf("reload request sent.\n");
235 		break;
236 	case FIB:
237 		errx(1, "action==FIB");
238 		break;
239 	case FIB_COUPLE:
240 		imsg_compose(ibuf, IMSG_CTL_FIB_COUPLE, 0, 0, -1, NULL, 0);
241 		printf("couple request sent.\n");
242 		done = 1;
243 		break;
244 	case FIB_DECOUPLE:
245 		imsg_compose(ibuf, IMSG_CTL_FIB_DECOUPLE, 0, 0, -1, NULL, 0);
246 		printf("decouple request sent.\n");
247 		done = 1;
248 		break;
249 	case NEIGHBOR:
250 		errx(1, "action==NEIGHBOR");
251 		break;
252 	case NEIGHBOR_UP:
253 		imsg_compose(ibuf, IMSG_CTL_NEIGHBOR_UP, 0, 0, -1,
254 		    &neighbor, sizeof(neighbor));
255 		break;
256 	case NEIGHBOR_DOWN:
257 		imsg_compose(ibuf, IMSG_CTL_NEIGHBOR_DOWN, 0, 0, -1,
258 		    &neighbor, sizeof(neighbor));
259 		break;
260 	case NEIGHBOR_CLEAR:
261 		imsg_compose(ibuf, IMSG_CTL_NEIGHBOR_CLEAR, 0, 0, -1,
262 		    &neighbor, sizeof(neighbor));
263 		break;
264 	case NEIGHBOR_RREFRESH:
265 		imsg_compose(ibuf, IMSG_CTL_NEIGHBOR_RREFRESH, 0, 0, -1,
266 		    &neighbor, sizeof(neighbor));
267 		break;
268 	case NETWORK_ADD:
269 	case NETWORK_REMOVE:
270 		bzero(&net, sizeof(net));
271 		memcpy(&net.prefix, &res->addr, sizeof(res->addr));
272 		net.prefixlen = res->prefixlen;
273 		/* attribute sets are not supported */
274 		if (res->action == NETWORK_ADD) {
275 			imsg_compose(ibuf, IMSG_NETWORK_ADD, 0, 0, -1,
276 			    &net, sizeof(net));
277 			send_filterset(ibuf, &res->set);
278 			imsg_compose(ibuf, IMSG_NETWORK_DONE, 0, 0, -1,
279 			    NULL, 0);
280 		} else
281 			imsg_compose(ibuf, IMSG_NETWORK_REMOVE, 0, 0, -1,
282 			    &net, sizeof(net));
283 		printf("request sent.\n");
284 		done = 1;
285 		break;
286 	case NETWORK_FLUSH:
287 		imsg_compose(ibuf, IMSG_NETWORK_FLUSH, 0, 0, -1, NULL, 0);
288 		printf("request sent.\n");
289 		done = 1;
290 		break;
291 	case NETWORK_SHOW:
292 		imsg_compose(ibuf, IMSG_CTL_SHOW_NETWORK, 0, 0, -1,
293 		    &res->af, sizeof(res->af));
294 		show_network_head();
295 		break;
296 	}
297 
298 	while (ibuf->w.queued)
299 		if (msgbuf_write(&ibuf->w) < 0)
300 			err(1, "write error");
301 
302 	while (!done) {
303 		if ((n = imsg_read(ibuf)) == -1)
304 			errx(1, "imsg_read error");
305 		if (n == 0)
306 			errx(1, "pipe closed");
307 
308 		while (!done) {
309 			if ((n = imsg_get(ibuf, &imsg)) == -1)
310 				errx(1, "imsg_get error");
311 			if (n == 0)
312 				break;
313 
314 			if (imsg.hdr.type == IMSG_CTL_RESULT) {
315 				done = show_result(&imsg);
316 				imsg_free(&imsg);
317 				continue;
318 			}
319 
320 			switch (res->action) {
321 			case SHOW:
322 			case SHOW_SUMMARY:
323 				done = show_summary_msg(&imsg, nodescr);
324 				break;
325 			case SHOW_SUMMARY_TERSE:
326 				done = show_summary_terse_msg(&imsg, nodescr);
327 				break;
328 			case SHOW_FIB:
329 				done = show_fib_msg(&imsg);
330 				break;
331 			case SHOW_NEXTHOP:
332 				done = show_nexthop_msg(&imsg);
333 				break;
334 			case SHOW_INTERFACE:
335 				done = show_interface_msg(&imsg);
336 				break;
337 			case SHOW_NEIGHBOR:
338 				done = show_neighbor_msg(&imsg, NV_DEFAULT);
339 				break;
340 			case SHOW_NEIGHBOR_TIMERS:
341 				done = show_neighbor_msg(&imsg, NV_TIMERS);
342 				break;
343 			case SHOW_NEIGHBOR_TERSE:
344 				done = show_neighbor_terse(&imsg);
345 				break;
346 			case SHOW_RIB:
347 				if (res->flags & F_CTL_DETAIL)
348 					done = show_rib_detail_msg(&imsg,
349 					    nodescr);
350 				else
351 					done = show_rib_summary_msg(&imsg);
352 				break;
353 			case SHOW_RIB_MEM:
354 				done = show_rib_memory_msg(&imsg);
355 				break;
356 			case NETWORK_SHOW:
357 				done = show_fib_msg(&imsg);
358 				break;
359 			case NEIGHBOR:
360 			case NEIGHBOR_UP:
361 			case NEIGHBOR_DOWN:
362 			case NEIGHBOR_CLEAR:
363 			case NEIGHBOR_RREFRESH:
364 			case NONE:
365 			case RELOAD:
366 			case FIB:
367 			case FIB_COUPLE:
368 			case FIB_DECOUPLE:
369 			case NETWORK_ADD:
370 			case NETWORK_REMOVE:
371 			case NETWORK_FLUSH:
372 			case IRRFILTER:
373 				break;
374 			}
375 			imsg_free(&imsg);
376 		}
377 	}
378 	close(fd);
379 	free(ibuf);
380 
381 	exit(0);
382 }
383 
384 char *
385 fmt_peer(const char *descr, const struct bgpd_addr *remote_addr,
386     int masklen, int nodescr)
387 {
388 	const char	*ip;
389 	char		*p;
390 
391 	if (descr[0] && !nodescr) {
392 		if ((p = strdup(descr)) == NULL)
393 			err(1, NULL);
394 		return (p);
395 	}
396 
397 	ip = log_addr(remote_addr);
398 	if (masklen != -1 && ((remote_addr->af == AF_INET && masklen != 32) ||
399 	    (remote_addr->af == AF_INET6 && masklen != 128))) {
400 		if (asprintf(&p, "%s/%u", ip, masklen) == -1)
401 			err(1, NULL);
402 	} else {
403 		if ((p = strdup(ip)) == NULL)
404 			err(1, NULL);
405 	}
406 
407 	return (p);
408 }
409 
410 void
411 show_summary_head(void)
412 {
413 	printf("%-20s %8s %10s %10s %5s %-8s %s\n", "Neighbor", "AS",
414 	    "MsgRcvd", "MsgSent", "OutQ", "Up/Down", "State/PrfRcvd");
415 }
416 
417 int
418 show_summary_msg(struct imsg *imsg, int nodescr)
419 {
420 	struct peer		*p;
421 	char			*s;
422 
423 	switch (imsg->hdr.type) {
424 	case IMSG_CTL_SHOW_NEIGHBOR:
425 		p = imsg->data;
426 		s = fmt_peer(p->conf.descr, &p->conf.remote_addr,
427 		    p->conf.remote_masklen, nodescr);
428 		if (strlen(s) >= 20)
429 			s[20] = 0;
430 		printf("%-20s %8s %10llu %10llu %5u %-8s ",
431 		    s, log_as(p->conf.remote_as),
432 		    p->stats.msg_rcvd_open + p->stats.msg_rcvd_notification +
433 		    p->stats.msg_rcvd_update + p->stats.msg_rcvd_keepalive +
434 		    p->stats.msg_rcvd_rrefresh,
435 		    p->stats.msg_sent_open + p->stats.msg_sent_notification +
436 		    p->stats.msg_sent_update + p->stats.msg_sent_keepalive +
437 		    p->stats.msg_sent_rrefresh,
438 		    p->wbuf.queued,
439 		    fmt_timeframe(p->stats.last_updown));
440 		if (p->state == STATE_ESTABLISHED) {
441 			printf("%6u", p->stats.prefix_cnt);
442 			if (p->conf.max_prefix != 0)
443 				printf("/%u", p->conf.max_prefix);
444 		} else if (p->conf.template)
445 			printf("Template");
446 		else
447 			printf("%s", statenames[p->state]);
448 		printf("\n");
449 		free(s);
450 		break;
451 	case IMSG_CTL_END:
452 		return (1);
453 	default:
454 		break;
455 	}
456 
457 	return (0);
458 }
459 
460 int
461 show_summary_terse_msg(struct imsg *imsg, int nodescr)
462 {
463 	struct peer		*p;
464 	char			*s;
465 
466 	switch (imsg->hdr.type) {
467 	case IMSG_CTL_SHOW_NEIGHBOR:
468 		p = imsg->data;
469 		s = fmt_peer(p->conf.descr, &p->conf.remote_addr,
470 		    p->conf.remote_masklen, nodescr);
471 		printf("%s %s %s\n", s, log_as(p->conf.remote_as),
472 		    p->conf.template ? "Template" : statenames[p->state]);
473 		free(s);
474 		break;
475 	case IMSG_CTL_END:
476 		return (1);
477 	default:
478 		break;
479 	}
480 
481 	return (0);
482 }
483 
484 int
485 show_neighbor_terse(struct imsg *imsg)
486 {
487 	struct peer		*p;
488 
489 	switch (imsg->hdr.type) {
490 	case IMSG_CTL_SHOW_NEIGHBOR:
491 		p = imsg->data;
492 		printf("%llu %llu %llu %llu %llu %llu %llu "
493 		    "%llu %llu %llu %u %u %llu %llu %llu %llu\n",
494 		    p->stats.msg_sent_open, p->stats.msg_rcvd_open,
495 		    p->stats.msg_sent_notification,
496 		    p->stats.msg_rcvd_notification,
497 		    p->stats.msg_sent_update, p->stats.msg_rcvd_update,
498 		    p->stats.msg_sent_keepalive, p->stats.msg_rcvd_keepalive,
499 		    p->stats.msg_sent_rrefresh, p->stats.msg_rcvd_rrefresh,
500 		    p->stats.prefix_cnt, p->conf.max_prefix,
501 		    p->stats.prefix_sent_update, p->stats.prefix_rcvd_update,
502 		    p->stats.prefix_sent_withdraw,
503 		    p->stats.prefix_rcvd_withdraw);
504 		break;
505 	case IMSG_CTL_END:
506 		return (1);
507 	default:
508 		break;
509 	}
510 
511 	return (0);
512 }
513 
514 int
515 show_neighbor_msg(struct imsg *imsg, enum neighbor_views nv)
516 {
517 	struct peer		*p;
518 	struct ctl_timer	*t;
519 	struct in_addr		 ina;
520 	char			 buf[NI_MAXHOST], pbuf[NI_MAXSERV], *s;
521 
522 	switch (imsg->hdr.type) {
523 	case IMSG_CTL_SHOW_NEIGHBOR:
524 		p = imsg->data;
525 		if ((p->conf.remote_addr.af == AF_INET &&
526 		    p->conf.remote_masklen != 32) ||
527 		    (p->conf.remote_addr.af == AF_INET6 &&
528 		    p->conf.remote_masklen != 128)) {
529 			if (asprintf(&s, "%s/%u",
530 			    log_addr(&p->conf.remote_addr),
531 			    p->conf.remote_masklen) == -1)
532 				err(1, NULL);
533 		} else
534 			if ((s = strdup(log_addr(&p->conf.remote_addr))) ==
535 			    NULL)
536 				err(1, "strdup");
537 
538 		ina.s_addr = p->remote_bgpid;
539 		printf("BGP neighbor is %s, ", s);
540 		free(s);
541 		if (p->conf.remote_as == 0 && p->conf.template)
542 			printf("remote AS: accept any");
543 		else
544 			printf("remote AS %s", log_as(p->conf.remote_as));
545 		if (p->conf.template)
546 			printf(", Template");
547 		if (p->conf.cloned)
548 			printf(", Cloned");
549 		printf("\n");
550 		if (p->conf.descr[0])
551 			printf(" Description: %s\n", p->conf.descr);
552 		printf("  BGP version 4, remote router-id %s\n",
553 		    inet_ntoa(ina));
554 		printf("  BGP state = %s", statenames[p->state]);
555 		if (p->stats.last_updown != 0)
556 			printf(", %s for %s",
557 			    p->state == STATE_ESTABLISHED ? "up" : "down",
558 			    fmt_timeframe(p->stats.last_updown));
559 		printf("\n");
560 		printf("  Last read %s, holdtime %us, keepalive interval %us\n",
561 		    fmt_timeframe(p->stats.last_read),
562 		    p->holdtime, p->holdtime/3);
563 		if (p->capa.peer.mp_v4 || p->capa.peer.mp_v6 ||
564 		    p->capa.peer.refresh || p->capa.peer.restart ||
565 		    p->capa.peer.as4byte) {
566 			printf("  Neighbor capabilities:\n");
567 			if (p->capa.peer.mp_v4) {
568 				printf("    Multiprotocol extensions: IPv4");
569 				print_neighbor_capa_mp_safi(p->capa.peer.mp_v4);
570 			}
571 			if (p->capa.peer.mp_v6) {
572 				printf("    Multiprotocol extensions: IPv6");
573 				print_neighbor_capa_mp_safi(p->capa.peer.mp_v6);
574 			}
575 			if (p->capa.peer.refresh)
576 				printf("    Route Refresh\n");
577 			if (p->capa.peer.restart)
578 				printf("    Graceful Restart\n");
579 			if (p->capa.peer.as4byte)
580 				printf("    4-byte AS numbers\n");
581 		}
582 		printf("\n");
583 		if (nv == NV_TIMERS)
584 			break;
585 		print_neighbor_msgstats(p);
586 		printf("\n");
587 		if (p->state == STATE_IDLE) {
588 			static const char	*errstr;
589 
590 			errstr = get_errstr(p->stats.last_sent_errcode,
591 			    p->stats.last_sent_suberr);
592 			if (errstr)
593 				printf("  Last error: %s\n\n", errstr);
594 		} else {
595 			if (getnameinfo((struct sockaddr *)&p->sa_local,
596 			    (socklen_t)p->sa_local.ss_len,
597 			    buf, sizeof(buf), pbuf, sizeof(pbuf),
598 			    NI_NUMERICHOST | NI_NUMERICSERV)) {
599 				strlcpy(buf, "(unknown)", sizeof(buf));
600 				strlcpy(pbuf, "", sizeof(pbuf));
601 			}
602 			printf("  Local host:  %20s, Local port:  %5s\n", buf,
603 			    pbuf);
604 
605 			if (getnameinfo((struct sockaddr *)&p->sa_remote,
606 			    (socklen_t)p->sa_remote.ss_len,
607 			    buf, sizeof(buf), pbuf, sizeof(pbuf),
608 			    NI_NUMERICHOST | NI_NUMERICSERV)) {
609 				strlcpy(buf, "(unknown)", sizeof(buf));
610 				strlcpy(pbuf, "", sizeof(pbuf));
611 			}
612 			printf("  Remote host: %20s, Remote port: %5s\n", buf,
613 			    pbuf);
614 			printf("\n");
615 		}
616 		break;
617 	case IMSG_CTL_SHOW_TIMER:
618 		t = imsg->data;
619 		if (t->type > 0 && t->type < Timer_Max)
620 			print_timer(timernames[t->type], t->val);
621 		break;
622 	case IMSG_CTL_END:
623 		return (1);
624 		break;
625 	default:
626 		break;
627 	}
628 
629 	return (0);
630 }
631 
632 void
633 print_neighbor_capa_mp_safi(u_int8_t safi)
634 {
635 	switch (safi) {
636 	case SAFI_UNICAST:
637 		printf(" Unicast");
638 		break;
639 	case SAFI_MULTICAST:
640 		printf(" Multicast");
641 		break;
642 	default:
643 		printf(" unknown (%u)", safi);
644 		break;
645 	}
646 	printf("\n");
647 }
648 
649 void
650 print_neighbor_msgstats(struct peer *p)
651 {
652 	printf("  Message statistics:\n");
653 	printf("  %-15s %-10s %-10s\n", "", "Sent", "Received");
654 	printf("  %-15s %10llu %10llu\n", "Opens",
655 	    p->stats.msg_sent_open, p->stats.msg_rcvd_open);
656 	printf("  %-15s %10llu %10llu\n", "Notifications",
657 	    p->stats.msg_sent_notification, p->stats.msg_rcvd_notification);
658 	printf("  %-15s %10llu %10llu\n", "Updates",
659 	    p->stats.msg_sent_update, p->stats.msg_rcvd_update);
660 	printf("  %-15s %10llu %10llu\n", "Keepalives",
661 	    p->stats.msg_sent_keepalive, p->stats.msg_rcvd_keepalive);
662 	printf("  %-15s %10llu %10llu\n", "Route Refresh",
663 	    p->stats.msg_sent_rrefresh, p->stats.msg_rcvd_rrefresh);
664 	printf("  %-15s %10llu %10llu\n\n", "Total",
665 	    p->stats.msg_sent_open + p->stats.msg_sent_notification +
666 	    p->stats.msg_sent_update + p->stats.msg_sent_keepalive +
667 	    p->stats.msg_sent_rrefresh,
668 	    p->stats.msg_rcvd_open + p->stats.msg_rcvd_notification +
669 	    p->stats.msg_rcvd_update + p->stats.msg_rcvd_keepalive +
670 	    p->stats.msg_rcvd_rrefresh);
671 	printf("  Update statistics:\n");
672 	printf("  %-15s %-10s %-10s\n", "", "Sent", "Received");
673 	printf("  %-15s %10llu %10llu\n", "Updates",
674 	    p->stats.prefix_sent_update, p->stats.prefix_rcvd_update);
675 	printf("  %-15s %10llu %10llu\n", "Withdraws",
676 	    p->stats.prefix_sent_withdraw, p->stats.prefix_rcvd_withdraw);
677 }
678 
679 void
680 print_timer(const char *name, timer_t d)
681 {
682 	printf("  %-20s ", name);
683 
684 	if (d <= 0)
685 		printf("%-20s\n", "due");
686 	else
687 		printf("due in %-13s\n", fmt_timeframe_core(d));
688 }
689 
690 #define TF_BUFS	8
691 #define TF_LEN	9
692 
693 static char *
694 fmt_timeframe(time_t t)
695 {
696 	if (t == 0)
697 		return ("Never");
698 	else
699 		return (fmt_timeframe_core(time(NULL) - t));
700 }
701 
702 static char *
703 fmt_timeframe_core(time_t t)
704 {
705 	char		*buf;
706 	static char	 tfbuf[TF_BUFS][TF_LEN];	/* ring buffer */
707 	static int	 idx = 0;
708 	unsigned int	 sec, min, hrs, day, week;
709 
710 	buf = tfbuf[idx++];
711 	if (idx == TF_BUFS)
712 		idx = 0;
713 
714 	week = t;
715 
716 	sec = week % 60;
717 	week /= 60;
718 	min = week % 60;
719 	week /= 60;
720 	hrs = week % 24;
721 	week /= 24;
722 	day = week % 7;
723 	week /= 7;
724 
725 	if (week > 0)
726 		snprintf(buf, TF_LEN, "%02uw%01ud%02uh", week, day, hrs);
727 	else if (day > 0)
728 		snprintf(buf, TF_LEN, "%01ud%02uh%02um", day, hrs, min);
729 	else
730 		snprintf(buf, TF_LEN, "%02u:%02u:%02u", hrs, min, sec);
731 
732 	return (buf);
733 }
734 
735 void
736 show_fib_head(void)
737 {
738 	printf("flags: * = valid, B = BGP, C = Connected, S = Static\n");
739 	printf("       N = BGP Nexthop reachable via this route\n");
740 	printf("       r = reject route, b = blackhole route\n\n");
741 	printf("flags prio destination          gateway\n");
742 }
743 
744 void
745 show_network_head(void)
746 {
747 	printf("flags: S = Static\n");
748 	printf("flags destination\n");
749 }
750 
751 void
752 show_fib_flags(u_int16_t flags)
753 {
754 	if (flags & F_DOWN)
755 		printf(" ");
756 	else
757 		printf("*");
758 
759 	if (flags & F_BGPD_INSERTED)
760 		printf("B");
761 	else if (flags & F_CONNECTED)
762 		printf("C");
763 	else if (flags & F_STATIC)
764 		printf("S");
765 	else
766 		printf(" ");
767 
768 	if (flags & F_NEXTHOP)
769 		printf("N");
770 	else
771 		printf(" ");
772 
773 	if (flags & F_REJECT && flags & F_BLACKHOLE)
774 		printf("f");
775 	else if (flags & F_REJECT)
776 		printf("r");
777 	else if (flags & F_BLACKHOLE)
778 		printf("b");
779 	else
780 		printf(" ");
781 
782 	printf("  ");
783 }
784 
785 int
786 show_fib_msg(struct imsg *imsg)
787 {
788 	struct kroute		*k;
789 	struct kroute6		*k6;
790 	char			*p;
791 
792 	switch (imsg->hdr.type) {
793 	case IMSG_CTL_KROUTE:
794 	case IMSG_CTL_SHOW_NETWORK:
795 		if (imsg->hdr.len < IMSG_HEADER_SIZE + sizeof(struct kroute))
796 			errx(1, "wrong imsg len");
797 		k = imsg->data;
798 
799 		show_fib_flags(k->flags);
800 
801 		if (asprintf(&p, "%s/%u", inet_ntoa(k->prefix), k->prefixlen) ==
802 		    -1)
803 			err(1, NULL);
804 		printf("%4i %-20s ", k->priority, p);
805 		free(p);
806 
807 		if (k->nexthop.s_addr)
808 			printf("%s", inet_ntoa(k->nexthop));
809 		else if (k->flags & F_CONNECTED)
810 			printf("link#%u", k->ifindex);
811 		printf("\n");
812 
813 		break;
814 	case IMSG_CTL_KROUTE6:
815 	case IMSG_CTL_SHOW_NETWORK6:
816 		if (imsg->hdr.len < IMSG_HEADER_SIZE + sizeof(struct kroute6))
817 			errx(1, "wrong imsg len");
818 		k6 = imsg->data;
819 
820 		show_fib_flags(k6->flags);
821 
822 		if (asprintf(&p, "%s/%u", log_in6addr(&k6->prefix),
823 		    k6->prefixlen) == -1)
824 			err(1, NULL);
825 		printf("%4i %-20s ", k6->priority, p);
826 		free(p);
827 
828 		if (!IN6_IS_ADDR_UNSPECIFIED(&k6->nexthop))
829 			printf("%s", log_in6addr(&k6->nexthop));
830 		else if (k6->flags & F_CONNECTED)
831 			printf("link#%u", k6->ifindex);
832 		printf("\n");
833 
834 		break;
835 	case IMSG_CTL_END:
836 		return (1);
837 		break;
838 	default:
839 		break;
840 	}
841 
842 	return (0);
843 }
844 
845 void
846 show_nexthop_head(void)
847 {
848 	printf("%-20s %-10s\n", "Nexthop", "State");
849 }
850 
851 int
852 show_nexthop_msg(struct imsg *imsg)
853 {
854 	struct ctl_show_nexthop	*p;
855 	int			 ifms_type;
856 
857 	switch (imsg->hdr.type) {
858 	case IMSG_CTL_SHOW_NEXTHOP:
859 		p = imsg->data;
860 		printf("%-20s %-10s", log_addr(&p->addr),
861 		    p->valid ? "valid" : "invalid");
862 		if (p->kif.ifname[0]) {
863 			printf("%-8s", p->kif.ifname);
864 			if (p->kif.flags & IFF_UP) {
865 				printf("UP");
866 				ifms_type = ift2ifm(p->kif.media_type);
867 				if (ifms_type != 0)
868 					printf(", %s, %s",
869 					    get_media_descr(ifms_type),
870 					    get_linkstate(ifms_type,
871 					    p->kif.link_state));
872 				if (p->kif.baudrate) {
873 					printf(", ");
874 					print_baudrate(p->kif.baudrate);
875 				}
876 			}
877 		}
878 		printf("\n");
879 		break;
880 	case IMSG_CTL_END:
881 		return (1);
882 		break;
883 	default:
884 		break;
885 	}
886 
887 	return (0);
888 }
889 
890 
891 void
892 show_interface_head(void)
893 {
894 	printf("%-15s%-15s%-15s%s\n", "Interface", "Nexthop state", "Flags",
895 	    "Link state");
896 }
897 
898 const int	ifm_status_valid_list[] = IFM_STATUS_VALID_LIST;
899 const struct ifmedia_status_description
900 		ifm_status_descriptions[] = IFM_STATUS_DESCRIPTIONS;
901 const struct ifmedia_description
902 		ifm_type_descriptions[] = IFM_TYPE_DESCRIPTIONS;
903 
904 int
905 ift2ifm(int media_type)
906 {
907 	switch (media_type) {
908 	case IFT_ETHER:
909 		return (IFM_ETHER);
910 	case IFT_FDDI:
911 		return (IFM_FDDI);
912 	case IFT_CARP:
913 		return (IFM_CARP);
914 	case IFT_IEEE80211:
915 		return (IFM_IEEE80211);
916 	default:
917 		return (0);
918 	}
919 }
920 
921 const char *
922 get_media_descr(int media_type)
923 {
924 	const struct ifmedia_description	*p;
925 
926 	for (p = ifm_type_descriptions; p->ifmt_string != NULL; p++)
927 		if (media_type == p->ifmt_word)
928 			return (p->ifmt_string);
929 
930 	return ("unknown media");
931 }
932 
933 const char *
934 get_linkstate(int media_type, int link_state)
935 {
936 	const struct ifmedia_status_description	*p;
937 	int					 i;
938 
939 	if (link_state == LINK_STATE_UNKNOWN)
940 		return ("unknown");
941 
942 	for (i = 0; ifm_status_valid_list[i] != 0; i++)
943 		for (p = ifm_status_descriptions; p->ifms_valid != 0; p++) {
944 			if (p->ifms_type != media_type ||
945 			    p->ifms_valid != ifm_status_valid_list[i])
946 				continue;
947 			if (LINK_STATE_IS_UP(link_state))
948 				return (p->ifms_string[1]);
949 			return (p->ifms_string[0]);
950 		}
951 
952 	return ("unknown link state");
953 }
954 
955 void
956 print_baudrate(u_int64_t baudrate)
957 {
958 	if (baudrate > IF_Gbps(1))
959 		printf("%llu GBit/s", baudrate / IF_Gbps(1));
960 	else if (baudrate > IF_Mbps(1))
961 		printf("%llu MBit/s", baudrate / IF_Mbps(1));
962 	else if (baudrate > IF_Kbps(1))
963 		printf("%llu KBit/s", baudrate / IF_Kbps(1));
964 	else
965 		printf("%llu Bit/s", baudrate);
966 }
967 
968 int
969 show_interface_msg(struct imsg *imsg)
970 {
971 	struct kif	*k;
972 	int		 ifms_type;
973 
974 	switch (imsg->hdr.type) {
975 	case IMSG_CTL_SHOW_INTERFACE:
976 		k = imsg->data;
977 		printf("%-15s", k->ifname);
978 		printf("%-15s", k->nh_reachable ? "ok" : "invalid");
979 		printf("%-15s", k->flags & IFF_UP ? "UP" : "");
980 
981 		if ((ifms_type = ift2ifm(k->media_type)) != 0)
982 			printf("%s, %s", get_media_descr(ifms_type),
983 			    get_linkstate(ifms_type, k->link_state));
984 		else if (k->link_state == LINK_STATE_UNKNOWN)
985 			printf("unknown");
986 		else
987 			printf("link state %u", k->link_state);
988 
989 		if (k->link_state != LINK_STATE_DOWN && k->baudrate > 0) {
990 			printf(", ");
991 			print_baudrate(k->baudrate);
992 		}
993 		printf("\n");
994 		break;
995 	case IMSG_CTL_END:
996 		return (1);
997 		break;
998 	default:
999 		break;
1000 	}
1001 
1002 	return (0);
1003 }
1004 
1005 void
1006 show_rib_summary_head(void)
1007 {
1008 	printf(
1009 	    "flags: * = Valid, > = Selected, I = via IBGP, A = Announced\n");
1010 	printf("origin: i = IGP, e = EGP, ? = Incomplete\n\n");
1011 	printf("%-5s %-20s%-15s  %5s %5s %s\n", "flags", "destination",
1012 	    "gateway", "lpref", "med", "aspath origin");
1013 }
1014 
1015 void
1016 print_prefix(struct bgpd_addr *prefix, u_int8_t prefixlen, u_int8_t flags)
1017 {
1018 	char			*p;
1019 
1020 	print_flags(flags, 1);
1021 	if (asprintf(&p, "%s/%u", log_addr(prefix), prefixlen) == -1)
1022 		err(1, NULL);
1023 	printf("%-20s", p);
1024 	free(p);
1025 }
1026 
1027 const char *
1028 print_origin(u_int8_t origin, int sum)
1029 {
1030 	switch (origin) {
1031 	case ORIGIN_IGP:
1032 		return (sum ? "i" : "IGP");
1033 	case ORIGIN_EGP:
1034 		return (sum ? "e" : "EGP");
1035 	case ORIGIN_INCOMPLETE:
1036 		return (sum ? "?" : "incomplete");
1037 	default:
1038 		return (sum ? "X" : "bad origin");
1039 	}
1040 }
1041 
1042 void
1043 print_flags(u_int8_t flags, int sum)
1044 {
1045 	char	 flagstr[5];
1046 	char	*p = flagstr;
1047 
1048 	if (sum) {
1049 		if (flags & F_RIB_ANNOUNCE)
1050 			*p++ = 'A';
1051 		if (flags & F_RIB_INTERNAL)
1052 			*p++ = 'I';
1053 		if (flags & F_RIB_ELIGIBLE)
1054 			*p++ = '*';
1055 		if (flags & F_RIB_ACTIVE)
1056 			*p++ = '>';
1057 		*p = '\0';
1058 		printf("%-5s ", flagstr);
1059 	} else {
1060 		if (flags & F_RIB_INTERNAL)
1061 			printf("internal");
1062 		else
1063 			printf("external");
1064 		if (flags & F_RIB_ELIGIBLE)
1065 			printf(", valid");
1066 		if (flags & F_RIB_ACTIVE)
1067 			printf(", best");
1068 		if (flags & F_RIB_ANNOUNCE)
1069 			printf(", announced");
1070 	}
1071 }
1072 
1073 int
1074 show_rib_summary_msg(struct imsg *imsg)
1075 {
1076 	struct ctl_show_rib	 rib;
1077 	char			*aspath;
1078 	u_char			*asdata;
1079 
1080 	switch (imsg->hdr.type) {
1081 	case IMSG_CTL_SHOW_RIB:
1082 		memcpy(&rib, imsg->data, sizeof(rib));
1083 
1084 		print_prefix(&rib.prefix, rib.prefixlen, rib.flags);
1085 		printf("%-15s ", log_addr(&rib.exit_nexthop));
1086 
1087 		printf(" %5u %5u ", rib.local_pref, rib.med);
1088 
1089 		asdata = imsg->data;
1090 		asdata += sizeof(struct ctl_show_rib);
1091 		if (aspath_asprint(&aspath, asdata, rib.aspath_len) == -1)
1092 			err(1, NULL);
1093 		if (strlen(aspath) > 0)
1094 			printf("%s ", aspath);
1095 		free(aspath);
1096 
1097 		printf("%s\n", print_origin(rib.origin, 1));
1098 		break;
1099 	case IMSG_CTL_END:
1100 		return (1);
1101 	default:
1102 		break;
1103 	}
1104 
1105 	return (0);
1106 }
1107 
1108 int
1109 show_rib_detail_msg(struct imsg *imsg, int nodescr)
1110 {
1111 	struct ctl_show_rib	 rib;
1112 	struct in_addr		 id;
1113 	char			*aspath, *s;
1114 	u_char			*data;
1115 	u_int32_t		 as;
1116 	u_int16_t		 ilen, alen, ioff;
1117 	u_int8_t		 flags, type;
1118 	time_t			 now;
1119 
1120 	switch (imsg->hdr.type) {
1121 	case IMSG_CTL_SHOW_RIB:
1122 		memcpy(&rib, imsg->data, sizeof(rib));
1123 
1124 		printf("\nBGP routing table entry for %s/%u\n",
1125 		    log_addr(&rib.prefix), rib.prefixlen);
1126 
1127 		data = imsg->data;
1128 		data += sizeof(struct ctl_show_rib);
1129 		if (aspath_asprint(&aspath, data, rib.aspath_len) == -1)
1130 			err(1, NULL);
1131 		if (strlen(aspath) > 0)
1132 			printf("    %s\n", aspath);
1133 		free(aspath);
1134 
1135 		s = fmt_peer(rib.descr, &rib.remote_addr, -1, nodescr);
1136 		printf("    Nexthop %s ", log_addr(&rib.exit_nexthop));
1137 		printf("(via %s) from %s (", log_addr(&rib.true_nexthop), s);
1138 		free(s);
1139 		id.s_addr = htonl(rib.remote_id);
1140 		printf("%s)\n", inet_ntoa(id));
1141 
1142 		printf("    Origin %s, metric %u, localpref %u, ",
1143 		    print_origin(rib.origin, 0), rib.med, rib.local_pref);
1144 		print_flags(rib.flags, 0);
1145 
1146 		now = time(NULL);
1147 		if (now > rib.lastchange)
1148 			now -= rib.lastchange;
1149 		else
1150 			now = 0;
1151 
1152 		printf("\n    Last update: %s ago\n",
1153 		    fmt_timeframe_core(now));
1154 		break;
1155 	case IMSG_CTL_SHOW_RIB_ATTR:
1156 		ilen = imsg->hdr.len - IMSG_HEADER_SIZE;
1157 		if (ilen < 3)
1158 			errx(1, "bad IMSG_CTL_SHOW_RIB_ATTR received");
1159 		data = imsg->data;
1160 		flags = data[0];
1161 		type = data[1];
1162 
1163 		/* get the attribute length */
1164 		if (flags & ATTR_EXTLEN) {
1165 			if (ilen < 4)
1166 				errx(1, "bad IMSG_CTL_SHOW_RIB_ATTR received");
1167 			memcpy(&alen, data+2, sizeof(u_int16_t));
1168 			alen = ntohs(alen);
1169 			data += 4;
1170 			ilen -= 4;
1171 		} else {
1172 			alen = data[2];
1173 			data += 3;
1174 			ilen -= 3;
1175 		}
1176 		/* bad imsg len how can that happen!? */
1177 		if (alen != ilen)
1178 			errx(1, "bad IMSG_CTL_SHOW_RIB_ATTR received");
1179 
1180 		switch (type) {
1181 		case ATTR_COMMUNITIES:
1182 			printf("    Communities: ");
1183 			show_community(data, alen);
1184 			printf("\n");
1185 			break;
1186 		case ATTR_AGGREGATOR:
1187 			memcpy(&as, data, sizeof(as));
1188 			memcpy(&id, data + sizeof(as), sizeof(id));
1189 			printf("    Aggregator: %s [%s]\n",
1190 			    log_as(htonl(as)), inet_ntoa(id));
1191 			break;
1192 		case ATTR_ORIGINATOR_ID:
1193 			memcpy(&id, data, sizeof(id));
1194 			printf("    Originator Id: %s\n", inet_ntoa(id));
1195 			break;
1196 		case ATTR_CLUSTER_LIST:
1197 			printf("    Cluster ID List:");
1198 			for (ioff = 0; ioff + sizeof(id) <= ilen;
1199 			    ioff += sizeof(id)) {
1200 				memcpy(&id, data + ioff, sizeof(id));
1201 				printf(" %s", inet_ntoa(id));
1202 			}
1203 			printf("\n");
1204 			break;
1205 		case ATTR_EXT_COMMUNITIES:
1206 			printf("    Ext. communities: ");
1207 			show_ext_community(data, alen);
1208 			printf("\n");
1209 			break;
1210 		default:
1211 			/* ignore unknown attributes */
1212 			break;
1213 		}
1214 		break;
1215 	case IMSG_CTL_END:
1216 		printf("\n");
1217 		return (1);
1218 	default:
1219 		break;
1220 	}
1221 
1222 	return (0);
1223 }
1224 
1225 char *
1226 fmt_mem(int64_t num)
1227 {
1228 	static char	buf[16];
1229 
1230 	if (fmt_scaled(num, buf) == -1)
1231 		snprintf(buf, sizeof(buf), "%lldB", (long long)num);
1232 
1233 	return (buf);
1234 }
1235 
1236 int
1237 show_rib_memory_msg(struct imsg *imsg)
1238 {
1239 	struct rde_memstats	stats;
1240 
1241 	switch (imsg->hdr.type) {
1242 	case IMSG_CTL_SHOW_RIB_MEM:
1243 		memcpy(&stats, imsg->data, sizeof(stats));
1244 		printf("RDE memory statistics\n");
1245 		printf("%10lld IPv4 network entries using %s of memory\n",
1246 		    (long long)stats.pt4_cnt, fmt_mem(stats.pt4_cnt *
1247 		    sizeof(struct pt_entry4)));
1248 		if (stats.pt6_cnt != 0)
1249 			printf("%10lld IPv6 network entries using "
1250 			    "%s of memory\n", (long long)stats.pt6_cnt,
1251 			    fmt_mem(stats.pt6_cnt * sizeof(struct pt_entry6)));
1252 		printf("%10lld prefix entries using %s of memory\n",
1253 		    (long long)stats.prefix_cnt, fmt_mem(stats.prefix_cnt *
1254 		    sizeof(struct prefix)));
1255 		printf("%10lld BGP path attribute entries using %s of memory\n",
1256 		    (long long)stats.path_cnt, fmt_mem(stats.path_cnt *
1257 		    sizeof(struct rde_aspath)));
1258 		printf("%10lld BGP AS-PATH attribute entries using "
1259 		    "%s of memory,\n\t   and holding %lld references\n",
1260 		    (long long)stats.aspath_cnt, fmt_mem(stats.aspath_size),
1261 		    (long long)stats.aspath_refs);
1262 		printf("%10lld BGP attributes entries using %s of memory\n",
1263 		    (long long)stats.attr_cnt, fmt_mem(stats.attr_cnt *
1264 		    sizeof(struct attr)));
1265 		printf("\t   and holding %lld references\n",
1266 		    (long long)stats.attr_refs);
1267 		printf("%10lld BGP attributes using %s of memory\n",
1268 		    (long long)stats.attr_dcnt, fmt_mem(stats.attr_data));
1269 		printf("RIB using %s of memory\n", fmt_mem(
1270 		    stats.pt4_cnt * sizeof(struct pt_entry4) +
1271 		    stats.pt6_cnt * sizeof(struct pt_entry6) +
1272 		    stats.prefix_cnt * sizeof(struct prefix) +
1273 		    stats.path_cnt * sizeof(struct rde_aspath) +
1274 		    stats.aspath_size + stats.attr_cnt * sizeof(struct attr) +
1275 		    stats.attr_data));
1276 		break;
1277 	default:
1278 		break;
1279 	}
1280 
1281 	return (1);
1282 }
1283 
1284 void
1285 show_community(u_char *data, u_int16_t len)
1286 {
1287 	u_int16_t	a, v;
1288 	u_int16_t	i;
1289 
1290 	if (len & 0x3)
1291 		return;
1292 
1293 	for (i = 0; i < len; i += 4) {
1294 		memcpy(&a, data + i, sizeof(a));
1295 		memcpy(&v, data + i + 2, sizeof(v));
1296 		a = ntohs(a);
1297 		v = ntohs(v);
1298 		if (a == COMMUNITY_WELLKNOWN)
1299 			switch (v) {
1300 			case COMMUNITY_NO_EXPORT:
1301 				printf("NO_EXPORT");
1302 				break;
1303 			case COMMUNITY_NO_ADVERTISE:
1304 				printf("NO_ADVERTISE");
1305 				break;
1306 			case COMMUNITY_NO_EXPSUBCONFED:
1307 				printf("NO_EXPORT_SUBCONFED");
1308 				break;
1309 			case COMMUNITY_NO_PEER:
1310 				printf("NO_PEER");
1311 				break;
1312 			default:
1313 				printf("WELLKNOWN:%hu", v);
1314 				break;
1315 			}
1316 		else
1317 			printf("%hu:%hu", a, v);
1318 
1319 		if (i + 4 < len)
1320 			printf(" ");
1321 	}
1322 }
1323 
1324 const char *
1325 get_ext_subtype(u_int8_t type)
1326 {
1327 	static char etype[6];
1328 
1329 	switch (type) {
1330 	case EXT_COMMUNITY_ROUTE_TGT:
1331 		return "rt";	/* route target */
1332 	case EXT_CUMMUNITY_ROUTE_ORIG:
1333 		return "soo";	/* source of origin */
1334 	case EXT_COMMUNITY_OSPF_DOM_ID:
1335 		return "odi";	/* ospf domain id */
1336 	case EXT_COMMUNITY_OSPF_RTR_TYPE:
1337 		return "ort";	/* ospf route type */
1338 	case EXT_COMMUNITY_OSPF_RTR_ID:
1339 		return "ori";	/* ospf router id */
1340 	case EXT_COMMUNITY_BGP_COLLECT:
1341 		return "bdc";	/* bgp data collection */
1342 	default:
1343 		snprintf(etype, sizeof(etype), "[%i]", (int)type);
1344 		return etype;
1345 	}
1346 }
1347 
1348 void
1349 show_ext_community(u_char *data, u_int16_t len)
1350 {
1351 	u_int64_t	ext;
1352 	struct in_addr	ip;
1353 	u_int32_t	as4, u32;
1354 	u_int16_t	i, as2, u16;
1355 	u_int8_t	type, subtype;
1356 
1357 	if (len & 0x7)
1358 		return;
1359 
1360 	for (i = 0; i < len; i += 8) {
1361 		type = data[i];
1362 		subtype = data[i + 1];
1363 
1364 		switch (type & EXT_COMMUNITY_VALUE) {
1365 		case EXT_COMMUNITY_TWO_AS:
1366 			memcpy(&as2, data + i + 2, sizeof(as2));
1367 			memcpy(&u32, data + i + 4, sizeof(u32));
1368 			printf("%s %hu:%u", get_ext_subtype(subtype), as2, u32);
1369 			break;
1370 		case EXT_COMMUNITY_IPV4:
1371 			memcpy(&ip, data + i + 2, sizeof(ip));
1372 			memcpy(&u16, data + i + 6, sizeof(u16));
1373 			printf("%s %s:%hu", get_ext_subtype(subtype),
1374 			    inet_ntoa(ip), u16);
1375 			break;
1376 		case EXT_COMMUNITY_FOUR_AS:
1377 			memcpy(&as4, data + i + 2, sizeof(as4));
1378 			memcpy(&u16, data + i + 6, sizeof(u16));
1379 			printf("%s %s:%hu", get_ext_subtype(subtype),
1380 			    log_as(as4), u16);
1381 			break;
1382 		case EXT_COMMUNITY_OPAQUE:
1383 			memcpy(&ext, data + i, sizeof(ext));
1384 			ext = betoh64(ext) & 0xffffffffffffLL;
1385 			printf("%s 0x%llx", get_ext_subtype(subtype), ext);
1386 			break;
1387 		default:
1388 			memcpy(&ext, data + i, sizeof(ext));
1389 			printf("0x%llx", betoh64(ext));
1390 		}
1391 		if (i + 8 < len)
1392 			printf(", ");
1393 	}
1394 }
1395 
1396 void
1397 send_filterset(struct imsgbuf *i, struct filter_set_head *set)
1398 {
1399 	struct filter_set	*s;
1400 
1401 	while ((s = TAILQ_FIRST(set)) != NULL) {
1402 		imsg_compose(i, IMSG_FILTER_SET, 0, 0, -1, s,
1403 		    sizeof(struct filter_set));
1404 		TAILQ_REMOVE(set, s, entry);
1405 		free(s);
1406 	}
1407 }
1408 
1409 static const char *
1410 get_errstr(u_int8_t errcode, u_int8_t subcode)
1411 {
1412 	static const char	*errstr = NULL;
1413 
1414 	if (errcode && errcode < sizeof(errnames)/sizeof(char *))
1415 		errstr = errnames[errcode];
1416 
1417 	switch (errcode) {
1418 	case ERR_HEADER:
1419 		if (subcode &&
1420 		    subcode < sizeof(suberr_header_names)/sizeof(char *))
1421 			errstr = suberr_header_names[subcode];
1422 		break;
1423 	case ERR_OPEN:
1424 		if (subcode &&
1425 		    subcode < sizeof(suberr_open_names)/sizeof(char *))
1426 			errstr = suberr_open_names[subcode];
1427 		break;
1428 	case ERR_UPDATE:
1429 		if (subcode &&
1430 		    subcode < sizeof(suberr_update_names)/sizeof(char *))
1431 			errstr = suberr_update_names[subcode];
1432 		break;
1433 	case ERR_HOLDTIMEREXPIRED:
1434 	case ERR_FSM:
1435 	case ERR_CEASE:
1436 		break;
1437 	default:
1438 		return ("unknown error code");
1439 	}
1440 
1441 	return (errstr);
1442 }
1443 
1444 int
1445 show_result(struct imsg *imsg)
1446 {
1447 	u_int	rescode;
1448 
1449 	if (imsg->hdr.len != IMSG_HEADER_SIZE + sizeof(rescode))
1450 		errx(1, "got IMSG_CTL_RESULT with wrong len");
1451 	memcpy(&rescode, imsg->data, sizeof(rescode));
1452 
1453 	if (rescode == 0)
1454 		printf("request processed\n");
1455 	else {
1456 		if (rescode >
1457 		    sizeof(ctl_res_strerror)/sizeof(ctl_res_strerror[0]))
1458 			errx(1, "illegal error code %u", rescode);
1459 		printf("%s\n", ctl_res_strerror[rescode]);
1460 	}
1461 
1462 	return (1);
1463 }
1464 
1465 /* following functions are necessary for imsg framework */
1466 void
1467 log_warnx(const char *emsg, ...)
1468 {
1469 	va_list	 ap;
1470 
1471 	va_start(ap, emsg);
1472 	vwarnx(emsg, ap);
1473 	va_end(ap);
1474 }
1475 
1476 void
1477 log_warn(const char *emsg, ...)
1478 {
1479 	va_list	 ap;
1480 
1481 	va_start(ap, emsg);
1482 	vwarn(emsg, ap);
1483 	va_end(ap);
1484 }
1485 
1486 void
1487 fatal(const char *emsg)
1488 {
1489 	err(1, emsg);
1490 }
1491