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