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