1 /* $OpenBSD: output.c,v 1.16 2021/04/26 18:23:20 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, D = Dynamic\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 u_int8_t i; 139 140 printf(" Multiprotocol extensions: "); 141 for (i = 0, 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_restart(struct capabilities *capa) 151 { 152 int comma; 153 u_int8_t i; 154 155 printf(" Graceful Restart"); 156 if (capa->grestart.timeout) 157 printf(": Timeout: %d, ", capa->grestart.timeout); 158 for (i = 0, comma = 0; i < AID_MAX; i++) 159 if (capa->grestart.flags[i] & CAPA_GR_PRESENT) { 160 if (!comma && 161 capa->grestart.flags[i] & CAPA_GR_RESTART) 162 printf("restarted, "); 163 if (comma) 164 printf(", "); 165 printf("%s", aid2str(i)); 166 if (capa->grestart.flags[i] & CAPA_GR_FORWARD) 167 printf(" (preserved)"); 168 comma = 1; 169 } 170 printf("\n"); 171 } 172 173 static void 174 show_neighbor_msgstats(struct peer *p) 175 { 176 printf(" Message statistics:\n"); 177 printf(" %-15s %-10s %-10s\n", "", "Sent", "Received"); 178 printf(" %-15s %10llu %10llu\n", "Opens", 179 p->stats.msg_sent_open, p->stats.msg_rcvd_open); 180 printf(" %-15s %10llu %10llu\n", "Notifications", 181 p->stats.msg_sent_notification, p->stats.msg_rcvd_notification); 182 printf(" %-15s %10llu %10llu\n", "Updates", 183 p->stats.msg_sent_update, p->stats.msg_rcvd_update); 184 printf(" %-15s %10llu %10llu\n", "Keepalives", 185 p->stats.msg_sent_keepalive, p->stats.msg_rcvd_keepalive); 186 printf(" %-15s %10llu %10llu\n", "Route Refresh", 187 p->stats.msg_sent_rrefresh, p->stats.msg_rcvd_rrefresh); 188 printf(" %-15s %10llu %10llu\n\n", "Total", 189 p->stats.msg_sent_open + p->stats.msg_sent_notification + 190 p->stats.msg_sent_update + p->stats.msg_sent_keepalive + 191 p->stats.msg_sent_rrefresh, 192 p->stats.msg_rcvd_open + p->stats.msg_rcvd_notification + 193 p->stats.msg_rcvd_update + p->stats.msg_rcvd_keepalive + 194 p->stats.msg_rcvd_rrefresh); 195 printf(" Update statistics:\n"); 196 printf(" %-15s %-10s %-10s\n", "", "Sent", "Received"); 197 printf(" %-15s %10u %10u\n", "Prefixes", 198 p->stats.prefix_out_cnt, p->stats.prefix_cnt); 199 printf(" %-15s %10llu %10llu\n", "Updates", 200 p->stats.prefix_sent_update, p->stats.prefix_rcvd_update); 201 printf(" %-15s %10llu %10llu\n", "Withdraws", 202 p->stats.prefix_sent_withdraw, p->stats.prefix_rcvd_withdraw); 203 printf(" %-15s %10llu %10llu\n", "End-of-Rib", 204 p->stats.prefix_sent_eor, p->stats.prefix_rcvd_eor); 205 } 206 207 static void 208 show_neighbor_full(struct peer *p, struct parse_result *res) 209 { 210 const char *errstr; 211 struct in_addr ina; 212 char *s; 213 int hascapamp = 0; 214 u_int8_t i; 215 216 if ((p->conf.remote_addr.aid == AID_INET && 217 p->conf.remote_masklen != 32) || 218 (p->conf.remote_addr.aid == AID_INET6 && 219 p->conf.remote_masklen != 128)) { 220 if (asprintf(&s, "%s/%u", 221 log_addr(&p->conf.remote_addr), 222 p->conf.remote_masklen) == -1) 223 err(1, NULL); 224 } else if ((s = strdup(log_addr(&p->conf.remote_addr))) == NULL) 225 err(1, "strdup"); 226 227 printf("BGP neighbor is %s, ", s); 228 free(s); 229 if (p->conf.remote_as == 0 && p->conf.template) 230 printf("remote AS: accept any"); 231 else 232 printf("remote AS %s", log_as(p->conf.remote_as)); 233 if (p->conf.template) 234 printf(", Template"); 235 if (p->template) 236 printf(", Cloned"); 237 if (p->conf.passive) 238 printf(", Passive"); 239 if (p->conf.ebgp && p->conf.distance > 1) 240 printf(", Multihop (%u)", (int)p->conf.distance); 241 printf("\n"); 242 if (p->conf.descr[0]) 243 printf(" Description: %s\n", p->conf.descr); 244 if (p->conf.max_prefix) { 245 printf(" Max-prefix: %u", p->conf.max_prefix); 246 if (p->conf.max_prefix_restart) 247 printf(" (restart %u)", 248 p->conf.max_prefix_restart); 249 } 250 if (p->conf.max_out_prefix) { 251 printf(" Max-prefix out: %u", p->conf.max_out_prefix); 252 if (p->conf.max_out_prefix_restart) 253 printf(" (restart %u)", 254 p->conf.max_out_prefix_restart); 255 } 256 if (p->conf.max_prefix || p->conf.max_out_prefix) 257 printf("\n"); 258 259 if (p->state == STATE_ESTABLISHED) { 260 ina.s_addr = p->remote_bgpid; 261 printf(" BGP version 4, remote router-id %s", 262 inet_ntoa(ina)); 263 printf("%s\n", fmt_auth_method(p->auth.method)); 264 } 265 printf(" BGP state = %s", statenames[p->state]); 266 if (p->conf.down) { 267 printf(", marked down"); 268 } 269 if (p->conf.reason[0]) { 270 printf(" with shutdown reason \"%s\"", 271 log_reason(p->conf.reason)); 272 } 273 if (p->stats.last_updown != 0) 274 printf(", %s for %s", 275 p->state == STATE_ESTABLISHED ? "up" : "down", 276 fmt_monotime(p->stats.last_updown)); 277 printf("\n"); 278 printf(" Last read %s, holdtime %us, keepalive interval %us\n", 279 fmt_monotime(p->stats.last_read), 280 p->holdtime, p->holdtime/3); 281 printf(" Last write %s\n", fmt_monotime(p->stats.last_write)); 282 for (i = 0; i < AID_MAX; i++) 283 if (p->capa.peer.mp[i]) 284 hascapamp = 1; 285 if (hascapamp || p->capa.peer.refresh || 286 p->capa.peer.grestart.restart || p->capa.peer.as4byte) { 287 printf(" Neighbor capabilities:\n"); 288 if (hascapamp) 289 show_neighbor_capa_mp(&p->capa.peer); 290 if (p->capa.peer.refresh) 291 printf(" Route Refresh\n"); 292 if (p->capa.peer.grestart.restart) 293 show_neighbor_capa_restart(&p->capa.peer); 294 if (p->capa.peer.as4byte) 295 printf(" 4-byte AS numbers\n"); 296 } 297 for (i = 0; i < AID_MAX; i++) 298 if (p->capa.neg.mp[i]) 299 hascapamp = 1; 300 if (hascapamp || p->capa.neg.refresh || 301 p->capa.neg.grestart.restart || p->capa.neg.as4byte) { 302 printf(" Negotiated capabilities:\n"); 303 if (hascapamp) 304 show_neighbor_capa_mp(&p->capa.neg); 305 if (p->capa.neg.refresh) 306 printf(" Route Refresh\n"); 307 if (p->capa.neg.grestart.restart) 308 show_neighbor_capa_restart(&p->capa.neg); 309 if (p->capa.neg.as4byte) 310 printf(" 4-byte AS numbers\n"); 311 } 312 printf("\n"); 313 314 if (res->action == SHOW_NEIGHBOR_TIMERS) 315 return; 316 317 show_neighbor_msgstats(p); 318 printf("\n"); 319 if (p->stats.last_reason[0]) { 320 printf(" Last received shutdown reason: \"%s\"\n", 321 log_reason(p->stats.last_reason)); 322 } 323 324 errstr = fmt_errstr(p->stats.last_sent_errcode, 325 p->stats.last_sent_suberr); 326 if (errstr) 327 printf(" Last error sent: %s\n", errstr); 328 errstr = fmt_errstr(p->stats.last_rcvd_errcode, 329 p->stats.last_rcvd_suberr); 330 if (errstr) 331 printf(" Last error received: %s\n", errstr); 332 333 if (p->state >= STATE_OPENSENT) { 334 printf(" Local host: %20s, Local port: %5u\n", 335 log_addr(&p->local), p->local_port); 336 337 printf(" Remote host: %20s, Remote port: %5u\n", 338 log_addr(&p->remote), p->remote_port); 339 printf("\n"); 340 } 341 } 342 343 static void 344 show_neighbor(struct peer *p, struct parse_result *res) 345 { 346 char *s; 347 348 switch (res->action) { 349 case SHOW: 350 case SHOW_SUMMARY: 351 show_summary(p); 352 break; 353 case SHOW_SUMMARY_TERSE: 354 s = fmt_peer(p->conf.descr, &p->conf.remote_addr, 355 p->conf.remote_masklen); 356 printf("%s %s %s\n", s, log_as(p->conf.remote_as), 357 p->conf.template ? "Template" : statenames[p->state]); 358 free(s); 359 break; 360 case SHOW_NEIGHBOR: 361 case SHOW_NEIGHBOR_TIMERS: 362 show_neighbor_full(p, res); 363 break; 364 case SHOW_NEIGHBOR_TERSE: 365 s = fmt_peer(NULL, &p->conf.remote_addr, 366 p->conf.remote_masklen); 367 printf("%llu %llu %llu %llu %llu %llu %llu %llu %llu " 368 "%llu %u %u %llu %llu %llu %llu %s %s \"%s\"\n", 369 p->stats.msg_sent_open, p->stats.msg_rcvd_open, 370 p->stats.msg_sent_notification, 371 p->stats.msg_rcvd_notification, 372 p->stats.msg_sent_update, p->stats.msg_rcvd_update, 373 p->stats.msg_sent_keepalive, p->stats.msg_rcvd_keepalive, 374 p->stats.msg_sent_rrefresh, p->stats.msg_rcvd_rrefresh, 375 p->stats.prefix_cnt, p->conf.max_prefix, 376 p->stats.prefix_sent_update, p->stats.prefix_rcvd_update, 377 p->stats.prefix_sent_withdraw, 378 p->stats.prefix_rcvd_withdraw, s, 379 log_as(p->conf.remote_as), p->conf.descr); 380 free(s); 381 break; 382 default: 383 break; 384 } 385 } 386 387 static void 388 show_timer(struct ctl_timer *t) 389 { 390 printf(" %-20s ", timernames[t->type]); 391 392 if (t->val <= 0) 393 printf("%-20s\n", "due"); 394 else 395 printf("due in %-13s\n", fmt_timeframe(t->val)); 396 } 397 398 static void 399 show_fib(struct kroute_full *kf) 400 { 401 char *p; 402 403 if (asprintf(&p, "%s/%u", log_addr(&kf->prefix), kf->prefixlen) == -1) 404 err(1, NULL); 405 printf("%s%4i %-20s ", fmt_fib_flags(kf->flags), kf->priority, p); 406 free(p); 407 408 if (kf->flags & F_CONNECTED) 409 printf("link#%u", kf->ifindex); 410 else 411 printf("%s", log_addr(&kf->nexthop)); 412 printf("\n"); 413 } 414 415 static void 416 show_fib_table(struct ktable *kt) 417 { 418 printf("%5i %-20s %-8s%s\n", kt->rtableid, kt->descr, 419 kt->fib_sync ? "coupled" : "decoupled", 420 kt->fib_sync != kt->fib_conf ? "*" : ""); 421 } 422 423 static void 424 show_nexthop(struct ctl_show_nexthop *nh) 425 { 426 struct kroute *k; 427 struct kroute6 *k6; 428 char *s; 429 430 printf("%s %-15s ", nh->valid ? "*" : " ", log_addr(&nh->addr)); 431 if (!nh->krvalid) { 432 printf("\n"); 433 return; 434 } 435 switch (nh->addr.aid) { 436 case AID_INET: 437 k = &nh->kr.kr4; 438 if (asprintf(&s, "%s/%u", inet_ntoa(k->prefix), 439 k->prefixlen) == -1) 440 err(1, NULL); 441 printf("%-20s", s); 442 free(s); 443 printf("%3i %-15s ", k->priority, 444 k->flags & F_CONNECTED ? "connected" : 445 inet_ntoa(k->nexthop)); 446 break; 447 case AID_INET6: 448 k6 = &nh->kr.kr6; 449 if (asprintf(&s, "%s/%u", log_in6addr(&k6->prefix), 450 k6->prefixlen) == -1) 451 err(1, NULL); 452 printf("%-20s", s); 453 free(s); 454 printf("%3i %-15s ", k6->priority, 455 k6->flags & F_CONNECTED ? "connected" : 456 log_in6addr(&k6->nexthop)); 457 break; 458 default: 459 printf("unknown address family\n"); 460 return; 461 } 462 if (nh->iface.ifname[0]) { 463 printf("%s (%s, %s)", nh->iface.ifname, 464 nh->iface.is_up ? "UP" : "DOWN", 465 nh->iface.baudrate ? 466 get_baudrate(nh->iface.baudrate, "bps") : 467 nh->iface.linkstate); 468 } 469 printf("\n"); 470 } 471 472 static void 473 show_interface(struct ctl_show_interface *iface) 474 { 475 printf("%-15s", iface->ifname); 476 printf("%-9u", iface->rdomain); 477 printf("%-9s", iface->nh_reachable ? "ok" : "invalid"); 478 printf("%-7s", iface->is_up ? "UP" : ""); 479 480 if (iface->media[0]) 481 printf("%s, ", iface->media); 482 printf("%s", iface->linkstate); 483 484 if (iface->baudrate > 0) 485 printf(", %s", get_baudrate(iface->baudrate, "Bit/s")); 486 printf("\n"); 487 } 488 489 static void 490 show_communities(u_char *data, size_t len, struct parse_result *res) 491 { 492 struct community c; 493 size_t i; 494 u_int64_t ext; 495 u_int8_t type = 0; 496 497 if (len % sizeof(c)) 498 return; 499 500 for (i = 0; i < len; i += sizeof(c)) { 501 memcpy(&c, data + i, sizeof(c)); 502 503 if (type != c.flags) { 504 if (type != 0) 505 printf("%c", EOL0(res->flags)); 506 printf(" %s:", fmt_attr(c.flags, 507 ATTR_OPTIONAL | ATTR_TRANSITIVE)); 508 type = c.flags; 509 } 510 511 switch (c.flags) { 512 case COMMUNITY_TYPE_BASIC: 513 printf(" %s", fmt_community(c.data1, c.data2)); 514 break; 515 case COMMUNITY_TYPE_LARGE: 516 printf(" %s", 517 fmt_large_community(c.data1, c.data2, c.data3)); 518 break; 519 case COMMUNITY_TYPE_EXT: 520 ext = (u_int64_t)c.data3 << 48; 521 switch (c.data3 >> 8) { 522 case EXT_COMMUNITY_TRANS_TWO_AS: 523 case EXT_COMMUNITY_TRANS_OPAQUE: 524 case EXT_COMMUNITY_TRANS_EVPN: 525 case EXT_COMMUNITY_NON_TRANS_OPAQUE: 526 ext |= ((u_int64_t)c.data1 & 0xffff) << 32; 527 ext |= (u_int64_t)c.data2; 528 break; 529 case EXT_COMMUNITY_TRANS_FOUR_AS: 530 case EXT_COMMUNITY_TRANS_IPV4: 531 ext |= (u_int64_t)c.data1 << 16; 532 ext |= (u_int64_t)c.data2 & 0xffff; 533 break; 534 } 535 ext = htobe64(ext); 536 537 printf(" %s", fmt_ext_community((void *)&ext)); 538 break; 539 } 540 } 541 542 printf("%c", EOL0(res->flags)); 543 } 544 545 static void 546 show_community(u_char *data, u_int16_t len) 547 { 548 u_int16_t a, v; 549 u_int16_t i; 550 551 if (len & 0x3) { 552 printf("bad length"); 553 return; 554 } 555 556 for (i = 0; i < len; i += 4) { 557 memcpy(&a, data + i, sizeof(a)); 558 memcpy(&v, data + i + 2, sizeof(v)); 559 a = ntohs(a); 560 v = ntohs(v); 561 printf("%s", fmt_community(a, v)); 562 563 if (i + 4 < len) 564 printf(" "); 565 } 566 } 567 568 static void 569 show_large_community(u_char *data, u_int16_t len) 570 { 571 u_int32_t a, l1, l2; 572 u_int16_t i; 573 574 if (len % 12) { 575 printf("bad length"); 576 return; 577 } 578 579 for (i = 0; i < len; i += 12) { 580 memcpy(&a, data + i, sizeof(a)); 581 memcpy(&l1, data + i + 4, sizeof(l1)); 582 memcpy(&l2, data + i + 8, sizeof(l2)); 583 a = ntohl(a); 584 l1 = ntohl(l1); 585 l2 = ntohl(l2); 586 printf("%s", fmt_large_community(a, l1, l2)); 587 588 if (i + 12 < len) 589 printf(" "); 590 } 591 } 592 593 static void 594 show_ext_community(u_char *data, u_int16_t len) 595 { 596 u_int16_t i; 597 598 if (len & 0x7) { 599 printf("bad length"); 600 return; 601 } 602 603 for (i = 0; i < len; i += 8) { 604 printf("%s", fmt_ext_community(data + i)); 605 606 if (i + 8 < len) 607 printf(" "); 608 } 609 } 610 611 static void 612 show_attr(u_char *data, size_t len, int reqflags) 613 { 614 u_char *path; 615 struct in_addr id; 616 struct bgpd_addr prefix; 617 char *aspath; 618 u_int32_t as; 619 u_int16_t alen, ioff, short_as, afi; 620 u_int8_t flags, type, safi, aid, prefixlen; 621 int i, pos, e2, e4; 622 623 if (len < 3) { 624 warnx("Too short BGP attrbute"); 625 return; 626 } 627 628 flags = data[0]; 629 type = data[1]; 630 631 /* get the attribute length */ 632 if (flags & ATTR_EXTLEN) { 633 if (len < 4) { 634 warnx("Too short BGP attrbute"); 635 return; 636 } 637 memcpy(&alen, data+2, sizeof(u_int16_t)); 638 alen = ntohs(alen); 639 data += 4; 640 len -= 4; 641 } else { 642 alen = data[2]; 643 data += 3; 644 len -= 3; 645 } 646 647 /* bad imsg len how can that happen!? */ 648 if (alen > len) { 649 warnx("Bad BGP attrbute length"); 650 return; 651 } 652 653 printf(" %s: ", fmt_attr(type, flags)); 654 655 switch (type) { 656 case ATTR_ORIGIN: 657 if (alen == 1) 658 printf("%s", fmt_origin(*data, 0)); 659 else 660 printf("bad length"); 661 break; 662 case ATTR_ASPATH: 663 case ATTR_AS4_PATH: 664 /* prefer 4-byte AS here */ 665 e4 = aspath_verify(data, alen, 1, 0); 666 e2 = aspath_verify(data, alen, 0, 0); 667 if (e4 == 0 || e4 == AS_ERR_SOFT) { 668 path = data; 669 } else if (e2 == 0 || e2 == AS_ERR_SOFT) { 670 path = aspath_inflate(data, alen, &alen); 671 if (path == NULL) 672 errx(1, "aspath_inflate failed"); 673 } else { 674 printf("bad AS-Path"); 675 break; 676 } 677 if (aspath_asprint(&aspath, path, alen) == -1) 678 err(1, NULL); 679 printf("%s", aspath); 680 free(aspath); 681 if (path != data) 682 free(path); 683 break; 684 case ATTR_NEXTHOP: 685 if (alen == 4) { 686 memcpy(&id, data, sizeof(id)); 687 printf("%s", inet_ntoa(id)); 688 } else 689 printf("bad length"); 690 break; 691 case ATTR_MED: 692 case ATTR_LOCALPREF: 693 if (alen == 4) { 694 u_int32_t val; 695 memcpy(&val, data, sizeof(val)); 696 val = ntohl(val); 697 printf("%u", val); 698 } else 699 printf("bad length"); 700 break; 701 case ATTR_AGGREGATOR: 702 case ATTR_AS4_AGGREGATOR: 703 if (alen == 8) { 704 memcpy(&as, data, sizeof(as)); 705 memcpy(&id, data + sizeof(as), sizeof(id)); 706 as = ntohl(as); 707 } else if (alen == 6) { 708 memcpy(&short_as, data, sizeof(short_as)); 709 memcpy(&id, data + sizeof(short_as), sizeof(id)); 710 as = ntohs(short_as); 711 } else { 712 printf("bad length"); 713 break; 714 } 715 printf("%s [%s]", log_as(as), inet_ntoa(id)); 716 break; 717 case ATTR_COMMUNITIES: 718 show_community(data, alen); 719 break; 720 case ATTR_ORIGINATOR_ID: 721 if (alen == 4) { 722 memcpy(&id, data, sizeof(id)); 723 printf("%s", inet_ntoa(id)); 724 } else 725 printf("bad length"); 726 break; 727 case ATTR_CLUSTER_LIST: 728 for (ioff = 0; ioff + sizeof(id) <= alen; 729 ioff += sizeof(id)) { 730 memcpy(&id, data + ioff, sizeof(id)); 731 printf(" %s", inet_ntoa(id)); 732 } 733 break; 734 case ATTR_MP_REACH_NLRI: 735 case ATTR_MP_UNREACH_NLRI: 736 if (alen < 3) { 737 bad_len: 738 printf("bad length"); 739 break; 740 } 741 memcpy(&afi, data, 2); 742 data += 2; 743 alen -= 2; 744 afi = ntohs(afi); 745 safi = *data++; 746 alen--; 747 748 if (afi2aid(afi, safi, &aid) == -1) { 749 printf("bad AFI/SAFI pair"); 750 break; 751 } 752 printf(" %s", aid2str(aid)); 753 754 if (type == ATTR_MP_REACH_NLRI) { 755 struct bgpd_addr nexthop; 756 u_int8_t nhlen; 757 if (len == 0) 758 goto bad_len; 759 nhlen = *data++; 760 alen--; 761 if (nhlen > len) 762 goto bad_len; 763 memset(&nexthop, 0, sizeof(nexthop)); 764 switch (aid) { 765 case AID_INET6: 766 nexthop.aid = aid; 767 if (nhlen != 16 && nhlen != 32) 768 goto bad_len; 769 memcpy(&nexthop.v6.s6_addr, data, 16); 770 break; 771 case AID_VPN_IPv4: 772 if (nhlen != 12) 773 goto bad_len; 774 nexthop.aid = AID_INET; 775 memcpy(&nexthop.v4, data + sizeof(u_int64_t), 776 sizeof(nexthop.v4)); 777 break; 778 case AID_VPN_IPv6: 779 if (nhlen != 24) 780 goto bad_len; 781 nexthop.aid = AID_INET6; 782 memcpy(&nexthop.v6, data + sizeof(u_int64_t), 783 sizeof(nexthop.v6)); 784 break; 785 default: 786 printf("unhandled AID #%u", aid); 787 goto done; 788 } 789 /* ignore reserved (old SNPA) field as per RFC4760 */ 790 data += nhlen + 1; 791 alen -= nhlen + 1; 792 793 printf(" nexthop: %s", log_addr(&nexthop)); 794 } 795 796 while (alen > 0) { 797 switch (aid) { 798 case AID_INET6: 799 pos = nlri_get_prefix6(data, alen, &prefix, 800 &prefixlen); 801 break; 802 case AID_VPN_IPv4: 803 pos = nlri_get_vpn4(data, alen, &prefix, 804 &prefixlen, 1); 805 break; 806 case AID_VPN_IPv6: 807 pos = nlri_get_vpn6(data, alen, &prefix, 808 &prefixlen, 1); 809 break; 810 default: 811 printf("unhandled AID #%u", aid); 812 goto done; 813 } 814 if (pos == -1) { 815 printf("bad %s prefix", aid2str(aid)); 816 break; 817 } 818 printf(" %s/%u", log_addr(&prefix), prefixlen); 819 data += pos; 820 alen -= pos; 821 } 822 break; 823 case ATTR_EXT_COMMUNITIES: 824 show_ext_community(data, alen); 825 break; 826 case ATTR_LARGE_COMMUNITIES: 827 show_large_community(data, alen); 828 break; 829 case ATTR_ATOMIC_AGGREGATE: 830 default: 831 printf(" len %u", alen); 832 if (alen) { 833 printf(":"); 834 for (i=0; i < alen; i++) 835 printf(" %02x", *(data+i)); 836 } 837 break; 838 } 839 done: 840 printf("%c", EOL0(reqflags)); 841 } 842 843 static void 844 show_rib_brief(struct ctl_show_rib *r, u_char *asdata, size_t aslen) 845 { 846 char *p, *aspath; 847 848 if (asprintf(&p, "%s/%u", log_addr(&r->prefix), r->prefixlen) == -1) 849 err(1, NULL); 850 printf("%s %3s %-20s %-15s %5u %5u ", 851 fmt_flags(r->flags, 1), fmt_ovs(r->validation_state, 1), p, 852 log_addr(&r->exit_nexthop), r->local_pref, r->med); 853 free(p); 854 855 if (aspath_asprint(&aspath, asdata, aslen) == -1) 856 err(1, NULL); 857 if (strlen(aspath) > 0) 858 printf("%s ", aspath); 859 free(aspath); 860 861 printf("%s\n", fmt_origin(r->origin, 1)); 862 } 863 864 static void 865 show_rib_detail(struct ctl_show_rib *r, u_char *asdata, size_t aslen, 866 int flag0) 867 { 868 struct in_addr id; 869 char *aspath, *s; 870 871 printf("\nBGP routing table entry for %s/%u%c", 872 log_addr(&r->prefix), r->prefixlen, 873 EOL0(flag0)); 874 875 if (aspath_asprint(&aspath, asdata, aslen) == -1) 876 err(1, NULL); 877 if (strlen(aspath) > 0) 878 printf(" %s%c", aspath, EOL0(flag0)); 879 free(aspath); 880 881 s = fmt_peer(r->descr, &r->remote_addr, -1); 882 printf(" Nexthop %s ", log_addr(&r->exit_nexthop)); 883 printf("(via %s) Neighbor %s (", log_addr(&r->true_nexthop), s); 884 free(s); 885 id.s_addr = htonl(r->remote_id); 886 printf("%s)%c", inet_ntoa(id), EOL0(flag0)); 887 888 printf(" Origin %s, metric %u, localpref %u, weight %u, ovs %s, ", 889 fmt_origin(r->origin, 0), r->med, r->local_pref, r->weight, 890 fmt_ovs(r->validation_state, 0)); 891 printf("%s", fmt_flags(r->flags, 0)); 892 893 printf("%c Last update: %s ago%c", EOL0(flag0), 894 fmt_timeframe(r->age), EOL0(flag0)); 895 } 896 897 static void 898 show_rib(struct ctl_show_rib *r, u_char *asdata, size_t aslen, 899 struct parse_result *res) 900 { 901 if (res->flags & F_CTL_DETAIL) 902 show_rib_detail(r, asdata, aslen, res->flags); 903 else 904 show_rib_brief(r, asdata, aslen); 905 } 906 907 static void 908 show_rib_mem(struct rde_memstats *stats) 909 { 910 size_t pts = 0; 911 int i; 912 913 printf("RDE memory statistics\n"); 914 for (i = 0; i < AID_MAX; i++) { 915 if (stats->pt_cnt[i] == 0) 916 continue; 917 pts += stats->pt_cnt[i] * pt_sizes[i]; 918 printf("%10lld %s network entries using %s of memory\n", 919 stats->pt_cnt[i], aid_vals[i].name, 920 fmt_mem(stats->pt_cnt[i] * pt_sizes[i])); 921 } 922 printf("%10lld rib entries using %s of memory\n", 923 stats->rib_cnt, fmt_mem(stats->rib_cnt * 924 sizeof(struct rib_entry))); 925 printf("%10lld prefix entries using %s of memory\n", 926 stats->prefix_cnt, fmt_mem(stats->prefix_cnt * 927 sizeof(struct prefix))); 928 printf("%10lld BGP path attribute entries using %s of memory\n", 929 stats->path_cnt, fmt_mem(stats->path_cnt * 930 sizeof(struct rde_aspath))); 931 printf("\t and holding %lld references\n", 932 stats->path_refs); 933 printf("%10lld BGP AS-PATH attribute entries using " 934 "%s of memory\n\t and holding %lld references\n", 935 stats->aspath_cnt, fmt_mem(stats->aspath_size), 936 stats->aspath_refs); 937 printf("%10lld entries for %lld BGP communities " 938 "using %s of memory\n", stats->comm_cnt, stats->comm_nmemb, 939 fmt_mem(stats->comm_cnt * sizeof(struct rde_community) + 940 stats->comm_size * sizeof(struct community))); 941 printf("\t and holding %lld references\n", 942 stats->comm_refs); 943 printf("%10lld BGP attributes entries using %s of memory\n", 944 stats->attr_cnt, fmt_mem(stats->attr_cnt * 945 sizeof(struct attr))); 946 printf("\t and holding %lld references\n", 947 stats->attr_refs); 948 printf("%10lld BGP attributes using %s of memory\n", 949 stats->attr_dcnt, fmt_mem(stats->attr_data)); 950 printf("%10lld as-set elements in %lld tables using " 951 "%s of memory\n", stats->aset_nmemb, stats->aset_cnt, 952 fmt_mem(stats->aset_size)); 953 printf("%10lld prefix-set elements using %s of memory\n", 954 stats->pset_cnt, fmt_mem(stats->pset_size)); 955 printf("RIB using %s of memory\n", fmt_mem(pts + 956 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)); 961 printf("Sets using %s of memory\n", fmt_mem(stats->aset_size + 962 stats->pset_size)); 963 printf("\nRDE hash statistics\n"); 964 } 965 966 static void 967 show_rib_hash(struct rde_hashstats *hash) 968 { 969 double avg, dev; 970 971 printf("\t%s: size %lld, %lld entries\n", hash->name, hash->num, 972 hash->sum); 973 avg = (double)hash->sum / (double)hash->num; 974 dev = sqrt(fmax(0, hash->sumq / hash->num - avg * avg)); 975 printf("\t min %lld max %lld avg/std-dev = %.3f/%.3f\n", 976 hash->min, hash->max, avg, dev); 977 } 978 979 static void 980 show_rib_set(struct ctl_show_set *set) 981 { 982 char buf[64]; 983 984 if (set->type == ASNUM_SET) 985 snprintf(buf, sizeof(buf), "%7s %7s %6zu", 986 "-", "-", set->as_cnt); 987 else 988 snprintf(buf, sizeof(buf), "%7zu %7zu %6s", 989 set->v4_cnt, set->v6_cnt, "-"); 990 991 printf("%-6s %-34s %s %11s\n", fmt_set_type(set), set->name, 992 buf, fmt_monotime(set->lastchange)); 993 } 994 995 static void 996 show_rtr(struct ctl_show_rtr *rtr) 997 { 998 static int not_first; 999 1000 if (not_first) 1001 printf("\n"); 1002 not_first = 1; 1003 1004 printf("RTR neighbor is %s, port %u\n", 1005 log_addr(&rtr->remote_addr), rtr->remote_port); 1006 if (rtr->descr[0]) 1007 printf(" Description: %s\n", rtr->descr); 1008 if (rtr->local_addr.aid != AID_UNSPEC) 1009 printf(" Local Address: %s\n", log_addr(&rtr->local_addr)); 1010 if (rtr->session_id != -1) 1011 printf (" Session ID: %d Serial #: %u\n", 1012 rtr->session_id, rtr->serial); 1013 printf(" Refresh: %u, Retry: %u, Expire: %u\n", 1014 rtr->refresh, rtr->retry, rtr->expire); 1015 1016 if (rtr->last_sent_error != NO_ERROR) { 1017 printf(" Last sent error: %s\n", 1018 log_rtr_error(rtr->last_sent_error)); 1019 if (rtr->last_sent_msg[0]) 1020 printf(" with reason \"%s\"", 1021 log_reason(rtr->last_sent_msg)); 1022 } 1023 if (rtr->last_recv_error != NO_ERROR) { 1024 printf("Last received error: %s\n", 1025 log_rtr_error(rtr->last_recv_error)); 1026 if (rtr->last_recv_msg[0]) 1027 printf(" with reason \"%s\"", 1028 log_reason(rtr->last_recv_msg)); 1029 } 1030 1031 printf("\n"); 1032 } 1033 1034 static void 1035 show_result(u_int rescode) 1036 { 1037 if (rescode == 0) 1038 printf("request processed\n"); 1039 else if (rescode >= 1040 sizeof(ctl_res_strerror)/sizeof(ctl_res_strerror[0])) 1041 printf("unknown result error code %u\n", rescode); 1042 else 1043 printf("%s\n", ctl_res_strerror[rescode]); 1044 } 1045 1046 static void 1047 show_tail(void) 1048 { 1049 /* nothing */ 1050 } 1051 1052 const struct output show_output = { 1053 .head = show_head, 1054 .neighbor = show_neighbor, 1055 .timer = show_timer, 1056 .fib = show_fib, 1057 .fib_table = show_fib_table, 1058 .nexthop = show_nexthop, 1059 .interface = show_interface, 1060 .communities = show_communities, 1061 .attr = show_attr, 1062 .rib = show_rib, 1063 .rib_mem = show_rib_mem, 1064 .rib_hash = show_rib_hash, 1065 .set = show_rib_set, 1066 .rtr = show_rtr, 1067 .result = show_result, 1068 .tail = show_tail 1069 }; 1070