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