xref: /openbsd/usr.sbin/bgpctl/bgpctl.c (revision 5af055cd)
1 /*	$OpenBSD: bgpctl.c,v 1.187 2015/12/05 13:17:05 claudio Exp $ */
2 
3 /*
4  * Copyright (c) 2003 Henning Brauer <henning@openbsd.org>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include <sys/types.h>
20 #include <sys/socket.h>
21 #include <sys/un.h>
22 #include <net/if.h>
23 #include <net/if_media.h>
24 #include <net/if_types.h>
25 
26 #include <err.h>
27 #include <errno.h>
28 #include <fcntl.h>
29 #include <netdb.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <unistd.h>
34 #include <util.h>
35 
36 #include "bgpd.h"
37 #include "session.h"
38 #include "rde.h"
39 #include "log.h"
40 #include "parser.h"
41 #include "irrfilter.h"
42 #include "mrtparser.h"
43 
44 enum neighbor_views {
45 	NV_DEFAULT,
46 	NV_TIMERS
47 };
48 
49 int		 main(int, char *[]);
50 char		*fmt_peer(const char *, const struct bgpd_addr *, int, int);
51 void		 show_summary_head(void);
52 int		 show_summary_msg(struct imsg *, int);
53 int		 show_summary_terse_msg(struct imsg *, int);
54 int		 show_neighbor_terse(struct imsg *);
55 int		 show_neighbor_msg(struct imsg *, enum neighbor_views);
56 void		 print_neighbor_capa_mp(struct peer *);
57 void		 print_neighbor_capa_restart(struct peer *);
58 void		 print_neighbor_msgstats(struct peer *);
59 void		 print_timer(const char *, time_t);
60 static char	*fmt_timeframe(time_t t);
61 static char	*fmt_timeframe_core(time_t t);
62 void		 show_fib_head(void);
63 void		 show_fib_tables_head(void);
64 void		 show_network_head(void);
65 void		 show_fib_flags(u_int16_t);
66 int		 show_fib_msg(struct imsg *);
67 void		 show_nexthop_head(void);
68 int		 show_nexthop_msg(struct imsg *);
69 void		 show_interface_head(void);
70 uint64_t	 ift2ifm(uint8_t);
71 const char *	 get_media_descr(uint64_t);
72 const char *	 get_linkstate(uint8_t, int);
73 const char *	 get_baudrate(u_int64_t, char *);
74 int		 show_interface_msg(struct imsg *);
75 void		 show_rib_summary_head(void);
76 void		 print_prefix(struct bgpd_addr *, u_int8_t, u_int8_t);
77 const char *	 print_origin(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);
81 void		 show_rib_brief(struct ctl_show_rib *, u_char *);
82 void		 show_rib_detail(struct ctl_show_rib *, u_char *, int);
83 void		 show_attr(void *, u_int16_t);
84 void		 show_community(u_char *, u_int16_t);
85 void		 show_ext_community(u_char *, u_int16_t);
86 char		*fmt_mem(int64_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 void		 mrt_to_bgpd_addr(union mrt_addr *, struct bgpd_addr *);
96 const char	*msg_type(u_int8_t);
97 void		 network_bulk(struct parse_result *);
98 const char	*print_auth_method(enum auth_method);
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 
104 __dead void
105 usage(void)
106 {
107 	extern char	*__progname;
108 
109 	fprintf(stderr, "usage: %s [-n] [-s socket] command [argument ...]\n",
110 	    __progname);
111 	exit(1);
112 }
113 
114 int
115 main(int argc, char *argv[])
116 {
117 	struct sockaddr_un	 sun;
118 	int			 fd, n, done, ch, nodescr = 0, verbose = 0;
119 	struct imsg		 imsg;
120 	struct network_config	 net;
121 	struct parse_result	*res;
122 	struct ctl_neighbor	 neighbor;
123 	struct ctl_show_rib_request	ribreq;
124 	char			*sockname;
125 	enum imsg_type		 type;
126 
127 	if (pledge("stdio rpath wpath cpath unix inet dns", NULL) == -1)
128 		err(1, "pledge");
129 
130 	sockname = SOCKET_NAME;
131 	while ((ch = getopt(argc, argv, "ns:")) != -1) {
132 		switch (ch) {
133 		case 'n':
134 			if (++nodescr > 1)
135 				usage();
136 			break;
137 		case 's':
138 			sockname = optarg;
139 			break;
140 		default:
141 			usage();
142 			/* NOTREACHED */
143 		}
144 	}
145 	argc -= optind;
146 	argv += optind;
147 
148 	if ((res = parse(argc, argv)) == NULL)
149 		exit(1);
150 
151 	if (res->action == IRRFILTER) {
152 		if (!(res->flags & (F_IPV4|F_IPV6)))
153 			res->flags |= (F_IPV4|F_IPV6);
154 		irr_main(res->as.as, res->flags, res->irr_outdir);
155 	}
156 
157 	if (pledge("stdio rpath wpath unix", NULL) == -1)
158 		err(1, "pledge");
159 
160 	memcpy(&neighbor.addr, &res->peeraddr, sizeof(neighbor.addr));
161 	strlcpy(neighbor.descr, res->peerdesc, sizeof(neighbor.descr));
162 
163 	if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
164 		err(1, "control_init: socket");
165 
166 	bzero(&sun, sizeof(sun));
167 	sun.sun_family = AF_UNIX;
168 	if (strlcpy(sun.sun_path, sockname, sizeof(sun.sun_path)) >=
169 	    sizeof(sun.sun_path))
170 		errx(1, "socket name too long");
171 	if (connect(fd, (struct sockaddr *)&sun, sizeof(sun)) == -1)
172 		err(1, "connect: %s", sockname);
173 
174 	if (pledge("stdio rpath wpath", NULL) == -1)
175 		err(1, "pledge");
176 
177 	if ((ibuf = malloc(sizeof(struct imsgbuf))) == NULL)
178 		err(1, NULL);
179 	imsg_init(ibuf, fd);
180 	done = 0;
181 
182 	switch (res->action) {
183 	case NONE:
184 	case IRRFILTER:
185 		usage();
186 		/* NOTREACHED */
187 	case SHOW:
188 	case SHOW_SUMMARY:
189 		imsg_compose(ibuf, IMSG_CTL_SHOW_NEIGHBOR, 0, 0, -1, NULL, 0);
190 		show_summary_head();
191 		break;
192 	case SHOW_SUMMARY_TERSE:
193 		imsg_compose(ibuf, IMSG_CTL_SHOW_TERSE, 0, 0, -1, NULL, 0);
194 		break;
195 	case SHOW_FIB:
196 		if (!res->addr.aid) {
197 			struct ibuf	*msg;
198 			sa_family_t	 af;
199 
200 			af = aid2af(res->aid);
201 			if ((msg = imsg_create(ibuf, IMSG_CTL_KROUTE,
202 			    res->rtableid, 0, sizeof(res->flags) +
203 			    sizeof(af))) == NULL)
204 				errx(1, "imsg_create failure");
205 			if (imsg_add(msg, &res->flags, sizeof(res->flags)) ==
206 			    -1 ||
207 			    imsg_add(msg, &af, sizeof(af)) == -1)
208 				errx(1, "imsg_add failure");
209 			imsg_close(ibuf, msg);
210 		} else
211 			imsg_compose(ibuf, IMSG_CTL_KROUTE_ADDR, res->rtableid,
212 			    0, -1, &res->addr, sizeof(res->addr));
213 		show_fib_head();
214 		break;
215 	case SHOW_FIB_TABLES:
216 		imsg_compose(ibuf, IMSG_CTL_SHOW_FIB_TABLES, 0, 0, -1, NULL, 0);
217 		show_fib_tables_head();
218 		break;
219 	case SHOW_NEXTHOP:
220 		imsg_compose(ibuf, IMSG_CTL_SHOW_NEXTHOP, res->rtableid, 0, -1,
221 		    NULL, 0);
222 		show_nexthop_head();
223 		break;
224 	case SHOW_INTERFACE:
225 		imsg_compose(ibuf, IMSG_CTL_SHOW_INTERFACE, 0, 0, -1, NULL, 0);
226 		show_interface_head();
227 		break;
228 	case SHOW_NEIGHBOR:
229 	case SHOW_NEIGHBOR_TIMERS:
230 	case SHOW_NEIGHBOR_TERSE:
231 		neighbor.show_timers = (res->action == SHOW_NEIGHBOR_TIMERS);
232 		if (res->peeraddr.aid || res->peerdesc[0])
233 			imsg_compose(ibuf, IMSG_CTL_SHOW_NEIGHBOR, 0, 0, -1,
234 			    &neighbor, sizeof(neighbor));
235 		else
236 			imsg_compose(ibuf, IMSG_CTL_SHOW_NEIGHBOR, 0, 0, -1,
237 			    NULL, 0);
238 		break;
239 	case SHOW_RIB:
240 		bzero(&ribreq, sizeof(ribreq));
241 		type = IMSG_CTL_SHOW_RIB;
242 		if (res->as.type != AS_NONE) {
243 			memcpy(&ribreq.as, &res->as, sizeof(res->as));
244 			type = IMSG_CTL_SHOW_RIB_AS;
245 		}
246 		if (res->addr.aid) {
247 			memcpy(&ribreq.prefix, &res->addr, sizeof(res->addr));
248 			ribreq.prefixlen = res->prefixlen;
249 			type = IMSG_CTL_SHOW_RIB_PREFIX;
250 		}
251 		if (res->community.as != COMMUNITY_UNSET &&
252 		    res->community.type != COMMUNITY_UNSET) {
253 			memcpy(&ribreq.community, &res->community,
254 			    sizeof(res->community));
255 			type = IMSG_CTL_SHOW_RIB_COMMUNITY;
256 		}
257 		memcpy(&ribreq.neighbor, &neighbor, sizeof(ribreq.neighbor));
258 		strlcpy(ribreq.rib, res->rib, sizeof(ribreq.rib));
259 		ribreq.aid = res->aid;
260 		ribreq.flags = res->flags;
261 		imsg_compose(ibuf, type, 0, 0, -1, &ribreq, sizeof(ribreq));
262 		if (!(res->flags & F_CTL_DETAIL))
263 			show_rib_summary_head();
264 		break;
265 	case SHOW_MRT:
266 		close(fd);
267 		bzero(&ribreq, sizeof(ribreq));
268 		if (res->as.type != AS_NONE)
269 			memcpy(&ribreq.as, &res->as, sizeof(res->as));
270 		if (res->addr.aid) {
271 			memcpy(&ribreq.prefix, &res->addr, sizeof(res->addr));
272 			ribreq.prefixlen = res->prefixlen;
273 		}
274 		if (res->community.as != COMMUNITY_UNSET &&
275 		    res->community.type != COMMUNITY_UNSET)
276 			memcpy(&ribreq.community, &res->community,
277 			    sizeof(res->community));
278 		memcpy(&ribreq.neighbor, &neighbor, sizeof(ribreq.neighbor));
279 		ribreq.aid = res->aid;
280 		ribreq.flags = res->flags;
281 		show_mrt.arg = &ribreq;
282 		if (!(res->flags & F_CTL_DETAIL))
283 			show_rib_summary_head();
284 		mrt_parse(res->mrtfd, &show_mrt, 1);
285 		exit(0);
286 	case SHOW_RIB_MEM:
287 		imsg_compose(ibuf, IMSG_CTL_SHOW_RIB_MEM, 0, 0, -1, NULL, 0);
288 		break;
289 	case RELOAD:
290 		imsg_compose(ibuf, IMSG_CTL_RELOAD, 0, 0, -1, NULL, 0);
291 		printf("reload request sent.\n");
292 		break;
293 	case FIB:
294 		errx(1, "action==FIB");
295 		break;
296 	case FIB_COUPLE:
297 		imsg_compose(ibuf, IMSG_CTL_FIB_COUPLE, res->rtableid, 0, -1,
298 		    NULL, 0);
299 		printf("couple request sent.\n");
300 		done = 1;
301 		break;
302 	case FIB_DECOUPLE:
303 		imsg_compose(ibuf, IMSG_CTL_FIB_DECOUPLE, res->rtableid, 0, -1,
304 		    NULL, 0);
305 		printf("decouple request sent.\n");
306 		done = 1;
307 		break;
308 	case NEIGHBOR:
309 		errx(1, "action==NEIGHBOR");
310 		break;
311 	case NEIGHBOR_UP:
312 		imsg_compose(ibuf, IMSG_CTL_NEIGHBOR_UP, 0, 0, -1,
313 		    &neighbor, sizeof(neighbor));
314 		break;
315 	case NEIGHBOR_DOWN:
316 		imsg_compose(ibuf, IMSG_CTL_NEIGHBOR_DOWN, 0, 0, -1,
317 		    &neighbor, sizeof(neighbor));
318 		break;
319 	case NEIGHBOR_CLEAR:
320 		imsg_compose(ibuf, IMSG_CTL_NEIGHBOR_CLEAR, 0, 0, -1,
321 		    &neighbor, sizeof(neighbor));
322 		break;
323 	case NEIGHBOR_RREFRESH:
324 		imsg_compose(ibuf, IMSG_CTL_NEIGHBOR_RREFRESH, 0, 0, -1,
325 		    &neighbor, sizeof(neighbor));
326 		break;
327 	case NEIGHBOR_DESTROY:
328 		imsg_compose(ibuf, IMSG_CTL_NEIGHBOR_DESTROY, 0, 0, -1,
329 		    &neighbor, sizeof(neighbor));
330 		break;
331 	case NETWORK_BULK_ADD:
332 	case NETWORK_BULK_REMOVE:
333 		network_bulk(res);
334 		printf("requests sent.\n");
335 		done = 1;
336 		break;
337 	case NETWORK_ADD:
338 	case NETWORK_REMOVE:
339 		bzero(&net, sizeof(net));
340 		memcpy(&net.prefix, &res->addr, sizeof(res->addr));
341 		net.prefixlen = res->prefixlen;
342 		/* attribute sets are not supported */
343 		if (res->action == NETWORK_ADD) {
344 			imsg_compose(ibuf, IMSG_NETWORK_ADD, 0, 0, -1,
345 			    &net, sizeof(net));
346 			send_filterset(ibuf, &res->set);
347 			imsg_compose(ibuf, IMSG_NETWORK_DONE, 0, 0, -1,
348 			    NULL, 0);
349 		} else
350 			imsg_compose(ibuf, IMSG_NETWORK_REMOVE, 0, 0, -1,
351 			    &net, sizeof(net));
352 		printf("request sent.\n");
353 		done = 1;
354 		break;
355 	case NETWORK_FLUSH:
356 		imsg_compose(ibuf, IMSG_NETWORK_FLUSH, 0, 0, -1, NULL, 0);
357 		printf("request sent.\n");
358 		done = 1;
359 		break;
360 	case NETWORK_SHOW:
361 		bzero(&ribreq, sizeof(ribreq));
362 		ribreq.aid = res->aid;
363 		strlcpy(ribreq.rib, res->rib, sizeof(ribreq.rib));
364 		imsg_compose(ibuf, IMSG_CTL_SHOW_NETWORK, 0, 0, -1,
365 		    &ribreq, sizeof(ribreq));
366 		show_network_head();
367 		break;
368 	case NETWORK_MRT:
369 		bzero(&ribreq, sizeof(ribreq));
370 		if (res->as.type != AS_NONE)
371 			memcpy(&ribreq.as, &res->as, sizeof(res->as));
372 		if (res->addr.aid) {
373 			memcpy(&ribreq.prefix, &res->addr, sizeof(res->addr));
374 			ribreq.prefixlen = res->prefixlen;
375 		}
376 		if (res->community.as != COMMUNITY_UNSET &&
377 		    res->community.type != COMMUNITY_UNSET)
378 			memcpy(&ribreq.community, &res->community,
379 			    sizeof(res->community));
380 		memcpy(&ribreq.neighbor, &neighbor, sizeof(ribreq.neighbor));
381 		ribreq.aid = res->aid;
382 		ribreq.flags = res->flags;
383 		net_mrt.arg = &ribreq;
384 		mrt_parse(res->mrtfd, &net_mrt, 1);
385 		done = 1;
386 		break;
387 	case LOG_VERBOSE:
388 		verbose = 1;
389 		/* FALLTHROUGH */
390 	case LOG_BRIEF:
391 		imsg_compose(ibuf, IMSG_CTL_LOG_VERBOSE, 0, 0, -1,
392 		    &verbose, sizeof(verbose));
393 		printf("logging request sent.\n");
394 		done = 1;
395 		break;
396 	}
397 
398 	while (ibuf->w.queued)
399 		if (msgbuf_write(&ibuf->w) <= 0 && errno != EAGAIN)
400 			err(1, "write error");
401 
402 	while (!done) {
403 		if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN)
404 			err(1, "imsg_read error");
405 		if (n == 0)
406 			errx(1, "pipe closed");
407 
408 		while (!done) {
409 			if ((n = imsg_get(ibuf, &imsg)) == -1)
410 				err(1, "imsg_get error");
411 			if (n == 0)
412 				break;
413 
414 			if (imsg.hdr.type == IMSG_CTL_RESULT) {
415 				done = show_result(&imsg);
416 				imsg_free(&imsg);
417 				continue;
418 			}
419 
420 			switch (res->action) {
421 			case SHOW:
422 			case SHOW_SUMMARY:
423 				done = show_summary_msg(&imsg, nodescr);
424 				break;
425 			case SHOW_SUMMARY_TERSE:
426 				done = show_summary_terse_msg(&imsg, nodescr);
427 				break;
428 			case SHOW_FIB:
429 			case SHOW_FIB_TABLES:
430 			case NETWORK_SHOW:
431 				done = show_fib_msg(&imsg);
432 				break;
433 			case SHOW_NEXTHOP:
434 				done = show_nexthop_msg(&imsg);
435 				break;
436 			case SHOW_INTERFACE:
437 				done = show_interface_msg(&imsg);
438 				break;
439 			case SHOW_NEIGHBOR:
440 				done = show_neighbor_msg(&imsg, NV_DEFAULT);
441 				break;
442 			case SHOW_NEIGHBOR_TIMERS:
443 				done = show_neighbor_msg(&imsg, NV_TIMERS);
444 				break;
445 			case SHOW_NEIGHBOR_TERSE:
446 				done = show_neighbor_terse(&imsg);
447 				break;
448 			case SHOW_RIB:
449 				if (res->flags & F_CTL_DETAIL)
450 					done = show_rib_detail_msg(&imsg,
451 					    nodescr);
452 				else
453 					done = show_rib_summary_msg(&imsg);
454 				break;
455 			case SHOW_RIB_MEM:
456 				done = show_rib_memory_msg(&imsg);
457 				break;
458 			case NEIGHBOR:
459 			case NEIGHBOR_UP:
460 			case NEIGHBOR_DOWN:
461 			case NEIGHBOR_CLEAR:
462 			case NEIGHBOR_RREFRESH:
463 			case NEIGHBOR_DESTROY:
464 			case NONE:
465 			case RELOAD:
466 			case FIB:
467 			case FIB_COUPLE:
468 			case FIB_DECOUPLE:
469 			case NETWORK_ADD:
470 			case NETWORK_REMOVE:
471 			case NETWORK_FLUSH:
472 			case NETWORK_BULK_ADD:
473 			case NETWORK_BULK_REMOVE:
474 			case IRRFILTER:
475 			case LOG_VERBOSE:
476 			case LOG_BRIEF:
477 			case SHOW_MRT:
478 			case NETWORK_MRT:
479 				break;
480 			}
481 			imsg_free(&imsg);
482 		}
483 	}
484 	close(fd);
485 	free(ibuf);
486 
487 	exit(0);
488 }
489 
490 char *
491 fmt_peer(const char *descr, const struct bgpd_addr *remote_addr,
492     int masklen, int nodescr)
493 {
494 	const char	*ip;
495 	char		*p;
496 
497 	if (descr[0] && !nodescr) {
498 		if ((p = strdup(descr)) == NULL)
499 			err(1, NULL);
500 		return (p);
501 	}
502 
503 	ip = log_addr(remote_addr);
504 	if (masklen != -1 && ((remote_addr->aid == AID_INET && masklen != 32) ||
505 	    (remote_addr->aid == AID_INET6 && masklen != 128))) {
506 		if (asprintf(&p, "%s/%u", ip, masklen) == -1)
507 			err(1, NULL);
508 	} else {
509 		if ((p = strdup(ip)) == NULL)
510 			err(1, NULL);
511 	}
512 
513 	return (p);
514 }
515 
516 void
517 show_summary_head(void)
518 {
519 	printf("%-20s %8s %10s %10s %5s %-8s %s\n", "Neighbor", "AS",
520 	    "MsgRcvd", "MsgSent", "OutQ", "Up/Down", "State/PrfRcvd");
521 }
522 
523 int
524 show_summary_msg(struct imsg *imsg, int nodescr)
525 {
526 	struct peer		*p;
527 	char			*s;
528 	const char		*a;
529 	size_t			alen;
530 
531 	switch (imsg->hdr.type) {
532 	case IMSG_CTL_SHOW_NEIGHBOR:
533 		p = imsg->data;
534 		s = fmt_peer(p->conf.descr, &p->conf.remote_addr,
535 		    p->conf.remote_masklen, nodescr);
536 
537 		a = log_as(p->conf.remote_as);
538 		alen = strlen(a);
539 		/* max displayed lenght of the peers name is 28 */
540 		if (alen < 28) {
541 			if (strlen(s) > 28 - alen)
542 				s[28 - alen] = 0;
543 		} else
544 			alen = 0;
545 
546 		printf("%-*s %s %10llu %10llu %5u %-8s ",
547 		    (28 - (int)alen), s, a,
548 		    p->stats.msg_rcvd_open + p->stats.msg_rcvd_notification +
549 		    p->stats.msg_rcvd_update + p->stats.msg_rcvd_keepalive +
550 		    p->stats.msg_rcvd_rrefresh,
551 		    p->stats.msg_sent_open + p->stats.msg_sent_notification +
552 		    p->stats.msg_sent_update + p->stats.msg_sent_keepalive +
553 		    p->stats.msg_sent_rrefresh,
554 		    p->wbuf.queued,
555 		    fmt_timeframe(p->stats.last_updown));
556 		if (p->state == STATE_ESTABLISHED) {
557 			printf("%6u", p->stats.prefix_cnt);
558 			if (p->conf.max_prefix != 0)
559 				printf("/%u", p->conf.max_prefix);
560 		} else if (p->conf.template)
561 			printf("Template");
562 		else
563 			printf("%s", statenames[p->state]);
564 		printf("\n");
565 		free(s);
566 		break;
567 	case IMSG_CTL_END:
568 		return (1);
569 	default:
570 		break;
571 	}
572 
573 	return (0);
574 }
575 
576 int
577 show_summary_terse_msg(struct imsg *imsg, int nodescr)
578 {
579 	struct peer		*p;
580 	char			*s;
581 
582 	switch (imsg->hdr.type) {
583 	case IMSG_CTL_SHOW_NEIGHBOR:
584 		p = imsg->data;
585 		s = fmt_peer(p->conf.descr, &p->conf.remote_addr,
586 		    p->conf.remote_masklen, nodescr);
587 		printf("%s %s %s\n", s, log_as(p->conf.remote_as),
588 		    p->conf.template ? "Template" : statenames[p->state]);
589 		free(s);
590 		break;
591 	case IMSG_CTL_END:
592 		return (1);
593 	default:
594 		break;
595 	}
596 
597 	return (0);
598 }
599 
600 int
601 show_neighbor_terse(struct imsg *imsg)
602 {
603 	struct peer		*p;
604 
605 	switch (imsg->hdr.type) {
606 	case IMSG_CTL_SHOW_NEIGHBOR:
607 		p = imsg->data;
608 		printf("%llu %llu %llu %llu %llu %llu %llu "
609 		    "%llu %llu %llu %u %u %llu %llu %llu %llu\n",
610 		    p->stats.msg_sent_open, p->stats.msg_rcvd_open,
611 		    p->stats.msg_sent_notification,
612 		    p->stats.msg_rcvd_notification,
613 		    p->stats.msg_sent_update, p->stats.msg_rcvd_update,
614 		    p->stats.msg_sent_keepalive, p->stats.msg_rcvd_keepalive,
615 		    p->stats.msg_sent_rrefresh, p->stats.msg_rcvd_rrefresh,
616 		    p->stats.prefix_cnt, p->conf.max_prefix,
617 		    p->stats.prefix_sent_update, p->stats.prefix_rcvd_update,
618 		    p->stats.prefix_sent_withdraw,
619 		    p->stats.prefix_rcvd_withdraw);
620 		break;
621 	case IMSG_CTL_END:
622 		return (1);
623 	default:
624 		break;
625 	}
626 
627 	return (0);
628 }
629 
630 const char *
631 print_auth_method(enum auth_method method)
632 {
633 	switch (method) {
634 	case AUTH_MD5SIG:
635 		return ", using md5sig";
636 	case AUTH_IPSEC_MANUAL_ESP:
637 		return ", using ipsec manual esp";
638 	case AUTH_IPSEC_MANUAL_AH:
639 		return ", using ipsec manual ah";
640 	case AUTH_IPSEC_IKE_ESP:
641 		return ", using ipsec ike esp";
642 	case AUTH_IPSEC_IKE_AH:
643 		return ", using ipsec ike ah";
644 	case AUTH_NONE:	/* FALLTHROUGH */
645 	default:
646 		return "";
647 	}
648 }
649 
650 int
651 show_neighbor_msg(struct imsg *imsg, enum neighbor_views nv)
652 {
653 	struct peer		*p;
654 	struct ctl_timer	*t;
655 	struct in_addr		 ina;
656 	char			 buf[NI_MAXHOST], pbuf[NI_MAXSERV], *s;
657 	int			 hascapamp = 0;
658 	u_int8_t		 i;
659 
660 	switch (imsg->hdr.type) {
661 	case IMSG_CTL_SHOW_NEIGHBOR:
662 		p = imsg->data;
663 		if ((p->conf.remote_addr.aid == AID_INET &&
664 		    p->conf.remote_masklen != 32) ||
665 		    (p->conf.remote_addr.aid == AID_INET6 &&
666 		    p->conf.remote_masklen != 128)) {
667 			if (asprintf(&s, "%s/%u",
668 			    log_addr(&p->conf.remote_addr),
669 			    p->conf.remote_masklen) == -1)
670 				err(1, NULL);
671 		} else
672 			if ((s = strdup(log_addr(&p->conf.remote_addr))) ==
673 			    NULL)
674 				err(1, "strdup");
675 
676 		ina.s_addr = p->remote_bgpid;
677 		printf("BGP neighbor is %s, ", s);
678 		free(s);
679 		if (p->conf.remote_as == 0 && p->conf.template)
680 			printf("remote AS: accept any");
681 		else
682 			printf("remote AS %s", log_as(p->conf.remote_as));
683 		if (p->conf.template)
684 			printf(", Template");
685 		if (p->template)
686 			printf(", Cloned");
687 		if (p->conf.passive)
688 			printf(", Passive");
689 		if (p->conf.ebgp && p->conf.distance > 1)
690 			printf(", Multihop (%u)", (int)p->conf.distance);
691 		printf("\n");
692 		if (p->conf.descr[0])
693 			printf(" Description: %s\n", p->conf.descr);
694 		if (p->conf.max_prefix) {
695 			printf(" Max-prefix: %u", p->conf.max_prefix);
696 			if (p->conf.max_prefix_restart)
697 				printf(" (restart %u)",
698 				    p->conf.max_prefix_restart);
699 			printf("\n");
700 		}
701 		printf("  BGP version 4, remote router-id %s",
702 		    inet_ntoa(ina));
703 		printf("%s\n", print_auth_method(p->auth.method));
704 		printf("  BGP state = %s", statenames[p->state]);
705 		if (p->stats.last_updown != 0)
706 			printf(", %s for %s",
707 			    p->state == STATE_ESTABLISHED ? "up" : "down",
708 			    fmt_timeframe(p->stats.last_updown));
709 		printf("\n");
710 		printf("  Last read %s, holdtime %us, keepalive interval %us\n",
711 		    fmt_timeframe(p->stats.last_read),
712 		    p->holdtime, p->holdtime/3);
713 		for (i = 0; i < AID_MAX; i++)
714 			if (p->capa.peer.mp[i])
715 				hascapamp = 1;
716 		if (hascapamp || p->capa.peer.refresh ||
717 		    p->capa.peer.grestart.restart || p->capa.peer.as4byte) {
718 			printf("  Neighbor capabilities:\n");
719 			if (hascapamp) {
720 				printf("    Multiprotocol extensions: ");
721 				print_neighbor_capa_mp(p);
722 				printf("\n");
723 			}
724 			if (p->capa.peer.refresh)
725 				printf("    Route Refresh\n");
726 			if (p->capa.peer.grestart.restart) {
727 				printf("    Graceful Restart");
728 				print_neighbor_capa_restart(p);
729 				printf("\n");
730 			}
731 			if (p->capa.peer.as4byte)
732 				printf("    4-byte AS numbers\n");
733 		}
734 		printf("\n");
735 		if (nv == NV_TIMERS)
736 			break;
737 		print_neighbor_msgstats(p);
738 		printf("\n");
739 		if (p->state == STATE_IDLE) {
740 			static const char	*errstr;
741 
742 			errstr = get_errstr(p->stats.last_sent_errcode,
743 			    p->stats.last_sent_suberr);
744 			if (errstr)
745 				printf("  Last error: %s\n\n", errstr);
746 		} else {
747 			if (getnameinfo((struct sockaddr *)&p->sa_local,
748 			    (socklen_t)p->sa_local.ss_len,
749 			    buf, sizeof(buf), pbuf, sizeof(pbuf),
750 			    NI_NUMERICHOST | NI_NUMERICSERV)) {
751 				strlcpy(buf, "(unknown)", sizeof(buf));
752 				strlcpy(pbuf, "", sizeof(pbuf));
753 			}
754 			printf("  Local host:  %20s, Local port:  %5s\n", buf,
755 			    pbuf);
756 
757 			if (getnameinfo((struct sockaddr *)&p->sa_remote,
758 			    (socklen_t)p->sa_remote.ss_len,
759 			    buf, sizeof(buf), pbuf, sizeof(pbuf),
760 			    NI_NUMERICHOST | NI_NUMERICSERV)) {
761 				strlcpy(buf, "(unknown)", sizeof(buf));
762 				strlcpy(pbuf, "", sizeof(pbuf));
763 			}
764 			printf("  Remote host: %20s, Remote port: %5s\n", buf,
765 			    pbuf);
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 R = redistributed\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 destination\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_REDISTRIBUTED)
957 		printf("R");
958 	else
959 		printf(" ");
960 
961 	if (flags & F_REJECT && flags & F_BLACKHOLE)
962 		printf("f");
963 	else if (flags & F_REJECT)
964 		printf("r");
965 	else if (flags & F_BLACKHOLE)
966 		printf("b");
967 	else
968 		printf(" ");
969 
970 	printf(" ");
971 }
972 
973 int
974 show_fib_msg(struct imsg *imsg)
975 {
976 	struct kroute_full	*kf;
977 	struct ktable		*kt;
978 	char			*p;
979 
980 	switch (imsg->hdr.type) {
981 	case IMSG_CTL_KROUTE:
982 	case IMSG_CTL_SHOW_NETWORK:
983 		if (imsg->hdr.len < IMSG_HEADER_SIZE + sizeof(*kf))
984 			errx(1, "wrong imsg len");
985 		kf = imsg->data;
986 
987 		show_fib_flags(kf->flags);
988 
989 		if (asprintf(&p, "%s/%u", log_addr(&kf->prefix),
990 		    kf->prefixlen) == -1)
991 			err(1, NULL);
992 		printf("%4i %-20s ", kf->priority, p);
993 		free(p);
994 
995 		if (kf->flags & F_CONNECTED)
996 			printf("link#%u", kf->ifindex);
997 		else
998 			printf("%s", log_addr(&kf->nexthop));
999 		printf("\n");
1000 
1001 		break;
1002 	case IMSG_CTL_SHOW_FIB_TABLES:
1003 		if (imsg->hdr.len < IMSG_HEADER_SIZE + sizeof(*kt))
1004 			errx(1, "wrong imsg len");
1005 		kt = imsg->data;
1006 
1007 		printf("%5i %-20s %-8s%s\n", kt->rtableid, kt->descr,
1008 		    kt->fib_sync ? "coupled" : "decoupled",
1009 		    kt->fib_sync != kt->fib_conf ? "*" : "");
1010 
1011 		break;
1012 	case IMSG_CTL_END:
1013 		return (1);
1014 	default:
1015 		break;
1016 	}
1017 
1018 	return (0);
1019 }
1020 
1021 void
1022 show_nexthop_head(void)
1023 {
1024 	printf("Flags: * = nexthop valid\n");
1025 	printf("\n  %-15s %-19s%-4s %-15s %-20s\n", "Nexthop", "Route",
1026 	     "Prio", "Gateway", "Iface");
1027 }
1028 
1029 int
1030 show_nexthop_msg(struct imsg *imsg)
1031 {
1032 	struct ctl_show_nexthop	*p;
1033 	struct kroute		*k;
1034 	struct kroute6		*k6;
1035 	char			*s;
1036 
1037 	switch (imsg->hdr.type) {
1038 	case IMSG_CTL_SHOW_NEXTHOP:
1039 		p = imsg->data;
1040 		printf("%s %-15s ", p->valid ? "*" : " ", log_addr(&p->addr));
1041 		if (!p->krvalid) {
1042 			printf("\n");
1043 			return (0);
1044 		}
1045 		switch (p->addr.aid) {
1046 		case AID_INET:
1047 			k = &p->kr.kr4;
1048 			if (asprintf(&s, "%s/%u", inet_ntoa(k->prefix),
1049 			    k->prefixlen) == -1)
1050 				err(1, NULL);
1051 			printf("%-20s", s);
1052 			free(s);
1053 			printf("%3i %-15s ", k->priority,
1054 			    k->flags & F_CONNECTED ? "connected" :
1055 			    inet_ntoa(k->nexthop));
1056 			break;
1057 		case AID_INET6:
1058 			k6 = &p->kr.kr6;
1059 			if (asprintf(&s, "%s/%u", log_in6addr(&k6->prefix),
1060 			    k6->prefixlen) == -1)
1061 				err(1, NULL);
1062 			printf("%-20s", s);
1063 			free(s);
1064 			printf("%3i %-15s ", k6->priority,
1065 			    k6->flags & F_CONNECTED ? "connected" :
1066 			    log_in6addr(&k6->nexthop));
1067 			break;
1068 		default:
1069 			printf("unknown address family\n");
1070 			return (0);
1071 		}
1072 		if (p->kif.ifname[0]) {
1073 			char *s1;
1074 			if (p->kif.baudrate) {
1075 				if (asprintf(&s1, ", %s",
1076 				    get_baudrate(p->kif.baudrate,
1077 				    "bps")) == -1)
1078 					err(1, NULL);
1079 			} else if (asprintf(&s1, ", %s", get_linkstate(
1080 			    p->kif.if_type, p->kif.link_state)) == -1)
1081 					err(1, NULL);
1082 			if (asprintf(&s, "%s (%s%s)", p->kif.ifname,
1083 			    p->kif.flags & IFF_UP ? "UP" : "DOWN", s1) == -1)
1084 				err(1, NULL);
1085 			printf("%-15s", s);
1086 			free(s1);
1087 			free(s);
1088 		}
1089 		printf("\n");
1090 		break;
1091 	case IMSG_CTL_END:
1092 		return (1);
1093 		break;
1094 	default:
1095 		break;
1096 	}
1097 
1098 	return (0);
1099 }
1100 
1101 
1102 void
1103 show_interface_head(void)
1104 {
1105 	printf("%-15s%-15s%-15s%s\n", "Interface", "Nexthop state", "Flags",
1106 	    "Link state");
1107 }
1108 
1109 const struct if_status_description
1110 		if_status_descriptions[] = LINK_STATE_DESCRIPTIONS;
1111 const struct ifmedia_description
1112 		ifm_type_descriptions[] = IFM_TYPE_DESCRIPTIONS;
1113 
1114 uint64_t
1115 ift2ifm(uint8_t if_type)
1116 {
1117 	switch (if_type) {
1118 	case IFT_ETHER:
1119 		return (IFM_ETHER);
1120 	case IFT_FDDI:
1121 		return (IFM_FDDI);
1122 	case IFT_CARP:
1123 		return (IFM_CARP);
1124 	case IFT_IEEE80211:
1125 		return (IFM_IEEE80211);
1126 	default:
1127 		return (0);
1128 	}
1129 }
1130 
1131 const char *
1132 get_media_descr(uint64_t media_type)
1133 {
1134 	const struct ifmedia_description	*p;
1135 
1136 	for (p = ifm_type_descriptions; p->ifmt_string != NULL; p++)
1137 		if (media_type == p->ifmt_word)
1138 			return (p->ifmt_string);
1139 
1140 	return ("unknown media");
1141 }
1142 
1143 const char *
1144 get_linkstate(uint8_t if_type, int link_state)
1145 {
1146 	const struct if_status_description *p;
1147 	static char buf[8];
1148 
1149 	for (p = if_status_descriptions; p->ifs_string != NULL; p++) {
1150 		if (LINK_STATE_DESC_MATCH(p, if_type, link_state))
1151 			return (p->ifs_string);
1152 	}
1153 	snprintf(buf, sizeof(buf), "[#%d]", link_state);
1154 	return (buf);
1155 }
1156 
1157 const char *
1158 get_baudrate(u_int64_t baudrate, char *unit)
1159 {
1160 	static char bbuf[16];
1161 
1162 	if (baudrate > IF_Gbps(1))
1163 		snprintf(bbuf, sizeof(bbuf), "%llu G%s",
1164 		    baudrate / IF_Gbps(1), unit);
1165 	else if (baudrate > IF_Mbps(1))
1166 		snprintf(bbuf, sizeof(bbuf), "%llu M%s",
1167 		    baudrate / IF_Mbps(1), unit);
1168 	else if (baudrate > IF_Kbps(1))
1169 		snprintf(bbuf, sizeof(bbuf), "%llu K%s",
1170 		    baudrate / IF_Kbps(1), unit);
1171 	else
1172 		snprintf(bbuf, sizeof(bbuf), "%llu %s",
1173 		    baudrate, unit);
1174 
1175 	return (bbuf);
1176 }
1177 
1178 int
1179 show_interface_msg(struct imsg *imsg)
1180 {
1181 	struct kif	*k;
1182 	uint64_t	 ifms_type;
1183 
1184 	switch (imsg->hdr.type) {
1185 	case IMSG_CTL_SHOW_INTERFACE:
1186 		k = imsg->data;
1187 		printf("%-15s", k->ifname);
1188 		printf("%-15s", k->nh_reachable ? "ok" : "invalid");
1189 		printf("%-15s", k->flags & IFF_UP ? "UP" : "");
1190 
1191 		if ((ifms_type = ift2ifm(k->if_type)) != 0)
1192 			printf("%s, ", get_media_descr(ifms_type));
1193 
1194 		printf("%s", get_linkstate(k->if_type, k->link_state));
1195 
1196 		if (k->link_state != LINK_STATE_DOWN && k->baudrate > 0)
1197 			printf(", %s", get_baudrate(k->baudrate, "Bit/s"));
1198 		printf("\n");
1199 		break;
1200 	case IMSG_CTL_END:
1201 		return (1);
1202 		break;
1203 	default:
1204 		break;
1205 	}
1206 
1207 	return (0);
1208 }
1209 
1210 void
1211 show_rib_summary_head(void)
1212 {
1213 	printf("flags: * = Valid, > = Selected, I = via IBGP, A = Announced, "
1214 	    "S = Stale\n");
1215 	printf("origin: i = IGP, e = EGP, ? = Incomplete\n\n");
1216 	printf("%-5s %-20s %-15s  %5s %5s %s\n", "flags", "destination",
1217 	    "gateway", "lpref", "med", "aspath origin");
1218 }
1219 
1220 void
1221 print_prefix(struct bgpd_addr *prefix, u_int8_t prefixlen, u_int8_t flags)
1222 {
1223 	char			*p;
1224 
1225 	print_flags(flags, 1);
1226 	if (asprintf(&p, "%s/%u", log_addr(prefix), prefixlen) == -1)
1227 		err(1, NULL);
1228 	printf("%-20s", p);
1229 	free(p);
1230 }
1231 
1232 const char *
1233 print_origin(u_int8_t origin, int sum)
1234 {
1235 	switch (origin) {
1236 	case ORIGIN_IGP:
1237 		return (sum ? "i" : "IGP");
1238 	case ORIGIN_EGP:
1239 		return (sum ? "e" : "EGP");
1240 	case ORIGIN_INCOMPLETE:
1241 		return (sum ? "?" : "incomplete");
1242 	default:
1243 		return (sum ? "X" : "bad origin");
1244 	}
1245 }
1246 
1247 void
1248 print_flags(u_int8_t flags, int sum)
1249 {
1250 	char	 flagstr[5];
1251 	char	*p = flagstr;
1252 
1253 	if (sum) {
1254 		if (flags & F_PREF_ANNOUNCE)
1255 			*p++ = 'A';
1256 		if (flags & F_PREF_INTERNAL)
1257 			*p++ = 'I';
1258 		if (flags & F_PREF_STALE)
1259 			*p++ = 'S';
1260 		if (flags & F_PREF_ELIGIBLE)
1261 			*p++ = '*';
1262 		if (flags & F_PREF_ACTIVE)
1263 			*p++ = '>';
1264 		*p = '\0';
1265 		printf("%-5s ", flagstr);
1266 	} else {
1267 		if (flags & F_PREF_INTERNAL)
1268 			printf("internal");
1269 		else
1270 			printf("external");
1271 		if (flags & F_PREF_STALE)
1272 			printf(", stale");
1273 		if (flags & F_PREF_ELIGIBLE)
1274 			printf(", valid");
1275 		if (flags & F_PREF_ACTIVE)
1276 			printf(", best");
1277 		if (flags & F_PREF_ANNOUNCE)
1278 			printf(", announced");
1279 	}
1280 }
1281 
1282 int
1283 show_rib_summary_msg(struct imsg *imsg)
1284 {
1285 	struct ctl_show_rib	 rib;
1286 	u_char			*asdata;
1287 
1288 	switch (imsg->hdr.type) {
1289 	case IMSG_CTL_SHOW_RIB:
1290 		memcpy(&rib, imsg->data, sizeof(rib));
1291 		asdata = imsg->data;
1292 		asdata += sizeof(struct ctl_show_rib);
1293 		show_rib_brief(&rib, asdata);
1294 		break;
1295 	case IMSG_CTL_END:
1296 		return (1);
1297 	default:
1298 		break;
1299 	}
1300 
1301 	return (0);
1302 }
1303 
1304 int
1305 show_rib_detail_msg(struct imsg *imsg, int nodescr)
1306 {
1307 	struct ctl_show_rib	 rib;
1308 	u_char			*asdata;
1309 	u_int16_t		 ilen;
1310 
1311 	switch (imsg->hdr.type) {
1312 	case IMSG_CTL_SHOW_RIB:
1313 		memcpy(&rib, imsg->data, sizeof(rib));
1314 		asdata = imsg->data;
1315 		asdata += sizeof(struct ctl_show_rib);
1316 		show_rib_detail(&rib, asdata, nodescr);
1317 		break;
1318 	case IMSG_CTL_SHOW_RIB_ATTR:
1319 		ilen = imsg->hdr.len - IMSG_HEADER_SIZE;
1320 		if (ilen < 3)
1321 			errx(1, "bad IMSG_CTL_SHOW_RIB_ATTR received");
1322 		show_attr(imsg->data, ilen);
1323 		break;
1324 	case IMSG_CTL_END:
1325 		printf("\n");
1326 		return (1);
1327 	default:
1328 		break;
1329 	}
1330 
1331 	return (0);
1332 }
1333 
1334 void
1335 show_rib_brief(struct ctl_show_rib *r, u_char *asdata)
1336 {
1337 	char			*aspath;
1338 
1339 	print_prefix(&r->prefix, r->prefixlen, r->flags);
1340 	printf(" %-15s ", log_addr(&r->exit_nexthop));
1341 	printf(" %5u %5u ", r->local_pref, r->med);
1342 
1343 	if (aspath_asprint(&aspath, asdata, r->aspath_len) == -1)
1344 		err(1, NULL);
1345 	if (strlen(aspath) > 0)
1346 		printf("%s ", aspath);
1347 	free(aspath);
1348 
1349 	printf("%s\n", print_origin(r->origin, 1));
1350 }
1351 
1352 void
1353 show_rib_detail(struct ctl_show_rib *r, u_char *asdata, int nodescr)
1354 {
1355 	struct in_addr		 id;
1356 	char			*aspath, *s;
1357 	time_t			 now;
1358 
1359 	printf("\nBGP routing table entry for %s/%u\n",
1360 	    log_addr(&r->prefix), r->prefixlen);
1361 
1362 	if (aspath_asprint(&aspath, asdata, r->aspath_len) == -1)
1363 		err(1, NULL);
1364 	if (strlen(aspath) > 0)
1365 		printf("    %s\n", aspath);
1366 	free(aspath);
1367 
1368 	s = fmt_peer(r->descr, &r->remote_addr, -1, nodescr);
1369 	printf("    Nexthop %s ", log_addr(&r->exit_nexthop));
1370 	printf("(via %s) from %s (", log_addr(&r->true_nexthop), s);
1371 	free(s);
1372 	id.s_addr = htonl(r->remote_id);
1373 	printf("%s)\n", inet_ntoa(id));
1374 
1375 	printf("    Origin %s, metric %u, localpref %u, weight %u, ",
1376 	    print_origin(r->origin, 0), r->med, r->local_pref, r->weight);
1377 	print_flags(r->flags, 0);
1378 
1379 	now = time(NULL);
1380 	if (now > r->lastchange)
1381 		now -= r->lastchange;
1382 	else
1383 		now = 0;
1384 
1385 	printf("\n    Last update: %s ago\n", fmt_timeframe_core(now));
1386 }
1387 
1388 void
1389 show_attr(void *b, u_int16_t len)
1390 {
1391 	char		*data = b;
1392 	struct in_addr	 id;
1393 	u_int32_t	 as;
1394 	u_int16_t	 alen, ioff;
1395 	u_int8_t	 flags, type;
1396 
1397 	if (len < 3)
1398 		errx(1, "show_attr: too short bgp attr");
1399 
1400 	flags = data[0];
1401 	type = data[1];
1402 
1403 	/* get the attribute length */
1404 	if (flags & ATTR_EXTLEN) {
1405 		if (len < 4)
1406 			errx(1, "show_attr: too short bgp attr");
1407 		memcpy(&alen, data+2, sizeof(u_int16_t));
1408 		alen = ntohs(alen);
1409 		data += 4;
1410 		len -= 4;
1411 	} else {
1412 		alen = (u_char)data[2];
1413 		data += 3;
1414 		len -= 3;
1415 	}
1416 
1417 	/* bad imsg len how can that happen!? */
1418 	if (alen > len)
1419 		errx(1, "show_attr: bad length");
1420 
1421 	switch (type) {
1422 	case ATTR_COMMUNITIES:
1423 		printf("    Communities: ");
1424 		show_community(data, alen);
1425 		printf("\n");
1426 		break;
1427 	case ATTR_AGGREGATOR:
1428 		memcpy(&as, data, sizeof(as));
1429 		memcpy(&id, data + sizeof(as), sizeof(id));
1430 		printf("    Aggregator: %s [%s]\n",
1431 		    log_as(ntohl(as)), inet_ntoa(id));
1432 		break;
1433 	case ATTR_ORIGINATOR_ID:
1434 		memcpy(&id, data, sizeof(id));
1435 		printf("    Originator Id: %s\n", inet_ntoa(id));
1436 		break;
1437 	case ATTR_CLUSTER_LIST:
1438 		printf("    Cluster ID List:");
1439 		for (ioff = 0; ioff + sizeof(id) <= alen;
1440 		    ioff += sizeof(id)) {
1441 			memcpy(&id, data + ioff, sizeof(id));
1442 			printf(" %s", inet_ntoa(id));
1443 		}
1444 		printf("\n");
1445 		break;
1446 	case ATTR_EXT_COMMUNITIES:
1447 		printf("    Ext. communities: ");
1448 		show_ext_community(data, alen);
1449 		printf("\n");
1450 		break;
1451 	default:
1452 		/* ignore unknown attributes */
1453 		break;
1454 	}
1455 }
1456 
1457 void
1458 show_community(u_char *data, u_int16_t len)
1459 {
1460 	u_int16_t	a, v;
1461 	u_int16_t	i;
1462 
1463 	if (len & 0x3)
1464 		return;
1465 
1466 	for (i = 0; i < len; i += 4) {
1467 		memcpy(&a, data + i, sizeof(a));
1468 		memcpy(&v, data + i + 2, sizeof(v));
1469 		a = ntohs(a);
1470 		v = ntohs(v);
1471 		if (a == COMMUNITY_WELLKNOWN)
1472 			switch (v) {
1473 			case COMMUNITY_NO_EXPORT:
1474 				printf("NO_EXPORT");
1475 				break;
1476 			case COMMUNITY_NO_ADVERTISE:
1477 				printf("NO_ADVERTISE");
1478 				break;
1479 			case COMMUNITY_NO_EXPSUBCONFED:
1480 				printf("NO_EXPORT_SUBCONFED");
1481 				break;
1482 			case COMMUNITY_NO_PEER:
1483 				printf("NO_PEER");
1484 				break;
1485 			case COMMUNITY_BLACKHOLE:
1486 				printf("BLACKHOLE");
1487 				break;
1488 			default:
1489 				printf("WELLKNOWN:%hu", v);
1490 				break;
1491 			}
1492 		else
1493 			printf("%hu:%hu", a, v);
1494 
1495 		if (i + 4 < len)
1496 			printf(" ");
1497 	}
1498 }
1499 
1500 void
1501 show_ext_community(u_char *data, u_int16_t len)
1502 {
1503 	u_int64_t	ext;
1504 	struct in_addr	ip;
1505 	u_int32_t	as4, u32;
1506 	u_int16_t	i, as2, u16;
1507 	u_int8_t	type, subtype;
1508 
1509 	if (len & 0x7)
1510 		return;
1511 
1512 	for (i = 0; i < len; i += 8) {
1513 		type = data[i];
1514 		subtype = data[i + 1];
1515 
1516 		switch (type & EXT_COMMUNITY_VALUE) {
1517 		case EXT_COMMUNITY_TWO_AS:
1518 			memcpy(&as2, data + i + 2, sizeof(as2));
1519 			memcpy(&u32, data + i + 4, sizeof(u32));
1520 			printf("%s %s:%u", log_ext_subtype(subtype),
1521 			    log_as(ntohs(as2)), ntohl(u32));
1522 			break;
1523 		case EXT_COMMUNITY_IPV4:
1524 			memcpy(&ip, data + i + 2, sizeof(ip));
1525 			memcpy(&u16, data + i + 6, sizeof(u16));
1526 			printf("%s %s:%hu", log_ext_subtype(subtype),
1527 			    inet_ntoa(ip), ntohs(u16));
1528 			break;
1529 		case EXT_COMMUNITY_FOUR_AS:
1530 			memcpy(&as4, data + i + 2, sizeof(as4));
1531 			memcpy(&u16, data + i + 6, sizeof(u16));
1532 			printf("%s %s:%hu", log_ext_subtype(subtype),
1533 			    log_as(ntohl(as4)), ntohs(u16));
1534 			break;
1535 		case EXT_COMMUNITY_OPAQUE:
1536 			memcpy(&ext, data + i, sizeof(ext));
1537 			ext = betoh64(ext) & 0xffffffffffffLL;
1538 			printf("%s 0x%llx", log_ext_subtype(subtype), ext);
1539 			break;
1540 		default:
1541 			memcpy(&ext, data + i, sizeof(ext));
1542 			printf("0x%llx", betoh64(ext));
1543 		}
1544 		if (i + 8 < len)
1545 			printf(", ");
1546 	}
1547 }
1548 
1549 char *
1550 fmt_mem(int64_t num)
1551 {
1552 	static char	buf[16];
1553 
1554 	if (fmt_scaled(num, buf) == -1)
1555 		snprintf(buf, sizeof(buf), "%lldB", (long long)num);
1556 
1557 	return (buf);
1558 }
1559 
1560 size_t  pt_sizes[AID_MAX] = AID_PTSIZE;
1561 
1562 int
1563 show_rib_memory_msg(struct imsg *imsg)
1564 {
1565 	struct rde_memstats	stats;
1566 	size_t			pts = 0;
1567 	int			i;
1568 
1569 	switch (imsg->hdr.type) {
1570 	case IMSG_CTL_SHOW_RIB_MEM:
1571 		memcpy(&stats, imsg->data, sizeof(stats));
1572 		printf("RDE memory statistics\n");
1573 		for (i = 0; i < AID_MAX; i++) {
1574 			if (stats.pt_cnt[i] == 0)
1575 				continue;
1576 			pts += stats.pt_cnt[i] * pt_sizes[i];
1577 			printf("%10lld %s network entries using %s of memory\n",
1578 			    (long long)stats.pt_cnt[i], aid_vals[i].name,
1579 			    fmt_mem(stats.pt_cnt[i] * pt_sizes[i]));
1580 		}
1581 		printf("%10lld rib entries using %s of memory\n",
1582 		    (long long)stats.rib_cnt, fmt_mem(stats.rib_cnt *
1583 		    sizeof(struct rib_entry)));
1584 		printf("%10lld prefix entries using %s of memory\n",
1585 		    (long long)stats.prefix_cnt, fmt_mem(stats.prefix_cnt *
1586 		    sizeof(struct prefix)));
1587 		printf("%10lld BGP path attribute entries using %s of memory\n",
1588 		    (long long)stats.path_cnt, fmt_mem(stats.path_cnt *
1589 		    sizeof(struct rde_aspath)));
1590 		printf("%10lld BGP AS-PATH attribute entries using "
1591 		    "%s of memory,\n\t   and holding %lld references\n",
1592 		    (long long)stats.aspath_cnt, fmt_mem(stats.aspath_size),
1593 		    (long long)stats.aspath_refs);
1594 		printf("%10lld BGP attributes entries using %s of memory\n",
1595 		    (long long)stats.attr_cnt, fmt_mem(stats.attr_cnt *
1596 		    sizeof(struct attr)));
1597 		printf("\t   and holding %lld references\n",
1598 		    (long long)stats.attr_refs);
1599 		printf("%10lld BGP attributes using %s of memory\n",
1600 		    (long long)stats.attr_dcnt, fmt_mem(stats.attr_data));
1601 		printf("RIB using %s of memory\n", fmt_mem(pts +
1602 		    stats.prefix_cnt * sizeof(struct prefix) +
1603 		    stats.rib_cnt * sizeof(struct rib_entry) +
1604 		    stats.path_cnt * sizeof(struct rde_aspath) +
1605 		    stats.aspath_size + stats.attr_cnt * sizeof(struct attr) +
1606 		    stats.attr_data));
1607 		break;
1608 	default:
1609 		break;
1610 	}
1611 
1612 	return (1);
1613 }
1614 
1615 void
1616 send_filterset(struct imsgbuf *i, struct filter_set_head *set)
1617 {
1618 	struct filter_set	*s;
1619 
1620 	while ((s = TAILQ_FIRST(set)) != NULL) {
1621 		imsg_compose(i, IMSG_FILTER_SET, 0, 0, -1, s,
1622 		    sizeof(struct filter_set));
1623 		TAILQ_REMOVE(set, s, entry);
1624 		free(s);
1625 	}
1626 }
1627 
1628 const char *
1629 get_errstr(u_int8_t errcode, u_int8_t subcode)
1630 {
1631 	static const char	*errstr = NULL;
1632 
1633 	if (errcode && errcode < sizeof(errnames)/sizeof(char *))
1634 		errstr = errnames[errcode];
1635 
1636 	switch (errcode) {
1637 	case ERR_HEADER:
1638 		if (subcode &&
1639 		    subcode < sizeof(suberr_header_names)/sizeof(char *))
1640 			errstr = suberr_header_names[subcode];
1641 		break;
1642 	case ERR_OPEN:
1643 		if (subcode &&
1644 		    subcode < sizeof(suberr_open_names)/sizeof(char *))
1645 			errstr = suberr_open_names[subcode];
1646 		break;
1647 	case ERR_UPDATE:
1648 		if (subcode &&
1649 		    subcode < sizeof(suberr_update_names)/sizeof(char *))
1650 			errstr = suberr_update_names[subcode];
1651 		break;
1652 	case ERR_HOLDTIMEREXPIRED:
1653 	case ERR_FSM:
1654 	case ERR_CEASE:
1655 		break;
1656 	default:
1657 		return ("unknown error code");
1658 	}
1659 
1660 	return (errstr);
1661 }
1662 
1663 int
1664 show_result(struct imsg *imsg)
1665 {
1666 	u_int	rescode;
1667 
1668 	if (imsg->hdr.len != IMSG_HEADER_SIZE + sizeof(rescode))
1669 		errx(1, "got IMSG_CTL_RESULT with wrong len");
1670 	memcpy(&rescode, imsg->data, sizeof(rescode));
1671 
1672 	if (rescode == 0)
1673 		printf("request processed\n");
1674 	else {
1675 		if (rescode >
1676 		    sizeof(ctl_res_strerror)/sizeof(ctl_res_strerror[0]))
1677 			printf("unknown result error code %u\n", rescode);
1678 		else
1679 			printf("%s\n", ctl_res_strerror[rescode]);
1680 	}
1681 
1682 	return (1);
1683 }
1684 
1685 void
1686 network_bulk(struct parse_result *res)
1687 {
1688 	struct network_config net;
1689 	struct filter_set *s = NULL;
1690 	struct bgpd_addr h;
1691 	char *b, *buf, *lbuf;
1692 	size_t slen;
1693 	u_int8_t len;
1694 	FILE *f;
1695 
1696 	if ((f = fdopen(STDIN_FILENO, "r")) != NULL) {
1697 		while ((buf = fgetln(f, &slen))) {
1698 			lbuf = NULL;
1699 			if (buf[slen - 1] == '\n')
1700 				buf[slen - 1] = '\0';
1701 			else {
1702 				if ((lbuf = malloc(slen + 1)) == NULL)
1703 					err(1, NULL);
1704 				memcpy(lbuf, buf, slen);
1705 				lbuf[slen] = '\0';
1706 				buf = lbuf;
1707 			}
1708 
1709 			while ((b = strsep(&buf, " \t")) != NULL) {
1710 				/* Don't process commented entries */
1711 				if (strchr(b, '#') != NULL)
1712 					break;
1713 				bzero(&net, sizeof(net));
1714 				parse_prefix(b, strlen(b), &h, &len);
1715 				memcpy(&net.prefix, &h, sizeof(h));
1716 				net.prefixlen = len;
1717 
1718 				if (res->action == NETWORK_BULK_ADD) {
1719 					imsg_compose(ibuf, IMSG_NETWORK_ADD,
1720 					    0, 0, -1, &net, sizeof(net));
1721 					TAILQ_FOREACH(s, &res->set, entry) {
1722 						imsg_compose(ibuf,
1723 						    IMSG_FILTER_SET,
1724 						    0, 0, -1, s, sizeof(*s));
1725 					}
1726 					imsg_compose(ibuf, IMSG_NETWORK_DONE,
1727 					    0, 0, -1, NULL, 0);
1728 				} else
1729 					imsg_compose(ibuf, IMSG_NETWORK_REMOVE,
1730 					     0, 0, -1, &net, sizeof(net));
1731 			}
1732 			free(lbuf);
1733 		}
1734 		fclose(f);
1735 	} else {
1736 		err(1, "Failed to open stdin\n");
1737 	}
1738 }
1739 
1740 void
1741 show_mrt_dump(struct mrt_rib *mr, struct mrt_peer *mp, void *arg)
1742 {
1743 	struct ctl_show_rib		 ctl;
1744 	struct ctl_show_rib_request	*req = arg;
1745 	struct mrt_rib_entry		*mre;
1746 	u_int16_t			 i, j;
1747 
1748 	for (i = 0; i < mr->nentries; i++) {
1749 		mre = &mr->entries[i];
1750 		bzero(&ctl, sizeof(ctl));
1751 		mrt_to_bgpd_addr(&mr->prefix, &ctl.prefix);
1752 		ctl.prefixlen = mr->prefixlen;
1753 		ctl.lastchange = mre->originated;
1754 		mrt_to_bgpd_addr(&mre->nexthop, &ctl.true_nexthop);
1755 		mrt_to_bgpd_addr(&mre->nexthop, &ctl.exit_nexthop);
1756 		ctl.origin = mre->origin;
1757 		ctl.local_pref = mre->local_pref;
1758 		ctl.med = mre->med;
1759 		/* weight is not part of the mrt dump so it can't be set */
1760 		ctl.aspath_len = mre->aspath_len;
1761 
1762 		if (mre->peer_idx < mp->npeers) {
1763 			mrt_to_bgpd_addr(&mp->peers[mre->peer_idx].addr,
1764 			    &ctl.remote_addr);
1765 			ctl.remote_id = mp->peers[mre->peer_idx].bgp_id;
1766 		}
1767 
1768 		/* filter by neighbor */
1769 		if (req->neighbor.addr.aid != AID_UNSPEC &&
1770 		    memcmp(&req->neighbor.addr, &ctl.remote_addr,
1771 		    sizeof(ctl.remote_addr)) != 0)
1772 			continue;
1773 		/* filter by AF */
1774 		if (req->aid && req->aid != ctl.prefix.aid)
1775 			return;
1776 		/* filter by prefix */
1777 		if (req->prefix.aid != AID_UNSPEC) {
1778 			if (!prefix_compare(&req->prefix, &ctl.prefix,
1779 			    req->prefixlen)) {
1780 				if (req->flags & F_LONGER) {
1781 					if (req->prefixlen > ctl.prefixlen)
1782 						return;
1783 				} else if (req->prefixlen != ctl.prefixlen)
1784 					return;
1785 			} else
1786 				return;
1787 		}
1788 		/* filter by AS */
1789 		if (req->as.type != AS_NONE &&
1790 		   !aspath_match(mre->aspath, mre->aspath_len,
1791 		   req->as.type, req->as.as))
1792 			continue;
1793 
1794 		if (req->flags & F_CTL_DETAIL) {
1795 			show_rib_detail(&ctl, mre->aspath, 1);
1796 			for (j = 0; j < mre->nattrs; j++)
1797 				show_attr(mre->attrs[j].attr,
1798 					mre->attrs[j].attr_len);
1799 		} else
1800 			show_rib_brief(&ctl, mre->aspath);
1801 	}
1802 }
1803 
1804 void
1805 network_mrt_dump(struct mrt_rib *mr, struct mrt_peer *mp, void *arg)
1806 {
1807 	struct ctl_show_rib		 ctl;
1808 	struct network_config		 net;
1809 	struct ctl_show_rib_request	*req = arg;
1810 	struct mrt_rib_entry		*mre;
1811 	struct ibuf			*msg;
1812 	u_int16_t			 i, j;
1813 
1814 	for (i = 0; i < mr->nentries; i++) {
1815 		mre = &mr->entries[i];
1816 		bzero(&ctl, sizeof(ctl));
1817 		mrt_to_bgpd_addr(&mr->prefix, &ctl.prefix);
1818 		ctl.prefixlen = mr->prefixlen;
1819 		ctl.lastchange = mre->originated;
1820 		mrt_to_bgpd_addr(&mre->nexthop, &ctl.true_nexthop);
1821 		mrt_to_bgpd_addr(&mre->nexthop, &ctl.exit_nexthop);
1822 		ctl.origin = mre->origin;
1823 		ctl.local_pref = mre->local_pref;
1824 		ctl.med = mre->med;
1825 		ctl.aspath_len = mre->aspath_len;
1826 
1827 		if (mre->peer_idx < mp->npeers) {
1828 			mrt_to_bgpd_addr(&mp->peers[mre->peer_idx].addr,
1829 			    &ctl.remote_addr);
1830 			ctl.remote_id = mp->peers[mre->peer_idx].bgp_id;
1831 		}
1832 
1833 		/* filter by neighbor */
1834 		if (req->neighbor.addr.aid != AID_UNSPEC &&
1835 		    memcmp(&req->neighbor.addr, &ctl.remote_addr,
1836 		    sizeof(ctl.remote_addr)) != 0)
1837 			continue;
1838 		/* filter by AF */
1839 		if (req->aid && req->aid != ctl.prefix.aid)
1840 			return;
1841 		/* filter by prefix */
1842 		if (req->prefix.aid != AID_UNSPEC) {
1843 			if (!prefix_compare(&req->prefix, &ctl.prefix,
1844 			    req->prefixlen)) {
1845 				if (req->flags & F_LONGER) {
1846 					if (req->prefixlen > ctl.prefixlen)
1847 						return;
1848 				} else if (req->prefixlen != ctl.prefixlen)
1849 					return;
1850 			} else
1851 				return;
1852 		}
1853 		/* filter by AS */
1854 		if (req->as.type != AS_NONE &&
1855 		   !aspath_match(mre->aspath, mre->aspath_len,
1856 		   req->as.type, req->as.as))
1857 			continue;
1858 
1859 		bzero(&net, sizeof(net));
1860 		memcpy(&net.prefix, &ctl.prefix, sizeof(net.prefix));
1861 		net.prefixlen = ctl.prefixlen;
1862 		net.type = NETWORK_MRTCLONE;
1863 		/* XXX rtableid */
1864 
1865 		imsg_compose(ibuf, IMSG_NETWORK_ADD, 0, 0, -1,
1866 		    &net, sizeof(net));
1867 		if ((msg = imsg_create(ibuf, IMSG_NETWORK_ASPATH,
1868 		    0, 0, sizeof(ctl) + mre->aspath_len)) == NULL)
1869 			errx(1, "imsg_create failure");
1870 		if (imsg_add(msg, &ctl, sizeof(ctl)) == -1 ||
1871 		    imsg_add(msg, mre->aspath, mre->aspath_len) == -1)
1872 			errx(1, "imsg_add failure");
1873 		imsg_close(ibuf, msg);
1874 		for (j = 0; j < mre->nattrs; j++)
1875 			imsg_compose(ibuf, IMSG_NETWORK_ATTR, 0, 0, -1,
1876 			    mre->attrs[j].attr, mre->attrs[j].attr_len);
1877 		imsg_compose(ibuf, IMSG_NETWORK_DONE, 0, 0, -1, NULL, 0);
1878 
1879 		while (ibuf->w.queued) {
1880 			if (msgbuf_write(&ibuf->w) <= 0 && errno != EAGAIN)
1881 				err(1, "write error");
1882 		}
1883 	}
1884 }
1885 
1886 void
1887 show_mrt_state(struct mrt_bgp_state *ms, void *arg)
1888 {
1889 	struct bgpd_addr src, dst;
1890 
1891 	mrt_to_bgpd_addr(&ms->src, &src);
1892 	mrt_to_bgpd_addr(&ms->dst, &dst);
1893 	printf("%s[%u] -> ", log_addr(&src), ms->src_as);
1894 	printf("%s[%u]: %s -> %s\n", log_addr(&dst), ms->dst_as,
1895 	    statenames[ms->old_state], statenames[ms->new_state]);
1896 }
1897 
1898 void
1899 show_mrt_msg(struct mrt_bgp_msg *mm, void *arg)
1900 {
1901 	struct bgpd_addr src, dst;
1902 
1903 	mrt_to_bgpd_addr(&mm->src, &src);
1904 	mrt_to_bgpd_addr(&mm->dst, &dst);
1905 	printf("%s[%u] -> ", log_addr(&src), mm->src_as);
1906 	printf("%s[%u]: size %u\n", log_addr(&dst), mm->dst_as, mm->msg_len);
1907 }
1908 
1909 void
1910 mrt_to_bgpd_addr(union mrt_addr *ma, struct bgpd_addr *ba)
1911 {
1912 	switch (ma->sa.sa_family) {
1913 	case AF_INET:
1914 	case AF_INET6:
1915 		sa2addr(&ma->sa, ba);
1916 		break;
1917 	case AF_VPNv4:
1918 		bzero(ba, sizeof(*ba));
1919 		ba->aid = AID_VPN_IPv4;
1920 		ba->vpn4.rd = ma->svpn4.sv_rd;
1921 		ba->vpn4.addr.s_addr = ma->svpn4.sv_addr.s_addr;
1922 		memcpy(ba->vpn4.labelstack, ma->svpn4.sv_label,
1923 		    sizeof(ba->vpn4.labelstack));
1924 		break;
1925 	}
1926 }
1927 
1928 const char *
1929 msg_type(u_int8_t type)
1930 {
1931 	if (type >= sizeof(msgtypenames)/sizeof(msgtypenames[0]))
1932 		return "BAD";
1933 	return (msgtypenames[type]);
1934 }
1935 
1936 /* following functions are necessary for the imsg framework */
1937 void
1938 log_warnx(const char *emsg, ...)
1939 {
1940 	va_list	 ap;
1941 
1942 	va_start(ap, emsg);
1943 	vwarnx(emsg, ap);
1944 	va_end(ap);
1945 }
1946 
1947 void
1948 log_warn(const char *emsg, ...)
1949 {
1950 	va_list	 ap;
1951 
1952 	va_start(ap, emsg);
1953 	vwarn(emsg, ap);
1954 	va_end(ap);
1955 }
1956 
1957 void
1958 fatal(const char *emsg, ...)
1959 {
1960 	va_list	 ap;
1961 
1962 	va_start(ap, emsg);
1963 	verr(1, emsg, ap);
1964 	va_end(ap);
1965 }
1966 
1967 void
1968 fatalx(const char *emsg)
1969 {
1970 	errx(1, "%s", emsg);
1971 }
1972