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