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