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