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