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