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