xref: /openbsd-src/usr.sbin/bgpctl/bgpctl.c (revision 5e3c7963eb248119b7dfd4b0defad58a7d9cd306)
1 /*	$OpenBSD: bgpctl.c,v 1.228 2019/01/20 23:30:15 claudio Exp $ */
2 
3 /*
4  * Copyright (c) 2003 Henning Brauer <henning@openbsd.org>
5  * Copyright (c) 2016 Job Snijders <job@instituut.net>
6  * Copyright (c) 2016 Peter Hessler <phessler@openbsd.org>
7  *
8  * Permission to use, copy, modify, and distribute this software for any
9  * purpose with or without fee is hereby granted, provided that the above
10  * copyright notice and this permission notice appear in all copies.
11  *
12  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19  */
20 
21 #include <sys/types.h>
22 #include <sys/socket.h>
23 #include <sys/stat.h>
24 #include <sys/un.h>
25 
26 #include <err.h>
27 #include <errno.h>
28 #include <fcntl.h>
29 #include <math.h>
30 #include <netdb.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <time.h>
35 #include <unistd.h>
36 #include <util.h>
37 
38 #include "bgpd.h"
39 #include "session.h"
40 #include "rde.h"
41 #include "parser.h"
42 #include "irrfilter.h"
43 #include "mrtparser.h"
44 
45 enum neighbor_views {
46 	NV_DEFAULT,
47 	NV_TIMERS
48 };
49 
50 #define EOL0(flag)	((flag & F_CTL_SSV) ? ';' : '\n')
51 
52 int		 main(int, char *[]);
53 char		*fmt_peer(const char *, const struct bgpd_addr *, int, int);
54 void		 show_summary_head(void);
55 int		 show_summary_msg(struct imsg *, int);
56 int		 show_summary_terse_msg(struct imsg *, int);
57 int		 show_neighbor_terse(struct imsg *);
58 int		 show_neighbor_msg(struct imsg *, enum neighbor_views);
59 void		 print_neighbor_capa_mp(struct peer *);
60 void		 print_neighbor_capa_restart(struct peer *);
61 void		 print_neighbor_msgstats(struct peer *);
62 void		 print_timer(const char *, time_t);
63 static char	*fmt_timeframe(time_t t);
64 static char	*fmt_timeframe_core(time_t t);
65 void		 show_fib_head(void);
66 void		 show_fib_tables_head(void);
67 void		 show_network_head(void);
68 void		 show_fib_flags(u_int16_t);
69 int		 show_fib_msg(struct imsg *);
70 void		 show_nexthop_head(void);
71 int		 show_nexthop_msg(struct imsg *);
72 void		 show_interface_head(void);
73 int		 show_interface_msg(struct imsg *);
74 void		 show_rib_summary_head(void);
75 void		 print_prefix(struct bgpd_addr *, u_int8_t, u_int8_t, u_int8_t);
76 const char *	 print_origin(u_int8_t, int);
77 const char *	 print_ovs(u_int8_t, int);
78 void		 print_flags(u_int8_t, int);
79 int		 show_rib_summary_msg(struct imsg *);
80 int		 show_rib_detail_msg(struct imsg *, int, int);
81 void		 show_rib_brief(struct ctl_show_rib *, u_char *);
82 void		 show_rib_detail(struct ctl_show_rib *, u_char *, int, int);
83 void		 show_attr(void *, u_int16_t, int);
84 void		 show_community(u_char *, u_int16_t);
85 void		 show_large_community(u_char *, u_int16_t);
86 void		 show_ext_community(u_char *, u_int16_t);
87 char		*fmt_mem(int64_t);
88 int		 show_rib_memory_msg(struct imsg *);
89 void		 send_filterset(struct imsgbuf *, struct filter_set_head *);
90 const char	*get_errstr(u_int8_t, u_int8_t);
91 int		 show_result(struct imsg *);
92 void		 show_mrt_dump(struct mrt_rib *, struct mrt_peer *, void *);
93 void		 network_mrt_dump(struct mrt_rib *, struct mrt_peer *, void *);
94 void		 show_mrt_state(struct mrt_bgp_state *, void *);
95 void		 show_mrt_msg(struct mrt_bgp_msg *, void *);
96 void		 mrt_to_bgpd_addr(union mrt_addr *, struct bgpd_addr *);
97 const char	*msg_type(u_int8_t);
98 void		 network_bulk(struct parse_result *);
99 const char	*print_auth_method(enum auth_method);
100 int		 match_aspath(void *, u_int16_t, struct filter_as *);
101 
102 struct imsgbuf	*ibuf;
103 struct mrt_parser show_mrt = { show_mrt_dump, show_mrt_state, show_mrt_msg };
104 struct mrt_parser net_mrt = { network_mrt_dump, NULL, NULL };
105 int tableid;
106 
107 __dead void
108 usage(void)
109 {
110 	extern char	*__progname;
111 
112 	fprintf(stderr, "usage: %s [-n] [-s socket] command [argument ...]\n",
113 	    __progname);
114 	exit(1);
115 }
116 
117 int
118 main(int argc, char *argv[])
119 {
120 	struct sockaddr_un	 sun;
121 	int			 fd, n, done, ch, nodescr = 0, verbose = 0;
122 	struct imsg		 imsg;
123 	struct network_config	 net;
124 	struct parse_result	*res;
125 	struct ctl_neighbor	 neighbor;
126 	struct ctl_show_rib_request	ribreq;
127 	char			*sockname;
128 	enum imsg_type		 type;
129 
130 	if (pledge("stdio rpath wpath cpath unix inet dns", NULL) == -1)
131 		err(1, "pledge");
132 
133 	tableid = getrtable();
134 	if (asprintf(&sockname, "%s.%d", SOCKET_NAME, tableid) == -1)
135 		err(1, "asprintf");
136 
137 	while ((ch = getopt(argc, argv, "ns:")) != -1) {
138 		switch (ch) {
139 		case 'n':
140 			if (++nodescr > 1)
141 				usage();
142 			break;
143 		case 's':
144 			sockname = optarg;
145 			break;
146 		default:
147 			usage();
148 			/* NOTREACHED */
149 		}
150 	}
151 	argc -= optind;
152 	argv += optind;
153 
154 	if ((res = parse(argc, argv)) == NULL)
155 		exit(1);
156 
157 	memcpy(&neighbor.addr, &res->peeraddr, sizeof(neighbor.addr));
158 	strlcpy(neighbor.descr, res->peerdesc, sizeof(neighbor.descr));
159 	neighbor.is_group = res->is_group;
160 	strlcpy(neighbor.shutcomm, res->shutcomm, sizeof(neighbor.shutcomm));
161 
162 	switch (res->action) {
163 	case IRRFILTER:
164 		if (!(res->flags & (F_IPV4|F_IPV6)))
165 			res->flags |= (F_IPV4|F_IPV6);
166 		irr_main(res->as.as_min, res->flags, res->irr_outdir);
167 		break;
168 	case SHOW_MRT:
169 		if (pledge("stdio", NULL) == -1)
170 			err(1, "pledge");
171 
172 		bzero(&ribreq, sizeof(ribreq));
173 		if (res->as.type != AS_UNDEF)
174 			ribreq.as = res->as;
175 		if (res->addr.aid) {
176 			ribreq.prefix = res->addr;
177 			ribreq.prefixlen = res->prefixlen;
178 		}
179 		/* XXX currently no communities support */
180 		ribreq.neighbor = neighbor;
181 		ribreq.aid = res->aid;
182 		ribreq.flags = res->flags;
183 		ribreq.validation_state = res->validation_state;
184 		show_mrt.arg = &ribreq;
185 		if (!(res->flags & F_CTL_DETAIL))
186 			show_rib_summary_head();
187 		mrt_parse(res->mrtfd, &show_mrt, 1);
188 		exit(0);
189 	default:
190 		break;
191 	}
192 
193 	if (pledge("stdio unix", NULL) == -1)
194 		err(1, "pledge");
195 
196 	if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
197 		err(1, "control_init: socket");
198 
199 	bzero(&sun, sizeof(sun));
200 	sun.sun_family = AF_UNIX;
201 	if (strlcpy(sun.sun_path, sockname, sizeof(sun.sun_path)) >=
202 	    sizeof(sun.sun_path))
203 		errx(1, "socket name too long");
204 	if (connect(fd, (struct sockaddr *)&sun, sizeof(sun)) == -1)
205 		err(1, "connect: %s", sockname);
206 
207 	if (pledge("stdio", NULL) == -1)
208 		err(1, "pledge");
209 
210 	if ((ibuf = malloc(sizeof(struct imsgbuf))) == NULL)
211 		err(1, NULL);
212 	imsg_init(ibuf, fd);
213 	done = 0;
214 
215 	switch (res->action) {
216 	case NONE:
217 	case IRRFILTER:
218 	case SHOW_MRT:
219 		usage();
220 		/* NOTREACHED */
221 	case SHOW:
222 	case SHOW_SUMMARY:
223 		imsg_compose(ibuf, IMSG_CTL_SHOW_NEIGHBOR, 0, 0, -1, NULL, 0);
224 		show_summary_head();
225 		break;
226 	case SHOW_SUMMARY_TERSE:
227 		imsg_compose(ibuf, IMSG_CTL_SHOW_TERSE, 0, 0, -1, NULL, 0);
228 		break;
229 	case SHOW_FIB:
230 		if (!res->addr.aid) {
231 			struct ibuf	*msg;
232 			sa_family_t	 af;
233 
234 			af = aid2af(res->aid);
235 			if ((msg = imsg_create(ibuf, IMSG_CTL_KROUTE,
236 			    res->rtableid, 0, sizeof(res->flags) +
237 			    sizeof(af))) == NULL)
238 				errx(1, "imsg_create failure");
239 			if (imsg_add(msg, &res->flags, sizeof(res->flags)) ==
240 			    -1 ||
241 			    imsg_add(msg, &af, sizeof(af)) == -1)
242 				errx(1, "imsg_add failure");
243 			imsg_close(ibuf, msg);
244 		} else
245 			imsg_compose(ibuf, IMSG_CTL_KROUTE_ADDR, res->rtableid,
246 			    0, -1, &res->addr, sizeof(res->addr));
247 		show_fib_head();
248 		break;
249 	case SHOW_FIB_TABLES:
250 		imsg_compose(ibuf, IMSG_CTL_SHOW_FIB_TABLES, 0, 0, -1, NULL, 0);
251 		show_fib_tables_head();
252 		break;
253 	case SHOW_NEXTHOP:
254 		imsg_compose(ibuf, IMSG_CTL_SHOW_NEXTHOP, res->rtableid, 0, -1,
255 		    NULL, 0);
256 		show_nexthop_head();
257 		break;
258 	case SHOW_INTERFACE:
259 		imsg_compose(ibuf, IMSG_CTL_SHOW_INTERFACE, 0, 0, -1, NULL, 0);
260 		show_interface_head();
261 		break;
262 	case SHOW_NEIGHBOR:
263 	case SHOW_NEIGHBOR_TIMERS:
264 	case SHOW_NEIGHBOR_TERSE:
265 		neighbor.show_timers = (res->action == SHOW_NEIGHBOR_TIMERS);
266 		if (res->peeraddr.aid || res->peerdesc[0])
267 			imsg_compose(ibuf, IMSG_CTL_SHOW_NEIGHBOR, 0, 0, -1,
268 			    &neighbor, sizeof(neighbor));
269 		else
270 			imsg_compose(ibuf, IMSG_CTL_SHOW_NEIGHBOR, 0, 0, -1,
271 			    NULL, 0);
272 		break;
273 	case SHOW_RIB:
274 		bzero(&ribreq, sizeof(ribreq));
275 		type = IMSG_CTL_SHOW_RIB;
276 		if (res->addr.aid) {
277 			ribreq.prefix = res->addr;
278 			ribreq.prefixlen = res->prefixlen;
279 			type = IMSG_CTL_SHOW_RIB_PREFIX;
280 		}
281 		if (res->as.type != AS_UNDEF)
282 			ribreq.as = res->as;
283 		if (res->community.type != COMMUNITY_TYPE_NONE)
284 			ribreq.community = res->community;
285 		ribreq.neighbor = neighbor;
286 		strlcpy(ribreq.rib, res->rib, sizeof(ribreq.rib));
287 		ribreq.aid = res->aid;
288 		ribreq.flags = res->flags;
289 		imsg_compose(ibuf, type, 0, 0, -1, &ribreq, sizeof(ribreq));
290 		if (!(res->flags & F_CTL_DETAIL))
291 			show_rib_summary_head();
292 		break;
293 	case SHOW_RIB_MEM:
294 		imsg_compose(ibuf, IMSG_CTL_SHOW_RIB_MEM, 0, 0, -1, NULL, 0);
295 		break;
296 	case RELOAD:
297 		imsg_compose(ibuf, IMSG_CTL_RELOAD, 0, 0, -1, NULL, 0);
298 		printf("reload request sent.\n");
299 		break;
300 	case FIB:
301 		errx(1, "action==FIB");
302 		break;
303 	case FIB_COUPLE:
304 		imsg_compose(ibuf, IMSG_CTL_FIB_COUPLE, res->rtableid, 0, -1,
305 		    NULL, 0);
306 		printf("couple request sent.\n");
307 		done = 1;
308 		break;
309 	case FIB_DECOUPLE:
310 		imsg_compose(ibuf, IMSG_CTL_FIB_DECOUPLE, res->rtableid, 0, -1,
311 		    NULL, 0);
312 		printf("decouple request sent.\n");
313 		done = 1;
314 		break;
315 	case NEIGHBOR:
316 		errx(1, "action==NEIGHBOR");
317 		break;
318 	case NEIGHBOR_UP:
319 		imsg_compose(ibuf, IMSG_CTL_NEIGHBOR_UP, 0, 0, -1,
320 		    &neighbor, sizeof(neighbor));
321 		break;
322 	case NEIGHBOR_DOWN:
323 		imsg_compose(ibuf, IMSG_CTL_NEIGHBOR_DOWN, 0, 0, -1,
324 		    &neighbor, sizeof(neighbor));
325 		break;
326 	case NEIGHBOR_CLEAR:
327 		imsg_compose(ibuf, IMSG_CTL_NEIGHBOR_CLEAR, 0, 0, -1,
328 		    &neighbor, sizeof(neighbor));
329 		break;
330 	case NEIGHBOR_RREFRESH:
331 		imsg_compose(ibuf, IMSG_CTL_NEIGHBOR_RREFRESH, 0, 0, -1,
332 		    &neighbor, sizeof(neighbor));
333 		break;
334 	case NEIGHBOR_DESTROY:
335 		imsg_compose(ibuf, IMSG_CTL_NEIGHBOR_DESTROY, 0, 0, -1,
336 		    &neighbor, sizeof(neighbor));
337 		break;
338 	case NETWORK_BULK_ADD:
339 	case NETWORK_BULK_REMOVE:
340 		network_bulk(res);
341 		printf("requests sent.\n");
342 		done = 1;
343 		break;
344 	case NETWORK_ADD:
345 	case NETWORK_REMOVE:
346 		bzero(&net, sizeof(net));
347 		net.prefix = res->addr;
348 		net.prefixlen = res->prefixlen;
349 		net.rtableid = tableid;
350 		/* attribute sets are not supported */
351 		if (res->action == NETWORK_ADD) {
352 			imsg_compose(ibuf, IMSG_NETWORK_ADD, 0, 0, -1,
353 			    &net, sizeof(net));
354 			send_filterset(ibuf, &res->set);
355 			imsg_compose(ibuf, IMSG_NETWORK_DONE, 0, 0, -1,
356 			    NULL, 0);
357 		} else
358 			imsg_compose(ibuf, IMSG_NETWORK_REMOVE, 0, 0, -1,
359 			    &net, sizeof(net));
360 		printf("request sent.\n");
361 		done = 1;
362 		break;
363 	case NETWORK_FLUSH:
364 		imsg_compose(ibuf, IMSG_NETWORK_FLUSH, 0, 0, -1, NULL, 0);
365 		printf("request sent.\n");
366 		done = 1;
367 		break;
368 	case NETWORK_SHOW:
369 		bzero(&ribreq, sizeof(ribreq));
370 		ribreq.aid = res->aid;
371 		strlcpy(ribreq.rib, res->rib, sizeof(ribreq.rib));
372 		imsg_compose(ibuf, IMSG_CTL_SHOW_NETWORK, 0, 0, -1,
373 		    &ribreq, sizeof(ribreq));
374 		show_network_head();
375 		break;
376 	case NETWORK_MRT:
377 		bzero(&ribreq, sizeof(ribreq));
378 		if (res->as.type != AS_UNDEF)
379 			ribreq.as = res->as;
380 		if (res->addr.aid) {
381 			ribreq.prefix = res->addr;
382 			ribreq.prefixlen = res->prefixlen;
383 		}
384 		/* XXX currently no community support */
385 		ribreq.neighbor = neighbor;
386 		ribreq.aid = res->aid;
387 		ribreq.flags = res->flags;
388 		net_mrt.arg = &ribreq;
389 		mrt_parse(res->mrtfd, &net_mrt, 1);
390 		done = 1;
391 		break;
392 	case LOG_VERBOSE:
393 		verbose = 1;
394 		/* FALLTHROUGH */
395 	case LOG_BRIEF:
396 		imsg_compose(ibuf, IMSG_CTL_LOG_VERBOSE, 0, 0, -1,
397 		    &verbose, sizeof(verbose));
398 		printf("logging request sent.\n");
399 		done = 1;
400 		break;
401 	}
402 
403 	while (ibuf->w.queued)
404 		if (msgbuf_write(&ibuf->w) <= 0 && errno != EAGAIN)
405 			err(1, "write error");
406 
407 	while (!done) {
408 		if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN)
409 			err(1, "imsg_read error");
410 		if (n == 0)
411 			errx(1, "pipe closed");
412 
413 		while (!done) {
414 			if ((n = imsg_get(ibuf, &imsg)) == -1)
415 				err(1, "imsg_get error");
416 			if (n == 0)
417 				break;
418 
419 			if (imsg.hdr.type == IMSG_CTL_RESULT) {
420 				done = show_result(&imsg);
421 				imsg_free(&imsg);
422 				continue;
423 			}
424 
425 			switch (res->action) {
426 			case SHOW:
427 			case SHOW_SUMMARY:
428 				done = show_summary_msg(&imsg, nodescr);
429 				break;
430 			case SHOW_SUMMARY_TERSE:
431 				done = show_summary_terse_msg(&imsg, nodescr);
432 				break;
433 			case SHOW_FIB:
434 			case SHOW_FIB_TABLES:
435 			case NETWORK_SHOW:
436 				done = show_fib_msg(&imsg);
437 				break;
438 			case SHOW_NEXTHOP:
439 				done = show_nexthop_msg(&imsg);
440 				break;
441 			case SHOW_INTERFACE:
442 				done = show_interface_msg(&imsg);
443 				break;
444 			case SHOW_NEIGHBOR:
445 				done = show_neighbor_msg(&imsg, NV_DEFAULT);
446 				break;
447 			case SHOW_NEIGHBOR_TIMERS:
448 				done = show_neighbor_msg(&imsg, NV_TIMERS);
449 				break;
450 			case SHOW_NEIGHBOR_TERSE:
451 				done = show_neighbor_terse(&imsg);
452 				break;
453 			case SHOW_RIB:
454 				if (res->flags & F_CTL_DETAIL)
455 					done = show_rib_detail_msg(&imsg,
456 					    nodescr, res->flags);
457 				else
458 					done = show_rib_summary_msg(&imsg);
459 				break;
460 			case SHOW_RIB_MEM:
461 				done = show_rib_memory_msg(&imsg);
462 				break;
463 			case NEIGHBOR:
464 			case NEIGHBOR_UP:
465 			case NEIGHBOR_DOWN:
466 			case NEIGHBOR_CLEAR:
467 			case NEIGHBOR_RREFRESH:
468 			case NEIGHBOR_DESTROY:
469 			case NONE:
470 			case RELOAD:
471 			case FIB:
472 			case FIB_COUPLE:
473 			case FIB_DECOUPLE:
474 			case NETWORK_ADD:
475 			case NETWORK_REMOVE:
476 			case NETWORK_FLUSH:
477 			case NETWORK_BULK_ADD:
478 			case NETWORK_BULK_REMOVE:
479 			case IRRFILTER:
480 			case LOG_VERBOSE:
481 			case LOG_BRIEF:
482 			case SHOW_MRT:
483 			case NETWORK_MRT:
484 				break;
485 			}
486 			imsg_free(&imsg);
487 		}
488 	}
489 	close(fd);
490 	free(ibuf);
491 
492 	exit(0);
493 }
494 
495 char *
496 fmt_peer(const char *descr, const struct bgpd_addr *remote_addr,
497     int masklen, int nodescr)
498 {
499 	const char	*ip;
500 	char		*p;
501 
502 	if (descr[0] && !nodescr) {
503 		if ((p = strdup(descr)) == NULL)
504 			err(1, NULL);
505 		return (p);
506 	}
507 
508 	ip = log_addr(remote_addr);
509 	if (masklen != -1 && ((remote_addr->aid == AID_INET && masklen != 32) ||
510 	    (remote_addr->aid == AID_INET6 && masklen != 128))) {
511 		if (asprintf(&p, "%s/%u", ip, masklen) == -1)
512 			err(1, NULL);
513 	} else {
514 		if ((p = strdup(ip)) == NULL)
515 			err(1, NULL);
516 	}
517 
518 	return (p);
519 }
520 
521 void
522 show_summary_head(void)
523 {
524 	printf("%-20s %8s %10s %10s %5s %-8s %s\n", "Neighbor", "AS",
525 	    "MsgRcvd", "MsgSent", "OutQ", "Up/Down", "State/PrfRcvd");
526 }
527 
528 int
529 show_summary_msg(struct imsg *imsg, int nodescr)
530 {
531 	struct peer		*p;
532 	char			*s;
533 	const char		*a;
534 	size_t			alen;
535 
536 	switch (imsg->hdr.type) {
537 	case IMSG_CTL_SHOW_NEIGHBOR:
538 		p = imsg->data;
539 		s = fmt_peer(p->conf.descr, &p->conf.remote_addr,
540 		    p->conf.remote_masklen, nodescr);
541 
542 		a = log_as(p->conf.remote_as);
543 		alen = strlen(a);
544 		/* max displayed length of the peers name is 28 */
545 		if (alen < 28) {
546 			if (strlen(s) > 28 - alen)
547 				s[28 - alen] = 0;
548 		} else
549 			alen = 0;
550 
551 		printf("%-*s %s %10llu %10llu %5u %-8s ",
552 		    (28 - (int)alen), s, a,
553 		    p->stats.msg_rcvd_open + p->stats.msg_rcvd_notification +
554 		    p->stats.msg_rcvd_update + p->stats.msg_rcvd_keepalive +
555 		    p->stats.msg_rcvd_rrefresh,
556 		    p->stats.msg_sent_open + p->stats.msg_sent_notification +
557 		    p->stats.msg_sent_update + p->stats.msg_sent_keepalive +
558 		    p->stats.msg_sent_rrefresh,
559 		    p->wbuf.queued,
560 		    fmt_timeframe(p->stats.last_updown));
561 		if (p->state == STATE_ESTABLISHED) {
562 			printf("%6u", p->stats.prefix_cnt);
563 			if (p->conf.max_prefix != 0)
564 				printf("/%u", p->conf.max_prefix);
565 		} else if (p->conf.template)
566 			printf("Template");
567 		else
568 			printf("%s", statenames[p->state]);
569 		printf("\n");
570 		free(s);
571 		break;
572 	case IMSG_CTL_END:
573 		return (1);
574 	default:
575 		break;
576 	}
577 
578 	return (0);
579 }
580 
581 int
582 show_summary_terse_msg(struct imsg *imsg, int nodescr)
583 {
584 	struct peer		*p;
585 	char			*s;
586 
587 	switch (imsg->hdr.type) {
588 	case IMSG_CTL_SHOW_NEIGHBOR:
589 		p = imsg->data;
590 		s = fmt_peer(p->conf.descr, &p->conf.remote_addr,
591 		    p->conf.remote_masklen, nodescr);
592 		printf("%s %s %s\n", s, log_as(p->conf.remote_as),
593 		    p->conf.template ? "Template" : statenames[p->state]);
594 		free(s);
595 		break;
596 	case IMSG_CTL_END:
597 		return (1);
598 	default:
599 		break;
600 	}
601 
602 	return (0);
603 }
604 
605 int
606 show_neighbor_terse(struct imsg *imsg)
607 {
608 	struct peer		*p;
609 
610 	switch (imsg->hdr.type) {
611 	case IMSG_CTL_SHOW_NEIGHBOR:
612 		p = imsg->data;
613 		printf("%llu %llu %llu %llu %llu %llu %llu "
614 		    "%llu %llu %llu %u %u %llu %llu %llu %llu\n",
615 		    p->stats.msg_sent_open, p->stats.msg_rcvd_open,
616 		    p->stats.msg_sent_notification,
617 		    p->stats.msg_rcvd_notification,
618 		    p->stats.msg_sent_update, p->stats.msg_rcvd_update,
619 		    p->stats.msg_sent_keepalive, p->stats.msg_rcvd_keepalive,
620 		    p->stats.msg_sent_rrefresh, p->stats.msg_rcvd_rrefresh,
621 		    p->stats.prefix_cnt, p->conf.max_prefix,
622 		    p->stats.prefix_sent_update, p->stats.prefix_rcvd_update,
623 		    p->stats.prefix_sent_withdraw,
624 		    p->stats.prefix_rcvd_withdraw);
625 		break;
626 	case IMSG_CTL_END:
627 		return (1);
628 	default:
629 		break;
630 	}
631 
632 	return (0);
633 }
634 
635 const char *
636 print_auth_method(enum auth_method method)
637 {
638 	switch (method) {
639 	case AUTH_MD5SIG:
640 		return ", using md5sig";
641 	case AUTH_IPSEC_MANUAL_ESP:
642 		return ", using ipsec manual esp";
643 	case AUTH_IPSEC_MANUAL_AH:
644 		return ", using ipsec manual ah";
645 	case AUTH_IPSEC_IKE_ESP:
646 		return ", using ipsec ike esp";
647 	case AUTH_IPSEC_IKE_AH:
648 		return ", using ipsec ike ah";
649 	case AUTH_NONE:	/* FALLTHROUGH */
650 	default:
651 		return "";
652 	}
653 }
654 
655 int
656 show_neighbor_msg(struct imsg *imsg, enum neighbor_views nv)
657 {
658 	struct peer		*p;
659 	struct ctl_timer	*t;
660 	struct in_addr		 ina;
661 	char			 buf[NI_MAXHOST], pbuf[NI_MAXSERV], *s;
662 	int			 hascapamp = 0;
663 	u_int8_t		 i;
664 
665 	switch (imsg->hdr.type) {
666 	case IMSG_CTL_SHOW_NEIGHBOR:
667 		p = imsg->data;
668 		if ((p->conf.remote_addr.aid == AID_INET &&
669 		    p->conf.remote_masklen != 32) ||
670 		    (p->conf.remote_addr.aid == AID_INET6 &&
671 		    p->conf.remote_masklen != 128)) {
672 			if (asprintf(&s, "%s/%u",
673 			    log_addr(&p->conf.remote_addr),
674 			    p->conf.remote_masklen) == -1)
675 				err(1, NULL);
676 		} else
677 			if ((s = strdup(log_addr(&p->conf.remote_addr))) ==
678 			    NULL)
679 				err(1, "strdup");
680 
681 		ina.s_addr = p->remote_bgpid;
682 		printf("BGP neighbor is %s, ", s);
683 		free(s);
684 		if (p->conf.remote_as == 0 && p->conf.template)
685 			printf("remote AS: accept any");
686 		else
687 			printf("remote AS %s", log_as(p->conf.remote_as));
688 		if (p->conf.template)
689 			printf(", Template");
690 		if (p->template)
691 			printf(", Cloned");
692 		if (p->conf.passive)
693 			printf(", Passive");
694 		if (p->conf.ebgp && p->conf.distance > 1)
695 			printf(", Multihop (%u)", (int)p->conf.distance);
696 		printf("\n");
697 		if (p->conf.descr[0])
698 			printf(" Description: %s\n", p->conf.descr);
699 		if (p->conf.max_prefix) {
700 			printf(" Max-prefix: %u", p->conf.max_prefix);
701 			if (p->conf.max_prefix_restart)
702 				printf(" (restart %u)",
703 				    p->conf.max_prefix_restart);
704 			printf("\n");
705 		}
706 		printf("  BGP version 4, remote router-id %s",
707 		    inet_ntoa(ina));
708 		printf("%s\n", print_auth_method(p->auth.method));
709 		printf("  BGP state = %s", statenames[p->state]);
710 		if (p->conf.down) {
711 			printf(", marked down");
712 			if (*(p->conf.shutcomm)) {
713 				printf(" with shutdown reason \"%s\"",
714 				    log_shutcomm(p->conf.shutcomm));
715 			}
716 		}
717 		if (p->stats.last_updown != 0)
718 			printf(", %s for %s",
719 			    p->state == STATE_ESTABLISHED ? "up" : "down",
720 			    fmt_timeframe(p->stats.last_updown));
721 		printf("\n");
722 		printf("  Last read %s, holdtime %us, keepalive interval %us\n",
723 		    fmt_timeframe(p->stats.last_read),
724 		    p->holdtime, p->holdtime/3);
725 		for (i = 0; i < AID_MAX; i++)
726 			if (p->capa.peer.mp[i])
727 				hascapamp = 1;
728 		if (hascapamp || p->capa.peer.refresh ||
729 		    p->capa.peer.grestart.restart || p->capa.peer.as4byte) {
730 			printf("  Neighbor capabilities:\n");
731 			if (hascapamp) {
732 				printf("    Multiprotocol extensions: ");
733 				print_neighbor_capa_mp(p);
734 				printf("\n");
735 			}
736 			if (p->capa.peer.refresh)
737 				printf("    Route Refresh\n");
738 			if (p->capa.peer.grestart.restart) {
739 				printf("    Graceful Restart");
740 				print_neighbor_capa_restart(p);
741 				printf("\n");
742 			}
743 			if (p->capa.peer.as4byte)
744 				printf("    4-byte AS numbers\n");
745 		}
746 		printf("\n");
747 		if (nv == NV_TIMERS)
748 			break;
749 		print_neighbor_msgstats(p);
750 		printf("\n");
751 		if (*(p->stats.last_shutcomm)) {
752 			printf("  Last received shutdown reason: \"%s\"\n",
753 			    log_shutcomm(p->stats.last_shutcomm));
754 		}
755 		if (p->state == STATE_IDLE) {
756 			static const char	*errstr;
757 
758 			errstr = get_errstr(p->stats.last_sent_errcode,
759 			    p->stats.last_sent_suberr);
760 			if (errstr)
761 				printf("  Last error: %s\n\n", errstr);
762 		} else {
763 			if (getnameinfo((struct sockaddr *)&p->sa_local,
764 			    (socklen_t)p->sa_local.ss_len,
765 			    buf, sizeof(buf), pbuf, sizeof(pbuf),
766 			    NI_NUMERICHOST | NI_NUMERICSERV)) {
767 				strlcpy(buf, "(unknown)", sizeof(buf));
768 				strlcpy(pbuf, "", sizeof(pbuf));
769 			}
770 			printf("  Local host:  %20s, Local port:  %5s\n", buf,
771 			    pbuf);
772 
773 			if (getnameinfo((struct sockaddr *)&p->sa_remote,
774 			    (socklen_t)p->sa_remote.ss_len,
775 			    buf, sizeof(buf), pbuf, sizeof(pbuf),
776 			    NI_NUMERICHOST | NI_NUMERICSERV)) {
777 				strlcpy(buf, "(unknown)", sizeof(buf));
778 				strlcpy(pbuf, "", sizeof(pbuf));
779 			}
780 			printf("  Remote host: %20s, Remote port: %5s\n", buf,
781 			    pbuf);
782 			printf("\n");
783 		}
784 		break;
785 	case IMSG_CTL_SHOW_TIMER:
786 		t = imsg->data;
787 		if (t->type > 0 && t->type < Timer_Max)
788 			print_timer(timernames[t->type], t->val);
789 		break;
790 	case IMSG_CTL_END:
791 		return (1);
792 		break;
793 	default:
794 		break;
795 	}
796 
797 	return (0);
798 }
799 
800 void
801 print_neighbor_capa_mp(struct peer *p)
802 {
803 	int		comma;
804 	u_int8_t	i;
805 
806 	for (i = 0, comma = 0; i < AID_MAX; i++)
807 		if (p->capa.peer.mp[i]) {
808 			printf("%s%s", comma ? ", " : "", aid2str(i));
809 			comma = 1;
810 		}
811 }
812 
813 void
814 print_neighbor_capa_restart(struct peer *p)
815 {
816 	int		comma;
817 	u_int8_t	i;
818 
819 	if (p->capa.peer.grestart.timeout)
820 		printf(": Timeout: %d, ", p->capa.peer.grestart.timeout);
821 	for (i = 0, comma = 0; i < AID_MAX; i++)
822 		if (p->capa.peer.grestart.flags[i] & CAPA_GR_PRESENT) {
823 			if (!comma &&
824 			    p->capa.peer.grestart.flags[i] & CAPA_GR_RESTART)
825 				printf("restarted, ");
826 			if (comma)
827 				printf(", ");
828 			printf("%s", aid2str(i));
829 			if (p->capa.peer.grestart.flags[i] & CAPA_GR_FORWARD)
830 				printf(" (preserved)");
831 			comma = 1;
832 		}
833 }
834 
835 void
836 print_neighbor_msgstats(struct peer *p)
837 {
838 	printf("  Message statistics:\n");
839 	printf("  %-15s %-10s %-10s\n", "", "Sent", "Received");
840 	printf("  %-15s %10llu %10llu\n", "Opens",
841 	    p->stats.msg_sent_open, p->stats.msg_rcvd_open);
842 	printf("  %-15s %10llu %10llu\n", "Notifications",
843 	    p->stats.msg_sent_notification, p->stats.msg_rcvd_notification);
844 	printf("  %-15s %10llu %10llu\n", "Updates",
845 	    p->stats.msg_sent_update, p->stats.msg_rcvd_update);
846 	printf("  %-15s %10llu %10llu\n", "Keepalives",
847 	    p->stats.msg_sent_keepalive, p->stats.msg_rcvd_keepalive);
848 	printf("  %-15s %10llu %10llu\n", "Route Refresh",
849 	    p->stats.msg_sent_rrefresh, p->stats.msg_rcvd_rrefresh);
850 	printf("  %-15s %10llu %10llu\n\n", "Total",
851 	    p->stats.msg_sent_open + p->stats.msg_sent_notification +
852 	    p->stats.msg_sent_update + p->stats.msg_sent_keepalive +
853 	    p->stats.msg_sent_rrefresh,
854 	    p->stats.msg_rcvd_open + p->stats.msg_rcvd_notification +
855 	    p->stats.msg_rcvd_update + p->stats.msg_rcvd_keepalive +
856 	    p->stats.msg_rcvd_rrefresh);
857 	printf("  Update statistics:\n");
858 	printf("  %-15s %-10s %-10s\n", "", "Sent", "Received");
859 	printf("  %-15s %10llu %10llu\n", "Updates",
860 	    p->stats.prefix_sent_update, p->stats.prefix_rcvd_update);
861 	printf("  %-15s %10llu %10llu\n", "Withdraws",
862 	    p->stats.prefix_sent_withdraw, p->stats.prefix_rcvd_withdraw);
863 	printf("  %-15s %10llu %10llu\n", "End-of-Rib",
864 	    p->stats.prefix_sent_eor, p->stats.prefix_rcvd_eor);
865 }
866 
867 void
868 print_timer(const char *name, time_t d)
869 {
870 	printf("  %-20s ", name);
871 
872 	if (d <= 0)
873 		printf("%-20s\n", "due");
874 	else
875 		printf("due in %-13s\n", fmt_timeframe_core(d));
876 }
877 
878 #define TF_BUFS	8
879 #define TF_LEN	9
880 
881 static char *
882 fmt_timeframe(time_t t)
883 {
884 	if (t == 0)
885 		return ("Never");
886 	else
887 		return (fmt_timeframe_core(time(NULL) - t));
888 }
889 
890 static char *
891 fmt_timeframe_core(time_t t)
892 {
893 	char		*buf;
894 	static char	 tfbuf[TF_BUFS][TF_LEN];	/* ring buffer */
895 	static int	 idx = 0;
896 	unsigned int	 sec, min, hrs, day;
897 	unsigned long long	week;
898 
899 	buf = tfbuf[idx++];
900 	if (idx == TF_BUFS)
901 		idx = 0;
902 
903 	week = t;
904 
905 	sec = week % 60;
906 	week /= 60;
907 	min = week % 60;
908 	week /= 60;
909 	hrs = week % 24;
910 	week /= 24;
911 	day = week % 7;
912 	week /= 7;
913 
914 	if (week > 0)
915 		snprintf(buf, TF_LEN, "%02lluw%01ud%02uh", week, day, hrs);
916 	else if (day > 0)
917 		snprintf(buf, TF_LEN, "%01ud%02uh%02um", day, hrs, min);
918 	else
919 		snprintf(buf, TF_LEN, "%02u:%02u:%02u", hrs, min, sec);
920 
921 	return (buf);
922 }
923 
924 void
925 show_fib_head(void)
926 {
927 	printf("flags: "
928 	    "* = valid, B = BGP, C = Connected, S = Static, D = Dynamic\n");
929 	printf("       "
930 	    "N = BGP Nexthop reachable via this route R = redistributed\n");
931 	printf("       r = reject route, b = blackhole route\n\n");
932 	printf("flags prio destination          gateway\n");
933 }
934 
935 void
936 show_fib_tables_head(void)
937 {
938 	printf("%-5s %-20s %-8s\n", "Table", "Description", "State");
939 }
940 
941 void
942 show_network_head(void)
943 {
944 	printf("flags: S = Static\n");
945 	printf("flags prio destination          gateway\n");
946 }
947 
948 void
949 show_fib_flags(u_int16_t flags)
950 {
951 	if (flags & F_DOWN)
952 		printf(" ");
953 	else
954 		printf("*");
955 
956 	if (flags & F_BGPD_INSERTED)
957 		printf("B");
958 	else if (flags & F_CONNECTED)
959 		printf("C");
960 	else if (flags & F_STATIC)
961 		printf("S");
962 	else if (flags & F_DYNAMIC)
963 		printf("D");
964 	else
965 		printf(" ");
966 
967 	if (flags & F_NEXTHOP)
968 		printf("N");
969 	else
970 		printf(" ");
971 
972 	if (flags & F_REDISTRIBUTED)
973 		printf("R");
974 	else
975 		printf(" ");
976 
977 	if (flags & F_REJECT && flags & F_BLACKHOLE)
978 		printf("f");
979 	else if (flags & F_REJECT)
980 		printf("r");
981 	else if (flags & F_BLACKHOLE)
982 		printf("b");
983 	else
984 		printf(" ");
985 
986 	printf(" ");
987 }
988 
989 int
990 show_fib_msg(struct imsg *imsg)
991 {
992 	struct kroute_full	*kf;
993 	struct ktable		*kt;
994 	char			*p;
995 
996 	switch (imsg->hdr.type) {
997 	case IMSG_CTL_KROUTE:
998 	case IMSG_CTL_SHOW_NETWORK:
999 		if (imsg->hdr.len < IMSG_HEADER_SIZE + sizeof(*kf))
1000 			errx(1, "wrong imsg len");
1001 		kf = imsg->data;
1002 
1003 		show_fib_flags(kf->flags);
1004 
1005 		if (asprintf(&p, "%s/%u", log_addr(&kf->prefix),
1006 		    kf->prefixlen) == -1)
1007 			err(1, NULL);
1008 		printf("%4i %-20s ", kf->priority, p);
1009 		free(p);
1010 
1011 		if (kf->flags & F_CONNECTED)
1012 			printf("link#%u", kf->ifindex);
1013 		else
1014 			printf("%s", log_addr(&kf->nexthop));
1015 		printf("\n");
1016 
1017 		break;
1018 	case IMSG_CTL_SHOW_FIB_TABLES:
1019 		if (imsg->hdr.len < IMSG_HEADER_SIZE + sizeof(*kt))
1020 			errx(1, "wrong imsg len");
1021 		kt = imsg->data;
1022 
1023 		printf("%5i %-20s %-8s%s\n", kt->rtableid, kt->descr,
1024 		    kt->fib_sync ? "coupled" : "decoupled",
1025 		    kt->fib_sync != kt->fib_conf ? "*" : "");
1026 
1027 		break;
1028 	case IMSG_CTL_END:
1029 		return (1);
1030 	default:
1031 		break;
1032 	}
1033 
1034 	return (0);
1035 }
1036 
1037 void
1038 show_nexthop_head(void)
1039 {
1040 	printf("Flags: * = nexthop valid\n");
1041 	printf("\n  %-15s %-19s%-4s %-15s %-20s\n", "Nexthop", "Route",
1042 	     "Prio", "Gateway", "Iface");
1043 }
1044 
1045 int
1046 show_nexthop_msg(struct imsg *imsg)
1047 {
1048 	struct ctl_show_nexthop	*p;
1049 	struct kroute		*k;
1050 	struct kroute6		*k6;
1051 	char			*s;
1052 
1053 	switch (imsg->hdr.type) {
1054 	case IMSG_CTL_SHOW_NEXTHOP:
1055 		p = imsg->data;
1056 		printf("%s %-15s ", p->valid ? "*" : " ", log_addr(&p->addr));
1057 		if (!p->krvalid) {
1058 			printf("\n");
1059 			return (0);
1060 		}
1061 		switch (p->addr.aid) {
1062 		case AID_INET:
1063 			k = &p->kr.kr4;
1064 			if (asprintf(&s, "%s/%u", inet_ntoa(k->prefix),
1065 			    k->prefixlen) == -1)
1066 				err(1, NULL);
1067 			printf("%-20s", s);
1068 			free(s);
1069 			printf("%3i %-15s ", k->priority,
1070 			    k->flags & F_CONNECTED ? "connected" :
1071 			    inet_ntoa(k->nexthop));
1072 			break;
1073 		case AID_INET6:
1074 			k6 = &p->kr.kr6;
1075 			if (asprintf(&s, "%s/%u", log_in6addr(&k6->prefix),
1076 			    k6->prefixlen) == -1)
1077 				err(1, NULL);
1078 			printf("%-20s", s);
1079 			free(s);
1080 			printf("%3i %-15s ", k6->priority,
1081 			    k6->flags & F_CONNECTED ? "connected" :
1082 			    log_in6addr(&k6->nexthop));
1083 			break;
1084 		default:
1085 			printf("unknown address family\n");
1086 			return (0);
1087 		}
1088 		if (p->kif.ifname[0]) {
1089 			char *s1;
1090 			if (p->kif.baudrate) {
1091 				if (asprintf(&s1, ", %s",
1092 				    get_baudrate(p->kif.baudrate,
1093 				    "bps")) == -1)
1094 					err(1, NULL);
1095 			} else if (asprintf(&s1, ", %s", get_linkstate(
1096 			    p->kif.if_type, p->kif.link_state)) == -1)
1097 					err(1, NULL);
1098 			if (asprintf(&s, "%s (%s%s)", p->kif.ifname,
1099 			    p->kif.flags & IFF_UP ? "UP" : "DOWN", s1) == -1)
1100 				err(1, NULL);
1101 			printf("%-15s", s);
1102 			free(s1);
1103 			free(s);
1104 		}
1105 		printf("\n");
1106 		break;
1107 	case IMSG_CTL_END:
1108 		return (1);
1109 		break;
1110 	default:
1111 		break;
1112 	}
1113 
1114 	return (0);
1115 }
1116 
1117 
1118 void
1119 show_interface_head(void)
1120 {
1121 	printf("%-15s%-9s%-9s%-7s%s\n", "Interface", "rdomain", "Nexthop", "Flags",
1122 	    "Link state");
1123 }
1124 
1125 int
1126 show_interface_msg(struct imsg *imsg)
1127 {
1128 	struct kif	*k;
1129 	uint64_t	 ifms_type;
1130 
1131 	switch (imsg->hdr.type) {
1132 	case IMSG_CTL_SHOW_INTERFACE:
1133 		k = imsg->data;
1134 		printf("%-15s", k->ifname);
1135 		printf("%-9u", k->rdomain);
1136 		printf("%-9s", k->nh_reachable ? "ok" : "invalid");
1137 		printf("%-7s", k->flags & IFF_UP ? "UP" : "");
1138 
1139 		if ((ifms_type = ift2ifm(k->if_type)) != 0)
1140 			printf("%s, ", get_media_descr(ifms_type));
1141 
1142 		printf("%s", get_linkstate(k->if_type, k->link_state));
1143 
1144 		if (k->link_state != LINK_STATE_DOWN && k->baudrate > 0)
1145 			printf(", %s", get_baudrate(k->baudrate, "Bit/s"));
1146 		printf("\n");
1147 		break;
1148 	case IMSG_CTL_END:
1149 		return (1);
1150 		break;
1151 	default:
1152 		break;
1153 	}
1154 
1155 	return (0);
1156 }
1157 
1158 void
1159 show_rib_summary_head(void)
1160 {
1161 	printf("flags: * = Valid, > = Selected, I = via IBGP, A = Announced,\n"
1162 	    "       S = Stale, E = Error\n");
1163 	printf("origin validation state: N = not-found, V = valid, ! = invalid\n");
1164 	printf("origin: i = IGP, e = EGP, ? = Incomplete\n\n");
1165 	printf("%-5s %3s %-20s %-15s  %5s %5s %s\n", "flags", "ovs", "destination",
1166 	    "gateway", "lpref", "med", "aspath origin");
1167 }
1168 
1169 void
1170 print_prefix(struct bgpd_addr *prefix, u_int8_t prefixlen, u_int8_t flags,
1171     u_int8_t ovs)
1172 {
1173 	char			*p;
1174 
1175 	print_flags(flags, 1);
1176 	printf("%3s ", print_ovs(ovs, 1));
1177 	if (asprintf(&p, "%s/%u", log_addr(prefix), prefixlen) == -1)
1178 		err(1, NULL);
1179 	printf("%-20s", p);
1180 	free(p);
1181 }
1182 
1183 const char *
1184 print_origin(u_int8_t origin, int sum)
1185 {
1186 	switch (origin) {
1187 	case ORIGIN_IGP:
1188 		return (sum ? "i" : "IGP");
1189 	case ORIGIN_EGP:
1190 		return (sum ? "e" : "EGP");
1191 	case ORIGIN_INCOMPLETE:
1192 		return (sum ? "?" : "incomplete");
1193 	default:
1194 		return (sum ? "X" : "bad origin");
1195 	}
1196 }
1197 
1198 void
1199 print_flags(u_int8_t flags, int sum)
1200 {
1201 	char	 flagstr[5];
1202 	char	*p = flagstr;
1203 
1204 	if (sum) {
1205 		if (flags & F_PREF_INVALID)
1206 			*p++ = 'E';
1207 		if (flags & F_PREF_ANNOUNCE)
1208 			*p++ = 'A';
1209 		if (flags & F_PREF_INTERNAL)
1210 			*p++ = 'I';
1211 		if (flags & F_PREF_STALE)
1212 			*p++ = 'S';
1213 		if (flags & F_PREF_ELIGIBLE)
1214 			*p++ = '*';
1215 		if (flags & F_PREF_ACTIVE)
1216 			*p++ = '>';
1217 		*p = '\0';
1218 		printf("%-5s ", flagstr);
1219 	} else {
1220 		if (flags & F_PREF_INTERNAL)
1221 			printf("internal");
1222 		else
1223 			printf("external");
1224 		if (flags & F_PREF_STALE)
1225 			printf(", stale");
1226 		if (flags & F_PREF_ELIGIBLE)
1227 			printf(", valid");
1228 		if (flags & F_PREF_ACTIVE)
1229 			printf(", best");
1230 		if (flags & F_PREF_ANNOUNCE)
1231 			printf(", announced");
1232 	}
1233 }
1234 
1235 const char *
1236 print_ovs(u_int8_t validation_state, int sum)
1237 {
1238 	switch (validation_state) {
1239 	case ROA_INVALID:
1240 		return (sum ? "!" : "invalid");
1241 	case ROA_VALID:
1242 		return (sum ? "V" : "valid");
1243 	default:
1244 		return (sum ? "N" : "not-found");
1245 	}
1246 }
1247 
1248 int
1249 show_rib_summary_msg(struct imsg *imsg)
1250 {
1251 	struct ctl_show_rib	 rib;
1252 	u_char			*asdata;
1253 
1254 	switch (imsg->hdr.type) {
1255 	case IMSG_CTL_SHOW_RIB:
1256 		memcpy(&rib, imsg->data, sizeof(rib));
1257 		asdata = imsg->data;
1258 		asdata += sizeof(struct ctl_show_rib);
1259 		show_rib_brief(&rib, asdata);
1260 		break;
1261 	case IMSG_CTL_END:
1262 		return (1);
1263 	default:
1264 		break;
1265 	}
1266 
1267 	return (0);
1268 }
1269 
1270 int
1271 show_rib_detail_msg(struct imsg *imsg, int nodescr, int flag0)
1272 {
1273 	struct ctl_show_rib	 rib;
1274 	u_char			*asdata;
1275 	u_int16_t		 ilen;
1276 
1277 	switch (imsg->hdr.type) {
1278 	case IMSG_CTL_SHOW_RIB:
1279 		memcpy(&rib, imsg->data, sizeof(rib));
1280 		asdata = imsg->data;
1281 		asdata += sizeof(struct ctl_show_rib);
1282 		show_rib_detail(&rib, asdata, nodescr, flag0);
1283 		break;
1284 	case IMSG_CTL_SHOW_RIB_ATTR:
1285 		ilen = imsg->hdr.len - IMSG_HEADER_SIZE;
1286 		if (ilen < 3)
1287 			errx(1, "bad IMSG_CTL_SHOW_RIB_ATTR received");
1288 		show_attr(imsg->data, ilen, flag0);
1289 		break;
1290 	case IMSG_CTL_END:
1291 		printf("\n");
1292 		return (1);
1293 	default:
1294 		break;
1295 	}
1296 
1297 	return (0);
1298 }
1299 
1300 void
1301 show_rib_brief(struct ctl_show_rib *r, u_char *asdata)
1302 {
1303 	char			*aspath;
1304 
1305 	print_prefix(&r->prefix, r->prefixlen, r->flags, r->validation_state);
1306 	printf(" %-15s ", log_addr(&r->exit_nexthop));
1307 	printf(" %5u %5u ", r->local_pref, r->med);
1308 
1309 	if (aspath_asprint(&aspath, asdata, r->aspath_len) == -1)
1310 		err(1, NULL);
1311 	if (strlen(aspath) > 0)
1312 		printf("%s ", aspath);
1313 	free(aspath);
1314 
1315 	printf("%s\n", print_origin(r->origin, 1));
1316 }
1317 
1318 void
1319 show_rib_detail(struct ctl_show_rib *r, u_char *asdata, int nodescr, int flag0)
1320 {
1321 	struct in_addr		 id;
1322 	char			*aspath, *s;
1323 	time_t			 now;
1324 
1325 	printf("\nBGP routing table entry for %s/%u%c",
1326 	    log_addr(&r->prefix), r->prefixlen,
1327 	    EOL0(flag0));
1328 
1329 	if (aspath_asprint(&aspath, asdata, r->aspath_len) == -1)
1330 		err(1, NULL);
1331 	if (strlen(aspath) > 0)
1332 		printf("    %s%c", aspath, EOL0(flag0));
1333 	free(aspath);
1334 
1335 	s = fmt_peer(r->descr, &r->remote_addr, -1, nodescr);
1336 	printf("    Nexthop %s ", log_addr(&r->exit_nexthop));
1337 	printf("(via %s) from %s (", log_addr(&r->true_nexthop), s);
1338 	free(s);
1339 	id.s_addr = htonl(r->remote_id);
1340 	printf("%s)%c", inet_ntoa(id), EOL0(flag0));
1341 
1342 	printf("    Origin %s, metric %u, localpref %u, weight %u, ovs %s, ",
1343 	    print_origin(r->origin, 0), r->med, r->local_pref, r->weight,
1344 	    print_ovs(r->validation_state, 0));
1345 	print_flags(r->flags, 0);
1346 
1347 	now = time(NULL);
1348 	if (now > r->lastchange)
1349 		now -= r->lastchange;
1350 	else
1351 		now = 0;
1352 
1353 	printf("%c    Last update: %s ago%c", EOL0(flag0),
1354 	    fmt_timeframe_core(now), EOL0(flag0));
1355 }
1356 
1357 static const char *
1358 print_attr(u_int8_t type, u_int8_t flags)
1359 {
1360 #define CHECK_FLAGS(s, t, m)	\
1361 	if (((s) & ~(ATTR_DEFMASK | (m))) != (t)) pflags = 1
1362 
1363 	static char cstr[48];
1364 	int pflags = 0;
1365 
1366 	switch (type) {
1367 	case ATTR_ORIGIN:
1368 		CHECK_FLAGS(flags, ATTR_WELL_KNOWN, 0);
1369 		strlcpy(cstr, "Origin", sizeof(cstr));
1370 		break;
1371 	case ATTR_ASPATH:
1372 		CHECK_FLAGS(flags, ATTR_WELL_KNOWN, 0);
1373 		strlcpy(cstr, "AS-Path", sizeof(cstr));
1374 		break;
1375 	case ATTR_AS4_PATH:
1376 		CHECK_FLAGS(flags, ATTR_WELL_KNOWN, 0);
1377 		strlcpy(cstr, "AS4-Path", sizeof(cstr));
1378 		break;
1379 	case ATTR_NEXTHOP:
1380 		CHECK_FLAGS(flags, ATTR_WELL_KNOWN, 0);
1381 		strlcpy(cstr, "Nexthop", sizeof(cstr));
1382 		break;
1383 	case ATTR_MED:
1384 		CHECK_FLAGS(flags, ATTR_OPTIONAL, 0);
1385 		strlcpy(cstr, "Med", sizeof(cstr));
1386 		break;
1387 	case ATTR_LOCALPREF:
1388 		CHECK_FLAGS(flags, ATTR_WELL_KNOWN, 0);
1389 		strlcpy(cstr, "Localpref", sizeof(cstr));
1390 		break;
1391 	case ATTR_ATOMIC_AGGREGATE:
1392 		CHECK_FLAGS(flags, ATTR_WELL_KNOWN, 0);
1393 		strlcpy(cstr, "Atomic Aggregate", sizeof(cstr));
1394 		break;
1395 	case ATTR_AGGREGATOR:
1396 		CHECK_FLAGS(flags, ATTR_OPTIONAL|ATTR_TRANSITIVE, ATTR_PARTIAL);
1397 		strlcpy(cstr, "Aggregator", sizeof(cstr));
1398 		break;
1399 	case ATTR_AS4_AGGREGATOR:
1400 		CHECK_FLAGS(flags, ATTR_OPTIONAL|ATTR_TRANSITIVE, ATTR_PARTIAL);
1401 		strlcpy(cstr, "AS4-Aggregator", sizeof(cstr));
1402 		break;
1403 	case ATTR_COMMUNITIES:
1404 		CHECK_FLAGS(flags, ATTR_OPTIONAL|ATTR_TRANSITIVE, ATTR_PARTIAL);
1405 		strlcpy(cstr, "Communities", sizeof(cstr));
1406 		break;
1407 	case ATTR_ORIGINATOR_ID:
1408 		CHECK_FLAGS(flags, ATTR_OPTIONAL, 0);
1409 		strlcpy(cstr, "Originator Id", sizeof(cstr));
1410 		break;
1411 	case ATTR_CLUSTER_LIST:
1412 		CHECK_FLAGS(flags, ATTR_OPTIONAL, 0);
1413 		strlcpy(cstr, "Cluster Id List", sizeof(cstr));
1414 		break;
1415 	case ATTR_MP_REACH_NLRI:
1416 		CHECK_FLAGS(flags, ATTR_OPTIONAL, 0);
1417 		strlcpy(cstr, "MP Reach NLRI", sizeof(cstr));
1418 		break;
1419 	case ATTR_MP_UNREACH_NLRI:
1420 		CHECK_FLAGS(flags, ATTR_OPTIONAL, 0);
1421 		strlcpy(cstr, "MP Unreach NLRI", sizeof(cstr));
1422 		break;
1423 	case ATTR_EXT_COMMUNITIES:
1424 		CHECK_FLAGS(flags, ATTR_OPTIONAL|ATTR_TRANSITIVE, ATTR_PARTIAL);
1425 		strlcpy(cstr, "Ext. Communities", sizeof(cstr));
1426 		break;
1427 	case ATTR_LARGE_COMMUNITIES:
1428 		CHECK_FLAGS(flags, ATTR_OPTIONAL|ATTR_TRANSITIVE, ATTR_PARTIAL);
1429 		strlcpy(cstr, "Large Communities", sizeof(cstr));
1430 		break;
1431 	default:
1432 		/* ignore unknown attributes */
1433 		snprintf(cstr, sizeof(cstr), "Unknown Attribute #%u", type);
1434 		pflags = 1;
1435 		break;
1436 	}
1437 	if (pflags) {
1438 		strlcat(cstr, " flags [", sizeof(cstr));
1439 		if (flags & ATTR_OPTIONAL)
1440 			strlcat(cstr, "O", sizeof(cstr));
1441 		if (flags & ATTR_TRANSITIVE)
1442 			strlcat(cstr, "T", sizeof(cstr));
1443 		if (flags & ATTR_PARTIAL)
1444 			strlcat(cstr, "P", sizeof(cstr));
1445 		strlcat(cstr, "]", sizeof(cstr));
1446 	}
1447 	return (cstr);
1448 
1449 #undef CHECK_FLAGS
1450 }
1451 
1452 void
1453 show_attr(void *b, u_int16_t len, int flag0)
1454 {
1455 	u_char		*data = b, *path;
1456 	struct in_addr	 id;
1457 	struct bgpd_addr prefix;
1458 	char		*aspath;
1459 	u_int32_t	 as;
1460 	u_int16_t	 alen, ioff, short_as, afi;
1461 	u_int8_t	 flags, type, safi, aid, prefixlen;
1462 	int		 i, pos, e2, e4;
1463 
1464 	if (len < 3)
1465 		errx(1, "show_attr: too short bgp attr");
1466 
1467 	flags = data[0];
1468 	type = data[1];
1469 
1470 	/* get the attribute length */
1471 	if (flags & ATTR_EXTLEN) {
1472 		if (len < 4)
1473 			errx(1, "show_attr: too short bgp attr");
1474 		memcpy(&alen, data+2, sizeof(u_int16_t));
1475 		alen = ntohs(alen);
1476 		data += 4;
1477 		len -= 4;
1478 	} else {
1479 		alen = (u_char)data[2];
1480 		data += 3;
1481 		len -= 3;
1482 	}
1483 
1484 	/* bad imsg len how can that happen!? */
1485 	if (alen > len)
1486 		errx(1, "show_attr: bad length");
1487 
1488 	printf("    %s: ", print_attr(type, flags));
1489 
1490 	switch (type) {
1491 	case ATTR_ORIGIN:
1492 		if (alen == 1)
1493 			printf("%u", *data);
1494 		else
1495 			printf("bad length");
1496 		break;
1497 	case ATTR_ASPATH:
1498 	case ATTR_AS4_PATH:
1499 		/* prefer 4-byte AS here */
1500 		e4 = aspath_verify(data, alen, 1);
1501 		e2 = aspath_verify(data, alen, 0);
1502 		if (e4 == 0 || e4 == AS_ERR_SOFT) {
1503 			path = data;
1504 		} else if (e2 == 0 || e2 == AS_ERR_SOFT) {
1505 			path = aspath_inflate(data, alen, &alen);
1506 			if (path == NULL)
1507 				errx(1, "aspath_inflate failed");
1508 		} else {
1509 			printf("bad AS-Path");
1510 			break;
1511 		}
1512 		if (aspath_asprint(&aspath, path, alen) == -1)
1513 			err(1, NULL);
1514 		printf("%s", aspath);
1515 		free(aspath);
1516 		if (path != data)
1517 			free(path);
1518 		break;
1519 	case ATTR_NEXTHOP:
1520 		if (alen == 4) {
1521 			memcpy(&id, data, sizeof(id));
1522 			printf("%s", inet_ntoa(id));
1523 		} else
1524 			printf("bad length");
1525 		break;
1526 	case ATTR_MED:
1527 	case ATTR_LOCALPREF:
1528 		if (alen == 4) {
1529 			u_int32_t val;
1530 			memcpy(&val, data, sizeof(val));
1531 			val = ntohl(val);
1532 			printf("%u", val);
1533 		} else
1534 			printf("bad length");
1535 		break;
1536 	case ATTR_AGGREGATOR:
1537 	case ATTR_AS4_AGGREGATOR:
1538 		if (alen == 8) {
1539 			memcpy(&as, data, sizeof(as));
1540 			memcpy(&id, data + sizeof(as), sizeof(id));
1541 			as = ntohl(as);
1542 		} else if (alen == 6) {
1543 			memcpy(&short_as, data, sizeof(short_as));
1544 			memcpy(&id, data + sizeof(short_as), sizeof(id));
1545 			as = ntohs(short_as);
1546 		} else {
1547 			printf("bad length");
1548 			break;
1549 		}
1550 		printf("%s [%s]", log_as(as), inet_ntoa(id));
1551 		break;
1552 	case ATTR_COMMUNITIES:
1553 		show_community(data, alen);
1554 		break;
1555 	case ATTR_ORIGINATOR_ID:
1556 		memcpy(&id, data, sizeof(id));
1557 		printf("%s", inet_ntoa(id));
1558 		break;
1559 	case ATTR_CLUSTER_LIST:
1560 		for (ioff = 0; ioff + sizeof(id) <= alen;
1561 		    ioff += sizeof(id)) {
1562 			memcpy(&id, data + ioff, sizeof(id));
1563 			printf(" %s", inet_ntoa(id));
1564 		}
1565 		break;
1566 	case ATTR_MP_REACH_NLRI:
1567 	case ATTR_MP_UNREACH_NLRI:
1568 		if (alen < 3) {
1569  bad_len:
1570 			printf("bad length");
1571 			break;
1572 		}
1573 		memcpy(&afi, data, 2);
1574 		data += 2;
1575 		alen -= 2;
1576 		afi = ntohs(afi);
1577 		safi = *data++;
1578 		alen--;
1579 
1580 		if (afi2aid(afi, safi, &aid) == -1) {
1581 			printf("bad AFI/SAFI pair");
1582 			break;
1583 		}
1584 		printf(" %s", aid2str(aid));
1585 
1586 		if (type == ATTR_MP_REACH_NLRI) {
1587 			struct bgpd_addr nexthop;
1588 			u_int8_t nhlen;
1589 			if (len == 0)
1590 				goto bad_len;
1591 			nhlen = *data++;
1592 			alen--;
1593 			if (nhlen > len)
1594 				goto bad_len;
1595 			bzero(&nexthop, sizeof(nexthop));
1596 			switch (aid) {
1597 			case AID_INET6:
1598 				nexthop.aid = aid;
1599 				if (nhlen != 16 && nhlen != 32)
1600 					goto bad_len;
1601 				memcpy(&nexthop.v6.s6_addr, data, 16);
1602 				break;
1603 			case AID_VPN_IPv4:
1604 				if (nhlen != 12)
1605 					goto bad_len;
1606 				nexthop.aid = AID_INET;
1607 				memcpy(&nexthop.v4, data + sizeof(u_int64_t),
1608 				    sizeof(nexthop.v4));
1609 			default:
1610 				printf("unhandled AID #%u", aid);
1611 				goto done;
1612 			}
1613 			/* ignore reserved (old SNPA) field as per RFC4760 */
1614 			data += nhlen + 1;
1615 			alen -= nhlen + 1;
1616 
1617 			printf(" nexthop: %s", log_addr(&nexthop));
1618 		}
1619 
1620 		while (alen > 0) {
1621 			switch (aid) {
1622 			case AID_INET6:
1623 				pos = nlri_get_prefix6(data, alen, &prefix,
1624 				    &prefixlen);
1625 				break;
1626 			case AID_VPN_IPv4:
1627 				pos = nlri_get_vpn4(data, alen, &prefix,
1628 				    &prefixlen, 1);
1629 				break;
1630 			default:
1631 				printf("unhandled AID #%u", aid);
1632 				goto done;
1633 			}
1634 			if (pos == -1) {
1635 				printf("bad %s prefix", aid2str(aid));
1636 				break;
1637 			}
1638 			printf(" %s/%u", log_addr(&prefix), prefixlen);
1639 			data += pos;
1640 			alen -= pos;
1641 		}
1642 		break;
1643 	case ATTR_EXT_COMMUNITIES:
1644 		show_ext_community(data, alen);
1645 		break;
1646 	case ATTR_LARGE_COMMUNITIES:
1647 		show_large_community(data, alen);
1648 		break;
1649 	case ATTR_ATOMIC_AGGREGATE:
1650 	default:
1651 		printf(" len %u", alen);
1652 		if (alen) {
1653 			printf(":");
1654 			for (i=0; i < alen; i++)
1655 				printf(" %02x", *(data+i));
1656 		}
1657 		break;
1658 	}
1659  done:
1660 	printf("%c", EOL0(flag0));
1661 }
1662 
1663 void
1664 show_community(u_char *data, u_int16_t len)
1665 {
1666 	u_int16_t	a, v;
1667 	u_int16_t	i;
1668 
1669 	if (len & 0x3)
1670 		return;
1671 
1672 	for (i = 0; i < len; i += 4) {
1673 		memcpy(&a, data + i, sizeof(a));
1674 		memcpy(&v, data + i + 2, sizeof(v));
1675 		a = ntohs(a);
1676 		v = ntohs(v);
1677 		if (a == COMMUNITY_WELLKNOWN)
1678 			switch (v) {
1679 			case COMMUNITY_GRACEFUL_SHUTDOWN:
1680 				printf("GRACEFUL_SHUTDOWN");
1681 				break;
1682 			case COMMUNITY_NO_EXPORT:
1683 				printf("NO_EXPORT");
1684 				break;
1685 			case COMMUNITY_NO_ADVERTISE:
1686 				printf("NO_ADVERTISE");
1687 				break;
1688 			case COMMUNITY_NO_EXPSUBCONFED:
1689 				printf("NO_EXPORT_SUBCONFED");
1690 				break;
1691 			case COMMUNITY_NO_PEER:
1692 				printf("NO_PEER");
1693 				break;
1694 			case COMMUNITY_BLACKHOLE:
1695 				printf("BLACKHOLE");
1696 				break;
1697 			default:
1698 				printf("%hu:%hu", a, v);
1699 				break;
1700 			}
1701 		else
1702 			printf("%hu:%hu", a, v);
1703 
1704 		if (i + 4 < len)
1705 			printf(" ");
1706 	}
1707 }
1708 
1709 void
1710 show_large_community(u_char *data, u_int16_t len)
1711 {
1712 	u_int32_t	a, l1, l2;
1713 	u_int16_t	i;
1714 
1715 	if (len % 12)
1716 		return;
1717 
1718 	for (i = 0; i < len; i += 12) {
1719 		memcpy(&a, data + i, sizeof(a));
1720 		memcpy(&l1, data + i + 4, sizeof(l1));
1721 		memcpy(&l2, data + i + 8, sizeof(l2));
1722 		a = ntohl(a);
1723 		l1 = ntohl(l1);
1724 		l2 = ntohl(l2);
1725 		printf("%u:%u:%u", a, l1, l2);
1726 
1727 		if (i + 12 < len)
1728 			printf(" ");
1729 	}
1730 }
1731 
1732 void
1733 show_ext_community(u_char *data, u_int16_t len)
1734 {
1735 	u_int64_t	ext;
1736 	struct in_addr	ip;
1737 	u_int32_t	as4, u32;
1738 	u_int16_t	i, as2, u16;
1739 	u_int8_t	type, subtype;
1740 
1741 	if (len & 0x7)
1742 		return;
1743 
1744 	for (i = 0; i < len; i += 8) {
1745 		type = data[i];
1746 		subtype = data[i + 1];
1747 
1748 		printf("%s ", log_ext_subtype(type, subtype));
1749 
1750 		switch (type) {
1751 		case EXT_COMMUNITY_TRANS_TWO_AS:
1752 			memcpy(&as2, data + i + 2, sizeof(as2));
1753 			memcpy(&u32, data + i + 4, sizeof(u32));
1754 			printf("%s:%u", log_as(ntohs(as2)), ntohl(u32));
1755 			break;
1756 		case EXT_COMMUNITY_TRANS_IPV4:
1757 			memcpy(&ip, data + i + 2, sizeof(ip));
1758 			memcpy(&u16, data + i + 6, sizeof(u16));
1759 			printf("%s:%hu", inet_ntoa(ip), ntohs(u16));
1760 			break;
1761 		case EXT_COMMUNITY_TRANS_FOUR_AS:
1762 			memcpy(&as4, data + i + 2, sizeof(as4));
1763 			memcpy(&u16, data + i + 6, sizeof(u16));
1764 			printf("%s:%hu", log_as(ntohl(as4)), ntohs(u16));
1765 			break;
1766 		case EXT_COMMUNITY_TRANS_OPAQUE:
1767 		case EXT_COMMUNITY_TRANS_EVPN:
1768 			memcpy(&ext, data + i, sizeof(ext));
1769 			ext = betoh64(ext) & 0xffffffffffffLL;
1770 			printf("0x%llx", ext);
1771 			break;
1772 		case EXT_COMMUNITY_NON_TRANS_OPAQUE:
1773 			memcpy(&ext, data + i, sizeof(ext));
1774 			ext = betoh64(ext) & 0xffffffffffffLL;
1775 			switch (ext) {
1776 			case EXT_COMMUNITY_OVS_VALID:
1777 				printf("valid ");
1778 				break;
1779 			case EXT_COMMUNITY_OVS_NOTFOUND:
1780 				printf("not-found ");
1781 				break;
1782 			case EXT_COMMUNITY_OVS_INVALID:
1783 				printf("invalid ");
1784 				break;
1785 			default:
1786 				printf("0x%llx ", ext);
1787 				break;
1788 			}
1789 			break;
1790 		default:
1791 			memcpy(&ext, data + i, sizeof(ext));
1792 			printf("0x%llx", betoh64(ext));
1793 		}
1794 		if (i + 8 < len)
1795 			printf(", ");
1796 	}
1797 }
1798 
1799 char *
1800 fmt_mem(int64_t num)
1801 {
1802 	static char	buf[16];
1803 
1804 	if (fmt_scaled(num, buf) == -1)
1805 		snprintf(buf, sizeof(buf), "%lldB", (long long)num);
1806 
1807 	return (buf);
1808 }
1809 
1810 size_t  pt_sizes[AID_MAX] = AID_PTSIZE;
1811 
1812 int
1813 show_rib_memory_msg(struct imsg *imsg)
1814 {
1815 	struct rde_memstats	stats;
1816 	struct rde_hashstats	hash;
1817 	size_t			pts = 0;
1818 	int			i;
1819 	double			avg, dev;
1820 
1821 	switch (imsg->hdr.type) {
1822 	case IMSG_CTL_SHOW_RIB_MEM:
1823 		memcpy(&stats, imsg->data, sizeof(stats));
1824 		printf("RDE memory statistics\n");
1825 		for (i = 0; i < AID_MAX; i++) {
1826 			if (stats.pt_cnt[i] == 0)
1827 				continue;
1828 			pts += stats.pt_cnt[i] * pt_sizes[i];
1829 			printf("%10lld %s network entries using %s of memory\n",
1830 			    (long long)stats.pt_cnt[i], aid_vals[i].name,
1831 			    fmt_mem(stats.pt_cnt[i] * pt_sizes[i]));
1832 		}
1833 		printf("%10lld rib entries using %s of memory\n",
1834 		    (long long)stats.rib_cnt, fmt_mem(stats.rib_cnt *
1835 		    sizeof(struct rib_entry)));
1836 		printf("%10lld prefix entries using %s of memory\n",
1837 		    (long long)stats.prefix_cnt, fmt_mem(stats.prefix_cnt *
1838 		    sizeof(struct prefix)));
1839 		printf("%10lld BGP path attribute entries using %s of memory\n",
1840 		    (long long)stats.path_cnt, fmt_mem(stats.path_cnt *
1841 		    sizeof(struct rde_aspath)));
1842 		printf("\t   and holding %lld references\n",
1843 		    (long long)stats.path_refs);
1844 		printf("%10lld BGP AS-PATH attribute entries using "
1845 		    "%s of memory\n\t   and holding %lld references\n",
1846 		    (long long)stats.aspath_cnt, fmt_mem(stats.aspath_size),
1847 		    (long long)stats.aspath_refs);
1848 		printf("%10lld BGP attributes entries using %s of memory\n",
1849 		    (long long)stats.attr_cnt, fmt_mem(stats.attr_cnt *
1850 		    sizeof(struct attr)));
1851 		printf("\t   and holding %lld references\n",
1852 		    (long long)stats.attr_refs);
1853 		printf("%10lld BGP attributes using %s of memory\n",
1854 		    (long long)stats.attr_dcnt, fmt_mem(stats.attr_data));
1855 		printf("%10lld as-set elements in %lld tables using "
1856 		    "%s of memory\n", stats.aset_nmemb, stats.aset_cnt,
1857 		    fmt_mem(stats.aset_size));
1858 		printf("%10lld prefix-set elements using %s of memory\n",
1859 		    stats.pset_cnt, fmt_mem(stats.pset_size));
1860 		printf("RIB using %s of memory\n", fmt_mem(pts +
1861 		    stats.prefix_cnt * sizeof(struct prefix) +
1862 		    stats.rib_cnt * sizeof(struct rib_entry) +
1863 		    stats.path_cnt * sizeof(struct rde_aspath) +
1864 		    stats.aspath_size + stats.attr_cnt * sizeof(struct attr) +
1865 		    stats.attr_data));
1866 		printf("Sets using %s of memory\n", fmt_mem(stats.aset_size +
1867 		    stats.pset_size));
1868 		printf("\nRDE hash statistics\n");
1869 		break;
1870 	case IMSG_CTL_SHOW_RIB_HASH:
1871 		memcpy(&hash, imsg->data, sizeof(hash));
1872 		printf("\t%s: size %lld, %lld entries\n", hash.name, hash.num,
1873 		    hash.sum);
1874 		avg = (double)hash.sum / (double)hash.num;
1875 		dev = sqrt(fmax(0, hash.sumq / hash.num - avg * avg));
1876 		printf("\t    min %lld max %lld avg/std-dev = %.3f/%.3f\n",
1877 		    hash.min, hash.max, avg, dev);
1878 		break;
1879 	case IMSG_CTL_END:
1880 		return (1);
1881 	default:
1882 		break;
1883 	}
1884 
1885 	return (0);
1886 }
1887 
1888 void
1889 send_filterset(struct imsgbuf *i, struct filter_set_head *set)
1890 {
1891 	struct filter_set	*s;
1892 
1893 	while ((s = TAILQ_FIRST(set)) != NULL) {
1894 		imsg_compose(i, IMSG_FILTER_SET, 0, 0, -1, s,
1895 		    sizeof(struct filter_set));
1896 		TAILQ_REMOVE(set, s, entry);
1897 		free(s);
1898 	}
1899 }
1900 
1901 const char *
1902 get_errstr(u_int8_t errcode, u_int8_t subcode)
1903 {
1904 	static const char	*errstr = NULL;
1905 
1906 	if (errcode && errcode < sizeof(errnames)/sizeof(char *))
1907 		errstr = errnames[errcode];
1908 
1909 	switch (errcode) {
1910 	case ERR_HEADER:
1911 		if (subcode &&
1912 		    subcode < sizeof(suberr_header_names)/sizeof(char *))
1913 			errstr = suberr_header_names[subcode];
1914 		break;
1915 	case ERR_OPEN:
1916 		if (subcode &&
1917 		    subcode < sizeof(suberr_open_names)/sizeof(char *))
1918 			errstr = suberr_open_names[subcode];
1919 		break;
1920 	case ERR_UPDATE:
1921 		if (subcode &&
1922 		    subcode < sizeof(suberr_update_names)/sizeof(char *))
1923 			errstr = suberr_update_names[subcode];
1924 		break;
1925 	case ERR_HOLDTIMEREXPIRED:
1926 	case ERR_FSM:
1927 	case ERR_CEASE:
1928 		break;
1929 	default:
1930 		return ("unknown error code");
1931 	}
1932 
1933 	return (errstr);
1934 }
1935 
1936 int
1937 show_result(struct imsg *imsg)
1938 {
1939 	u_int	rescode;
1940 
1941 	if (imsg->hdr.len != IMSG_HEADER_SIZE + sizeof(rescode))
1942 		errx(1, "got IMSG_CTL_RESULT with wrong len");
1943 	memcpy(&rescode, imsg->data, sizeof(rescode));
1944 
1945 	if (rescode == 0)
1946 		printf("request processed\n");
1947 	else {
1948 		if (rescode >
1949 		    sizeof(ctl_res_strerror)/sizeof(ctl_res_strerror[0]))
1950 			printf("unknown result error code %u\n", rescode);
1951 		else
1952 			printf("%s\n", ctl_res_strerror[rescode]);
1953 	}
1954 
1955 	return (1);
1956 }
1957 
1958 void
1959 network_bulk(struct parse_result *res)
1960 {
1961 	struct network_config net;
1962 	struct filter_set *s = NULL;
1963 	struct bgpd_addr h;
1964 	char *line = NULL;
1965 	size_t linesize = 0;
1966 	ssize_t linelen;
1967 	u_int8_t len;
1968 	FILE *f;
1969 
1970 	if ((f = fdopen(STDIN_FILENO, "r")) == NULL)
1971 		err(1, "Failed to open stdin\n");
1972 
1973 	while ((linelen = getline(&line, &linesize, f)) != -1) {
1974 		char *b, *buf = line;
1975 		while ((b = strsep(&buf, " \t\n")) != NULL) {
1976 			if (*b == '\0')	/* skip empty tokens */
1977 				continue;
1978 			/* Stop processing after a comment */
1979 			if (*b == '#')
1980 				break;
1981 			bzero(&net, sizeof(net));
1982 			if (parse_prefix(b, strlen(b), &h, &len) != 1)
1983 				errx(1, "bad prefix: %s", b);
1984 			net.prefix = h;
1985 			net.prefixlen = len;
1986 			net.rtableid = tableid;
1987 
1988 			if (res->action == NETWORK_BULK_ADD) {
1989 				imsg_compose(ibuf, IMSG_NETWORK_ADD,
1990 				    0, 0, -1, &net, sizeof(net));
1991 				TAILQ_FOREACH(s, &res->set, entry) {
1992 					imsg_compose(ibuf,
1993 					    IMSG_FILTER_SET,
1994 					    0, 0, -1, s, sizeof(*s));
1995 				}
1996 				imsg_compose(ibuf, IMSG_NETWORK_DONE,
1997 				    0, 0, -1, NULL, 0);
1998 			} else
1999 				imsg_compose(ibuf, IMSG_NETWORK_REMOVE,
2000 				     0, 0, -1, &net, sizeof(net));
2001 		}
2002 	}
2003 	free(line);
2004 	if (ferror(f))
2005 		err(1, "getline");
2006 	fclose(f);
2007 }
2008 
2009 void
2010 show_mrt_dump(struct mrt_rib *mr, struct mrt_peer *mp, void *arg)
2011 {
2012 	struct ctl_show_rib		 ctl;
2013 	struct ctl_show_rib_request	*req = arg;
2014 	struct mrt_rib_entry		*mre;
2015 	u_int16_t			 i, j;
2016 
2017 	for (i = 0; i < mr->nentries; i++) {
2018 		mre = &mr->entries[i];
2019 		bzero(&ctl, sizeof(ctl));
2020 		mrt_to_bgpd_addr(&mr->prefix, &ctl.prefix);
2021 		ctl.prefixlen = mr->prefixlen;
2022 		ctl.lastchange = mre->originated;
2023 		mrt_to_bgpd_addr(&mre->nexthop, &ctl.true_nexthop);
2024 		mrt_to_bgpd_addr(&mre->nexthop, &ctl.exit_nexthop);
2025 		ctl.origin = mre->origin;
2026 		ctl.local_pref = mre->local_pref;
2027 		ctl.med = mre->med;
2028 		/* weight is not part of the mrt dump so it can't be set */
2029 		ctl.aspath_len = mre->aspath_len;
2030 
2031 		if (mre->peer_idx < mp->npeers) {
2032 			mrt_to_bgpd_addr(&mp->peers[mre->peer_idx].addr,
2033 			    &ctl.remote_addr);
2034 			ctl.remote_id = mp->peers[mre->peer_idx].bgp_id;
2035 		}
2036 
2037 		/* filter by neighbor */
2038 		if (req->neighbor.addr.aid != AID_UNSPEC &&
2039 		    memcmp(&req->neighbor.addr, &ctl.remote_addr,
2040 		    sizeof(ctl.remote_addr)) != 0)
2041 			continue;
2042 		/* filter by AF */
2043 		if (req->aid && req->aid != ctl.prefix.aid)
2044 			return;
2045 		/* filter by prefix */
2046 		if (req->prefix.aid != AID_UNSPEC) {
2047 			if (!prefix_compare(&req->prefix, &ctl.prefix,
2048 			    req->prefixlen)) {
2049 				if (req->flags & F_LONGER) {
2050 					if (req->prefixlen > ctl.prefixlen)
2051 						return;
2052 				} else if (req->prefixlen != ctl.prefixlen)
2053 					return;
2054 			} else
2055 				return;
2056 		}
2057 		/* filter by AS */
2058 		if (req->as.type != AS_UNDEF &&
2059 		   !match_aspath(mre->aspath, mre->aspath_len, &req->as))
2060 			continue;
2061 
2062 		if (req->flags & F_CTL_DETAIL) {
2063 			show_rib_detail(&ctl, mre->aspath, 1, 0);
2064 			for (j = 0; j < mre->nattrs; j++)
2065 				show_attr(mre->attrs[j].attr,
2066 				    mre->attrs[j].attr_len,
2067 				    req->flags);
2068 		} else
2069 			show_rib_brief(&ctl, mre->aspath);
2070 	}
2071 }
2072 
2073 void
2074 network_mrt_dump(struct mrt_rib *mr, struct mrt_peer *mp, void *arg)
2075 {
2076 	struct ctl_show_rib		 ctl;
2077 	struct network_config		 net;
2078 	struct ctl_show_rib_request	*req = arg;
2079 	struct mrt_rib_entry		*mre;
2080 	struct ibuf			*msg;
2081 	u_int16_t			 i, j;
2082 
2083 	for (i = 0; i < mr->nentries; i++) {
2084 		mre = &mr->entries[i];
2085 		bzero(&ctl, sizeof(ctl));
2086 		mrt_to_bgpd_addr(&mr->prefix, &ctl.prefix);
2087 		ctl.prefixlen = mr->prefixlen;
2088 		ctl.lastchange = mre->originated;
2089 		mrt_to_bgpd_addr(&mre->nexthop, &ctl.true_nexthop);
2090 		mrt_to_bgpd_addr(&mre->nexthop, &ctl.exit_nexthop);
2091 		ctl.origin = mre->origin;
2092 		ctl.local_pref = mre->local_pref;
2093 		ctl.med = mre->med;
2094 		ctl.aspath_len = mre->aspath_len;
2095 
2096 		if (mre->peer_idx < mp->npeers) {
2097 			mrt_to_bgpd_addr(&mp->peers[mre->peer_idx].addr,
2098 			    &ctl.remote_addr);
2099 			ctl.remote_id = mp->peers[mre->peer_idx].bgp_id;
2100 		}
2101 
2102 		/* filter by neighbor */
2103 		if (req->neighbor.addr.aid != AID_UNSPEC &&
2104 		    memcmp(&req->neighbor.addr, &ctl.remote_addr,
2105 		    sizeof(ctl.remote_addr)) != 0)
2106 			continue;
2107 		/* filter by AF */
2108 		if (req->aid && req->aid != ctl.prefix.aid)
2109 			return;
2110 		/* filter by prefix */
2111 		if (req->prefix.aid != AID_UNSPEC) {
2112 			if (!prefix_compare(&req->prefix, &ctl.prefix,
2113 			    req->prefixlen)) {
2114 				if (req->flags & F_LONGER) {
2115 					if (req->prefixlen > ctl.prefixlen)
2116 						return;
2117 				} else if (req->prefixlen != ctl.prefixlen)
2118 					return;
2119 			} else
2120 				return;
2121 		}
2122 		/* filter by AS */
2123 		if (req->as.type != AS_UNDEF &&
2124 		   !match_aspath(mre->aspath, mre->aspath_len, &req->as))
2125 			continue;
2126 
2127 		bzero(&net, sizeof(net));
2128 		net.prefix = ctl.prefix;
2129 		net.prefixlen = ctl.prefixlen;
2130 		net.type = NETWORK_MRTCLONE;
2131 		/* XXX rtableid */
2132 
2133 		imsg_compose(ibuf, IMSG_NETWORK_ADD, 0, 0, -1,
2134 		    &net, sizeof(net));
2135 		if ((msg = imsg_create(ibuf, IMSG_NETWORK_ASPATH,
2136 		    0, 0, sizeof(ctl) + mre->aspath_len)) == NULL)
2137 			errx(1, "imsg_create failure");
2138 		if (imsg_add(msg, &ctl, sizeof(ctl)) == -1 ||
2139 		    imsg_add(msg, mre->aspath, mre->aspath_len) == -1)
2140 			errx(1, "imsg_add failure");
2141 		imsg_close(ibuf, msg);
2142 		for (j = 0; j < mre->nattrs; j++)
2143 			imsg_compose(ibuf, IMSG_NETWORK_ATTR, 0, 0, -1,
2144 			    mre->attrs[j].attr, mre->attrs[j].attr_len);
2145 		imsg_compose(ibuf, IMSG_NETWORK_DONE, 0, 0, -1, NULL, 0);
2146 
2147 		while (ibuf->w.queued) {
2148 			if (msgbuf_write(&ibuf->w) <= 0 && errno != EAGAIN)
2149 				err(1, "write error");
2150 		}
2151 	}
2152 }
2153 
2154 static const char *
2155 print_time(struct timespec *t)
2156 {
2157 	static char timebuf[32];
2158 	static struct timespec prevtime;
2159 	struct timespec temp;
2160 
2161 	timespecsub(t, &prevtime, &temp);
2162 	snprintf(timebuf, sizeof(timebuf), "%lld.%06ld",
2163 	    (long long)temp.tv_sec, temp.tv_nsec / 1000);
2164 	prevtime = *t;
2165 	return (timebuf);
2166 }
2167 
2168 void
2169 show_mrt_state(struct mrt_bgp_state *ms, void *arg)
2170 {
2171 	struct bgpd_addr src, dst;
2172 
2173 	mrt_to_bgpd_addr(&ms->src, &src);
2174 	mrt_to_bgpd_addr(&ms->dst, &dst);
2175 	printf("%s %s[%u] -> ", print_time(&ms->time),
2176 	    log_addr(&src), ms->src_as);
2177 	printf("%s[%u]: %s -> %s\n", log_addr(&dst), ms->dst_as,
2178 	    statenames[ms->old_state], statenames[ms->new_state]);
2179 }
2180 
2181 static void
2182 print_afi(u_char *p, u_int8_t len)
2183 {
2184 	u_int16_t afi;
2185 	u_int8_t safi, aid;
2186 
2187 	if (len != 4) {
2188 		printf("bad length");
2189 		return;
2190 	}
2191 
2192 	/* afi, 2 byte */
2193 	memcpy(&afi, p, sizeof(afi));
2194 	afi = ntohs(afi);
2195 	p += 2;
2196 	/* reserved, 1 byte */
2197 	p += 1;
2198 	/* safi, 1 byte */
2199 	memcpy(&safi, p, sizeof(safi));
2200 	if (afi2aid(afi, safi, &aid) == -1)
2201 		printf("unkown afi %u safi %u", afi, safi);
2202 	else
2203 		printf("%s", aid2str(aid));
2204 }
2205 
2206 static void
2207 print_capability(u_int8_t capa_code, u_char *p, u_int8_t len)
2208 {
2209 	switch (capa_code) {
2210 	case CAPA_MP:
2211 		printf("multiprotocol capability: ");
2212 		print_afi(p, len);
2213 		break;
2214 	case CAPA_REFRESH:
2215 		printf("route refresh capability");
2216 		break;
2217 	case CAPA_RESTART:
2218 		printf("graceful restart capability");
2219 		/* XXX there is more needed here */
2220 		break;
2221 	case CAPA_AS4BYTE:
2222 		printf("4-byte AS num capability: ");
2223 		if (len == 4) {
2224 			u_int32_t as;
2225 			memcpy(&as, p, sizeof(as));
2226 			as = ntohl(as);
2227 			printf("AS %u", as);
2228 		} else
2229 			printf("bad length");
2230 		break;
2231 	default:
2232 		printf("unknown capability %u length %u", capa_code, len);
2233 		break;
2234 	}
2235 }
2236 
2237 static void
2238 print_notification(u_int8_t errcode, u_int8_t subcode)
2239 {
2240 	const char *suberrname = NULL;
2241 	int uk = 0;
2242 
2243 	switch (errcode) {
2244 	case ERR_HEADER:
2245 		if (subcode >= sizeof(suberr_header_names)/sizeof(char *))
2246 			uk = 1;
2247 		else
2248 			suberrname = suberr_header_names[subcode];
2249 		break;
2250 	case ERR_OPEN:
2251 		if (subcode >= sizeof(suberr_open_names)/sizeof(char *))
2252 			uk = 1;
2253 		else
2254 			suberrname = suberr_open_names[subcode];
2255 		break;
2256 	case ERR_UPDATE:
2257 		if (subcode >= sizeof(suberr_update_names)/sizeof(char *))
2258 			uk = 1;
2259 		else
2260 			suberrname = suberr_update_names[subcode];
2261 		break;
2262 	case ERR_CEASE:
2263 		if (subcode >= sizeof(suberr_cease_names)/sizeof(char *))
2264 			uk = 1;
2265 		else
2266 			suberrname = suberr_cease_names[subcode];
2267 		break;
2268 	case ERR_HOLDTIMEREXPIRED:
2269 		if (subcode != 0)
2270 			uk = 1;
2271 		break;
2272 	case ERR_FSM:
2273 		if (subcode >= sizeof(suberr_fsm_names)/sizeof(char *))
2274 			uk = 1;
2275 		else
2276 			suberrname = suberr_fsm_names[subcode];
2277 		break;
2278 	default:
2279 		printf("unknown errcode %u, subcode %u",
2280 		    errcode, subcode);
2281 		return;
2282 	}
2283 
2284 	if (uk)
2285 		printf("%s, unknown subcode %u", errnames[errcode], subcode);
2286 	else {
2287 		if (suberrname == NULL)
2288 			printf("%s", errnames[errcode]);
2289 		else
2290 			printf("%s, %s", errnames[errcode], suberrname);
2291 	}
2292 }
2293 
2294 static int
2295 show_mrt_capabilities(u_char *p, u_int16_t len)
2296 {
2297 	u_int16_t totlen = len;
2298 	u_int8_t capa_code, capa_len;
2299 
2300 	while (len > 2) {
2301 		memcpy(&capa_code, p, sizeof(capa_code));
2302 		p += sizeof(capa_code);
2303 		len -= sizeof(capa_code);
2304 		memcpy(&capa_len, p, sizeof(capa_len));
2305 		p += sizeof(capa_len);
2306 		len -= sizeof(capa_len);
2307 		if (len < capa_len) {
2308 			printf("capa_len %u exceeds remaining length",
2309 			    capa_len);
2310 			return (-1);
2311 		}
2312 		printf("\n        ");
2313 		print_capability(capa_code, p, capa_len);
2314 		p += capa_len;
2315 		len -= capa_len;
2316 	}
2317 	if (len != 0) {
2318 		printf("length missmatch while capability parsing");
2319 		return (-1);
2320 	}
2321 	return (totlen);
2322 }
2323 
2324 static void
2325 show_mrt_open(u_char *p, u_int16_t len)
2326 {
2327 	u_int8_t version, optparamlen;
2328 	u_int16_t short_as, holdtime;
2329 	struct in_addr bgpid;
2330 
2331 	/* length check up to optparamlen already happened */
2332 	memcpy(&version, p, sizeof(version));
2333 	p += sizeof(version);
2334 	len -= sizeof(version);
2335 	memcpy(&short_as, p, sizeof(short_as));
2336 	p += sizeof(short_as);
2337 	len -= sizeof(short_as);
2338 	short_as = ntohs(short_as);
2339 	memcpy(&holdtime, p, sizeof(holdtime));
2340 	holdtime = ntohs(holdtime);
2341 	p += sizeof(holdtime);
2342 	len -= sizeof(holdtime);
2343 	memcpy(&bgpid, p, sizeof(bgpid));
2344 	p += sizeof(bgpid);
2345 	len -= sizeof(bgpid);
2346 	memcpy(&optparamlen, p, sizeof(optparamlen));
2347 	p += sizeof(optparamlen);
2348 	len -= sizeof(optparamlen);
2349 
2350 	printf("\n    ");
2351 	printf("Version: %d AS: %u Holdtime: %u BGP Id: %s Paramlen: %u",
2352 	    version, short_as, holdtime, inet_ntoa(bgpid), optparamlen);
2353 	if (optparamlen != len) {
2354 		printf("optional parameter length mismatch");
2355 		return;
2356 	}
2357 	while (len > 2) {
2358 		u_int8_t op_type, op_len;
2359 		int r;
2360 
2361 		memcpy(&op_type, p, sizeof(op_type));
2362 		p += sizeof(op_type);
2363 		len -= sizeof(op_type);
2364 		memcpy(&op_len, p, sizeof(op_len));
2365 		p += sizeof(op_len);
2366 		len -= sizeof(op_len);
2367 
2368 		printf("\n    ");
2369 		switch (op_type) {
2370 		case OPT_PARAM_CAPABILITIES:
2371 			printf("Capabilities: size %u", op_len);
2372 			r = show_mrt_capabilities(p, op_len);
2373 			if (r == -1)
2374 				return;
2375 			p += r;
2376 			len -= r;
2377 			break;
2378 		case OPT_PARAM_AUTH:
2379 		default:
2380 			printf("unsupported optional parameter: type %u",
2381 			    op_type);
2382 			return;
2383 		}
2384 	}
2385 	if (len != 0) {
2386 		printf("optional parameter encoding error");
2387 		return;
2388 	}
2389 }
2390 
2391 static void
2392 show_mrt_notification(u_char *p, u_int16_t len)
2393 {
2394 	u_int16_t i;
2395 	u_int8_t errcode, subcode, shutcomm_len;
2396 	char shutcomm[SHUT_COMM_LEN];
2397 
2398 	memcpy(&errcode, p, sizeof(errcode));
2399 	p += sizeof(errcode);
2400 	len -= sizeof(errcode);
2401 
2402 	memcpy(&subcode, p, sizeof(subcode));
2403 	p += sizeof(subcode);
2404 	len -= sizeof(subcode);
2405 
2406 	printf("\n    ");
2407 	print_notification(errcode, subcode);
2408 
2409 	if (errcode == ERR_CEASE && (subcode == ERR_CEASE_ADMIN_DOWN ||
2410 	    subcode == ERR_CEASE_ADMIN_RESET)) {
2411 		if (len >= sizeof(shutcomm_len)) {
2412 			memcpy(&shutcomm_len, p, sizeof(shutcomm_len));
2413 			p += sizeof(shutcomm_len);
2414 			len -= sizeof(shutcomm_len);
2415 			if(len < shutcomm_len) {
2416 				printf("truncated shutdown reason");
2417 				return;
2418 			}
2419 			if (shutcomm_len > (SHUT_COMM_LEN-1)) {
2420 				printf("overly long shutdown reason");
2421 				return;
2422 			}
2423 			memcpy(shutcomm, p, shutcomm_len);
2424 			shutcomm[shutcomm_len] = '\0';
2425 			printf("shutdown reason: \"%s\"",
2426 			    log_shutcomm(shutcomm));
2427 			p += shutcomm_len;
2428 			len -= shutcomm_len;
2429 		}
2430 	}
2431 	if (errcode == ERR_OPEN && subcode == ERR_OPEN_CAPA) {
2432 		int r;
2433 
2434 		r = show_mrt_capabilities(p, len);
2435 		if (r == -1)
2436 			return;
2437 		p += r;
2438 		len -= r;
2439 	}
2440 
2441 	if (len > 0) {
2442 		printf("\n    additional data %u bytes", len);
2443 		for (i = 0; i < len; i++) {
2444 			if (i % 16 == 0)
2445 				printf("\n    ");
2446 			if (i % 8 == 0)
2447 				printf("   ");
2448 			printf(" %02X", *p++);
2449 		}
2450 	}
2451 }
2452 
2453 static void
2454 show_mrt_update(u_char *p, u_int16_t len)
2455 {
2456 	struct bgpd_addr prefix;
2457 	int pos;
2458 	u_int16_t wlen, alen;
2459 	u_int8_t prefixlen;
2460 
2461 	if (len < sizeof(wlen)) {
2462 		printf("bad length");
2463 		return;
2464 	}
2465 	memcpy(&wlen, p, sizeof(wlen));
2466 	wlen = ntohs(wlen);
2467 	p += sizeof(wlen);
2468 	len -= sizeof(wlen);
2469 
2470 	if (len < wlen) {
2471 		printf("bad withdraw length");
2472 		return;
2473 	}
2474 	if (wlen > 0) {
2475 		printf("\n     Withdrawn prefixes:");
2476 		while (wlen > 0) {
2477 			if ((pos = nlri_get_prefix(p, wlen, &prefix,
2478 			    &prefixlen)) == -1) {
2479 				printf("bad withdraw prefix");
2480 				return;
2481 			}
2482 			printf(" %s/%u", log_addr(&prefix), prefixlen);
2483 			p += pos;
2484 			len -= pos;
2485 			wlen -= pos;
2486 		}
2487 	}
2488 
2489 	if (len < sizeof(alen)) {
2490 		printf("bad length");
2491 		return;
2492 	}
2493 	memcpy(&alen, p, sizeof(alen));
2494 	alen = ntohs(alen);
2495 	p += sizeof(alen);
2496 	len -= sizeof(alen);
2497 
2498 	if (len < alen) {
2499 		printf("bad attribute length");
2500 		return;
2501 	}
2502 	printf("\n");
2503 	/* alen attributes here */
2504 	while (alen > 3) {
2505 		u_int8_t flags, type;
2506 		u_int16_t attrlen;
2507 
2508 		flags = p[0];
2509 		type = p[1];
2510 
2511 		/* get the attribute length */
2512 		if (flags & ATTR_EXTLEN) {
2513 			if (len < sizeof(attrlen) + 2)
2514 				printf("bad attribute length");
2515 			memcpy(&attrlen, &p[2], sizeof(attrlen));
2516 			attrlen = ntohs(attrlen);
2517 			attrlen += sizeof(attrlen) + 2;
2518 		} else {
2519 			attrlen = p[2];
2520 			attrlen += 1 + 2;
2521 		}
2522 
2523 		show_attr(p, attrlen, 0);
2524 		p += attrlen;
2525 		alen -= attrlen;
2526 		len -= attrlen;
2527 	}
2528 
2529 	if (len > 0) {
2530 		printf("    NLRI prefixes:");
2531 		while (len > 0) {
2532 			if ((pos = nlri_get_prefix(p, len, &prefix,
2533 			    &prefixlen)) == -1) {
2534 				printf("bad withdraw prefix");
2535 				return;
2536 			}
2537 			printf(" %s/%u", log_addr(&prefix), prefixlen);
2538 			p += pos;
2539 			len -= pos;
2540 		}
2541 	}
2542 }
2543 
2544 void
2545 show_mrt_msg(struct mrt_bgp_msg *mm, void *arg)
2546 {
2547 	static const u_int8_t marker[MSGSIZE_HEADER_MARKER] = {
2548 	    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
2549 	    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
2550 	struct bgpd_addr src, dst;
2551 	u_char *p;
2552 	u_int16_t len;
2553 	u_int8_t type;
2554 
2555 	mrt_to_bgpd_addr(&mm->src, &src);
2556 	mrt_to_bgpd_addr(&mm->dst, &dst);
2557 	printf("%s %s[%u] -> ", print_time(&mm->time),
2558 	    log_addr(&src), mm->src_as);
2559 	printf("%s[%u]: size %u ", log_addr(&dst), mm->dst_as, mm->msg_len);
2560 	p = mm->msg;
2561 	len = mm->msg_len;
2562 
2563 	if (len < MSGSIZE_HEADER) {
2564 		printf("illegal header length: %u byte\n", len);
2565 		return;
2566 	}
2567 
2568 	/* parse BGP message header */
2569 	if (memcmp(p, marker, sizeof(marker))) {
2570 		printf("incorrect marker in BGP message\n");
2571 		return;
2572 	}
2573 	p += MSGSIZE_HEADER_MARKER;
2574 
2575 	memcpy(&len, p, 2);
2576 	len = ntohs(len);
2577 	p += 2;
2578 	memcpy(&type, p, 1);
2579 	p += 1;
2580 
2581 	if (len < MSGSIZE_HEADER || len > MAX_PKTSIZE) {
2582 		printf("illegal header length: %u byte\n", len);
2583 		return;
2584 	}
2585 
2586 	switch (type) {
2587 	case OPEN:
2588 		printf("%s ", msgtypenames[type]);
2589 		if (len < MSGSIZE_OPEN_MIN) {
2590 			printf("illegal length: %u byte\n", len);
2591 			return;
2592 		}
2593 		show_mrt_open(p, len - MSGSIZE_HEADER);
2594 		break;
2595 	case NOTIFICATION:
2596 		printf("%s ", msgtypenames[type]);
2597 		if (len < MSGSIZE_NOTIFICATION_MIN) {
2598 			printf("illegal length: %u byte\n", len);
2599 			return;
2600 		}
2601 		show_mrt_notification(p, len - MSGSIZE_HEADER);
2602 		break;
2603 	case UPDATE:
2604 		printf("%s ", msgtypenames[type]);
2605 		if (len < MSGSIZE_UPDATE_MIN) {
2606 			printf("illegal length: %u byte\n", len);
2607 			return;
2608 		}
2609 		show_mrt_update(p, len - MSGSIZE_HEADER);
2610 		break;
2611 	case KEEPALIVE:
2612 		printf("%s ", msgtypenames[type]);
2613 		if (len != MSGSIZE_KEEPALIVE) {
2614 			printf("illegal length: %u byte\n", len);
2615 			return;
2616 		}
2617 		/* nothing */
2618 		break;
2619 	case RREFRESH:
2620 		printf("%s ", msgtypenames[type]);
2621 		if (len != MSGSIZE_RREFRESH) {
2622 			printf("illegal length: %u byte\n", len);
2623 			return;
2624 		}
2625 		print_afi(p, len);
2626 		break;
2627 	default:
2628 		printf("unknown type %u\n", type);
2629 		return;
2630 	}
2631 	printf("\n");
2632 }
2633 
2634 void
2635 mrt_to_bgpd_addr(union mrt_addr *ma, struct bgpd_addr *ba)
2636 {
2637 	switch (ma->sa.sa_family) {
2638 	case AF_INET:
2639 	case AF_INET6:
2640 		sa2addr(&ma->sa, ba);
2641 		break;
2642 	case AF_VPNv4:
2643 		bzero(ba, sizeof(*ba));
2644 		ba->aid = AID_VPN_IPv4;
2645 		ba->vpn4.rd = ma->svpn4.sv_rd;
2646 		ba->vpn4.addr.s_addr = ma->svpn4.sv_addr.s_addr;
2647 		memcpy(ba->vpn4.labelstack, ma->svpn4.sv_label,
2648 		    sizeof(ba->vpn4.labelstack));
2649 		break;
2650 	}
2651 }
2652 
2653 const char *
2654 msg_type(u_int8_t type)
2655 {
2656 	if (type >= sizeof(msgtypenames)/sizeof(msgtypenames[0]))
2657 		return "BAD";
2658 	return (msgtypenames[type]);
2659 }
2660 
2661 int
2662 match_aspath(void *data, u_int16_t len, struct filter_as *f)
2663 {
2664 	u_int8_t	*seg;
2665 	int		 final;
2666 	u_int16_t	 seg_size;
2667 	u_int8_t	 i, seg_len;
2668 	u_int32_t	 as = 0;
2669 
2670 	if (f->type == AS_EMPTY) {
2671 		if (len == 0)
2672 			return (1);
2673 		else
2674 			return (0);
2675 	}
2676 
2677 	seg = data;
2678 
2679 	/* just check the leftmost AS */
2680 	if (f->type == AS_PEER && len >= 6) {
2681 		as = aspath_extract(seg, 0);
2682 		if (f->as_min == as)
2683 			return (1);
2684 		else
2685 			return (0);
2686 	}
2687 
2688 	for (; len >= 6; len -= seg_size, seg += seg_size) {
2689 		seg_len = seg[1];
2690 		seg_size = 2 + sizeof(u_int32_t) * seg_len;
2691 
2692 		final = (len == seg_size);
2693 
2694 		if (f->type == AS_SOURCE) {
2695 			/*
2696 			 * Just extract the rightmost AS
2697 			 * but if that segment is an AS_SET then the rightmost
2698 			 * AS of a previous AS_SEQUENCE segment should be used.
2699 			 * Because of that just look at AS_SEQUENCE segments.
2700 			 */
2701 			if (seg[0] == AS_SEQUENCE)
2702 				as = aspath_extract(seg, seg_len - 1);
2703 			/* not yet in the final segment */
2704 			if (!final)
2705 				continue;
2706 			if (f->as_min == as)
2707 				return (1);
2708 			else
2709 				return (0);
2710 		}
2711 		/* AS_TRANSIT or AS_ALL */
2712 		for (i = 0; i < seg_len; i++) {
2713 			/*
2714 			 * the source (rightmost) AS is excluded from
2715 			 * AS_TRANSIT matches.
2716 			 */
2717 			if (final && i == seg_len - 1 && f->type == AS_TRANSIT)
2718 				return (0);
2719 			as = aspath_extract(seg, i);
2720 			if (f->as_min == as)
2721 				return (1);
2722 		}
2723 	}
2724 	return (0);
2725 }
2726