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