1 /* 2 * Copyright (c) 2017, Spectra Logic Corporation 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without modification, 6 * are permitted provided that the following conditions are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright notice, 9 * thislist of conditions and the following disclaimer. 10 * 11 * 2. Redistributions in binary form must reproduce the above copyright notice, 12 * this list of conditions and the following disclaimer in the documentation and/or 13 * other materials provided with the distribution. 14 * 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 18 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 23 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 * 27 * $FreeBSD$ 28 */ 29 30 #include <sys/param.h> 31 #include <sys/ioctl.h> 32 #include <sys/socket.h> 33 34 #include <arpa/inet.h> 35 #include <net/ethernet.h> 36 #include <net/if.h> 37 #include <net/if_dl.h> 38 #include <net/if_lagg.h> 39 #include <net/if_media.h> 40 #include <net/if_types.h> 41 #include <netinet/in.h> 42 #include <netinet/ip_carp.h> 43 #include <netinet6/in6_var.h> 44 #include <netinet6/nd6.h> 45 46 #include <err.h> 47 #include <errno.h> 48 #include <ifaddrs.h> 49 #include <netdb.h> 50 #include <stdio.h> 51 #include <stdlib.h> 52 #include <string.h> 53 #include <libifconfig.h> 54 55 static const char *carp_states[] = { CARP_STATES }; 56 57 static void 58 print_carp(ifconfig_handle_t *lifh, struct ifaddrs *ifa) 59 { 60 struct carpreq carpr[CARP_MAXVHID]; 61 int i; 62 63 if (ifconfig_carp_get_info(lifh, ifa->ifa_name, carpr, CARP_MAXVHID)) { 64 return; /* Probably not configured on this interface */ 65 } 66 for (i = 0; i < carpr[0].carpr_count; i++) { 67 printf("\tcarp: %s vhid %d advbase %d advskew %d", 68 carp_states[carpr[i].carpr_state], carpr[i].carpr_vhid, 69 carpr[i].carpr_advbase, carpr[i].carpr_advskew); 70 printf("\n"); 71 } 72 } 73 74 static void 75 print_inet4_addr(ifconfig_handle_t *lifh, struct ifaddrs *ifa) 76 { 77 struct ifconfig_inet_addr addr; 78 char addr_buf[NI_MAXHOST]; 79 80 if (ifconfig_inet_get_addrinfo(lifh, ifa->ifa_name, ifa, &addr) != 0) { 81 return; 82 } 83 84 inet_ntop(AF_INET, &addr.sin->sin_addr, addr_buf, sizeof(addr_buf)); 85 printf("\tinet %s", addr_buf); 86 87 if (addr.dst) { 88 printf(" --> %s", inet_ntoa(addr.dst->sin_addr)); 89 } 90 91 printf(" netmask 0x%x ", ntohl(addr.netmask->sin_addr.s_addr)); 92 93 if ((addr.broadcast != NULL) && 94 (addr.broadcast->sin_addr.s_addr != 0)) { 95 printf("broadcast %s ", inet_ntoa(addr.broadcast->sin_addr)); 96 } 97 98 if (addr.vhid != 0) { 99 printf("vhid %d ", addr.vhid); 100 } 101 printf("\n"); 102 } 103 104 static void 105 print_inet6_addr(ifconfig_handle_t *lifh, struct ifaddrs *ifa) 106 { 107 struct ifconfig_inet6_addr addr; 108 char addr_buf[NI_MAXHOST]; 109 struct timespec now; 110 111 /* Print the address */ 112 if (ifconfig_inet6_get_addrinfo(lifh, ifa->ifa_name, ifa, &addr) != 0) { 113 err(1, "ifconfig_inet6_get_addrinfo"); 114 } 115 if (0 != getnameinfo((struct sockaddr *)addr.sin6, addr.sin6->sin6_len, 116 addr_buf, sizeof(addr_buf), NULL, 0, NI_NUMERICHOST)) { 117 inet_ntop(AF_INET6, &addr.sin6->sin6_addr, addr_buf, 118 sizeof(addr_buf)); 119 } 120 printf("\tinet6 %s", addr_buf); 121 122 if (addr.dstin6) { 123 inet_ntop(AF_INET6, addr.dstin6, addr_buf, sizeof(addr_buf)); 124 printf(" --> %s", addr_buf); 125 } 126 127 /* Print the netmask */ 128 printf(" prefixlen %d ", addr.prefixlen); 129 130 /* Print the scopeid*/ 131 if (addr.sin6->sin6_scope_id) { 132 printf("scopeid 0x%x ", addr.sin6->sin6_scope_id); 133 } 134 135 /* Print the flags */ 136 if ((addr.flags & IN6_IFF_ANYCAST) != 0) { 137 printf("anycast "); 138 } 139 if ((addr.flags & IN6_IFF_TENTATIVE) != 0) { 140 printf("tentative "); 141 } 142 if ((addr.flags & IN6_IFF_DUPLICATED) != 0) { 143 printf("duplicated "); 144 } 145 if ((addr.flags & IN6_IFF_DETACHED) != 0) { 146 printf("detached "); 147 } 148 if ((addr.flags & IN6_IFF_DEPRECATED) != 0) { 149 printf("deprecated "); 150 } 151 if ((addr.flags & IN6_IFF_AUTOCONF) != 0) { 152 printf("autoconf "); 153 } 154 if ((addr.flags & IN6_IFF_TEMPORARY) != 0) { 155 printf("temporary "); 156 } 157 if ((addr.flags & IN6_IFF_PREFER_SOURCE) != 0) { 158 printf("prefer_source "); 159 } 160 161 /* Print the lifetimes */ 162 clock_gettime(CLOCK_MONOTONIC_FAST, &now); 163 if (addr.lifetime.ia6t_preferred || addr.lifetime.ia6t_expire) { 164 printf("pltime "); 165 if (addr.lifetime.ia6t_preferred) { 166 printf("%ld ", MAX(0l, 167 addr.lifetime.ia6t_preferred - now.tv_sec)); 168 } else { 169 printf("infty "); 170 } 171 172 printf("vltime "); 173 if (addr.lifetime.ia6t_expire) { 174 printf("%ld ", MAX(0l, 175 addr.lifetime.ia6t_expire - now.tv_sec)); 176 } else { 177 printf("infty "); 178 } 179 } 180 181 /* Print the vhid */ 182 if (addr.vhid != 0) { 183 printf("vhid %d ", addr.vhid); 184 } 185 printf("\n"); 186 } 187 188 static void 189 print_link_addr(ifconfig_handle_t *lifh, struct ifaddrs *ifa) 190 { 191 char addr_buf[NI_MAXHOST]; 192 struct sockaddr_dl *sdl; 193 int n; 194 195 sdl = (struct sockaddr_dl *)ifa->ifa_addr; 196 if ((sdl != NULL) && (sdl->sdl_alen > 0)) { 197 if (((sdl->sdl_type == IFT_ETHER) || 198 (sdl->sdl_type == IFT_L2VLAN) || 199 (sdl->sdl_type == IFT_BRIDGE)) && 200 (sdl->sdl_alen == ETHER_ADDR_LEN)) { 201 ether_ntoa_r((struct ether_addr *)LLADDR(sdl), 202 addr_buf); 203 printf("\tether %s\n", addr_buf); 204 } else { 205 n = sdl->sdl_nlen > 0 ? sdl->sdl_nlen + 1 : 0; 206 207 printf("\tlladdr %s\n", link_ntoa(sdl) + n); 208 } 209 } 210 } 211 212 static void 213 print_ifaddr(ifconfig_handle_t *lifh, struct ifaddrs *ifa, void *udata __unused) 214 { 215 switch (ifa->ifa_addr->sa_family) { 216 case AF_INET: 217 print_inet4_addr(lifh, ifa); 218 break; 219 case AF_INET6: 220 221 /* 222 * printing AF_INET6 status requires calling SIOCGIFAFLAG_IN6 223 * and SIOCGIFALIFETIME_IN6. TODO: figure out the best way to 224 * do that from within libifconfig 225 */ 226 print_inet6_addr(lifh, ifa); 227 break; 228 case AF_LINK: 229 print_link_addr(lifh, ifa); 230 break; 231 case AF_LOCAL: 232 case AF_UNSPEC: 233 default: 234 /* TODO */ 235 break; 236 } 237 } 238 239 static void 240 print_nd6(ifconfig_handle_t *lifh, struct ifaddrs *ifa) 241 { 242 struct in6_ndireq nd; 243 244 if (ifconfig_get_nd6(lifh, ifa->ifa_name, &nd) == 0) { 245 printf("\tnd6 options=%x\n", nd.ndi.flags); 246 } else { 247 err(1, "Failed to get nd6 options"); 248 } 249 } 250 251 static void 252 print_fib(ifconfig_handle_t *lifh, struct ifaddrs *ifa) 253 { 254 int fib; 255 256 if (ifconfig_get_fib(lifh, ifa->ifa_name, &fib) == 0) { 257 printf("\tfib: %d\n", fib); 258 } else { 259 err(1, "Failed to get interface FIB"); 260 } 261 } 262 263 static void 264 print_lagg(ifconfig_handle_t *lifh, struct ifaddrs *ifa) 265 { 266 struct lagg_protos lpr[] = LAGG_PROTOS; 267 struct ifconfig_lagg_status *ls; 268 struct lacp_opreq *lp; 269 const char *proto = "<unknown>"; 270 int i; 271 272 if (ifconfig_lagg_get_lagg_status(lifh, ifa->ifa_name, &ls) < 0) { 273 if (ifconfig_err_errno(lifh) == EINVAL) { 274 return; 275 } 276 err(1, "Failed to get interface lagg status"); 277 } 278 279 /* First print the proto */ 280 for (i = 0; i < nitems(lpr); i++) { 281 if (ls->ra->ra_proto == lpr[i].lpr_proto) { 282 proto = lpr[i].lpr_name; 283 break; 284 } 285 } 286 printf("\tlaggproto %s", proto); 287 288 /* Now print the lagg hash */ 289 if (ls->rf->rf_flags & LAGG_F_HASHMASK) { 290 const char *sep = ""; 291 292 printf(" lagghash "); 293 if (ls->rf->rf_flags & LAGG_F_HASHL2) { 294 printf("%sl2", sep); 295 sep = ","; 296 } 297 if (ls->rf->rf_flags & LAGG_F_HASHL3) { 298 printf("%sl3", sep); 299 sep = ","; 300 } 301 if (ls->rf->rf_flags & LAGG_F_HASHL4) { 302 printf("%sl4", sep); 303 sep = ","; 304 } 305 } 306 putchar('\n'); 307 printf("\tlagg options:\n"); 308 printf("\t\tflags=%x", ls->ro->ro_opts); 309 putchar('\n'); 310 printf("\t\tflowid_shift: %d\n", ls->ro->ro_flowid_shift); 311 if (ls->ra->ra_proto == LAGG_PROTO_ROUNDROBIN) { 312 printf("\t\trr_limit: %d\n", ls->ro->ro_bkt); 313 } 314 printf("\tlagg statistics:\n"); 315 printf("\t\tactive ports: %d\n", ls->ro->ro_active); 316 printf("\t\tflapping: %u\n", ls->ro->ro_flapping); 317 for (i = 0; i < ls->ra->ra_ports; i++) { 318 lp = (struct lacp_opreq *)&ls->ra->ra_port[i].rp_lacpreq; 319 printf("\tlaggport: %s ", ls->ra->ra_port[i].rp_portname); 320 printf("flags=%x", ls->ra->ra_port[i].rp_flags); 321 if (ls->ra->ra_proto == LAGG_PROTO_LACP) { 322 printf(" state=%x", lp->actor_state); 323 } 324 putchar('\n'); 325 } 326 327 printf("\n"); 328 ifconfig_lagg_free_lagg_status(ls); 329 } 330 331 static void 332 print_laggport(ifconfig_handle_t *lifh, struct ifaddrs *ifa) 333 { 334 struct lagg_reqport rp; 335 336 if (ifconfig_lagg_get_laggport_status(lifh, ifa->ifa_name, &rp) < 0) { 337 if ((ifconfig_err_errno(lifh) == EINVAL) || 338 (ifconfig_err_errno(lifh) == ENOENT)) { 339 return; 340 } else { 341 err(1, "Failed to get lagg port status"); 342 } 343 } 344 345 printf("\tlaggdev: %s\n", rp.rp_ifname); 346 } 347 348 static void 349 print_groups(ifconfig_handle_t *lifh, struct ifaddrs *ifa) 350 { 351 struct ifgroupreq ifgr; 352 struct ifg_req *ifg; 353 int len; 354 int cnt = 0; 355 356 if (ifconfig_get_groups(lifh, ifa->ifa_name, &ifgr) != 0) { 357 err(1, "Failed to get groups"); 358 } 359 360 ifg = ifgr.ifgr_groups; 361 len = ifgr.ifgr_len; 362 for (; ifg && len >= sizeof(struct ifg_req); ifg++) { 363 len -= sizeof(struct ifg_req); 364 if (strcmp(ifg->ifgrq_group, "all")) { 365 if (cnt == 0) { 366 printf("\tgroups: "); 367 } 368 cnt++; 369 printf("%s ", ifg->ifgrq_group); 370 } 371 } 372 if (cnt) { 373 printf("\n"); 374 } 375 376 free(ifgr.ifgr_groups); 377 } 378 379 static void 380 print_media(ifconfig_handle_t *lifh, struct ifaddrs *ifa) 381 { 382 int i; 383 384 /* Outline: 385 * 1) Determine whether the iface supports SIOGIFMEDIA or SIOGIFXMEDIA 386 * 2) Get the full media list 387 * 3) Print the current media word 388 * 4) Print the active media word, if different 389 * 5) Print the status 390 * 6) Print the supported media list 391 * 392 * How to print the media word: 393 * 1) Get the top-level interface type and description 394 * 2) Print the subtype 395 * 3) For current word only, print the top type, if it exists 396 * 4) Print options list 397 * 5) Print the instance, if there is one 398 * 399 * How to get the top-level interface type 400 * 1) Shift ifmw right by 0x20 and index into IFM_TYPE_DESCRIPTIONS 401 * 402 * How to get the top-level interface subtype 403 * 1) Shift ifmw right by 0x20, index into ifmedia_types_to_subtypes 404 * 2) Iterate through the resulting table's subtypes table, ignoring 405 * aliases. Iterate through the resulting ifmedia_description 406 * tables, finding an entry with the right media subtype 407 */ 408 struct ifmediareq *ifmr; 409 410 if (ifconfig_media_get_mediareq(lifh, ifa->ifa_name, &ifmr) != 0) { 411 if (ifconfig_err_errtype(lifh) != OK) { 412 err(1, "Failed to get media info"); 413 } else { 414 return; /* Interface doesn't support media info */ 415 } 416 } 417 418 printf("\tmedia: %s %s", ifconfig_media_get_type(ifmr->ifm_current), 419 ifconfig_media_get_subtype(ifmr->ifm_current)); 420 if (ifmr->ifm_active != ifmr->ifm_current) { 421 const char **options; 422 423 printf(" (%s", ifconfig_media_get_subtype(ifmr->ifm_active)); 424 options = ifconfig_media_get_options(ifmr->ifm_active); 425 if (options != NULL && options[0] != NULL) { 426 printf(" <%s", options[0]); 427 for (size_t i = 1; options[i] != NULL; ++i) 428 printf(",%s", options[i]); 429 printf(">)\n"); 430 } else { 431 printf(")\n"); 432 } 433 free(options); 434 } else { 435 printf("\n"); 436 } 437 438 if (ifmr->ifm_status & IFM_AVALID) { 439 printf("\tstatus: %s\n", 440 ifconfig_media_get_status(ifmr)); 441 } 442 443 printf("\tsupported media:\n"); 444 for (i = 0; i < ifmr->ifm_count; i++) { 445 const char **options; 446 447 printf("\t\tmedia %s", 448 ifconfig_media_get_subtype(ifmr->ifm_ulist[i])); 449 options = ifconfig_media_get_options(ifmr->ifm_ulist[i]); 450 if (options != NULL && options[0] != NULL) { 451 printf(" mediaopt %s", options[0]); 452 for (size_t i = 1; options[i] != NULL; ++i) 453 printf(",%s", options[i]); 454 printf("\n"); 455 } else { 456 printf("\n"); 457 } 458 free(options); 459 } 460 free(ifmr); 461 } 462 463 static void 464 print_iface(ifconfig_handle_t *lifh, struct ifaddrs *ifa, void *udata __unused) 465 { 466 int metric, mtu; 467 char *description = NULL; 468 struct ifconfig_capabilities caps; 469 struct ifstat ifs; 470 471 printf("%s: flags=%x ", ifa->ifa_name, ifa->ifa_flags); 472 473 if (ifconfig_get_metric(lifh, ifa->ifa_name, &metric) == 0) { 474 printf("metric %d ", metric); 475 } else { 476 err(1, "Failed to get interface metric"); 477 } 478 479 if (ifconfig_get_mtu(lifh, ifa->ifa_name, &mtu) == 0) { 480 printf("mtu %d\n", mtu); 481 } else { 482 err(1, "Failed to get interface MTU"); 483 } 484 485 if (ifconfig_get_description(lifh, ifa->ifa_name, &description) == 0) { 486 printf("\tdescription: %s\n", description); 487 } 488 489 if (ifconfig_get_capability(lifh, ifa->ifa_name, &caps) == 0) { 490 if (caps.curcap != 0) { 491 printf("\toptions=%x\n", caps.curcap); 492 } 493 if (caps.reqcap != 0) { 494 printf("\tcapabilities=%x\n", caps.reqcap); 495 } 496 } else { 497 err(1, "Failed to get interface capabilities"); 498 } 499 500 ifconfig_foreach_ifaddr(lifh, ifa, print_ifaddr, NULL); 501 502 /* This paragraph is equivalent to ifconfig's af_other_status funcs */ 503 print_nd6(lifh, ifa); 504 print_media(lifh, ifa); 505 print_groups(lifh, ifa); 506 print_fib(lifh, ifa); 507 print_carp(lifh, ifa); 508 print_lagg(lifh, ifa); 509 print_laggport(lifh, ifa); 510 511 if (ifconfig_get_ifstatus(lifh, ifa->ifa_name, &ifs) == 0) { 512 printf("%s", ifs.ascii); 513 } 514 515 free(description); 516 } 517 518 int 519 main(int argc, char *argv[]) 520 { 521 ifconfig_handle_t *lifh; 522 523 if (argc != 1) { 524 errx(1, "Usage: example_status"); 525 } 526 527 lifh = ifconfig_open(); 528 if (lifh == NULL) { 529 errx(1, "Failed to open libifconfig handle."); 530 } 531 532 if (ifconfig_foreach_iface(lifh, print_iface, NULL) != 0) { 533 err(1, "Failed to get interfaces"); 534 } 535 536 ifconfig_close(lifh); 537 lifh = NULL; 538 return (-1); 539 } 540