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