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