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