]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - share/examples/libifconfig/status.c
Xr make_dev(9) from devfs(5).
[FreeBSD/FreeBSD.git] / share / examples / libifconfig / status.c
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         char opts[80];
410
411         if (ifconfig_media_get_mediareq(lifh, ifa->ifa_name, &ifmr) != 0) {
412                 if (ifconfig_err_errtype(lifh) != OK) {
413                         err(1, "Failed to get media info");
414                 } else {
415                         return; /* Interface doesn't support media info */
416                 }
417         }
418
419         printf("\tmedia: %s %s", ifconfig_media_get_type(ifmr->ifm_current),
420             ifconfig_media_get_subtype(ifmr->ifm_current));
421         if (ifmr->ifm_active != ifmr->ifm_current) {
422                 printf(" (%s", ifconfig_media_get_subtype(ifmr->ifm_active));
423                 ifconfig_media_get_options_string(ifmr->ifm_active, opts,
424                     sizeof(opts));
425                 if (opts[0] != '\0') {
426                         printf(" <%s>)\n", opts);
427                 } else {
428                         printf(")\n");
429                 }
430         } else {
431                 printf("\n");
432         }
433
434         if (ifmr->ifm_status & IFM_AVALID) {
435                 printf("\tstatus: %s\n",
436                     ifconfig_media_get_status(ifmr));
437         }
438
439         printf("\tsupported media:\n");
440         for (i = 0; i < ifmr->ifm_count; i++) {
441                 printf("\t\tmedia %s",
442                     ifconfig_media_get_subtype(ifmr->ifm_ulist[i]));
443                 ifconfig_media_get_options_string(ifmr->ifm_ulist[i], opts,
444                     sizeof(opts));
445                 if (opts[0] != '\0') {
446                         printf(" mediaopt %s\n", opts);
447                 } else {
448                         printf("\n");
449                 }
450         }
451         free(ifmr);
452 }
453
454 static void
455 print_iface(ifconfig_handle_t *lifh, struct ifaddrs *ifa, void *udata __unused)
456 {
457         int metric, mtu;
458         char *description = NULL;
459         struct ifconfig_capabilities caps;
460         struct ifstat ifs;
461
462         printf("%s: flags=%x ", ifa->ifa_name, ifa->ifa_flags);
463
464         if (ifconfig_get_metric(lifh, ifa->ifa_name, &metric) == 0) {
465                 printf("metric %d ", metric);
466         } else {
467                 err(1, "Failed to get interface metric");
468         }
469
470         if (ifconfig_get_mtu(lifh, ifa->ifa_name, &mtu) == 0) {
471                 printf("mtu %d\n", mtu);
472         } else {
473                 err(1, "Failed to get interface MTU");
474         }
475
476         if (ifconfig_get_description(lifh, ifa->ifa_name, &description) == 0) {
477                 printf("\tdescription: %s\n", description);
478         }
479
480         if (ifconfig_get_capability(lifh, ifa->ifa_name, &caps) == 0) {
481                 if (caps.curcap != 0) {
482                         printf("\toptions=%x\n", caps.curcap);
483                 }
484                 if (caps.reqcap != 0) {
485                         printf("\tcapabilities=%x\n", caps.reqcap);
486                 }
487         } else {
488                 err(1, "Failed to get interface capabilities");
489         }
490
491         ifconfig_foreach_ifaddr(lifh, ifa, print_ifaddr, NULL);
492
493         /* This paragraph is equivalent to ifconfig's af_other_status funcs */
494         print_nd6(lifh, ifa);
495         print_media(lifh, ifa);
496         print_groups(lifh, ifa);
497         print_fib(lifh, ifa);
498         print_carp(lifh, ifa);
499         print_lagg(lifh, ifa);
500         print_laggport(lifh, ifa);
501
502         if (ifconfig_get_ifstatus(lifh, ifa->ifa_name, &ifs) == 0) {
503                 printf("%s", ifs.ascii);
504         }
505
506         free(description);
507 }
508
509 int
510 main(int argc, char *argv[])
511 {
512         ifconfig_handle_t *lifh;
513
514         if (argc != 1) {
515                 errx(1, "Usage: example_status");
516         }
517
518         lifh = ifconfig_open();
519         if (lifh == NULL) {
520                 errx(1, "Failed to open libifconfig handle.");
521         }
522
523         if (ifconfig_foreach_iface(lifh, print_iface, NULL) != 0) {
524                 err(1, "Failed to get interfaces");
525         }
526
527         ifconfig_close(lifh);
528         lifh = NULL;
529         return (-1);
530 }