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