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