xref: /illumos-gate/usr/src/test/os-tests/tests/libsocket/getifaddrs_dl.c (revision b5c46058df272e09a79597fb15cd84399922d666)
1*b5c46058SRobert Mustacchi /*
2*b5c46058SRobert Mustacchi  * This file and its contents are supplied under the terms of the
3*b5c46058SRobert Mustacchi  * Common Development and Distribution License ("CDDL"), version 1.0.
4*b5c46058SRobert Mustacchi  * You may only use this file in accordance with the terms of version
5*b5c46058SRobert Mustacchi  * 1.0 of the CDDL.
6*b5c46058SRobert Mustacchi  *
7*b5c46058SRobert Mustacchi  * A full copy of the text of the CDDL should have accompanied this
8*b5c46058SRobert Mustacchi  * source.  A copy of the CDDL is also available via the Internet at
9*b5c46058SRobert Mustacchi  * http://www.illumos.org/license/CDDL.
10*b5c46058SRobert Mustacchi  */
11*b5c46058SRobert Mustacchi 
12*b5c46058SRobert Mustacchi /*
13*b5c46058SRobert Mustacchi  * Copyright 2026 Oxide Computer Company
14*b5c46058SRobert Mustacchi  */
15*b5c46058SRobert Mustacchi 
16*b5c46058SRobert Mustacchi /*
17*b5c46058SRobert Mustacchi  * This is a basic set of sanity checks for getifaddrs(3SOCKET) and its behavior
18*b5c46058SRobert Mustacchi  * with AF_LINK addresses. This is generally designed around being a regression
19*b5c46058SRobert Mustacchi  * test for #16383 and #16384 which were missing data entries in both the
20*b5c46058SRobert Mustacchi  * sockaddr_dl and the struct if_data.  Rather than change the system and see
21*b5c46058SRobert Mustacchi  * what's there, we instead walk the links in the system assuming there is
22*b5c46058SRobert Mustacchi  * usually at least one interface present.
23*b5c46058SRobert Mustacchi  */
24*b5c46058SRobert Mustacchi 
25*b5c46058SRobert Mustacchi #include <sys/types.h>
26*b5c46058SRobert Mustacchi #include <sys/socket.h>
27*b5c46058SRobert Mustacchi #include <ifaddrs.h>
28*b5c46058SRobert Mustacchi #include <net/if.h>
29*b5c46058SRobert Mustacchi #include <stdlib.h>
30*b5c46058SRobert Mustacchi #include <err.h>
31*b5c46058SRobert Mustacchi #include <libdladm.h>
32*b5c46058SRobert Mustacchi #include <libdllink.h>
33*b5c46058SRobert Mustacchi #include <string.h>
34*b5c46058SRobert Mustacchi #include <stdbool.h>
35*b5c46058SRobert Mustacchi #include <libdlpi.h>
36*b5c46058SRobert Mustacchi 
37*b5c46058SRobert Mustacchi typedef struct {
38*b5c46058SRobert Mustacchi 	const struct ifaddrs *ic_ifa;
39*b5c46058SRobert Mustacchi 	int ic_ret;
40*b5c46058SRobert Mustacchi 	uint32_t ic_nmatch;
41*b5c46058SRobert Mustacchi } ifaddr_cb_t;
42*b5c46058SRobert Mustacchi 
43*b5c46058SRobert Mustacchi typedef struct {
44*b5c46058SRobert Mustacchi 	bool mc_found;
45*b5c46058SRobert Mustacchi 	bool *mc_pass;
46*b5c46058SRobert Mustacchi 	const char *mc_name;
47*b5c46058SRobert Mustacchi 	const struct ifaddrs *mc_ifa;
48*b5c46058SRobert Mustacchi } mac_cb_t;
49*b5c46058SRobert Mustacchi 
50*b5c46058SRobert Mustacchi static boolean_t
dladm_walk_mac_cb(void * arg,dladm_macaddr_attr_t * attr)51*b5c46058SRobert Mustacchi dladm_walk_mac_cb(void *arg, dladm_macaddr_attr_t *attr)
52*b5c46058SRobert Mustacchi {
53*b5c46058SRobert Mustacchi 	mac_cb_t *cb = arg;
54*b5c46058SRobert Mustacchi 	const struct ifaddrs *ifa = cb->mc_ifa;
55*b5c46058SRobert Mustacchi 	const struct sockaddr_dl *dl = (struct sockaddr_dl *)ifa->ifa_addr;
56*b5c46058SRobert Mustacchi 	const struct if_data *if_data = ifa->ifa_data;
57*b5c46058SRobert Mustacchi 
58*b5c46058SRobert Mustacchi 	if (attr->ma_addrlen != dl->sdl_alen)
59*b5c46058SRobert Mustacchi 		return (B_TRUE);
60*b5c46058SRobert Mustacchi 
61*b5c46058SRobert Mustacchi 	if (memcmp(LLADDR(dl), attr->ma_addr, attr->ma_addrlen) != 0) {
62*b5c46058SRobert Mustacchi 		return (B_TRUE);
63*b5c46058SRobert Mustacchi 	}
64*b5c46058SRobert Mustacchi 
65*b5c46058SRobert Mustacchi 	cb->mc_found = true;
66*b5c46058SRobert Mustacchi 	if (if_data != NULL && if_data->ifi_addrlen != attr->ma_addrlen) {
67*b5c46058SRobert Mustacchi 		warnx("TEST FAILED: link %s: found if_data address length "
68*b5c46058SRobert Mustacchi 		    "0x%x, but expected 0x%x", cb->mc_name,
69*b5c46058SRobert Mustacchi 		    if_data->ifi_addrlen, attr->ma_addrlen);
70*b5c46058SRobert Mustacchi 		*cb->mc_pass = false;
71*b5c46058SRobert Mustacchi 	}
72*b5c46058SRobert Mustacchi 
73*b5c46058SRobert Mustacchi 	return (B_TRUE);
74*b5c46058SRobert Mustacchi }
75*b5c46058SRobert Mustacchi 
76*b5c46058SRobert Mustacchi static int
dladm_walk_cb(dladm_handle_t hdl,datalink_id_t id,void * arg)77*b5c46058SRobert Mustacchi dladm_walk_cb(dladm_handle_t hdl, datalink_id_t id, void *arg)
78*b5c46058SRobert Mustacchi {
79*b5c46058SRobert Mustacchi 	dladm_status_t dlret;
80*b5c46058SRobert Mustacchi 	ifaddr_cb_t *cb = arg;
81*b5c46058SRobert Mustacchi 	char name[MAXLINKNAMELEN];
82*b5c46058SRobert Mustacchi 	char dlerr[DLADM_STRSIZE];
83*b5c46058SRobert Mustacchi 	uint32_t media;
84*b5c46058SRobert Mustacchi 	char buf[DLADM_PROP_VAL_MAX];
85*b5c46058SRobert Mustacchi 	char *valptr[1];
86*b5c46058SRobert Mustacchi 	uint_t valcnt;
87*b5c46058SRobert Mustacchi 
88*b5c46058SRobert Mustacchi 	dlret = dladm_datalink_id2info(hdl, id, NULL, NULL, &media, name,
89*b5c46058SRobert Mustacchi 	    sizeof (name));
90*b5c46058SRobert Mustacchi 	if (dlret != DLADM_STATUS_OK) {
91*b5c46058SRobert Mustacchi 		cb->ic_ret = EXIT_FAILURE;
92*b5c46058SRobert Mustacchi 		warnx("INTERNAL TEST FAILURE: failed to get datalink "
93*b5c46058SRobert Mustacchi 		    "information for link 0x%x: %s", id, dladm_status2str(dlret,
94*b5c46058SRobert Mustacchi 		    dlerr));
95*b5c46058SRobert Mustacchi 
96*b5c46058SRobert Mustacchi 		return (DLADM_WALK_CONTINUE);
97*b5c46058SRobert Mustacchi 	}
98*b5c46058SRobert Mustacchi 
99*b5c46058SRobert Mustacchi 	/*
100*b5c46058SRobert Mustacchi 	 * Before we scan the list looking for this, see if the link is up. In
101*b5c46058SRobert Mustacchi 	 * particular, dladm will see all datalinks; however, if it isn't really
102*b5c46058SRobert Mustacchi 	 * in use by some client, then it's likely that it's not actually in our
103*b5c46058SRobert Mustacchi 	 * getifaddrs() list. If filtering to links that are not in an unknown
104*b5c46058SRobert Mustacchi 	 * state gives us false positives then we can revisit this.
105*b5c46058SRobert Mustacchi 	 */
106*b5c46058SRobert Mustacchi 	valptr[0] = buf;
107*b5c46058SRobert Mustacchi 	valcnt = 1;
108*b5c46058SRobert Mustacchi 	if (dladm_get_linkprop(hdl, id, DLADM_PROP_VAL_CURRENT, "state", valptr,
109*b5c46058SRobert Mustacchi 	    &valcnt) != DLADM_STATUS_OK) {
110*b5c46058SRobert Mustacchi 		warnx("skipping datalink %s as we could not get \"state\" link "
111*b5c46058SRobert Mustacchi 		    "link property", name);
112*b5c46058SRobert Mustacchi 		return (DLADM_WALK_CONTINUE);
113*b5c46058SRobert Mustacchi 	}
114*b5c46058SRobert Mustacchi 
115*b5c46058SRobert Mustacchi 	if (strcmp(buf, "up") != 0 && strcmp(buf, "down") != 0) {
116*b5c46058SRobert Mustacchi 		return (DLADM_WALK_CONTINUE);
117*b5c46058SRobert Mustacchi 	}
118*b5c46058SRobert Mustacchi 
119*b5c46058SRobert Mustacchi 	for (const struct ifaddrs *i = cb->ic_ifa; i != NULL; i = i->ifa_next) {
120*b5c46058SRobert Mustacchi 		bool pass = true;
121*b5c46058SRobert Mustacchi 
122*b5c46058SRobert Mustacchi 		if (strcmp(name, i->ifa_name) != 0)
123*b5c46058SRobert Mustacchi 			continue;
124*b5c46058SRobert Mustacchi 		if (i->ifa_addr->sa_family != AF_LINK)
125*b5c46058SRobert Mustacchi 			continue;
126*b5c46058SRobert Mustacchi 
127*b5c46058SRobert Mustacchi 		struct sockaddr_dl *dl = (struct sockaddr_dl *)i->ifa_addr;
128*b5c46058SRobert Mustacchi 		uint_t ift_type = dlpi_iftype(media);
129*b5c46058SRobert Mustacchi 
130*b5c46058SRobert Mustacchi 		if (ift_type != dl->sdl_type) {
131*b5c46058SRobert Mustacchi 			pass = false;
132*b5c46058SRobert Mustacchi 			warnx("TEST FAILED: link %s: found type 0x%x, but "
133*b5c46058SRobert Mustacchi 			    "expected type 0x%x (dlpi 0x%x)", name,
134*b5c46058SRobert Mustacchi 			    dl->sdl_type, ift_type, media);
135*b5c46058SRobert Mustacchi 		}
136*b5c46058SRobert Mustacchi 
137*b5c46058SRobert Mustacchi 		size_t nlen = strlen(name);
138*b5c46058SRobert Mustacchi 		if (nlen != dl->sdl_nlen) {
139*b5c46058SRobert Mustacchi 			pass = false;
140*b5c46058SRobert Mustacchi 			warnx("TEST FAILED: link %s: name length mismatch: "
141*b5c46058SRobert Mustacchi 			    "found %u, expected %zu", name, dl->sdl_nlen, nlen);
142*b5c46058SRobert Mustacchi 		}
143*b5c46058SRobert Mustacchi 
144*b5c46058SRobert Mustacchi 		if (dl->sdl_nlen > 0) {
145*b5c46058SRobert Mustacchi 			if (strncmp(name, &dl->sdl_data[0], dl->sdl_nlen) !=
146*b5c46058SRobert Mustacchi 			    0) {
147*b5c46058SRobert Mustacchi 				pass = false;
148*b5c46058SRobert Mustacchi 				warnx("TEST FAILED: link %s: sockaddr_dl does "
149*b5c46058SRobert Mustacchi 				    "not match name", name);
150*b5c46058SRobert Mustacchi 			}
151*b5c46058SRobert Mustacchi 		}
152*b5c46058SRobert Mustacchi 
153*b5c46058SRobert Mustacchi 		/*
154*b5c46058SRobert Mustacchi 		 * Walk device MAC addresses to ensure that this looks right.
155*b5c46058SRobert Mustacchi 		 */
156*b5c46058SRobert Mustacchi 		mac_cb_t mcb = { false, &pass, name, i };
157*b5c46058SRobert Mustacchi 		(void) dladm_walk_macaddr(hdl, id, &mcb, dladm_walk_mac_cb);
158*b5c46058SRobert Mustacchi 		if (!mcb.mc_found) {
159*b5c46058SRobert Mustacchi 			pass = false;
160*b5c46058SRobert Mustacchi 			warnx("TEST FAILED: link %s: failed to find matching "
161*b5c46058SRobert Mustacchi 			    "mac address", name);
162*b5c46058SRobert Mustacchi 		}
163*b5c46058SRobert Mustacchi 
164*b5c46058SRobert Mustacchi 		/*
165*b5c46058SRobert Mustacchi 		 * Check a few last aspects of the ifi_data. The ifi_addrlen has
166*b5c46058SRobert Mustacchi 		 * already been filled in. We need to verify the MTU and type.
167*b5c46058SRobert Mustacchi 		 */
168*b5c46058SRobert Mustacchi 		if (i->ifa_data != NULL) {
169*b5c46058SRobert Mustacchi 			struct if_data *data = i->ifa_data;
170*b5c46058SRobert Mustacchi 
171*b5c46058SRobert Mustacchi 			if (data->ifi_type != ift_type) {
172*b5c46058SRobert Mustacchi 				pass = false;
173*b5c46058SRobert Mustacchi 				warnx("TEST FAILED: link %s: found if_data "
174*b5c46058SRobert Mustacchi 				    "ifi_type 0x%x, but expected type 0x%x "
175*b5c46058SRobert Mustacchi 				    "(dlpi 0x%x)", name, data->ifi_type,
176*b5c46058SRobert Mustacchi 				    ift_type, media);
177*b5c46058SRobert Mustacchi 			}
178*b5c46058SRobert Mustacchi 
179*b5c46058SRobert Mustacchi 			valptr[0] = buf;
180*b5c46058SRobert Mustacchi 			valcnt = 1;
181*b5c46058SRobert Mustacchi 			if (dladm_get_linkprop(hdl, id, DLADM_PROP_VAL_CURRENT,
182*b5c46058SRobert Mustacchi 			    "mtu", valptr, &valcnt) == DLADM_STATUS_OK) {
183*b5c46058SRobert Mustacchi 				/*
184*b5c46058SRobert Mustacchi 				 * Assume libdladm gives us something
185*b5c46058SRobert Mustacchi 				 * reasonable.
186*b5c46058SRobert Mustacchi 				 */
187*b5c46058SRobert Mustacchi 				ulong_t val = strtoul(buf, NULL, 10);
188*b5c46058SRobert Mustacchi 				if (val != data->ifi_mtu) {
189*b5c46058SRobert Mustacchi 					pass = false;
190*b5c46058SRobert Mustacchi 					warnx("TEST FAILED: link %s: found "
191*b5c46058SRobert Mustacchi 					    "MTU %u, expected %lu", name,
192*b5c46058SRobert Mustacchi 					    data->ifi_mtu, val);
193*b5c46058SRobert Mustacchi 				}
194*b5c46058SRobert Mustacchi 			}
195*b5c46058SRobert Mustacchi 		} else {
196*b5c46058SRobert Mustacchi 			pass = false;
197*b5c46058SRobert Mustacchi 			warnx("TEST FAILED: link %s: found NULL ifa_data "
198*b5c46058SRobert Mustacchi 			    "pointer", name);
199*b5c46058SRobert Mustacchi 		}
200*b5c46058SRobert Mustacchi 
201*b5c46058SRobert Mustacchi 		if (pass) {
202*b5c46058SRobert Mustacchi 			(void) printf("TEST PASSED: %s AF_LINK entry looks "
203*b5c46058SRobert Mustacchi 			    "right\n", name);
204*b5c46058SRobert Mustacchi 		} else {
205*b5c46058SRobert Mustacchi 			cb->ic_ret = EXIT_FAILURE;
206*b5c46058SRobert Mustacchi 		}
207*b5c46058SRobert Mustacchi 
208*b5c46058SRobert Mustacchi 		cb->ic_nmatch++;
209*b5c46058SRobert Mustacchi 		return (DLADM_WALK_CONTINUE);
210*b5c46058SRobert Mustacchi 	}
211*b5c46058SRobert Mustacchi 
212*b5c46058SRobert Mustacchi 	warnx("TEST FAILED: failed to find matching ifaddrs entry for datalink "
213*b5c46058SRobert Mustacchi 	    "%s (0x%x)", name, id);
214*b5c46058SRobert Mustacchi 	cb->ic_ret = EXIT_FAILURE;
215*b5c46058SRobert Mustacchi 	return (DLADM_WALK_CONTINUE);
216*b5c46058SRobert Mustacchi }
217*b5c46058SRobert Mustacchi 
218*b5c46058SRobert Mustacchi int
main(void)219*b5c46058SRobert Mustacchi main(void)
220*b5c46058SRobert Mustacchi {
221*b5c46058SRobert Mustacchi 	struct ifaddrs *ifa;
222*b5c46058SRobert Mustacchi 	dladm_status_t dlret;
223*b5c46058SRobert Mustacchi 	dladm_handle_t dladm;
224*b5c46058SRobert Mustacchi 	char dlerr[DLADM_STRSIZE];
225*b5c46058SRobert Mustacchi 	ifaddr_cb_t cb;
226*b5c46058SRobert Mustacchi 
227*b5c46058SRobert Mustacchi 	if (getifaddrs(&ifa) != 0) {
228*b5c46058SRobert Mustacchi 		err(EXIT_FAILURE, "INTERNAL TEST FAILURE: getifaddrs() failed: "
229*b5c46058SRobert Mustacchi 		    "test cannot proceed");
230*b5c46058SRobert Mustacchi 	}
231*b5c46058SRobert Mustacchi 
232*b5c46058SRobert Mustacchi 	dlret = dladm_open(&dladm);
233*b5c46058SRobert Mustacchi 	if (dlret != DLADM_STATUS_OK) {
234*b5c46058SRobert Mustacchi 		errx(EXIT_FAILURE, "INTERNAL TEST FAILURE: failed to "
235*b5c46058SRobert Mustacchi 		    "initialize libdladm handle: %s", dladm_status2str(dlret,
236*b5c46058SRobert Mustacchi 		    dlerr));
237*b5c46058SRobert Mustacchi 	}
238*b5c46058SRobert Mustacchi 
239*b5c46058SRobert Mustacchi 	cb.ic_ifa = ifa;
240*b5c46058SRobert Mustacchi 	cb.ic_ret = EXIT_SUCCESS;
241*b5c46058SRobert Mustacchi 	cb.ic_nmatch = 0;
242*b5c46058SRobert Mustacchi 	(void) dladm_walk_datalink_id(dladm_walk_cb, dladm, &cb,
243*b5c46058SRobert Mustacchi 	    DATALINK_CLASS_PHYS | DATALINK_CLASS_VNIC, DATALINK_ANY_MEDIATYPE,
244*b5c46058SRobert Mustacchi 	    DLADM_OPT_ACTIVE);
245*b5c46058SRobert Mustacchi 	dladm_close(dladm);
246*b5c46058SRobert Mustacchi 	freeifaddrs(ifa);
247*b5c46058SRobert Mustacchi 
248*b5c46058SRobert Mustacchi 	if (cb.ic_nmatch == 0) {
249*b5c46058SRobert Mustacchi 		cb.ic_ret = EXIT_FAILURE;
250*b5c46058SRobert Mustacchi 		warnx("no AF_LINK entries found");
251*b5c46058SRobert Mustacchi 	}
252*b5c46058SRobert Mustacchi 
253*b5c46058SRobert Mustacchi 	if (cb.ic_ret == EXIT_SUCCESS) {
254*b5c46058SRobert Mustacchi 		(void) printf("All tests passed successfully\n");
255*b5c46058SRobert Mustacchi 	}
256*b5c46058SRobert Mustacchi 	return (cb.ic_ret);
257*b5c46058SRobert Mustacchi }
258