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