GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/bgplg/bgpctl/../../../usr.sbin/bgpctl/bgpctl.c Lines: 0 1082 0.0 %
Date: 2017-11-07 Branches: 0 652 0.0 %

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