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

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