1 /* $OpenBSD: output.c,v 1.24 2022/07/08 16:12:11 claudio Exp $ */ 2 3 /* 4 * Copyright (c) 2003 Henning Brauer <henning@openbsd.org> 5 * Copyright (c) 2004-2019 Claudio Jeker <claudio@openbsd.org> 6 * Copyright (c) 2016 Job Snijders <job@instituut.net> 7 * Copyright (c) 2016 Peter Hessler <phessler@openbsd.org> 8 * 9 * Permission to use, copy, modify, and distribute this software for any 10 * purpose with or without fee is hereby granted, provided that the above 11 * copyright notice and this permission notice appear in all copies. 12 * 13 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 14 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 15 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 16 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 17 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 18 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 19 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 20 */ 21 22 #include <endian.h> 23 #include <err.h> 24 #include <math.h> 25 #include <stdio.h> 26 #include <stdlib.h> 27 #include <string.h> 28 29 #include "bgpd.h" 30 #include "session.h" 31 #include "rde.h" 32 33 #include "bgpctl.h" 34 #include "parser.h" 35 36 const size_t pt_sizes[AID_MAX] = AID_PTSIZE; 37 38 static void 39 show_head(struct parse_result *res) 40 { 41 switch (res->action) { 42 case SHOW: 43 case SHOW_SUMMARY: 44 printf("%-20s %8s %10s %10s %5s %-8s %s\n", "Neighbor", "AS", 45 "MsgRcvd", "MsgSent", "OutQ", "Up/Down", "State/PrfRcvd"); 46 break; 47 case SHOW_FIB: 48 printf("flags: * = valid, B = BGP, C = Connected, " 49 "S = Static\n"); 50 printf(" " 51 "N = BGP Nexthop reachable via this route\n"); 52 printf(" r = reject route, b = blackhole route\n\n"); 53 printf("flags prio destination gateway\n"); 54 break; 55 case SHOW_FIB_TABLES: 56 printf("%-5s %-20s %-8s\n", "Table", "Description", "State"); 57 break; 58 case SHOW_NEXTHOP: 59 printf("Flags: * = nexthop valid\n"); 60 printf("\n %-15s %-19s%-4s %-15s %-20s\n", "Nexthop", "Route", 61 "Prio", "Gateway", "Iface"); 62 break; 63 case SHOW_INTERFACE: 64 printf("%-15s%-9s%-9s%-7s%s\n", "Interface", "rdomain", 65 "Nexthop", "Flags", "Link state"); 66 break; 67 case SHOW_RIB: 68 if (res->flags & F_CTL_DETAIL) 69 break; 70 printf("flags: " 71 "* = Valid, > = Selected, I = via IBGP, A = Announced,\n" 72 " S = Stale, E = Error\n"); 73 printf("origin validation state: " 74 "N = not-found, V = valid, ! = invalid\n"); 75 printf("origin: i = IGP, e = EGP, ? = Incomplete\n\n"); 76 printf("%-5s %3s %-20s %-15s %5s %5s %s\n", 77 "flags", "ovs", "destination", "gateway", "lpref", "med", 78 "aspath origin"); 79 break; 80 case SHOW_SET: 81 printf("%-6s %-34s %7s %7s %6s %11s\n", "Type", "Name", 82 "#IPv4", "#IPv6", "#ASnum", "Last Change"); 83 break; 84 case NETWORK_SHOW: 85 printf("flags: S = Static\n"); 86 printf("flags prio destination gateway\n"); 87 break; 88 default: 89 break; 90 } 91 } 92 93 static void 94 show_summary(struct peer *p) 95 { 96 char *s; 97 const char *a; 98 size_t alen; 99 100 s = fmt_peer(p->conf.descr, &p->conf.remote_addr, 101 p->conf.remote_masklen); 102 103 a = log_as(p->conf.remote_as); 104 alen = strlen(a); 105 /* max displayed length of the peers name is 28 */ 106 if (alen < 28) { 107 if (strlen(s) > 28 - alen) 108 s[28 - alen] = '\0'; 109 } else 110 alen = 0; 111 112 printf("%-*s %s %10llu %10llu %5u %-8s ", 113 (28 - (int)alen), s, a, 114 p->stats.msg_rcvd_open + p->stats.msg_rcvd_notification + 115 p->stats.msg_rcvd_update + p->stats.msg_rcvd_keepalive + 116 p->stats.msg_rcvd_rrefresh, 117 p->stats.msg_sent_open + p->stats.msg_sent_notification + 118 p->stats.msg_sent_update + p->stats.msg_sent_keepalive + 119 p->stats.msg_sent_rrefresh, 120 p->wbuf.queued, 121 fmt_monotime(p->stats.last_updown)); 122 if (p->state == STATE_ESTABLISHED) { 123 printf("%6u", p->stats.prefix_cnt); 124 if (p->conf.max_prefix != 0) 125 printf("/%u", p->conf.max_prefix); 126 } else if (p->conf.template) 127 printf("Template"); 128 else 129 printf("%s", statenames[p->state]); 130 printf("\n"); 131 free(s); 132 } 133 134 static void 135 show_neighbor_capa_mp(struct capabilities *capa) 136 { 137 int comma; 138 uint8_t i; 139 140 printf(" Multiprotocol extensions: "); 141 for (i = AID_MIN, comma = 0; i < AID_MAX; i++) 142 if (capa->mp[i]) { 143 printf("%s%s", comma ? ", " : "", aid2str(i)); 144 comma = 1; 145 } 146 printf("\n"); 147 } 148 149 static void 150 show_neighbor_capa_add_path(struct capabilities *capa) 151 { 152 const char *mode; 153 int comma; 154 uint8_t i; 155 156 printf(" Add-path: "); 157 for (i = AID_MIN, comma = 0; i < AID_MAX; i++) { 158 switch (capa->add_path[i]) { 159 case 0: 160 default: 161 continue; 162 case CAPA_AP_RECV: 163 mode = "recv"; 164 break; 165 case CAPA_AP_SEND: 166 mode = "send"; 167 break; 168 case CAPA_AP_BIDIR: 169 mode = "bidir"; 170 } 171 printf("%s%s %s", comma ? ", " : "", aid2str(i), mode); 172 comma = 1; 173 } 174 printf("\n"); 175 } 176 177 static void 178 show_neighbor_capa_restart(struct capabilities *capa) 179 { 180 int comma; 181 uint8_t i; 182 183 printf(" Graceful Restart"); 184 if (capa->grestart.timeout) 185 printf(": Timeout: %d, ", capa->grestart.timeout); 186 for (i = AID_MIN, comma = 0; i < AID_MAX; i++) 187 if (capa->grestart.flags[i] & CAPA_GR_PRESENT) { 188 if (!comma && 189 capa->grestart.flags[i] & CAPA_GR_RESTART) 190 printf("restarted, "); 191 if (comma) 192 printf(", "); 193 printf("%s", aid2str(i)); 194 if (capa->grestart.flags[i] & CAPA_GR_FORWARD) 195 printf(" (preserved)"); 196 comma = 1; 197 } 198 printf("\n"); 199 } 200 201 static void 202 show_neighbor_msgstats(struct peer *p) 203 { 204 printf(" Message statistics:\n"); 205 printf(" %-15s %-10s %-10s\n", "", "Sent", "Received"); 206 printf(" %-15s %10llu %10llu\n", "Opens", 207 p->stats.msg_sent_open, p->stats.msg_rcvd_open); 208 printf(" %-15s %10llu %10llu\n", "Notifications", 209 p->stats.msg_sent_notification, p->stats.msg_rcvd_notification); 210 printf(" %-15s %10llu %10llu\n", "Updates", 211 p->stats.msg_sent_update, p->stats.msg_rcvd_update); 212 printf(" %-15s %10llu %10llu\n", "Keepalives", 213 p->stats.msg_sent_keepalive, p->stats.msg_rcvd_keepalive); 214 printf(" %-15s %10llu %10llu\n", "Route Refresh", 215 p->stats.msg_sent_rrefresh, p->stats.msg_rcvd_rrefresh); 216 printf(" %-15s %10llu %10llu\n\n", "Total", 217 p->stats.msg_sent_open + p->stats.msg_sent_notification + 218 p->stats.msg_sent_update + p->stats.msg_sent_keepalive + 219 p->stats.msg_sent_rrefresh, 220 p->stats.msg_rcvd_open + p->stats.msg_rcvd_notification + 221 p->stats.msg_rcvd_update + p->stats.msg_rcvd_keepalive + 222 p->stats.msg_rcvd_rrefresh); 223 printf(" Update statistics:\n"); 224 printf(" %-15s %-10s %-10s\n", "", "Sent", "Received"); 225 printf(" %-15s %10u %10u\n", "Prefixes", 226 p->stats.prefix_out_cnt, p->stats.prefix_cnt); 227 printf(" %-15s %10llu %10llu\n", "Updates", 228 p->stats.prefix_sent_update, p->stats.prefix_rcvd_update); 229 printf(" %-15s %10llu %10llu\n", "Withdraws", 230 p->stats.prefix_sent_withdraw, p->stats.prefix_rcvd_withdraw); 231 printf(" %-15s %10llu %10llu\n", "End-of-Rib", 232 p->stats.prefix_sent_eor, p->stats.prefix_rcvd_eor); 233 printf(" Route Refresh statistics:\n"); 234 printf(" %-15s %10llu %10llu\n", "Request", 235 p->stats.refresh_sent_req, p->stats.refresh_rcvd_req); 236 printf(" %-15s %10llu %10llu\n", "Begin-of-RR", 237 p->stats.refresh_sent_borr, p->stats.refresh_rcvd_borr); 238 printf(" %-15s %10llu %10llu\n", "End-of-RR", 239 p->stats.refresh_sent_eorr, p->stats.refresh_rcvd_eorr); 240 } 241 242 static void 243 show_neighbor_full(struct peer *p, struct parse_result *res) 244 { 245 const char *errstr; 246 struct in_addr ina; 247 char *s; 248 int hascapamp, hascapaap; 249 uint8_t i; 250 251 if ((p->conf.remote_addr.aid == AID_INET && 252 p->conf.remote_masklen != 32) || 253 (p->conf.remote_addr.aid == AID_INET6 && 254 p->conf.remote_masklen != 128)) { 255 if (asprintf(&s, "%s/%u", 256 log_addr(&p->conf.remote_addr), 257 p->conf.remote_masklen) == -1) 258 err(1, NULL); 259 } else if ((s = strdup(log_addr(&p->conf.remote_addr))) == NULL) 260 err(1, "strdup"); 261 262 printf("BGP neighbor is %s, ", s); 263 free(s); 264 if (p->conf.remote_as == 0 && p->conf.template) 265 printf("remote AS: accept any"); 266 else 267 printf("remote AS %s", log_as(p->conf.remote_as)); 268 if (p->conf.template) 269 printf(", Template"); 270 if (p->template) 271 printf(", Cloned"); 272 if (p->conf.passive) 273 printf(", Passive"); 274 if (p->conf.ebgp && p->conf.distance > 1) 275 printf(", Multihop (%u)", (int)p->conf.distance); 276 printf("\n"); 277 if (p->conf.descr[0]) 278 printf(" Description: %s\n", p->conf.descr); 279 if (p->conf.max_prefix) { 280 printf(" Max-prefix: %u", p->conf.max_prefix); 281 if (p->conf.max_prefix_restart) 282 printf(" (restart %u)", 283 p->conf.max_prefix_restart); 284 } 285 if (p->conf.max_out_prefix) { 286 printf(" Max-prefix out: %u", p->conf.max_out_prefix); 287 if (p->conf.max_out_prefix_restart) 288 printf(" (restart %u)", 289 p->conf.max_out_prefix_restart); 290 } 291 if (p->conf.max_prefix || p->conf.max_out_prefix) 292 printf("\n"); 293 294 if (p->state == STATE_ESTABLISHED) { 295 ina.s_addr = p->remote_bgpid; 296 printf(" BGP version 4, remote router-id %s", 297 inet_ntoa(ina)); 298 printf("%s\n", fmt_auth_method(p->auth.method)); 299 } 300 printf(" BGP state = %s", statenames[p->state]); 301 if (p->conf.down) { 302 printf(", marked down"); 303 } 304 if (p->conf.reason[0]) { 305 printf(" with shutdown reason \"%s\"", 306 log_reason(p->conf.reason)); 307 } 308 if (p->stats.last_updown != 0) 309 printf(", %s for %s", 310 p->state == STATE_ESTABLISHED ? "up" : "down", 311 fmt_monotime(p->stats.last_updown)); 312 printf("\n"); 313 printf(" Last read %s, holdtime %us, keepalive interval %us\n", 314 fmt_monotime(p->stats.last_read), 315 p->holdtime, p->holdtime/3); 316 printf(" Last write %s\n", fmt_monotime(p->stats.last_write)); 317 318 hascapamp = 0; 319 hascapaap = 0; 320 for (i = AID_MIN; i < AID_MAX; i++) { 321 if (p->capa.peer.mp[i]) 322 hascapamp = 1; 323 if (p->capa.peer.add_path[i]) 324 hascapaap = 1; 325 } 326 if (hascapamp || hascapaap || p->capa.peer.grestart.restart || 327 p->capa.peer.refresh || p->capa.peer.enhanced_rr || 328 p->capa.peer.as4byte || p->capa.peer.role_ena) { 329 printf(" Neighbor capabilities:\n"); 330 if (hascapamp) 331 show_neighbor_capa_mp(&p->capa.peer); 332 if (p->capa.peer.as4byte) 333 printf(" 4-byte AS numbers\n"); 334 if (p->capa.peer.refresh) 335 printf(" Route Refresh\n"); 336 if (p->capa.peer.enhanced_rr) 337 printf(" Enhanced Route Refresh\n"); 338 if (p->capa.peer.grestart.restart) 339 show_neighbor_capa_restart(&p->capa.peer); 340 if (hascapaap) 341 show_neighbor_capa_add_path(&p->capa.peer); 342 if (p->capa.peer.role_ena) 343 printf(" Open Policy role %s (local %s)\n", 344 log_policy(p->capa.peer.role), 345 log_policy(p->capa.ann.role)); 346 } 347 348 hascapamp = 0; 349 hascapaap = 0; 350 for (i = AID_MIN; i < AID_MAX; i++) { 351 if (p->capa.neg.mp[i]) 352 hascapamp = 1; 353 if (p->capa.neg.add_path[i]) 354 hascapaap = 1; 355 } 356 if (hascapamp || hascapaap || p->capa.neg.grestart.restart || 357 p->capa.neg.refresh || p->capa.neg.enhanced_rr || 358 p->capa.neg.as4byte || p->capa.neg.role_ena) { 359 printf(" Negotiated capabilities:\n"); 360 if (hascapamp) 361 show_neighbor_capa_mp(&p->capa.neg); 362 if (p->capa.neg.as4byte) 363 printf(" 4-byte AS numbers\n"); 364 if (p->capa.neg.refresh) 365 printf(" Route Refresh\n"); 366 if (p->capa.neg.enhanced_rr) 367 printf(" Enhanced Route Refresh\n"); 368 if (p->capa.neg.grestart.restart) 369 show_neighbor_capa_restart(&p->capa.neg); 370 if (hascapaap) 371 show_neighbor_capa_add_path(&p->capa.neg); 372 if (p->capa.neg.role_ena) 373 printf(" Open Policy role %s (local %s)\n", 374 log_policy(p->capa.neg.role), 375 log_policy(p->capa.ann.role)); 376 } 377 printf("\n"); 378 379 if (res->action == SHOW_NEIGHBOR_TIMERS) 380 return; 381 382 show_neighbor_msgstats(p); 383 printf("\n"); 384 if (p->stats.last_reason[0]) { 385 printf(" Last received shutdown reason: \"%s\"\n", 386 log_reason(p->stats.last_reason)); 387 } 388 389 errstr = fmt_errstr(p->stats.last_sent_errcode, 390 p->stats.last_sent_suberr); 391 if (errstr) 392 printf(" Last error sent: %s\n", errstr); 393 errstr = fmt_errstr(p->stats.last_rcvd_errcode, 394 p->stats.last_rcvd_suberr); 395 if (errstr) 396 printf(" Last error received: %s\n", errstr); 397 398 if (p->state >= STATE_OPENSENT) { 399 printf(" Local host: %20s, Local port: %5u\n", 400 log_addr(&p->local), p->local_port); 401 402 printf(" Remote host: %20s, Remote port: %5u\n", 403 log_addr(&p->remote), p->remote_port); 404 printf("\n"); 405 } 406 } 407 408 static void 409 show_neighbor(struct peer *p, struct parse_result *res) 410 { 411 char *s; 412 413 switch (res->action) { 414 case SHOW: 415 case SHOW_SUMMARY: 416 show_summary(p); 417 break; 418 case SHOW_SUMMARY_TERSE: 419 s = fmt_peer(p->conf.descr, &p->conf.remote_addr, 420 p->conf.remote_masklen); 421 printf("%s %s %s\n", s, log_as(p->conf.remote_as), 422 p->conf.template ? "Template" : statenames[p->state]); 423 free(s); 424 break; 425 case SHOW_NEIGHBOR: 426 case SHOW_NEIGHBOR_TIMERS: 427 show_neighbor_full(p, res); 428 break; 429 case SHOW_NEIGHBOR_TERSE: 430 s = fmt_peer(NULL, &p->conf.remote_addr, 431 p->conf.remote_masklen); 432 printf("%llu %llu %llu %llu %llu %llu %llu %llu %llu " 433 "%llu %u %u %llu %llu %llu %llu %s %s \"%s\"\n", 434 p->stats.msg_sent_open, p->stats.msg_rcvd_open, 435 p->stats.msg_sent_notification, 436 p->stats.msg_rcvd_notification, 437 p->stats.msg_sent_update, p->stats.msg_rcvd_update, 438 p->stats.msg_sent_keepalive, p->stats.msg_rcvd_keepalive, 439 p->stats.msg_sent_rrefresh, p->stats.msg_rcvd_rrefresh, 440 p->stats.prefix_cnt, p->conf.max_prefix, 441 p->stats.prefix_sent_update, p->stats.prefix_rcvd_update, 442 p->stats.prefix_sent_withdraw, 443 p->stats.prefix_rcvd_withdraw, s, 444 log_as(p->conf.remote_as), p->conf.descr); 445 free(s); 446 break; 447 default: 448 break; 449 } 450 } 451 452 static void 453 show_timer(struct ctl_timer *t) 454 { 455 printf(" %-20s ", timernames[t->type]); 456 457 if (t->val <= 0) 458 printf("%-20s\n", "due"); 459 else 460 printf("due in %-13s\n", fmt_timeframe(t->val)); 461 } 462 463 static void 464 show_fib(struct kroute_full *kf) 465 { 466 char *p; 467 468 if (asprintf(&p, "%s/%u", log_addr(&kf->prefix), kf->prefixlen) == -1) 469 err(1, NULL); 470 printf("%s%4i %-20s ", fmt_fib_flags(kf->flags), kf->priority, p); 471 free(p); 472 473 if (kf->flags & F_CONNECTED) 474 printf("link#%u", kf->ifindex); 475 else 476 printf("%s", log_addr(&kf->nexthop)); 477 printf("\n"); 478 } 479 480 static void 481 show_fib_table(struct ktable *kt) 482 { 483 printf("%5i %-20s %-8s%s\n", kt->rtableid, kt->descr, 484 kt->fib_sync ? "coupled" : "decoupled", 485 kt->fib_sync != kt->fib_conf ? "*" : ""); 486 } 487 488 static void 489 show_nexthop(struct ctl_show_nexthop *nh) 490 { 491 char *s; 492 493 printf("%s %-15s ", nh->valid ? "*" : " ", log_addr(&nh->addr)); 494 if (!nh->krvalid) { 495 printf("\n"); 496 return; 497 } 498 if (asprintf(&s, "%s/%u", log_addr(&nh->kr.prefix), 499 nh->kr.prefixlen) == -1) 500 err(1, NULL); 501 printf("%-20s", s); 502 free(s); 503 printf("%3i %-15s ", nh->kr.priority, 504 nh->kr.flags & F_CONNECTED ? "connected" : 505 log_addr(&nh->kr.nexthop)); 506 507 if (nh->iface.ifname[0]) { 508 printf("%s (%s, %s)", nh->iface.ifname, 509 nh->iface.is_up ? "UP" : "DOWN", 510 nh->iface.baudrate ? 511 get_baudrate(nh->iface.baudrate, "bps") : 512 nh->iface.linkstate); 513 } 514 printf("\n"); 515 } 516 517 static void 518 show_interface(struct ctl_show_interface *iface) 519 { 520 printf("%-15s", iface->ifname); 521 printf("%-9u", iface->rdomain); 522 printf("%-9s", iface->nh_reachable ? "ok" : "invalid"); 523 printf("%-7s", iface->is_up ? "UP" : ""); 524 525 if (iface->media[0]) 526 printf("%s, ", iface->media); 527 printf("%s", iface->linkstate); 528 529 if (iface->baudrate > 0) 530 printf(", %s", get_baudrate(iface->baudrate, "Bit/s")); 531 printf("\n"); 532 } 533 534 static void 535 show_communities(u_char *data, size_t len, struct parse_result *res) 536 { 537 struct community c; 538 size_t i; 539 uint64_t ext; 540 uint8_t type = 0; 541 542 if (len % sizeof(c)) 543 return; 544 545 for (i = 0; i < len; i += sizeof(c)) { 546 memcpy(&c, data + i, sizeof(c)); 547 548 if (type != c.flags) { 549 if (type != 0) 550 printf("%c", EOL0(res->flags)); 551 printf(" %s:", fmt_attr(c.flags, 552 ATTR_OPTIONAL | ATTR_TRANSITIVE)); 553 type = c.flags; 554 } 555 556 switch (c.flags) { 557 case COMMUNITY_TYPE_BASIC: 558 printf(" %s", fmt_community(c.data1, c.data2)); 559 break; 560 case COMMUNITY_TYPE_LARGE: 561 printf(" %s", 562 fmt_large_community(c.data1, c.data2, c.data3)); 563 break; 564 case COMMUNITY_TYPE_EXT: 565 ext = (uint64_t)c.data3 << 48; 566 switch (c.data3 >> 8) { 567 case EXT_COMMUNITY_TRANS_TWO_AS: 568 case EXT_COMMUNITY_TRANS_OPAQUE: 569 case EXT_COMMUNITY_TRANS_EVPN: 570 case EXT_COMMUNITY_NON_TRANS_OPAQUE: 571 ext |= ((uint64_t)c.data1 & 0xffff) << 32; 572 ext |= (uint64_t)c.data2; 573 break; 574 case EXT_COMMUNITY_TRANS_FOUR_AS: 575 case EXT_COMMUNITY_TRANS_IPV4: 576 ext |= (uint64_t)c.data1 << 16; 577 ext |= (uint64_t)c.data2 & 0xffff; 578 break; 579 } 580 ext = htobe64(ext); 581 582 printf(" %s", fmt_ext_community((void *)&ext)); 583 break; 584 } 585 } 586 587 printf("%c", EOL0(res->flags)); 588 } 589 590 static void 591 show_community(u_char *data, uint16_t len) 592 { 593 uint16_t a, v; 594 uint16_t i; 595 596 if (len & 0x3) { 597 printf("bad length"); 598 return; 599 } 600 601 for (i = 0; i < len; i += 4) { 602 memcpy(&a, data + i, sizeof(a)); 603 memcpy(&v, data + i + 2, sizeof(v)); 604 a = ntohs(a); 605 v = ntohs(v); 606 printf("%s", fmt_community(a, v)); 607 608 if (i + 4 < len) 609 printf(" "); 610 } 611 } 612 613 static void 614 show_large_community(u_char *data, uint16_t len) 615 { 616 uint32_t a, l1, l2; 617 uint16_t i; 618 619 if (len % 12) { 620 printf("bad length"); 621 return; 622 } 623 624 for (i = 0; i < len; i += 12) { 625 memcpy(&a, data + i, sizeof(a)); 626 memcpy(&l1, data + i + 4, sizeof(l1)); 627 memcpy(&l2, data + i + 8, sizeof(l2)); 628 a = ntohl(a); 629 l1 = ntohl(l1); 630 l2 = ntohl(l2); 631 printf("%s", fmt_large_community(a, l1, l2)); 632 633 if (i + 12 < len) 634 printf(" "); 635 } 636 } 637 638 static void 639 show_ext_community(u_char *data, uint16_t len) 640 { 641 uint16_t i; 642 643 if (len & 0x7) { 644 printf("bad length"); 645 return; 646 } 647 648 for (i = 0; i < len; i += 8) { 649 printf("%s", fmt_ext_community(data + i)); 650 651 if (i + 8 < len) 652 printf(" "); 653 } 654 } 655 656 static void 657 show_attr(u_char *data, size_t len, int reqflags, int addpath) 658 { 659 u_char *path; 660 struct in_addr id; 661 struct bgpd_addr prefix; 662 char *aspath; 663 uint32_t as, pathid; 664 uint16_t alen, ioff, short_as, afi; 665 uint8_t flags, type, safi, aid, prefixlen; 666 int i, pos, e2, e4; 667 668 if (len < 3) { 669 warnx("Too short BGP attrbute"); 670 return; 671 } 672 673 flags = data[0]; 674 type = data[1]; 675 676 /* get the attribute length */ 677 if (flags & ATTR_EXTLEN) { 678 if (len < 4) { 679 warnx("Too short BGP attrbute"); 680 return; 681 } 682 memcpy(&alen, data+2, sizeof(uint16_t)); 683 alen = ntohs(alen); 684 data += 4; 685 len -= 4; 686 } else { 687 alen = data[2]; 688 data += 3; 689 len -= 3; 690 } 691 692 /* bad imsg len how can that happen!? */ 693 if (alen > len) { 694 warnx("Bad BGP attrbute length"); 695 return; 696 } 697 698 printf(" %s: ", fmt_attr(type, flags)); 699 700 switch (type) { 701 case ATTR_ORIGIN: 702 if (alen == 1) 703 printf("%s", fmt_origin(*data, 0)); 704 else 705 printf("bad length"); 706 break; 707 case ATTR_ASPATH: 708 case ATTR_AS4_PATH: 709 /* prefer 4-byte AS here */ 710 e4 = aspath_verify(data, alen, 1, 0); 711 e2 = aspath_verify(data, alen, 0, 0); 712 if (e4 == 0 || e4 == AS_ERR_SOFT) { 713 path = data; 714 } else if (e2 == 0 || e2 == AS_ERR_SOFT) { 715 path = aspath_inflate(data, alen, &alen); 716 if (path == NULL) 717 errx(1, "aspath_inflate failed"); 718 } else { 719 printf("bad AS-Path"); 720 break; 721 } 722 if (aspath_asprint(&aspath, path, alen) == -1) 723 err(1, NULL); 724 printf("%s", aspath); 725 free(aspath); 726 if (path != data) 727 free(path); 728 break; 729 case ATTR_NEXTHOP: 730 if (alen == 4) { 731 memcpy(&id, data, sizeof(id)); 732 printf("%s", inet_ntoa(id)); 733 } else 734 printf("bad length"); 735 break; 736 case ATTR_MED: 737 case ATTR_LOCALPREF: 738 if (alen == 4) { 739 uint32_t val; 740 memcpy(&val, data, sizeof(val)); 741 val = ntohl(val); 742 printf("%u", val); 743 } else 744 printf("bad length"); 745 break; 746 case ATTR_AGGREGATOR: 747 case ATTR_AS4_AGGREGATOR: 748 if (alen == 8) { 749 memcpy(&as, data, sizeof(as)); 750 memcpy(&id, data + sizeof(as), sizeof(id)); 751 as = ntohl(as); 752 } else if (alen == 6) { 753 memcpy(&short_as, data, sizeof(short_as)); 754 memcpy(&id, data + sizeof(short_as), sizeof(id)); 755 as = ntohs(short_as); 756 } else { 757 printf("bad length"); 758 break; 759 } 760 printf("%s [%s]", log_as(as), inet_ntoa(id)); 761 break; 762 case ATTR_COMMUNITIES: 763 show_community(data, alen); 764 break; 765 case ATTR_ORIGINATOR_ID: 766 if (alen == 4) { 767 memcpy(&id, data, sizeof(id)); 768 printf("%s", inet_ntoa(id)); 769 } else 770 printf("bad length"); 771 break; 772 case ATTR_CLUSTER_LIST: 773 for (ioff = 0; ioff + sizeof(id) <= alen; 774 ioff += sizeof(id)) { 775 memcpy(&id, data + ioff, sizeof(id)); 776 printf(" %s", inet_ntoa(id)); 777 } 778 break; 779 case ATTR_MP_REACH_NLRI: 780 case ATTR_MP_UNREACH_NLRI: 781 if (alen < 3) { 782 bad_len: 783 printf("bad length"); 784 break; 785 } 786 memcpy(&afi, data, 2); 787 data += 2; 788 alen -= 2; 789 afi = ntohs(afi); 790 safi = *data++; 791 alen--; 792 793 if (afi2aid(afi, safi, &aid) == -1) { 794 printf("bad AFI/SAFI pair"); 795 break; 796 } 797 printf(" %s", aid2str(aid)); 798 799 if (type == ATTR_MP_REACH_NLRI) { 800 struct bgpd_addr nexthop; 801 uint8_t nhlen; 802 if (len == 0) 803 goto bad_len; 804 nhlen = *data++; 805 alen--; 806 if (nhlen > len) 807 goto bad_len; 808 memset(&nexthop, 0, sizeof(nexthop)); 809 switch (aid) { 810 case AID_INET6: 811 nexthop.aid = aid; 812 if (nhlen != 16 && nhlen != 32) 813 goto bad_len; 814 memcpy(&nexthop.v6.s6_addr, data, 16); 815 break; 816 case AID_VPN_IPv4: 817 if (nhlen != 12) 818 goto bad_len; 819 nexthop.aid = AID_INET; 820 memcpy(&nexthop.v4, data + sizeof(uint64_t), 821 sizeof(nexthop.v4)); 822 break; 823 case AID_VPN_IPv6: 824 if (nhlen != 24) 825 goto bad_len; 826 nexthop.aid = AID_INET6; 827 memcpy(&nexthop.v6, data + sizeof(uint64_t), 828 sizeof(nexthop.v6)); 829 break; 830 default: 831 printf("unhandled AID #%u", aid); 832 goto done; 833 } 834 /* ignore reserved (old SNPA) field as per RFC4760 */ 835 data += nhlen + 1; 836 alen -= nhlen + 1; 837 838 printf(" nexthop: %s", log_addr(&nexthop)); 839 } 840 841 while (alen > 0) { 842 if (addpath) { 843 if (alen <= sizeof(pathid)) { 844 printf("bad nlri prefix"); 845 return; 846 } 847 memcpy(&pathid, data, sizeof(pathid)); 848 pathid = ntohl(pathid); 849 data += sizeof(pathid); 850 alen -= sizeof(pathid); 851 } 852 switch (aid) { 853 case AID_INET6: 854 pos = nlri_get_prefix6(data, alen, &prefix, 855 &prefixlen); 856 break; 857 case AID_VPN_IPv4: 858 pos = nlri_get_vpn4(data, alen, &prefix, 859 &prefixlen, 1); 860 break; 861 case AID_VPN_IPv6: 862 pos = nlri_get_vpn6(data, alen, &prefix, 863 &prefixlen, 1); 864 break; 865 default: 866 printf("unhandled AID #%u", aid); 867 goto done; 868 } 869 if (pos == -1) { 870 printf("bad %s prefix", aid2str(aid)); 871 break; 872 } 873 printf(" %s/%u", log_addr(&prefix), prefixlen); 874 if (addpath) 875 printf(" path-id %u", pathid); 876 data += pos; 877 alen -= pos; 878 } 879 break; 880 case ATTR_EXT_COMMUNITIES: 881 show_ext_community(data, alen); 882 break; 883 case ATTR_LARGE_COMMUNITIES: 884 show_large_community(data, alen); 885 break; 886 case ATTR_OTC: 887 if (alen == 4) { 888 memcpy(&as, data, sizeof(as)); 889 as = ntohl(as); 890 printf("%s", log_as(as)); 891 } else { 892 printf("bad length"); 893 } 894 break; 895 case ATTR_ATOMIC_AGGREGATE: 896 default: 897 printf(" len %u", alen); 898 if (alen) { 899 printf(":"); 900 for (i=0; i < alen; i++) 901 printf(" %02x", *(data+i)); 902 } 903 break; 904 } 905 done: 906 printf("%c", EOL0(reqflags)); 907 } 908 909 static void 910 show_rib_brief(struct ctl_show_rib *r, u_char *asdata, size_t aslen) 911 { 912 char *p, *aspath; 913 914 if (asprintf(&p, "%s/%u", log_addr(&r->prefix), r->prefixlen) == -1) 915 err(1, NULL); 916 printf("%s %3s %-20s %-15s %5u %5u ", 917 fmt_flags(r->flags, 1), fmt_ovs(r->validation_state, 1), p, 918 log_addr(&r->exit_nexthop), r->local_pref, r->med); 919 free(p); 920 921 if (aspath_asprint(&aspath, asdata, aslen) == -1) 922 err(1, NULL); 923 if (strlen(aspath) > 0) 924 printf("%s ", aspath); 925 free(aspath); 926 927 printf("%s\n", fmt_origin(r->origin, 1)); 928 } 929 930 static void 931 show_rib_detail(struct ctl_show_rib *r, u_char *asdata, size_t aslen, 932 int flag0) 933 { 934 struct in_addr id; 935 char *aspath, *s; 936 937 printf("\nBGP routing table entry for %s/%u%c", 938 log_addr(&r->prefix), r->prefixlen, 939 EOL0(flag0)); 940 941 if (aspath_asprint(&aspath, asdata, aslen) == -1) 942 err(1, NULL); 943 if (strlen(aspath) > 0) 944 printf(" %s%c", aspath, EOL0(flag0)); 945 free(aspath); 946 947 s = fmt_peer(r->descr, &r->remote_addr, -1); 948 id.s_addr = htonl(r->remote_id); 949 printf(" Nexthop %s ", log_addr(&r->exit_nexthop)); 950 printf("(via %s) Neighbor %s (%s)", log_addr(&r->true_nexthop), s, 951 inet_ntoa(id)); 952 if (r->flags & F_PREF_PATH_ID) 953 printf(" Path-Id: %u", r->path_id); 954 printf("%c", EOL0(flag0)); 955 free(s); 956 957 printf(" Origin %s, metric %u, localpref %u, weight %u, ovs %s, ", 958 fmt_origin(r->origin, 0), r->med, r->local_pref, r->weight, 959 fmt_ovs(r->validation_state, 0)); 960 printf("%s", fmt_flags(r->flags, 0)); 961 962 printf("%c Last update: %s ago%c", EOL0(flag0), 963 fmt_timeframe(r->age), EOL0(flag0)); 964 } 965 966 static void 967 show_rib(struct ctl_show_rib *r, u_char *asdata, size_t aslen, 968 struct parse_result *res) 969 { 970 if (res->flags & F_CTL_DETAIL) 971 show_rib_detail(r, asdata, aslen, res->flags); 972 else 973 show_rib_brief(r, asdata, aslen); 974 } 975 976 static void 977 show_rib_mem(struct rde_memstats *stats) 978 { 979 size_t pts = 0; 980 int i; 981 982 printf("RDE memory statistics\n"); 983 for (i = 0; i < AID_MAX; i++) { 984 if (stats->pt_cnt[i] == 0) 985 continue; 986 pts += stats->pt_cnt[i] * pt_sizes[i]; 987 printf("%10lld %s network entries using %s of memory\n", 988 stats->pt_cnt[i], aid_vals[i].name, 989 fmt_mem(stats->pt_cnt[i] * pt_sizes[i])); 990 } 991 printf("%10lld rib entries using %s of memory\n", 992 stats->rib_cnt, fmt_mem(stats->rib_cnt * 993 sizeof(struct rib_entry))); 994 printf("%10lld prefix entries using %s of memory\n", 995 stats->prefix_cnt, fmt_mem(stats->prefix_cnt * 996 sizeof(struct prefix))); 997 printf("%10lld BGP path attribute entries using %s of memory\n", 998 stats->path_cnt, fmt_mem(stats->path_cnt * 999 sizeof(struct rde_aspath))); 1000 printf("\t and holding %lld references\n", 1001 stats->path_refs); 1002 printf("%10lld BGP AS-PATH attribute entries using " 1003 "%s of memory\n\t and holding %lld references\n", 1004 stats->aspath_cnt, fmt_mem(stats->aspath_size), 1005 stats->aspath_refs); 1006 printf("%10lld entries for %lld BGP communities " 1007 "using %s of memory\n", stats->comm_cnt, stats->comm_nmemb, 1008 fmt_mem(stats->comm_cnt * sizeof(struct rde_community) + 1009 stats->comm_size * sizeof(struct community))); 1010 printf("\t and holding %lld references\n", 1011 stats->comm_refs); 1012 printf("%10lld BGP attributes entries using %s of memory\n", 1013 stats->attr_cnt, fmt_mem(stats->attr_cnt * 1014 sizeof(struct attr))); 1015 printf("\t and holding %lld references\n", 1016 stats->attr_refs); 1017 printf("%10lld BGP attributes using %s of memory\n", 1018 stats->attr_dcnt, fmt_mem(stats->attr_data)); 1019 printf("%10lld as-set elements in %lld tables using " 1020 "%s of memory\n", stats->aset_nmemb, stats->aset_cnt, 1021 fmt_mem(stats->aset_size)); 1022 printf("%10lld prefix-set elements using %s of memory\n", 1023 stats->pset_cnt, fmt_mem(stats->pset_size)); 1024 printf("RIB using %s of memory\n", fmt_mem(pts + 1025 stats->prefix_cnt * sizeof(struct prefix) + 1026 stats->rib_cnt * sizeof(struct rib_entry) + 1027 stats->path_cnt * sizeof(struct rde_aspath) + 1028 stats->aspath_size + stats->attr_cnt * sizeof(struct attr) + 1029 stats->attr_data)); 1030 printf("Sets using %s of memory\n", fmt_mem(stats->aset_size + 1031 stats->pset_size)); 1032 printf("\nRDE hash statistics\n"); 1033 } 1034 1035 static void 1036 show_rib_hash(struct rde_hashstats *hash) 1037 { 1038 double avg, dev; 1039 1040 printf("\t%s: size %lld, %lld entries\n", hash->name, hash->num, 1041 hash->sum); 1042 avg = (double)hash->sum / (double)hash->num; 1043 dev = sqrt(fmax(0, hash->sumq / hash->num - avg * avg)); 1044 printf("\t min %lld max %lld avg/std-dev = %.3f/%.3f\n", 1045 hash->min, hash->max, avg, dev); 1046 } 1047 1048 static void 1049 show_rib_set(struct ctl_show_set *set) 1050 { 1051 char buf[64]; 1052 1053 if (set->type == ASNUM_SET) 1054 snprintf(buf, sizeof(buf), "%7s %7s %6zu", 1055 "-", "-", set->as_cnt); 1056 else 1057 snprintf(buf, sizeof(buf), "%7zu %7zu %6s", 1058 set->v4_cnt, set->v6_cnt, "-"); 1059 1060 printf("%-6s %-34s %s %11s\n", fmt_set_type(set), set->name, 1061 buf, fmt_monotime(set->lastchange)); 1062 } 1063 1064 static void 1065 show_rtr(struct ctl_show_rtr *rtr) 1066 { 1067 static int not_first; 1068 1069 if (not_first) 1070 printf("\n"); 1071 not_first = 1; 1072 1073 printf("RTR neighbor is %s, port %u\n", 1074 log_addr(&rtr->remote_addr), rtr->remote_port); 1075 if (rtr->descr[0]) 1076 printf(" Description: %s\n", rtr->descr); 1077 if (rtr->local_addr.aid != AID_UNSPEC) 1078 printf(" Local Address: %s\n", log_addr(&rtr->local_addr)); 1079 if (rtr->session_id != -1) 1080 printf (" Session ID: %d Serial #: %u\n", 1081 rtr->session_id, rtr->serial); 1082 printf(" Refresh: %u, Retry: %u, Expire: %u\n", 1083 rtr->refresh, rtr->retry, rtr->expire); 1084 1085 if (rtr->last_sent_error != NO_ERROR) { 1086 printf(" Last sent error: %s\n", 1087 log_rtr_error(rtr->last_sent_error)); 1088 if (rtr->last_sent_msg[0]) 1089 printf(" with reason \"%s\"", 1090 log_reason(rtr->last_sent_msg)); 1091 } 1092 if (rtr->last_recv_error != NO_ERROR) { 1093 printf("Last received error: %s\n", 1094 log_rtr_error(rtr->last_recv_error)); 1095 if (rtr->last_recv_msg[0]) 1096 printf(" with reason \"%s\"", 1097 log_reason(rtr->last_recv_msg)); 1098 } 1099 1100 printf("\n"); 1101 } 1102 1103 static void 1104 show_result(u_int rescode) 1105 { 1106 if (rescode == 0) 1107 printf("request processed\n"); 1108 else if (rescode >= 1109 sizeof(ctl_res_strerror)/sizeof(ctl_res_strerror[0])) 1110 printf("unknown result error code %u\n", rescode); 1111 else 1112 printf("%s\n", ctl_res_strerror[rescode]); 1113 } 1114 1115 static void 1116 show_tail(void) 1117 { 1118 /* nothing */ 1119 } 1120 1121 const struct output show_output = { 1122 .head = show_head, 1123 .neighbor = show_neighbor, 1124 .timer = show_timer, 1125 .fib = show_fib, 1126 .fib_table = show_fib_table, 1127 .nexthop = show_nexthop, 1128 .interface = show_interface, 1129 .communities = show_communities, 1130 .attr = show_attr, 1131 .rib = show_rib, 1132 .rib_mem = show_rib_mem, 1133 .rib_hash = show_rib_hash, 1134 .set = show_rib_set, 1135 .rtr = show_rtr, 1136 .result = show_result, 1137 .tail = show_tail 1138 }; 1139