xref: /openbsd-src/usr.sbin/bgpctl/bgpctl.c (revision b3b12989e092569d8b673c55a17258692d7c68e9)
1*b3b12989Sclaudio /*	$OpenBSD: bgpctl.c,v 1.314 2024/12/16 16:10:46 claudio Exp $ */
2fd0978b9Shenning 
3fd0978b9Shenning /*
4fd0978b9Shenning  * Copyright (c) 2003 Henning Brauer <henning@openbsd.org>
56671ac0bSclaudio  * Copyright (c) 2004-2019 Claudio Jeker <claudio@openbsd.org>
6280f24a4Sphessler  * Copyright (c) 2016 Job Snijders <job@instituut.net>
7280f24a4Sphessler  * Copyright (c) 2016 Peter Hessler <phessler@openbsd.org>
8fd0978b9Shenning  *
9fd0978b9Shenning  * Permission to use, copy, modify, and distribute this software for any
10fd0978b9Shenning  * purpose with or without fee is hereby granted, provided that the above
11fd0978b9Shenning  * copyright notice and this permission notice appear in all copies.
12fd0978b9Shenning  *
13fd0978b9Shenning  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
14fd0978b9Shenning  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15fd0978b9Shenning  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
16fd0978b9Shenning  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17fd0978b9Shenning  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18fd0978b9Shenning  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
19fd0978b9Shenning  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20fd0978b9Shenning  */
21fd0978b9Shenning 
2289cb8daeSclaudio #include <sys/time.h>
23fd0978b9Shenning #include <sys/types.h>
24fd0978b9Shenning #include <sys/socket.h>
258d7b500cSbenno #include <sys/stat.h>
26fd0978b9Shenning #include <sys/un.h>
271b3c4f02Shenning 
28bb4118bdSclaudio #include <endian.h>
29fd0978b9Shenning #include <err.h>
30c0dbf5cfSsthen #include <errno.h>
310ac5a32aSphessler #include <fcntl.h>
323afc9eb1Sclaudio #include <math.h>
33fd0978b9Shenning #include <stdio.h>
34fb57b3f9Shenning #include <stdlib.h>
35fd0978b9Shenning #include <string.h>
3685411ad9Sclaudio #include <time.h>
37fd0978b9Shenning #include <unistd.h>
386c34dfd1Sclaudio #include <util.h>
39fd0978b9Shenning 
40fd0978b9Shenning #include "bgpd.h"
41a0f4a7e3Shenning #include "session.h"
427b6c56a0Sclaudio #include "rde.h"
433eb1af85Sjob #include "version.h"
446671ac0bSclaudio 
456671ac0bSclaudio #include "bgpctl.h"
46acd8015aShenning #include "parser.h"
47a20554fdSclaudio #include "mrtparser.h"
48fde0bae3Shenning 
49fd0978b9Shenning int		 main(int, char *[]);
50f084a78cSclaudio int		 show(struct imsg *, struct parse_result *);
519caec0aeSclaudio void		 send_filterset(struct imsgbuf *, struct filter_set_head *);
52b5cff06cSclaudio void		 show_mrt_dump_neighbors(struct mrt_rib *, struct mrt_peer *,
53b5cff06cSclaudio 		    void *);
54a20554fdSclaudio void		 show_mrt_dump(struct mrt_rib *, struct mrt_peer *, void *);
55f486926aSclaudio void		 network_mrt_dump(struct mrt_rib *, struct mrt_peer *, void *);
56a20554fdSclaudio void		 show_mrt_state(struct mrt_bgp_state *, void *);
57a20554fdSclaudio void		 show_mrt_msg(struct mrt_bgp_msg *, void *);
5859154960Sclaudio const char	*msg_type(uint8_t);
590ac5a32aSphessler void		 network_bulk(struct parse_result *);
6059154960Sclaudio int		 match_aspath(void *, uint16_t, struct filter_as *);
61e3925e28Sclaudio struct flowspec	*res_to_flowspec(struct parse_result *);
620ac5a32aSphessler 
6340466abfSclaudio struct imsgbuf	*imsgbuf;
64a20554fdSclaudio struct mrt_parser show_mrt = { show_mrt_dump, show_mrt_state, show_mrt_msg };
65f486926aSclaudio struct mrt_parser net_mrt = { network_mrt_dump, NULL, NULL };
66d30a810dSclaudio const struct output	*output = &show_output;
6747ffa64dSdenis int tableid;
68f084a78cSclaudio int nodescr;
69fd0978b9Shenning 
70cbb557dbShenning __dead void
71a39dd3f0Shenning usage(void)
72a39dd3f0Shenning {
73a39dd3f0Shenning 	extern char	*__progname;
74a39dd3f0Shenning 
753123221bSclaudio 	fprintf(stderr, "usage: %s [-jnV] [-s socket] command [argument ...]\n",
7666761d00Ssobrado 	    __progname);
77a39dd3f0Shenning 	exit(1);
78a39dd3f0Shenning }
79a39dd3f0Shenning 
80fd0978b9Shenning int
81fd0978b9Shenning main(int argc, char *argv[])
82fd0978b9Shenning {
83f0d589c3Sclaudio 	struct sockaddr_un	 sa_un;
8477a10e6fSclaudio 	int			 fd, n, done, numdone, ch, verbose = 0;
85fd0978b9Shenning 	struct imsg		 imsg;
86a4cb7d77Sclaudio 	struct network_config	 net;
87acd8015aShenning 	struct parse_result	*res;
88fd71c51dShenning 	struct ctl_neighbor	 neighbor;
89ba099d61Sclaudio 	struct ctl_show_rib_request	ribreq;
90e3925e28Sclaudio 	struct flowspec		*f;
912302052bShenning 	char			*sockname;
92ba099d61Sclaudio 	enum imsg_type		 type;
93acd8015aShenning 
94445db22eSbenno 	if (pledge("stdio rpath wpath cpath unix inet dns", NULL) == -1)
95445db22eSbenno 		err(1, "pledge");
96445db22eSbenno 
9747ffa64dSdenis 	tableid = getrtable();
9847ffa64dSdenis 	if (asprintf(&sockname, "%s.%d", SOCKET_NAME, tableid) == -1)
998d7b500cSbenno 		err(1, "asprintf");
1008d7b500cSbenno 
1013eb1af85Sjob 	while ((ch = getopt(argc, argv, "jns:V")) != -1) {
1022ec7f40eShenning 		switch (ch) {
1032ec7f40eShenning 		case 'n':
1042ec7f40eShenning 			if (++nodescr > 1)
1052ec7f40eShenning 				usage();
1062ec7f40eShenning 			break;
10714178ff0Sclaudio 		case 'j':
10814178ff0Sclaudio 			output = &json_output;
10914178ff0Sclaudio 			break;
1108d594bb1Sclaudio 		case 's':
1118d594bb1Sclaudio 			sockname = optarg;
1128d594bb1Sclaudio 			break;
1133eb1af85Sjob 		case 'V':
1143eb1af85Sjob 			fprintf(stderr, "OpenBGPD %s\n", BGPD_VERSION);
1153eb1af85Sjob 			return 0;
1162ec7f40eShenning 		default:
1172ec7f40eShenning 			usage();
1182ec7f40eShenning 			/* NOTREACHED */
1192ec7f40eShenning 		}
1202ec7f40eShenning 	}
1214e9d3417Shenning 	argc -= optind;
1224e9d3417Shenning 	argv += optind;
1232ec7f40eShenning 
124acd8015aShenning 	if ((res = parse(argc, argv)) == NULL)
125acd8015aShenning 		exit(1);
126fd0978b9Shenning 
12730868731Sclaudio 	memcpy(&neighbor.addr, &res->peeraddr, sizeof(neighbor.addr));
12830868731Sclaudio 	strlcpy(neighbor.descr, res->peerdesc, sizeof(neighbor.descr));
129903de74aSclaudio 	neighbor.is_group = res->is_group;
130a78f83ceSderaadt 	strlcpy(neighbor.reason, res->reason, sizeof(neighbor.reason));
13130868731Sclaudio 
13230868731Sclaudio 	switch (res->action) {
13330868731Sclaudio 	case SHOW_MRT:
13430868731Sclaudio 		if (pledge("stdio", NULL) == -1)
13530868731Sclaudio 			err(1, "pledge");
13630868731Sclaudio 
1374a99c744Sclaudio 		memset(&ribreq, 0, sizeof(ribreq));
1389efe3de0Sclaudio 		if (res->as.type != AS_UNDEF)
13930868731Sclaudio 			ribreq.as = res->as;
14030868731Sclaudio 		if (res->addr.aid) {
14130868731Sclaudio 			ribreq.prefix = res->addr;
14230868731Sclaudio 			ribreq.prefixlen = res->prefixlen;
14330868731Sclaudio 		}
144187619b8Sclaudio 		/* XXX currently no communities support */
14530868731Sclaudio 		ribreq.neighbor = neighbor;
14630868731Sclaudio 		ribreq.aid = res->aid;
14730868731Sclaudio 		ribreq.flags = res->flags;
1482f429709Sjob 		ribreq.validation_state = res->validation_state;
14930868731Sclaudio 		show_mrt.arg = &ribreq;
150b5cff06cSclaudio 		if (res->flags & F_CTL_NEIGHBORS)
151b5cff06cSclaudio 			show_mrt.dump = show_mrt_dump_neighbors;
152f084a78cSclaudio 		else
153d30a810dSclaudio 			output->head(res);
15430868731Sclaudio 		mrt_parse(res->mrtfd, &show_mrt, 1);
15530868731Sclaudio 		exit(0);
15630868731Sclaudio 	default:
15730868731Sclaudio 		break;
158ec8f8491Sclaudio 	}
1593503d06eShenning 
160e647dd64Sderaadt 	if (pledge("stdio unix", NULL) == -1)
161bf641d7bSbenno 		err(1, "pledge");
162bf641d7bSbenno 
1635dd784b9Shenning 	if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
164fd0978b9Shenning 		err(1, "control_init: socket");
165fd0978b9Shenning 
1664a99c744Sclaudio 	memset(&sa_un, 0, sizeof(sa_un));
167f0d589c3Sclaudio 	sa_un.sun_family = AF_UNIX;
168f0d589c3Sclaudio 	if (strlcpy(sa_un.sun_path, sockname, sizeof(sa_un.sun_path)) >=
169f0d589c3Sclaudio 	    sizeof(sa_un.sun_path))
1708d594bb1Sclaudio 		errx(1, "socket name too long");
171f0d589c3Sclaudio 	if (connect(fd, (struct sockaddr *)&sa_un, sizeof(sa_un)) == -1)
1728d594bb1Sclaudio 		err(1, "connect: %s", sockname);
173fd0978b9Shenning 
17430868731Sclaudio 	if (pledge("stdio", NULL) == -1)
175bf641d7bSbenno 		err(1, "pledge");
176bf641d7bSbenno 
17740466abfSclaudio 	if ((imsgbuf = malloc(sizeof(struct imsgbuf))) == NULL)
17878d6515aSclaudio 		err(1, NULL);
1795bf6f543Sclaudio 	if (imsgbuf_init(imsgbuf, fd) == -1 ||
1805bf6f543Sclaudio 	    imsgbuf_set_maxsize(imsgbuf, MAX_BGPD_IMSGSIZE) == -1)
181f1b790a5Sclaudio 		err(1, NULL);
1823d6334e3Shenning 	done = 0;
183fd0978b9Shenning 
184acd8015aShenning 	switch (res->action) {
185a7bd0fd3Shenning 	case NONE:
18630868731Sclaudio 	case SHOW_MRT:
187a7bd0fd3Shenning 		usage();
1886d93a853Sclaudio 		/* NOTREACHED */
189fde0bae3Shenning 	case SHOW:
190fde0bae3Shenning 	case SHOW_SUMMARY:
19140466abfSclaudio 		imsg_compose(imsgbuf, IMSG_CTL_SHOW_NEIGHBOR, 0, 0, -1,
19240466abfSclaudio 		    NULL, 0);
193fde0bae3Shenning 		break;
19416fcf8d2Shenning 	case SHOW_SUMMARY_TERSE:
19540466abfSclaudio 		imsg_compose(imsgbuf, IMSG_CTL_SHOW_TERSE, 0, 0, -1, NULL, 0);
19616fcf8d2Shenning 		break;
197fb57b3f9Shenning 	case SHOW_FIB:
198b26dd4adSclaudio 		if (!res->addr.aid) {
199ee979483Sclaudio 			struct ctl_kroute_req	req = { 0 };
200dd4f9aa8Shenning 
201ee979483Sclaudio 			req.af = aid2af(res->aid);
202ee979483Sclaudio 			req.flags = res->flags;
203ee979483Sclaudio 
204ee979483Sclaudio 			imsg_compose(imsgbuf, IMSG_CTL_KROUTE, res->rtableid,
205ee979483Sclaudio 			    0, -1, &req, sizeof(req));
206dd4f9aa8Shenning 		} else
20740466abfSclaudio 			imsg_compose(imsgbuf, IMSG_CTL_KROUTE_ADDR,
20840466abfSclaudio 			    res->rtableid, 0, -1,
20940466abfSclaudio 			    &res->addr, sizeof(res->addr));
210fb57b3f9Shenning 		break;
2117f410e5eSclaudio 	case SHOW_FIB_TABLES:
21240466abfSclaudio 		imsg_compose(imsgbuf, IMSG_CTL_SHOW_FIB_TABLES, 0, 0, -1,
2137f410e5eSclaudio 		    NULL, 0);
214af7abb58Shenning 		break;
21540466abfSclaudio 	case SHOW_NEXTHOP:
21640466abfSclaudio 		imsg_compose(imsgbuf, IMSG_CTL_SHOW_NEXTHOP, res->rtableid,
21740466abfSclaudio 		    0, -1, NULL, 0);
21840466abfSclaudio 		break;
219a8b61ed1Shenning 	case SHOW_INTERFACE:
22040466abfSclaudio 		imsg_compose(imsgbuf, IMSG_CTL_SHOW_INTERFACE, 0, 0, -1,
22140466abfSclaudio 		    NULL, 0);
222a8b61ed1Shenning 		break;
223413f97b7Sclaudio 	case SHOW_SET:
22440466abfSclaudio 		imsg_compose(imsgbuf, IMSG_CTL_SHOW_SET, 0, 0, -1, NULL, 0);
225413f97b7Sclaudio 		break;
22669d2b5abSclaudio 	case SHOW_RTR:
22740466abfSclaudio 		imsg_compose(imsgbuf, IMSG_CTL_SHOW_RTR, 0, 0, -1, NULL, 0);
22869d2b5abSclaudio 		break;
229fde0bae3Shenning 	case SHOW_NEIGHBOR:
230ed99340cShenning 	case SHOW_NEIGHBOR_TIMERS:
2315901a216Sclaudio 	case SHOW_NEIGHBOR_TERSE:
2320d594c94Shenning 		neighbor.show_timers = (res->action == SHOW_NEIGHBOR_TIMERS);
233b26dd4adSclaudio 		if (res->peeraddr.aid || res->peerdesc[0])
23440466abfSclaudio 			imsg_compose(imsgbuf, IMSG_CTL_SHOW_NEIGHBOR, 0, 0, -1,
2354acf9b2eShenning 			    &neighbor, sizeof(neighbor));
236acd8015aShenning 		else
23740466abfSclaudio 			imsg_compose(imsgbuf, IMSG_CTL_SHOW_NEIGHBOR, 0, 0, -1,
23809ad4f82Shenning 			    NULL, 0);
239fde0bae3Shenning 		break;
2407b6c56a0Sclaudio 	case SHOW_RIB:
2414a99c744Sclaudio 		memset(&ribreq, 0, sizeof(ribreq));
242ba099d61Sclaudio 		type = IMSG_CTL_SHOW_RIB;
243b26dd4adSclaudio 		if (res->addr.aid) {
24438500be7Sbenno 			ribreq.prefix = res->addr;
245ba099d61Sclaudio 			ribreq.prefixlen = res->prefixlen;
246ba099d61Sclaudio 			type = IMSG_CTL_SHOW_RIB_PREFIX;
247ba099d61Sclaudio 		}
248187619b8Sclaudio 		if (res->as.type != AS_UNDEF)
249187619b8Sclaudio 			ribreq.as = res->as;
2500ca99656Sclaudio 		if (res->community.flags != 0)
25138500be7Sbenno 			ribreq.community = res->community;
25238500be7Sbenno 		ribreq.neighbor = neighbor;
253a9a0337fSclaudio 		strlcpy(ribreq.rib, res->rib, sizeof(ribreq.rib));
254536c61dcSclaudio 		ribreq.aid = res->aid;
25546daf8ccSclaudio 		ribreq.path_id = res->pathid;
256ba099d61Sclaudio 		ribreq.flags = res->flags;
25740466abfSclaudio 		imsg_compose(imsgbuf, type, 0, 0, -1, &ribreq, sizeof(ribreq));
2587b6c56a0Sclaudio 		break;
2596c34dfd1Sclaudio 	case SHOW_RIB_MEM:
26040466abfSclaudio 		imsg_compose(imsgbuf, IMSG_CTL_SHOW_RIB_MEM, 0, 0, -1, NULL, 0);
2616c34dfd1Sclaudio 		break;
262cbe08412Sclaudio 	case SHOW_METRICS:
26377a10e6fSclaudio 		output = &ometric_output;
26477a10e6fSclaudio 		numdone = 2;
26540466abfSclaudio 		imsg_compose(imsgbuf, IMSG_CTL_SHOW_NEIGHBOR, 0, 0, -1,
26640466abfSclaudio 		    NULL, 0);
26740466abfSclaudio 		imsg_compose(imsgbuf, IMSG_CTL_SHOW_RIB_MEM, 0, 0, -1, NULL, 0);
26877a10e6fSclaudio 		break;
269fa8c3b18Shenning 	case RELOAD:
27040466abfSclaudio 		imsg_compose(imsgbuf, IMSG_CTL_RELOAD, 0, 0, -1,
271a78f83ceSderaadt 		    res->reason, sizeof(res->reason));
272a78f83ceSderaadt 		if (res->reason[0])
273a78f83ceSderaadt 			printf("reload request sent: %s\n", res->reason);
274a78f83ceSderaadt 		else
275fa8c3b18Shenning 			printf("reload request sent.\n");
2765b1876b6Shenning 		break;
2775b1876b6Shenning 	case FIB:
278acd8015aShenning 		errx(1, "action==FIB");
2795b1876b6Shenning 		break;
2805b1876b6Shenning 	case FIB_COUPLE:
28140466abfSclaudio 		imsg_compose(imsgbuf, IMSG_CTL_FIB_COUPLE, res->rtableid, 0, -1,
2827f410e5eSclaudio 		    NULL, 0);
2835b1876b6Shenning 		printf("couple request sent.\n");
2845b1876b6Shenning 		done = 1;
2855b1876b6Shenning 		break;
2865b1876b6Shenning 	case FIB_DECOUPLE:
28740466abfSclaudio 		imsg_compose(imsgbuf, IMSG_CTL_FIB_DECOUPLE, res->rtableid,
28840466abfSclaudio 		    0, -1, NULL, 0);
2895b1876b6Shenning 		printf("decouple request sent.\n");
2905b1876b6Shenning 		done = 1;
2915b1876b6Shenning 		break;
292ca112d92Shenning 	case NEIGHBOR:
293acd8015aShenning 		errx(1, "action==NEIGHBOR");
294ca112d92Shenning 		break;
295ca112d92Shenning 	case NEIGHBOR_UP:
29640466abfSclaudio 		imsg_compose(imsgbuf, IMSG_CTL_NEIGHBOR_UP, 0, 0, -1,
297fd71c51dShenning 		    &neighbor, sizeof(neighbor));
298ca112d92Shenning 		break;
299ca112d92Shenning 	case NEIGHBOR_DOWN:
30040466abfSclaudio 		imsg_compose(imsgbuf, IMSG_CTL_NEIGHBOR_DOWN, 0, 0, -1,
301fd71c51dShenning 		    &neighbor, sizeof(neighbor));
302ca112d92Shenning 		break;
303e5f05614Shenning 	case NEIGHBOR_CLEAR:
30440466abfSclaudio 		imsg_compose(imsgbuf, IMSG_CTL_NEIGHBOR_CLEAR, 0, 0, -1,
305fd71c51dShenning 		    &neighbor, sizeof(neighbor));
306e5f05614Shenning 		break;
307846ad25aShenning 	case NEIGHBOR_RREFRESH:
30840466abfSclaudio 		imsg_compose(imsgbuf, IMSG_CTL_NEIGHBOR_RREFRESH, 0, 0, -1,
309846ad25aShenning 		    &neighbor, sizeof(neighbor));
310846ad25aShenning 		break;
31107820ff6Sclaudio 	case NEIGHBOR_DESTROY:
31240466abfSclaudio 		imsg_compose(imsgbuf, IMSG_CTL_NEIGHBOR_DESTROY, 0, 0, -1,
31307820ff6Sclaudio 		    &neighbor, sizeof(neighbor));
31407820ff6Sclaudio 		break;
3150ac5a32aSphessler 	case NETWORK_BULK_ADD:
3160ac5a32aSphessler 	case NETWORK_BULK_REMOVE:
3170ac5a32aSphessler 		network_bulk(res);
3180ac5a32aSphessler 		printf("requests sent.\n");
3190ac5a32aSphessler 		done = 1;
3200ac5a32aSphessler 		break;
321a4cb7d77Sclaudio 	case NETWORK_ADD:
322a4cb7d77Sclaudio 	case NETWORK_REMOVE:
3234a99c744Sclaudio 		memset(&net, 0, sizeof(net));
32438500be7Sbenno 		net.prefix = res->addr;
325a4cb7d77Sclaudio 		net.prefixlen = res->prefixlen;
326a73789d3Sclaudio 		net.rd = res->rd;
327a4cb7d77Sclaudio 		/* attribute sets are not supported */
3286aa205c5Sclaudio 		if (res->action == NETWORK_ADD) {
32940466abfSclaudio 			imsg_compose(imsgbuf, IMSG_NETWORK_ADD, 0, 0, -1,
330a4cb7d77Sclaudio 			    &net, sizeof(net));
33140466abfSclaudio 			send_filterset(imsgbuf, &res->set);
33240466abfSclaudio 			imsg_compose(imsgbuf, IMSG_NETWORK_DONE, 0, 0, -1,
3336aa205c5Sclaudio 			    NULL, 0);
3346aa205c5Sclaudio 		} else
33540466abfSclaudio 			imsg_compose(imsgbuf, IMSG_NETWORK_REMOVE, 0, 0, -1,
336a4cb7d77Sclaudio 			    &net, sizeof(net));
337a4cb7d77Sclaudio 		printf("request sent.\n");
338a4cb7d77Sclaudio 		done = 1;
339a4cb7d77Sclaudio 		break;
340a4cb7d77Sclaudio 	case NETWORK_FLUSH:
34140466abfSclaudio 		imsg_compose(imsgbuf, IMSG_NETWORK_FLUSH, 0, 0, -1, NULL, 0);
342a4cb7d77Sclaudio 		printf("request sent.\n");
343a4cb7d77Sclaudio 		done = 1;
344a4cb7d77Sclaudio 		break;
345a4cb7d77Sclaudio 	case NETWORK_SHOW:
3464a99c744Sclaudio 		memset(&ribreq, 0, sizeof(ribreq));
347536c61dcSclaudio 		ribreq.aid = res->aid;
348a9a0337fSclaudio 		strlcpy(ribreq.rib, res->rib, sizeof(ribreq.rib));
34940466abfSclaudio 		imsg_compose(imsgbuf, IMSG_CTL_SHOW_NETWORK, 0, 0, -1,
3505fe14a4bSclaudio 		    &ribreq, sizeof(ribreq));
351a4cb7d77Sclaudio 		break;
352f486926aSclaudio 	case NETWORK_MRT:
3534a99c744Sclaudio 		memset(&ribreq, 0, sizeof(ribreq));
3549efe3de0Sclaudio 		if (res->as.type != AS_UNDEF)
35538500be7Sbenno 			ribreq.as = res->as;
356f486926aSclaudio 		if (res->addr.aid) {
35738500be7Sbenno 			ribreq.prefix = res->addr;
358f486926aSclaudio 			ribreq.prefixlen = res->prefixlen;
359f486926aSclaudio 		}
360187619b8Sclaudio 		/* XXX currently no community support */
36138500be7Sbenno 		ribreq.neighbor = neighbor;
362f486926aSclaudio 		ribreq.aid = res->aid;
363f486926aSclaudio 		ribreq.flags = res->flags;
364f486926aSclaudio 		net_mrt.arg = &ribreq;
365f486926aSclaudio 		mrt_parse(res->mrtfd, &net_mrt, 1);
366f486926aSclaudio 		done = 1;
367f486926aSclaudio 		break;
3685fed6b04Sclaudio 	case FLOWSPEC_ADD:
3695fed6b04Sclaudio 	case FLOWSPEC_REMOVE:
370e3925e28Sclaudio 		f = res_to_flowspec(res);
371e3925e28Sclaudio 		/* attribute sets are not supported */
372e3925e28Sclaudio 		if (res->action == FLOWSPEC_ADD) {
37340466abfSclaudio 			imsg_compose(imsgbuf, IMSG_FLOWSPEC_ADD, 0, 0, -1,
374e3925e28Sclaudio 			    f, FLOWSPEC_SIZE + f->len);
37540466abfSclaudio 			send_filterset(imsgbuf, &res->set);
37640466abfSclaudio 			imsg_compose(imsgbuf, IMSG_FLOWSPEC_DONE, 0, 0, -1,
377e3925e28Sclaudio 			    NULL, 0);
378e3925e28Sclaudio 		} else
37940466abfSclaudio 			imsg_compose(imsgbuf, IMSG_FLOWSPEC_REMOVE, 0, 0, -1,
380e3925e28Sclaudio 			    f, FLOWSPEC_SIZE + f->len);
381e3925e28Sclaudio 		printf("request sent.\n");
3825fed6b04Sclaudio 		done = 1;
3835fed6b04Sclaudio 		break;
3845fed6b04Sclaudio 	case FLOWSPEC_FLUSH:
38540466abfSclaudio 		imsg_compose(imsgbuf, IMSG_FLOWSPEC_FLUSH, 0, 0, -1, NULL, 0);
3865fed6b04Sclaudio 		printf("request sent.\n");
3875fed6b04Sclaudio 		done = 1;
3885fed6b04Sclaudio 		break;
3895fed6b04Sclaudio 	case FLOWSPEC_SHOW:
3905fed6b04Sclaudio 		memset(&ribreq, 0, sizeof(ribreq));
391890b8b5dSclaudio 		switch (res->aid) {
392890b8b5dSclaudio 		case AID_INET:
393890b8b5dSclaudio 			ribreq.aid = AID_FLOWSPECv4;
394890b8b5dSclaudio 			break;
395890b8b5dSclaudio 		case AID_INET6:
396890b8b5dSclaudio 			ribreq.aid = AID_FLOWSPECv6;
397890b8b5dSclaudio 			break;
398890b8b5dSclaudio 		case AID_UNSPEC:
3995fed6b04Sclaudio 			ribreq.aid = res->aid;
400890b8b5dSclaudio 			break;
401890b8b5dSclaudio 		default:
402890b8b5dSclaudio 			errx(1, "flowspec family %s currently not supported",
403890b8b5dSclaudio 			    aid2str(res->aid));
404890b8b5dSclaudio 		}
4055fed6b04Sclaudio 		strlcpy(ribreq.rib, res->rib, sizeof(ribreq.rib));
40640466abfSclaudio 		imsg_compose(imsgbuf, IMSG_CTL_SHOW_FLOWSPEC, 0, 0, -1,
4075fed6b04Sclaudio 		    &ribreq, sizeof(ribreq));
4085fed6b04Sclaudio 		break;
409c3319070Sclaudio 	case LOG_VERBOSE:
410c3319070Sclaudio 		verbose = 1;
411c3319070Sclaudio 		/* FALLTHROUGH */
412c3319070Sclaudio 	case LOG_BRIEF:
41340466abfSclaudio 		imsg_compose(imsgbuf, IMSG_CTL_LOG_VERBOSE, 0, 0, -1,
414c3319070Sclaudio 		    &verbose, sizeof(verbose));
415c3319070Sclaudio 		printf("logging request sent.\n");
416c3319070Sclaudio 		done = 1;
417c3319070Sclaudio 		break;
418ba6ea253Shenning 	}
419ba6ea253Shenning 
420d30a810dSclaudio 	output->head(res);
421f084a78cSclaudio 
42277a10e6fSclaudio  again:
423dd7efffeSclaudio 	if (imsgbuf_flush(imsgbuf) == -1)
42477a10e6fSclaudio 		err(1, "write error");
425f0c28eecShenning 
4263d6334e3Shenning 	while (!done) {
42777a10e6fSclaudio 		while (!done) {
42840466abfSclaudio 			if ((n = imsg_get(imsgbuf, &imsg)) == -1)
42909fbff4eSclaudio 				err(1, "imsg_get error");
430b733d123Shenning 			if (n == 0)
431fd0978b9Shenning 				break;
432c2410a5fShenning 
433f084a78cSclaudio 			done = show(&imsg, res);
434c2410a5fShenning 			imsg_free(&imsg);
435f084a78cSclaudio 		}
43677a10e6fSclaudio 
43777a10e6fSclaudio 		if (done)
43877a10e6fSclaudio 			break;
43977a10e6fSclaudio 
440dd7efffeSclaudio 		if ((n = imsgbuf_read(imsgbuf)) == -1)
441ef2e27a1Sclaudio 			err(1, "read error");
44277a10e6fSclaudio 		if (n == 0)
44377a10e6fSclaudio 			errx(1, "pipe closed");
44477a10e6fSclaudio 
44577a10e6fSclaudio 	}
44677a10e6fSclaudio 
447cbe08412Sclaudio 	if (res->action == SHOW_METRICS && --numdone > 0) {
44877a10e6fSclaudio 		done = 0;
44977a10e6fSclaudio 		goto again;
450f084a78cSclaudio 	}
451d30a810dSclaudio 
452d30a810dSclaudio 	output->tail();
453d30a810dSclaudio 
454f084a78cSclaudio 	close(fd);
45540466abfSclaudio 	free(imsgbuf);
456f084a78cSclaudio 
457f084a78cSclaudio 	exit(0);
458f084a78cSclaudio }
459f084a78cSclaudio 
460f084a78cSclaudio int
461f084a78cSclaudio show(struct imsg *imsg, struct parse_result *res)
462f084a78cSclaudio {
463fbeb5293Sclaudio 	struct peer		 p;
46469d2b5abSclaudio 	struct ctl_timer	 t;
465fbeb5293Sclaudio 	struct ctl_show_interface iface;
466fbeb5293Sclaudio 	struct ctl_show_nexthop	 nh;
46769d2b5abSclaudio 	struct ctl_show_set	 set;
46869d2b5abSclaudio 	struct ctl_show_rtr	 rtr;
469fbeb5293Sclaudio 	struct kroute_full	 kf;
470fbeb5293Sclaudio 	struct ktable		 kt;
471fbeb5293Sclaudio 	struct flowspec		 f;
4723e9f8020Sclaudio 	struct ctl_show_rib	 rib;
4733e9f8020Sclaudio 	struct rde_memstats	 stats;
4744b4c1963Sclaudio 	struct ibuf		 ibuf;
475dd147aaaSclaudio 	u_int			 rescode;
476f084a78cSclaudio 
477f084a78cSclaudio 	switch (imsg->hdr.type) {
4783e9f8020Sclaudio 	case IMSG_CTL_SHOW_NEIGHBOR:
47977a10e6fSclaudio 		if (output->neighbor == NULL)
48077a10e6fSclaudio 			break;
481fbeb5293Sclaudio 		if (imsg_get_data(imsg, &p, sizeof(p)) == -1)
482fbeb5293Sclaudio 			err(1, "imsg_get_data");
483fbeb5293Sclaudio 		output->neighbor(&p, res);
4843e9f8020Sclaudio 		break;
4853e9f8020Sclaudio 	case IMSG_CTL_SHOW_TIMER:
48677a10e6fSclaudio 		if (output->timer == NULL)
48777a10e6fSclaudio 			break;
488fbeb5293Sclaudio 		if (imsg_get_data(imsg, &t, sizeof(t)) == -1)
489fbeb5293Sclaudio 			err(1, "imsg_get_data");
49069d2b5abSclaudio 		if (t.type > 0 && t.type < Timer_Max)
49169d2b5abSclaudio 			output->timer(&t);
4923e9f8020Sclaudio 		break;
4933e9f8020Sclaudio 	case IMSG_CTL_SHOW_INTERFACE:
49477a10e6fSclaudio 		if (output->interface == NULL)
49577a10e6fSclaudio 			break;
496fbeb5293Sclaudio 		if (imsg_get_data(imsg, &iface, sizeof(iface)) == -1)
497fbeb5293Sclaudio 			err(1, "imsg_get_data");
498fbeb5293Sclaudio 		output->interface(&iface);
4993e9f8020Sclaudio 		break;
5003e9f8020Sclaudio 	case IMSG_CTL_SHOW_NEXTHOP:
50177a10e6fSclaudio 		if (output->nexthop == NULL)
50277a10e6fSclaudio 			break;
503fbeb5293Sclaudio 		if (imsg_get_data(imsg, &nh, sizeof(nh)) == -1)
504fbeb5293Sclaudio 			err(1, "imsg_get_data");
505fbeb5293Sclaudio 		output->nexthop(&nh);
5063e9f8020Sclaudio 		break;
5073e9f8020Sclaudio 	case IMSG_CTL_KROUTE:
5083e9f8020Sclaudio 	case IMSG_CTL_SHOW_NETWORK:
50977a10e6fSclaudio 		if (output->fib == NULL)
51077a10e6fSclaudio 			break;
511fbeb5293Sclaudio 		if (imsg_get_data(imsg, &kf, sizeof(kf)) == -1)
512fbeb5293Sclaudio 			err(1, "imsg_get_data");
513fbeb5293Sclaudio 		output->fib(&kf);
5143e9f8020Sclaudio 		break;
5155fed6b04Sclaudio 	case IMSG_CTL_SHOW_FLOWSPEC:
5165fed6b04Sclaudio 		if (output->flowspec == NULL)
5175fed6b04Sclaudio 			break;
518fbeb5293Sclaudio 		if (imsg_get_data(imsg, &f, sizeof(f)) == -1)
519fbeb5293Sclaudio 			err(1, "imsg_get_data");
520fbeb5293Sclaudio 		output->flowspec(&f);
5215fed6b04Sclaudio 		break;
5223e9f8020Sclaudio 	case IMSG_CTL_SHOW_FIB_TABLES:
52377a10e6fSclaudio 		if (output->fib_table == NULL)
52477a10e6fSclaudio 			break;
525fbeb5293Sclaudio 		if (imsg_get_data(imsg, &kt, sizeof(kt)) == -1)
526fbeb5293Sclaudio 			err(1, "imsg_get_data");
527fbeb5293Sclaudio 		output->fib_table(&kt);
5283e9f8020Sclaudio 		break;
5293e9f8020Sclaudio 	case IMSG_CTL_SHOW_RIB:
53077a10e6fSclaudio 		if (output->rib == NULL)
53177a10e6fSclaudio 			break;
53246d5331aSclaudio 		if (imsg_get_ibuf(imsg, &ibuf) == -1)
53346d5331aSclaudio 			err(1, "imsg_get_ibuf");
53446d5331aSclaudio 		if (ibuf_get(&ibuf, &rib, sizeof(rib)) == -1)
53546d5331aSclaudio 			err(1, "imsg_get_ibuf");
53646d5331aSclaudio 		output->rib(&rib, &ibuf, res);
5373e9f8020Sclaudio 		break;
5383e9f8020Sclaudio 	case IMSG_CTL_SHOW_RIB_COMMUNITIES:
53977a10e6fSclaudio 		if (output->communities == NULL)
54077a10e6fSclaudio 			break;
5414b4c1963Sclaudio 		if (imsg_get_ibuf(imsg, &ibuf) == -1)
5424b4c1963Sclaudio 			err(1, "imsg_get_ibuf");
5434b4c1963Sclaudio 		output->communities(&ibuf, res);
5443e9f8020Sclaudio 		break;
5453e9f8020Sclaudio 	case IMSG_CTL_SHOW_RIB_ATTR:
54677a10e6fSclaudio 		if (output->attr == NULL)
54777a10e6fSclaudio 			break;
548dd147aaaSclaudio 		if (imsg_get_ibuf(imsg, &ibuf) == -1)
549dd147aaaSclaudio 			err(1, "imsg_get_ibuf");
550dd147aaaSclaudio 		output->attr(&ibuf, res->flags, 0);
5513e9f8020Sclaudio 		break;
5523e9f8020Sclaudio 	case IMSG_CTL_SHOW_RIB_MEM:
55377a10e6fSclaudio 		if (output->rib_mem == NULL)
55477a10e6fSclaudio 			break;
555fbeb5293Sclaudio 		if (imsg_get_data(imsg, &stats, sizeof(stats)) == -1)
556fbeb5293Sclaudio 			err(1, "imsg_get_data");
557d30a810dSclaudio 		output->rib_mem(&stats);
558374adf67Sclaudio 		return (1);
559413f97b7Sclaudio 	case IMSG_CTL_SHOW_SET:
56077a10e6fSclaudio 		if (output->set == NULL)
56177a10e6fSclaudio 			break;
562fbeb5293Sclaudio 		if (imsg_get_data(imsg, &set, sizeof(set)) == -1)
563fbeb5293Sclaudio 			err(1, "imsg_get_data");
56469d2b5abSclaudio 		output->set(&set);
56569d2b5abSclaudio 		break;
56669d2b5abSclaudio 	case IMSG_CTL_SHOW_RTR:
56777a10e6fSclaudio 		if (output->rtr == NULL)
56877a10e6fSclaudio 			break;
569fbeb5293Sclaudio 		if (imsg_get_data(imsg, &rtr, sizeof(rtr)) == -1)
570fbeb5293Sclaudio 			err(1, "imsg_get_data");
57169d2b5abSclaudio 		output->rtr(&rtr);
572413f97b7Sclaudio 		break;
573f084a78cSclaudio 	case IMSG_CTL_RESULT:
57477a10e6fSclaudio 		if (output->result == NULL)
57577a10e6fSclaudio 			break;
576fbeb5293Sclaudio 		if (imsg_get_data(imsg, &rescode, sizeof(rescode)) == -1)
577fbeb5293Sclaudio 			err(1, "imsg_get_data");
578d30a810dSclaudio 		output->result(rescode);
579f084a78cSclaudio 		return (1);
580f084a78cSclaudio 	case IMSG_CTL_END:
581f084a78cSclaudio 		return (1);
582f084a78cSclaudio 	default:
5833e9f8020Sclaudio 		warnx("unknown imsg %d received", imsg->hdr.type);
584f084a78cSclaudio 		break;
585c2410a5fShenning 	}
586c2410a5fShenning 
5873e9f8020Sclaudio 	return (0);
588fd0978b9Shenning }
589f85ac724Shenning 
590fd18fec4Sclaudio time_t
591fd18fec4Sclaudio get_monotime(time_t t)
592fd18fec4Sclaudio {
593fd18fec4Sclaudio 	struct timespec ts;
594fd18fec4Sclaudio 
595fd18fec4Sclaudio 	if (t == 0)
596fd18fec4Sclaudio 		return -1;
597fd18fec4Sclaudio 	if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0)
598fd18fec4Sclaudio 		err(1, "clock_gettime");
599fd18fec4Sclaudio 	if (t > ts.tv_sec)	/* time in the future is not possible */
600fd18fec4Sclaudio 		t = ts.tv_sec;
601fd18fec4Sclaudio 	return (ts.tv_sec - t);
602fd18fec4Sclaudio }
603fd18fec4Sclaudio 
6042ec7f40eShenning char *
6057e256512Sclaudio fmt_peer(const char *descr, const struct bgpd_addr *remote_addr,
606f084a78cSclaudio     int masklen)
6072ec7f40eShenning {
6082ec7f40eShenning 	const char	*ip;
6092ec7f40eShenning 	char		*p;
6102ec7f40eShenning 
6113e9f8020Sclaudio 	if (descr && descr[0] && !nodescr) {
6127e256512Sclaudio 		if ((p = strdup(descr)) == NULL)
61378d6515aSclaudio 			err(1, NULL);
6142ec7f40eShenning 		return (p);
6152ec7f40eShenning 	}
6162ec7f40eShenning 
6177e256512Sclaudio 	ip = log_addr(remote_addr);
618b26dd4adSclaudio 	if (masklen != -1 && ((remote_addr->aid == AID_INET && masklen != 32) ||
619b26dd4adSclaudio 	    (remote_addr->aid == AID_INET6 && masklen != 128))) {
6207e256512Sclaudio 		if (asprintf(&p, "%s/%u", ip, masklen) == -1)
62178d6515aSclaudio 			err(1, NULL);
6222ec7f40eShenning 	} else {
6232ec7f40eShenning 		if ((p = strdup(ip)) == NULL)
62478d6515aSclaudio 			err(1, NULL);
6252ec7f40eShenning 	}
6262ec7f40eShenning 
6272ec7f40eShenning 	return (p);
6282ec7f40eShenning }
6292ec7f40eShenning 
6303d210dfcSphessler const char *
63104d0a88fSclaudio fmt_auth_method(enum auth_method method)
6323d210dfcSphessler {
6333d210dfcSphessler 	switch (method) {
6343d210dfcSphessler 	case AUTH_MD5SIG:
6353d210dfcSphessler 		return ", using md5sig";
6363d210dfcSphessler 	case AUTH_IPSEC_MANUAL_ESP:
6373d210dfcSphessler 		return ", using ipsec manual esp";
6383d210dfcSphessler 	case AUTH_IPSEC_MANUAL_AH:
6393d210dfcSphessler 		return ", using ipsec manual ah";
6403d210dfcSphessler 	case AUTH_IPSEC_IKE_ESP:
6413d210dfcSphessler 		return ", using ipsec ike esp";
6423d210dfcSphessler 	case AUTH_IPSEC_IKE_AH:
6433d210dfcSphessler 		return ", using ipsec ike ah";
6443d210dfcSphessler 	case AUTH_NONE:	/* FALLTHROUGH */
6453d210dfcSphessler 	default:
6463d210dfcSphessler 		return "";
6473d210dfcSphessler 	}
6483d210dfcSphessler }
6493d210dfcSphessler 
65081dd5016Sclaudio #define TF_LEN	16
651c5b029bbShenning 
652e67b1a58Sclaudio const char *
653e67b1a58Sclaudio fmt_timeframe(time_t t)
654ed99340cShenning {
65581dd5016Sclaudio 	static char	 buf[TF_LEN];
656035b0708Sgilles 	unsigned int	 sec, min, hrs, day;
657035b0708Sgilles 	unsigned long long	 week;
658c5b029bbShenning 
65981dd5016Sclaudio 	if (t < 0)
66081dd5016Sclaudio 		t = 0;
661ed99340cShenning 	week = t;
662c5b029bbShenning 
663c5b029bbShenning 	sec = week % 60;
664c5b029bbShenning 	week /= 60;
665c5b029bbShenning 	min = week % 60;
666c5b029bbShenning 	week /= 60;
667c5b029bbShenning 	hrs = week % 24;
668c5b029bbShenning 	week /= 24;
669c5b029bbShenning 	day = week % 7;
670c5b029bbShenning 	week /= 7;
671c5b029bbShenning 
67281dd5016Sclaudio 	if (week >= 1000)
67381dd5016Sclaudio 		snprintf(buf, TF_LEN, "%02lluw", week);
67481dd5016Sclaudio 	else if (week > 0)
675035b0708Sgilles 		snprintf(buf, TF_LEN, "%02lluw%01ud%02uh", week, day, hrs);
676c5b029bbShenning 	else if (day > 0)
677c5b029bbShenning 		snprintf(buf, TF_LEN, "%01ud%02uh%02um", day, hrs, min);
678c5b029bbShenning 	else
679c5b029bbShenning 		snprintf(buf, TF_LEN, "%02u:%02u:%02u", hrs, min, sec);
680c5b029bbShenning 
681c5b029bbShenning 	return (buf);
682c5b029bbShenning }
683b66d179dShenning 
684da270b4dSclaudio const char *
685e67b1a58Sclaudio fmt_monotime(time_t t)
686da270b4dSclaudio {
687fd18fec4Sclaudio 	t = get_monotime(t);
688da270b4dSclaudio 
689fd18fec4Sclaudio 	if (t == -1)
690da270b4dSclaudio 		return ("Never");
691da270b4dSclaudio 
692fd18fec4Sclaudio 	return (fmt_timeframe(t));
693da270b4dSclaudio }
694da270b4dSclaudio 
69504d0a88fSclaudio const char *
69659154960Sclaudio fmt_fib_flags(uint16_t flags)
697b5908c68Shenning {
69804d0a88fSclaudio 	static char buf[8];
69904d0a88fSclaudio 
700ef0c8610Sclaudio 	if (flags & F_BGPD)
7010d49b5f3Sclaudio 		strlcpy(buf, "B", sizeof(buf));
702b5908c68Shenning 	else if (flags & F_CONNECTED)
7030d49b5f3Sclaudio 		strlcpy(buf, "C", sizeof(buf));
704b5908c68Shenning 	else if (flags & F_STATIC)
7050d49b5f3Sclaudio 		strlcpy(buf, "S", sizeof(buf));
706b5908c68Shenning 	else
7070d49b5f3Sclaudio 		strlcpy(buf, " ", sizeof(buf));
708b5908c68Shenning 
709b5908c68Shenning 	if (flags & F_NEXTHOP)
71004d0a88fSclaudio 		strlcat(buf, "N", sizeof(buf));
711b5908c68Shenning 	else
71204d0a88fSclaudio 		strlcat(buf, " ", sizeof(buf));
713b5908c68Shenning 
714b5908c68Shenning 	if (flags & F_REJECT && flags & F_BLACKHOLE)
71504d0a88fSclaudio 		strlcat(buf, "f", sizeof(buf));
716b5908c68Shenning 	else if (flags & F_REJECT)
71704d0a88fSclaudio 		strlcat(buf, "r", sizeof(buf));
718b5908c68Shenning 	else if (flags & F_BLACKHOLE)
71904d0a88fSclaudio 		strlcat(buf, "b", sizeof(buf));
720b5908c68Shenning 	else
72104d0a88fSclaudio 		strlcat(buf, " ", sizeof(buf));
722b5908c68Shenning 
72304d0a88fSclaudio 	return buf;
7247b6c56a0Sclaudio }
7257b6c56a0Sclaudio 
7267b6c56a0Sclaudio const char *
72759154960Sclaudio fmt_origin(uint8_t origin, int sum)
7287b6c56a0Sclaudio {
7297b6c56a0Sclaudio 	switch (origin) {
7307b6c56a0Sclaudio 	case ORIGIN_IGP:
7317b6c56a0Sclaudio 		return (sum ? "i" : "IGP");
7327b6c56a0Sclaudio 	case ORIGIN_EGP:
7337b6c56a0Sclaudio 		return (sum ? "e" : "EGP");
7347b6c56a0Sclaudio 	case ORIGIN_INCOMPLETE:
7357b6c56a0Sclaudio 		return (sum ? "?" : "incomplete");
7367b6c56a0Sclaudio 	default:
7377b6c56a0Sclaudio 		return (sum ? "X" : "bad origin");
7387b6c56a0Sclaudio 	}
7397b6c56a0Sclaudio }
7407b6c56a0Sclaudio 
74104d0a88fSclaudio const char *
7422953a2c1Sclaudio fmt_flags(uint32_t flags, int sum)
74373d4348fSclaudio {
74404d0a88fSclaudio 	static char buf[80];
74573d4348fSclaudio 	char	 flagstr[5];
74673d4348fSclaudio 	char	*p = flagstr;
74773d4348fSclaudio 
74873d4348fSclaudio 	if (sum) {
74909b2f24cSclaudio 		if (flags & F_PREF_FILTERED)
75009b2f24cSclaudio 			*p++ = 'F';
75179dfb877Sclaudio 		if (flags & F_PREF_INVALID)
75279dfb877Sclaudio 			*p++ = 'E';
75312abdda6Sclaudio 		if (flags & F_PREF_OTC_LEAK)
754135bf897Sclaudio 			*p++ = 'L';
7557f410e5eSclaudio 		if (flags & F_PREF_ANNOUNCE)
75673d4348fSclaudio 			*p++ = 'A';
7577f410e5eSclaudio 		if (flags & F_PREF_INTERNAL)
75873d4348fSclaudio 			*p++ = 'I';
7596d93a853Sclaudio 		if (flags & F_PREF_STALE)
7606d93a853Sclaudio 			*p++ = 'S';
7617f410e5eSclaudio 		if (flags & F_PREF_ELIGIBLE)
76273d4348fSclaudio 			*p++ = '*';
7634ff57d1dSclaudio 		if (flags & F_PREF_BEST)
76473d4348fSclaudio 			*p++ = '>';
7652953a2c1Sclaudio 		if (flags & F_PREF_ECMP)
7662953a2c1Sclaudio 			*p++ = 'm';
7672953a2c1Sclaudio 		if (flags & F_PREF_AS_WIDE)
7682953a2c1Sclaudio 			*p++ = 'w';
76973d4348fSclaudio 		*p = '\0';
77004d0a88fSclaudio 		snprintf(buf, sizeof(buf), "%-5s", flagstr);
77173d4348fSclaudio 	} else {
7727f410e5eSclaudio 		if (flags & F_PREF_INTERNAL)
77304d0a88fSclaudio 			strlcpy(buf, "internal", sizeof(buf));
77473d4348fSclaudio 		else
77504d0a88fSclaudio 			strlcpy(buf, "external", sizeof(buf));
77604d0a88fSclaudio 
77709b2f24cSclaudio 		if (flags & F_PREF_FILTERED)
77809b2f24cSclaudio 			strlcat(buf, ", filtered", sizeof(buf));
779135bf897Sclaudio 		if (flags & F_PREF_INVALID)
780135bf897Sclaudio 			strlcat(buf, ", invalid", sizeof(buf));
78112abdda6Sclaudio 		if (flags & F_PREF_OTC_LEAK)
78212abdda6Sclaudio 			strlcat(buf, ", otc leak", sizeof(buf));
7836d93a853Sclaudio 		if (flags & F_PREF_STALE)
78404d0a88fSclaudio 			strlcat(buf, ", stale", sizeof(buf));
7857f410e5eSclaudio 		if (flags & F_PREF_ELIGIBLE)
78604d0a88fSclaudio 			strlcat(buf, ", valid", sizeof(buf));
7874ff57d1dSclaudio 		if (flags & F_PREF_BEST)
78804d0a88fSclaudio 			strlcat(buf, ", best", sizeof(buf));
7892953a2c1Sclaudio 		if (flags & F_PREF_ECMP)
7902953a2c1Sclaudio 			strlcat(buf, ", ecmp", sizeof(buf));
7912953a2c1Sclaudio 		if (flags & F_PREF_AS_WIDE)
7922953a2c1Sclaudio 			strlcat(buf, ", as-wide", sizeof(buf));
7937f410e5eSclaudio 		if (flags & F_PREF_ANNOUNCE)
79404d0a88fSclaudio 			strlcat(buf, ", announced", sizeof(buf));
79504d0a88fSclaudio 		if (strlen(buf) >= sizeof(buf) - 1)
79604d0a88fSclaudio 			errx(1, "%s buffer too small", __func__);
79773d4348fSclaudio 	}
79804d0a88fSclaudio 
79904d0a88fSclaudio 	return buf;
80073d4348fSclaudio }
80173d4348fSclaudio 
8022f429709Sjob const char *
80359154960Sclaudio fmt_ovs(uint8_t validation_state, int sum)
8042f429709Sjob {
8052f429709Sjob 	switch (validation_state) {
8062f429709Sjob 	case ROA_INVALID:
8072f429709Sjob 		return (sum ? "!" : "invalid");
8082f429709Sjob 	case ROA_VALID:
8092f429709Sjob 		return (sum ? "V" : "valid");
8102f429709Sjob 	default:
8112f429709Sjob 		return (sum ? "N" : "not-found");
8122f429709Sjob 	}
8132f429709Sjob }
8142f429709Sjob 
81504d0a88fSclaudio const char *
81650d35cacSclaudio fmt_avs(uint8_t validation_state, int sum)
81750d35cacSclaudio {
81850d35cacSclaudio 	switch (validation_state) {
81950d35cacSclaudio 	case ASPA_INVALID:
82050d35cacSclaudio 		return (sum ? "!" : "invalid");
82150d35cacSclaudio 	case ASPA_VALID:
82250d35cacSclaudio 		return (sum ? "V" : "valid");
82350d35cacSclaudio 	default:
82450d35cacSclaudio 		return (sum ? "?" : "unknown");
82550d35cacSclaudio 	}
82650d35cacSclaudio }
82750d35cacSclaudio 
82850d35cacSclaudio const char *
82904d0a88fSclaudio fmt_mem(long long num)
83004d0a88fSclaudio {
83104d0a88fSclaudio 	static char	buf[16];
83204d0a88fSclaudio 
83304d0a88fSclaudio 	if (fmt_scaled(num, buf) == -1)
83404d0a88fSclaudio 		snprintf(buf, sizeof(buf), "%lldB", num);
83504d0a88fSclaudio 
83604d0a88fSclaudio 	return (buf);
83704d0a88fSclaudio }
83804d0a88fSclaudio 
83904d0a88fSclaudio const char *
84059154960Sclaudio fmt_errstr(uint8_t errcode, uint8_t subcode)
84104d0a88fSclaudio {
84204d0a88fSclaudio 	static char	 errbuf[256];
84304d0a88fSclaudio 	const char	*errstr = NULL;
84404d0a88fSclaudio 	const char	*suberr = NULL;
84504d0a88fSclaudio 	int		 uk = 0;
84604d0a88fSclaudio 
84704d0a88fSclaudio 	if (errcode == 0)	/* no error */
84804d0a88fSclaudio 		return NULL;
84904d0a88fSclaudio 
85004d0a88fSclaudio 	if (errcode < sizeof(errnames)/sizeof(char *))
85104d0a88fSclaudio 		errstr = errnames[errcode];
85204d0a88fSclaudio 
85304d0a88fSclaudio 	switch (errcode) {
85404d0a88fSclaudio 	case ERR_HEADER:
85504d0a88fSclaudio 		if (subcode < sizeof(suberr_header_names)/sizeof(char *))
85604d0a88fSclaudio 			suberr = suberr_header_names[subcode];
85704d0a88fSclaudio 		else
85804d0a88fSclaudio 			uk = 1;
85904d0a88fSclaudio 		break;
86004d0a88fSclaudio 	case ERR_OPEN:
86104d0a88fSclaudio 		if (subcode < sizeof(suberr_open_names)/sizeof(char *))
86204d0a88fSclaudio 			suberr = suberr_open_names[subcode];
86304d0a88fSclaudio 		else
86404d0a88fSclaudio 			uk = 1;
86504d0a88fSclaudio 		break;
86604d0a88fSclaudio 	case ERR_UPDATE:
86704d0a88fSclaudio 		if (subcode < sizeof(suberr_update_names)/sizeof(char *))
86804d0a88fSclaudio 			suberr = suberr_update_names[subcode];
86904d0a88fSclaudio 		else
87004d0a88fSclaudio 			uk = 1;
87104d0a88fSclaudio 		break;
87204d0a88fSclaudio 	case ERR_HOLDTIMEREXPIRED:
87304d0a88fSclaudio 		if (subcode != 0)
87404d0a88fSclaudio 			uk = 1;
87504d0a88fSclaudio 		break;
87604d0a88fSclaudio 	case ERR_FSM:
87704d0a88fSclaudio 		if (subcode < sizeof(suberr_fsm_names)/sizeof(char *))
87804d0a88fSclaudio 			suberr = suberr_fsm_names[subcode];
87904d0a88fSclaudio 		else
88004d0a88fSclaudio 			uk = 1;
88104d0a88fSclaudio 		break;
88204d0a88fSclaudio 	case ERR_CEASE:
88304d0a88fSclaudio 		if (subcode < sizeof(suberr_cease_names)/sizeof(char *))
88404d0a88fSclaudio 			suberr = suberr_cease_names[subcode];
88504d0a88fSclaudio 		else
88604d0a88fSclaudio 			uk = 1;
88704d0a88fSclaudio 		break;
88804d0a88fSclaudio 	default:
88904d0a88fSclaudio 		snprintf(errbuf, sizeof(errbuf),
89004d0a88fSclaudio 		    "unknown error code %u subcode %u", errcode, subcode);
89104d0a88fSclaudio 		return (errbuf);
89204d0a88fSclaudio 	}
89304d0a88fSclaudio 
89404d0a88fSclaudio 	if (uk)
89504d0a88fSclaudio 		snprintf(errbuf, sizeof(errbuf),
89604d0a88fSclaudio 		    "%s, unknown subcode %u", errstr, subcode);
89704d0a88fSclaudio 	else if (suberr == NULL)
89804d0a88fSclaudio 		return (errstr);
89904d0a88fSclaudio 	else
90004d0a88fSclaudio 		snprintf(errbuf, sizeof(errbuf),
90104d0a88fSclaudio 		    "%s, %s", errstr, suberr);
90204d0a88fSclaudio 
90304d0a88fSclaudio 	return (errbuf);
90404d0a88fSclaudio }
90504d0a88fSclaudio 
90604d0a88fSclaudio const char *
90759154960Sclaudio fmt_attr(uint8_t type, int flags)
90847c6720fSclaudio {
90947c6720fSclaudio #define CHECK_FLAGS(s, t, m)	\
91047c6720fSclaudio 	if (((s) & ~(ATTR_DEFMASK | (m))) != (t)) pflags = 1
91147c6720fSclaudio 
91247c6720fSclaudio 	static char cstr[48];
91347c6720fSclaudio 	int pflags = 0;
91447c6720fSclaudio 
91547c6720fSclaudio 	switch (type) {
91647c6720fSclaudio 	case ATTR_ORIGIN:
91747c6720fSclaudio 		CHECK_FLAGS(flags, ATTR_WELL_KNOWN, 0);
91847c6720fSclaudio 		strlcpy(cstr, "Origin", sizeof(cstr));
91947c6720fSclaudio 		break;
92047c6720fSclaudio 	case ATTR_ASPATH:
92147c6720fSclaudio 		CHECK_FLAGS(flags, ATTR_WELL_KNOWN, 0);
92247c6720fSclaudio 		strlcpy(cstr, "AS-Path", sizeof(cstr));
92347c6720fSclaudio 		break;
92447c6720fSclaudio 	case ATTR_AS4_PATH:
92547c6720fSclaudio 		CHECK_FLAGS(flags, ATTR_WELL_KNOWN, 0);
92647c6720fSclaudio 		strlcpy(cstr, "AS4-Path", sizeof(cstr));
92747c6720fSclaudio 		break;
92847c6720fSclaudio 	case ATTR_NEXTHOP:
92947c6720fSclaudio 		CHECK_FLAGS(flags, ATTR_WELL_KNOWN, 0);
93047c6720fSclaudio 		strlcpy(cstr, "Nexthop", sizeof(cstr));
93147c6720fSclaudio 		break;
93247c6720fSclaudio 	case ATTR_MED:
93347c6720fSclaudio 		CHECK_FLAGS(flags, ATTR_OPTIONAL, 0);
93447c6720fSclaudio 		strlcpy(cstr, "Med", sizeof(cstr));
93547c6720fSclaudio 		break;
93647c6720fSclaudio 	case ATTR_LOCALPREF:
93747c6720fSclaudio 		CHECK_FLAGS(flags, ATTR_WELL_KNOWN, 0);
93847c6720fSclaudio 		strlcpy(cstr, "Localpref", sizeof(cstr));
93947c6720fSclaudio 		break;
94047c6720fSclaudio 	case ATTR_ATOMIC_AGGREGATE:
94147c6720fSclaudio 		CHECK_FLAGS(flags, ATTR_WELL_KNOWN, 0);
94247c6720fSclaudio 		strlcpy(cstr, "Atomic Aggregate", sizeof(cstr));
94347c6720fSclaudio 		break;
94447c6720fSclaudio 	case ATTR_AGGREGATOR:
94547c6720fSclaudio 		CHECK_FLAGS(flags, ATTR_OPTIONAL|ATTR_TRANSITIVE, ATTR_PARTIAL);
94647c6720fSclaudio 		strlcpy(cstr, "Aggregator", sizeof(cstr));
94747c6720fSclaudio 		break;
94847c6720fSclaudio 	case ATTR_AS4_AGGREGATOR:
94947c6720fSclaudio 		CHECK_FLAGS(flags, ATTR_OPTIONAL|ATTR_TRANSITIVE, ATTR_PARTIAL);
95047c6720fSclaudio 		strlcpy(cstr, "AS4-Aggregator", sizeof(cstr));
95147c6720fSclaudio 		break;
95247c6720fSclaudio 	case ATTR_COMMUNITIES:
95347c6720fSclaudio 		CHECK_FLAGS(flags, ATTR_OPTIONAL|ATTR_TRANSITIVE, ATTR_PARTIAL);
95447c6720fSclaudio 		strlcpy(cstr, "Communities", sizeof(cstr));
95547c6720fSclaudio 		break;
95647c6720fSclaudio 	case ATTR_ORIGINATOR_ID:
95747c6720fSclaudio 		CHECK_FLAGS(flags, ATTR_OPTIONAL, 0);
95847c6720fSclaudio 		strlcpy(cstr, "Originator Id", sizeof(cstr));
95947c6720fSclaudio 		break;
96047c6720fSclaudio 	case ATTR_CLUSTER_LIST:
96147c6720fSclaudio 		CHECK_FLAGS(flags, ATTR_OPTIONAL, 0);
96247c6720fSclaudio 		strlcpy(cstr, "Cluster Id List", sizeof(cstr));
96347c6720fSclaudio 		break;
96447c6720fSclaudio 	case ATTR_MP_REACH_NLRI:
96547c6720fSclaudio 		CHECK_FLAGS(flags, ATTR_OPTIONAL, 0);
96647c6720fSclaudio 		strlcpy(cstr, "MP Reach NLRI", sizeof(cstr));
96747c6720fSclaudio 		break;
96847c6720fSclaudio 	case ATTR_MP_UNREACH_NLRI:
96947c6720fSclaudio 		CHECK_FLAGS(flags, ATTR_OPTIONAL, 0);
97047c6720fSclaudio 		strlcpy(cstr, "MP Unreach NLRI", sizeof(cstr));
97147c6720fSclaudio 		break;
97247c6720fSclaudio 	case ATTR_EXT_COMMUNITIES:
97347c6720fSclaudio 		CHECK_FLAGS(flags, ATTR_OPTIONAL|ATTR_TRANSITIVE, ATTR_PARTIAL);
97447c6720fSclaudio 		strlcpy(cstr, "Ext. Communities", sizeof(cstr));
97547c6720fSclaudio 		break;
97647c6720fSclaudio 	case ATTR_LARGE_COMMUNITIES:
97747c6720fSclaudio 		CHECK_FLAGS(flags, ATTR_OPTIONAL|ATTR_TRANSITIVE, ATTR_PARTIAL);
97847c6720fSclaudio 		strlcpy(cstr, "Large Communities", sizeof(cstr));
97947c6720fSclaudio 		break;
980135bf897Sclaudio 	case ATTR_OTC:
981135bf897Sclaudio 		CHECK_FLAGS(flags, ATTR_OPTIONAL|ATTR_TRANSITIVE, ATTR_PARTIAL);
982135bf897Sclaudio 		strlcpy(cstr, "OTC", sizeof(cstr));
983135bf897Sclaudio 		break;
98447c6720fSclaudio 	default:
98547c6720fSclaudio 		/* ignore unknown attributes */
98647c6720fSclaudio 		snprintf(cstr, sizeof(cstr), "Unknown Attribute #%u", type);
98747c6720fSclaudio 		pflags = 1;
98847c6720fSclaudio 		break;
98947c6720fSclaudio 	}
990a47383e2Sclaudio 	if (flags != -1 && pflags) {
99147c6720fSclaudio 		strlcat(cstr, " flags [", sizeof(cstr));
99247c6720fSclaudio 		if (flags & ATTR_OPTIONAL)
99347c6720fSclaudio 			strlcat(cstr, "O", sizeof(cstr));
99447c6720fSclaudio 		if (flags & ATTR_TRANSITIVE)
99547c6720fSclaudio 			strlcat(cstr, "T", sizeof(cstr));
99647c6720fSclaudio 		if (flags & ATTR_PARTIAL)
99747c6720fSclaudio 			strlcat(cstr, "P", sizeof(cstr));
99847c6720fSclaudio 		strlcat(cstr, "]", sizeof(cstr));
99947c6720fSclaudio 	}
100047c6720fSclaudio 	return (cstr);
100147c6720fSclaudio 
100247c6720fSclaudio #undef CHECK_FLAGS
100347c6720fSclaudio }
100447c6720fSclaudio 
100504d0a88fSclaudio const char *
100659154960Sclaudio fmt_community(uint16_t a, uint16_t v)
1007a20554fdSclaudio {
100804d0a88fSclaudio 	static char buf[12];
1009a20554fdSclaudio 
101073d4348fSclaudio 	if (a == COMMUNITY_WELLKNOWN)
101173d4348fSclaudio 		switch (v) {
101215406510Sphessler 		case COMMUNITY_GRACEFUL_SHUTDOWN:
101304d0a88fSclaudio 			return "GRACEFUL_SHUTDOWN";
101473d4348fSclaudio 		case COMMUNITY_NO_EXPORT:
101504d0a88fSclaudio 			return "NO_EXPORT";
101673d4348fSclaudio 		case COMMUNITY_NO_ADVERTISE:
101704d0a88fSclaudio 			return "NO_ADVERTISE";
101873d4348fSclaudio 		case COMMUNITY_NO_EXPSUBCONFED:
101904d0a88fSclaudio 			return "NO_EXPORT_SUBCONFED";
102073d4348fSclaudio 		case COMMUNITY_NO_PEER:
102104d0a88fSclaudio 			return "NO_PEER";
102217c84f89Ssthen 		case COMMUNITY_BLACKHOLE:
102304d0a88fSclaudio 			return "BLACKHOLE";
102473d4348fSclaudio 		default:
102573d4348fSclaudio 			break;
102673d4348fSclaudio 		}
102773d4348fSclaudio 
102804d0a88fSclaudio 	snprintf(buf, sizeof(buf), "%hu:%hu", a, v);
102904d0a88fSclaudio 	return buf;
103004d0a88fSclaudio }
103104d0a88fSclaudio 
103204d0a88fSclaudio const char *
103359154960Sclaudio fmt_large_community(uint32_t d1, uint32_t d2, uint32_t d3)
10340ca99656Sclaudio {
103504d0a88fSclaudio 	static char buf[33];
103604d0a88fSclaudio 
103704d0a88fSclaudio 	snprintf(buf, sizeof(buf), "%u:%u:%u", d1, d2, d3);
103804d0a88fSclaudio 	return buf;
103904d0a88fSclaudio }
104004d0a88fSclaudio 
104104d0a88fSclaudio const char *
10424b4c1963Sclaudio fmt_ext_community(uint64_t ext)
104304d0a88fSclaudio {
104404d0a88fSclaudio 	static char	buf[32];
10450ca99656Sclaudio 	struct in_addr	ip;
104659154960Sclaudio 	uint32_t	as4, u32;
104759154960Sclaudio 	uint16_t	as2, u16;
104859154960Sclaudio 	uint8_t		type, subtype;
10490ca99656Sclaudio 
10504b4c1963Sclaudio 	type = ext >> 56;
10514b4c1963Sclaudio 	subtype = ext >> 48;
10520ca99656Sclaudio 
10530ca99656Sclaudio 	switch (type) {
10540ca99656Sclaudio 	case EXT_COMMUNITY_TRANS_TWO_AS:
1055c2371130Sclaudio 	case EXT_COMMUNITY_GEN_TWO_AS:
10564b4c1963Sclaudio 		as2 = ext >> 32;
10574b4c1963Sclaudio 		u32 = ext;
105804d0a88fSclaudio 		snprintf(buf, sizeof(buf), "%s %s:%u",
10594b4c1963Sclaudio 		    log_ext_subtype(type, subtype), log_as(as2), u32);
106004d0a88fSclaudio 		return buf;
10610ca99656Sclaudio 	case EXT_COMMUNITY_TRANS_IPV4:
1062c2371130Sclaudio 	case EXT_COMMUNITY_GEN_IPV4:
10634b4c1963Sclaudio 		ip.s_addr = htonl(ext >> 16);
10644b4c1963Sclaudio 		u16 = ext;
106504d0a88fSclaudio 		snprintf(buf, sizeof(buf), "%s %s:%hu",
10664b4c1963Sclaudio 		    log_ext_subtype(type, subtype), inet_ntoa(ip), u16);
106704d0a88fSclaudio 		return buf;
10680ca99656Sclaudio 	case EXT_COMMUNITY_TRANS_FOUR_AS:
1069c2371130Sclaudio 	case EXT_COMMUNITY_GEN_FOUR_AS:
10704b4c1963Sclaudio 		as4 = ext >> 16;
10714b4c1963Sclaudio 		u16 = ext;
107204d0a88fSclaudio 		snprintf(buf, sizeof(buf), "%s %s:%hu",
10734b4c1963Sclaudio 		    log_ext_subtype(type, subtype), log_as(as4), u16);
107404d0a88fSclaudio 		return buf;
10750ca99656Sclaudio 	case EXT_COMMUNITY_TRANS_OPAQUE:
10760ca99656Sclaudio 	case EXT_COMMUNITY_TRANS_EVPN:
10774b4c1963Sclaudio 		ext &= 0xffffffffffffULL;
107804d0a88fSclaudio 		snprintf(buf, sizeof(buf), "%s 0x%llx",
107904d0a88fSclaudio 		    log_ext_subtype(type, subtype), (unsigned long long)ext);
108004d0a88fSclaudio 		return buf;
10810ca99656Sclaudio 	case EXT_COMMUNITY_NON_TRANS_OPAQUE:
10824b4c1963Sclaudio 		ext &= 0xffffffffffffULL;
1083c2371130Sclaudio 		if (subtype == EXT_COMMUNITY_SUBTYPE_OVS) {
10840ca99656Sclaudio 			switch (ext) {
10850ca99656Sclaudio 			case EXT_COMMUNITY_OVS_VALID:
108604d0a88fSclaudio 				snprintf(buf, sizeof(buf), "%s valid",
108704d0a88fSclaudio 				    log_ext_subtype(type, subtype));
108804d0a88fSclaudio 				return buf;
10890ca99656Sclaudio 			case EXT_COMMUNITY_OVS_NOTFOUND:
109004d0a88fSclaudio 				snprintf(buf, sizeof(buf), "%s not-found",
109104d0a88fSclaudio 				    log_ext_subtype(type, subtype));
109204d0a88fSclaudio 				return buf;
10930ca99656Sclaudio 			case EXT_COMMUNITY_OVS_INVALID:
109404d0a88fSclaudio 				snprintf(buf, sizeof(buf), "%s invalid",
109504d0a88fSclaudio 				    log_ext_subtype(type, subtype));
109604d0a88fSclaudio 				return buf;
10970ca99656Sclaudio 			default:
109804d0a88fSclaudio 				snprintf(buf, sizeof(buf), "%s 0x%llx",
109904d0a88fSclaudio 				    log_ext_subtype(type, subtype),
110004d0a88fSclaudio 				    (unsigned long long)ext);
110104d0a88fSclaudio 				return buf;
11020ca99656Sclaudio 			}
1103c2371130Sclaudio 		} else {
1104c2371130Sclaudio 			snprintf(buf, sizeof(buf), "%s 0x%llx",
1105c2371130Sclaudio 			    log_ext_subtype(type, subtype),
1106c2371130Sclaudio 			    (unsigned long long)ext);
1107c2371130Sclaudio 			return buf;
1108c2371130Sclaudio 		}
11090ca99656Sclaudio 		break;
11100ca99656Sclaudio 	default:
11114b4c1963Sclaudio 		snprintf(buf, sizeof(buf), "0x%llx", (unsigned long long)ext);
111204d0a88fSclaudio 		return buf;
11130ca99656Sclaudio 	}
11140ca99656Sclaudio }
11150ca99656Sclaudio 
1116413f97b7Sclaudio const char *
1117413f97b7Sclaudio fmt_set_type(struct ctl_show_set *set)
1118413f97b7Sclaudio {
1119413f97b7Sclaudio 	switch (set->type) {
1120c4f772fdSclaudio 	case ASPA_SET:
1121c4f772fdSclaudio 		return "ASPA";
1122413f97b7Sclaudio 	case ROA_SET:
1123413f97b7Sclaudio 		return "ROA";
1124413f97b7Sclaudio 	case PREFIX_SET:
1125413f97b7Sclaudio 		return "PREFIX";
1126413f97b7Sclaudio 	case ORIGIN_SET:
1127413f97b7Sclaudio 		return "ORIGIN";
1128413f97b7Sclaudio 	case ASNUM_SET:
1129413f97b7Sclaudio 		return "ASNUM";
1130413f97b7Sclaudio 	default:
1131413f97b7Sclaudio 		return "BULA";
1132413f97b7Sclaudio 	}
1133413f97b7Sclaudio }
1134413f97b7Sclaudio 
11350ca99656Sclaudio void
11369caec0aeSclaudio send_filterset(struct imsgbuf *i, struct filter_set_head *set)
11379caec0aeSclaudio {
11389caec0aeSclaudio 	struct filter_set	*s;
11399caec0aeSclaudio 
114038cb626eSfgsch 	while ((s = TAILQ_FIRST(set)) != NULL) {
11419caec0aeSclaudio 		imsg_compose(i, IMSG_FILTER_SET, 0, 0, -1, s,
11429caec0aeSclaudio 		    sizeof(struct filter_set));
114338cb626eSfgsch 		TAILQ_REMOVE(set, s, entry);
11449caec0aeSclaudio 		free(s);
11459caec0aeSclaudio 	}
11469caec0aeSclaudio }
11479caec0aeSclaudio 
1148a20554fdSclaudio void
11490ac5a32aSphessler network_bulk(struct parse_result *res)
11500ac5a32aSphessler {
11510ac5a32aSphessler 	struct network_config net;
11520ac5a32aSphessler 	struct filter_set *s = NULL;
11530ac5a32aSphessler 	struct bgpd_addr h;
11541ce75666Sclaudio 	char *line = NULL;
11551ce75666Sclaudio 	size_t linesize = 0;
11561ce75666Sclaudio 	ssize_t linelen;
115759154960Sclaudio 	uint8_t len;
11580ac5a32aSphessler 	FILE *f;
11590ac5a32aSphessler 
11601ce75666Sclaudio 	if ((f = fdopen(STDIN_FILENO, "r")) == NULL)
11611ce75666Sclaudio 		err(1, "Failed to open stdin\n");
11620ac5a32aSphessler 
11631ce75666Sclaudio 	while ((linelen = getline(&line, &linesize, f)) != -1) {
11641ce75666Sclaudio 		char *b, *buf = line;
11651ce75666Sclaudio 		while ((b = strsep(&buf, " \t\n")) != NULL) {
11661ce75666Sclaudio 			if (*b == '\0')	/* skip empty tokens */
11671ce75666Sclaudio 				continue;
11681ce75666Sclaudio 			/* Stop processing after a comment */
11691ce75666Sclaudio 			if (*b == '#')
11700ac5a32aSphessler 				break;
11714a99c744Sclaudio 			memset(&net, 0, sizeof(net));
11721ce75666Sclaudio 			if (parse_prefix(b, strlen(b), &h, &len) != 1)
11731ce75666Sclaudio 				errx(1, "bad prefix: %s", b);
117438500be7Sbenno 			net.prefix = h;
11750ac5a32aSphessler 			net.prefixlen = len;
1176a73789d3Sclaudio 			net.rd = res->rd;
11770ac5a32aSphessler 
11780ac5a32aSphessler 			if (res->action == NETWORK_BULK_ADD) {
117940466abfSclaudio 				imsg_compose(imsgbuf, IMSG_NETWORK_ADD,
11800ac5a32aSphessler 				    0, 0, -1, &net, sizeof(net));
1181143a9790Sclaudio 				/*
1182143a9790Sclaudio 				 * can't use send_filterset since that
1183143a9790Sclaudio 				 * would free the set.
1184143a9790Sclaudio 				 */
11850ac5a32aSphessler 				TAILQ_FOREACH(s, &res->set, entry) {
118640466abfSclaudio 					imsg_compose(imsgbuf,
11870ac5a32aSphessler 					    IMSG_FILTER_SET,
11880ac5a32aSphessler 					    0, 0, -1, s, sizeof(*s));
11890ac5a32aSphessler 				}
119040466abfSclaudio 				imsg_compose(imsgbuf, IMSG_NETWORK_DONE,
11910ac5a32aSphessler 				    0, 0, -1, NULL, 0);
11920ac5a32aSphessler 			} else
119340466abfSclaudio 				imsg_compose(imsgbuf, IMSG_NETWORK_REMOVE,
11940ac5a32aSphessler 				     0, 0, -1, &net, sizeof(net));
11950ac5a32aSphessler 		}
11960ac5a32aSphessler 	}
11971ce75666Sclaudio 	free(line);
11981ce75666Sclaudio 	if (ferror(f))
11991ce75666Sclaudio 		err(1, "getline");
12000ac5a32aSphessler 	fclose(f);
12010ac5a32aSphessler }
12020ac5a32aSphessler 
12030ac5a32aSphessler void
1204b5cff06cSclaudio show_mrt_dump_neighbors(struct mrt_rib *mr, struct mrt_peer *mp, void *arg)
1205b5cff06cSclaudio {
1206b5cff06cSclaudio 	struct mrt_peer_entry *p;
1207b5cff06cSclaudio 	struct in_addr ina;
120859154960Sclaudio 	uint16_t i;
1209b5cff06cSclaudio 
1210b5cff06cSclaudio 	ina.s_addr = htonl(mp->bgp_id);
1211b5cff06cSclaudio 	printf("view: %s BGP ID: %s Number of peers: %u\n\n",
1212b5cff06cSclaudio 	    mp->view, inet_ntoa(ina), mp->npeers);
1213b5cff06cSclaudio 	printf("%-30s %8s %15s\n", "Neighbor", "AS", "BGP ID");
1214b5cff06cSclaudio 	for (i = 0; i < mp->npeers; i++) {
1215b5cff06cSclaudio 		p = &mp->peers[i];
1216b5cff06cSclaudio 		ina.s_addr = htonl(p->bgp_id);
1217b5cff06cSclaudio 		printf("%-30s %8u %15s\n", log_addr(&p->addr), p->asnum,
1218b5cff06cSclaudio 		    inet_ntoa(ina));
1219b5cff06cSclaudio 	}
1220b5cff06cSclaudio 	/* we only print the first message */
1221b5cff06cSclaudio 	exit(0);
1222b5cff06cSclaudio }
1223b5cff06cSclaudio 
1224b5cff06cSclaudio void
1225a20554fdSclaudio show_mrt_dump(struct mrt_rib *mr, struct mrt_peer *mp, void *arg)
1226a20554fdSclaudio {
1227a20554fdSclaudio 	struct ctl_show_rib		 ctl;
1228a069aa25Sclaudio 	struct parse_result		 res;
1229a20554fdSclaudio 	struct ctl_show_rib_request	*req = arg;
1230a20554fdSclaudio 	struct mrt_rib_entry		*mre;
123146d5331aSclaudio 	struct ibuf			 ibuf;
1232e67b1a58Sclaudio 	time_t				 now;
123359154960Sclaudio 	uint16_t			 i, j;
1234a20554fdSclaudio 
1235a069aa25Sclaudio 	memset(&res, 0, sizeof(res));
1236a069aa25Sclaudio 	res.flags = req->flags;
1237e67b1a58Sclaudio 	now = time(NULL);
1238a069aa25Sclaudio 
1239a20554fdSclaudio 	for (i = 0; i < mr->nentries; i++) {
1240a20554fdSclaudio 		mre = &mr->entries[i];
12414a99c744Sclaudio 		memset(&ctl, 0, sizeof(ctl));
1242000f4bc7Sclaudio 		ctl.prefix = mr->prefix;
1243a20554fdSclaudio 		ctl.prefixlen = mr->prefixlen;
1244e67b1a58Sclaudio 		if (mre->originated <= now)
1245e67b1a58Sclaudio 			ctl.age = now - mre->originated;
1246000f4bc7Sclaudio 		ctl.true_nexthop = mre->nexthop;
1247000f4bc7Sclaudio 		ctl.exit_nexthop = mre->nexthop;
1248a20554fdSclaudio 		ctl.origin = mre->origin;
1249a20554fdSclaudio 		ctl.local_pref = mre->local_pref;
1250a20554fdSclaudio 		ctl.med = mre->med;
125116f78093Sclaudio 		/* weight is not part of the mrt dump so it can't be set */
12529e59dee7Sclaudio 		if (mr->add_path) {
12539e59dee7Sclaudio 			ctl.flags |= F_PREF_PATH_ID;
12549e59dee7Sclaudio 			ctl.path_id = mre->path_id;
12559e59dee7Sclaudio 		}
1256a20554fdSclaudio 
1257a20554fdSclaudio 		if (mre->peer_idx < mp->npeers) {
1258000f4bc7Sclaudio 			ctl.remote_addr = mp->peers[mre->peer_idx].addr;
1259a20554fdSclaudio 			ctl.remote_id = mp->peers[mre->peer_idx].bgp_id;
1260a20554fdSclaudio 		}
1261a20554fdSclaudio 
1262a20554fdSclaudio 		/* filter by neighbor */
1263a20554fdSclaudio 		if (req->neighbor.addr.aid != AID_UNSPEC &&
1264a20554fdSclaudio 		    memcmp(&req->neighbor.addr, &ctl.remote_addr,
1265a20554fdSclaudio 		    sizeof(ctl.remote_addr)) != 0)
1266a20554fdSclaudio 			continue;
1267a20554fdSclaudio 		/* filter by AF */
1268a20554fdSclaudio 		if (req->aid && req->aid != ctl.prefix.aid)
1269a20554fdSclaudio 			return;
1270a20554fdSclaudio 		/* filter by prefix */
1271a20554fdSclaudio 		if (req->prefix.aid != AID_UNSPEC) {
1272a20554fdSclaudio 			if (req->flags & F_LONGER) {
1273a20554fdSclaudio 				if (req->prefixlen > ctl.prefixlen)
1274a20554fdSclaudio 					return;
1275945d4f9bSclaudio 				if (prefix_compare(&req->prefix, &ctl.prefix,
1276945d4f9bSclaudio 				    req->prefixlen))
1277a20554fdSclaudio 					return;
1278945d4f9bSclaudio 			} else if (req->flags & F_SHORTER) {
1279945d4f9bSclaudio 				if (req->prefixlen < ctl.prefixlen)
1280a20554fdSclaudio 					return;
1281945d4f9bSclaudio 				if (prefix_compare(&req->prefix, &ctl.prefix,
1282945d4f9bSclaudio 				    ctl.prefixlen))
1283945d4f9bSclaudio 					return;
1284945d4f9bSclaudio 			} else {
1285945d4f9bSclaudio 				if (req->prefixlen != ctl.prefixlen)
1286945d4f9bSclaudio 					return;
1287945d4f9bSclaudio 				if (prefix_compare(&req->prefix, &ctl.prefix,
1288945d4f9bSclaudio 				    req->prefixlen))
1289945d4f9bSclaudio 					return;
1290945d4f9bSclaudio 			}
1291a20554fdSclaudio 		}
1292a20554fdSclaudio 		/* filter by AS */
12939efe3de0Sclaudio 		if (req->as.type != AS_UNDEF &&
1294291f32dfSclaudio 		    !match_aspath(mre->aspath, mre->aspath_len, &req->as))
1295f486926aSclaudio 			continue;
1296a20554fdSclaudio 
129746d5331aSclaudio 		ibuf_from_buffer(&ibuf, mre->aspath, mre->aspath_len);
129846d5331aSclaudio 		output->rib(&ctl, &ibuf, &res);
1299a20554fdSclaudio 		if (req->flags & F_CTL_DETAIL) {
1300dd147aaaSclaudio 			for (j = 0; j < mre->nattrs; j++) {
1301dd147aaaSclaudio 				ibuf_from_buffer(&ibuf, mre->attrs[j].attr,
1302dd147aaaSclaudio 				    mre->attrs[j].attr_len);
1303dd147aaaSclaudio 				output->attr(&ibuf, req->flags, 0);
1304dd147aaaSclaudio 			}
1305a069aa25Sclaudio 		}
1306a20554fdSclaudio 	}
1307a20554fdSclaudio }
1308a20554fdSclaudio 
1309a20554fdSclaudio void
1310f486926aSclaudio network_mrt_dump(struct mrt_rib *mr, struct mrt_peer *mp, void *arg)
1311f486926aSclaudio {
1312f486926aSclaudio 	struct ctl_show_rib		 ctl;
1313f486926aSclaudio 	struct network_config		 net;
1314f486926aSclaudio 	struct ctl_show_rib_request	*req = arg;
1315f486926aSclaudio 	struct mrt_rib_entry		*mre;
1316f486926aSclaudio 	struct ibuf			*msg;
1317e67b1a58Sclaudio 	time_t				 now;
131859154960Sclaudio 	uint16_t			 i, j;
1319f486926aSclaudio 
13209e59dee7Sclaudio 	/* can't announce more than one path so ignore add-path */
13219e59dee7Sclaudio 	if (mr->add_path)
13229e59dee7Sclaudio 		return;
13239e59dee7Sclaudio 
1324e67b1a58Sclaudio 	now = time(NULL);
1325f486926aSclaudio 	for (i = 0; i < mr->nentries; i++) {
1326f486926aSclaudio 		mre = &mr->entries[i];
13274a99c744Sclaudio 		memset(&ctl, 0, sizeof(ctl));
1328000f4bc7Sclaudio 		ctl.prefix = mr->prefix;
1329f486926aSclaudio 		ctl.prefixlen = mr->prefixlen;
1330e67b1a58Sclaudio 		if (mre->originated <= now)
1331e67b1a58Sclaudio 			ctl.age = now - mre->originated;
1332000f4bc7Sclaudio 		ctl.true_nexthop = mre->nexthop;
1333000f4bc7Sclaudio 		ctl.exit_nexthop = mre->nexthop;
1334f486926aSclaudio 		ctl.origin = mre->origin;
1335f486926aSclaudio 		ctl.local_pref = mre->local_pref;
1336f486926aSclaudio 		ctl.med = mre->med;
1337f486926aSclaudio 
1338f486926aSclaudio 		if (mre->peer_idx < mp->npeers) {
1339000f4bc7Sclaudio 			ctl.remote_addr = mp->peers[mre->peer_idx].addr;
1340f486926aSclaudio 			ctl.remote_id = mp->peers[mre->peer_idx].bgp_id;
1341f486926aSclaudio 		}
1342f486926aSclaudio 
1343f486926aSclaudio 		/* filter by neighbor */
1344f486926aSclaudio 		if (req->neighbor.addr.aid != AID_UNSPEC &&
1345f486926aSclaudio 		    memcmp(&req->neighbor.addr, &ctl.remote_addr,
1346f486926aSclaudio 		    sizeof(ctl.remote_addr)) != 0)
1347f486926aSclaudio 			continue;
1348f486926aSclaudio 		/* filter by AF */
1349f486926aSclaudio 		if (req->aid && req->aid != ctl.prefix.aid)
1350f486926aSclaudio 			return;
1351f486926aSclaudio 		/* filter by prefix */
1352f486926aSclaudio 		if (req->prefix.aid != AID_UNSPEC) {
1353f486926aSclaudio 			if (!prefix_compare(&req->prefix, &ctl.prefix,
1354f486926aSclaudio 			    req->prefixlen)) {
1355f486926aSclaudio 				if (req->flags & F_LONGER) {
1356f486926aSclaudio 					if (req->prefixlen > ctl.prefixlen)
1357f486926aSclaudio 						return;
1358f486926aSclaudio 				} else if (req->prefixlen != ctl.prefixlen)
1359f486926aSclaudio 					return;
1360f486926aSclaudio 			} else
1361f486926aSclaudio 				return;
1362f486926aSclaudio 		}
1363f486926aSclaudio 		/* filter by AS */
13649efe3de0Sclaudio 		if (req->as.type != AS_UNDEF &&
1365291f32dfSclaudio 		    !match_aspath(mre->aspath, mre->aspath_len, &req->as))
1366f486926aSclaudio 			continue;
1367f486926aSclaudio 
13684a99c744Sclaudio 		memset(&net, 0, sizeof(net));
136938500be7Sbenno 		net.prefix = ctl.prefix;
1370f486926aSclaudio 		net.prefixlen = ctl.prefixlen;
1371f486926aSclaudio 		net.type = NETWORK_MRTCLONE;
1372a73789d3Sclaudio 		/* XXX rd can't be set and will be 0 */
1373f486926aSclaudio 
137440466abfSclaudio 		imsg_compose(imsgbuf, IMSG_NETWORK_ADD, 0, 0, -1,
1375f486926aSclaudio 		    &net, sizeof(net));
137640466abfSclaudio 		if ((msg = imsg_create(imsgbuf, IMSG_NETWORK_ASPATH,
1377f486926aSclaudio 		    0, 0, sizeof(ctl) + mre->aspath_len)) == NULL)
1378f486926aSclaudio 			errx(1, "imsg_create failure");
1379f486926aSclaudio 		if (imsg_add(msg, &ctl, sizeof(ctl)) == -1 ||
1380f486926aSclaudio 		    imsg_add(msg, mre->aspath, mre->aspath_len) == -1)
1381f486926aSclaudio 			errx(1, "imsg_add failure");
138240466abfSclaudio 		imsg_close(imsgbuf, msg);
1383f486926aSclaudio 		for (j = 0; j < mre->nattrs; j++)
138440466abfSclaudio 			imsg_compose(imsgbuf, IMSG_NETWORK_ATTR, 0, 0, -1,
1385f486926aSclaudio 			    mre->attrs[j].attr, mre->attrs[j].attr_len);
138640466abfSclaudio 		imsg_compose(imsgbuf, IMSG_NETWORK_DONE, 0, 0, -1, NULL, 0);
1387f486926aSclaudio 
1388dd7efffeSclaudio 		if (imsgbuf_flush(imsgbuf) == -1)
1389f486926aSclaudio 			err(1, "write error");
1390f486926aSclaudio 	}
1391f486926aSclaudio }
1392f486926aSclaudio 
139385411ad9Sclaudio static const char *
139404d0a88fSclaudio fmt_time(struct timespec *t)
139585411ad9Sclaudio {
139685411ad9Sclaudio 	static char timebuf[32];
139785411ad9Sclaudio 	static struct timespec prevtime;
139885411ad9Sclaudio 	struct timespec temp;
139985411ad9Sclaudio 
140085411ad9Sclaudio 	timespecsub(t, &prevtime, &temp);
140185411ad9Sclaudio 	snprintf(timebuf, sizeof(timebuf), "%lld.%06ld",
140285411ad9Sclaudio 	    (long long)temp.tv_sec, temp.tv_nsec / 1000);
140385411ad9Sclaudio 	prevtime = *t;
140485411ad9Sclaudio 	return (timebuf);
140585411ad9Sclaudio }
140685411ad9Sclaudio 
1407f486926aSclaudio void
1408a20554fdSclaudio show_mrt_state(struct mrt_bgp_state *ms, void *arg)
1409a20554fdSclaudio {
141004d0a88fSclaudio 	printf("%s %s[%u] -> ", fmt_time(&ms->time),
1411000f4bc7Sclaudio 	    log_addr(&ms->src), ms->src_as);
1412000f4bc7Sclaudio 	printf("%s[%u]: %s -> %s\n", log_addr(&ms->dst), ms->dst_as,
1413e86c4bdeSclaudio 	    statenames[ms->old_state], statenames[ms->new_state]);
1414a20554fdSclaudio }
1415a20554fdSclaudio 
141647c6720fSclaudio static void
14176b941460Sclaudio print_afi(struct ibuf *b)
141847c6720fSclaudio {
141959154960Sclaudio 	uint16_t afi;
142059154960Sclaudio 	uint8_t safi, aid;
142147c6720fSclaudio 
14226b941460Sclaudio 	if (ibuf_get_n16(b, &afi) == -1 ||	/* afi, 2 byte */
14236b941460Sclaudio 	    ibuf_skip(b, 1) == -1 ||		/* reserved, 1 byte */
14246b941460Sclaudio 	    ibuf_get_n8(b, &safi) == -1 ||	/* safi, 1 byte */
14256b941460Sclaudio 	    ibuf_size(b) != 0) {
142647c6720fSclaudio 		printf("bad length");
142747c6720fSclaudio 		return;
142847c6720fSclaudio 	}
142947c6720fSclaudio 
143047c6720fSclaudio 	if (afi2aid(afi, safi, &aid) == -1)
14319c5d31d7Sjob 		printf("unknown afi %u safi %u", afi, safi);
143247c6720fSclaudio 	else
143347c6720fSclaudio 		printf("%s", aid2str(aid));
143447c6720fSclaudio }
143547c6720fSclaudio 
143647c6720fSclaudio static void
14376b941460Sclaudio print_capability(uint8_t capa_code, struct ibuf *b)
143847c6720fSclaudio {
14396b941460Sclaudio 	uint32_t as;
14406b941460Sclaudio 
144147c6720fSclaudio 	switch (capa_code) {
144247c6720fSclaudio 	case CAPA_MP:
144347c6720fSclaudio 		printf("multiprotocol capability: ");
14446b941460Sclaudio 		print_afi(b);
144547c6720fSclaudio 		break;
144647c6720fSclaudio 	case CAPA_REFRESH:
144747c6720fSclaudio 		printf("route refresh capability");
144847c6720fSclaudio 		break;
144947c6720fSclaudio 	case CAPA_RESTART:
145047c6720fSclaudio 		printf("graceful restart capability");
145147c6720fSclaudio 		/* XXX there is more needed here */
145247c6720fSclaudio 		break;
145347c6720fSclaudio 	case CAPA_AS4BYTE:
145447c6720fSclaudio 		printf("4-byte AS num capability: ");
14556b941460Sclaudio 		if (ibuf_get_n32(b, &as) == -1 ||
14566b941460Sclaudio 		    ibuf_size(b) != 0)
145747c6720fSclaudio 			printf("bad length");
14586b941460Sclaudio 		else
14596b941460Sclaudio 			printf("AS %u", as);
146047c6720fSclaudio 		break;
1461b6faf4c9Sclaudio 	case CAPA_ADD_PATH:
1462b6faf4c9Sclaudio 		printf("add-path capability");
1463b6faf4c9Sclaudio 		/* XXX there is more needed here */
1464b6faf4c9Sclaudio 		break;
1465b6faf4c9Sclaudio 	case CAPA_ENHANCED_RR:
1466b6faf4c9Sclaudio 		printf("enhanced route refresh capability");
1467b6faf4c9Sclaudio 		break;
146882293aebSclaudio 	case CAPA_EXT_MSG:
146982293aebSclaudio 		printf("extended message capability");
147082293aebSclaudio 		break;
147147c6720fSclaudio 	default:
14726b941460Sclaudio 		printf("unknown capability %u length %zu",
14736b941460Sclaudio 		    capa_code, ibuf_size(b));
147447c6720fSclaudio 		break;
147547c6720fSclaudio 	}
147647c6720fSclaudio }
147747c6720fSclaudio 
147847c6720fSclaudio static void
147959154960Sclaudio print_notification(uint8_t errcode, uint8_t subcode)
148047c6720fSclaudio {
148147c6720fSclaudio 	const char *suberrname = NULL;
148247c6720fSclaudio 	int uk = 0;
148347c6720fSclaudio 
148447c6720fSclaudio 	switch (errcode) {
148547c6720fSclaudio 	case ERR_HEADER:
148647c6720fSclaudio 		if (subcode >= sizeof(suberr_header_names)/sizeof(char *))
148747c6720fSclaudio 			uk = 1;
148847c6720fSclaudio 		else
148947c6720fSclaudio 			suberrname = suberr_header_names[subcode];
149047c6720fSclaudio 		break;
149147c6720fSclaudio 	case ERR_OPEN:
149247c6720fSclaudio 		if (subcode >= sizeof(suberr_open_names)/sizeof(char *))
149347c6720fSclaudio 			uk = 1;
149447c6720fSclaudio 		else
149547c6720fSclaudio 			suberrname = suberr_open_names[subcode];
149647c6720fSclaudio 		break;
149747c6720fSclaudio 	case ERR_UPDATE:
149847c6720fSclaudio 		if (subcode >= sizeof(suberr_update_names)/sizeof(char *))
149947c6720fSclaudio 			uk = 1;
150047c6720fSclaudio 		else
150147c6720fSclaudio 			suberrname = suberr_update_names[subcode];
150247c6720fSclaudio 		break;
150347c6720fSclaudio 	case ERR_CEASE:
150447c6720fSclaudio 		if (subcode >= sizeof(suberr_cease_names)/sizeof(char *))
150547c6720fSclaudio 			uk = 1;
150647c6720fSclaudio 		else
150747c6720fSclaudio 			suberrname = suberr_cease_names[subcode];
150847c6720fSclaudio 		break;
150947c6720fSclaudio 	case ERR_HOLDTIMEREXPIRED:
151047c6720fSclaudio 		if (subcode != 0)
151147c6720fSclaudio 			uk = 1;
151247c6720fSclaudio 		break;
151347c6720fSclaudio 	case ERR_FSM:
151447c6720fSclaudio 		if (subcode >= sizeof(suberr_fsm_names)/sizeof(char *))
151547c6720fSclaudio 			uk = 1;
151647c6720fSclaudio 		else
151747c6720fSclaudio 			suberrname = suberr_fsm_names[subcode];
151847c6720fSclaudio 		break;
151947c6720fSclaudio 	default:
152047c6720fSclaudio 		printf("unknown errcode %u, subcode %u",
152147c6720fSclaudio 		    errcode, subcode);
152247c6720fSclaudio 		return;
152347c6720fSclaudio 	}
152447c6720fSclaudio 
152547c6720fSclaudio 	if (uk)
152647c6720fSclaudio 		printf("%s, unknown subcode %u", errnames[errcode], subcode);
152747c6720fSclaudio 	else {
152847c6720fSclaudio 		if (suberrname == NULL)
152947c6720fSclaudio 			printf("%s", errnames[errcode]);
153047c6720fSclaudio 		else
153147c6720fSclaudio 			printf("%s, %s", errnames[errcode], suberrname);
153247c6720fSclaudio 	}
153347c6720fSclaudio }
153447c6720fSclaudio 
153547c6720fSclaudio static int
15366b941460Sclaudio show_mrt_capabilities(struct ibuf *b)
153747c6720fSclaudio {
153859154960Sclaudio 	uint8_t capa_code, capa_len;
15396b941460Sclaudio 	struct ibuf cbuf;
154047c6720fSclaudio 
15416b941460Sclaudio 	while (ibuf_size(b) > 0) {
15426b941460Sclaudio 		if (ibuf_get_n8(b, &capa_code) == -1 ||
15436b941460Sclaudio 		    ibuf_get_n8(b, &capa_len) == -1 ||
15446b941460Sclaudio 		    ibuf_get_ibuf(b, capa_len, &cbuf) == -1) {
15456b941460Sclaudio 			printf("truncated capabilities");
154647c6720fSclaudio 			return (-1);
154747c6720fSclaudio 		}
154847c6720fSclaudio 		printf("\n        ");
15496b941460Sclaudio 		print_capability(capa_code, &cbuf);
155047c6720fSclaudio 	}
15516b941460Sclaudio 	return (0);
155247c6720fSclaudio }
155347c6720fSclaudio 
155447c6720fSclaudio static void
15556b941460Sclaudio show_mrt_open(struct ibuf *b)
155647c6720fSclaudio {
1557765bd20aSclaudio 	struct in_addr ina;
1558765bd20aSclaudio 	uint32_t bgpid;
155959154960Sclaudio 	uint16_t short_as, holdtime;
156059154960Sclaudio 	uint8_t version, optparamlen;
156147c6720fSclaudio 
156247c6720fSclaudio 	/* length check up to optparamlen already happened */
15636b941460Sclaudio 	if (ibuf_get_n8(b, &version) == -1 ||
15646b941460Sclaudio 	    ibuf_get_n16(b, &short_as) == -1 ||
15656b941460Sclaudio 	    ibuf_get_n16(b, &holdtime) == -1 ||
1566765bd20aSclaudio 	    ibuf_get_n32(b, &bgpid) == -1 ||
15676b941460Sclaudio 	    ibuf_get_n8(b, &optparamlen) == -1) {
15686b941460Sclaudio  trunc:
15696b941460Sclaudio 		printf("truncated message");
15706b941460Sclaudio 		return;
15716b941460Sclaudio 	}
157247c6720fSclaudio 
157347c6720fSclaudio 	printf("\n    ");
1574765bd20aSclaudio 	ina.s_addr = htonl(bgpid);
157547c6720fSclaudio 	printf("Version: %d AS: %u Holdtime: %u BGP Id: %s Paramlen: %u",
1576765bd20aSclaudio 	    version, short_as, holdtime, inet_ntoa(ina), optparamlen);
15776b941460Sclaudio 	if (optparamlen != ibuf_size(b)) {
15786b941460Sclaudio 		/* XXX missing support for RFC9072 */
157947c6720fSclaudio 		printf("optional parameter length mismatch");
158047c6720fSclaudio 		return;
158147c6720fSclaudio 	}
15826b941460Sclaudio 	while (ibuf_size(b) > 0) {
158359154960Sclaudio 		uint8_t op_type, op_len;
158447c6720fSclaudio 
15856b941460Sclaudio 		if (ibuf_get_n8(b, &op_type) == -1 ||
15866b941460Sclaudio 		    ibuf_get_n8(b, &op_len) == -1)
15876b941460Sclaudio 			goto trunc;
158847c6720fSclaudio 
158947c6720fSclaudio 		printf("\n    ");
159047c6720fSclaudio 		switch (op_type) {
159147c6720fSclaudio 		case OPT_PARAM_CAPABILITIES:
15926b941460Sclaudio 			printf("Capabilities: %u bytes", op_len);
15936b941460Sclaudio 			if (show_mrt_capabilities(b) == -1)
159447c6720fSclaudio 				return;
159547c6720fSclaudio 			break;
159647c6720fSclaudio 		case OPT_PARAM_AUTH:
159747c6720fSclaudio 		default:
159847c6720fSclaudio 			printf("unsupported optional parameter: type %u",
159947c6720fSclaudio 			    op_type);
160047c6720fSclaudio 			return;
160147c6720fSclaudio 		}
160247c6720fSclaudio 	}
160347c6720fSclaudio }
160447c6720fSclaudio 
160547c6720fSclaudio static void
16066b941460Sclaudio show_mrt_notification(struct ibuf *b)
160747c6720fSclaudio {
1608a78f83ceSderaadt 	char reason[REASON_LEN];
16096b941460Sclaudio 	uint8_t errcode, subcode, reason_len, c;
16106b941460Sclaudio 	size_t i, len;
161147c6720fSclaudio 
16126b941460Sclaudio 	if (ibuf_get_n8(b, &errcode) == -1 ||
16136b941460Sclaudio 	    ibuf_get_n8(b, &subcode) == -1) {
16146b941460Sclaudio  trunc:
16156b941460Sclaudio 		printf("truncated message");
16166b941460Sclaudio 		return;
16176b941460Sclaudio 	}
161847c6720fSclaudio 
161947c6720fSclaudio 	printf("\n    ");
162047c6720fSclaudio 	print_notification(errcode, subcode);
162147c6720fSclaudio 
162247c6720fSclaudio 	if (errcode == ERR_CEASE && (subcode == ERR_CEASE_ADMIN_DOWN ||
162347c6720fSclaudio 	    subcode == ERR_CEASE_ADMIN_RESET)) {
16246b941460Sclaudio 		if (ibuf_size(b) > 1) {
16256b941460Sclaudio 			if (ibuf_get_n8(b, &reason_len) == -1)
16266b941460Sclaudio 				goto trunc;
16276b941460Sclaudio 			if (ibuf_get(b, reason, reason_len) == -1)
16286b941460Sclaudio 				goto trunc;
1629a78f83ceSderaadt 			reason[reason_len] = '\0';
163047c6720fSclaudio 			printf("shutdown reason: \"%s\"",
1631a78f83ceSderaadt 			    log_reason(reason));
163247c6720fSclaudio 		}
163347c6720fSclaudio 	}
163447c6720fSclaudio 	if (errcode == ERR_OPEN && subcode == ERR_OPEN_CAPA) {
16356b941460Sclaudio 		if (show_mrt_capabilities(b) == -1)
163647c6720fSclaudio 			return;
163747c6720fSclaudio 	}
163847c6720fSclaudio 
16396b941460Sclaudio 	if (ibuf_size(b) > 0) {
16406b941460Sclaudio 		len = ibuf_size(b);
16416b941460Sclaudio 		printf("\n    additional data, %zu bytes", len);
164247c6720fSclaudio 		for (i = 0; i < len; i++) {
164347c6720fSclaudio 			if (i % 16 == 0)
164447c6720fSclaudio 				printf("\n    ");
164547c6720fSclaudio 			if (i % 8 == 0)
164647c6720fSclaudio 				printf("   ");
16476b941460Sclaudio 			if (ibuf_get_n8(b, &c) == -1)
16486b941460Sclaudio 				goto trunc;
16496b941460Sclaudio 			printf(" %02X", c);
165047c6720fSclaudio 		}
165147c6720fSclaudio 	}
165247c6720fSclaudio }
165347c6720fSclaudio 
1654d30a810dSclaudio /* XXX this function does not handle JSON output */
165547c6720fSclaudio static void
16566b941460Sclaudio show_mrt_update(struct ibuf *b, int reqflags, int addpath)
165747c6720fSclaudio {
165847c6720fSclaudio 	struct bgpd_addr prefix;
16596b941460Sclaudio 	struct ibuf wbuf, abuf;
166059154960Sclaudio 	uint32_t pathid;
166159154960Sclaudio 	uint16_t wlen, alen;
166259154960Sclaudio 	uint8_t prefixlen;
166347c6720fSclaudio 
16645ad4fcbaSclaudio 	if (ibuf_get_n16(b, &wlen) == -1 ||
16655ad4fcbaSclaudio 	    ibuf_get_ibuf(b, wlen, &wbuf) == -1)
16665ad4fcbaSclaudio 		goto trunc;
16676b941460Sclaudio 
166847c6720fSclaudio 	if (wlen > 0) {
166947c6720fSclaudio 		printf("\n     Withdrawn prefixes:");
16705ad4fcbaSclaudio 		while (ibuf_size(&wbuf) > 0) {
16715ad4fcbaSclaudio 			if (addpath)
16725ad4fcbaSclaudio 				if (ibuf_get_n32(&wbuf, &pathid) == -1)
16735ad4fcbaSclaudio 					goto trunc;
16745ad4fcbaSclaudio 			if (nlri_get_prefix(&wbuf, &prefix, &prefixlen) == -1)
16755ad4fcbaSclaudio 				goto trunc;
16765ad4fcbaSclaudio 
167747c6720fSclaudio 			printf(" %s/%u", log_addr(&prefix), prefixlen);
16789e59dee7Sclaudio 			if (addpath)
16799e59dee7Sclaudio 				printf(" path-id %u", pathid);
168047c6720fSclaudio 		}
168147c6720fSclaudio 	}
168247c6720fSclaudio 
16835ad4fcbaSclaudio 	if (ibuf_get_n16(b, &alen) == -1 ||
16845ad4fcbaSclaudio 	    ibuf_get_ibuf(b, alen, &abuf) == -1)
16855ad4fcbaSclaudio 		goto trunc;
168647c6720fSclaudio 
168747c6720fSclaudio 	printf("\n");
168847c6720fSclaudio 	/* alen attributes here */
16895ad4fcbaSclaudio 	while (ibuf_size(&abuf) > 0) {
16905ad4fcbaSclaudio 		struct ibuf attrbuf;
169159154960Sclaudio 		uint16_t attrlen;
16925ad4fcbaSclaudio 		uint8_t flags;
169347c6720fSclaudio 
16945ad4fcbaSclaudio 		ibuf_from_ibuf(&abuf, &attrbuf);
16955ad4fcbaSclaudio 		if (ibuf_get_n8(&attrbuf, &flags) == -1 ||
16965ad4fcbaSclaudio 		    ibuf_skip(&attrbuf, 1) == -1)
16975ad4fcbaSclaudio 			goto trunc;
169847c6720fSclaudio 
169947c6720fSclaudio 		/* get the attribute length */
170047c6720fSclaudio 		if (flags & ATTR_EXTLEN) {
17015ad4fcbaSclaudio 			if (ibuf_get_n16(&attrbuf, &attrlen) == -1)
17025ad4fcbaSclaudio 				goto trunc;
170347c6720fSclaudio 		} else {
17045ad4fcbaSclaudio 			uint8_t tmp;
17055ad4fcbaSclaudio 			if (ibuf_get_n8(&attrbuf, &tmp) == -1)
17065ad4fcbaSclaudio 				goto trunc;
17075ad4fcbaSclaudio 			attrlen = tmp;
17085ad4fcbaSclaudio 		}
17095ad4fcbaSclaudio 		if (ibuf_truncate(&attrbuf, attrlen) == -1)
17105ad4fcbaSclaudio 			goto trunc;
17115ad4fcbaSclaudio 		ibuf_rewind(&attrbuf);
17125ad4fcbaSclaudio 		if (ibuf_skip(&abuf, ibuf_size(&attrbuf)) == -1)
17135ad4fcbaSclaudio 			goto trunc;
17145ad4fcbaSclaudio 
1715dd147aaaSclaudio 		output->attr(&attrbuf, reqflags, addpath);
171647c6720fSclaudio 	}
171747c6720fSclaudio 
17185ad4fcbaSclaudio 	if (ibuf_size(b) > 0) {
171947c6720fSclaudio 		printf("    NLRI prefixes:");
17205ad4fcbaSclaudio 		while (ibuf_size(b) > 0) {
17215ad4fcbaSclaudio 			if (addpath)
17225ad4fcbaSclaudio 				if (ibuf_get_n32(b, &pathid) == -1)
17235ad4fcbaSclaudio 					goto trunc;
17245ad4fcbaSclaudio 			if (nlri_get_prefix(b, &prefix, &prefixlen) == -1)
17255ad4fcbaSclaudio 				goto trunc;
17265ad4fcbaSclaudio 
172747c6720fSclaudio 			printf(" %s/%u", log_addr(&prefix), prefixlen);
17289e59dee7Sclaudio 			if (addpath)
17299e59dee7Sclaudio 				printf(" path-id %u", pathid);
173047c6720fSclaudio 		}
173147c6720fSclaudio 	}
17325ad4fcbaSclaudio 	return;
17335ad4fcbaSclaudio 
17345ad4fcbaSclaudio  trunc:
17355ad4fcbaSclaudio 	printf("truncated message");
173647c6720fSclaudio }
173747c6720fSclaudio 
1738a20554fdSclaudio void
1739a20554fdSclaudio show_mrt_msg(struct mrt_bgp_msg *mm, void *arg)
1740a20554fdSclaudio {
174159154960Sclaudio 	static const uint8_t marker[MSGSIZE_HEADER_MARKER] = {
174247c6720fSclaudio 	    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
174347c6720fSclaudio 	    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
17446b941460Sclaudio 	uint8_t m[MSGSIZE_HEADER_MARKER];
17456b941460Sclaudio 	struct ibuf *b;
174659154960Sclaudio 	uint16_t len;
174759154960Sclaudio 	uint8_t type;
174852d49889Sclaudio 	struct ctl_show_rib_request *req = arg;
1749e86c4bdeSclaudio 
175004d0a88fSclaudio 	printf("%s %s[%u] -> ", fmt_time(&mm->time),
1751000f4bc7Sclaudio 	    log_addr(&mm->src), mm->src_as);
17526b941460Sclaudio 	printf("%s[%u]: size %zu%s ", log_addr(&mm->dst), mm->dst_as,
17536b941460Sclaudio 	    ibuf_size(&mm->msg), mm->add_path ? " addpath" : "");
17546b941460Sclaudio 	b = &mm->msg;
175547c6720fSclaudio 
17566b941460Sclaudio 	if (ibuf_get(b, m, sizeof(m)) == -1) {
17576b941460Sclaudio 		printf("bad message: short header\n");
175847c6720fSclaudio 		return;
175947c6720fSclaudio 	}
176047c6720fSclaudio 
176147c6720fSclaudio 	/* parse BGP message header */
17626b941460Sclaudio 	if (memcmp(m, marker, sizeof(marker))) {
176347c6720fSclaudio 		printf("incorrect marker in BGP message\n");
176447c6720fSclaudio 		return;
176547c6720fSclaudio 	}
176647c6720fSclaudio 
17676b941460Sclaudio 	if (ibuf_get_n16(b, &len) == -1 ||
17686b941460Sclaudio 	    ibuf_get_n8(b, &type) == -1) {
17696b941460Sclaudio 		printf("bad message: short header\n");
17706b941460Sclaudio 		return;
17716b941460Sclaudio 	}
177247c6720fSclaudio 
177347c6720fSclaudio 	if (len < MSGSIZE_HEADER || len > MAX_PKTSIZE) {
177447c6720fSclaudio 		printf("illegal header length: %u byte\n", len);
177547c6720fSclaudio 		return;
177647c6720fSclaudio 	}
177747c6720fSclaudio 
177847c6720fSclaudio 	switch (type) {
1779*b3b12989Sclaudio 	case MSG_OPEN:
178047c6720fSclaudio 		printf("%s ", msgtypenames[type]);
178147c6720fSclaudio 		if (len < MSGSIZE_OPEN_MIN) {
17826b941460Sclaudio 			printf("bad length: %u bytes\n", len);
178347c6720fSclaudio 			return;
178447c6720fSclaudio 		}
17856b941460Sclaudio 		show_mrt_open(b);
178647c6720fSclaudio 		break;
1787*b3b12989Sclaudio 	case MSG_NOTIFICATION:
178847c6720fSclaudio 		printf("%s ", msgtypenames[type]);
178947c6720fSclaudio 		if (len < MSGSIZE_NOTIFICATION_MIN) {
17906b941460Sclaudio 			printf("bad length: %u bytes\n", len);
179147c6720fSclaudio 			return;
179247c6720fSclaudio 		}
17936b941460Sclaudio 		show_mrt_notification(b);
179447c6720fSclaudio 		break;
1795*b3b12989Sclaudio 	case MSG_UPDATE:
179647c6720fSclaudio 		printf("%s ", msgtypenames[type]);
179747c6720fSclaudio 		if (len < MSGSIZE_UPDATE_MIN) {
17986b941460Sclaudio 			printf("bad length: %u bytes\n", len);
179947c6720fSclaudio 			return;
180047c6720fSclaudio 		}
18016b941460Sclaudio 		show_mrt_update(b, req->flags, mm->add_path);
180247c6720fSclaudio 		break;
1803*b3b12989Sclaudio 	case MSG_KEEPALIVE:
180447c6720fSclaudio 		printf("%s ", msgtypenames[type]);
180547c6720fSclaudio 		if (len != MSGSIZE_KEEPALIVE) {
18066b941460Sclaudio 			printf("bad length: %u bytes\n", len);
180747c6720fSclaudio 			return;
180847c6720fSclaudio 		}
180947c6720fSclaudio 		/* nothing */
181047c6720fSclaudio 		break;
1811*b3b12989Sclaudio 	case MSG_RREFRESH:
181247c6720fSclaudio 		printf("%s ", msgtypenames[type]);
181347c6720fSclaudio 		if (len != MSGSIZE_RREFRESH) {
18146b941460Sclaudio 			printf("bad length: %u bytes\n", len);
181547c6720fSclaudio 			return;
181647c6720fSclaudio 		}
18176b941460Sclaudio 		print_afi(b);
181847c6720fSclaudio 		break;
181947c6720fSclaudio 	default:
182047c6720fSclaudio 		printf("unknown type %u\n", type);
182147c6720fSclaudio 		return;
182247c6720fSclaudio 	}
182347c6720fSclaudio 	printf("\n");
1824a20554fdSclaudio }
1825a20554fdSclaudio 
1826e86c4bdeSclaudio const char *
182759154960Sclaudio msg_type(uint8_t type)
1828e86c4bdeSclaudio {
1829e86c4bdeSclaudio 	if (type >= sizeof(msgtypenames)/sizeof(msgtypenames[0]))
1830e86c4bdeSclaudio 		return "BAD";
1831e86c4bdeSclaudio 	return (msgtypenames[type]);
1832e86c4bdeSclaudio }
1833ddebc6f6Sclaudio 
1834722ee4e7Sclaudio int
183559154960Sclaudio match_aspath(void *data, uint16_t len, struct filter_as *f)
1836ddebc6f6Sclaudio {
183759154960Sclaudio 	uint8_t		*seg;
1838291f32dfSclaudio 	int		 final;
183959154960Sclaudio 	uint16_t	 seg_size;
184059154960Sclaudio 	uint8_t		 i, seg_len;
184159154960Sclaudio 	uint32_t	 as = 0;
1842291f32dfSclaudio 
1843291f32dfSclaudio 	if (f->type == AS_EMPTY) {
1844291f32dfSclaudio 		if (len == 0)
1845291f32dfSclaudio 			return (1);
1846291f32dfSclaudio 		else
1847291f32dfSclaudio 			return (0);
1848291f32dfSclaudio 	}
1849291f32dfSclaudio 
1850291f32dfSclaudio 	seg = data;
1851291f32dfSclaudio 
1852291f32dfSclaudio 	/* just check the leftmost AS */
1853291f32dfSclaudio 	if (f->type == AS_PEER && len >= 6) {
1854291f32dfSclaudio 		as = aspath_extract(seg, 0);
1855291f32dfSclaudio 		if (f->as_min == as)
1856291f32dfSclaudio 			return (1);
1857291f32dfSclaudio 		else
1858291f32dfSclaudio 			return (0);
1859291f32dfSclaudio 	}
1860291f32dfSclaudio 
1861291f32dfSclaudio 	for (; len >= 6; len -= seg_size, seg += seg_size) {
1862291f32dfSclaudio 		seg_len = seg[1];
186359154960Sclaudio 		seg_size = 2 + sizeof(uint32_t) * seg_len;
1864291f32dfSclaudio 
1865291f32dfSclaudio 		final = (len == seg_size);
1866291f32dfSclaudio 
1867291f32dfSclaudio 		if (f->type == AS_SOURCE) {
1868291f32dfSclaudio 			/*
1869291f32dfSclaudio 			 * Just extract the rightmost AS
1870291f32dfSclaudio 			 * but if that segment is an AS_SET then the rightmost
1871291f32dfSclaudio 			 * AS of a previous AS_SEQUENCE segment should be used.
1872291f32dfSclaudio 			 * Because of that just look at AS_SEQUENCE segments.
1873291f32dfSclaudio 			 */
1874291f32dfSclaudio 			if (seg[0] == AS_SEQUENCE)
1875291f32dfSclaudio 				as = aspath_extract(seg, seg_len - 1);
1876291f32dfSclaudio 			/* not yet in the final segment */
1877291f32dfSclaudio 			if (!final)
1878291f32dfSclaudio 				continue;
1879291f32dfSclaudio 			if (f->as_min == as)
1880291f32dfSclaudio 				return (1);
1881291f32dfSclaudio 			else
1882291f32dfSclaudio 				return (0);
1883291f32dfSclaudio 		}
1884291f32dfSclaudio 		/* AS_TRANSIT or AS_ALL */
1885291f32dfSclaudio 		for (i = 0; i < seg_len; i++) {
1886291f32dfSclaudio 			/*
1887291f32dfSclaudio 			 * the source (rightmost) AS is excluded from
1888291f32dfSclaudio 			 * AS_TRANSIT matches.
1889291f32dfSclaudio 			 */
1890291f32dfSclaudio 			if (final && i == seg_len - 1 && f->type == AS_TRANSIT)
1891291f32dfSclaudio 				return (0);
1892291f32dfSclaudio 			as = aspath_extract(seg, i);
1893291f32dfSclaudio 			if (f->as_min == as)
1894291f32dfSclaudio 				return (1);
1895291f32dfSclaudio 		}
1896291f32dfSclaudio 	}
1897722ee4e7Sclaudio 	return (0);
1898ddebc6f6Sclaudio }
1899e3925e28Sclaudio 
1900e3925e28Sclaudio static void
1901e3925e28Sclaudio component_finish(int type, uint8_t *data, int len)
1902e3925e28Sclaudio {
1903e3925e28Sclaudio 	uint8_t *last;
1904e3925e28Sclaudio 	int i;
1905e3925e28Sclaudio 
1906e3925e28Sclaudio 	switch (type) {
1907e3925e28Sclaudio 	case FLOWSPEC_TYPE_DEST:
1908e3925e28Sclaudio 	case FLOWSPEC_TYPE_SOURCE:
1909e3925e28Sclaudio 		/* nothing todo */
1910e3925e28Sclaudio 		return;
1911e3925e28Sclaudio 	default:
1912e3925e28Sclaudio 		break;
1913e3925e28Sclaudio 	}
1914e3925e28Sclaudio 
1915e3925e28Sclaudio 	i = 0;
1916e3925e28Sclaudio 	do {
1917e3925e28Sclaudio 		last = data + i;
1918e3925e28Sclaudio 		i += FLOWSPEC_OP_LEN(*last) + 1;
1919e3925e28Sclaudio 	} while (i < len);
1920e3925e28Sclaudio 	*last |= FLOWSPEC_OP_EOL;
1921e3925e28Sclaudio }
1922e3925e28Sclaudio 
1923e3925e28Sclaudio static void
1924e3925e28Sclaudio push_prefix(struct parse_result *r, int type, struct bgpd_addr *addr,
1925e3925e28Sclaudio     uint8_t len)
1926e3925e28Sclaudio {
1927e3925e28Sclaudio 	void *data;
1928e3925e28Sclaudio 	uint8_t *comp;
1929e3925e28Sclaudio 	int complen, l;
1930e3925e28Sclaudio 
1931e3925e28Sclaudio 	switch (addr->aid) {
1932e3925e28Sclaudio 	case AID_UNSPEC:
1933e3925e28Sclaudio 		return;
1934e3925e28Sclaudio 	case AID_INET:
1935e3925e28Sclaudio 		complen = PREFIX_SIZE(len);
1936e3925e28Sclaudio 		data = &addr->v4;
1937e3925e28Sclaudio 		break;
1938e3925e28Sclaudio 	case AID_INET6:
1939e3925e28Sclaudio 		/* IPv6 includes an offset byte */
1940e3925e28Sclaudio 		complen = PREFIX_SIZE(len) + 1;
1941e3925e28Sclaudio 		data = &addr->v6;
1942e3925e28Sclaudio 		break;
19435cff40bcSclaudio 	default:
19445cff40bcSclaudio 		errx(1, "unsupported address family for flowspec address");
1945e3925e28Sclaudio 	}
1946e3925e28Sclaudio 	comp = malloc(complen);
1947e3925e28Sclaudio 	if (comp == NULL)
1948e3925e28Sclaudio 		err(1, NULL);
1949e3925e28Sclaudio 
1950e3925e28Sclaudio 	l = 0;
1951e3925e28Sclaudio 	comp[l++] = len;
1952e3925e28Sclaudio 	if (addr->aid == AID_INET6)
1953e3925e28Sclaudio 		comp[l++] = 0;
1954e3925e28Sclaudio 	memcpy(comp + l, data, complen - l);
1955e3925e28Sclaudio 
1956e3925e28Sclaudio 	r->flow.complen[type] = complen;
1957e3925e28Sclaudio 	r->flow.components[type] = comp;
1958e3925e28Sclaudio }
1959e3925e28Sclaudio 
1960e3925e28Sclaudio 
1961e3925e28Sclaudio struct flowspec *
1962e3925e28Sclaudio res_to_flowspec(struct parse_result *r)
1963e3925e28Sclaudio {
1964e3925e28Sclaudio 	struct flowspec *f;
1965e3925e28Sclaudio 	int i, len = 0;
1966e3925e28Sclaudio 	uint8_t aid;
1967e3925e28Sclaudio 
1968e3925e28Sclaudio 	switch (r->aid) {
1969e3925e28Sclaudio 	case AID_INET:
1970e3925e28Sclaudio 		aid = AID_FLOWSPECv4;
1971e3925e28Sclaudio 		break;
1972e3925e28Sclaudio 	case AID_INET6:
1973e3925e28Sclaudio 		aid = AID_FLOWSPECv6;
1974e3925e28Sclaudio 		break;
1975e3925e28Sclaudio 	default:
1976e3925e28Sclaudio 		errx(1, "unsupported AFI %s for flowspec rule",
1977e3925e28Sclaudio 		    aid2str(r->aid));
1978e3925e28Sclaudio 	}
1979e3925e28Sclaudio 
1980e3925e28Sclaudio 	push_prefix(r, FLOWSPEC_TYPE_DEST, &r->flow.dst, r->flow.dstlen);
1981e3925e28Sclaudio 	push_prefix(r, FLOWSPEC_TYPE_SOURCE, &r->flow.src, r->flow.srclen);
1982e3925e28Sclaudio 
1983e3925e28Sclaudio 	for (i = FLOWSPEC_TYPE_MIN; i < FLOWSPEC_TYPE_MAX; i++)
1984e3925e28Sclaudio 		if (r->flow.components[i] != NULL)
1985e3925e28Sclaudio 			len += r->flow.complen[i] + 1;
1986e3925e28Sclaudio 
1987e3925e28Sclaudio 	if (len == 0)
1988e3925e28Sclaudio 		errx(1, "no flowspec rule defined");
1989e3925e28Sclaudio 
1990e3925e28Sclaudio 	f = malloc(FLOWSPEC_SIZE + len);
1991e3925e28Sclaudio 	if (f == NULL)
1992e3925e28Sclaudio 		err(1, NULL);
1993e3925e28Sclaudio 	memset(f, 0, FLOWSPEC_SIZE);
1994e3925e28Sclaudio 
1995e3925e28Sclaudio 	f->aid = aid;
1996e3925e28Sclaudio 	f->len = len;
1997e3925e28Sclaudio 
1998e3925e28Sclaudio 	len = 0;
1999e3925e28Sclaudio 	for (i = FLOWSPEC_TYPE_MIN; i < FLOWSPEC_TYPE_MAX; i++)
2000e3925e28Sclaudio 		if (r->flow.components[i] != NULL) {
2001e3925e28Sclaudio 			f->data[len++] = i;
2002e3925e28Sclaudio 			component_finish(i, r->flow.components[i],
2003e3925e28Sclaudio 			    r->flow.complen[i]);
2004e3925e28Sclaudio 			memcpy(f->data + len, r->flow.components[i],
2005e3925e28Sclaudio 			    r->flow.complen[i]);
2006e3925e28Sclaudio 			len += r->flow.complen[i];
2007e3925e28Sclaudio 		}
2008e3925e28Sclaudio 
2009e3925e28Sclaudio 	return f;
2010e3925e28Sclaudio }
2011