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