1 /* $OpenBSD: bgpctl.c,v 1.199 2017/08/10 14:22:59 benno 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 #include <net/if.h> 26 #include <net/if_media.h> 27 #include <net/if_types.h> 28 29 #include <err.h> 30 #include <errno.h> 31 #include <fcntl.h> 32 #include <netdb.h> 33 #include <stdio.h> 34 #include <stdlib.h> 35 #include <string.h> 36 #include <unistd.h> 37 #include <util.h> 38 39 #include "bgpd.h" 40 #include "session.h" 41 #include "rde.h" 42 #include "parser.h" 43 #include "irrfilter.h" 44 #include "mrtparser.h" 45 46 enum neighbor_views { 47 NV_DEFAULT, 48 NV_TIMERS 49 }; 50 51 int main(int, char *[]); 52 char *fmt_peer(const char *, const struct bgpd_addr *, int, int); 53 void show_summary_head(void); 54 int show_summary_msg(struct imsg *, int); 55 int show_summary_terse_msg(struct imsg *, int); 56 int show_neighbor_terse(struct imsg *); 57 int show_neighbor_msg(struct imsg *, enum neighbor_views); 58 void print_neighbor_capa_mp(struct peer *); 59 void print_neighbor_capa_restart(struct peer *); 60 void print_neighbor_msgstats(struct peer *); 61 void print_timer(const char *, time_t); 62 static char *fmt_timeframe(time_t t); 63 static char *fmt_timeframe_core(time_t t); 64 void show_fib_head(void); 65 void show_fib_tables_head(void); 66 void show_network_head(void); 67 void show_fib_flags(u_int16_t); 68 int show_fib_msg(struct imsg *); 69 void show_nexthop_head(void); 70 int show_nexthop_msg(struct imsg *); 71 void show_interface_head(void); 72 uint64_t ift2ifm(uint8_t); 73 const char * get_media_descr(uint64_t); 74 const char * get_linkstate(uint8_t, int); 75 const char * get_baudrate(u_int64_t, char *); 76 int show_interface_msg(struct imsg *); 77 void show_rib_summary_head(void); 78 void print_prefix(struct bgpd_addr *, u_int8_t, u_int8_t); 79 const char * print_origin(u_int8_t, int); 80 void print_flags(u_int8_t, int); 81 int show_rib_summary_msg(struct imsg *); 82 int show_rib_detail_msg(struct imsg *, int); 83 void show_rib_brief(struct ctl_show_rib *, u_char *); 84 void show_rib_detail(struct ctl_show_rib *, u_char *, int); 85 void show_attr(void *, u_int16_t); 86 void show_community(u_char *, u_int16_t); 87 void show_large_community(u_char *, u_int16_t); 88 void show_ext_community(u_char *, u_int16_t); 89 char *fmt_mem(int64_t); 90 int show_rib_memory_msg(struct imsg *); 91 void send_filterset(struct imsgbuf *, struct filter_set_head *); 92 const char *get_errstr(u_int8_t, u_int8_t); 93 int show_result(struct imsg *); 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 void mrt_to_bgpd_addr(union mrt_addr *, struct bgpd_addr *); 99 const char *msg_type(u_int8_t); 100 void network_bulk(struct parse_result *); 101 const char *print_auth_method(enum auth_method); 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 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, r; 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 r = getrtable(); 131 if (asprintf(&sockname, "%s.%d", SOCKET_NAME, r) == -1) 132 err(1, "asprintf"); 133 134 if (pledge("stdio rpath wpath cpath unix inet dns", NULL) == -1) 135 err(1, "pledge"); 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 if (res->action == IRRFILTER) { 158 if (!(res->flags & (F_IPV4|F_IPV6))) 159 res->flags |= (F_IPV4|F_IPV6); 160 irr_main(res->as.as, res->flags, res->irr_outdir); 161 } 162 163 if (pledge("stdio rpath wpath unix", NULL) == -1) 164 err(1, "pledge"); 165 166 memcpy(&neighbor.addr, &res->peeraddr, sizeof(neighbor.addr)); 167 strlcpy(neighbor.descr, res->peerdesc, sizeof(neighbor.descr)); 168 strlcpy(neighbor.shutcomm, res->shutcomm, sizeof(neighbor.shutcomm)); 169 170 if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) 171 err(1, "control_init: socket"); 172 173 bzero(&sun, sizeof(sun)); 174 sun.sun_family = AF_UNIX; 175 if (strlcpy(sun.sun_path, sockname, sizeof(sun.sun_path)) >= 176 sizeof(sun.sun_path)) 177 errx(1, "socket name too long"); 178 if (connect(fd, (struct sockaddr *)&sun, sizeof(sun)) == -1) 179 err(1, "connect: %s", sockname); 180 181 if (pledge("stdio rpath wpath", NULL) == -1) 182 err(1, "pledge"); 183 184 if ((ibuf = malloc(sizeof(struct imsgbuf))) == NULL) 185 err(1, NULL); 186 imsg_init(ibuf, fd); 187 done = 0; 188 189 switch (res->action) { 190 case NONE: 191 case IRRFILTER: 192 usage(); 193 /* NOTREACHED */ 194 case SHOW: 195 case SHOW_SUMMARY: 196 imsg_compose(ibuf, IMSG_CTL_SHOW_NEIGHBOR, 0, 0, -1, NULL, 0); 197 show_summary_head(); 198 break; 199 case SHOW_SUMMARY_TERSE: 200 imsg_compose(ibuf, IMSG_CTL_SHOW_TERSE, 0, 0, -1, NULL, 0); 201 break; 202 case SHOW_FIB: 203 if (!res->addr.aid) { 204 struct ibuf *msg; 205 sa_family_t af; 206 207 af = aid2af(res->aid); 208 if ((msg = imsg_create(ibuf, IMSG_CTL_KROUTE, 209 res->rtableid, 0, sizeof(res->flags) + 210 sizeof(af))) == NULL) 211 errx(1, "imsg_create failure"); 212 if (imsg_add(msg, &res->flags, sizeof(res->flags)) == 213 -1 || 214 imsg_add(msg, &af, sizeof(af)) == -1) 215 errx(1, "imsg_add failure"); 216 imsg_close(ibuf, msg); 217 } else 218 imsg_compose(ibuf, IMSG_CTL_KROUTE_ADDR, res->rtableid, 219 0, -1, &res->addr, sizeof(res->addr)); 220 show_fib_head(); 221 break; 222 case SHOW_FIB_TABLES: 223 imsg_compose(ibuf, IMSG_CTL_SHOW_FIB_TABLES, 0, 0, -1, NULL, 0); 224 show_fib_tables_head(); 225 break; 226 case SHOW_NEXTHOP: 227 imsg_compose(ibuf, IMSG_CTL_SHOW_NEXTHOP, res->rtableid, 0, -1, 228 NULL, 0); 229 show_nexthop_head(); 230 break; 231 case SHOW_INTERFACE: 232 imsg_compose(ibuf, IMSG_CTL_SHOW_INTERFACE, 0, 0, -1, NULL, 0); 233 show_interface_head(); 234 break; 235 case SHOW_NEIGHBOR: 236 case SHOW_NEIGHBOR_TIMERS: 237 case SHOW_NEIGHBOR_TERSE: 238 neighbor.show_timers = (res->action == SHOW_NEIGHBOR_TIMERS); 239 if (res->peeraddr.aid || res->peerdesc[0]) 240 imsg_compose(ibuf, IMSG_CTL_SHOW_NEIGHBOR, 0, 0, -1, 241 &neighbor, sizeof(neighbor)); 242 else 243 imsg_compose(ibuf, IMSG_CTL_SHOW_NEIGHBOR, 0, 0, -1, 244 NULL, 0); 245 break; 246 case SHOW_RIB: 247 bzero(&ribreq, sizeof(ribreq)); 248 type = IMSG_CTL_SHOW_RIB; 249 if (res->as.type != AS_NONE) { 250 ribreq.as = res->as; 251 type = IMSG_CTL_SHOW_RIB_AS; 252 } 253 if (res->addr.aid) { 254 ribreq.prefix = res->addr; 255 ribreq.prefixlen = res->prefixlen; 256 type = IMSG_CTL_SHOW_RIB_PREFIX; 257 } 258 if (res->community.as != COMMUNITY_UNSET && 259 res->community.type != COMMUNITY_UNSET) { 260 ribreq.community = res->community; 261 type = IMSG_CTL_SHOW_RIB_COMMUNITY; 262 } 263 if (res->extcommunity.flags == EXT_COMMUNITY_FLAG_VALID) { 264 ribreq.extcommunity = res->extcommunity; 265 type = IMSG_CTL_SHOW_RIB_EXTCOMMUNITY; 266 } 267 if (res->large_community.as != COMMUNITY_UNSET && 268 res->large_community.ld1 != COMMUNITY_UNSET && 269 res->large_community.ld2 != COMMUNITY_UNSET) { 270 ribreq.large_community = res->large_community; 271 type = IMSG_CTL_SHOW_RIB_LARGECOMMUNITY; 272 } 273 ribreq.neighbor = neighbor; 274 strlcpy(ribreq.rib, res->rib, sizeof(ribreq.rib)); 275 ribreq.aid = res->aid; 276 ribreq.flags = res->flags; 277 imsg_compose(ibuf, type, 0, 0, -1, &ribreq, sizeof(ribreq)); 278 if (!(res->flags & F_CTL_DETAIL)) 279 show_rib_summary_head(); 280 break; 281 case SHOW_MRT: 282 close(fd); 283 bzero(&ribreq, sizeof(ribreq)); 284 if (res->as.type != AS_NONE) 285 ribreq.as = res->as; 286 if (res->addr.aid) { 287 ribreq.prefix = res->addr; 288 ribreq.prefixlen = res->prefixlen; 289 } 290 if (res->community.as != COMMUNITY_UNSET && 291 res->community.type != COMMUNITY_UNSET) 292 ribreq.community = res->community; 293 if (res->large_community.as != COMMUNITY_UNSET && 294 res->large_community.ld1 != COMMUNITY_UNSET && 295 res->large_community.ld2 != COMMUNITY_UNSET) 296 ribreq.large_community = res->large_community; 297 /* XXX extended communities missing? */ 298 ribreq.neighbor = neighbor; 299 ribreq.aid = res->aid; 300 ribreq.flags = res->flags; 301 show_mrt.arg = &ribreq; 302 if (!(res->flags & F_CTL_DETAIL)) 303 show_rib_summary_head(); 304 mrt_parse(res->mrtfd, &show_mrt, 1); 305 exit(0); 306 case SHOW_RIB_MEM: 307 imsg_compose(ibuf, IMSG_CTL_SHOW_RIB_MEM, 0, 0, -1, NULL, 0); 308 break; 309 case RELOAD: 310 imsg_compose(ibuf, IMSG_CTL_RELOAD, 0, 0, -1, NULL, 0); 311 printf("reload request sent.\n"); 312 break; 313 case FIB: 314 errx(1, "action==FIB"); 315 break; 316 case FIB_COUPLE: 317 imsg_compose(ibuf, IMSG_CTL_FIB_COUPLE, res->rtableid, 0, -1, 318 NULL, 0); 319 printf("couple request sent.\n"); 320 done = 1; 321 break; 322 case FIB_DECOUPLE: 323 imsg_compose(ibuf, IMSG_CTL_FIB_DECOUPLE, res->rtableid, 0, -1, 324 NULL, 0); 325 printf("decouple request sent.\n"); 326 done = 1; 327 break; 328 case NEIGHBOR: 329 errx(1, "action==NEIGHBOR"); 330 break; 331 case NEIGHBOR_UP: 332 imsg_compose(ibuf, IMSG_CTL_NEIGHBOR_UP, 0, 0, -1, 333 &neighbor, sizeof(neighbor)); 334 break; 335 case NEIGHBOR_DOWN: 336 imsg_compose(ibuf, IMSG_CTL_NEIGHBOR_DOWN, 0, 0, -1, 337 &neighbor, sizeof(neighbor)); 338 break; 339 case NEIGHBOR_CLEAR: 340 imsg_compose(ibuf, IMSG_CTL_NEIGHBOR_CLEAR, 0, 0, -1, 341 &neighbor, sizeof(neighbor)); 342 break; 343 case NEIGHBOR_RREFRESH: 344 imsg_compose(ibuf, IMSG_CTL_NEIGHBOR_RREFRESH, 0, 0, -1, 345 &neighbor, sizeof(neighbor)); 346 break; 347 case NEIGHBOR_DESTROY: 348 imsg_compose(ibuf, IMSG_CTL_NEIGHBOR_DESTROY, 0, 0, -1, 349 &neighbor, sizeof(neighbor)); 350 break; 351 case NETWORK_BULK_ADD: 352 case NETWORK_BULK_REMOVE: 353 network_bulk(res); 354 printf("requests sent.\n"); 355 done = 1; 356 break; 357 case NETWORK_ADD: 358 case NETWORK_REMOVE: 359 bzero(&net, sizeof(net)); 360 net.prefix = res->addr; 361 net.prefixlen = res->prefixlen; 362 /* attribute sets are not supported */ 363 if (res->action == NETWORK_ADD) { 364 imsg_compose(ibuf, IMSG_NETWORK_ADD, 0, 0, -1, 365 &net, sizeof(net)); 366 send_filterset(ibuf, &res->set); 367 imsg_compose(ibuf, IMSG_NETWORK_DONE, 0, 0, -1, 368 NULL, 0); 369 } else 370 imsg_compose(ibuf, IMSG_NETWORK_REMOVE, 0, 0, -1, 371 &net, sizeof(net)); 372 printf("request sent.\n"); 373 done = 1; 374 break; 375 case NETWORK_FLUSH: 376 imsg_compose(ibuf, IMSG_NETWORK_FLUSH, 0, 0, -1, NULL, 0); 377 printf("request sent.\n"); 378 done = 1; 379 break; 380 case NETWORK_SHOW: 381 bzero(&ribreq, sizeof(ribreq)); 382 ribreq.aid = res->aid; 383 strlcpy(ribreq.rib, res->rib, sizeof(ribreq.rib)); 384 imsg_compose(ibuf, IMSG_CTL_SHOW_NETWORK, 0, 0, -1, 385 &ribreq, sizeof(ribreq)); 386 show_network_head(); 387 break; 388 case NETWORK_MRT: 389 bzero(&ribreq, sizeof(ribreq)); 390 if (res->as.type != AS_NONE) 391 ribreq.as = res->as; 392 if (res->addr.aid) { 393 ribreq.prefix = res->addr; 394 ribreq.prefixlen = res->prefixlen; 395 } 396 if (res->community.as != COMMUNITY_UNSET && 397 res->community.type != COMMUNITY_UNSET) 398 ribreq.community = res->community; 399 if (res->large_community.as != COMMUNITY_UNSET && 400 res->large_community.ld1 != COMMUNITY_UNSET && 401 res->large_community.ld2 != COMMUNITY_UNSET) 402 ribreq.large_community = res->large_community; 403 /* XXX ext communities missing? */ 404 ribreq.neighbor = neighbor; 405 ribreq.aid = res->aid; 406 ribreq.flags = res->flags; 407 net_mrt.arg = &ribreq; 408 mrt_parse(res->mrtfd, &net_mrt, 1); 409 done = 1; 410 break; 411 case LOG_VERBOSE: 412 verbose = 1; 413 /* FALLTHROUGH */ 414 case LOG_BRIEF: 415 imsg_compose(ibuf, IMSG_CTL_LOG_VERBOSE, 0, 0, -1, 416 &verbose, sizeof(verbose)); 417 printf("logging request sent.\n"); 418 done = 1; 419 break; 420 } 421 422 while (ibuf->w.queued) 423 if (msgbuf_write(&ibuf->w) <= 0 && errno != EAGAIN) 424 err(1, "write error"); 425 426 while (!done) { 427 if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) 428 err(1, "imsg_read error"); 429 if (n == 0) 430 errx(1, "pipe closed"); 431 432 while (!done) { 433 if ((n = imsg_get(ibuf, &imsg)) == -1) 434 err(1, "imsg_get error"); 435 if (n == 0) 436 break; 437 438 if (imsg.hdr.type == IMSG_CTL_RESULT) { 439 done = show_result(&imsg); 440 imsg_free(&imsg); 441 continue; 442 } 443 444 switch (res->action) { 445 case SHOW: 446 case SHOW_SUMMARY: 447 done = show_summary_msg(&imsg, nodescr); 448 break; 449 case SHOW_SUMMARY_TERSE: 450 done = show_summary_terse_msg(&imsg, nodescr); 451 break; 452 case SHOW_FIB: 453 case SHOW_FIB_TABLES: 454 case NETWORK_SHOW: 455 done = show_fib_msg(&imsg); 456 break; 457 case SHOW_NEXTHOP: 458 done = show_nexthop_msg(&imsg); 459 break; 460 case SHOW_INTERFACE: 461 done = show_interface_msg(&imsg); 462 break; 463 case SHOW_NEIGHBOR: 464 done = show_neighbor_msg(&imsg, NV_DEFAULT); 465 break; 466 case SHOW_NEIGHBOR_TIMERS: 467 done = show_neighbor_msg(&imsg, NV_TIMERS); 468 break; 469 case SHOW_NEIGHBOR_TERSE: 470 done = show_neighbor_terse(&imsg); 471 break; 472 case SHOW_RIB: 473 if (res->flags & F_CTL_DETAIL) 474 done = show_rib_detail_msg(&imsg, 475 nodescr); 476 else 477 done = show_rib_summary_msg(&imsg); 478 break; 479 case SHOW_RIB_MEM: 480 done = show_rib_memory_msg(&imsg); 481 break; 482 case NEIGHBOR: 483 case NEIGHBOR_UP: 484 case NEIGHBOR_DOWN: 485 case NEIGHBOR_CLEAR: 486 case NEIGHBOR_RREFRESH: 487 case NEIGHBOR_DESTROY: 488 case NONE: 489 case RELOAD: 490 case FIB: 491 case FIB_COUPLE: 492 case FIB_DECOUPLE: 493 case NETWORK_ADD: 494 case NETWORK_REMOVE: 495 case NETWORK_FLUSH: 496 case NETWORK_BULK_ADD: 497 case NETWORK_BULK_REMOVE: 498 case IRRFILTER: 499 case LOG_VERBOSE: 500 case LOG_BRIEF: 501 case SHOW_MRT: 502 case NETWORK_MRT: 503 break; 504 } 505 imsg_free(&imsg); 506 } 507 } 508 close(fd); 509 free(ibuf); 510 511 exit(0); 512 } 513 514 char * 515 fmt_peer(const char *descr, const struct bgpd_addr *remote_addr, 516 int masklen, int nodescr) 517 { 518 const char *ip; 519 char *p; 520 521 if (descr[0] && !nodescr) { 522 if ((p = strdup(descr)) == NULL) 523 err(1, NULL); 524 return (p); 525 } 526 527 ip = log_addr(remote_addr); 528 if (masklen != -1 && ((remote_addr->aid == AID_INET && masklen != 32) || 529 (remote_addr->aid == AID_INET6 && masklen != 128))) { 530 if (asprintf(&p, "%s/%u", ip, masklen) == -1) 531 err(1, NULL); 532 } else { 533 if ((p = strdup(ip)) == NULL) 534 err(1, NULL); 535 } 536 537 return (p); 538 } 539 540 void 541 show_summary_head(void) 542 { 543 printf("%-20s %8s %10s %10s %5s %-8s %s\n", "Neighbor", "AS", 544 "MsgRcvd", "MsgSent", "OutQ", "Up/Down", "State/PrfRcvd"); 545 } 546 547 int 548 show_summary_msg(struct imsg *imsg, int nodescr) 549 { 550 struct peer *p; 551 char *s; 552 const char *a; 553 size_t alen; 554 555 switch (imsg->hdr.type) { 556 case IMSG_CTL_SHOW_NEIGHBOR: 557 p = imsg->data; 558 s = fmt_peer(p->conf.descr, &p->conf.remote_addr, 559 p->conf.remote_masklen, nodescr); 560 561 a = log_as(p->conf.remote_as); 562 alen = strlen(a); 563 /* max displayed lenght of the peers name is 28 */ 564 if (alen < 28) { 565 if (strlen(s) > 28 - alen) 566 s[28 - alen] = 0; 567 } else 568 alen = 0; 569 570 printf("%-*s %s %10llu %10llu %5u %-8s ", 571 (28 - (int)alen), s, a, 572 p->stats.msg_rcvd_open + p->stats.msg_rcvd_notification + 573 p->stats.msg_rcvd_update + p->stats.msg_rcvd_keepalive + 574 p->stats.msg_rcvd_rrefresh, 575 p->stats.msg_sent_open + p->stats.msg_sent_notification + 576 p->stats.msg_sent_update + p->stats.msg_sent_keepalive + 577 p->stats.msg_sent_rrefresh, 578 p->wbuf.queued, 579 fmt_timeframe(p->stats.last_updown)); 580 if (p->state == STATE_ESTABLISHED) { 581 printf("%6u", p->stats.prefix_cnt); 582 if (p->conf.max_prefix != 0) 583 printf("/%u", p->conf.max_prefix); 584 } else if (p->conf.template) 585 printf("Template"); 586 else 587 printf("%s", statenames[p->state]); 588 printf("\n"); 589 free(s); 590 break; 591 case IMSG_CTL_END: 592 return (1); 593 default: 594 break; 595 } 596 597 return (0); 598 } 599 600 int 601 show_summary_terse_msg(struct imsg *imsg, int nodescr) 602 { 603 struct peer *p; 604 char *s; 605 606 switch (imsg->hdr.type) { 607 case IMSG_CTL_SHOW_NEIGHBOR: 608 p = imsg->data; 609 s = fmt_peer(p->conf.descr, &p->conf.remote_addr, 610 p->conf.remote_masklen, nodescr); 611 printf("%s %s %s\n", s, log_as(p->conf.remote_as), 612 p->conf.template ? "Template" : statenames[p->state]); 613 free(s); 614 break; 615 case IMSG_CTL_END: 616 return (1); 617 default: 618 break; 619 } 620 621 return (0); 622 } 623 624 int 625 show_neighbor_terse(struct imsg *imsg) 626 { 627 struct peer *p; 628 629 switch (imsg->hdr.type) { 630 case IMSG_CTL_SHOW_NEIGHBOR: 631 p = imsg->data; 632 printf("%llu %llu %llu %llu %llu %llu %llu " 633 "%llu %llu %llu %u %u %llu %llu %llu %llu\n", 634 p->stats.msg_sent_open, p->stats.msg_rcvd_open, 635 p->stats.msg_sent_notification, 636 p->stats.msg_rcvd_notification, 637 p->stats.msg_sent_update, p->stats.msg_rcvd_update, 638 p->stats.msg_sent_keepalive, p->stats.msg_rcvd_keepalive, 639 p->stats.msg_sent_rrefresh, p->stats.msg_rcvd_rrefresh, 640 p->stats.prefix_cnt, p->conf.max_prefix, 641 p->stats.prefix_sent_update, p->stats.prefix_rcvd_update, 642 p->stats.prefix_sent_withdraw, 643 p->stats.prefix_rcvd_withdraw); 644 break; 645 case IMSG_CTL_END: 646 return (1); 647 default: 648 break; 649 } 650 651 return (0); 652 } 653 654 const char * 655 print_auth_method(enum auth_method method) 656 { 657 switch (method) { 658 case AUTH_MD5SIG: 659 return ", using md5sig"; 660 case AUTH_IPSEC_MANUAL_ESP: 661 return ", using ipsec manual esp"; 662 case AUTH_IPSEC_MANUAL_AH: 663 return ", using ipsec manual ah"; 664 case AUTH_IPSEC_IKE_ESP: 665 return ", using ipsec ike esp"; 666 case AUTH_IPSEC_IKE_AH: 667 return ", using ipsec ike ah"; 668 case AUTH_NONE: /* FALLTHROUGH */ 669 default: 670 return ""; 671 } 672 } 673 674 int 675 show_neighbor_msg(struct imsg *imsg, enum neighbor_views nv) 676 { 677 struct peer *p; 678 struct ctl_timer *t; 679 struct in_addr ina; 680 char buf[NI_MAXHOST], pbuf[NI_MAXSERV], *s; 681 int hascapamp = 0; 682 u_int8_t i; 683 684 switch (imsg->hdr.type) { 685 case IMSG_CTL_SHOW_NEIGHBOR: 686 p = imsg->data; 687 if ((p->conf.remote_addr.aid == AID_INET && 688 p->conf.remote_masklen != 32) || 689 (p->conf.remote_addr.aid == AID_INET6 && 690 p->conf.remote_masklen != 128)) { 691 if (asprintf(&s, "%s/%u", 692 log_addr(&p->conf.remote_addr), 693 p->conf.remote_masklen) == -1) 694 err(1, NULL); 695 } else 696 if ((s = strdup(log_addr(&p->conf.remote_addr))) == 697 NULL) 698 err(1, "strdup"); 699 700 ina.s_addr = p->remote_bgpid; 701 printf("BGP neighbor is %s, ", s); 702 free(s); 703 if (p->conf.remote_as == 0 && p->conf.template) 704 printf("remote AS: accept any"); 705 else 706 printf("remote AS %s", log_as(p->conf.remote_as)); 707 if (p->conf.template) 708 printf(", Template"); 709 if (p->template) 710 printf(", Cloned"); 711 if (p->conf.passive) 712 printf(", Passive"); 713 if (p->conf.ebgp && p->conf.distance > 1) 714 printf(", Multihop (%u)", (int)p->conf.distance); 715 printf("\n"); 716 if (p->conf.descr[0]) 717 printf(" Description: %s\n", p->conf.descr); 718 if (p->conf.max_prefix) { 719 printf(" Max-prefix: %u", p->conf.max_prefix); 720 if (p->conf.max_prefix_restart) 721 printf(" (restart %u)", 722 p->conf.max_prefix_restart); 723 printf("\n"); 724 } 725 printf(" BGP version 4, remote router-id %s", 726 inet_ntoa(ina)); 727 printf("%s\n", print_auth_method(p->auth.method)); 728 printf(" BGP state = %s", statenames[p->state]); 729 if (p->conf.down) { 730 printf(", marked down"); 731 if (*(p->conf.shutcomm)) { 732 printf(" with shutdown reason \"%s\"", 733 log_shutcomm(p->conf.shutcomm)); 734 } 735 } 736 if (p->stats.last_updown != 0) 737 printf(", %s for %s", 738 p->state == STATE_ESTABLISHED ? "up" : "down", 739 fmt_timeframe(p->stats.last_updown)); 740 printf("\n"); 741 printf(" Last read %s, holdtime %us, keepalive interval %us\n", 742 fmt_timeframe(p->stats.last_read), 743 p->holdtime, p->holdtime/3); 744 for (i = 0; i < AID_MAX; i++) 745 if (p->capa.peer.mp[i]) 746 hascapamp = 1; 747 if (hascapamp || p->capa.peer.refresh || 748 p->capa.peer.grestart.restart || p->capa.peer.as4byte) { 749 printf(" Neighbor capabilities:\n"); 750 if (hascapamp) { 751 printf(" Multiprotocol extensions: "); 752 print_neighbor_capa_mp(p); 753 printf("\n"); 754 } 755 if (p->capa.peer.refresh) 756 printf(" Route Refresh\n"); 757 if (p->capa.peer.grestart.restart) { 758 printf(" Graceful Restart"); 759 print_neighbor_capa_restart(p); 760 printf("\n"); 761 } 762 if (p->capa.peer.as4byte) 763 printf(" 4-byte AS numbers\n"); 764 } 765 printf("\n"); 766 if (nv == NV_TIMERS) 767 break; 768 print_neighbor_msgstats(p); 769 printf("\n"); 770 if (*(p->stats.last_shutcomm)) { 771 printf(" Last received shutdown reason: \"%s\"\n", 772 log_shutcomm(p->stats.last_shutcomm)); 773 } 774 if (p->state == STATE_IDLE) { 775 static const char *errstr; 776 777 errstr = get_errstr(p->stats.last_sent_errcode, 778 p->stats.last_sent_suberr); 779 if (errstr) 780 printf(" Last error: %s\n\n", errstr); 781 } else { 782 if (getnameinfo((struct sockaddr *)&p->sa_local, 783 (socklen_t)p->sa_local.ss_len, 784 buf, sizeof(buf), pbuf, sizeof(pbuf), 785 NI_NUMERICHOST | NI_NUMERICSERV)) { 786 strlcpy(buf, "(unknown)", sizeof(buf)); 787 strlcpy(pbuf, "", sizeof(pbuf)); 788 } 789 printf(" Local host: %20s, Local port: %5s\n", buf, 790 pbuf); 791 792 if (getnameinfo((struct sockaddr *)&p->sa_remote, 793 (socklen_t)p->sa_remote.ss_len, 794 buf, sizeof(buf), pbuf, sizeof(pbuf), 795 NI_NUMERICHOST | NI_NUMERICSERV)) { 796 strlcpy(buf, "(unknown)", sizeof(buf)); 797 strlcpy(pbuf, "", sizeof(pbuf)); 798 } 799 printf(" Remote host: %20s, Remote port: %5s\n", buf, 800 pbuf); 801 printf("\n"); 802 } 803 break; 804 case IMSG_CTL_SHOW_TIMER: 805 t = imsg->data; 806 if (t->type > 0 && t->type < Timer_Max) 807 print_timer(timernames[t->type], t->val); 808 break; 809 case IMSG_CTL_END: 810 return (1); 811 break; 812 default: 813 break; 814 } 815 816 return (0); 817 } 818 819 void 820 print_neighbor_capa_mp(struct peer *p) 821 { 822 int comma; 823 u_int8_t i; 824 825 for (i = 0, comma = 0; i < AID_MAX; i++) 826 if (p->capa.peer.mp[i]) { 827 printf("%s%s", comma ? ", " : "", aid2str(i)); 828 comma = 1; 829 } 830 } 831 832 void 833 print_neighbor_capa_restart(struct peer *p) 834 { 835 int comma; 836 u_int8_t i; 837 838 if (p->capa.peer.grestart.timeout) 839 printf(": Timeout: %d, ", p->capa.peer.grestart.timeout); 840 for (i = 0, comma = 0; i < AID_MAX; i++) 841 if (p->capa.peer.grestart.flags[i] & CAPA_GR_PRESENT) { 842 if (!comma && 843 p->capa.peer.grestart.flags[i] & CAPA_GR_RESTART) 844 printf("restarted, "); 845 if (comma) 846 printf(", "); 847 printf("%s", aid2str(i)); 848 if (p->capa.peer.grestart.flags[i] & CAPA_GR_FORWARD) 849 printf(" (preserved)"); 850 comma = 1; 851 } 852 } 853 854 void 855 print_neighbor_msgstats(struct peer *p) 856 { 857 printf(" Message statistics:\n"); 858 printf(" %-15s %-10s %-10s\n", "", "Sent", "Received"); 859 printf(" %-15s %10llu %10llu\n", "Opens", 860 p->stats.msg_sent_open, p->stats.msg_rcvd_open); 861 printf(" %-15s %10llu %10llu\n", "Notifications", 862 p->stats.msg_sent_notification, p->stats.msg_rcvd_notification); 863 printf(" %-15s %10llu %10llu\n", "Updates", 864 p->stats.msg_sent_update, p->stats.msg_rcvd_update); 865 printf(" %-15s %10llu %10llu\n", "Keepalives", 866 p->stats.msg_sent_keepalive, p->stats.msg_rcvd_keepalive); 867 printf(" %-15s %10llu %10llu\n", "Route Refresh", 868 p->stats.msg_sent_rrefresh, p->stats.msg_rcvd_rrefresh); 869 printf(" %-15s %10llu %10llu\n\n", "Total", 870 p->stats.msg_sent_open + p->stats.msg_sent_notification + 871 p->stats.msg_sent_update + p->stats.msg_sent_keepalive + 872 p->stats.msg_sent_rrefresh, 873 p->stats.msg_rcvd_open + p->stats.msg_rcvd_notification + 874 p->stats.msg_rcvd_update + p->stats.msg_rcvd_keepalive + 875 p->stats.msg_rcvd_rrefresh); 876 printf(" Update statistics:\n"); 877 printf(" %-15s %-10s %-10s\n", "", "Sent", "Received"); 878 printf(" %-15s %10llu %10llu\n", "Updates", 879 p->stats.prefix_sent_update, p->stats.prefix_rcvd_update); 880 printf(" %-15s %10llu %10llu\n", "Withdraws", 881 p->stats.prefix_sent_withdraw, p->stats.prefix_rcvd_withdraw); 882 printf(" %-15s %10llu %10llu\n", "End-of-Rib", 883 p->stats.prefix_sent_eor, p->stats.prefix_rcvd_eor); 884 } 885 886 void 887 print_timer(const char *name, time_t d) 888 { 889 printf(" %-20s ", name); 890 891 if (d <= 0) 892 printf("%-20s\n", "due"); 893 else 894 printf("due in %-13s\n", fmt_timeframe_core(d)); 895 } 896 897 #define TF_BUFS 8 898 #define TF_LEN 9 899 900 static char * 901 fmt_timeframe(time_t t) 902 { 903 if (t == 0) 904 return ("Never"); 905 else 906 return (fmt_timeframe_core(time(NULL) - t)); 907 } 908 909 static char * 910 fmt_timeframe_core(time_t t) 911 { 912 char *buf; 913 static char tfbuf[TF_BUFS][TF_LEN]; /* ring buffer */ 914 static int idx = 0; 915 unsigned int sec, min, hrs, day; 916 unsigned long long week; 917 918 buf = tfbuf[idx++]; 919 if (idx == TF_BUFS) 920 idx = 0; 921 922 week = t; 923 924 sec = week % 60; 925 week /= 60; 926 min = week % 60; 927 week /= 60; 928 hrs = week % 24; 929 week /= 24; 930 day = week % 7; 931 week /= 7; 932 933 if (week > 0) 934 snprintf(buf, TF_LEN, "%02lluw%01ud%02uh", week, day, hrs); 935 else if (day > 0) 936 snprintf(buf, TF_LEN, "%01ud%02uh%02um", day, hrs, min); 937 else 938 snprintf(buf, TF_LEN, "%02u:%02u:%02u", hrs, min, sec); 939 940 return (buf); 941 } 942 943 void 944 show_fib_head(void) 945 { 946 printf("flags: " 947 "* = valid, B = BGP, C = Connected, S = Static, D = Dynamic\n"); 948 printf(" " 949 "N = BGP Nexthop reachable via this route R = redistributed\n"); 950 printf(" r = reject route, b = blackhole route\n\n"); 951 printf("flags prio destination gateway\n"); 952 } 953 954 void 955 show_fib_tables_head(void) 956 { 957 printf("%-5s %-20s %-8s\n", "Table", "Description", "State"); 958 } 959 960 void 961 show_network_head(void) 962 { 963 printf("flags: S = Static\n"); 964 printf("flags destination\n"); 965 } 966 967 void 968 show_fib_flags(u_int16_t flags) 969 { 970 if (flags & F_DOWN) 971 printf(" "); 972 else 973 printf("*"); 974 975 if (flags & F_BGPD_INSERTED) 976 printf("B"); 977 else if (flags & F_CONNECTED) 978 printf("C"); 979 else if (flags & F_STATIC) 980 printf("S"); 981 else if (flags & F_DYNAMIC) 982 printf("D"); 983 else 984 printf(" "); 985 986 if (flags & F_NEXTHOP) 987 printf("N"); 988 else 989 printf(" "); 990 991 if (flags & F_REDISTRIBUTED) 992 printf("R"); 993 else 994 printf(" "); 995 996 if (flags & F_REJECT && flags & F_BLACKHOLE) 997 printf("f"); 998 else if (flags & F_REJECT) 999 printf("r"); 1000 else if (flags & F_BLACKHOLE) 1001 printf("b"); 1002 else 1003 printf(" "); 1004 1005 printf(" "); 1006 } 1007 1008 int 1009 show_fib_msg(struct imsg *imsg) 1010 { 1011 struct kroute_full *kf; 1012 struct ktable *kt; 1013 char *p; 1014 1015 switch (imsg->hdr.type) { 1016 case IMSG_CTL_KROUTE: 1017 case IMSG_CTL_SHOW_NETWORK: 1018 if (imsg->hdr.len < IMSG_HEADER_SIZE + sizeof(*kf)) 1019 errx(1, "wrong imsg len"); 1020 kf = imsg->data; 1021 1022 show_fib_flags(kf->flags); 1023 1024 if (asprintf(&p, "%s/%u", log_addr(&kf->prefix), 1025 kf->prefixlen) == -1) 1026 err(1, NULL); 1027 printf("%4i %-20s ", kf->priority, p); 1028 free(p); 1029 1030 if (kf->flags & F_CONNECTED) 1031 printf("link#%u", kf->ifindex); 1032 else 1033 printf("%s", log_addr(&kf->nexthop)); 1034 printf("\n"); 1035 1036 break; 1037 case IMSG_CTL_SHOW_FIB_TABLES: 1038 if (imsg->hdr.len < IMSG_HEADER_SIZE + sizeof(*kt)) 1039 errx(1, "wrong imsg len"); 1040 kt = imsg->data; 1041 1042 printf("%5i %-20s %-8s%s\n", kt->rtableid, kt->descr, 1043 kt->fib_sync ? "coupled" : "decoupled", 1044 kt->fib_sync != kt->fib_conf ? "*" : ""); 1045 1046 break; 1047 case IMSG_CTL_END: 1048 return (1); 1049 default: 1050 break; 1051 } 1052 1053 return (0); 1054 } 1055 1056 void 1057 show_nexthop_head(void) 1058 { 1059 printf("Flags: * = nexthop valid\n"); 1060 printf("\n %-15s %-19s%-4s %-15s %-20s\n", "Nexthop", "Route", 1061 "Prio", "Gateway", "Iface"); 1062 } 1063 1064 int 1065 show_nexthop_msg(struct imsg *imsg) 1066 { 1067 struct ctl_show_nexthop *p; 1068 struct kroute *k; 1069 struct kroute6 *k6; 1070 char *s; 1071 1072 switch (imsg->hdr.type) { 1073 case IMSG_CTL_SHOW_NEXTHOP: 1074 p = imsg->data; 1075 printf("%s %-15s ", p->valid ? "*" : " ", log_addr(&p->addr)); 1076 if (!p->krvalid) { 1077 printf("\n"); 1078 return (0); 1079 } 1080 switch (p->addr.aid) { 1081 case AID_INET: 1082 k = &p->kr.kr4; 1083 if (asprintf(&s, "%s/%u", inet_ntoa(k->prefix), 1084 k->prefixlen) == -1) 1085 err(1, NULL); 1086 printf("%-20s", s); 1087 free(s); 1088 printf("%3i %-15s ", k->priority, 1089 k->flags & F_CONNECTED ? "connected" : 1090 inet_ntoa(k->nexthop)); 1091 break; 1092 case AID_INET6: 1093 k6 = &p->kr.kr6; 1094 if (asprintf(&s, "%s/%u", log_in6addr(&k6->prefix), 1095 k6->prefixlen) == -1) 1096 err(1, NULL); 1097 printf("%-20s", s); 1098 free(s); 1099 printf("%3i %-15s ", k6->priority, 1100 k6->flags & F_CONNECTED ? "connected" : 1101 log_in6addr(&k6->nexthop)); 1102 break; 1103 default: 1104 printf("unknown address family\n"); 1105 return (0); 1106 } 1107 if (p->kif.ifname[0]) { 1108 char *s1; 1109 if (p->kif.baudrate) { 1110 if (asprintf(&s1, ", %s", 1111 get_baudrate(p->kif.baudrate, 1112 "bps")) == -1) 1113 err(1, NULL); 1114 } else if (asprintf(&s1, ", %s", get_linkstate( 1115 p->kif.if_type, p->kif.link_state)) == -1) 1116 err(1, NULL); 1117 if (asprintf(&s, "%s (%s%s)", p->kif.ifname, 1118 p->kif.flags & IFF_UP ? "UP" : "DOWN", s1) == -1) 1119 err(1, NULL); 1120 printf("%-15s", s); 1121 free(s1); 1122 free(s); 1123 } 1124 printf("\n"); 1125 break; 1126 case IMSG_CTL_END: 1127 return (1); 1128 break; 1129 default: 1130 break; 1131 } 1132 1133 return (0); 1134 } 1135 1136 1137 void 1138 show_interface_head(void) 1139 { 1140 printf("%-15s%-15s%-15s%s\n", "Interface", "Nexthop state", "Flags", 1141 "Link state"); 1142 } 1143 1144 const struct if_status_description 1145 if_status_descriptions[] = LINK_STATE_DESCRIPTIONS; 1146 const struct ifmedia_description 1147 ifm_type_descriptions[] = IFM_TYPE_DESCRIPTIONS; 1148 1149 uint64_t 1150 ift2ifm(uint8_t if_type) 1151 { 1152 switch (if_type) { 1153 case IFT_ETHER: 1154 return (IFM_ETHER); 1155 case IFT_FDDI: 1156 return (IFM_FDDI); 1157 case IFT_CARP: 1158 return (IFM_CARP); 1159 case IFT_IEEE80211: 1160 return (IFM_IEEE80211); 1161 default: 1162 return (0); 1163 } 1164 } 1165 1166 const char * 1167 get_media_descr(uint64_t media_type) 1168 { 1169 const struct ifmedia_description *p; 1170 1171 for (p = ifm_type_descriptions; p->ifmt_string != NULL; p++) 1172 if (media_type == p->ifmt_word) 1173 return (p->ifmt_string); 1174 1175 return ("unknown media"); 1176 } 1177 1178 const char * 1179 get_linkstate(uint8_t if_type, int link_state) 1180 { 1181 const struct if_status_description *p; 1182 static char buf[8]; 1183 1184 for (p = if_status_descriptions; p->ifs_string != NULL; p++) { 1185 if (LINK_STATE_DESC_MATCH(p, if_type, link_state)) 1186 return (p->ifs_string); 1187 } 1188 snprintf(buf, sizeof(buf), "[#%d]", link_state); 1189 return (buf); 1190 } 1191 1192 const char * 1193 get_baudrate(u_int64_t baudrate, char *unit) 1194 { 1195 static char bbuf[16]; 1196 1197 if (baudrate > IF_Gbps(1)) 1198 snprintf(bbuf, sizeof(bbuf), "%llu G%s", 1199 baudrate / IF_Gbps(1), unit); 1200 else if (baudrate > IF_Mbps(1)) 1201 snprintf(bbuf, sizeof(bbuf), "%llu M%s", 1202 baudrate / IF_Mbps(1), unit); 1203 else if (baudrate > IF_Kbps(1)) 1204 snprintf(bbuf, sizeof(bbuf), "%llu K%s", 1205 baudrate / IF_Kbps(1), unit); 1206 else 1207 snprintf(bbuf, sizeof(bbuf), "%llu %s", 1208 baudrate, unit); 1209 1210 return (bbuf); 1211 } 1212 1213 int 1214 show_interface_msg(struct imsg *imsg) 1215 { 1216 struct kif *k; 1217 uint64_t ifms_type; 1218 1219 switch (imsg->hdr.type) { 1220 case IMSG_CTL_SHOW_INTERFACE: 1221 k = imsg->data; 1222 printf("%-15s", k->ifname); 1223 printf("%-15s", k->nh_reachable ? "ok" : "invalid"); 1224 printf("%-15s", k->flags & IFF_UP ? "UP" : ""); 1225 1226 if ((ifms_type = ift2ifm(k->if_type)) != 0) 1227 printf("%s, ", get_media_descr(ifms_type)); 1228 1229 printf("%s", get_linkstate(k->if_type, k->link_state)); 1230 1231 if (k->link_state != LINK_STATE_DOWN && k->baudrate > 0) 1232 printf(", %s", get_baudrate(k->baudrate, "Bit/s")); 1233 printf("\n"); 1234 break; 1235 case IMSG_CTL_END: 1236 return (1); 1237 break; 1238 default: 1239 break; 1240 } 1241 1242 return (0); 1243 } 1244 1245 void 1246 show_rib_summary_head(void) 1247 { 1248 printf("flags: * = Valid, > = Selected, I = via IBGP, A = Announced, " 1249 "S = Stale\n"); 1250 printf("origin: i = IGP, e = EGP, ? = Incomplete\n\n"); 1251 printf("%-5s %-20s %-15s %5s %5s %s\n", "flags", "destination", 1252 "gateway", "lpref", "med", "aspath origin"); 1253 } 1254 1255 void 1256 print_prefix(struct bgpd_addr *prefix, u_int8_t prefixlen, u_int8_t flags) 1257 { 1258 char *p; 1259 1260 print_flags(flags, 1); 1261 if (asprintf(&p, "%s/%u", log_addr(prefix), prefixlen) == -1) 1262 err(1, NULL); 1263 printf("%-20s", p); 1264 free(p); 1265 } 1266 1267 const char * 1268 print_origin(u_int8_t origin, int sum) 1269 { 1270 switch (origin) { 1271 case ORIGIN_IGP: 1272 return (sum ? "i" : "IGP"); 1273 case ORIGIN_EGP: 1274 return (sum ? "e" : "EGP"); 1275 case ORIGIN_INCOMPLETE: 1276 return (sum ? "?" : "incomplete"); 1277 default: 1278 return (sum ? "X" : "bad origin"); 1279 } 1280 } 1281 1282 void 1283 print_flags(u_int8_t flags, int sum) 1284 { 1285 char flagstr[5]; 1286 char *p = flagstr; 1287 1288 if (sum) { 1289 if (flags & F_PREF_ANNOUNCE) 1290 *p++ = 'A'; 1291 if (flags & F_PREF_INTERNAL) 1292 *p++ = 'I'; 1293 if (flags & F_PREF_STALE) 1294 *p++ = 'S'; 1295 if (flags & F_PREF_ELIGIBLE) 1296 *p++ = '*'; 1297 if (flags & F_PREF_ACTIVE) 1298 *p++ = '>'; 1299 *p = '\0'; 1300 printf("%-5s ", flagstr); 1301 } else { 1302 if (flags & F_PREF_INTERNAL) 1303 printf("internal"); 1304 else 1305 printf("external"); 1306 if (flags & F_PREF_STALE) 1307 printf(", stale"); 1308 if (flags & F_PREF_ELIGIBLE) 1309 printf(", valid"); 1310 if (flags & F_PREF_ACTIVE) 1311 printf(", best"); 1312 if (flags & F_PREF_ANNOUNCE) 1313 printf(", announced"); 1314 } 1315 } 1316 1317 int 1318 show_rib_summary_msg(struct imsg *imsg) 1319 { 1320 struct ctl_show_rib rib; 1321 u_char *asdata; 1322 1323 switch (imsg->hdr.type) { 1324 case IMSG_CTL_SHOW_RIB: 1325 memcpy(&rib, imsg->data, sizeof(rib)); 1326 asdata = imsg->data; 1327 asdata += sizeof(struct ctl_show_rib); 1328 show_rib_brief(&rib, asdata); 1329 break; 1330 case IMSG_CTL_END: 1331 return (1); 1332 default: 1333 break; 1334 } 1335 1336 return (0); 1337 } 1338 1339 int 1340 show_rib_detail_msg(struct imsg *imsg, int nodescr) 1341 { 1342 struct ctl_show_rib rib; 1343 u_char *asdata; 1344 u_int16_t ilen; 1345 1346 switch (imsg->hdr.type) { 1347 case IMSG_CTL_SHOW_RIB: 1348 memcpy(&rib, imsg->data, sizeof(rib)); 1349 asdata = imsg->data; 1350 asdata += sizeof(struct ctl_show_rib); 1351 show_rib_detail(&rib, asdata, nodescr); 1352 break; 1353 case IMSG_CTL_SHOW_RIB_ATTR: 1354 ilen = imsg->hdr.len - IMSG_HEADER_SIZE; 1355 if (ilen < 3) 1356 errx(1, "bad IMSG_CTL_SHOW_RIB_ATTR received"); 1357 show_attr(imsg->data, ilen); 1358 break; 1359 case IMSG_CTL_END: 1360 printf("\n"); 1361 return (1); 1362 default: 1363 break; 1364 } 1365 1366 return (0); 1367 } 1368 1369 void 1370 show_rib_brief(struct ctl_show_rib *r, u_char *asdata) 1371 { 1372 char *aspath; 1373 1374 print_prefix(&r->prefix, r->prefixlen, r->flags); 1375 printf(" %-15s ", log_addr(&r->exit_nexthop)); 1376 printf(" %5u %5u ", r->local_pref, r->med); 1377 1378 if (aspath_asprint(&aspath, asdata, r->aspath_len) == -1) 1379 err(1, NULL); 1380 if (strlen(aspath) > 0) 1381 printf("%s ", aspath); 1382 free(aspath); 1383 1384 printf("%s\n", print_origin(r->origin, 1)); 1385 } 1386 1387 void 1388 show_rib_detail(struct ctl_show_rib *r, u_char *asdata, int nodescr) 1389 { 1390 struct in_addr id; 1391 char *aspath, *s; 1392 time_t now; 1393 1394 printf("\nBGP routing table entry for %s/%u\n", 1395 log_addr(&r->prefix), r->prefixlen); 1396 1397 if (aspath_asprint(&aspath, asdata, r->aspath_len) == -1) 1398 err(1, NULL); 1399 if (strlen(aspath) > 0) 1400 printf(" %s\n", aspath); 1401 free(aspath); 1402 1403 s = fmt_peer(r->descr, &r->remote_addr, -1, nodescr); 1404 printf(" Nexthop %s ", log_addr(&r->exit_nexthop)); 1405 printf("(via %s) from %s (", log_addr(&r->true_nexthop), s); 1406 free(s); 1407 id.s_addr = htonl(r->remote_id); 1408 printf("%s)\n", inet_ntoa(id)); 1409 1410 printf(" Origin %s, metric %u, localpref %u, weight %u, ", 1411 print_origin(r->origin, 0), r->med, r->local_pref, r->weight); 1412 print_flags(r->flags, 0); 1413 1414 now = time(NULL); 1415 if (now > r->lastchange) 1416 now -= r->lastchange; 1417 else 1418 now = 0; 1419 1420 printf("\n Last update: %s ago\n", fmt_timeframe_core(now)); 1421 } 1422 1423 void 1424 show_attr(void *b, u_int16_t len) 1425 { 1426 char *data = b; 1427 struct in_addr id; 1428 u_int32_t as; 1429 u_int16_t alen, ioff; 1430 u_int8_t flags, type; 1431 int i; 1432 1433 if (len < 3) 1434 errx(1, "show_attr: too short bgp attr"); 1435 1436 flags = data[0]; 1437 type = data[1]; 1438 1439 /* get the attribute length */ 1440 if (flags & ATTR_EXTLEN) { 1441 if (len < 4) 1442 errx(1, "show_attr: too short bgp attr"); 1443 memcpy(&alen, data+2, sizeof(u_int16_t)); 1444 alen = ntohs(alen); 1445 data += 4; 1446 len -= 4; 1447 } else { 1448 alen = (u_char)data[2]; 1449 data += 3; 1450 len -= 3; 1451 } 1452 1453 /* bad imsg len how can that happen!? */ 1454 if (alen > len) 1455 errx(1, "show_attr: bad length"); 1456 1457 switch (type) { 1458 case ATTR_COMMUNITIES: 1459 printf(" Communities: "); 1460 show_community(data, alen); 1461 printf("\n"); 1462 break; 1463 case ATTR_LARGE_COMMUNITIES: 1464 printf(" Large Communities: "); 1465 show_large_community(data, alen); 1466 printf("\n"); 1467 break; 1468 case ATTR_AGGREGATOR: 1469 memcpy(&as, data, sizeof(as)); 1470 memcpy(&id, data + sizeof(as), sizeof(id)); 1471 printf(" Aggregator: %s [%s]\n", 1472 log_as(ntohl(as)), inet_ntoa(id)); 1473 break; 1474 case ATTR_ORIGINATOR_ID: 1475 memcpy(&id, data, sizeof(id)); 1476 printf(" Originator Id: %s\n", inet_ntoa(id)); 1477 break; 1478 case ATTR_CLUSTER_LIST: 1479 printf(" Cluster ID List:"); 1480 for (ioff = 0; ioff + sizeof(id) <= alen; 1481 ioff += sizeof(id)) { 1482 memcpy(&id, data + ioff, sizeof(id)); 1483 printf(" %s", inet_ntoa(id)); 1484 } 1485 printf("\n"); 1486 break; 1487 case ATTR_EXT_COMMUNITIES: 1488 printf(" Ext. communities: "); 1489 show_ext_community(data, alen); 1490 printf("\n"); 1491 break; 1492 case ATTR_ATOMIC_AGGREGATE: 1493 /* ignore */ 1494 break; 1495 default: 1496 /* ignore unknown attributes */ 1497 printf(" Unknown Attribute #%u", type); 1498 if (flags) { 1499 printf(" flags ["); 1500 if (flags & ATTR_OPTIONAL) 1501 printf("O"); 1502 if (flags & ATTR_TRANSITIVE) 1503 printf("T"); 1504 if (flags & ATTR_PARTIAL) 1505 printf("P"); 1506 printf("]"); 1507 } 1508 printf(" len %u", alen); 1509 if (alen) { 1510 printf(":"); 1511 for (i=0; i < alen; i++) 1512 printf(" %02x", *(data+i) & 0xFF); 1513 } 1514 printf("\n"); 1515 break; 1516 } 1517 } 1518 1519 void 1520 show_community(u_char *data, u_int16_t len) 1521 { 1522 u_int16_t a, v; 1523 u_int16_t i; 1524 1525 if (len & 0x3) 1526 return; 1527 1528 for (i = 0; i < len; i += 4) { 1529 memcpy(&a, data + i, sizeof(a)); 1530 memcpy(&v, data + i + 2, sizeof(v)); 1531 a = ntohs(a); 1532 v = ntohs(v); 1533 if (a == COMMUNITY_WELLKNOWN) 1534 switch (v) { 1535 case COMMUNITY_GRACEFUL_SHUTDOWN: 1536 printf("GRACEFUL_SHUTDOWN"); 1537 break; 1538 case COMMUNITY_NO_EXPORT: 1539 printf("NO_EXPORT"); 1540 break; 1541 case COMMUNITY_NO_ADVERTISE: 1542 printf("NO_ADVERTISE"); 1543 break; 1544 case COMMUNITY_NO_EXPSUBCONFED: 1545 printf("NO_EXPORT_SUBCONFED"); 1546 break; 1547 case COMMUNITY_NO_PEER: 1548 printf("NO_PEER"); 1549 break; 1550 case COMMUNITY_BLACKHOLE: 1551 printf("BLACKHOLE"); 1552 break; 1553 default: 1554 printf("%hu:%hu", a, v); 1555 break; 1556 } 1557 else 1558 printf("%hu:%hu", a, v); 1559 1560 if (i + 4 < len) 1561 printf(" "); 1562 } 1563 } 1564 1565 void 1566 show_large_community(u_char *data, u_int16_t len) 1567 { 1568 u_int32_t a, l1, l2; 1569 u_int16_t i; 1570 1571 if (len % 12) 1572 return; 1573 1574 for (i = 0; i < len; i += 12) { 1575 memcpy(&a, data + i, sizeof(a)); 1576 memcpy(&l1, data + i + 4, sizeof(l1)); 1577 memcpy(&l2, data + i + 8, sizeof(l2)); 1578 a = ntohl(a); 1579 l1 = ntohl(l1); 1580 l2 = ntohl(l2); 1581 printf("%u:%u:%u", a, l1, l2); 1582 1583 if (i + 12 < len) 1584 printf(" "); 1585 } 1586 } 1587 1588 void 1589 show_ext_community(u_char *data, u_int16_t len) 1590 { 1591 u_int64_t ext; 1592 struct in_addr ip; 1593 u_int32_t as4, u32; 1594 u_int16_t i, as2, u16; 1595 u_int8_t type, subtype; 1596 1597 if (len & 0x7) 1598 return; 1599 1600 for (i = 0; i < len; i += 8) { 1601 type = data[i]; 1602 subtype = data[i + 1]; 1603 1604 printf("%s ", log_ext_subtype(type, subtype)); 1605 1606 switch (type) { 1607 case EXT_COMMUNITY_TRANS_TWO_AS: 1608 memcpy(&as2, data + i + 2, sizeof(as2)); 1609 memcpy(&u32, data + i + 4, sizeof(u32)); 1610 printf("%s:%u", log_as(ntohs(as2)), ntohl(u32)); 1611 break; 1612 case EXT_COMMUNITY_TRANS_IPV4: 1613 memcpy(&ip, data + i + 2, sizeof(ip)); 1614 memcpy(&u16, data + i + 6, sizeof(u16)); 1615 printf("%s:%hu", inet_ntoa(ip), ntohs(u16)); 1616 break; 1617 case EXT_COMMUNITY_TRANS_FOUR_AS: 1618 memcpy(&as4, data + i + 2, sizeof(as4)); 1619 memcpy(&u16, data + i + 6, sizeof(u16)); 1620 printf("%s:%hu", log_as(ntohl(as4)), ntohs(u16)); 1621 break; 1622 case EXT_COMMUNITY_TRANS_OPAQUE: 1623 case EXT_COMMUNITY_TRANS_EVPN: 1624 memcpy(&ext, data + i, sizeof(ext)); 1625 ext = betoh64(ext) & 0xffffffffffffLL; 1626 printf("0x%llx", ext); 1627 break; 1628 case EXT_COMMUNITY_NON_TRANS_OPAQUE: 1629 memcpy(&ext, data + i, sizeof(ext)); 1630 ext = betoh64(ext) & 0xffffffffffffLL; 1631 switch (ext) { 1632 case EXT_COMMUNITY_OVS_VALID: 1633 printf("valid "); 1634 break; 1635 case EXT_COMMUNITY_OVS_NOTFOUND: 1636 printf("not-found "); 1637 break; 1638 case EXT_COMMUNITY_OVS_INVALID: 1639 printf("invalid "); 1640 break; 1641 default: 1642 printf("0x%llx ", ext); 1643 break; 1644 } 1645 break; 1646 default: 1647 memcpy(&ext, data + i, sizeof(ext)); 1648 printf("0x%llx", betoh64(ext)); 1649 } 1650 if (i + 8 < len) 1651 printf(", "); 1652 } 1653 } 1654 1655 char * 1656 fmt_mem(int64_t num) 1657 { 1658 static char buf[16]; 1659 1660 if (fmt_scaled(num, buf) == -1) 1661 snprintf(buf, sizeof(buf), "%lldB", (long long)num); 1662 1663 return (buf); 1664 } 1665 1666 size_t pt_sizes[AID_MAX] = AID_PTSIZE; 1667 1668 int 1669 show_rib_memory_msg(struct imsg *imsg) 1670 { 1671 struct rde_memstats stats; 1672 size_t pts = 0; 1673 int i; 1674 1675 switch (imsg->hdr.type) { 1676 case IMSG_CTL_SHOW_RIB_MEM: 1677 memcpy(&stats, imsg->data, sizeof(stats)); 1678 printf("RDE memory statistics\n"); 1679 for (i = 0; i < AID_MAX; i++) { 1680 if (stats.pt_cnt[i] == 0) 1681 continue; 1682 pts += stats.pt_cnt[i] * pt_sizes[i]; 1683 printf("%10lld %s network entries using %s of memory\n", 1684 (long long)stats.pt_cnt[i], aid_vals[i].name, 1685 fmt_mem(stats.pt_cnt[i] * pt_sizes[i])); 1686 } 1687 printf("%10lld rib entries using %s of memory\n", 1688 (long long)stats.rib_cnt, fmt_mem(stats.rib_cnt * 1689 sizeof(struct rib_entry))); 1690 printf("%10lld prefix entries using %s of memory\n", 1691 (long long)stats.prefix_cnt, fmt_mem(stats.prefix_cnt * 1692 sizeof(struct prefix))); 1693 printf("%10lld BGP path attribute entries using %s of memory\n", 1694 (long long)stats.path_cnt, fmt_mem(stats.path_cnt * 1695 sizeof(struct rde_aspath))); 1696 printf("%10lld BGP AS-PATH attribute entries using " 1697 "%s of memory,\n\t and holding %lld references\n", 1698 (long long)stats.aspath_cnt, fmt_mem(stats.aspath_size), 1699 (long long)stats.aspath_refs); 1700 printf("%10lld BGP attributes entries using %s of memory\n", 1701 (long long)stats.attr_cnt, fmt_mem(stats.attr_cnt * 1702 sizeof(struct attr))); 1703 printf("\t and holding %lld references\n", 1704 (long long)stats.attr_refs); 1705 printf("%10lld BGP attributes using %s of memory\n", 1706 (long long)stats.attr_dcnt, fmt_mem(stats.attr_data)); 1707 printf("RIB using %s of memory\n", fmt_mem(pts + 1708 stats.prefix_cnt * sizeof(struct prefix) + 1709 stats.rib_cnt * sizeof(struct rib_entry) + 1710 stats.path_cnt * sizeof(struct rde_aspath) + 1711 stats.aspath_size + stats.attr_cnt * sizeof(struct attr) + 1712 stats.attr_data)); 1713 break; 1714 default: 1715 break; 1716 } 1717 1718 return (1); 1719 } 1720 1721 void 1722 send_filterset(struct imsgbuf *i, struct filter_set_head *set) 1723 { 1724 struct filter_set *s; 1725 1726 while ((s = TAILQ_FIRST(set)) != NULL) { 1727 imsg_compose(i, IMSG_FILTER_SET, 0, 0, -1, s, 1728 sizeof(struct filter_set)); 1729 TAILQ_REMOVE(set, s, entry); 1730 free(s); 1731 } 1732 } 1733 1734 const char * 1735 get_errstr(u_int8_t errcode, u_int8_t subcode) 1736 { 1737 static const char *errstr = NULL; 1738 1739 if (errcode && errcode < sizeof(errnames)/sizeof(char *)) 1740 errstr = errnames[errcode]; 1741 1742 switch (errcode) { 1743 case ERR_HEADER: 1744 if (subcode && 1745 subcode < sizeof(suberr_header_names)/sizeof(char *)) 1746 errstr = suberr_header_names[subcode]; 1747 break; 1748 case ERR_OPEN: 1749 if (subcode && 1750 subcode < sizeof(suberr_open_names)/sizeof(char *)) 1751 errstr = suberr_open_names[subcode]; 1752 break; 1753 case ERR_UPDATE: 1754 if (subcode && 1755 subcode < sizeof(suberr_update_names)/sizeof(char *)) 1756 errstr = suberr_update_names[subcode]; 1757 break; 1758 case ERR_HOLDTIMEREXPIRED: 1759 case ERR_FSM: 1760 case ERR_CEASE: 1761 break; 1762 default: 1763 return ("unknown error code"); 1764 } 1765 1766 return (errstr); 1767 } 1768 1769 int 1770 show_result(struct imsg *imsg) 1771 { 1772 u_int rescode; 1773 1774 if (imsg->hdr.len != IMSG_HEADER_SIZE + sizeof(rescode)) 1775 errx(1, "got IMSG_CTL_RESULT with wrong len"); 1776 memcpy(&rescode, imsg->data, sizeof(rescode)); 1777 1778 if (rescode == 0) 1779 printf("request processed\n"); 1780 else { 1781 if (rescode > 1782 sizeof(ctl_res_strerror)/sizeof(ctl_res_strerror[0])) 1783 printf("unknown result error code %u\n", rescode); 1784 else 1785 printf("%s\n", ctl_res_strerror[rescode]); 1786 } 1787 1788 return (1); 1789 } 1790 1791 void 1792 network_bulk(struct parse_result *res) 1793 { 1794 struct network_config net; 1795 struct filter_set *s = NULL; 1796 struct bgpd_addr h; 1797 char *b, *buf, *lbuf; 1798 size_t slen; 1799 u_int8_t len; 1800 FILE *f; 1801 1802 if ((f = fdopen(STDIN_FILENO, "r")) != NULL) { 1803 while ((buf = fgetln(f, &slen))) { 1804 lbuf = NULL; 1805 if (buf[slen - 1] == '\n') 1806 buf[slen - 1] = '\0'; 1807 else { 1808 if ((lbuf = malloc(slen + 1)) == NULL) 1809 err(1, NULL); 1810 memcpy(lbuf, buf, slen); 1811 lbuf[slen] = '\0'; 1812 buf = lbuf; 1813 } 1814 1815 while ((b = strsep(&buf, " \t")) != NULL) { 1816 /* Don't process commented entries */ 1817 if (strchr(b, '#') != NULL) 1818 break; 1819 bzero(&net, sizeof(net)); 1820 parse_prefix(b, strlen(b), &h, &len); 1821 net.prefix = h; 1822 net.prefixlen = len; 1823 1824 if (res->action == NETWORK_BULK_ADD) { 1825 imsg_compose(ibuf, IMSG_NETWORK_ADD, 1826 0, 0, -1, &net, sizeof(net)); 1827 TAILQ_FOREACH(s, &res->set, entry) { 1828 imsg_compose(ibuf, 1829 IMSG_FILTER_SET, 1830 0, 0, -1, s, sizeof(*s)); 1831 } 1832 imsg_compose(ibuf, IMSG_NETWORK_DONE, 1833 0, 0, -1, NULL, 0); 1834 } else 1835 imsg_compose(ibuf, IMSG_NETWORK_REMOVE, 1836 0, 0, -1, &net, sizeof(net)); 1837 } 1838 free(lbuf); 1839 } 1840 fclose(f); 1841 } else { 1842 err(1, "Failed to open stdin\n"); 1843 } 1844 } 1845 1846 void 1847 show_mrt_dump(struct mrt_rib *mr, struct mrt_peer *mp, void *arg) 1848 { 1849 struct ctl_show_rib ctl; 1850 struct ctl_show_rib_request *req = arg; 1851 struct mrt_rib_entry *mre; 1852 u_int16_t i, j; 1853 1854 for (i = 0; i < mr->nentries; i++) { 1855 mre = &mr->entries[i]; 1856 bzero(&ctl, sizeof(ctl)); 1857 mrt_to_bgpd_addr(&mr->prefix, &ctl.prefix); 1858 ctl.prefixlen = mr->prefixlen; 1859 ctl.lastchange = mre->originated; 1860 mrt_to_bgpd_addr(&mre->nexthop, &ctl.true_nexthop); 1861 mrt_to_bgpd_addr(&mre->nexthop, &ctl.exit_nexthop); 1862 ctl.origin = mre->origin; 1863 ctl.local_pref = mre->local_pref; 1864 ctl.med = mre->med; 1865 /* weight is not part of the mrt dump so it can't be set */ 1866 ctl.aspath_len = mre->aspath_len; 1867 1868 if (mre->peer_idx < mp->npeers) { 1869 mrt_to_bgpd_addr(&mp->peers[mre->peer_idx].addr, 1870 &ctl.remote_addr); 1871 ctl.remote_id = mp->peers[mre->peer_idx].bgp_id; 1872 } 1873 1874 /* filter by neighbor */ 1875 if (req->neighbor.addr.aid != AID_UNSPEC && 1876 memcmp(&req->neighbor.addr, &ctl.remote_addr, 1877 sizeof(ctl.remote_addr)) != 0) 1878 continue; 1879 /* filter by AF */ 1880 if (req->aid && req->aid != ctl.prefix.aid) 1881 return; 1882 /* filter by prefix */ 1883 if (req->prefix.aid != AID_UNSPEC) { 1884 if (!prefix_compare(&req->prefix, &ctl.prefix, 1885 req->prefixlen)) { 1886 if (req->flags & F_LONGER) { 1887 if (req->prefixlen > ctl.prefixlen) 1888 return; 1889 } else if (req->prefixlen != ctl.prefixlen) 1890 return; 1891 } else 1892 return; 1893 } 1894 /* filter by AS */ 1895 if (req->as.type != AS_NONE && 1896 !aspath_match(mre->aspath, mre->aspath_len, 1897 &req->as, req->as.as)) 1898 continue; 1899 1900 if (req->flags & F_CTL_DETAIL) { 1901 show_rib_detail(&ctl, mre->aspath, 1); 1902 for (j = 0; j < mre->nattrs; j++) 1903 show_attr(mre->attrs[j].attr, 1904 mre->attrs[j].attr_len); 1905 } else 1906 show_rib_brief(&ctl, mre->aspath); 1907 } 1908 } 1909 1910 void 1911 network_mrt_dump(struct mrt_rib *mr, struct mrt_peer *mp, void *arg) 1912 { 1913 struct ctl_show_rib ctl; 1914 struct network_config net; 1915 struct ctl_show_rib_request *req = arg; 1916 struct mrt_rib_entry *mre; 1917 struct ibuf *msg; 1918 u_int16_t i, j; 1919 1920 for (i = 0; i < mr->nentries; i++) { 1921 mre = &mr->entries[i]; 1922 bzero(&ctl, sizeof(ctl)); 1923 mrt_to_bgpd_addr(&mr->prefix, &ctl.prefix); 1924 ctl.prefixlen = mr->prefixlen; 1925 ctl.lastchange = mre->originated; 1926 mrt_to_bgpd_addr(&mre->nexthop, &ctl.true_nexthop); 1927 mrt_to_bgpd_addr(&mre->nexthop, &ctl.exit_nexthop); 1928 ctl.origin = mre->origin; 1929 ctl.local_pref = mre->local_pref; 1930 ctl.med = mre->med; 1931 ctl.aspath_len = mre->aspath_len; 1932 1933 if (mre->peer_idx < mp->npeers) { 1934 mrt_to_bgpd_addr(&mp->peers[mre->peer_idx].addr, 1935 &ctl.remote_addr); 1936 ctl.remote_id = mp->peers[mre->peer_idx].bgp_id; 1937 } 1938 1939 /* filter by neighbor */ 1940 if (req->neighbor.addr.aid != AID_UNSPEC && 1941 memcmp(&req->neighbor.addr, &ctl.remote_addr, 1942 sizeof(ctl.remote_addr)) != 0) 1943 continue; 1944 /* filter by AF */ 1945 if (req->aid && req->aid != ctl.prefix.aid) 1946 return; 1947 /* filter by prefix */ 1948 if (req->prefix.aid != AID_UNSPEC) { 1949 if (!prefix_compare(&req->prefix, &ctl.prefix, 1950 req->prefixlen)) { 1951 if (req->flags & F_LONGER) { 1952 if (req->prefixlen > ctl.prefixlen) 1953 return; 1954 } else if (req->prefixlen != ctl.prefixlen) 1955 return; 1956 } else 1957 return; 1958 } 1959 /* filter by AS */ 1960 if (req->as.type != AS_NONE && 1961 !aspath_match(mre->aspath, mre->aspath_len, 1962 &req->as, req->as.as)) 1963 continue; 1964 1965 bzero(&net, sizeof(net)); 1966 net.prefix = ctl.prefix; 1967 net.prefixlen = ctl.prefixlen; 1968 net.type = NETWORK_MRTCLONE; 1969 /* XXX rtableid */ 1970 1971 imsg_compose(ibuf, IMSG_NETWORK_ADD, 0, 0, -1, 1972 &net, sizeof(net)); 1973 if ((msg = imsg_create(ibuf, IMSG_NETWORK_ASPATH, 1974 0, 0, sizeof(ctl) + mre->aspath_len)) == NULL) 1975 errx(1, "imsg_create failure"); 1976 if (imsg_add(msg, &ctl, sizeof(ctl)) == -1 || 1977 imsg_add(msg, mre->aspath, mre->aspath_len) == -1) 1978 errx(1, "imsg_add failure"); 1979 imsg_close(ibuf, msg); 1980 for (j = 0; j < mre->nattrs; j++) 1981 imsg_compose(ibuf, IMSG_NETWORK_ATTR, 0, 0, -1, 1982 mre->attrs[j].attr, mre->attrs[j].attr_len); 1983 imsg_compose(ibuf, IMSG_NETWORK_DONE, 0, 0, -1, NULL, 0); 1984 1985 while (ibuf->w.queued) { 1986 if (msgbuf_write(&ibuf->w) <= 0 && errno != EAGAIN) 1987 err(1, "write error"); 1988 } 1989 } 1990 } 1991 1992 void 1993 show_mrt_state(struct mrt_bgp_state *ms, void *arg) 1994 { 1995 struct bgpd_addr src, dst; 1996 1997 mrt_to_bgpd_addr(&ms->src, &src); 1998 mrt_to_bgpd_addr(&ms->dst, &dst); 1999 printf("%s[%u] -> ", log_addr(&src), ms->src_as); 2000 printf("%s[%u]: %s -> %s\n", log_addr(&dst), ms->dst_as, 2001 statenames[ms->old_state], statenames[ms->new_state]); 2002 } 2003 2004 void 2005 show_mrt_msg(struct mrt_bgp_msg *mm, void *arg) 2006 { 2007 struct bgpd_addr src, dst; 2008 2009 mrt_to_bgpd_addr(&mm->src, &src); 2010 mrt_to_bgpd_addr(&mm->dst, &dst); 2011 printf("%s[%u] -> ", log_addr(&src), mm->src_as); 2012 printf("%s[%u]: size %u\n", log_addr(&dst), mm->dst_as, mm->msg_len); 2013 } 2014 2015 void 2016 mrt_to_bgpd_addr(union mrt_addr *ma, struct bgpd_addr *ba) 2017 { 2018 switch (ma->sa.sa_family) { 2019 case AF_INET: 2020 case AF_INET6: 2021 sa2addr(&ma->sa, ba); 2022 break; 2023 case AF_VPNv4: 2024 bzero(ba, sizeof(*ba)); 2025 ba->aid = AID_VPN_IPv4; 2026 ba->vpn4.rd = ma->svpn4.sv_rd; 2027 ba->vpn4.addr.s_addr = ma->svpn4.sv_addr.s_addr; 2028 memcpy(ba->vpn4.labelstack, ma->svpn4.sv_label, 2029 sizeof(ba->vpn4.labelstack)); 2030 break; 2031 } 2032 } 2033 2034 const char * 2035 msg_type(u_int8_t type) 2036 { 2037 if (type >= sizeof(msgtypenames)/sizeof(msgtypenames[0])) 2038 return "BAD"; 2039 return (msgtypenames[type]); 2040 } 2041