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