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