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