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