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