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