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