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