1 /* $OpenBSD: ospf6ctl.c,v 1.36 2011/05/05 15:58:53 claudio Exp $ */ 2 3 /* 4 * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org> 5 * Copyright (c) 2004, 2005 Esben Norby <norby@openbsd.org> 6 * Copyright (c) 2003 Henning Brauer <henning@openbsd.org> 7 * 8 * Permission to use, copy, modify, and distribute this software for any 9 * purpose with or without fee is hereby granted, provided that the above 10 * copyright notice and this permission notice appear in all copies. 11 * 12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 13 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 14 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 15 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 16 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 17 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 18 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 19 */ 20 21 #include <sys/types.h> 22 #include <sys/socket.h> 23 #include <sys/un.h> 24 #include <netinet/in.h> 25 #include <arpa/inet.h> 26 #include <net/if_media.h> 27 #include <net/if_types.h> 28 29 #include <err.h> 30 #include <stdio.h> 31 #include <stdlib.h> 32 #include <string.h> 33 #include <unistd.h> 34 35 #include "ospf6.h" 36 #include "ospf6d.h" 37 #include "ospfe.h" 38 #include "parser.h" 39 #include "log.h" 40 41 __dead void usage(void); 42 int show_summary_msg(struct imsg *); 43 int get_ifms_type(int); 44 int show_interface_msg(struct imsg *); 45 int show_interface_detail_msg(struct imsg *); 46 const char *print_link(int); 47 const char *fmt_timeframe(time_t t); 48 const char *fmt_timeframe_core(time_t t); 49 const char *log_id(u_int32_t ); 50 const char *log_adv_rtr(u_int32_t); 51 void show_database_head(struct in_addr, char *, u_int16_t); 52 int show_database_msg(struct imsg *); 53 char *print_ls_type(u_int16_t); 54 void show_db_hdr_msg_detail(struct lsa_hdr *); 55 char *print_rtr_link_type(u_int8_t); 56 const char *print_ospf_flags(u_int8_t); 57 const char *print_asext_flags(u_int32_t); 58 const char *print_prefix_opt(u_int8_t); 59 int show_db_msg_detail(struct imsg *imsg); 60 int show_nbr_msg(struct imsg *); 61 const char *print_ospf_options(u_int32_t); 62 int show_nbr_detail_msg(struct imsg *); 63 int show_rib_msg(struct imsg *); 64 void show_rib_head(struct in_addr, u_int8_t, u_int8_t); 65 const char *print_ospf_rtr_flags(u_int8_t); 66 int show_rib_detail_msg(struct imsg *); 67 void show_fib_head(void); 68 int show_fib_msg(struct imsg *); 69 const char * get_media_descr(int); 70 const char * get_linkstate(int, int); 71 void print_baudrate(u_int64_t); 72 73 struct imsgbuf *ibuf; 74 75 __dead void 76 usage(void) 77 { 78 extern char *__progname; 79 80 fprintf(stderr, "usage: %s command [argument ...]\n", __progname); 81 exit(1); 82 } 83 84 int 85 main(int argc, char *argv[]) 86 { 87 struct sockaddr_un sun; 88 struct parse_result *res; 89 struct imsg imsg; 90 unsigned int ifidx = 0; 91 int ctl_sock; 92 int done = 0, verbose = 0; 93 int n; 94 95 /* parse options */ 96 if ((res = parse(argc - 1, argv + 1)) == NULL) 97 exit(1); 98 99 /* connect to ospf6d control socket */ 100 if ((ctl_sock = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) 101 err(1, "socket"); 102 103 bzero(&sun, sizeof(sun)); 104 sun.sun_family = AF_UNIX; 105 strlcpy(sun.sun_path, OSPF6D_SOCKET, sizeof(sun.sun_path)); 106 if (connect(ctl_sock, (struct sockaddr *)&sun, sizeof(sun)) == -1) 107 err(1, "connect: %s", OSPF6D_SOCKET); 108 109 if ((ibuf = malloc(sizeof(struct imsgbuf))) == NULL) 110 err(1, NULL); 111 imsg_init(ibuf, ctl_sock); 112 done = 0; 113 114 /* process user request */ 115 switch (res->action) { 116 case NONE: 117 usage(); 118 /* not reached */ 119 case SHOW: 120 case SHOW_SUM: 121 imsg_compose(ibuf, IMSG_CTL_SHOW_SUM, 0, 0, -1, NULL, 0); 122 break; 123 case SHOW_IFACE: 124 printf("%-11s %-29s %-6s %-10s %-10s %-8s\n", 125 "Interface", "Address", "State", "HelloTimer", "Linkstate", 126 "Uptime"); 127 /*FALLTHROUGH*/ 128 case SHOW_IFACE_DTAIL: 129 if (*res->ifname) { 130 ifidx = if_nametoindex(res->ifname); 131 if (ifidx == 0) 132 errx(1, "no such interface %s", res->ifname); 133 } 134 imsg_compose(ibuf, IMSG_CTL_SHOW_INTERFACE, 0, 0, -1, 135 &ifidx, sizeof(ifidx)); 136 break; 137 case SHOW_NBR: 138 printf("%-15s %-3s %-12s %-9s %-11s %s\n", "ID", "Pri", 139 "State", "DeadTime", "Iface","Uptime"); 140 /*FALLTHROUGH*/ 141 case SHOW_NBR_DTAIL: 142 imsg_compose(ibuf, IMSG_CTL_SHOW_NBR, 0, 0, -1, NULL, 0); 143 break; 144 case SHOW_DB: 145 imsg_compose(ibuf, IMSG_CTL_SHOW_DATABASE, 0, 0, -1, NULL, 0); 146 break; 147 case SHOW_DBBYAREA: 148 imsg_compose(ibuf, IMSG_CTL_SHOW_DATABASE, 0, 0, -1, 149 &res->addr, sizeof(res->addr)); 150 break; 151 case SHOW_DBEXT: 152 imsg_compose(ibuf, IMSG_CTL_SHOW_DB_EXT, 0, 0, -1, NULL, 0); 153 break; 154 case SHOW_DBLINK: 155 imsg_compose(ibuf, IMSG_CTL_SHOW_DB_LINK, 0, 0, -1, NULL, 0); 156 break; 157 case SHOW_DBNET: 158 imsg_compose(ibuf, IMSG_CTL_SHOW_DB_NET, 0, 0, -1, NULL, 0); 159 break; 160 case SHOW_DBRTR: 161 imsg_compose(ibuf, IMSG_CTL_SHOW_DB_RTR, 0, 0, -1, NULL, 0); 162 break; 163 case SHOW_DBINTRA: 164 imsg_compose(ibuf, IMSG_CTL_SHOW_DB_INTRA, 0, 0, -1, NULL, 0); 165 break; 166 case SHOW_DBSELF: 167 imsg_compose(ibuf, IMSG_CTL_SHOW_DB_SELF, 0, 0, -1, NULL, 0); 168 break; 169 case SHOW_DBSUM: 170 imsg_compose(ibuf, IMSG_CTL_SHOW_DB_SUM, 0, 0, -1, NULL, 0); 171 break; 172 case SHOW_DBASBR: 173 imsg_compose(ibuf, IMSG_CTL_SHOW_DB_ASBR, 0, 0, -1, NULL, 0); 174 break; 175 case SHOW_RIB: 176 printf("%-20s %-17s %-12s %-9s %-7s %-8s\n", "Destination", 177 "Nexthop", "Path Type", "Type", "Cost", "Uptime"); 178 /*FALLTHROUGH*/ 179 case SHOW_RIB_DTAIL: 180 imsg_compose(ibuf, IMSG_CTL_SHOW_RIB, 0, 0, -1, NULL, 0); 181 break; 182 case SHOW_FIB: 183 if (IN6_IS_ADDR_UNSPECIFIED(&res->addr)) 184 imsg_compose(ibuf, IMSG_CTL_KROUTE, 0, 0, -1, 185 &res->flags, sizeof(res->flags)); 186 else 187 imsg_compose(ibuf, IMSG_CTL_KROUTE_ADDR, 0, 0, -1, 188 &res->addr, sizeof(res->addr)); 189 show_fib_head(); 190 break; 191 case FIB: 192 errx(1, "fib couple|decouple"); 193 break; 194 case FIB_COUPLE: 195 imsg_compose(ibuf, IMSG_CTL_FIB_COUPLE, 0, 0, -1, NULL, 0); 196 printf("couple request sent.\n"); 197 done = 1; 198 break; 199 case FIB_DECOUPLE: 200 imsg_compose(ibuf, IMSG_CTL_FIB_DECOUPLE, 0, 0, -1, NULL, 0); 201 printf("decouple request sent.\n"); 202 done = 1; 203 break; 204 case LOG_VERBOSE: 205 verbose = 1; 206 /* FALLTHROUGH */ 207 case LOG_BRIEF: 208 imsg_compose(ibuf, IMSG_CTL_LOG_VERBOSE, 0, 0, -1, 209 &verbose, sizeof(verbose)); 210 printf("logging request sent.\n"); 211 done = 1; 212 break; 213 case RELOAD: 214 imsg_compose(ibuf, IMSG_CTL_RELOAD, 0, 0, -1, NULL, 0); 215 printf("reload request sent.\n"); 216 done = 1; 217 break; 218 } 219 220 while (ibuf->w.queued) 221 if (msgbuf_write(&ibuf->w) < 0) 222 err(1, "write error"); 223 224 while (!done) { 225 if ((n = imsg_read(ibuf)) == -1) 226 errx(1, "imsg_read error"); 227 if (n == 0) 228 errx(1, "pipe closed"); 229 230 while (!done) { 231 if ((n = imsg_get(ibuf, &imsg)) == -1) 232 errx(1, "imsg_get error"); 233 if (n == 0) 234 break; 235 switch (res->action) { 236 case SHOW: 237 case SHOW_SUM: 238 done = show_summary_msg(&imsg); 239 break; 240 case SHOW_IFACE: 241 done = show_interface_msg(&imsg); 242 break; 243 case SHOW_IFACE_DTAIL: 244 done = show_interface_detail_msg(&imsg); 245 break; 246 case SHOW_NBR: 247 done = show_nbr_msg(&imsg); 248 break; 249 case SHOW_NBR_DTAIL: 250 done = show_nbr_detail_msg(&imsg); 251 break; 252 case SHOW_DB: 253 case SHOW_DBBYAREA: 254 case SHOW_DBSELF: 255 done = show_database_msg(&imsg); 256 break; 257 case SHOW_DBEXT: 258 case SHOW_DBLINK: 259 case SHOW_DBNET: 260 case SHOW_DBRTR: 261 case SHOW_DBINTRA: 262 case SHOW_DBSUM: 263 case SHOW_DBASBR: 264 done = show_db_msg_detail(&imsg); 265 break; 266 case SHOW_RIB: 267 done = show_rib_msg(&imsg); 268 break; 269 case SHOW_RIB_DTAIL: 270 done = show_rib_detail_msg(&imsg); 271 break; 272 case SHOW_FIB: 273 done = show_fib_msg(&imsg); 274 break; 275 case NONE: 276 case FIB: 277 case FIB_COUPLE: 278 case FIB_DECOUPLE: 279 case LOG_VERBOSE: 280 case LOG_BRIEF: 281 case RELOAD: 282 break; 283 } 284 imsg_free(&imsg); 285 } 286 } 287 close(ctl_sock); 288 free(ibuf); 289 290 return (0); 291 } 292 293 int 294 show_summary_msg(struct imsg *imsg) 295 { 296 struct ctl_sum *sum; 297 struct ctl_sum_area *sumarea; 298 299 switch (imsg->hdr.type) { 300 case IMSG_CTL_SHOW_SUM: 301 sum = imsg->data; 302 printf("Router ID: %s\n", inet_ntoa(sum->rtr_id)); 303 printf("Uptime: %s\n", fmt_timeframe_core(sum->uptime)); 304 305 printf("SPF delay is %d sec(s), hold time between two SPFs " 306 "is %d sec(s)\n", sum->spf_delay, sum->spf_hold_time); 307 printf("Number of external LSA(s) %d\n", sum->num_ext_lsa); 308 printf("Number of areas attached to this router: %d\n", 309 sum->num_area); 310 break; 311 case IMSG_CTL_SHOW_SUM_AREA: 312 sumarea = imsg->data; 313 printf("\nArea ID: %s\n", inet_ntoa(sumarea->area)); 314 printf(" Number of interfaces in this area: %d\n", 315 sumarea->num_iface); 316 printf(" Number of fully adjacent neighbors in this " 317 "area: %d\n", sumarea->num_adj_nbr); 318 printf(" SPF algorithm executed %d time(s)\n", 319 sumarea->num_spf_calc); 320 printf(" Number LSA(s) %d\n", sumarea->num_lsa); 321 break; 322 case IMSG_CTL_END: 323 printf("\n"); 324 return (1); 325 default: 326 break; 327 } 328 329 return (0); 330 } 331 332 int 333 get_ifms_type(int mediatype) 334 { 335 switch (mediatype) { 336 case IFT_ETHER: 337 return (IFM_ETHER); 338 case IFT_FDDI: 339 return (IFM_FDDI); 340 case IFT_CARP: 341 return (IFM_CARP); 342 case IFT_PPP: 343 return (IFM_TDM); 344 default: 345 return (0); 346 } 347 } 348 349 int 350 show_interface_msg(struct imsg *imsg) 351 { 352 struct ctl_iface *iface; 353 char *netid; 354 355 switch (imsg->hdr.type) { 356 case IMSG_CTL_SHOW_INTERFACE: 357 iface = imsg->data; 358 359 if (asprintf(&netid, "%s", log_in6addr(&iface->addr)) == -1) 360 err(1, NULL); 361 printf("%-11s %-29s %-6s %-10s %-10s %s\n", 362 iface->name, netid, if_state_name(iface->state), 363 fmt_timeframe_core(iface->hello_timer), 364 get_linkstate(iface->mediatype, iface->linkstate), 365 fmt_timeframe_core(iface->uptime)); 366 free(netid); 367 break; 368 case IMSG_CTL_END: 369 printf("\n"); 370 return (1); 371 default: 372 break; 373 } 374 375 return (0); 376 } 377 378 int 379 show_interface_detail_msg(struct imsg *imsg) 380 { 381 struct ctl_iface *iface; 382 383 switch (imsg->hdr.type) { 384 case IMSG_CTL_SHOW_INTERFACE: 385 iface = imsg->data; 386 printf("\n"); 387 printf("Interface %s, line protocol is %s\n", 388 iface->name, print_link(iface->flags)); 389 printf(" Internet address %s Area %s\n", 390 log_in6addr(&iface->addr), inet_ntoa(iface->area)); 391 printf(" Link type %s, state %s", 392 get_media_descr(get_ifms_type(iface->mediatype)), 393 get_linkstate(iface->mediatype, iface->linkstate)); 394 if (iface->linkstate != LINK_STATE_DOWN && 395 iface->baudrate > 0) { 396 printf(", "); 397 print_baudrate(iface->baudrate); 398 } 399 printf("\n"); 400 printf(" Router ID %s, network type %s, cost: %d\n", 401 inet_ntoa(iface->rtr_id), 402 if_type_name(iface->type), iface->metric); 403 printf(" Transmit delay is %d sec(s), state %s, priority %d\n", 404 iface->transmit_delay, if_state_name(iface->state), 405 iface->priority); 406 printf(" Designated Router (ID) %s\n", 407 inet_ntoa(iface->dr_id)); 408 printf(" Interface address %s\n", 409 log_in6addr(&iface->dr_addr)); 410 printf(" Backup Designated Router (ID) %s\n", 411 inet_ntoa(iface->bdr_id)); 412 printf(" Interface address %s\n", 413 log_in6addr(&iface->bdr_addr)); 414 printf(" Timer intervals configured, " 415 "hello %d, dead %d, wait %d, retransmit %d\n", 416 iface->hello_interval, iface->dead_interval, 417 iface->dead_interval, iface->rxmt_interval); 418 if (iface->passive) 419 printf(" Passive interface (No Hellos)\n"); 420 else if (iface->hello_timer < 0) 421 printf(" Hello timer not running\n"); 422 else 423 printf(" Hello timer due in %s\n", 424 fmt_timeframe_core(iface->hello_timer)); 425 printf(" Uptime %s\n", fmt_timeframe_core(iface->uptime)); 426 printf(" Neighbor count is %d, adjacent neighbor count is " 427 "%d\n", iface->nbr_cnt, iface->adj_cnt); 428 break; 429 case IMSG_CTL_END: 430 printf("\n"); 431 return (1); 432 default: 433 break; 434 } 435 436 return (0); 437 } 438 439 const char * 440 print_link(int state) 441 { 442 if (state & IFF_UP) 443 return ("UP"); 444 else 445 return ("DOWN"); 446 } 447 448 #define TF_BUFS 8 449 #define TF_LEN 9 450 451 const char * 452 fmt_timeframe(time_t t) 453 { 454 if (t == 0) 455 return ("Never"); 456 else 457 return (fmt_timeframe_core(time(NULL) - t)); 458 } 459 460 const char * 461 fmt_timeframe_core(time_t t) 462 { 463 char *buf; 464 static char tfbuf[TF_BUFS][TF_LEN]; /* ring buffer */ 465 static int idx = 0; 466 unsigned int sec, min, hrs, day, week; 467 468 if (t == 0) 469 return ("00:00:00"); 470 471 buf = tfbuf[idx++]; 472 if (idx == TF_BUFS) 473 idx = 0; 474 475 week = t; 476 477 sec = week % 60; 478 week /= 60; 479 min = week % 60; 480 week /= 60; 481 hrs = week % 24; 482 week /= 24; 483 day = week % 7; 484 week /= 7; 485 486 if (week > 0) 487 snprintf(buf, TF_LEN, "%02uw%01ud%02uh", week, day, hrs); 488 else if (day > 0) 489 snprintf(buf, TF_LEN, "%01ud%02uh%02um", day, hrs, min); 490 else 491 snprintf(buf, TF_LEN, "%02u:%02u:%02u", hrs, min, sec); 492 493 return (buf); 494 } 495 496 const char * 497 log_id(u_int32_t id) 498 { 499 static char buf[48]; 500 struct in_addr addr; 501 502 addr.s_addr = id; 503 504 if (inet_ntop(AF_INET, &addr, buf, sizeof(buf)) == NULL) 505 return ("?"); 506 else 507 return (buf); 508 } 509 510 const char * 511 log_adv_rtr(u_int32_t adv_rtr) 512 { 513 static char buf[48]; 514 struct in_addr addr; 515 516 addr.s_addr = adv_rtr; 517 518 if (inet_ntop(AF_INET, &addr, buf, sizeof(buf)) == NULL) 519 return ("?"); 520 else 521 return (buf); 522 } 523 524 void 525 show_database_head(struct in_addr aid, char *ifname, u_int16_t type) 526 { 527 char *header, *format; 528 int cleanup = 0; 529 530 switch (ntohs(type)) { 531 case LSA_TYPE_LINK: 532 format = "Link (Type-8) Link States"; 533 break; 534 case LSA_TYPE_ROUTER: 535 format = "Router Link States"; 536 break; 537 case LSA_TYPE_NETWORK: 538 format = "Net Link States"; 539 break; 540 case LSA_TYPE_INTER_A_PREFIX: 541 format = "Inter Area Prefix Link States"; 542 break; 543 case LSA_TYPE_INTER_A_ROUTER: 544 format = "Inter Area Router Link States"; 545 break; 546 case LSA_TYPE_INTRA_A_PREFIX: 547 format = "Intra Area Prefix Link States"; 548 break; 549 case LSA_TYPE_EXTERNAL: 550 printf("\n%-15s %s\n\n", "", "Type-5 AS External Link States"); 551 return; 552 default: 553 if (asprintf(&format, "LSA type %x", ntohs(type)) == -1) 554 err(1, NULL); 555 cleanup = 1; 556 break; 557 } 558 if (LSA_IS_SCOPE_AREA(ntohs(type))) { 559 if (asprintf(&header, "%s (Area %s)", format, 560 inet_ntoa(aid)) == -1) 561 err(1, NULL); 562 } else if (LSA_IS_SCOPE_LLOCAL(ntohs(type))) { 563 if (asprintf(&header, "%s (Area %s Interface %s)", format, 564 inet_ntoa(aid), ifname) == -1) 565 err(1, NULL); 566 } 567 568 printf("\n%-15s %s\n\n", "", header); 569 free(header); 570 if (cleanup) 571 free(format); 572 } 573 574 int 575 show_database_msg(struct imsg *imsg) 576 { 577 static struct in_addr area_id; 578 static char ifname[IF_NAMESIZE]; 579 static u_int16_t lasttype; 580 struct area *area; 581 struct iface *iface; 582 struct lsa_hdr *lsa; 583 584 switch (imsg->hdr.type) { 585 case IMSG_CTL_SHOW_DATABASE: 586 case IMSG_CTL_SHOW_DB_SELF: 587 lsa = imsg->data; 588 if (lsa->type != lasttype) { 589 show_database_head(area_id, ifname, lsa->type); 590 printf("%-15s %-15s %-4s %-10s %-8s\n", "Link ID", 591 "Adv Router", "Age", "Seq#", "Checksum"); 592 } 593 printf("%-15s %-15s %-4d 0x%08x 0x%04x\n", 594 log_id(lsa->ls_id), log_adv_rtr(lsa->adv_rtr), 595 ntohs(lsa->age), ntohl(lsa->seq_num), 596 ntohs(lsa->ls_chksum)); 597 lasttype = lsa->type; 598 break; 599 case IMSG_CTL_AREA: 600 area = imsg->data; 601 area_id = area->id; 602 lasttype = 0; 603 break; 604 case IMSG_CTL_IFACE: 605 iface = imsg->data; 606 strlcpy(ifname, iface->name, sizeof(ifname)); 607 lasttype = 0; 608 break; 609 case IMSG_CTL_END: 610 printf("\n"); 611 return (1); 612 default: 613 break; 614 } 615 616 return (0); 617 } 618 619 char * 620 print_ls_type(u_int16_t type) 621 { 622 switch (ntohs(type)) { 623 case LSA_TYPE_LINK: 624 return ("Link"); 625 case LSA_TYPE_ROUTER: 626 return ("Router"); 627 case LSA_TYPE_NETWORK: 628 return ("Network"); 629 case LSA_TYPE_INTER_A_PREFIX: 630 return ("Inter Area (Prefix)"); 631 case LSA_TYPE_INTER_A_ROUTER: 632 return ("Inter Area (Router)"); 633 case LSA_TYPE_INTRA_A_PREFIX: 634 return ("Intra Area (Prefix)"); 635 case LSA_TYPE_EXTERNAL: 636 return ("AS External"); 637 default: 638 return ("Unknown"); 639 } 640 } 641 642 void 643 show_db_hdr_msg_detail(struct lsa_hdr *lsa) 644 { 645 printf("LS age: %d\n", ntohs(lsa->age)); 646 printf("LS Type: %s\n", print_ls_type(lsa->type)); 647 648 switch (ntohs(lsa->type)) { 649 case LSA_TYPE_ROUTER: 650 case LSA_TYPE_INTER_A_PREFIX: 651 case LSA_TYPE_INTER_A_ROUTER: 652 case LSA_TYPE_INTRA_A_PREFIX: 653 case LSA_TYPE_EXTERNAL: 654 printf("Link State ID: %s\n", log_id(lsa->ls_id)); 655 break; 656 case LSA_TYPE_LINK: 657 printf("Link State ID: %s (Interface ID of Advertising " 658 "Router)\n", log_id(lsa->ls_id)); 659 break; 660 case LSA_TYPE_NETWORK: 661 printf("Link State ID: %s (Interface ID of Designated " 662 "Router)\n", log_id(lsa->ls_id)); 663 break; 664 } 665 666 printf("Advertising Router: %s\n", log_adv_rtr(lsa->adv_rtr)); 667 printf("LS Seq Number: 0x%08x\n", ntohl(lsa->seq_num)); 668 printf("Checksum: 0x%04x\n", ntohs(lsa->ls_chksum)); 669 printf("Length: %d\n", ntohs(lsa->len)); 670 } 671 672 char * 673 print_rtr_link_type(u_int8_t type) 674 { 675 switch (type) { 676 case LINK_TYPE_POINTTOPOINT: 677 return ("Point-to-Point"); 678 case LINK_TYPE_TRANSIT_NET: 679 return ("Transit Network"); 680 case LINK_TYPE_RESERVED: 681 return ("Reserved"); 682 case LINK_TYPE_VIRTUAL: 683 return ("Virtual Link"); 684 default: 685 return ("Unknown"); 686 } 687 } 688 689 const char * 690 print_ospf_flags(u_int8_t opts) 691 { 692 static char optbuf[32]; 693 694 snprintf(optbuf, sizeof(optbuf), "*|*|*|*|*|%s|%s|%s", 695 opts & OSPF_RTR_V ? "V" : "-", 696 opts & OSPF_RTR_E ? "E" : "-", 697 opts & OSPF_RTR_B ? "B" : "-"); 698 return (optbuf); 699 } 700 701 const char * 702 print_asext_flags(u_int32_t opts) 703 { 704 static char optbuf[32]; 705 706 snprintf(optbuf, sizeof(optbuf), "*|*|*|*|*|%s|%s|%s", 707 opts & LSA_ASEXT_E_FLAG ? "E" : "-", 708 opts & LSA_ASEXT_F_FLAG ? "F" : "-", 709 opts & LSA_ASEXT_T_FLAG ? "T" : "-"); 710 return (optbuf); 711 } 712 713 const char * 714 print_prefix_opt(u_int8_t opts) 715 { 716 static char optbuf[32]; 717 718 if (opts) { 719 snprintf(optbuf, sizeof(optbuf), 720 " Options: *|*|*|%s|%s|x|%s|%s", 721 opts & OSPF_PREFIX_DN ? "DN" : "-", 722 opts & OSPF_PREFIX_P ? "P" : "-", 723 opts & OSPF_PREFIX_LA ? "LA" : "-", 724 opts & OSPF_PREFIX_NU ? "NU" : "-"); 725 return (optbuf); 726 } 727 return (""); 728 } 729 730 int 731 show_db_msg_detail(struct imsg *imsg) 732 { 733 static struct in_addr area_id; 734 static char ifname[IF_NAMESIZE]; 735 static u_int16_t lasttype; 736 struct in6_addr ia6; 737 struct in_addr addr, data; 738 struct area *area; 739 struct iface *iface; 740 struct lsa *lsa; 741 struct lsa_rtr_link *rtr_link; 742 struct lsa_net_link *net_link; 743 struct lsa_prefix *prefix; 744 struct lsa_asext *asext; 745 u_int32_t ext_tag; 746 u_int16_t i, nlinks, off; 747 748 /* XXX sanity checks! */ 749 750 switch (imsg->hdr.type) { 751 case IMSG_CTL_SHOW_DB_EXT: 752 lsa = imsg->data; 753 if (lsa->hdr.type != lasttype) 754 show_database_head(area_id, ifname, lsa->hdr.type); 755 show_db_hdr_msg_detail(&lsa->hdr); 756 757 asext = (struct lsa_asext *)((char *)lsa + sizeof(lsa->hdr)); 758 759 printf(" Flags: %s\n", 760 print_asext_flags(ntohl(lsa->data.asext.metric))); 761 printf(" Metric: %d Type: ", ntohl(asext->metric) 762 & LSA_METRIC_MASK); 763 if (ntohl(lsa->data.asext.metric) & LSA_ASEXT_E_FLAG) 764 printf("2\n"); 765 else 766 printf("1\n"); 767 768 prefix = &asext->prefix; 769 bzero(&ia6, sizeof(ia6)); 770 bcopy(prefix + 1, &ia6, LSA_PREFIXSIZE(prefix->prefixlen)); 771 printf(" Prefix: %s/%d%s\n", log_in6addr(&ia6), 772 prefix->prefixlen, print_prefix_opt(prefix->options)); 773 774 off = sizeof(*asext) + LSA_PREFIXSIZE(prefix->prefixlen); 775 if (ntohl(lsa->data.asext.metric) & LSA_ASEXT_F_FLAG) { 776 bcopy((char *)asext + off, &ia6, sizeof(ia6)); 777 printf(" Forwarding Address: %s\n", 778 log_in6addr(&ia6)); 779 off += sizeof(ia6); 780 } 781 if (ntohl(lsa->data.asext.metric) & LSA_ASEXT_T_FLAG) { 782 bcopy((char *)asext + off, &ext_tag, sizeof(ext_tag)); 783 printf(" External Route Tag: %d\n", ntohl(ext_tag)); 784 } 785 printf("\n"); 786 lasttype = lsa->hdr.type; 787 break; 788 case IMSG_CTL_SHOW_DB_LINK: 789 lsa = imsg->data; 790 if (lsa->hdr.type != lasttype) 791 show_database_head(area_id, ifname, lsa->hdr.type); 792 show_db_hdr_msg_detail(&lsa->hdr); 793 printf("Options: %s\n", print_ospf_options(LSA_24_GETLO( 794 ntohl(lsa->data.link.opts)))); 795 printf("Link Local Address: %s\n", 796 log_in6addr(&lsa->data.link.lladdr)); 797 798 nlinks = ntohl(lsa->data.link.numprefix); 799 printf("Number of Prefixes: %d\n", nlinks); 800 off = sizeof(lsa->hdr) + sizeof(struct lsa_link); 801 802 for (i = 0; i < nlinks; i++) { 803 prefix = (struct lsa_prefix *)((char *)lsa + off); 804 bzero(&ia6, sizeof(ia6)); 805 bcopy(prefix + 1, &ia6, 806 LSA_PREFIXSIZE(prefix->prefixlen)); 807 808 printf(" Prefix: %s/%d%s\n", log_in6addr(&ia6), 809 prefix->prefixlen, 810 print_prefix_opt(prefix->options)); 811 812 off += sizeof(struct lsa_prefix) 813 + LSA_PREFIXSIZE(prefix->prefixlen); 814 } 815 816 printf("\n"); 817 lasttype = lsa->hdr.type; 818 break; 819 case IMSG_CTL_SHOW_DB_NET: 820 lsa = imsg->data; 821 if (lsa->hdr.type != lasttype) 822 show_database_head(area_id, ifname, lsa->hdr.type); 823 show_db_hdr_msg_detail(&lsa->hdr); 824 printf("Options: %s\n", 825 print_ospf_options(LSA_24_GETLO(ntohl(lsa->data.net.opts)))); 826 827 nlinks = (ntohs(lsa->hdr.len) - sizeof(struct lsa_hdr) - 828 sizeof(struct lsa_net)) / sizeof(struct lsa_net_link); 829 net_link = (struct lsa_net_link *)((char *)lsa + 830 sizeof(lsa->hdr) + sizeof(lsa->data.net)); 831 printf("Number of Routers: %d\n", nlinks); 832 833 for (i = 0; i < nlinks; i++) { 834 addr.s_addr = net_link->att_rtr; 835 printf(" Attached Router: %s\n", inet_ntoa(addr)); 836 net_link++; 837 } 838 839 printf("\n"); 840 lasttype = lsa->hdr.type; 841 break; 842 case IMSG_CTL_SHOW_DB_RTR: 843 lsa = imsg->data; 844 if (lsa->hdr.type != lasttype) 845 show_database_head(area_id, ifname, lsa->hdr.type); 846 show_db_hdr_msg_detail(&lsa->hdr); 847 printf("Flags: %s\n", 848 print_ospf_flags(LSA_24_GETHI(ntohl(lsa->data.rtr.opts)))); 849 printf("Options: %s\n", 850 print_ospf_options(LSA_24_GETLO(ntohl(lsa->data.rtr.opts)))); 851 852 nlinks = (ntohs(lsa->hdr.len) - sizeof(struct lsa_hdr) 853 - sizeof(u_int32_t)) / sizeof(struct lsa_rtr_link); 854 printf("Number of Links: %d\n\n", nlinks); 855 856 off = sizeof(lsa->hdr) + sizeof(struct lsa_rtr); 857 858 for (i = 0; i < nlinks; i++) { 859 rtr_link = (struct lsa_rtr_link *)((char *)lsa + off); 860 861 printf(" Link (Interface ID %s) connected to: %s\n", 862 log_id(rtr_link->iface_id), 863 print_rtr_link_type(rtr_link->type)); 864 865 addr.s_addr = rtr_link->nbr_rtr_id; 866 data.s_addr = rtr_link->nbr_iface_id; 867 868 switch (rtr_link->type) { 869 case LINK_TYPE_POINTTOPOINT: 870 case LINK_TYPE_VIRTUAL: 871 printf(" Router ID: %s\n", inet_ntoa(addr)); 872 printf(" Interface ID: %s\n", 873 inet_ntoa(data)); 874 break; 875 case LINK_TYPE_TRANSIT_NET: 876 printf(" Designated Router ID: %s\n", 877 inet_ntoa(addr)); 878 printf(" DR Interface ID: %s\n", 879 inet_ntoa(data)); 880 break; 881 default: 882 printf(" Link ID (Unknown type %d): %s\n", 883 rtr_link->type, inet_ntoa(addr)); 884 printf(" Link Data (Unknown): %s\n", 885 inet_ntoa(data)); 886 break; 887 } 888 889 printf(" Metric: %d\n\n", ntohs(rtr_link->metric)); 890 891 off += sizeof(struct lsa_rtr_link); 892 } 893 894 lasttype = lsa->hdr.type; 895 break; 896 case IMSG_CTL_SHOW_DB_INTRA: 897 lsa = imsg->data; 898 if (lsa->hdr.type != lasttype) 899 show_database_head(area_id, ifname, lsa->hdr.type); 900 show_db_hdr_msg_detail(&lsa->hdr); 901 printf("Referenced LS Type: %s\n", 902 print_ls_type(lsa->data.pref_intra.ref_type)); 903 addr.s_addr = lsa->data.pref_intra.ref_ls_id; 904 printf("Referenced Link State ID: %s\n", inet_ntoa(addr)); 905 addr.s_addr = lsa->data.pref_intra.ref_adv_rtr; 906 printf("Referenced Advertising Router: %s\n", inet_ntoa(addr)); 907 nlinks = ntohs(lsa->data.pref_intra.numprefix); 908 printf("Number of Prefixes: %d\n", nlinks); 909 910 off = sizeof(lsa->hdr) + sizeof(struct lsa_intra_prefix); 911 912 for (i = 0; i < nlinks; i++) { 913 prefix = (struct lsa_prefix *)((char *)lsa + off); 914 bzero(&ia6, sizeof(ia6)); 915 bcopy(prefix + 1, &ia6, 916 LSA_PREFIXSIZE(prefix->prefixlen)); 917 918 printf(" Prefix: %s/%d%s\n", log_in6addr(&ia6), 919 prefix->prefixlen, 920 print_prefix_opt(prefix->options)); 921 922 off += sizeof(struct lsa_prefix) 923 + LSA_PREFIXSIZE(prefix->prefixlen); 924 } 925 926 printf("\n"); 927 lasttype = lsa->hdr.type; 928 break; 929 case IMSG_CTL_SHOW_DB_SUM: 930 lsa = imsg->data; 931 if (lsa->hdr.type != lasttype) 932 show_database_head(area_id, ifname, lsa->hdr.type); 933 show_db_hdr_msg_detail(&lsa->hdr); 934 printf("Prefix: XXX\n"); 935 printf("Metric: %d\n", ntohl(lsa->data.pref_sum.metric) & 936 LSA_METRIC_MASK); 937 lasttype = lsa->hdr.type; 938 break; 939 case IMSG_CTL_SHOW_DB_ASBR: 940 lsa = imsg->data; 941 if (lsa->hdr.type != lasttype) 942 show_database_head(area_id, ifname, lsa->hdr.type); 943 show_db_hdr_msg_detail(&lsa->hdr); 944 945 addr.s_addr = lsa->data.rtr_sum.dest_rtr_id; 946 printf("Destination Router ID: %s\n", inet_ntoa(addr)); 947 printf("Options: %s\n", 948 print_ospf_options(ntohl(lsa->data.rtr_sum.opts))); 949 printf("Metric: %d\n\n", ntohl(lsa->data.rtr_sum.metric) & 950 LSA_METRIC_MASK); 951 case IMSG_CTL_AREA: 952 area = imsg->data; 953 area_id = area->id; 954 lasttype = 0; 955 break; 956 case IMSG_CTL_IFACE: 957 iface = imsg->data; 958 strlcpy(ifname, iface->name, sizeof(ifname)); 959 lasttype = 0; 960 break; 961 case IMSG_CTL_END: 962 return (1); 963 default: 964 break; 965 } 966 967 return (0); 968 } 969 970 int 971 show_nbr_msg(struct imsg *imsg) 972 { 973 struct ctl_nbr *nbr; 974 char *state; 975 976 switch (imsg->hdr.type) { 977 case IMSG_CTL_SHOW_NBR: 978 nbr = imsg->data; 979 if (asprintf(&state, "%s/%s", nbr_state_name(nbr->nbr_state), 980 if_state_name(nbr->iface_state)) == -1) 981 err(1, NULL); 982 printf("%-15s %-3d %-12s %-10s", inet_ntoa(nbr->id), 983 nbr->priority, state, fmt_timeframe_core(nbr->dead_timer)); 984 printf("%-11s %s\n", nbr->name, 985 nbr->uptime == 0 ? "-" : fmt_timeframe_core(nbr->uptime)); 986 free(state); 987 break; 988 case IMSG_CTL_END: 989 printf("\n"); 990 return (1); 991 default: 992 break; 993 } 994 995 return (0); 996 } 997 998 const char * 999 print_ospf_options(u_int32_t opts) 1000 { 1001 static char optbuf[32]; 1002 1003 snprintf(optbuf, sizeof(optbuf), "*|*|%s|%s|%s|*|%s|%s", 1004 opts & OSPF_OPTION_DC ? "DC" : "-", 1005 opts & OSPF_OPTION_R ? "R" : "-", 1006 opts & OSPF_OPTION_N ? "N" : "-", 1007 opts & OSPF_OPTION_E ? "E" : "-", 1008 opts & OSPF_OPTION_V6 ? "V6" : "-"); 1009 return (optbuf); 1010 } 1011 1012 int 1013 show_nbr_detail_msg(struct imsg *imsg) 1014 { 1015 struct ctl_nbr *nbr; 1016 1017 switch (imsg->hdr.type) { 1018 case IMSG_CTL_SHOW_NBR: 1019 nbr = imsg->data; 1020 printf("\nNeighbor %s, ", inet_ntoa(nbr->id)); 1021 printf("interface address %s\n", log_in6addr(&nbr->addr)); 1022 printf(" Area %s, interface %s\n", inet_ntoa(nbr->area), 1023 nbr->name); 1024 printf(" Neighbor priority is %d, " 1025 "State is %s, %d state changes\n", 1026 nbr->priority, nbr_state_name(nbr->nbr_state), 1027 nbr->state_chng_cnt); 1028 printf(" DR is %s, ", inet_ntoa(nbr->dr)); 1029 printf("BDR is %s\n", inet_ntoa(nbr->bdr)); 1030 printf(" Options %s\n", print_ospf_options(nbr->options)); 1031 printf(" Dead timer due in %s\n", 1032 fmt_timeframe_core(nbr->dead_timer)); 1033 printf(" Uptime %s\n", fmt_timeframe_core(nbr->uptime)); 1034 printf(" Database Summary List %d\n", nbr->db_sum_lst_cnt); 1035 printf(" Link State Request List %d\n", nbr->ls_req_lst_cnt); 1036 printf(" Link State Retransmission List %d\n", 1037 nbr->ls_retrans_lst_cnt); 1038 break; 1039 case IMSG_CTL_END: 1040 printf("\n"); 1041 return (1); 1042 default: 1043 break; 1044 } 1045 1046 return (0); 1047 } 1048 1049 int 1050 show_rib_msg(struct imsg *imsg) 1051 { 1052 struct ctl_rt *rt; 1053 char *dstnet; 1054 1055 switch (imsg->hdr.type) { 1056 case IMSG_CTL_SHOW_RIB: 1057 rt = imsg->data; 1058 switch (rt->d_type) { 1059 case DT_NET: 1060 if (asprintf(&dstnet, "%s/%d", log_in6addr(&rt->prefix), 1061 rt->prefixlen) == -1) 1062 err(1, NULL); 1063 break; 1064 case DT_RTR: 1065 if (asprintf(&dstnet, "%s", 1066 log_in6addr(&rt->prefix)) == -1) 1067 err(1, NULL); 1068 break; 1069 default: 1070 errx(1, "Invalid route type"); 1071 } 1072 1073 printf("%-20s %-17s %-12s %-9s %-7d %s\n", dstnet, 1074 log_in6addr_scope(&rt->nexthop, rt->ifindex), 1075 path_type_name(rt->p_type), dst_type_name(rt->d_type), 1076 rt->cost, 1077 rt->uptime == 0 ? "-" : fmt_timeframe_core(rt->uptime)); 1078 free(dstnet); 1079 break; 1080 case IMSG_CTL_END: 1081 printf("\n"); 1082 return (1); 1083 default: 1084 break; 1085 } 1086 1087 return (0); 1088 } 1089 1090 void 1091 show_rib_head(struct in_addr aid, u_int8_t d_type, u_int8_t p_type) 1092 { 1093 char *header, *format, *format2; 1094 1095 switch (p_type) { 1096 case PT_INTRA_AREA: 1097 case PT_INTER_AREA: 1098 switch (d_type) { 1099 case DT_NET: 1100 format = "Network Routing Table"; 1101 format2 = ""; 1102 break; 1103 case DT_RTR: 1104 format = "Router Routing Table"; 1105 format2 = "Type"; 1106 break; 1107 default: 1108 errx(1, "unknown route type"); 1109 } 1110 break; 1111 case PT_TYPE1_EXT: 1112 case PT_TYPE2_EXT: 1113 format = NULL; 1114 format2 = "Cost 2"; 1115 if ((header = strdup("External Routing Table")) == NULL) 1116 err(1, NULL); 1117 break; 1118 default: 1119 errx(1, "unknown route type"); 1120 } 1121 1122 if (p_type != PT_TYPE1_EXT && p_type != PT_TYPE2_EXT) 1123 if (asprintf(&header, "%s (Area %s)", format, 1124 inet_ntoa(aid)) == -1) 1125 err(1, NULL); 1126 1127 printf("\n%-18s %s\n", "", header); 1128 free(header); 1129 1130 printf("\n%-18s %-15s %-15s %-12s %-7s %-7s\n", "Destination", 1131 "Nexthop", "Adv Router", "Path type", "Cost", format2); 1132 } 1133 1134 const char * 1135 print_ospf_rtr_flags(u_int8_t opts) 1136 { 1137 static char optbuf[32]; 1138 1139 snprintf(optbuf, sizeof(optbuf), "%s%s%s", 1140 opts & OSPF_RTR_E ? "AS" : "", 1141 opts & OSPF_RTR_E && opts & OSPF_RTR_B ? "+" : "", 1142 opts & OSPF_RTR_B ? "ABR" : ""); 1143 return (optbuf); 1144 } 1145 1146 int 1147 show_rib_detail_msg(struct imsg *imsg) 1148 { 1149 static struct in_addr area_id; 1150 struct ctl_rt *rt; 1151 struct area *area; 1152 char *dstnet; 1153 static u_int8_t lasttype; 1154 1155 switch (imsg->hdr.type) { 1156 case IMSG_CTL_SHOW_RIB: 1157 rt = imsg->data; 1158 1159 switch (rt->p_type) { 1160 case PT_INTRA_AREA: 1161 case PT_INTER_AREA: 1162 switch (rt->d_type) { 1163 case DT_NET: 1164 if (lasttype != RIB_NET) 1165 show_rib_head(rt->area, rt->d_type, 1166 rt->p_type); 1167 if (asprintf(&dstnet, "%s/%d", 1168 log_in6addr(&rt->prefix), 1169 rt->prefixlen) == -1) 1170 err(1, NULL); 1171 lasttype = RIB_NET; 1172 break; 1173 case DT_RTR: 1174 if (lasttype != RIB_RTR) 1175 show_rib_head(rt->area, rt->d_type, 1176 rt->p_type); 1177 if (asprintf(&dstnet, "%s", 1178 log_in6addr(&rt->prefix)) == -1) 1179 err(1, NULL); 1180 lasttype = RIB_RTR; 1181 break; 1182 default: 1183 errx(1, "unknown route type"); 1184 } 1185 printf("%-18s %-15s ", dstnet, 1186 log_in6addr_scope(&rt->nexthop, rt->ifindex)); 1187 printf("%-15s %-12s %-7d", inet_ntoa(rt->adv_rtr), 1188 path_type_name(rt->p_type), rt->cost); 1189 free(dstnet); 1190 1191 if (rt->d_type == DT_RTR) 1192 printf(" %-7s", 1193 print_ospf_rtr_flags(rt->flags)); 1194 1195 printf("\n"); 1196 break; 1197 case PT_TYPE1_EXT: 1198 case PT_TYPE2_EXT: 1199 if (lasttype != RIB_EXT) 1200 show_rib_head(rt->area, rt->d_type, rt->p_type); 1201 1202 if (asprintf(&dstnet, "%s/%d", 1203 log_in6addr(&rt->prefix), rt->prefixlen) == -1) 1204 err(1, NULL); 1205 1206 printf("%-18s %-15s ", dstnet, 1207 log_in6addr_scope(&rt->nexthop, rt->ifindex)); 1208 printf("%-15s %-12s %-7d %-7d\n", 1209 inet_ntoa(rt->adv_rtr), path_type_name(rt->p_type), 1210 rt->cost, rt->cost2); 1211 free(dstnet); 1212 1213 lasttype = RIB_EXT; 1214 break; 1215 default: 1216 errx(1, "unknown route type"); 1217 } 1218 break; 1219 case IMSG_CTL_AREA: 1220 area = imsg->data; 1221 area_id = area->id; 1222 break; 1223 case IMSG_CTL_END: 1224 printf("\n"); 1225 return (1); 1226 default: 1227 break; 1228 } 1229 1230 return (0); 1231 } 1232 1233 void 1234 show_fib_head(void) 1235 { 1236 printf("flags: * = valid, O = OSPF, C = Connected, S = Static\n"); 1237 printf("%-6s %-20s %-17s\n", "Flags", "Destination", "Nexthop"); 1238 } 1239 1240 int 1241 show_fib_msg(struct imsg *imsg) 1242 { 1243 struct kroute *k; 1244 char *p; 1245 1246 switch (imsg->hdr.type) { 1247 case IMSG_CTL_KROUTE: 1248 if (imsg->hdr.len < IMSG_HEADER_SIZE + sizeof(struct kroute)) 1249 errx(1, "wrong imsg len"); 1250 k = imsg->data; 1251 1252 if (k->flags & F_DOWN) 1253 printf(" "); 1254 else 1255 printf("*"); 1256 1257 if (!(k->flags & F_KERNEL)) 1258 printf("O"); 1259 else if (k->flags & F_CONNECTED) 1260 printf("C"); 1261 else if (k->flags & F_STATIC) 1262 printf("S"); 1263 else 1264 printf(" "); 1265 1266 printf(" "); 1267 if (asprintf(&p, "%s/%u", log_in6addr(&k->prefix), 1268 k->prefixlen) == -1) 1269 err(1, NULL); 1270 printf("%-20s ", p); 1271 free(p); 1272 1273 if (!IN6_IS_ADDR_UNSPECIFIED(&k->nexthop)) 1274 printf("%s", log_in6addr_scope(&k->nexthop, k->scope)); 1275 else if (k->flags & F_CONNECTED) 1276 printf("link#%u", k->ifindex); 1277 printf("\n"); 1278 1279 break; 1280 case IMSG_CTL_END: 1281 printf("\n"); 1282 return (1); 1283 default: 1284 break; 1285 } 1286 1287 return (0); 1288 } 1289 1290 const struct if_status_description 1291 if_status_descriptions[] = LINK_STATE_DESCRIPTIONS; 1292 const struct ifmedia_description 1293 ifm_type_descriptions[] = IFM_TYPE_DESCRIPTIONS; 1294 1295 const char * 1296 get_media_descr(int media_type) 1297 { 1298 const struct ifmedia_description *p; 1299 1300 for (p = ifm_type_descriptions; p->ifmt_string != NULL; p++) 1301 if (media_type == p->ifmt_word) 1302 return (p->ifmt_string); 1303 1304 return ("unknown"); 1305 } 1306 1307 const char * 1308 get_linkstate(int media_type, int link_state) 1309 { 1310 const struct if_status_description *p; 1311 static char buf[8]; 1312 1313 for (p = if_status_descriptions; p->ifs_string != NULL; p++) { 1314 if (LINK_STATE_DESC_MATCH(p, media_type, link_state)) 1315 return (p->ifs_string); 1316 } 1317 snprintf(buf, sizeof(buf), "[#%d]", link_state); 1318 return (buf); 1319 } 1320 1321 void 1322 print_baudrate(u_int64_t baudrate) 1323 { 1324 if (baudrate > IF_Gbps(1)) 1325 printf("%llu GBit/s", baudrate / IF_Gbps(1)); 1326 else if (baudrate > IF_Mbps(1)) 1327 printf("%llu MBit/s", baudrate / IF_Mbps(1)); 1328 else if (baudrate > IF_Kbps(1)) 1329 printf("%llu KBit/s", baudrate / IF_Kbps(1)); 1330 else 1331 printf("%llu Bit/s", baudrate); 1332 } 1333