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