1 /* $OpenBSD: bgpctl.c,v 1.236 2019/05/03 01:48:42 jsg Exp $ */ 2 3 /* 4 * Copyright (c) 2003 Henning Brauer <henning@openbsd.org> 5 * Copyright (c) 2016 Job Snijders <job@instituut.net> 6 * Copyright (c) 2016 Peter Hessler <phessler@openbsd.org> 7 * 8 * Permission to use, copy, modify, and distribute this software for any 9 * purpose with or without fee is hereby granted, provided that the above 10 * copyright notice and this permission notice appear in all copies. 11 * 12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 13 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 14 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 15 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 16 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 17 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 18 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 19 */ 20 21 #include <sys/types.h> 22 #include <sys/socket.h> 23 #include <sys/stat.h> 24 #include <sys/un.h> 25 26 #include <endian.h> 27 #include <err.h> 28 #include <errno.h> 29 #include <fcntl.h> 30 #include <math.h> 31 #include <stdio.h> 32 #include <stdlib.h> 33 #include <string.h> 34 #include <time.h> 35 #include <unistd.h> 36 #include <util.h> 37 38 #include "bgpd.h" 39 #include "session.h" 40 #include "rde.h" 41 #include "parser.h" 42 #include "irrfilter.h" 43 #include "mrtparser.h" 44 45 enum neighbor_views { 46 NV_DEFAULT, 47 NV_TIMERS 48 }; 49 50 #define EOL0(flag) ((flag & F_CTL_SSV) ? ';' : '\n') 51 52 int main(int, char *[]); 53 char *fmt_peer(const char *, const struct bgpd_addr *, int, int); 54 void show_summary_head(void); 55 int show_summary_msg(struct imsg *, int); 56 int show_summary_terse_msg(struct imsg *, int); 57 int show_neighbor_terse(struct imsg *); 58 int show_neighbor_msg(struct imsg *, enum neighbor_views); 59 void print_neighbor_capa_mp(struct peer *); 60 void print_neighbor_capa_restart(struct peer *); 61 void print_neighbor_msgstats(struct peer *); 62 void print_timer(const char *, time_t); 63 static char *fmt_timeframe(time_t t); 64 static char *fmt_timeframe_core(time_t t); 65 void show_fib_head(void); 66 void show_fib_tables_head(void); 67 void show_network_head(void); 68 void show_fib_flags(u_int16_t); 69 int show_fib_msg(struct imsg *); 70 void show_nexthop_head(void); 71 int show_nexthop_msg(struct imsg *); 72 void show_interface_head(void); 73 int show_interface_msg(struct imsg *); 74 void show_rib_summary_head(void); 75 void print_prefix(struct bgpd_addr *, u_int8_t, u_int8_t, u_int8_t); 76 const char * print_origin(u_int8_t, int); 77 const char * print_ovs(u_int8_t, int); 78 void print_flags(u_int8_t, int); 79 int show_rib_summary_msg(struct imsg *); 80 int show_rib_detail_msg(struct imsg *, int, int); 81 void show_rib_brief(struct ctl_show_rib *, u_char *); 82 void show_rib_detail(struct ctl_show_rib *, u_char *, int, int); 83 void show_attr(void *, u_int16_t, int); 84 void show_community(u_char *, u_int16_t); 85 void show_large_community(u_char *, u_int16_t); 86 void show_ext_community(u_char *, u_int16_t); 87 int show_rib_memory_msg(struct imsg *); 88 void send_filterset(struct imsgbuf *, struct filter_set_head *); 89 const char *get_errstr(u_int8_t, u_int8_t); 90 int show_result(struct imsg *); 91 void show_mrt_dump(struct mrt_rib *, struct mrt_peer *, void *); 92 void network_mrt_dump(struct mrt_rib *, struct mrt_peer *, void *); 93 void show_mrt_state(struct mrt_bgp_state *, void *); 94 void show_mrt_msg(struct mrt_bgp_msg *, void *); 95 const char *msg_type(u_int8_t); 96 void network_bulk(struct parse_result *); 97 const char *print_auth_method(enum auth_method); 98 int match_aspath(void *, u_int16_t, struct filter_as *); 99 100 struct imsgbuf *ibuf; 101 struct mrt_parser show_mrt = { show_mrt_dump, show_mrt_state, show_mrt_msg }; 102 struct mrt_parser net_mrt = { network_mrt_dump, NULL, NULL }; 103 int tableid; 104 105 __dead void 106 usage(void) 107 { 108 extern char *__progname; 109 110 fprintf(stderr, "usage: %s [-n] [-s socket] command [argument ...]\n", 111 __progname); 112 exit(1); 113 } 114 115 int 116 main(int argc, char *argv[]) 117 { 118 struct sockaddr_un sun; 119 int fd, n, done, ch, nodescr = 0, verbose = 0; 120 struct imsg imsg; 121 struct network_config net; 122 struct parse_result *res; 123 struct ctl_neighbor neighbor; 124 struct ctl_show_rib_request ribreq; 125 char *sockname; 126 enum imsg_type type; 127 128 if (pledge("stdio rpath wpath cpath unix inet dns", NULL) == -1) 129 err(1, "pledge"); 130 131 tableid = getrtable(); 132 if (asprintf(&sockname, "%s.%d", SOCKET_NAME, tableid) == -1) 133 err(1, "asprintf"); 134 135 while ((ch = getopt(argc, argv, "ns:")) != -1) { 136 switch (ch) { 137 case 'n': 138 if (++nodescr > 1) 139 usage(); 140 break; 141 case 's': 142 sockname = optarg; 143 break; 144 default: 145 usage(); 146 /* NOTREACHED */ 147 } 148 } 149 argc -= optind; 150 argv += optind; 151 152 if ((res = parse(argc, argv)) == NULL) 153 exit(1); 154 155 memcpy(&neighbor.addr, &res->peeraddr, sizeof(neighbor.addr)); 156 strlcpy(neighbor.descr, res->peerdesc, sizeof(neighbor.descr)); 157 neighbor.is_group = res->is_group; 158 strlcpy(neighbor.shutcomm, res->shutcomm, sizeof(neighbor.shutcomm)); 159 160 switch (res->action) { 161 case IRRFILTER: 162 if (!(res->flags & (F_IPV4|F_IPV6))) 163 res->flags |= (F_IPV4|F_IPV6); 164 irr_main(res->as.as_min, res->flags, res->irr_outdir); 165 break; 166 case SHOW_MRT: 167 if (pledge("stdio", NULL) == -1) 168 err(1, "pledge"); 169 170 bzero(&ribreq, sizeof(ribreq)); 171 if (res->as.type != AS_UNDEF) 172 ribreq.as = res->as; 173 if (res->addr.aid) { 174 ribreq.prefix = res->addr; 175 ribreq.prefixlen = res->prefixlen; 176 } 177 /* XXX currently no communities support */ 178 ribreq.neighbor = neighbor; 179 ribreq.aid = res->aid; 180 ribreq.flags = res->flags; 181 ribreq.validation_state = res->validation_state; 182 show_mrt.arg = &ribreq; 183 if (!(res->flags & F_CTL_DETAIL)) 184 show_rib_summary_head(); 185 mrt_parse(res->mrtfd, &show_mrt, 1); 186 exit(0); 187 default: 188 break; 189 } 190 191 if (pledge("stdio unix", NULL) == -1) 192 err(1, "pledge"); 193 194 if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) 195 err(1, "control_init: socket"); 196 197 bzero(&sun, sizeof(sun)); 198 sun.sun_family = AF_UNIX; 199 if (strlcpy(sun.sun_path, sockname, sizeof(sun.sun_path)) >= 200 sizeof(sun.sun_path)) 201 errx(1, "socket name too long"); 202 if (connect(fd, (struct sockaddr *)&sun, sizeof(sun)) == -1) 203 err(1, "connect: %s", sockname); 204 205 if (pledge("stdio", NULL) == -1) 206 err(1, "pledge"); 207 208 if ((ibuf = malloc(sizeof(struct imsgbuf))) == NULL) 209 err(1, NULL); 210 imsg_init(ibuf, fd); 211 done = 0; 212 213 switch (res->action) { 214 case NONE: 215 case IRRFILTER: 216 case SHOW_MRT: 217 usage(); 218 /* NOTREACHED */ 219 case SHOW: 220 case SHOW_SUMMARY: 221 imsg_compose(ibuf, IMSG_CTL_SHOW_NEIGHBOR, 0, 0, -1, NULL, 0); 222 show_summary_head(); 223 break; 224 case SHOW_SUMMARY_TERSE: 225 imsg_compose(ibuf, IMSG_CTL_SHOW_TERSE, 0, 0, -1, NULL, 0); 226 break; 227 case SHOW_FIB: 228 if (!res->addr.aid) { 229 struct ibuf *msg; 230 sa_family_t af; 231 232 af = aid2af(res->aid); 233 if ((msg = imsg_create(ibuf, IMSG_CTL_KROUTE, 234 res->rtableid, 0, sizeof(res->flags) + 235 sizeof(af))) == NULL) 236 errx(1, "imsg_create failure"); 237 if (imsg_add(msg, &res->flags, sizeof(res->flags)) == 238 -1 || 239 imsg_add(msg, &af, sizeof(af)) == -1) 240 errx(1, "imsg_add failure"); 241 imsg_close(ibuf, msg); 242 } else 243 imsg_compose(ibuf, IMSG_CTL_KROUTE_ADDR, res->rtableid, 244 0, -1, &res->addr, sizeof(res->addr)); 245 show_fib_head(); 246 break; 247 case SHOW_FIB_TABLES: 248 imsg_compose(ibuf, IMSG_CTL_SHOW_FIB_TABLES, 0, 0, -1, NULL, 0); 249 show_fib_tables_head(); 250 break; 251 case SHOW_NEXTHOP: 252 imsg_compose(ibuf, IMSG_CTL_SHOW_NEXTHOP, res->rtableid, 0, -1, 253 NULL, 0); 254 show_nexthop_head(); 255 break; 256 case SHOW_INTERFACE: 257 imsg_compose(ibuf, IMSG_CTL_SHOW_INTERFACE, 0, 0, -1, NULL, 0); 258 show_interface_head(); 259 break; 260 case SHOW_NEIGHBOR: 261 case SHOW_NEIGHBOR_TIMERS: 262 case SHOW_NEIGHBOR_TERSE: 263 neighbor.show_timers = (res->action == SHOW_NEIGHBOR_TIMERS); 264 if (res->peeraddr.aid || res->peerdesc[0]) 265 imsg_compose(ibuf, IMSG_CTL_SHOW_NEIGHBOR, 0, 0, -1, 266 &neighbor, sizeof(neighbor)); 267 else 268 imsg_compose(ibuf, IMSG_CTL_SHOW_NEIGHBOR, 0, 0, -1, 269 NULL, 0); 270 break; 271 case SHOW_RIB: 272 bzero(&ribreq, sizeof(ribreq)); 273 type = IMSG_CTL_SHOW_RIB; 274 if (res->addr.aid) { 275 ribreq.prefix = res->addr; 276 ribreq.prefixlen = res->prefixlen; 277 type = IMSG_CTL_SHOW_RIB_PREFIX; 278 } 279 if (res->as.type != AS_UNDEF) 280 ribreq.as = res->as; 281 if (res->community.type != COMMUNITY_TYPE_NONE) 282 ribreq.community = res->community; 283 ribreq.neighbor = neighbor; 284 strlcpy(ribreq.rib, res->rib, sizeof(ribreq.rib)); 285 ribreq.aid = res->aid; 286 ribreq.flags = res->flags; 287 imsg_compose(ibuf, type, 0, 0, -1, &ribreq, sizeof(ribreq)); 288 if (!(res->flags & F_CTL_DETAIL)) 289 show_rib_summary_head(); 290 break; 291 case SHOW_RIB_MEM: 292 imsg_compose(ibuf, IMSG_CTL_SHOW_RIB_MEM, 0, 0, -1, NULL, 0); 293 break; 294 case RELOAD: 295 imsg_compose(ibuf, IMSG_CTL_RELOAD, 0, 0, -1, NULL, 0); 296 printf("reload request sent.\n"); 297 break; 298 case FIB: 299 errx(1, "action==FIB"); 300 break; 301 case FIB_COUPLE: 302 imsg_compose(ibuf, IMSG_CTL_FIB_COUPLE, res->rtableid, 0, -1, 303 NULL, 0); 304 printf("couple request sent.\n"); 305 done = 1; 306 break; 307 case FIB_DECOUPLE: 308 imsg_compose(ibuf, IMSG_CTL_FIB_DECOUPLE, res->rtableid, 0, -1, 309 NULL, 0); 310 printf("decouple request sent.\n"); 311 done = 1; 312 break; 313 case NEIGHBOR: 314 errx(1, "action==NEIGHBOR"); 315 break; 316 case NEIGHBOR_UP: 317 imsg_compose(ibuf, IMSG_CTL_NEIGHBOR_UP, 0, 0, -1, 318 &neighbor, sizeof(neighbor)); 319 break; 320 case NEIGHBOR_DOWN: 321 imsg_compose(ibuf, IMSG_CTL_NEIGHBOR_DOWN, 0, 0, -1, 322 &neighbor, sizeof(neighbor)); 323 break; 324 case NEIGHBOR_CLEAR: 325 imsg_compose(ibuf, IMSG_CTL_NEIGHBOR_CLEAR, 0, 0, -1, 326 &neighbor, sizeof(neighbor)); 327 break; 328 case NEIGHBOR_RREFRESH: 329 imsg_compose(ibuf, IMSG_CTL_NEIGHBOR_RREFRESH, 0, 0, -1, 330 &neighbor, sizeof(neighbor)); 331 break; 332 case NEIGHBOR_DESTROY: 333 imsg_compose(ibuf, IMSG_CTL_NEIGHBOR_DESTROY, 0, 0, -1, 334 &neighbor, sizeof(neighbor)); 335 break; 336 case NETWORK_BULK_ADD: 337 case NETWORK_BULK_REMOVE: 338 network_bulk(res); 339 printf("requests sent.\n"); 340 done = 1; 341 break; 342 case NETWORK_ADD: 343 case NETWORK_REMOVE: 344 bzero(&net, sizeof(net)); 345 net.prefix = res->addr; 346 net.prefixlen = res->prefixlen; 347 net.rd = res->rd; 348 /* attribute sets are not supported */ 349 if (res->action == NETWORK_ADD) { 350 imsg_compose(ibuf, IMSG_NETWORK_ADD, 0, 0, -1, 351 &net, sizeof(net)); 352 send_filterset(ibuf, &res->set); 353 imsg_compose(ibuf, IMSG_NETWORK_DONE, 0, 0, -1, 354 NULL, 0); 355 } else 356 imsg_compose(ibuf, IMSG_NETWORK_REMOVE, 0, 0, -1, 357 &net, sizeof(net)); 358 printf("request sent.\n"); 359 done = 1; 360 break; 361 case NETWORK_FLUSH: 362 imsg_compose(ibuf, IMSG_NETWORK_FLUSH, 0, 0, -1, NULL, 0); 363 printf("request sent.\n"); 364 done = 1; 365 break; 366 case NETWORK_SHOW: 367 bzero(&ribreq, sizeof(ribreq)); 368 ribreq.aid = res->aid; 369 strlcpy(ribreq.rib, res->rib, sizeof(ribreq.rib)); 370 imsg_compose(ibuf, IMSG_CTL_SHOW_NETWORK, 0, 0, -1, 371 &ribreq, sizeof(ribreq)); 372 show_network_head(); 373 break; 374 case NETWORK_MRT: 375 bzero(&ribreq, sizeof(ribreq)); 376 if (res->as.type != AS_UNDEF) 377 ribreq.as = res->as; 378 if (res->addr.aid) { 379 ribreq.prefix = res->addr; 380 ribreq.prefixlen = res->prefixlen; 381 } 382 /* XXX currently no community support */ 383 ribreq.neighbor = neighbor; 384 ribreq.aid = res->aid; 385 ribreq.flags = res->flags; 386 net_mrt.arg = &ribreq; 387 mrt_parse(res->mrtfd, &net_mrt, 1); 388 done = 1; 389 break; 390 case LOG_VERBOSE: 391 verbose = 1; 392 /* FALLTHROUGH */ 393 case LOG_BRIEF: 394 imsg_compose(ibuf, IMSG_CTL_LOG_VERBOSE, 0, 0, -1, 395 &verbose, sizeof(verbose)); 396 printf("logging request sent.\n"); 397 done = 1; 398 break; 399 } 400 401 while (ibuf->w.queued) 402 if (msgbuf_write(&ibuf->w) <= 0 && errno != EAGAIN) 403 err(1, "write error"); 404 405 while (!done) { 406 if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) 407 err(1, "imsg_read error"); 408 if (n == 0) 409 errx(1, "pipe closed"); 410 411 while (!done) { 412 if ((n = imsg_get(ibuf, &imsg)) == -1) 413 err(1, "imsg_get error"); 414 if (n == 0) 415 break; 416 417 if (imsg.hdr.type == IMSG_CTL_RESULT) { 418 done = show_result(&imsg); 419 imsg_free(&imsg); 420 continue; 421 } 422 423 switch (res->action) { 424 case SHOW: 425 case SHOW_SUMMARY: 426 done = show_summary_msg(&imsg, nodescr); 427 break; 428 case SHOW_SUMMARY_TERSE: 429 done = show_summary_terse_msg(&imsg, nodescr); 430 break; 431 case SHOW_FIB: 432 case SHOW_FIB_TABLES: 433 case NETWORK_SHOW: 434 done = show_fib_msg(&imsg); 435 break; 436 case SHOW_NEXTHOP: 437 done = show_nexthop_msg(&imsg); 438 break; 439 case SHOW_INTERFACE: 440 done = show_interface_msg(&imsg); 441 break; 442 case SHOW_NEIGHBOR: 443 done = show_neighbor_msg(&imsg, NV_DEFAULT); 444 break; 445 case SHOW_NEIGHBOR_TIMERS: 446 done = show_neighbor_msg(&imsg, NV_TIMERS); 447 break; 448 case SHOW_NEIGHBOR_TERSE: 449 done = show_neighbor_terse(&imsg); 450 break; 451 case SHOW_RIB: 452 if (res->flags & F_CTL_DETAIL) 453 done = show_rib_detail_msg(&imsg, 454 nodescr, res->flags); 455 else 456 done = show_rib_summary_msg(&imsg); 457 break; 458 case SHOW_RIB_MEM: 459 done = show_rib_memory_msg(&imsg); 460 break; 461 case NEIGHBOR: 462 case NEIGHBOR_UP: 463 case NEIGHBOR_DOWN: 464 case NEIGHBOR_CLEAR: 465 case NEIGHBOR_RREFRESH: 466 case NEIGHBOR_DESTROY: 467 case NONE: 468 case RELOAD: 469 case FIB: 470 case FIB_COUPLE: 471 case FIB_DECOUPLE: 472 case NETWORK_ADD: 473 case NETWORK_REMOVE: 474 case NETWORK_FLUSH: 475 case NETWORK_BULK_ADD: 476 case NETWORK_BULK_REMOVE: 477 case IRRFILTER: 478 case LOG_VERBOSE: 479 case LOG_BRIEF: 480 case SHOW_MRT: 481 case NETWORK_MRT: 482 break; 483 } 484 imsg_free(&imsg); 485 } 486 } 487 close(fd); 488 free(ibuf); 489 490 exit(0); 491 } 492 493 char * 494 fmt_peer(const char *descr, const struct bgpd_addr *remote_addr, 495 int masklen, int nodescr) 496 { 497 const char *ip; 498 char *p; 499 500 if (descr[0] && !nodescr) { 501 if ((p = strdup(descr)) == NULL) 502 err(1, NULL); 503 return (p); 504 } 505 506 ip = log_addr(remote_addr); 507 if (masklen != -1 && ((remote_addr->aid == AID_INET && masklen != 32) || 508 (remote_addr->aid == AID_INET6 && masklen != 128))) { 509 if (asprintf(&p, "%s/%u", ip, masklen) == -1) 510 err(1, NULL); 511 } else { 512 if ((p = strdup(ip)) == NULL) 513 err(1, NULL); 514 } 515 516 return (p); 517 } 518 519 void 520 show_summary_head(void) 521 { 522 printf("%-20s %8s %10s %10s %5s %-8s %s\n", "Neighbor", "AS", 523 "MsgRcvd", "MsgSent", "OutQ", "Up/Down", "State/PrfRcvd"); 524 } 525 526 int 527 show_summary_msg(struct imsg *imsg, int nodescr) 528 { 529 struct peer *p; 530 char *s; 531 const char *a; 532 size_t alen; 533 534 switch (imsg->hdr.type) { 535 case IMSG_CTL_SHOW_NEIGHBOR: 536 p = imsg->data; 537 s = fmt_peer(p->conf.descr, &p->conf.remote_addr, 538 p->conf.remote_masklen, nodescr); 539 540 a = log_as(p->conf.remote_as); 541 alen = strlen(a); 542 /* max displayed length of the peers name is 28 */ 543 if (alen < 28) { 544 if (strlen(s) > 28 - alen) 545 s[28 - alen] = 0; 546 } else 547 alen = 0; 548 549 printf("%-*s %s %10llu %10llu %5u %-8s ", 550 (28 - (int)alen), s, a, 551 p->stats.msg_rcvd_open + p->stats.msg_rcvd_notification + 552 p->stats.msg_rcvd_update + p->stats.msg_rcvd_keepalive + 553 p->stats.msg_rcvd_rrefresh, 554 p->stats.msg_sent_open + p->stats.msg_sent_notification + 555 p->stats.msg_sent_update + p->stats.msg_sent_keepalive + 556 p->stats.msg_sent_rrefresh, 557 p->wbuf.queued, 558 fmt_timeframe(p->stats.last_updown)); 559 if (p->state == STATE_ESTABLISHED) { 560 printf("%6u", p->stats.prefix_cnt); 561 if (p->conf.max_prefix != 0) 562 printf("/%u", p->conf.max_prefix); 563 } else if (p->conf.template) 564 printf("Template"); 565 else 566 printf("%s", statenames[p->state]); 567 printf("\n"); 568 free(s); 569 break; 570 case IMSG_CTL_END: 571 return (1); 572 default: 573 break; 574 } 575 576 return (0); 577 } 578 579 int 580 show_summary_terse_msg(struct imsg *imsg, int nodescr) 581 { 582 struct peer *p; 583 char *s; 584 585 switch (imsg->hdr.type) { 586 case IMSG_CTL_SHOW_NEIGHBOR: 587 p = imsg->data; 588 s = fmt_peer(p->conf.descr, &p->conf.remote_addr, 589 p->conf.remote_masklen, nodescr); 590 printf("%s %s %s\n", s, log_as(p->conf.remote_as), 591 p->conf.template ? "Template" : statenames[p->state]); 592 free(s); 593 break; 594 case IMSG_CTL_END: 595 return (1); 596 default: 597 break; 598 } 599 600 return (0); 601 } 602 603 int 604 show_neighbor_terse(struct imsg *imsg) 605 { 606 struct peer *p; 607 608 switch (imsg->hdr.type) { 609 case IMSG_CTL_SHOW_NEIGHBOR: 610 p = imsg->data; 611 printf("%llu %llu %llu %llu %llu %llu %llu " 612 "%llu %llu %llu %u %u %llu %llu %llu %llu\n", 613 p->stats.msg_sent_open, p->stats.msg_rcvd_open, 614 p->stats.msg_sent_notification, 615 p->stats.msg_rcvd_notification, 616 p->stats.msg_sent_update, p->stats.msg_rcvd_update, 617 p->stats.msg_sent_keepalive, p->stats.msg_rcvd_keepalive, 618 p->stats.msg_sent_rrefresh, p->stats.msg_rcvd_rrefresh, 619 p->stats.prefix_cnt, p->conf.max_prefix, 620 p->stats.prefix_sent_update, p->stats.prefix_rcvd_update, 621 p->stats.prefix_sent_withdraw, 622 p->stats.prefix_rcvd_withdraw); 623 break; 624 case IMSG_CTL_END: 625 return (1); 626 default: 627 break; 628 } 629 630 return (0); 631 } 632 633 const char * 634 print_auth_method(enum auth_method method) 635 { 636 switch (method) { 637 case AUTH_MD5SIG: 638 return ", using md5sig"; 639 case AUTH_IPSEC_MANUAL_ESP: 640 return ", using ipsec manual esp"; 641 case AUTH_IPSEC_MANUAL_AH: 642 return ", using ipsec manual ah"; 643 case AUTH_IPSEC_IKE_ESP: 644 return ", using ipsec ike esp"; 645 case AUTH_IPSEC_IKE_AH: 646 return ", using ipsec ike ah"; 647 case AUTH_NONE: /* FALLTHROUGH */ 648 default: 649 return ""; 650 } 651 } 652 653 int 654 show_neighbor_msg(struct imsg *imsg, enum neighbor_views nv) 655 { 656 struct peer *p; 657 struct ctl_timer *t; 658 struct in_addr ina; 659 char *s; 660 int hascapamp = 0; 661 u_int8_t i; 662 663 switch (imsg->hdr.type) { 664 case IMSG_CTL_SHOW_NEIGHBOR: 665 p = imsg->data; 666 if ((p->conf.remote_addr.aid == AID_INET && 667 p->conf.remote_masklen != 32) || 668 (p->conf.remote_addr.aid == AID_INET6 && 669 p->conf.remote_masklen != 128)) { 670 if (asprintf(&s, "%s/%u", 671 log_addr(&p->conf.remote_addr), 672 p->conf.remote_masklen) == -1) 673 err(1, NULL); 674 } else 675 if ((s = strdup(log_addr(&p->conf.remote_addr))) == 676 NULL) 677 err(1, "strdup"); 678 679 ina.s_addr = p->remote_bgpid; 680 printf("BGP neighbor is %s, ", s); 681 free(s); 682 if (p->conf.remote_as == 0 && p->conf.template) 683 printf("remote AS: accept any"); 684 else 685 printf("remote AS %s", log_as(p->conf.remote_as)); 686 if (p->conf.template) 687 printf(", Template"); 688 if (p->template) 689 printf(", Cloned"); 690 if (p->conf.passive) 691 printf(", Passive"); 692 if (p->conf.ebgp && p->conf.distance > 1) 693 printf(", Multihop (%u)", (int)p->conf.distance); 694 printf("\n"); 695 if (p->conf.descr[0]) 696 printf(" Description: %s\n", p->conf.descr); 697 if (p->conf.max_prefix) { 698 printf(" Max-prefix: %u", p->conf.max_prefix); 699 if (p->conf.max_prefix_restart) 700 printf(" (restart %u)", 701 p->conf.max_prefix_restart); 702 printf("\n"); 703 } 704 printf(" BGP version 4, remote router-id %s", 705 inet_ntoa(ina)); 706 printf("%s\n", print_auth_method(p->auth.method)); 707 printf(" BGP state = %s", statenames[p->state]); 708 if (p->conf.down) { 709 printf(", marked down"); 710 if (*(p->conf.shutcomm)) { 711 printf(" with shutdown reason \"%s\"", 712 log_shutcomm(p->conf.shutcomm)); 713 } 714 } 715 if (p->stats.last_updown != 0) 716 printf(", %s for %s", 717 p->state == STATE_ESTABLISHED ? "up" : "down", 718 fmt_timeframe(p->stats.last_updown)); 719 printf("\n"); 720 printf(" Last read %s, holdtime %us, keepalive interval %us\n", 721 fmt_timeframe(p->stats.last_read), 722 p->holdtime, p->holdtime/3); 723 for (i = 0; i < AID_MAX; i++) 724 if (p->capa.peer.mp[i]) 725 hascapamp = 1; 726 if (hascapamp || p->capa.peer.refresh || 727 p->capa.peer.grestart.restart || p->capa.peer.as4byte) { 728 printf(" Neighbor capabilities:\n"); 729 if (hascapamp) { 730 printf(" Multiprotocol extensions: "); 731 print_neighbor_capa_mp(p); 732 printf("\n"); 733 } 734 if (p->capa.peer.refresh) 735 printf(" Route Refresh\n"); 736 if (p->capa.peer.grestart.restart) { 737 printf(" Graceful Restart"); 738 print_neighbor_capa_restart(p); 739 printf("\n"); 740 } 741 if (p->capa.peer.as4byte) 742 printf(" 4-byte AS numbers\n"); 743 } 744 printf("\n"); 745 if (nv == NV_TIMERS) 746 break; 747 print_neighbor_msgstats(p); 748 printf("\n"); 749 if (*(p->stats.last_shutcomm)) { 750 printf(" Last received shutdown reason: \"%s\"\n", 751 log_shutcomm(p->stats.last_shutcomm)); 752 } 753 if (p->state == STATE_IDLE) { 754 static const char *errstr; 755 756 errstr = get_errstr(p->stats.last_sent_errcode, 757 p->stats.last_sent_suberr); 758 if (errstr) 759 printf(" Last error: %s\n\n", errstr); 760 } else { 761 printf(" Local host: %20s, Local port: %5u\n", 762 log_addr(&p->local), p->local_port); 763 764 printf(" Remote host: %20s, Remote port: %5u\n", 765 log_addr(&p->remote), p->remote_port); 766 printf("\n"); 767 } 768 break; 769 case IMSG_CTL_SHOW_TIMER: 770 t = imsg->data; 771 if (t->type > 0 && t->type < Timer_Max) 772 print_timer(timernames[t->type], t->val); 773 break; 774 case IMSG_CTL_END: 775 return (1); 776 break; 777 default: 778 break; 779 } 780 781 return (0); 782 } 783 784 void 785 print_neighbor_capa_mp(struct peer *p) 786 { 787 int comma; 788 u_int8_t i; 789 790 for (i = 0, comma = 0; i < AID_MAX; i++) 791 if (p->capa.peer.mp[i]) { 792 printf("%s%s", comma ? ", " : "", aid2str(i)); 793 comma = 1; 794 } 795 } 796 797 void 798 print_neighbor_capa_restart(struct peer *p) 799 { 800 int comma; 801 u_int8_t i; 802 803 if (p->capa.peer.grestart.timeout) 804 printf(": Timeout: %d, ", p->capa.peer.grestart.timeout); 805 for (i = 0, comma = 0; i < AID_MAX; i++) 806 if (p->capa.peer.grestart.flags[i] & CAPA_GR_PRESENT) { 807 if (!comma && 808 p->capa.peer.grestart.flags[i] & CAPA_GR_RESTART) 809 printf("restarted, "); 810 if (comma) 811 printf(", "); 812 printf("%s", aid2str(i)); 813 if (p->capa.peer.grestart.flags[i] & CAPA_GR_FORWARD) 814 printf(" (preserved)"); 815 comma = 1; 816 } 817 } 818 819 void 820 print_neighbor_msgstats(struct peer *p) 821 { 822 printf(" Message statistics:\n"); 823 printf(" %-15s %-10s %-10s\n", "", "Sent", "Received"); 824 printf(" %-15s %10llu %10llu\n", "Opens", 825 p->stats.msg_sent_open, p->stats.msg_rcvd_open); 826 printf(" %-15s %10llu %10llu\n", "Notifications", 827 p->stats.msg_sent_notification, p->stats.msg_rcvd_notification); 828 printf(" %-15s %10llu %10llu\n", "Updates", 829 p->stats.msg_sent_update, p->stats.msg_rcvd_update); 830 printf(" %-15s %10llu %10llu\n", "Keepalives", 831 p->stats.msg_sent_keepalive, p->stats.msg_rcvd_keepalive); 832 printf(" %-15s %10llu %10llu\n", "Route Refresh", 833 p->stats.msg_sent_rrefresh, p->stats.msg_rcvd_rrefresh); 834 printf(" %-15s %10llu %10llu\n\n", "Total", 835 p->stats.msg_sent_open + p->stats.msg_sent_notification + 836 p->stats.msg_sent_update + p->stats.msg_sent_keepalive + 837 p->stats.msg_sent_rrefresh, 838 p->stats.msg_rcvd_open + p->stats.msg_rcvd_notification + 839 p->stats.msg_rcvd_update + p->stats.msg_rcvd_keepalive + 840 p->stats.msg_rcvd_rrefresh); 841 printf(" Update statistics:\n"); 842 printf(" %-15s %-10s %-10s\n", "", "Sent", "Received"); 843 printf(" %-15s %10llu %10llu\n", "Updates", 844 p->stats.prefix_sent_update, p->stats.prefix_rcvd_update); 845 printf(" %-15s %10llu %10llu\n", "Withdraws", 846 p->stats.prefix_sent_withdraw, p->stats.prefix_rcvd_withdraw); 847 printf(" %-15s %10llu %10llu\n", "End-of-Rib", 848 p->stats.prefix_sent_eor, p->stats.prefix_rcvd_eor); 849 } 850 851 void 852 print_timer(const char *name, time_t d) 853 { 854 printf(" %-20s ", name); 855 856 if (d <= 0) 857 printf("%-20s\n", "due"); 858 else 859 printf("due in %-13s\n", fmt_timeframe_core(d)); 860 } 861 862 #define TF_BUFS 8 863 #define TF_LEN 9 864 865 static char * 866 fmt_timeframe(time_t t) 867 { 868 if (t == 0) 869 return ("Never"); 870 else 871 return (fmt_timeframe_core(time(NULL) - t)); 872 } 873 874 static char * 875 fmt_timeframe_core(time_t t) 876 { 877 char *buf; 878 static char tfbuf[TF_BUFS][TF_LEN]; /* ring buffer */ 879 static int idx = 0; 880 unsigned int sec, min, hrs, day; 881 unsigned long long week; 882 883 buf = tfbuf[idx++]; 884 if (idx == TF_BUFS) 885 idx = 0; 886 887 week = t; 888 889 sec = week % 60; 890 week /= 60; 891 min = week % 60; 892 week /= 60; 893 hrs = week % 24; 894 week /= 24; 895 day = week % 7; 896 week /= 7; 897 898 if (week > 0) 899 snprintf(buf, TF_LEN, "%02lluw%01ud%02uh", week, day, hrs); 900 else if (day > 0) 901 snprintf(buf, TF_LEN, "%01ud%02uh%02um", day, hrs, min); 902 else 903 snprintf(buf, TF_LEN, "%02u:%02u:%02u", hrs, min, sec); 904 905 return (buf); 906 } 907 908 void 909 show_fib_head(void) 910 { 911 printf("flags: " 912 "* = valid, B = BGP, C = Connected, S = Static, D = Dynamic\n"); 913 printf(" " 914 "N = BGP Nexthop reachable via this route\n"); 915 printf(" r = reject route, b = blackhole route\n\n"); 916 printf("flags prio destination gateway\n"); 917 } 918 919 void 920 show_fib_tables_head(void) 921 { 922 printf("%-5s %-20s %-8s\n", "Table", "Description", "State"); 923 } 924 925 void 926 show_network_head(void) 927 { 928 printf("flags: S = Static\n"); 929 printf("flags prio destination gateway\n"); 930 } 931 932 void 933 show_fib_flags(u_int16_t flags) 934 { 935 if (flags & F_DOWN) 936 printf(" "); 937 else 938 printf("*"); 939 940 if (flags & F_BGPD_INSERTED) 941 printf("B"); 942 else if (flags & F_CONNECTED) 943 printf("C"); 944 else if (flags & F_STATIC) 945 printf("S"); 946 else if (flags & F_DYNAMIC) 947 printf("D"); 948 else 949 printf(" "); 950 951 if (flags & F_NEXTHOP) 952 printf("N"); 953 else 954 printf(" "); 955 956 if (flags & F_REJECT && flags & F_BLACKHOLE) 957 printf("f"); 958 else if (flags & F_REJECT) 959 printf("r"); 960 else if (flags & F_BLACKHOLE) 961 printf("b"); 962 else 963 printf(" "); 964 965 printf(" "); 966 } 967 968 int 969 show_fib_msg(struct imsg *imsg) 970 { 971 struct kroute_full *kf; 972 struct ktable *kt; 973 char *p; 974 975 switch (imsg->hdr.type) { 976 case IMSG_CTL_KROUTE: 977 case IMSG_CTL_SHOW_NETWORK: 978 if (imsg->hdr.len < IMSG_HEADER_SIZE + sizeof(*kf)) 979 errx(1, "wrong imsg len"); 980 kf = imsg->data; 981 982 show_fib_flags(kf->flags); 983 984 if (asprintf(&p, "%s/%u", log_addr(&kf->prefix), 985 kf->prefixlen) == -1) 986 err(1, NULL); 987 printf("%4i %-20s ", kf->priority, p); 988 free(p); 989 990 if (kf->flags & F_CONNECTED) 991 printf("link#%u", kf->ifindex); 992 else 993 printf("%s", log_addr(&kf->nexthop)); 994 printf("\n"); 995 996 break; 997 case IMSG_CTL_SHOW_FIB_TABLES: 998 if (imsg->hdr.len < IMSG_HEADER_SIZE + sizeof(*kt)) 999 errx(1, "wrong imsg len"); 1000 kt = imsg->data; 1001 1002 printf("%5i %-20s %-8s%s\n", kt->rtableid, kt->descr, 1003 kt->fib_sync ? "coupled" : "decoupled", 1004 kt->fib_sync != kt->fib_conf ? "*" : ""); 1005 1006 break; 1007 case IMSG_CTL_END: 1008 return (1); 1009 default: 1010 break; 1011 } 1012 1013 return (0); 1014 } 1015 1016 void 1017 show_nexthop_head(void) 1018 { 1019 printf("Flags: * = nexthop valid\n"); 1020 printf("\n %-15s %-19s%-4s %-15s %-20s\n", "Nexthop", "Route", 1021 "Prio", "Gateway", "Iface"); 1022 } 1023 1024 int 1025 show_nexthop_msg(struct imsg *imsg) 1026 { 1027 struct ctl_show_nexthop *p; 1028 struct kroute *k; 1029 struct kroute6 *k6; 1030 char *s; 1031 1032 switch (imsg->hdr.type) { 1033 case IMSG_CTL_SHOW_NEXTHOP: 1034 p = imsg->data; 1035 printf("%s %-15s ", p->valid ? "*" : " ", log_addr(&p->addr)); 1036 if (!p->krvalid) { 1037 printf("\n"); 1038 return (0); 1039 } 1040 switch (p->addr.aid) { 1041 case AID_INET: 1042 k = &p->kr.kr4; 1043 if (asprintf(&s, "%s/%u", inet_ntoa(k->prefix), 1044 k->prefixlen) == -1) 1045 err(1, NULL); 1046 printf("%-20s", s); 1047 free(s); 1048 printf("%3i %-15s ", k->priority, 1049 k->flags & F_CONNECTED ? "connected" : 1050 inet_ntoa(k->nexthop)); 1051 break; 1052 case AID_INET6: 1053 k6 = &p->kr.kr6; 1054 if (asprintf(&s, "%s/%u", log_in6addr(&k6->prefix), 1055 k6->prefixlen) == -1) 1056 err(1, NULL); 1057 printf("%-20s", s); 1058 free(s); 1059 printf("%3i %-15s ", k6->priority, 1060 k6->flags & F_CONNECTED ? "connected" : 1061 log_in6addr(&k6->nexthop)); 1062 break; 1063 default: 1064 printf("unknown address family\n"); 1065 return (0); 1066 } 1067 if (p->iface.ifname[0]) { 1068 printf("%s (%s, %s)", p->iface.ifname, 1069 p->iface.is_up ? "UP" : "DOWN", 1070 p->iface.baudrate ? 1071 get_baudrate(p->iface.baudrate, "bps") : 1072 p->iface.linkstate); 1073 } 1074 printf("\n"); 1075 break; 1076 case IMSG_CTL_END: 1077 return (1); 1078 break; 1079 default: 1080 break; 1081 } 1082 1083 return (0); 1084 } 1085 1086 1087 void 1088 show_interface_head(void) 1089 { 1090 printf("%-15s%-9s%-9s%-7s%s\n", "Interface", "rdomain", "Nexthop", "Flags", 1091 "Link state"); 1092 } 1093 1094 int 1095 show_interface_msg(struct imsg *imsg) 1096 { 1097 struct ctl_show_interface *iface; 1098 1099 switch (imsg->hdr.type) { 1100 case IMSG_CTL_SHOW_INTERFACE: 1101 iface = imsg->data; 1102 printf("%-15s", iface->ifname); 1103 printf("%-9u", iface->rdomain); 1104 printf("%-9s", iface->nh_reachable ? "ok" : "invalid"); 1105 printf("%-7s", iface->is_up ? "UP" : ""); 1106 1107 if (iface->media[0]) 1108 printf("%s, ", iface->media); 1109 printf("%s", iface->linkstate); 1110 1111 if (iface->baudrate > 0) 1112 printf(", %s", get_baudrate(iface->baudrate, "Bit/s")); 1113 printf("\n"); 1114 break; 1115 case IMSG_CTL_END: 1116 return (1); 1117 break; 1118 default: 1119 break; 1120 } 1121 1122 return (0); 1123 } 1124 1125 void 1126 show_rib_summary_head(void) 1127 { 1128 printf("flags: * = Valid, > = Selected, I = via IBGP, A = Announced,\n" 1129 " S = Stale, E = Error\n"); 1130 printf("origin validation state: N = not-found, V = valid, ! = invalid\n"); 1131 printf("origin: i = IGP, e = EGP, ? = Incomplete\n\n"); 1132 printf("%-5s %3s %-20s %-15s %5s %5s %s\n", "flags", "ovs", "destination", 1133 "gateway", "lpref", "med", "aspath origin"); 1134 } 1135 1136 void 1137 print_prefix(struct bgpd_addr *prefix, u_int8_t prefixlen, u_int8_t flags, 1138 u_int8_t ovs) 1139 { 1140 char *p; 1141 1142 print_flags(flags, 1); 1143 printf("%3s ", print_ovs(ovs, 1)); 1144 if (asprintf(&p, "%s/%u", log_addr(prefix), prefixlen) == -1) 1145 err(1, NULL); 1146 printf("%-20s", p); 1147 free(p); 1148 } 1149 1150 const char * 1151 print_origin(u_int8_t origin, int sum) 1152 { 1153 switch (origin) { 1154 case ORIGIN_IGP: 1155 return (sum ? "i" : "IGP"); 1156 case ORIGIN_EGP: 1157 return (sum ? "e" : "EGP"); 1158 case ORIGIN_INCOMPLETE: 1159 return (sum ? "?" : "incomplete"); 1160 default: 1161 return (sum ? "X" : "bad origin"); 1162 } 1163 } 1164 1165 void 1166 print_flags(u_int8_t flags, int sum) 1167 { 1168 char flagstr[5]; 1169 char *p = flagstr; 1170 1171 if (sum) { 1172 if (flags & F_PREF_INVALID) 1173 *p++ = 'E'; 1174 if (flags & F_PREF_ANNOUNCE) 1175 *p++ = 'A'; 1176 if (flags & F_PREF_INTERNAL) 1177 *p++ = 'I'; 1178 if (flags & F_PREF_STALE) 1179 *p++ = 'S'; 1180 if (flags & F_PREF_ELIGIBLE) 1181 *p++ = '*'; 1182 if (flags & F_PREF_ACTIVE) 1183 *p++ = '>'; 1184 *p = '\0'; 1185 printf("%-5s ", flagstr); 1186 } else { 1187 if (flags & F_PREF_INTERNAL) 1188 printf("internal"); 1189 else 1190 printf("external"); 1191 if (flags & F_PREF_STALE) 1192 printf(", stale"); 1193 if (flags & F_PREF_ELIGIBLE) 1194 printf(", valid"); 1195 if (flags & F_PREF_ACTIVE) 1196 printf(", best"); 1197 if (flags & F_PREF_ANNOUNCE) 1198 printf(", announced"); 1199 } 1200 } 1201 1202 const char * 1203 print_ovs(u_int8_t validation_state, int sum) 1204 { 1205 switch (validation_state) { 1206 case ROA_INVALID: 1207 return (sum ? "!" : "invalid"); 1208 case ROA_VALID: 1209 return (sum ? "V" : "valid"); 1210 default: 1211 return (sum ? "N" : "not-found"); 1212 } 1213 } 1214 1215 int 1216 show_rib_summary_msg(struct imsg *imsg) 1217 { 1218 struct ctl_show_rib rib; 1219 u_char *asdata; 1220 1221 switch (imsg->hdr.type) { 1222 case IMSG_CTL_SHOW_RIB: 1223 memcpy(&rib, imsg->data, sizeof(rib)); 1224 asdata = imsg->data; 1225 asdata += sizeof(struct ctl_show_rib); 1226 show_rib_brief(&rib, asdata); 1227 break; 1228 case IMSG_CTL_END: 1229 return (1); 1230 default: 1231 break; 1232 } 1233 1234 return (0); 1235 } 1236 1237 int 1238 show_rib_detail_msg(struct imsg *imsg, int nodescr, int flag0) 1239 { 1240 struct ctl_show_rib rib; 1241 u_char *asdata; 1242 u_int16_t ilen; 1243 1244 switch (imsg->hdr.type) { 1245 case IMSG_CTL_SHOW_RIB: 1246 memcpy(&rib, imsg->data, sizeof(rib)); 1247 asdata = imsg->data; 1248 asdata += sizeof(struct ctl_show_rib); 1249 show_rib_detail(&rib, asdata, nodescr, flag0); 1250 break; 1251 case IMSG_CTL_SHOW_RIB_ATTR: 1252 ilen = imsg->hdr.len - IMSG_HEADER_SIZE; 1253 if (ilen < 3) 1254 errx(1, "bad IMSG_CTL_SHOW_RIB_ATTR received"); 1255 show_attr(imsg->data, ilen, flag0); 1256 break; 1257 case IMSG_CTL_END: 1258 printf("\n"); 1259 return (1); 1260 default: 1261 break; 1262 } 1263 1264 return (0); 1265 } 1266 1267 void 1268 show_rib_brief(struct ctl_show_rib *r, u_char *asdata) 1269 { 1270 char *aspath; 1271 1272 print_prefix(&r->prefix, r->prefixlen, r->flags, r->validation_state); 1273 printf(" %-15s ", log_addr(&r->exit_nexthop)); 1274 printf(" %5u %5u ", r->local_pref, r->med); 1275 1276 if (aspath_asprint(&aspath, asdata, r->aspath_len) == -1) 1277 err(1, NULL); 1278 if (strlen(aspath) > 0) 1279 printf("%s ", aspath); 1280 free(aspath); 1281 1282 printf("%s\n", print_origin(r->origin, 1)); 1283 } 1284 1285 void 1286 show_rib_detail(struct ctl_show_rib *r, u_char *asdata, int nodescr, int flag0) 1287 { 1288 struct in_addr id; 1289 char *aspath, *s; 1290 time_t now; 1291 1292 printf("\nBGP routing table entry for %s/%u%c", 1293 log_addr(&r->prefix), r->prefixlen, 1294 EOL0(flag0)); 1295 1296 if (aspath_asprint(&aspath, asdata, r->aspath_len) == -1) 1297 err(1, NULL); 1298 if (strlen(aspath) > 0) 1299 printf(" %s%c", aspath, EOL0(flag0)); 1300 free(aspath); 1301 1302 s = fmt_peer(r->descr, &r->remote_addr, -1, nodescr); 1303 printf(" Nexthop %s ", log_addr(&r->exit_nexthop)); 1304 printf("(via %s) from %s (", log_addr(&r->true_nexthop), s); 1305 free(s); 1306 id.s_addr = htonl(r->remote_id); 1307 printf("%s)%c", inet_ntoa(id), EOL0(flag0)); 1308 1309 printf(" Origin %s, metric %u, localpref %u, weight %u, ovs %s, ", 1310 print_origin(r->origin, 0), r->med, r->local_pref, r->weight, 1311 print_ovs(r->validation_state, 0)); 1312 print_flags(r->flags, 0); 1313 1314 now = time(NULL); 1315 if (now > r->lastchange) 1316 now -= r->lastchange; 1317 else 1318 now = 0; 1319 1320 printf("%c Last update: %s ago%c", EOL0(flag0), 1321 fmt_timeframe_core(now), EOL0(flag0)); 1322 } 1323 1324 static const char * 1325 print_attr(u_int8_t type, u_int8_t flags) 1326 { 1327 #define CHECK_FLAGS(s, t, m) \ 1328 if (((s) & ~(ATTR_DEFMASK | (m))) != (t)) pflags = 1 1329 1330 static char cstr[48]; 1331 int pflags = 0; 1332 1333 switch (type) { 1334 case ATTR_ORIGIN: 1335 CHECK_FLAGS(flags, ATTR_WELL_KNOWN, 0); 1336 strlcpy(cstr, "Origin", sizeof(cstr)); 1337 break; 1338 case ATTR_ASPATH: 1339 CHECK_FLAGS(flags, ATTR_WELL_KNOWN, 0); 1340 strlcpy(cstr, "AS-Path", sizeof(cstr)); 1341 break; 1342 case ATTR_AS4_PATH: 1343 CHECK_FLAGS(flags, ATTR_WELL_KNOWN, 0); 1344 strlcpy(cstr, "AS4-Path", sizeof(cstr)); 1345 break; 1346 case ATTR_NEXTHOP: 1347 CHECK_FLAGS(flags, ATTR_WELL_KNOWN, 0); 1348 strlcpy(cstr, "Nexthop", sizeof(cstr)); 1349 break; 1350 case ATTR_MED: 1351 CHECK_FLAGS(flags, ATTR_OPTIONAL, 0); 1352 strlcpy(cstr, "Med", sizeof(cstr)); 1353 break; 1354 case ATTR_LOCALPREF: 1355 CHECK_FLAGS(flags, ATTR_WELL_KNOWN, 0); 1356 strlcpy(cstr, "Localpref", sizeof(cstr)); 1357 break; 1358 case ATTR_ATOMIC_AGGREGATE: 1359 CHECK_FLAGS(flags, ATTR_WELL_KNOWN, 0); 1360 strlcpy(cstr, "Atomic Aggregate", sizeof(cstr)); 1361 break; 1362 case ATTR_AGGREGATOR: 1363 CHECK_FLAGS(flags, ATTR_OPTIONAL|ATTR_TRANSITIVE, ATTR_PARTIAL); 1364 strlcpy(cstr, "Aggregator", sizeof(cstr)); 1365 break; 1366 case ATTR_AS4_AGGREGATOR: 1367 CHECK_FLAGS(flags, ATTR_OPTIONAL|ATTR_TRANSITIVE, ATTR_PARTIAL); 1368 strlcpy(cstr, "AS4-Aggregator", sizeof(cstr)); 1369 break; 1370 case ATTR_COMMUNITIES: 1371 CHECK_FLAGS(flags, ATTR_OPTIONAL|ATTR_TRANSITIVE, ATTR_PARTIAL); 1372 strlcpy(cstr, "Communities", sizeof(cstr)); 1373 break; 1374 case ATTR_ORIGINATOR_ID: 1375 CHECK_FLAGS(flags, ATTR_OPTIONAL, 0); 1376 strlcpy(cstr, "Originator Id", sizeof(cstr)); 1377 break; 1378 case ATTR_CLUSTER_LIST: 1379 CHECK_FLAGS(flags, ATTR_OPTIONAL, 0); 1380 strlcpy(cstr, "Cluster Id List", sizeof(cstr)); 1381 break; 1382 case ATTR_MP_REACH_NLRI: 1383 CHECK_FLAGS(flags, ATTR_OPTIONAL, 0); 1384 strlcpy(cstr, "MP Reach NLRI", sizeof(cstr)); 1385 break; 1386 case ATTR_MP_UNREACH_NLRI: 1387 CHECK_FLAGS(flags, ATTR_OPTIONAL, 0); 1388 strlcpy(cstr, "MP Unreach NLRI", sizeof(cstr)); 1389 break; 1390 case ATTR_EXT_COMMUNITIES: 1391 CHECK_FLAGS(flags, ATTR_OPTIONAL|ATTR_TRANSITIVE, ATTR_PARTIAL); 1392 strlcpy(cstr, "Ext. Communities", sizeof(cstr)); 1393 break; 1394 case ATTR_LARGE_COMMUNITIES: 1395 CHECK_FLAGS(flags, ATTR_OPTIONAL|ATTR_TRANSITIVE, ATTR_PARTIAL); 1396 strlcpy(cstr, "Large Communities", sizeof(cstr)); 1397 break; 1398 default: 1399 /* ignore unknown attributes */ 1400 snprintf(cstr, sizeof(cstr), "Unknown Attribute #%u", type); 1401 pflags = 1; 1402 break; 1403 } 1404 if (pflags) { 1405 strlcat(cstr, " flags [", sizeof(cstr)); 1406 if (flags & ATTR_OPTIONAL) 1407 strlcat(cstr, "O", sizeof(cstr)); 1408 if (flags & ATTR_TRANSITIVE) 1409 strlcat(cstr, "T", sizeof(cstr)); 1410 if (flags & ATTR_PARTIAL) 1411 strlcat(cstr, "P", sizeof(cstr)); 1412 strlcat(cstr, "]", sizeof(cstr)); 1413 } 1414 return (cstr); 1415 1416 #undef CHECK_FLAGS 1417 } 1418 1419 void 1420 show_attr(void *b, u_int16_t len, int flag0) 1421 { 1422 u_char *data = b, *path; 1423 struct in_addr id; 1424 struct bgpd_addr prefix; 1425 char *aspath; 1426 u_int32_t as; 1427 u_int16_t alen, ioff, short_as, afi; 1428 u_int8_t flags, type, safi, aid, prefixlen; 1429 int i, pos, e2, e4; 1430 1431 if (len < 3) 1432 errx(1, "show_attr: too short bgp attr"); 1433 1434 flags = data[0]; 1435 type = data[1]; 1436 1437 /* get the attribute length */ 1438 if (flags & ATTR_EXTLEN) { 1439 if (len < 4) 1440 errx(1, "show_attr: too short bgp attr"); 1441 memcpy(&alen, data+2, sizeof(u_int16_t)); 1442 alen = ntohs(alen); 1443 data += 4; 1444 len -= 4; 1445 } else { 1446 alen = (u_char)data[2]; 1447 data += 3; 1448 len -= 3; 1449 } 1450 1451 /* bad imsg len how can that happen!? */ 1452 if (alen > len) 1453 errx(1, "show_attr: bad length"); 1454 1455 printf(" %s: ", print_attr(type, flags)); 1456 1457 switch (type) { 1458 case ATTR_ORIGIN: 1459 if (alen == 1) 1460 printf("%u", *data); 1461 else 1462 printf("bad length"); 1463 break; 1464 case ATTR_ASPATH: 1465 case ATTR_AS4_PATH: 1466 /* prefer 4-byte AS here */ 1467 e4 = aspath_verify(data, alen, 1); 1468 e2 = aspath_verify(data, alen, 0); 1469 if (e4 == 0 || e4 == AS_ERR_SOFT) { 1470 path = data; 1471 } else if (e2 == 0 || e2 == AS_ERR_SOFT) { 1472 path = aspath_inflate(data, alen, &alen); 1473 if (path == NULL) 1474 errx(1, "aspath_inflate failed"); 1475 } else { 1476 printf("bad AS-Path"); 1477 break; 1478 } 1479 if (aspath_asprint(&aspath, path, alen) == -1) 1480 err(1, NULL); 1481 printf("%s", aspath); 1482 free(aspath); 1483 if (path != data) 1484 free(path); 1485 break; 1486 case ATTR_NEXTHOP: 1487 if (alen == 4) { 1488 memcpy(&id, data, sizeof(id)); 1489 printf("%s", inet_ntoa(id)); 1490 } else 1491 printf("bad length"); 1492 break; 1493 case ATTR_MED: 1494 case ATTR_LOCALPREF: 1495 if (alen == 4) { 1496 u_int32_t val; 1497 memcpy(&val, data, sizeof(val)); 1498 val = ntohl(val); 1499 printf("%u", val); 1500 } else 1501 printf("bad length"); 1502 break; 1503 case ATTR_AGGREGATOR: 1504 case ATTR_AS4_AGGREGATOR: 1505 if (alen == 8) { 1506 memcpy(&as, data, sizeof(as)); 1507 memcpy(&id, data + sizeof(as), sizeof(id)); 1508 as = ntohl(as); 1509 } else if (alen == 6) { 1510 memcpy(&short_as, data, sizeof(short_as)); 1511 memcpy(&id, data + sizeof(short_as), sizeof(id)); 1512 as = ntohs(short_as); 1513 } else { 1514 printf("bad length"); 1515 break; 1516 } 1517 printf("%s [%s]", log_as(as), inet_ntoa(id)); 1518 break; 1519 case ATTR_COMMUNITIES: 1520 show_community(data, alen); 1521 break; 1522 case ATTR_ORIGINATOR_ID: 1523 memcpy(&id, data, sizeof(id)); 1524 printf("%s", inet_ntoa(id)); 1525 break; 1526 case ATTR_CLUSTER_LIST: 1527 for (ioff = 0; ioff + sizeof(id) <= alen; 1528 ioff += sizeof(id)) { 1529 memcpy(&id, data + ioff, sizeof(id)); 1530 printf(" %s", inet_ntoa(id)); 1531 } 1532 break; 1533 case ATTR_MP_REACH_NLRI: 1534 case ATTR_MP_UNREACH_NLRI: 1535 if (alen < 3) { 1536 bad_len: 1537 printf("bad length"); 1538 break; 1539 } 1540 memcpy(&afi, data, 2); 1541 data += 2; 1542 alen -= 2; 1543 afi = ntohs(afi); 1544 safi = *data++; 1545 alen--; 1546 1547 if (afi2aid(afi, safi, &aid) == -1) { 1548 printf("bad AFI/SAFI pair"); 1549 break; 1550 } 1551 printf(" %s", aid2str(aid)); 1552 1553 if (type == ATTR_MP_REACH_NLRI) { 1554 struct bgpd_addr nexthop; 1555 u_int8_t nhlen; 1556 if (len == 0) 1557 goto bad_len; 1558 nhlen = *data++; 1559 alen--; 1560 if (nhlen > len) 1561 goto bad_len; 1562 bzero(&nexthop, sizeof(nexthop)); 1563 switch (aid) { 1564 case AID_INET6: 1565 nexthop.aid = aid; 1566 if (nhlen != 16 && nhlen != 32) 1567 goto bad_len; 1568 memcpy(&nexthop.v6.s6_addr, data, 16); 1569 break; 1570 case AID_VPN_IPv4: 1571 if (nhlen != 12) 1572 goto bad_len; 1573 nexthop.aid = AID_INET; 1574 memcpy(&nexthop.v4, data + sizeof(u_int64_t), 1575 sizeof(nexthop.v4)); 1576 break; 1577 default: 1578 printf("unhandled AID #%u", aid); 1579 goto done; 1580 } 1581 /* ignore reserved (old SNPA) field as per RFC4760 */ 1582 data += nhlen + 1; 1583 alen -= nhlen + 1; 1584 1585 printf(" nexthop: %s", log_addr(&nexthop)); 1586 } 1587 1588 while (alen > 0) { 1589 switch (aid) { 1590 case AID_INET6: 1591 pos = nlri_get_prefix6(data, alen, &prefix, 1592 &prefixlen); 1593 break; 1594 case AID_VPN_IPv4: 1595 pos = nlri_get_vpn4(data, alen, &prefix, 1596 &prefixlen, 1); 1597 break; 1598 default: 1599 printf("unhandled AID #%u", aid); 1600 goto done; 1601 } 1602 if (pos == -1) { 1603 printf("bad %s prefix", aid2str(aid)); 1604 break; 1605 } 1606 printf(" %s/%u", log_addr(&prefix), prefixlen); 1607 data += pos; 1608 alen -= pos; 1609 } 1610 break; 1611 case ATTR_EXT_COMMUNITIES: 1612 show_ext_community(data, alen); 1613 break; 1614 case ATTR_LARGE_COMMUNITIES: 1615 show_large_community(data, alen); 1616 break; 1617 case ATTR_ATOMIC_AGGREGATE: 1618 default: 1619 printf(" len %u", alen); 1620 if (alen) { 1621 printf(":"); 1622 for (i=0; i < alen; i++) 1623 printf(" %02x", *(data+i)); 1624 } 1625 break; 1626 } 1627 done: 1628 printf("%c", EOL0(flag0)); 1629 } 1630 1631 void 1632 show_community(u_char *data, u_int16_t len) 1633 { 1634 u_int16_t a, v; 1635 u_int16_t i; 1636 1637 if (len & 0x3) 1638 return; 1639 1640 for (i = 0; i < len; i += 4) { 1641 memcpy(&a, data + i, sizeof(a)); 1642 memcpy(&v, data + i + 2, sizeof(v)); 1643 a = ntohs(a); 1644 v = ntohs(v); 1645 if (a == COMMUNITY_WELLKNOWN) 1646 switch (v) { 1647 case COMMUNITY_GRACEFUL_SHUTDOWN: 1648 printf("GRACEFUL_SHUTDOWN"); 1649 break; 1650 case COMMUNITY_NO_EXPORT: 1651 printf("NO_EXPORT"); 1652 break; 1653 case COMMUNITY_NO_ADVERTISE: 1654 printf("NO_ADVERTISE"); 1655 break; 1656 case COMMUNITY_NO_EXPSUBCONFED: 1657 printf("NO_EXPORT_SUBCONFED"); 1658 break; 1659 case COMMUNITY_NO_PEER: 1660 printf("NO_PEER"); 1661 break; 1662 case COMMUNITY_BLACKHOLE: 1663 printf("BLACKHOLE"); 1664 break; 1665 default: 1666 printf("%hu:%hu", a, v); 1667 break; 1668 } 1669 else 1670 printf("%hu:%hu", a, v); 1671 1672 if (i + 4 < len) 1673 printf(" "); 1674 } 1675 } 1676 1677 void 1678 show_large_community(u_char *data, u_int16_t len) 1679 { 1680 u_int32_t a, l1, l2; 1681 u_int16_t i; 1682 1683 if (len % 12) 1684 return; 1685 1686 for (i = 0; i < len; i += 12) { 1687 memcpy(&a, data + i, sizeof(a)); 1688 memcpy(&l1, data + i + 4, sizeof(l1)); 1689 memcpy(&l2, data + i + 8, sizeof(l2)); 1690 a = ntohl(a); 1691 l1 = ntohl(l1); 1692 l2 = ntohl(l2); 1693 printf("%u:%u:%u", a, l1, l2); 1694 1695 if (i + 12 < len) 1696 printf(" "); 1697 } 1698 } 1699 1700 void 1701 show_ext_community(u_char *data, u_int16_t len) 1702 { 1703 u_int64_t ext; 1704 struct in_addr ip; 1705 u_int32_t as4, u32; 1706 u_int16_t i, as2, u16; 1707 u_int8_t type, subtype; 1708 1709 if (len & 0x7) 1710 return; 1711 1712 for (i = 0; i < len; i += 8) { 1713 type = data[i]; 1714 subtype = data[i + 1]; 1715 1716 printf("%s ", log_ext_subtype(type, subtype)); 1717 1718 switch (type) { 1719 case EXT_COMMUNITY_TRANS_TWO_AS: 1720 memcpy(&as2, data + i + 2, sizeof(as2)); 1721 memcpy(&u32, data + i + 4, sizeof(u32)); 1722 printf("%s:%u", log_as(ntohs(as2)), ntohl(u32)); 1723 break; 1724 case EXT_COMMUNITY_TRANS_IPV4: 1725 memcpy(&ip, data + i + 2, sizeof(ip)); 1726 memcpy(&u16, data + i + 6, sizeof(u16)); 1727 printf("%s:%hu", inet_ntoa(ip), ntohs(u16)); 1728 break; 1729 case EXT_COMMUNITY_TRANS_FOUR_AS: 1730 memcpy(&as4, data + i + 2, sizeof(as4)); 1731 memcpy(&u16, data + i + 6, sizeof(u16)); 1732 printf("%s:%hu", log_as(ntohl(as4)), ntohs(u16)); 1733 break; 1734 case EXT_COMMUNITY_TRANS_OPAQUE: 1735 case EXT_COMMUNITY_TRANS_EVPN: 1736 memcpy(&ext, data + i, sizeof(ext)); 1737 ext = be64toh(ext) & 0xffffffffffffLL; 1738 printf("0x%llx", (unsigned long long)ext); 1739 break; 1740 case EXT_COMMUNITY_NON_TRANS_OPAQUE: 1741 memcpy(&ext, data + i, sizeof(ext)); 1742 ext = be64toh(ext) & 0xffffffffffffLL; 1743 switch (ext) { 1744 case EXT_COMMUNITY_OVS_VALID: 1745 printf("valid "); 1746 break; 1747 case EXT_COMMUNITY_OVS_NOTFOUND: 1748 printf("not-found "); 1749 break; 1750 case EXT_COMMUNITY_OVS_INVALID: 1751 printf("invalid "); 1752 break; 1753 default: 1754 printf("0x%llx ", (unsigned long long)ext); 1755 break; 1756 } 1757 break; 1758 default: 1759 memcpy(&ext, data + i, sizeof(ext)); 1760 printf("0x%llx", (unsigned long long)be64toh(ext)); 1761 } 1762 if (i + 8 < len) 1763 printf(", "); 1764 } 1765 } 1766 1767 static char * 1768 fmt_mem(long long num) 1769 { 1770 static char buf[16]; 1771 1772 if (fmt_scaled(num, buf) == -1) 1773 snprintf(buf, sizeof(buf), "%lldB", num); 1774 1775 return (buf); 1776 } 1777 1778 size_t pt_sizes[AID_MAX] = AID_PTSIZE; 1779 1780 int 1781 show_rib_memory_msg(struct imsg *imsg) 1782 { 1783 struct rde_memstats stats; 1784 struct rde_hashstats hash; 1785 size_t pts = 0; 1786 int i; 1787 double avg, dev; 1788 1789 switch (imsg->hdr.type) { 1790 case IMSG_CTL_SHOW_RIB_MEM: 1791 memcpy(&stats, imsg->data, sizeof(stats)); 1792 printf("RDE memory statistics\n"); 1793 for (i = 0; i < AID_MAX; i++) { 1794 if (stats.pt_cnt[i] == 0) 1795 continue; 1796 pts += stats.pt_cnt[i] * pt_sizes[i]; 1797 printf("%10lld %s network entries using %s of memory\n", 1798 stats.pt_cnt[i], aid_vals[i].name, 1799 fmt_mem(stats.pt_cnt[i] * pt_sizes[i])); 1800 } 1801 printf("%10lld rib entries using %s of memory\n", 1802 stats.rib_cnt, fmt_mem(stats.rib_cnt * 1803 sizeof(struct rib_entry))); 1804 printf("%10lld prefix entries using %s of memory\n", 1805 stats.prefix_cnt, fmt_mem(stats.prefix_cnt * 1806 sizeof(struct prefix))); 1807 printf("%10lld BGP path attribute entries using %s of memory\n", 1808 stats.path_cnt, fmt_mem(stats.path_cnt * 1809 sizeof(struct rde_aspath))); 1810 printf("\t and holding %lld references\n", 1811 stats.path_refs); 1812 printf("%10lld BGP AS-PATH attribute entries using " 1813 "%s of memory\n\t and holding %lld references\n", 1814 stats.aspath_cnt, fmt_mem(stats.aspath_size), 1815 stats.aspath_refs); 1816 printf("%10lld BGP attributes entries using %s of memory\n", 1817 stats.attr_cnt, fmt_mem(stats.attr_cnt * 1818 sizeof(struct attr))); 1819 printf("\t and holding %lld references\n", 1820 stats.attr_refs); 1821 printf("%10lld BGP attributes using %s of memory\n", 1822 stats.attr_dcnt, fmt_mem(stats.attr_data)); 1823 printf("%10lld as-set elements in %lld tables using " 1824 "%s of memory\n", stats.aset_nmemb, stats.aset_cnt, 1825 fmt_mem(stats.aset_size)); 1826 printf("%10lld prefix-set elements using %s of memory\n", 1827 stats.pset_cnt, fmt_mem(stats.pset_size)); 1828 printf("RIB using %s of memory\n", fmt_mem(pts + 1829 stats.prefix_cnt * sizeof(struct prefix) + 1830 stats.rib_cnt * sizeof(struct rib_entry) + 1831 stats.path_cnt * sizeof(struct rde_aspath) + 1832 stats.aspath_size + stats.attr_cnt * sizeof(struct attr) + 1833 stats.attr_data)); 1834 printf("Sets using %s of memory\n", fmt_mem(stats.aset_size + 1835 stats.pset_size)); 1836 printf("\nRDE hash statistics\n"); 1837 break; 1838 case IMSG_CTL_SHOW_RIB_HASH: 1839 memcpy(&hash, imsg->data, sizeof(hash)); 1840 printf("\t%s: size %lld, %lld entries\n", hash.name, hash.num, 1841 hash.sum); 1842 avg = (double)hash.sum / (double)hash.num; 1843 dev = sqrt(fmax(0, hash.sumq / hash.num - avg * avg)); 1844 printf("\t min %lld max %lld avg/std-dev = %.3f/%.3f\n", 1845 hash.min, hash.max, avg, dev); 1846 break; 1847 case IMSG_CTL_END: 1848 return (1); 1849 default: 1850 break; 1851 } 1852 1853 return (0); 1854 } 1855 1856 void 1857 send_filterset(struct imsgbuf *i, struct filter_set_head *set) 1858 { 1859 struct filter_set *s; 1860 1861 while ((s = TAILQ_FIRST(set)) != NULL) { 1862 imsg_compose(i, IMSG_FILTER_SET, 0, 0, -1, s, 1863 sizeof(struct filter_set)); 1864 TAILQ_REMOVE(set, s, entry); 1865 free(s); 1866 } 1867 } 1868 1869 const char * 1870 get_errstr(u_int8_t errcode, u_int8_t subcode) 1871 { 1872 static const char *errstr = NULL; 1873 1874 if (errcode && errcode < sizeof(errnames)/sizeof(char *)) 1875 errstr = errnames[errcode]; 1876 1877 switch (errcode) { 1878 case ERR_HEADER: 1879 if (subcode && 1880 subcode < sizeof(suberr_header_names)/sizeof(char *)) 1881 errstr = suberr_header_names[subcode]; 1882 break; 1883 case ERR_OPEN: 1884 if (subcode && 1885 subcode < sizeof(suberr_open_names)/sizeof(char *)) 1886 errstr = suberr_open_names[subcode]; 1887 break; 1888 case ERR_UPDATE: 1889 if (subcode && 1890 subcode < sizeof(suberr_update_names)/sizeof(char *)) 1891 errstr = suberr_update_names[subcode]; 1892 break; 1893 case ERR_HOLDTIMEREXPIRED: 1894 case ERR_FSM: 1895 case ERR_CEASE: 1896 break; 1897 default: 1898 return ("unknown error code"); 1899 } 1900 1901 return (errstr); 1902 } 1903 1904 int 1905 show_result(struct imsg *imsg) 1906 { 1907 u_int rescode; 1908 1909 if (imsg->hdr.len != IMSG_HEADER_SIZE + sizeof(rescode)) 1910 errx(1, "got IMSG_CTL_RESULT with wrong len"); 1911 memcpy(&rescode, imsg->data, sizeof(rescode)); 1912 1913 if (rescode == 0) 1914 printf("request processed\n"); 1915 else { 1916 if (rescode > 1917 sizeof(ctl_res_strerror)/sizeof(ctl_res_strerror[0])) 1918 printf("unknown result error code %u\n", rescode); 1919 else 1920 printf("%s\n", ctl_res_strerror[rescode]); 1921 } 1922 1923 return (1); 1924 } 1925 1926 void 1927 network_bulk(struct parse_result *res) 1928 { 1929 struct network_config net; 1930 struct filter_set *s = NULL; 1931 struct bgpd_addr h; 1932 char *line = NULL; 1933 size_t linesize = 0; 1934 ssize_t linelen; 1935 u_int8_t len; 1936 FILE *f; 1937 1938 if ((f = fdopen(STDIN_FILENO, "r")) == NULL) 1939 err(1, "Failed to open stdin\n"); 1940 1941 while ((linelen = getline(&line, &linesize, f)) != -1) { 1942 char *b, *buf = line; 1943 while ((b = strsep(&buf, " \t\n")) != NULL) { 1944 if (*b == '\0') /* skip empty tokens */ 1945 continue; 1946 /* Stop processing after a comment */ 1947 if (*b == '#') 1948 break; 1949 bzero(&net, sizeof(net)); 1950 if (parse_prefix(b, strlen(b), &h, &len) != 1) 1951 errx(1, "bad prefix: %s", b); 1952 net.prefix = h; 1953 net.prefixlen = len; 1954 net.rd = res->rd; 1955 1956 if (res->action == NETWORK_BULK_ADD) { 1957 imsg_compose(ibuf, IMSG_NETWORK_ADD, 1958 0, 0, -1, &net, sizeof(net)); 1959 TAILQ_FOREACH(s, &res->set, entry) { 1960 imsg_compose(ibuf, 1961 IMSG_FILTER_SET, 1962 0, 0, -1, s, sizeof(*s)); 1963 } 1964 imsg_compose(ibuf, IMSG_NETWORK_DONE, 1965 0, 0, -1, NULL, 0); 1966 } else 1967 imsg_compose(ibuf, IMSG_NETWORK_REMOVE, 1968 0, 0, -1, &net, sizeof(net)); 1969 } 1970 } 1971 free(line); 1972 if (ferror(f)) 1973 err(1, "getline"); 1974 fclose(f); 1975 } 1976 1977 void 1978 show_mrt_dump(struct mrt_rib *mr, struct mrt_peer *mp, void *arg) 1979 { 1980 struct ctl_show_rib ctl; 1981 struct ctl_show_rib_request *req = arg; 1982 struct mrt_rib_entry *mre; 1983 u_int16_t i, j; 1984 1985 for (i = 0; i < mr->nentries; i++) { 1986 mre = &mr->entries[i]; 1987 bzero(&ctl, sizeof(ctl)); 1988 ctl.prefix = mr->prefix; 1989 ctl.prefixlen = mr->prefixlen; 1990 ctl.lastchange = mre->originated; 1991 ctl.true_nexthop = mre->nexthop; 1992 ctl.exit_nexthop = mre->nexthop; 1993 ctl.origin = mre->origin; 1994 ctl.local_pref = mre->local_pref; 1995 ctl.med = mre->med; 1996 /* weight is not part of the mrt dump so it can't be set */ 1997 ctl.aspath_len = mre->aspath_len; 1998 1999 if (mre->peer_idx < mp->npeers) { 2000 ctl.remote_addr = mp->peers[mre->peer_idx].addr; 2001 ctl.remote_id = mp->peers[mre->peer_idx].bgp_id; 2002 } 2003 2004 /* filter by neighbor */ 2005 if (req->neighbor.addr.aid != AID_UNSPEC && 2006 memcmp(&req->neighbor.addr, &ctl.remote_addr, 2007 sizeof(ctl.remote_addr)) != 0) 2008 continue; 2009 /* filter by AF */ 2010 if (req->aid && req->aid != ctl.prefix.aid) 2011 return; 2012 /* filter by prefix */ 2013 if (req->prefix.aid != AID_UNSPEC) { 2014 if (!prefix_compare(&req->prefix, &ctl.prefix, 2015 req->prefixlen)) { 2016 if (req->flags & F_LONGER) { 2017 if (req->prefixlen > ctl.prefixlen) 2018 return; 2019 } else if (req->prefixlen != ctl.prefixlen) 2020 return; 2021 } else 2022 return; 2023 } 2024 /* filter by AS */ 2025 if (req->as.type != AS_UNDEF && 2026 !match_aspath(mre->aspath, mre->aspath_len, &req->as)) 2027 continue; 2028 2029 if (req->flags & F_CTL_DETAIL) { 2030 show_rib_detail(&ctl, mre->aspath, 1, 0); 2031 for (j = 0; j < mre->nattrs; j++) 2032 show_attr(mre->attrs[j].attr, 2033 mre->attrs[j].attr_len, 2034 req->flags); 2035 } else 2036 show_rib_brief(&ctl, mre->aspath); 2037 } 2038 } 2039 2040 void 2041 network_mrt_dump(struct mrt_rib *mr, struct mrt_peer *mp, void *arg) 2042 { 2043 struct ctl_show_rib ctl; 2044 struct network_config net; 2045 struct ctl_show_rib_request *req = arg; 2046 struct mrt_rib_entry *mre; 2047 struct ibuf *msg; 2048 u_int16_t i, j; 2049 2050 for (i = 0; i < mr->nentries; i++) { 2051 mre = &mr->entries[i]; 2052 bzero(&ctl, sizeof(ctl)); 2053 ctl.prefix = mr->prefix; 2054 ctl.prefixlen = mr->prefixlen; 2055 ctl.lastchange = mre->originated; 2056 ctl.true_nexthop = mre->nexthop; 2057 ctl.exit_nexthop = mre->nexthop; 2058 ctl.origin = mre->origin; 2059 ctl.local_pref = mre->local_pref; 2060 ctl.med = mre->med; 2061 ctl.aspath_len = mre->aspath_len; 2062 2063 if (mre->peer_idx < mp->npeers) { 2064 ctl.remote_addr = mp->peers[mre->peer_idx].addr; 2065 ctl.remote_id = mp->peers[mre->peer_idx].bgp_id; 2066 } 2067 2068 /* filter by neighbor */ 2069 if (req->neighbor.addr.aid != AID_UNSPEC && 2070 memcmp(&req->neighbor.addr, &ctl.remote_addr, 2071 sizeof(ctl.remote_addr)) != 0) 2072 continue; 2073 /* filter by AF */ 2074 if (req->aid && req->aid != ctl.prefix.aid) 2075 return; 2076 /* filter by prefix */ 2077 if (req->prefix.aid != AID_UNSPEC) { 2078 if (!prefix_compare(&req->prefix, &ctl.prefix, 2079 req->prefixlen)) { 2080 if (req->flags & F_LONGER) { 2081 if (req->prefixlen > ctl.prefixlen) 2082 return; 2083 } else if (req->prefixlen != ctl.prefixlen) 2084 return; 2085 } else 2086 return; 2087 } 2088 /* filter by AS */ 2089 if (req->as.type != AS_UNDEF && 2090 !match_aspath(mre->aspath, mre->aspath_len, &req->as)) 2091 continue; 2092 2093 bzero(&net, sizeof(net)); 2094 net.prefix = ctl.prefix; 2095 net.prefixlen = ctl.prefixlen; 2096 net.type = NETWORK_MRTCLONE; 2097 /* XXX rd can't be set and will be 0 */ 2098 2099 imsg_compose(ibuf, IMSG_NETWORK_ADD, 0, 0, -1, 2100 &net, sizeof(net)); 2101 if ((msg = imsg_create(ibuf, IMSG_NETWORK_ASPATH, 2102 0, 0, sizeof(ctl) + mre->aspath_len)) == NULL) 2103 errx(1, "imsg_create failure"); 2104 if (imsg_add(msg, &ctl, sizeof(ctl)) == -1 || 2105 imsg_add(msg, mre->aspath, mre->aspath_len) == -1) 2106 errx(1, "imsg_add failure"); 2107 imsg_close(ibuf, msg); 2108 for (j = 0; j < mre->nattrs; j++) 2109 imsg_compose(ibuf, IMSG_NETWORK_ATTR, 0, 0, -1, 2110 mre->attrs[j].attr, mre->attrs[j].attr_len); 2111 imsg_compose(ibuf, IMSG_NETWORK_DONE, 0, 0, -1, NULL, 0); 2112 2113 while (ibuf->w.queued) { 2114 if (msgbuf_write(&ibuf->w) <= 0 && errno != EAGAIN) 2115 err(1, "write error"); 2116 } 2117 } 2118 } 2119 2120 static const char * 2121 print_time(struct timespec *t) 2122 { 2123 static char timebuf[32]; 2124 static struct timespec prevtime; 2125 struct timespec temp; 2126 2127 timespecsub(t, &prevtime, &temp); 2128 snprintf(timebuf, sizeof(timebuf), "%lld.%06ld", 2129 (long long)temp.tv_sec, temp.tv_nsec / 1000); 2130 prevtime = *t; 2131 return (timebuf); 2132 } 2133 2134 void 2135 show_mrt_state(struct mrt_bgp_state *ms, void *arg) 2136 { 2137 printf("%s %s[%u] -> ", print_time(&ms->time), 2138 log_addr(&ms->src), ms->src_as); 2139 printf("%s[%u]: %s -> %s\n", log_addr(&ms->dst), ms->dst_as, 2140 statenames[ms->old_state], statenames[ms->new_state]); 2141 } 2142 2143 static void 2144 print_afi(u_char *p, u_int8_t len) 2145 { 2146 u_int16_t afi; 2147 u_int8_t safi, aid; 2148 2149 if (len != 4) { 2150 printf("bad length"); 2151 return; 2152 } 2153 2154 /* afi, 2 byte */ 2155 memcpy(&afi, p, sizeof(afi)); 2156 afi = ntohs(afi); 2157 p += 2; 2158 /* reserved, 1 byte */ 2159 p += 1; 2160 /* safi, 1 byte */ 2161 memcpy(&safi, p, sizeof(safi)); 2162 if (afi2aid(afi, safi, &aid) == -1) 2163 printf("unkown afi %u safi %u", afi, safi); 2164 else 2165 printf("%s", aid2str(aid)); 2166 } 2167 2168 static void 2169 print_capability(u_int8_t capa_code, u_char *p, u_int8_t len) 2170 { 2171 switch (capa_code) { 2172 case CAPA_MP: 2173 printf("multiprotocol capability: "); 2174 print_afi(p, len); 2175 break; 2176 case CAPA_REFRESH: 2177 printf("route refresh capability"); 2178 break; 2179 case CAPA_RESTART: 2180 printf("graceful restart capability"); 2181 /* XXX there is more needed here */ 2182 break; 2183 case CAPA_AS4BYTE: 2184 printf("4-byte AS num capability: "); 2185 if (len == 4) { 2186 u_int32_t as; 2187 memcpy(&as, p, sizeof(as)); 2188 as = ntohl(as); 2189 printf("AS %u", as); 2190 } else 2191 printf("bad length"); 2192 break; 2193 default: 2194 printf("unknown capability %u length %u", capa_code, len); 2195 break; 2196 } 2197 } 2198 2199 static void 2200 print_notification(u_int8_t errcode, u_int8_t subcode) 2201 { 2202 const char *suberrname = NULL; 2203 int uk = 0; 2204 2205 switch (errcode) { 2206 case ERR_HEADER: 2207 if (subcode >= sizeof(suberr_header_names)/sizeof(char *)) 2208 uk = 1; 2209 else 2210 suberrname = suberr_header_names[subcode]; 2211 break; 2212 case ERR_OPEN: 2213 if (subcode >= sizeof(suberr_open_names)/sizeof(char *)) 2214 uk = 1; 2215 else 2216 suberrname = suberr_open_names[subcode]; 2217 break; 2218 case ERR_UPDATE: 2219 if (subcode >= sizeof(suberr_update_names)/sizeof(char *)) 2220 uk = 1; 2221 else 2222 suberrname = suberr_update_names[subcode]; 2223 break; 2224 case ERR_CEASE: 2225 if (subcode >= sizeof(suberr_cease_names)/sizeof(char *)) 2226 uk = 1; 2227 else 2228 suberrname = suberr_cease_names[subcode]; 2229 break; 2230 case ERR_HOLDTIMEREXPIRED: 2231 if (subcode != 0) 2232 uk = 1; 2233 break; 2234 case ERR_FSM: 2235 if (subcode >= sizeof(suberr_fsm_names)/sizeof(char *)) 2236 uk = 1; 2237 else 2238 suberrname = suberr_fsm_names[subcode]; 2239 break; 2240 default: 2241 printf("unknown errcode %u, subcode %u", 2242 errcode, subcode); 2243 return; 2244 } 2245 2246 if (uk) 2247 printf("%s, unknown subcode %u", errnames[errcode], subcode); 2248 else { 2249 if (suberrname == NULL) 2250 printf("%s", errnames[errcode]); 2251 else 2252 printf("%s, %s", errnames[errcode], suberrname); 2253 } 2254 } 2255 2256 static int 2257 show_mrt_capabilities(u_char *p, u_int16_t len) 2258 { 2259 u_int16_t totlen = len; 2260 u_int8_t capa_code, capa_len; 2261 2262 while (len > 2) { 2263 memcpy(&capa_code, p, sizeof(capa_code)); 2264 p += sizeof(capa_code); 2265 len -= sizeof(capa_code); 2266 memcpy(&capa_len, p, sizeof(capa_len)); 2267 p += sizeof(capa_len); 2268 len -= sizeof(capa_len); 2269 if (len < capa_len) { 2270 printf("capa_len %u exceeds remaining length", 2271 capa_len); 2272 return (-1); 2273 } 2274 printf("\n "); 2275 print_capability(capa_code, p, capa_len); 2276 p += capa_len; 2277 len -= capa_len; 2278 } 2279 if (len != 0) { 2280 printf("length missmatch while capability parsing"); 2281 return (-1); 2282 } 2283 return (totlen); 2284 } 2285 2286 static void 2287 show_mrt_open(u_char *p, u_int16_t len) 2288 { 2289 u_int8_t version, optparamlen; 2290 u_int16_t short_as, holdtime; 2291 struct in_addr bgpid; 2292 2293 /* length check up to optparamlen already happened */ 2294 memcpy(&version, p, sizeof(version)); 2295 p += sizeof(version); 2296 len -= sizeof(version); 2297 memcpy(&short_as, p, sizeof(short_as)); 2298 p += sizeof(short_as); 2299 len -= sizeof(short_as); 2300 short_as = ntohs(short_as); 2301 memcpy(&holdtime, p, sizeof(holdtime)); 2302 holdtime = ntohs(holdtime); 2303 p += sizeof(holdtime); 2304 len -= sizeof(holdtime); 2305 memcpy(&bgpid, p, sizeof(bgpid)); 2306 p += sizeof(bgpid); 2307 len -= sizeof(bgpid); 2308 memcpy(&optparamlen, p, sizeof(optparamlen)); 2309 p += sizeof(optparamlen); 2310 len -= sizeof(optparamlen); 2311 2312 printf("\n "); 2313 printf("Version: %d AS: %u Holdtime: %u BGP Id: %s Paramlen: %u", 2314 version, short_as, holdtime, inet_ntoa(bgpid), optparamlen); 2315 if (optparamlen != len) { 2316 printf("optional parameter length mismatch"); 2317 return; 2318 } 2319 while (len > 2) { 2320 u_int8_t op_type, op_len; 2321 int r; 2322 2323 memcpy(&op_type, p, sizeof(op_type)); 2324 p += sizeof(op_type); 2325 len -= sizeof(op_type); 2326 memcpy(&op_len, p, sizeof(op_len)); 2327 p += sizeof(op_len); 2328 len -= sizeof(op_len); 2329 2330 printf("\n "); 2331 switch (op_type) { 2332 case OPT_PARAM_CAPABILITIES: 2333 printf("Capabilities: size %u", op_len); 2334 r = show_mrt_capabilities(p, op_len); 2335 if (r == -1) 2336 return; 2337 p += r; 2338 len -= r; 2339 break; 2340 case OPT_PARAM_AUTH: 2341 default: 2342 printf("unsupported optional parameter: type %u", 2343 op_type); 2344 return; 2345 } 2346 } 2347 if (len != 0) { 2348 printf("optional parameter encoding error"); 2349 return; 2350 } 2351 } 2352 2353 static void 2354 show_mrt_notification(u_char *p, u_int16_t len) 2355 { 2356 u_int16_t i; 2357 u_int8_t errcode, subcode; 2358 size_t shutcomm_len; 2359 char shutcomm[SHUT_COMM_LEN]; 2360 2361 memcpy(&errcode, p, sizeof(errcode)); 2362 p += sizeof(errcode); 2363 len -= sizeof(errcode); 2364 2365 memcpy(&subcode, p, sizeof(subcode)); 2366 p += sizeof(subcode); 2367 len -= sizeof(subcode); 2368 2369 printf("\n "); 2370 print_notification(errcode, subcode); 2371 2372 if (errcode == ERR_CEASE && (subcode == ERR_CEASE_ADMIN_DOWN || 2373 subcode == ERR_CEASE_ADMIN_RESET)) { 2374 if (len > 1) { 2375 shutcomm_len = *p++; 2376 len--; 2377 if(len < shutcomm_len) { 2378 printf("truncated shutdown reason"); 2379 return; 2380 } 2381 if (shutcomm_len > SHUT_COMM_LEN - 1) { 2382 printf("overly long shutdown reason"); 2383 return; 2384 } 2385 memcpy(shutcomm, p, shutcomm_len); 2386 shutcomm[shutcomm_len] = '\0'; 2387 printf("shutdown reason: \"%s\"", 2388 log_shutcomm(shutcomm)); 2389 p += shutcomm_len; 2390 len -= shutcomm_len; 2391 } 2392 } 2393 if (errcode == ERR_OPEN && subcode == ERR_OPEN_CAPA) { 2394 int r; 2395 2396 r = show_mrt_capabilities(p, len); 2397 if (r == -1) 2398 return; 2399 p += r; 2400 len -= r; 2401 } 2402 2403 if (len > 0) { 2404 printf("\n additional data %u bytes", len); 2405 for (i = 0; i < len; i++) { 2406 if (i % 16 == 0) 2407 printf("\n "); 2408 if (i % 8 == 0) 2409 printf(" "); 2410 printf(" %02X", *p++); 2411 } 2412 } 2413 } 2414 2415 static void 2416 show_mrt_update(u_char *p, u_int16_t len) 2417 { 2418 struct bgpd_addr prefix; 2419 int pos; 2420 u_int16_t wlen, alen; 2421 u_int8_t prefixlen; 2422 2423 if (len < sizeof(wlen)) { 2424 printf("bad length"); 2425 return; 2426 } 2427 memcpy(&wlen, p, sizeof(wlen)); 2428 wlen = ntohs(wlen); 2429 p += sizeof(wlen); 2430 len -= sizeof(wlen); 2431 2432 if (len < wlen) { 2433 printf("bad withdraw length"); 2434 return; 2435 } 2436 if (wlen > 0) { 2437 printf("\n Withdrawn prefixes:"); 2438 while (wlen > 0) { 2439 if ((pos = nlri_get_prefix(p, wlen, &prefix, 2440 &prefixlen)) == -1) { 2441 printf("bad withdraw prefix"); 2442 return; 2443 } 2444 printf(" %s/%u", log_addr(&prefix), prefixlen); 2445 p += pos; 2446 len -= pos; 2447 wlen -= pos; 2448 } 2449 } 2450 2451 if (len < sizeof(alen)) { 2452 printf("bad length"); 2453 return; 2454 } 2455 memcpy(&alen, p, sizeof(alen)); 2456 alen = ntohs(alen); 2457 p += sizeof(alen); 2458 len -= sizeof(alen); 2459 2460 if (len < alen) { 2461 printf("bad attribute length"); 2462 return; 2463 } 2464 printf("\n"); 2465 /* alen attributes here */ 2466 while (alen > 3) { 2467 u_int8_t flags; 2468 u_int16_t attrlen; 2469 2470 flags = p[0]; 2471 /* type = p[1]; */ 2472 2473 /* get the attribute length */ 2474 if (flags & ATTR_EXTLEN) { 2475 if (len < sizeof(attrlen) + 2) 2476 printf("bad attribute length"); 2477 memcpy(&attrlen, &p[2], sizeof(attrlen)); 2478 attrlen = ntohs(attrlen); 2479 attrlen += sizeof(attrlen) + 2; 2480 } else { 2481 attrlen = p[2]; 2482 attrlen += 1 + 2; 2483 } 2484 2485 show_attr(p, attrlen, 0); 2486 p += attrlen; 2487 alen -= attrlen; 2488 len -= attrlen; 2489 } 2490 2491 if (len > 0) { 2492 printf(" NLRI prefixes:"); 2493 while (len > 0) { 2494 if ((pos = nlri_get_prefix(p, len, &prefix, 2495 &prefixlen)) == -1) { 2496 printf("bad withdraw prefix"); 2497 return; 2498 } 2499 printf(" %s/%u", log_addr(&prefix), prefixlen); 2500 p += pos; 2501 len -= pos; 2502 } 2503 } 2504 } 2505 2506 void 2507 show_mrt_msg(struct mrt_bgp_msg *mm, void *arg) 2508 { 2509 static const u_int8_t marker[MSGSIZE_HEADER_MARKER] = { 2510 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 2511 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; 2512 u_char *p; 2513 u_int16_t len; 2514 u_int8_t type; 2515 2516 printf("%s %s[%u] -> ", print_time(&mm->time), 2517 log_addr(&mm->src), mm->src_as); 2518 printf("%s[%u]: size %u ", log_addr(&mm->dst), mm->dst_as, mm->msg_len); 2519 p = mm->msg; 2520 len = mm->msg_len; 2521 2522 if (len < MSGSIZE_HEADER) { 2523 printf("illegal header length: %u byte\n", len); 2524 return; 2525 } 2526 2527 /* parse BGP message header */ 2528 if (memcmp(p, marker, sizeof(marker))) { 2529 printf("incorrect marker in BGP message\n"); 2530 return; 2531 } 2532 p += MSGSIZE_HEADER_MARKER; 2533 2534 memcpy(&len, p, 2); 2535 len = ntohs(len); 2536 p += 2; 2537 memcpy(&type, p, 1); 2538 p += 1; 2539 2540 if (len < MSGSIZE_HEADER || len > MAX_PKTSIZE) { 2541 printf("illegal header length: %u byte\n", len); 2542 return; 2543 } 2544 2545 switch (type) { 2546 case OPEN: 2547 printf("%s ", msgtypenames[type]); 2548 if (len < MSGSIZE_OPEN_MIN) { 2549 printf("illegal length: %u byte\n", len); 2550 return; 2551 } 2552 show_mrt_open(p, len - MSGSIZE_HEADER); 2553 break; 2554 case NOTIFICATION: 2555 printf("%s ", msgtypenames[type]); 2556 if (len < MSGSIZE_NOTIFICATION_MIN) { 2557 printf("illegal length: %u byte\n", len); 2558 return; 2559 } 2560 show_mrt_notification(p, len - MSGSIZE_HEADER); 2561 break; 2562 case UPDATE: 2563 printf("%s ", msgtypenames[type]); 2564 if (len < MSGSIZE_UPDATE_MIN) { 2565 printf("illegal length: %u byte\n", len); 2566 return; 2567 } 2568 show_mrt_update(p, len - MSGSIZE_HEADER); 2569 break; 2570 case KEEPALIVE: 2571 printf("%s ", msgtypenames[type]); 2572 if (len != MSGSIZE_KEEPALIVE) { 2573 printf("illegal length: %u byte\n", len); 2574 return; 2575 } 2576 /* nothing */ 2577 break; 2578 case RREFRESH: 2579 printf("%s ", msgtypenames[type]); 2580 if (len != MSGSIZE_RREFRESH) { 2581 printf("illegal length: %u byte\n", len); 2582 return; 2583 } 2584 print_afi(p, len); 2585 break; 2586 default: 2587 printf("unknown type %u\n", type); 2588 return; 2589 } 2590 printf("\n"); 2591 } 2592 2593 const char * 2594 msg_type(u_int8_t type) 2595 { 2596 if (type >= sizeof(msgtypenames)/sizeof(msgtypenames[0])) 2597 return "BAD"; 2598 return (msgtypenames[type]); 2599 } 2600 2601 int 2602 match_aspath(void *data, u_int16_t len, struct filter_as *f) 2603 { 2604 u_int8_t *seg; 2605 int final; 2606 u_int16_t seg_size; 2607 u_int8_t i, seg_len; 2608 u_int32_t as = 0; 2609 2610 if (f->type == AS_EMPTY) { 2611 if (len == 0) 2612 return (1); 2613 else 2614 return (0); 2615 } 2616 2617 seg = data; 2618 2619 /* just check the leftmost AS */ 2620 if (f->type == AS_PEER && len >= 6) { 2621 as = aspath_extract(seg, 0); 2622 if (f->as_min == as) 2623 return (1); 2624 else 2625 return (0); 2626 } 2627 2628 for (; len >= 6; len -= seg_size, seg += seg_size) { 2629 seg_len = seg[1]; 2630 seg_size = 2 + sizeof(u_int32_t) * seg_len; 2631 2632 final = (len == seg_size); 2633 2634 if (f->type == AS_SOURCE) { 2635 /* 2636 * Just extract the rightmost AS 2637 * but if that segment is an AS_SET then the rightmost 2638 * AS of a previous AS_SEQUENCE segment should be used. 2639 * Because of that just look at AS_SEQUENCE segments. 2640 */ 2641 if (seg[0] == AS_SEQUENCE) 2642 as = aspath_extract(seg, seg_len - 1); 2643 /* not yet in the final segment */ 2644 if (!final) 2645 continue; 2646 if (f->as_min == as) 2647 return (1); 2648 else 2649 return (0); 2650 } 2651 /* AS_TRANSIT or AS_ALL */ 2652 for (i = 0; i < seg_len; i++) { 2653 /* 2654 * the source (rightmost) AS is excluded from 2655 * AS_TRANSIT matches. 2656 */ 2657 if (final && i == seg_len - 1 && f->type == AS_TRANSIT) 2658 return (0); 2659 as = aspath_extract(seg, i); 2660 if (f->as_min == as) 2661 return (1); 2662 } 2663 } 2664 return (0); 2665 } 2666