xref: /openbsd/usr.sbin/bgpctl/output_json.c (revision 55cc5ba3)
1 /*	$OpenBSD: output_json.c,v 1.6 2021/01/25 09:17:33 claudio Exp $ */
2 
3 /*
4  * Copyright (c) 2020 Claudio Jeker <claudio@openbsd.org>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include <endian.h>
20 #include <err.h>
21 #include <math.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 
26 #include "bgpd.h"
27 #include "session.h"
28 #include "rde.h"
29 
30 #include "bgpctl.h"
31 #include "parser.h"
32 #include "json.h"
33 
34 static void
35 json_head(struct parse_result *res)
36 {
37 	json_do_start();
38 }
39 
40 static void
41 json_neighbor_capabilities(struct capabilities *capa)
42 {
43 	int hascapamp;
44 	uint8_t i;
45 
46 	for (i = 0; i < AID_MAX; i++)
47 		if (capa->mp[i])
48 			hascapamp = 1;
49 	if (!hascapamp && !capa->refresh && !capa->grestart.restart &&
50 	    !capa->as4byte)
51 		return;
52 
53 	json_do_object("capabilities");
54 	json_do_bool("as4byte", capa->as4byte);
55 	json_do_bool("refresh", capa->refresh);
56 
57 	if (hascapamp) {
58 		json_do_array("multiprotocol");
59 		for (i = 0; i < AID_MAX; i++)
60 			if (capa->mp[i])
61 				json_do_printf("mp", "%s", aid2str(i));
62 		json_do_end();
63 	}
64 	if (capa->grestart.restart) {
65 		int restarted = 0, present = 0;
66 
67 		for (i = 0; i < AID_MAX; i++)
68 			if (capa->grestart.flags[i] & CAPA_GR_PRESENT) {
69 				present = 1;
70 				if (capa->grestart.flags[i] & CAPA_GR_RESTART)
71 					restarted = 1;
72 				break;
73 			}
74 		json_do_object("graceful_restart");
75 		json_do_bool("eor", 1);
76 		json_do_bool("restart", restarted);
77 
78 		if (capa->grestart.timeout)
79 			json_do_uint("timeout", capa->grestart.timeout);
80 
81 		if (present) {
82 			json_do_array("protocols");
83 			for (i = 0; i < AID_MAX; i++)
84 				if (capa->grestart.flags[i] & CAPA_GR_PRESENT) {
85 					json_do_object("family");
86 					json_do_printf("family", "%s",
87 					    aid2str(i));
88 					json_do_bool("preserved",
89 					    capa->grestart.flags[i] &
90 					    CAPA_GR_FORWARD);
91 					json_do_end();
92 				}
93 			json_do_end();
94 		}
95 
96 		json_do_end();
97 	}
98 
99 	json_do_end();
100 }
101 
102 static void
103 json_neighbor_stats(struct peer *p)
104 {
105 	json_do_object("stats");
106 	json_do_printf("last_read", "%s", fmt_monotime(p->stats.last_read));
107 	json_do_printf("last_write", "%s", fmt_monotime(p->stats.last_write));
108 
109 	json_do_object("prefixes");
110 	json_do_uint("sent", p->stats.prefix_out_cnt);
111 	json_do_uint("received", p->stats.prefix_cnt);
112 	json_do_end();
113 
114 	json_do_object("message");
115 
116 	json_do_object("sent");
117 	json_do_uint("open", p->stats.msg_sent_open);
118 	json_do_uint("notifications", p->stats.msg_sent_notification);
119 	json_do_uint("updates", p->stats.msg_sent_update);
120 	json_do_uint("keepalives", p->stats.msg_sent_keepalive);
121 	json_do_uint("route_refresh", p->stats.msg_sent_rrefresh);
122 	json_do_uint("total",
123 	    p->stats.msg_sent_open + p->stats.msg_sent_notification +
124 	    p->stats.msg_sent_update + p->stats.msg_sent_keepalive +
125 	    p->stats.msg_sent_rrefresh);
126 	json_do_end();
127 
128 	json_do_object("received");
129 	json_do_uint("open", p->stats.msg_rcvd_open);
130 	json_do_uint("notifications", p->stats.msg_rcvd_notification);
131 	json_do_uint("updates", p->stats.msg_rcvd_update);
132 	json_do_uint("keepalives", p->stats.msg_rcvd_keepalive);
133 	json_do_uint("route_refresh", p->stats.msg_rcvd_rrefresh);
134 	json_do_uint("total",
135 	    p->stats.msg_rcvd_open + p->stats.msg_rcvd_notification +
136 	    p->stats.msg_rcvd_update + p->stats.msg_rcvd_keepalive +
137 	    p->stats.msg_rcvd_rrefresh);
138 	json_do_end();
139 
140 	json_do_end();
141 
142 	json_do_object("update");
143 
144 	json_do_object("sent");
145 	json_do_uint("updates", p->stats.prefix_sent_update);
146 	json_do_uint("withdraws", p->stats.prefix_sent_withdraw);
147 	json_do_uint("eor", p->stats.prefix_sent_eor);
148 	json_do_end();
149 
150 	json_do_object("received");
151 	json_do_uint("updates", p->stats.prefix_rcvd_update);
152 	json_do_uint("withdraws", p->stats.prefix_rcvd_withdraw);
153 	json_do_uint("eor", p->stats.prefix_rcvd_eor);
154 	json_do_end();
155 
156 	json_do_end();
157 
158 	json_do_end();
159 }
160 
161 static void
162 json_neighbor_full(struct peer *p)
163 {
164 	const char *errstr;
165 
166 	/* config */
167 	json_do_object("config");
168 	json_do_bool("template", p->conf.template);
169 	json_do_bool("cloned", p->template != NULL);
170 	json_do_bool("passive", p->conf.passive);
171 	json_do_bool("down", p->conf.down);
172 	json_do_bool("multihop", p->conf.ebgp && p->conf.distance > 1);
173 	if (p->conf.ebgp && p->conf.distance > 1)
174 		json_do_uint("multihop_distance", p->conf.distance);
175 	if (p->conf.max_prefix) {
176 		json_do_uint("max_prefix", p->conf.max_prefix);
177 		if (p->conf.max_prefix_restart)
178 			json_do_uint("max_prefix_restart",
179 			    p->conf.max_prefix_restart);
180 	}
181 	if (p->conf.max_out_prefix) {
182 		json_do_uint("max_out_prefix", p->conf.max_out_prefix);
183 		if (p->conf.max_out_prefix_restart)
184 			json_do_uint("max_out_prefix_restart",
185 			    p->conf.max_out_prefix_restart);
186 	}
187 	if (p->auth.method != AUTH_NONE)
188 		json_do_printf("authentication", "%s",
189 		    fmt_auth_method(p->auth.method));
190 	json_do_bool("ttl_security", p->conf.ttlsec);
191 	json_do_uint("holdtime", p->conf.holdtime);
192 	json_do_uint("min_holdtime", p->conf.min_holdtime);
193 
194 	/* capabilities */
195 	json_do_bool("announce_capabilities", p->conf.announce_capa);
196 	json_neighbor_capabilities(&p->conf.capabilities);
197 
198 	json_do_end();
199 
200 
201 	/* stats */
202 	json_neighbor_stats(p);
203 
204 	/* errors */
205 	if (*(p->conf.reason))
206 		json_do_printf("my_shutdown_reason", "%s",
207 		    log_reason(p->conf.reason));
208 	if (*(p->stats.last_reason))
209 		json_do_printf("last_shutdown_reason", "%s",
210 		    log_reason(p->stats.last_reason));
211 	errstr = fmt_errstr(p->stats.last_sent_errcode,
212 	    p->stats.last_sent_suberr);
213 	if (errstr)
214 		json_do_printf("last_error_sent", "%s", errstr);
215 	errstr = fmt_errstr(p->stats.last_rcvd_errcode,
216 	    p->stats.last_rcvd_suberr);
217 	if (errstr)
218 		json_do_printf("last_error_received", "%s", errstr);
219 
220 	/* connection info */
221 	if (p->state >= STATE_OPENSENT) {
222 		json_do_object("session");
223 		json_do_uint("holdtime", p->holdtime);
224 		json_do_uint("keepalive", p->holdtime / 3);
225 
226 		json_do_object("local");
227 		json_do_printf("address", "%s", log_addr(&p->local));
228 		json_do_uint("port", p->local_port);
229 		json_neighbor_capabilities(&p->capa.ann);
230 		json_do_end();
231 
232 		json_do_object("remote");
233 		json_do_printf("address", "%s", log_addr(&p->remote));
234 		json_do_uint("port", p->remote_port);
235 		json_neighbor_capabilities(&p->capa.peer);
236 		json_do_end();
237 
238 		/* capabilities */
239 		json_neighbor_capabilities(&p->capa.neg);
240 
241 		json_do_end();
242 	}
243 }
244 
245 static void
246 json_neighbor(struct peer *p, struct parse_result *res)
247 {
248 	json_do_array("neighbors");
249 
250 	json_do_object("neighbor");
251 
252 	json_do_printf("remote_as", "%s", log_as(p->conf.remote_as));
253 	if (p->conf.descr[0])
254 		json_do_printf("description", "%s", p->conf.descr);
255 	if (p->conf.group[0])
256 		json_do_printf("group", "%s", p->conf.group);
257 	if (!p->conf.template)
258 		json_do_printf("remote_addr", "%s",
259 		    log_addr(&p->conf.remote_addr));
260 	else
261 		json_do_printf("remote_addr", "%s/%u",
262 		    log_addr(&p->conf.remote_addr), p->conf.remote_masklen);
263 	if (p->state == STATE_ESTABLISHED) {
264 		struct in_addr ina;
265 		ina.s_addr = p->remote_bgpid;
266 		json_do_printf("bgpid", "%s", inet_ntoa(ina));
267 	}
268 	json_do_printf("state", "%s", statenames[p->state]);
269 	json_do_printf("last_updown", "%s", fmt_monotime(p->stats.last_updown));
270 
271 	switch (res->action) {
272 	case SHOW:
273 	case SHOW_SUMMARY:
274 	case SHOW_SUMMARY_TERSE:
275 		/* only show basic data */
276 		break;
277 	case SHOW_NEIGHBOR:
278 	case SHOW_NEIGHBOR_TIMERS:
279 	case SHOW_NEIGHBOR_TERSE:
280 		json_neighbor_full(p);
281 		break;
282 	default:
283 		break;
284 	}
285 
286 	/* keep the object open in case there are timers */
287 }
288 
289 static void
290 json_timer(struct ctl_timer *t)
291 {
292 	json_do_array("timers");
293 
294 	json_do_object("timer");
295 	json_do_printf("name", "%s", timernames[t->type]);
296 	json_do_int("due", t->val);
297 	json_do_end();
298 }
299 
300 static void
301 json_fib(struct kroute_full *kf)
302 {
303 	const char *origin;
304 
305 	json_do_array("fib");
306 
307 	json_do_object("fib_entry");
308 
309 	json_do_printf("prefix", "%s/%u", log_addr(&kf->prefix), kf->prefixlen);
310 	json_do_uint("priority", kf->priority);
311 	json_do_bool("up", !(kf->flags & F_DOWN));
312 	if (kf->flags & F_BGPD_INSERTED)
313 		origin = "bgp";
314 	else if (kf->flags & F_CONNECTED)
315 		origin = "connected";
316 	else if (kf->flags & F_STATIC)
317 		origin = "static";
318 	else if (kf->flags & F_DYNAMIC)
319 		origin = "dynamic";
320 	else
321 		origin = "unknown";
322 	json_do_printf("origin", "%s", origin);
323 	json_do_bool("used_by_nexthop", kf->flags & F_NEXTHOP);
324 	json_do_bool("blackhole", kf->flags & F_BLACKHOLE);
325 	json_do_bool("reject", kf->flags & F_REJECT);
326 
327 	if (kf->flags & F_CONNECTED)
328 		json_do_printf("nexthop", "link#%u", kf->ifindex);
329 	else
330 		json_do_printf("nexthop", "%s", log_addr(&kf->nexthop));
331 
332 	json_do_end();
333 }
334 
335 static void
336 json_fib_table(struct ktable *kt)
337 {
338 	json_do_array("fibtables");
339 
340 	json_do_object("fibtable");
341 	json_do_uint("rtableid", kt->rtableid);
342 	json_do_printf("description", "%s", kt->descr);
343 	json_do_bool("coupled", kt->fib_sync);
344 	json_do_bool("admin_change", kt->fib_sync != kt->fib_conf);
345 	json_do_end();
346 }
347 
348 static void
349 json_do_interface(struct ctl_show_interface *iface)
350 {
351 	json_do_object("interface");
352 
353 	json_do_printf("name", "%s", iface->ifname);
354 	json_do_uint("rdomain", iface->rdomain);
355 	json_do_bool("is_up", iface->is_up);
356 	json_do_bool("nh_reachable", iface->nh_reachable);
357 
358 	if (iface->media[0])
359 		json_do_printf("media", "%s", iface->media);
360 
361 	json_do_printf("linkstate", "%s", iface->linkstate);
362 	if (iface->baudrate > 0)
363 		json_do_uint("baudrate", iface->baudrate);
364 
365 	json_do_end();
366 }
367 
368 static void
369 json_nexthop(struct ctl_show_nexthop *nh)
370 {
371 	struct kroute *k;
372 	struct kroute6 *k6;
373 
374 	json_do_array("nexthops");
375 
376 	json_do_object("nexthop");
377 
378 	json_do_printf("address", "%s", log_addr(&nh->addr));
379 	json_do_bool("valid", nh->valid);
380 
381 	if (!nh->krvalid)
382 		goto done;
383 
384 	switch (nh->addr.aid) {
385 	case AID_INET:
386 		k = &nh->kr.kr4;
387 		json_do_printf("prefix", "%s/%u", inet_ntoa(k->prefix),
388 		    k->prefixlen);
389 		json_do_uint("priority", k->priority);
390 		json_do_bool("connected", k->flags & F_CONNECTED);
391 		json_do_printf("nexthop", "%s", inet_ntoa(k->nexthop));
392 		break;
393 	case AID_INET6:
394 		k6 = &nh->kr.kr6;
395 		json_do_printf("prefix", "%s/%u", log_in6addr(&k6->prefix),
396 		    k6->prefixlen);
397 		json_do_uint("priority", k6->priority);
398 		json_do_bool("connected", k6->flags & F_CONNECTED);
399 		json_do_printf("nexthop", "%s", log_in6addr(&k6->nexthop));
400 		break;
401 	default:
402 		warnx("nexthop: unknown address family");
403 		goto done;
404 	}
405 	if (nh->iface.ifname[0])
406 		json_do_interface(&nh->iface);
407 done:
408 	json_do_end();
409 	/* keep array open */
410 }
411 
412 static void
413 json_interface(struct ctl_show_interface *iface)
414 {
415 	json_do_array("interfaces");
416 	json_do_interface(iface);
417 }
418 
419 static void
420 json_communities(u_char *data, size_t len, struct parse_result *res)
421 {
422 	struct community c;
423 	size_t  i;
424 	uint64_t ext;
425 
426 	if (len % sizeof(c)) {
427 		warnx("communities: bad size");
428 		return;
429 	}
430 
431 	for (i = 0; i < len; i += sizeof(c)) {
432 		memcpy(&c, data + i, sizeof(c));
433 
434 		switch (c.flags) {
435 		case COMMUNITY_TYPE_BASIC:
436 			json_do_array("communities");
437 			json_do_printf("community", "%s",
438 			    fmt_community(c.data1, c.data2));
439 			break;
440 		case COMMUNITY_TYPE_LARGE:
441 			json_do_array("large_communities");
442 			json_do_printf("community", "%s",
443 			    fmt_large_community(c.data1, c.data2, c.data3));
444 			break;
445 		case COMMUNITY_TYPE_EXT:
446 			ext = (uint64_t)c.data3 << 48;
447 			switch (c.data3 >> 8) {
448 			case EXT_COMMUNITY_TRANS_TWO_AS:
449 			case EXT_COMMUNITY_TRANS_OPAQUE:
450 			case EXT_COMMUNITY_TRANS_EVPN:
451 			case EXT_COMMUNITY_NON_TRANS_OPAQUE:
452 				ext |= ((uint64_t)c.data1 & 0xffff) << 32;
453 				ext |= (uint64_t)c.data2;
454 				break;
455 			case EXT_COMMUNITY_TRANS_FOUR_AS:
456 			case EXT_COMMUNITY_TRANS_IPV4:
457 				ext |= (uint64_t)c.data1 << 16;
458 				ext |= (uint64_t)c.data2 & 0xffff;
459 				break;
460 			}
461 			ext = htobe64(ext);
462 
463 			json_do_array("extended_communities");
464 			json_do_printf("community", "%s",
465 			    fmt_ext_community((void *)&ext));
466 			break;
467 		}
468 	}
469 }
470 
471 static void
472 json_do_community(u_char *data, uint16_t len)
473 {
474 	uint16_t a, v, i;
475 
476 	if (len & 0x3) {
477 		json_do_printf("error", "bad length");
478 		return;
479 	}
480 
481 	json_do_array("communities");
482 
483 	for (i = 0; i < len; i += 4) {
484 		memcpy(&a, data + i, sizeof(a));
485 		memcpy(&v, data + i + 2, sizeof(v));
486 		a = ntohs(a);
487 		v = ntohs(v);
488 		json_do_printf("community", "%s", fmt_community(a, v));
489 	}
490 
491 	json_do_end();
492 }
493 
494 static void
495 json_do_large_community(u_char *data, uint16_t len)
496 {
497 	uint32_t a, l1, l2;
498 	u_int16_t i;
499 
500 	if (len % 12) {
501 		json_do_printf("error", "bad length");
502 		return;
503 	}
504 
505 	json_do_array("large_communities");
506 
507 	for (i = 0; i < len; i += 12) {
508 		memcpy(&a, data + i, sizeof(a));
509 		memcpy(&l1, data + i + 4, sizeof(l1));
510 		memcpy(&l2, data + i + 8, sizeof(l2));
511 		a = ntohl(a);
512 		l1 = ntohl(l1);
513 		l2 = ntohl(l2);
514 
515 		json_do_printf("community", "%s",
516 		    fmt_large_community(a, l1, l2));
517 	}
518 
519 	json_do_end();
520 }
521 
522 static void
523 json_do_ext_community(u_char *data, uint16_t len)
524 {
525 	uint16_t i;
526 
527 	if (len & 0x7) {
528 		json_do_printf("error", "bad length");
529 		return;
530 	}
531 
532 	json_do_array("extended_communities");
533 
534 	for (i = 0; i < len; i += 8)
535 		json_do_printf("community", "%s", fmt_ext_community(data + i));
536 
537 	json_do_end();
538 }
539 
540 static void
541 json_attr(u_char *data, size_t len, struct parse_result *res)
542 {
543 	struct bgpd_addr prefix;
544 	struct in_addr id;
545 	char *aspath;
546 	u_char *path;
547 	uint32_t as;
548 	uint16_t alen, afi, off, short_as;
549 	uint8_t flags, type, safi, aid, prefixlen;
550 	int e4, e2, pos;
551 
552 	if (len < 3) {
553 		warnx("Too short BGP attrbute");
554 		return;
555 	}
556 
557 	flags = data[0];
558 	type = data[1];
559 	if (flags & ATTR_EXTLEN) {
560 		if (len < 4) {
561 			warnx("Too short BGP attrbute");
562 			return;
563 		}
564 		memcpy(&alen, data+2, sizeof(uint16_t));
565 		alen = ntohs(alen);
566 		data += 4;
567 		len -= 4;
568 	} else {
569 		alen = data[2];
570 		data += 3;
571 		len -= 3;
572 	}
573 
574 	/* bad imsg len how can that happen!? */
575 	if (alen > len) {
576 		warnx("Bad BGP attrbute length");
577 		return;
578 	}
579 
580 	json_do_array("attributes");
581 
582 	json_do_object("attribute");
583 	json_do_printf("type", "%s", fmt_attr(type, -1));
584 	json_do_uint("length", alen);
585 	json_do_object("flags");
586 	json_do_bool("partial", flags & ATTR_PARTIAL);
587 	json_do_bool("transitive", flags & ATTR_TRANSITIVE);
588 	json_do_bool("optional", flags & ATTR_OPTIONAL);
589 	json_do_end();
590 
591 	switch (type) {
592 	case ATTR_ORIGIN:
593 		if (alen == 1)
594 			json_do_printf("origin", "%s", fmt_origin(*data, 0));
595 		else
596 			json_do_printf("error", "bad length");
597 		break;
598 	case ATTR_ASPATH:
599 	case ATTR_AS4_PATH:
600 		/* prefer 4-byte AS here */
601 		e4 = aspath_verify(data, alen, 1, 0);
602 		e2 = aspath_verify(data, alen, 0, 0);
603 		if (e4 == 0 || e4 == AS_ERR_SOFT) {
604 			path = data;
605 		} else if (e2 == 0 || e2 == AS_ERR_SOFT) {
606 			path = aspath_inflate(data, alen, &alen);
607 			if (path == NULL)
608 				errx(1, "aspath_inflate failed");
609 		} else {
610 			json_do_printf("error", "bad AS-Path");
611 			break;
612 		}
613 		if (aspath_asprint(&aspath, path, alen) == -1)
614 			err(1, NULL);
615 		json_do_printf("aspath", "%s", aspath);
616 		free(aspath);
617 		if (path != data)
618 			free(path);
619 		break;
620 	case ATTR_NEXTHOP:
621 		if (alen == 4) {
622 			memcpy(&id, data, sizeof(id));
623 			json_do_printf("nexthop", "%s", inet_ntoa(id));
624 		} else
625 			json_do_printf("error", "bad length");
626 		break;
627 	case ATTR_MED:
628 	case ATTR_LOCALPREF:
629 		if (alen == 4) {
630 			uint32_t val;
631 			memcpy(&val, data, sizeof(val));
632 			json_do_uint("metric", ntohl(val));
633 		} else
634 			json_do_printf("error", "bad length");
635 		break;
636 	case ATTR_AGGREGATOR:
637 	case ATTR_AS4_AGGREGATOR:
638 		if (alen == 8) {
639 			memcpy(&as, data, sizeof(as));
640 			memcpy(&id, data + sizeof(as), sizeof(id));
641 			as = ntohl(as);
642 		} else if (alen == 6) {
643 			memcpy(&short_as, data, sizeof(short_as));
644 			memcpy(&id, data + sizeof(short_as), sizeof(id));
645 			as = ntohs(short_as);
646 		} else {
647 			json_do_printf("error", "bad AS-Path");
648 			break;
649 		}
650 		json_do_uint("AS", as);
651 		json_do_printf("router_id", "%s", inet_ntoa(id));
652 		break;
653 	case ATTR_COMMUNITIES:
654 		json_do_community(data, alen);
655 		break;
656 	case ATTR_ORIGINATOR_ID:
657 		if (alen == 4) {
658 			memcpy(&id, data, sizeof(id));
659 			json_do_printf("originator", "%s", inet_ntoa(id));
660 		} else
661 			json_do_printf("error", "bad length");
662 		break;
663 	case ATTR_CLUSTER_LIST:
664 		json_do_array("cluster_list");
665 		for (off = 0; off + sizeof(id) <= alen;
666 		    off += sizeof(id)) {
667 			memcpy(&id, data + off, sizeof(id));
668 			json_do_printf("cluster_id", "%s", inet_ntoa(id));
669 		}
670 		json_do_end();
671 		break;
672 	case ATTR_MP_REACH_NLRI:
673 	case ATTR_MP_UNREACH_NLRI:
674 		if (alen < 3) {
675 bad_len:
676 			json_do_printf("error", "bad length");
677 			break;
678 		}
679 		memcpy(&afi, data, 2);
680 		data += 2;
681 		alen -= 2;
682 		afi = ntohs(afi);
683 		safi = *data++;
684 		alen--;
685 
686 		if (afi2aid(afi, safi, &aid) == -1) {
687 			json_do_printf("error", "bad AFI/SAFI pair: %d/%d",
688 			    afi, safi);
689 			break;
690 		}
691 		json_do_printf("family", "%s", aid2str(aid));
692 
693 		if (type == ATTR_MP_REACH_NLRI) {
694 			struct bgpd_addr nexthop;
695 			uint8_t nhlen;
696 			if (len == 0)
697 				goto bad_len;
698 			nhlen = *data++;
699 			alen--;
700 			if (nhlen > len)
701 				goto bad_len;
702 			memset(&nexthop, 0, sizeof(nexthop));
703 			switch (aid) {
704 			case AID_INET6:
705 				nexthop.aid = aid;
706 				if (nhlen != 16 && nhlen != 32)
707 					goto bad_len;
708 				memcpy(&nexthop.v6.s6_addr, data, 16);
709 				break;
710 			case AID_VPN_IPv4:
711 				if (nhlen != 12)
712 					goto bad_len;
713 				nexthop.aid = AID_INET;
714 				memcpy(&nexthop.v4, data + sizeof(uint64_t),
715 				    sizeof(nexthop.v4));
716 				break;
717 			case AID_VPN_IPv6:
718 				if (nhlen != 24)
719 					goto bad_len;
720 				nexthop.aid = AID_INET6;
721 				memcpy(&nexthop.v6, data + sizeof(uint64_t),
722 				    sizeof(nexthop.v6));
723 				break;
724 			default:
725 				json_do_printf("error", "unhandled AID: %d",
726 				    aid);
727 				return;
728 			}
729 			/* ignore reserved (old SNPA) field as per RFC4760 */
730 			data += nhlen + 1;
731 			alen -= nhlen + 1;
732 
733 			json_do_printf("nexthop", "%s", log_addr(&nexthop));
734 		}
735 
736 		json_do_array("NLRI");
737 		while (alen > 0) {
738 			switch (aid) {
739 			case AID_INET6:
740 				pos = nlri_get_prefix6(data, alen, &prefix,
741 				    &prefixlen);
742 				break;
743 			case AID_VPN_IPv4:
744 				 pos = nlri_get_vpn4(data, alen, &prefix,
745 				     &prefixlen, 1);
746 				 break;
747 			case AID_VPN_IPv6:
748 				 pos = nlri_get_vpn6(data, alen, &prefix,
749 				     &prefixlen, 1);
750 				 break;
751 			default:
752 				json_do_printf("error", "unhandled AID: %d",
753 				    aid);
754 				return;
755 			}
756 			if (pos == -1) {
757 				json_do_printf("error", "bad %s prefix",
758 				    aid2str(aid));
759 				break;
760 			}
761 			json_do_printf("prefix", "%s/%u", log_addr(&prefix),
762 			    prefixlen);
763 			data += pos;
764 			alen -= pos;
765 		}
766 		break;
767 	case ATTR_EXT_COMMUNITIES:
768 		json_do_ext_community(data, alen);
769 		break;
770 	case ATTR_LARGE_COMMUNITIES:
771 		json_do_large_community(data, alen);
772 		break;
773 	case ATTR_ATOMIC_AGGREGATE:
774 	default:
775 		if (alen)
776 			json_do_hexdump("data", data, alen);
777 		break;
778 	}
779 }
780 
781 static void
782 json_rib(struct ctl_show_rib *r, u_char *asdata, size_t aslen,
783     struct parse_result *res)
784 {
785 	struct in_addr id;
786 	char *aspath;
787 
788 	json_do_array("rib");
789 
790 	json_do_object("rib_entry");
791 
792 	json_do_printf("prefix", "%s/%u", log_addr(&r->prefix), r->prefixlen);
793 
794 	if (aspath_asprint(&aspath, asdata, aslen) == -1)
795 		err(1, NULL);
796 	json_do_printf("aspath", "%s", aspath);
797 	free(aspath);
798 
799 	json_do_printf("exit_nexthop", "%s", log_addr(&r->exit_nexthop));
800 	json_do_printf("true_nexthop", "%s", log_addr(&r->true_nexthop));
801 
802 	json_do_object("neighbor");
803 	if (r->descr[0])
804 		json_do_printf("description", "%s", r->descr);
805 	json_do_printf("remote_addr", "%s", log_addr(&r->remote_addr));
806 	id.s_addr = htonl(r->remote_id);
807 	json_do_printf("bgp_id", "%s", inet_ntoa(id));
808 	json_do_end();
809 
810 	/* flags */
811 	json_do_bool("valid", r->flags & F_PREF_ELIGIBLE);
812 	if (r->flags & F_PREF_ACTIVE)
813 		json_do_bool("best", 1);
814 	if (r->flags & F_PREF_INTERNAL)
815 		json_do_printf("source", "%s", "internal");
816 	else
817 		json_do_printf("source", "%s", "external");
818 	if (r->flags & F_PREF_STALE)
819 		json_do_bool("stale", 1);
820 	if (r->flags & F_PREF_ANNOUNCE)
821 		json_do_bool("announced", 1);
822 
823 	/* various attribibutes */
824 	json_do_printf("ovs", "%s", fmt_ovs(r->validation_state, 0));
825 	json_do_printf("origin", "%s", fmt_origin(r->origin, 0));
826 	json_do_uint("metric", r->med);
827 	json_do_uint("localpref", r->local_pref);
828 	json_do_uint("weight", r->weight);
829 	json_do_printf("last_update", "%s", fmt_timeframe(r->age));
830 
831 	/* keep the object open for communities and attribuites */
832 }
833 
834 static void
835 json_rib_mem_element(const char *name, uint64_t count, uint64_t size,
836     uint64_t refs)
837 {
838 	json_do_object(name);
839 	if (count != UINT64_MAX)
840 		json_do_uint("count", count);
841 	if (size != UINT64_MAX)
842 		json_do_uint("size", size);
843 	if (refs != UINT64_MAX)
844 		json_do_uint("references", refs);
845 	json_do_end();
846 }
847 
848 static void
849 json_rib_mem(struct rde_memstats *stats)
850 {
851 	size_t pts = 0;
852 	int i;
853 
854 	json_do_object("memory");
855 	for (i = 0; i < AID_MAX; i++) {
856 		if (stats->pt_cnt[i] == 0)
857 			continue;
858 		pts += stats->pt_cnt[i] * pt_sizes[i];
859 		json_rib_mem_element(aid_vals[i].name, stats->pt_cnt[i],
860 		    stats->pt_cnt[i] * pt_sizes[i], UINT64_MAX);
861 	}
862 	json_rib_mem_element("rib", stats->rib_cnt,
863 	    stats->rib_cnt * sizeof(struct rib_entry), UINT64_MAX);
864 	json_rib_mem_element("prefix", stats->prefix_cnt,
865 	    stats->prefix_cnt * sizeof(struct prefix), UINT64_MAX);
866 	json_rib_mem_element("rde_aspath", stats->path_cnt,
867 	    stats->path_cnt * sizeof(struct rde_aspath),
868 	    stats->path_refs);
869 	json_rib_mem_element("aspath", stats->aspath_cnt,
870 	    stats->aspath_size, stats->aspath_refs);
871 	json_rib_mem_element("community_entries", stats->comm_cnt,
872 	    stats->comm_cnt * sizeof(struct rde_community), UINT64_MAX);
873 	json_rib_mem_element("community", stats->comm_nmemb,
874 	    stats->comm_size * sizeof(struct community), stats->comm_refs);
875 	json_rib_mem_element("attributes_entries", stats->attr_cnt,
876 	    stats->attr_cnt * sizeof(struct attr), stats->attr_refs);
877 	json_rib_mem_element("attributes", stats->attr_dcnt,
878 	    stats->attr_data, UINT64_MAX);
879 	json_rib_mem_element("total", UINT64_MAX,
880 	    pts + stats->prefix_cnt * sizeof(struct prefix) +
881 	    stats->rib_cnt * sizeof(struct rib_entry) +
882 	    stats->path_cnt * sizeof(struct rde_aspath) +
883 	    stats->aspath_size + stats->attr_cnt * sizeof(struct attr) +
884 	    stats->attr_data, UINT64_MAX);
885 	json_do_end();
886 
887 	json_do_object("sets");
888 	json_rib_mem_element("as_set", stats->aset_nmemb,
889 	    stats->aset_size, UINT64_MAX);
890 	json_rib_mem_element("as_set_tables", stats->aset_cnt, UINT64_MAX,
891 	    UINT64_MAX);
892 	json_rib_mem_element("prefix_set", stats->pset_cnt, stats->pset_size,
893 	    UINT64_MAX);
894 	json_rib_mem_element("total", UINT64_MAX,
895 	    stats->aset_size + stats->pset_size, UINT64_MAX);
896 	json_do_end();
897 }
898 
899 static void
900 json_rib_hash(struct rde_hashstats *hash)
901 {
902 	double avg, dev;
903 
904 	json_do_array("hashtables");
905 
906 	avg = (double)hash->sum / (double)hash->num;
907 	dev = sqrt(fmax(0, hash->sumq / hash->num - avg * avg));
908 
909 	json_do_object("hashtable");
910 
911 	json_do_printf("name", "%s", hash->name);
912 	json_do_uint("size", hash->num);
913 	json_do_uint("entries", hash->sum);
914 	json_do_uint("min", hash->min);
915 	json_do_uint("max", hash->max);
916 	json_do_double("avg", avg);
917 	json_do_double("std_dev", dev);
918 	json_do_end();
919 }
920 
921 static void
922 json_rib_set(struct ctl_show_set *set)
923 {
924 	json_do_array("sets");
925 
926 	json_do_object("set");
927 	json_do_printf("name", "%s", set->name);
928 	json_do_printf("type", "%s", fmt_set_type(set));
929 	json_do_printf("last_change", "%s", fmt_monotime(set->lastchange));
930 	if (set->type == ASNUM_SET) {
931 		json_do_uint("num_ASnum", set->as_cnt);
932 	} else {
933 		json_do_uint("num_IPv4", set->v4_cnt);
934 		json_do_uint("num_IPv6", set->v6_cnt);
935 	}
936 	json_do_end();
937 }
938 
939 static void
940 json_result(u_int rescode)
941 {
942 	if (rescode == 0)
943 		json_do_printf("status", "OK");
944 	else if (rescode >
945 	    sizeof(ctl_res_strerror)/sizeof(ctl_res_strerror[0])) {
946 		json_do_printf("status", "FAILED");
947 		json_do_printf("error", "unknown error %d", rescode);
948 	} else {
949 		json_do_printf("status", "FAILED");
950 		json_do_printf("error", "%s", ctl_res_strerror[rescode]);
951 	}
952 }
953 
954 static void
955 json_tail(void)
956 {
957 	json_do_finish();
958 }
959 
960 const struct output json_output = {
961 	.head = json_head,
962 	.neighbor = json_neighbor,
963 	.timer = json_timer,
964 	.fib = json_fib,
965 	.fib_table = json_fib_table,
966 	.nexthop = json_nexthop,
967 	.interface = json_interface,
968 	.communities = json_communities,
969 	.attr = json_attr,
970 	.rib = json_rib,
971 	.rib_mem = json_rib_mem,
972 	.rib_hash = json_rib_hash,
973 	.set = json_rib_set,
974 	.result = json_result,
975 	.tail = json_tail
976 };
977