xref: /titanic_52/usr/src/lib/libdladm/common/libdllink.c (revision f595a68a3b8953a12aa778c2abd7642df8da8c3a)
1*f595a68aSyz147064 /*
2*f595a68aSyz147064  * CDDL HEADER START
3*f595a68aSyz147064  *
4*f595a68aSyz147064  * The contents of this file are subject to the terms of the
5*f595a68aSyz147064  * Common Development and Distribution License (the "License").
6*f595a68aSyz147064  * You may not use this file except in compliance with the License.
7*f595a68aSyz147064  *
8*f595a68aSyz147064  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*f595a68aSyz147064  * or http://www.opensolaris.org/os/licensing.
10*f595a68aSyz147064  * See the License for the specific language governing permissions
11*f595a68aSyz147064  * and limitations under the License.
12*f595a68aSyz147064  *
13*f595a68aSyz147064  * When distributing Covered Code, include this CDDL HEADER in each
14*f595a68aSyz147064  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*f595a68aSyz147064  * If applicable, add the following below this CDDL HEADER, with the
16*f595a68aSyz147064  * fields enclosed by brackets "[]" replaced with your own identifying
17*f595a68aSyz147064  * information: Portions Copyright [yyyy] [name of copyright owner]
18*f595a68aSyz147064  *
19*f595a68aSyz147064  * CDDL HEADER END
20*f595a68aSyz147064  */
21*f595a68aSyz147064 /*
22*f595a68aSyz147064  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
23*f595a68aSyz147064  * Use is subject to license terms.
24*f595a68aSyz147064  */
25*f595a68aSyz147064 
26*f595a68aSyz147064 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27*f595a68aSyz147064 
28*f595a68aSyz147064 #include <sys/types.h>
29*f595a68aSyz147064 #include <unistd.h>
30*f595a68aSyz147064 #include <errno.h>
31*f595a68aSyz147064 #include <fcntl.h>
32*f595a68aSyz147064 #include <strings.h>
33*f595a68aSyz147064 #include <sys/stat.h>
34*f595a68aSyz147064 #include <sys/dld.h>
35*f595a68aSyz147064 #include <libdlpi.h>
36*f595a68aSyz147064 #include <libdevinfo.h>
37*f595a68aSyz147064 #include <libdllink.h>
38*f595a68aSyz147064 #include <libdladm_impl.h>
39*f595a68aSyz147064 
40*f595a68aSyz147064 typedef struct dladm_dev {
41*f595a68aSyz147064 	char			dd_name[IFNAMSIZ];
42*f595a68aSyz147064 	struct dladm_dev	*dd_next;
43*f595a68aSyz147064 } dladm_dev_t;
44*f595a68aSyz147064 
45*f595a68aSyz147064 typedef struct dladm_walk {
46*f595a68aSyz147064 	dladm_dev_t		*dw_dev_list;
47*f595a68aSyz147064 } dladm_walk_t;
48*f595a68aSyz147064 
49*f595a68aSyz147064 /*
50*f595a68aSyz147064  * Return the attributes of the specified datalink from the DLD driver.
51*f595a68aSyz147064  */
52*f595a68aSyz147064 static int
53*f595a68aSyz147064 i_dladm_info(int fd, const char *name, dladm_attr_t *dap)
54*f595a68aSyz147064 {
55*f595a68aSyz147064 	dld_ioc_attr_t	dia;
56*f595a68aSyz147064 
57*f595a68aSyz147064 	if (strlen(name) >= IFNAMSIZ) {
58*f595a68aSyz147064 		errno = EINVAL;
59*f595a68aSyz147064 		return (-1);
60*f595a68aSyz147064 	}
61*f595a68aSyz147064 
62*f595a68aSyz147064 	(void) strlcpy(dia.dia_name, name, IFNAMSIZ);
63*f595a68aSyz147064 
64*f595a68aSyz147064 	if (i_dladm_ioctl(fd, DLDIOCATTR, &dia, sizeof (dia)) < 0)
65*f595a68aSyz147064 		return (-1);
66*f595a68aSyz147064 
67*f595a68aSyz147064 	(void) strlcpy(dap->da_dev, dia.dia_dev, MAXNAMELEN);
68*f595a68aSyz147064 	dap->da_max_sdu = dia.dia_max_sdu;
69*f595a68aSyz147064 	dap->da_vid = dia.dia_vid;
70*f595a68aSyz147064 
71*f595a68aSyz147064 	return (0);
72*f595a68aSyz147064 }
73*f595a68aSyz147064 
74*f595a68aSyz147064 /*
75*f595a68aSyz147064  * Adds a datalink to the array corresponding to arg.
76*f595a68aSyz147064  */
77*f595a68aSyz147064 static void
78*f595a68aSyz147064 i_dladm_nt_net_add(void *arg, char *name)
79*f595a68aSyz147064 {
80*f595a68aSyz147064 	dladm_walk_t	*dwp = arg;
81*f595a68aSyz147064 	dladm_dev_t	*ddp = dwp->dw_dev_list;
82*f595a68aSyz147064 	dladm_dev_t	**lastp = &dwp->dw_dev_list;
83*f595a68aSyz147064 
84*f595a68aSyz147064 	while (ddp) {
85*f595a68aSyz147064 		/*
86*f595a68aSyz147064 		 * Skip duplicates.
87*f595a68aSyz147064 		 */
88*f595a68aSyz147064 		if (strcmp(ddp->dd_name, name) == 0)
89*f595a68aSyz147064 			return;
90*f595a68aSyz147064 
91*f595a68aSyz147064 		lastp = &ddp->dd_next;
92*f595a68aSyz147064 		ddp = ddp->dd_next;
93*f595a68aSyz147064 	}
94*f595a68aSyz147064 
95*f595a68aSyz147064 	if ((ddp = malloc(sizeof (*ddp))) == NULL)
96*f595a68aSyz147064 		return;
97*f595a68aSyz147064 
98*f595a68aSyz147064 	(void) strlcpy(ddp->dd_name, name, IFNAMSIZ);
99*f595a68aSyz147064 	ddp->dd_next = NULL;
100*f595a68aSyz147064 	*lastp = ddp;
101*f595a68aSyz147064 }
102*f595a68aSyz147064 
103*f595a68aSyz147064 /*
104*f595a68aSyz147064  * Walker callback invoked for each DDI_NT_NET node.
105*f595a68aSyz147064  */
106*f595a68aSyz147064 static int
107*f595a68aSyz147064 i_dladm_nt_net_walk(di_node_t node, di_minor_t minor, void *arg)
108*f595a68aSyz147064 {
109*f595a68aSyz147064 	char		linkname[DLPI_LINKNAME_MAX];
110*f595a68aSyz147064 	dlpi_handle_t	dh;
111*f595a68aSyz147064 
112*f595a68aSyz147064 	if (dlpi_makelink(linkname, di_minor_name(minor),
113*f595a68aSyz147064 	    di_instance(node)) != DLPI_SUCCESS)
114*f595a68aSyz147064 		return (DI_WALK_CONTINUE);
115*f595a68aSyz147064 
116*f595a68aSyz147064 	if (dlpi_open(linkname, &dh, 0) == DLPI_SUCCESS) {
117*f595a68aSyz147064 		i_dladm_nt_net_add(arg, linkname);
118*f595a68aSyz147064 		dlpi_close(dh);
119*f595a68aSyz147064 	}
120*f595a68aSyz147064 	return (DI_WALK_CONTINUE);
121*f595a68aSyz147064 }
122*f595a68aSyz147064 
123*f595a68aSyz147064 /*
124*f595a68aSyz147064  * Hold a data-link.
125*f595a68aSyz147064  */
126*f595a68aSyz147064 static int
127*f595a68aSyz147064 i_dladm_hold_link(const char *name, zoneid_t zoneid, boolean_t docheck)
128*f595a68aSyz147064 {
129*f595a68aSyz147064 	int		fd;
130*f595a68aSyz147064 	dld_hold_vlan_t	dhv;
131*f595a68aSyz147064 
132*f595a68aSyz147064 	if (strlen(name) >= IFNAMSIZ) {
133*f595a68aSyz147064 		errno = EINVAL;
134*f595a68aSyz147064 		return (-1);
135*f595a68aSyz147064 	}
136*f595a68aSyz147064 
137*f595a68aSyz147064 	if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0)
138*f595a68aSyz147064 		return (-1);
139*f595a68aSyz147064 
140*f595a68aSyz147064 	bzero(&dhv, sizeof (dld_hold_vlan_t));
141*f595a68aSyz147064 	(void) strlcpy(dhv.dhv_name, name, IFNAMSIZ);
142*f595a68aSyz147064 	dhv.dhv_zid = zoneid;
143*f595a68aSyz147064 	dhv.dhv_docheck = docheck;
144*f595a68aSyz147064 
145*f595a68aSyz147064 	if (i_dladm_ioctl(fd, DLDIOCHOLDVLAN, &dhv, sizeof (dhv)) < 0) {
146*f595a68aSyz147064 		int olderrno = errno;
147*f595a68aSyz147064 
148*f595a68aSyz147064 		(void) close(fd);
149*f595a68aSyz147064 		errno = olderrno;
150*f595a68aSyz147064 		return (-1);
151*f595a68aSyz147064 	}
152*f595a68aSyz147064 
153*f595a68aSyz147064 	(void) close(fd);
154*f595a68aSyz147064 	return (0);
155*f595a68aSyz147064 }
156*f595a68aSyz147064 
157*f595a68aSyz147064 /*
158*f595a68aSyz147064  * Release a data-link.
159*f595a68aSyz147064  */
160*f595a68aSyz147064 static int
161*f595a68aSyz147064 i_dladm_rele_link(const char *name, zoneid_t zoneid, boolean_t docheck)
162*f595a68aSyz147064 {
163*f595a68aSyz147064 	int		fd;
164*f595a68aSyz147064 	dld_hold_vlan_t	dhv;
165*f595a68aSyz147064 
166*f595a68aSyz147064 	if (strlen(name) >= IFNAMSIZ) {
167*f595a68aSyz147064 		errno = EINVAL;
168*f595a68aSyz147064 		return (-1);
169*f595a68aSyz147064 	}
170*f595a68aSyz147064 
171*f595a68aSyz147064 	if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0)
172*f595a68aSyz147064 		return (-1);
173*f595a68aSyz147064 
174*f595a68aSyz147064 	bzero(&dhv, sizeof (dld_hold_vlan_t));
175*f595a68aSyz147064 	(void) strlcpy(dhv.dhv_name, name, IFNAMSIZ);
176*f595a68aSyz147064 	dhv.dhv_zid = zoneid;
177*f595a68aSyz147064 	dhv.dhv_docheck = docheck;
178*f595a68aSyz147064 
179*f595a68aSyz147064 	if (i_dladm_ioctl(fd, DLDIOCRELEVLAN, &dhv, sizeof (dhv)) < 0) {
180*f595a68aSyz147064 		int olderrno = errno;
181*f595a68aSyz147064 
182*f595a68aSyz147064 		(void) close(fd);
183*f595a68aSyz147064 		errno = olderrno;
184*f595a68aSyz147064 		return (-1);
185*f595a68aSyz147064 	}
186*f595a68aSyz147064 
187*f595a68aSyz147064 	(void) close(fd);
188*f595a68aSyz147064 	return (0);
189*f595a68aSyz147064 }
190*f595a68aSyz147064 
191*f595a68aSyz147064 /*
192*f595a68aSyz147064  * Invoke the specified callback function for each active DDI_NT_NET
193*f595a68aSyz147064  * node.
194*f595a68aSyz147064  */
195*f595a68aSyz147064 int
196*f595a68aSyz147064 dladm_walk(void (*fn)(void *, const char *), void *arg)
197*f595a68aSyz147064 {
198*f595a68aSyz147064 	di_node_t	root;
199*f595a68aSyz147064 	dladm_walk_t	dw;
200*f595a68aSyz147064 	dladm_dev_t	*ddp, *last_ddp;
201*f595a68aSyz147064 
202*f595a68aSyz147064 	if ((root = di_init("/", DINFOCACHE)) == DI_NODE_NIL) {
203*f595a68aSyz147064 		errno = EFAULT;
204*f595a68aSyz147064 		return (-1);
205*f595a68aSyz147064 	}
206*f595a68aSyz147064 	dw.dw_dev_list = NULL;
207*f595a68aSyz147064 
208*f595a68aSyz147064 	(void) di_walk_minor(root, DDI_NT_NET, DI_CHECK_ALIAS, &dw,
209*f595a68aSyz147064 	    i_dladm_nt_net_walk);
210*f595a68aSyz147064 
211*f595a68aSyz147064 	di_fini(root);
212*f595a68aSyz147064 
213*f595a68aSyz147064 	ddp = dw.dw_dev_list;
214*f595a68aSyz147064 	while (ddp) {
215*f595a68aSyz147064 		fn(arg, ddp->dd_name);
216*f595a68aSyz147064 		last_ddp = ddp;
217*f595a68aSyz147064 		ddp = ddp->dd_next;
218*f595a68aSyz147064 		free(last_ddp);
219*f595a68aSyz147064 	}
220*f595a68aSyz147064 
221*f595a68aSyz147064 	return (0);
222*f595a68aSyz147064 }
223*f595a68aSyz147064 
224*f595a68aSyz147064 /*
225*f595a68aSyz147064  * MAC Administration Library.
226*f595a68aSyz147064  *
227*f595a68aSyz147064  * This library is used by administration tools such as dladm(1M) to
228*f595a68aSyz147064  * iterate through the list of MAC interfaces
229*f595a68aSyz147064  *
230*f595a68aSyz147064  */
231*f595a68aSyz147064 
232*f595a68aSyz147064 typedef struct dladm_mac_dev {
233*f595a68aSyz147064 	char			dm_name[MAXNAMELEN];
234*f595a68aSyz147064 	struct dladm_mac_dev	*dm_next;
235*f595a68aSyz147064 } dladm_mac_dev_t;
236*f595a68aSyz147064 
237*f595a68aSyz147064 typedef struct macadm_walk {
238*f595a68aSyz147064 	dladm_mac_dev_t		*dmd_dev_list;
239*f595a68aSyz147064 } dladm_mac_walk_t;
240*f595a68aSyz147064 
241*f595a68aSyz147064 /*
242*f595a68aSyz147064  * Local callback invoked for each DDI_NT_NET node.
243*f595a68aSyz147064  */
244*f595a68aSyz147064 /* ARGSUSED */
245*f595a68aSyz147064 static int
246*f595a68aSyz147064 i_dladm_mac_walk(di_node_t node, di_minor_t minor, void *arg)
247*f595a68aSyz147064 {
248*f595a68aSyz147064 	dladm_mac_walk_t	*dmwp = arg;
249*f595a68aSyz147064 	dladm_mac_dev_t		*dmdp = dmwp->dmd_dev_list;
250*f595a68aSyz147064 	dladm_mac_dev_t		**last_dmdp = &dmwp->dmd_dev_list;
251*f595a68aSyz147064 	char			mac[MAXNAMELEN];
252*f595a68aSyz147064 
253*f595a68aSyz147064 	(void) snprintf(mac, MAXNAMELEN, "%s%d",
254*f595a68aSyz147064 	    di_driver_name(node), di_instance(node));
255*f595a68aSyz147064 
256*f595a68aSyz147064 	/*
257*f595a68aSyz147064 	 * Skip aggregations.
258*f595a68aSyz147064 	 */
259*f595a68aSyz147064 	if (strcmp("aggr", di_driver_name(node)) == 0)
260*f595a68aSyz147064 		return (DI_WALK_CONTINUE);
261*f595a68aSyz147064 
262*f595a68aSyz147064 	while (dmdp) {
263*f595a68aSyz147064 		/*
264*f595a68aSyz147064 		 * Skip duplicates.
265*f595a68aSyz147064 		 */
266*f595a68aSyz147064 		if (strcmp(dmdp->dm_name, mac) == 0)
267*f595a68aSyz147064 			return (DI_WALK_CONTINUE);
268*f595a68aSyz147064 
269*f595a68aSyz147064 		last_dmdp = &dmdp->dm_next;
270*f595a68aSyz147064 		dmdp = dmdp->dm_next;
271*f595a68aSyz147064 	}
272*f595a68aSyz147064 
273*f595a68aSyz147064 	if ((dmdp = malloc(sizeof (*dmdp))) == NULL)
274*f595a68aSyz147064 		return (DI_WALK_CONTINUE);
275*f595a68aSyz147064 
276*f595a68aSyz147064 	(void) strlcpy(dmdp->dm_name, mac, MAXNAMELEN);
277*f595a68aSyz147064 	dmdp->dm_next = NULL;
278*f595a68aSyz147064 	*last_dmdp = dmdp;
279*f595a68aSyz147064 
280*f595a68aSyz147064 	return (DI_WALK_CONTINUE);
281*f595a68aSyz147064 }
282*f595a68aSyz147064 
283*f595a68aSyz147064 /*
284*f595a68aSyz147064  * Invoke the specified callback for each DDI_NT_MAC node.
285*f595a68aSyz147064  */
286*f595a68aSyz147064 int
287*f595a68aSyz147064 dladm_mac_walk(void (*fn)(void *, const char *), void *arg)
288*f595a68aSyz147064 {
289*f595a68aSyz147064 	di_node_t		root;
290*f595a68aSyz147064 	dladm_mac_walk_t	dmw;
291*f595a68aSyz147064 	dladm_mac_dev_t		*dmdp, *next;
292*f595a68aSyz147064 
293*f595a68aSyz147064 	if ((root = di_init("/", DINFOCACHE)) == DI_NODE_NIL)
294*f595a68aSyz147064 		return (-1);
295*f595a68aSyz147064 
296*f595a68aSyz147064 	dmw.dmd_dev_list = NULL;
297*f595a68aSyz147064 
298*f595a68aSyz147064 	(void) di_walk_minor(root, DDI_NT_NET, DI_CHECK_ALIAS, &dmw,
299*f595a68aSyz147064 	    i_dladm_mac_walk);
300*f595a68aSyz147064 
301*f595a68aSyz147064 	di_fini(root);
302*f595a68aSyz147064 
303*f595a68aSyz147064 	dmdp = dmw.dmd_dev_list;
304*f595a68aSyz147064 	for (dmdp = dmw.dmd_dev_list; dmdp != NULL; dmdp = next) {
305*f595a68aSyz147064 		next = dmdp->dm_next;
306*f595a68aSyz147064 		(*fn)(arg, dmdp->dm_name);
307*f595a68aSyz147064 		free(dmdp);
308*f595a68aSyz147064 	}
309*f595a68aSyz147064 
310*f595a68aSyz147064 	return (0);
311*f595a68aSyz147064 }
312*f595a68aSyz147064 
313*f595a68aSyz147064 /*
314*f595a68aSyz147064  * Returns the current attributes of the specified datalink.
315*f595a68aSyz147064  */
316*f595a68aSyz147064 int
317*f595a68aSyz147064 dladm_info(const char *name, dladm_attr_t *dap)
318*f595a68aSyz147064 {
319*f595a68aSyz147064 	int		fd;
320*f595a68aSyz147064 
321*f595a68aSyz147064 	if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0)
322*f595a68aSyz147064 		return (-1);
323*f595a68aSyz147064 
324*f595a68aSyz147064 	if (i_dladm_info(fd, name, dap) < 0)
325*f595a68aSyz147064 		goto failed;
326*f595a68aSyz147064 
327*f595a68aSyz147064 	(void) close(fd);
328*f595a68aSyz147064 	return (0);
329*f595a68aSyz147064 
330*f595a68aSyz147064 failed:
331*f595a68aSyz147064 	(void) close(fd);
332*f595a68aSyz147064 	return (-1);
333*f595a68aSyz147064 }
334*f595a68aSyz147064 
335*f595a68aSyz147064 const char *
336*f595a68aSyz147064 dladm_linkstate2str(link_state_t state, char *buf)
337*f595a68aSyz147064 {
338*f595a68aSyz147064 	const char	*s;
339*f595a68aSyz147064 
340*f595a68aSyz147064 	switch (state) {
341*f595a68aSyz147064 	case LINK_STATE_UP:
342*f595a68aSyz147064 		s = "up";
343*f595a68aSyz147064 		break;
344*f595a68aSyz147064 	case LINK_STATE_DOWN:
345*f595a68aSyz147064 		s = "down";
346*f595a68aSyz147064 		break;
347*f595a68aSyz147064 	default:
348*f595a68aSyz147064 		s = "unknown";
349*f595a68aSyz147064 		break;
350*f595a68aSyz147064 	}
351*f595a68aSyz147064 	(void) snprintf(buf, DLADM_STRSIZE, "%s", s);
352*f595a68aSyz147064 	return (buf);
353*f595a68aSyz147064 }
354*f595a68aSyz147064 
355*f595a68aSyz147064 const char *
356*f595a68aSyz147064 dladm_linkduplex2str(link_duplex_t duplex, char *buf)
357*f595a68aSyz147064 {
358*f595a68aSyz147064 	const char	*s;
359*f595a68aSyz147064 
360*f595a68aSyz147064 	switch (duplex) {
361*f595a68aSyz147064 	case LINK_DUPLEX_FULL:
362*f595a68aSyz147064 		s = "full";
363*f595a68aSyz147064 		break;
364*f595a68aSyz147064 	case LINK_DUPLEX_HALF:
365*f595a68aSyz147064 		s = "half";
366*f595a68aSyz147064 		break;
367*f595a68aSyz147064 	default:
368*f595a68aSyz147064 		s = "unknown";
369*f595a68aSyz147064 		break;
370*f595a68aSyz147064 	}
371*f595a68aSyz147064 	(void) snprintf(buf, DLADM_STRSIZE, "%s", s);
372*f595a68aSyz147064 	return (buf);
373*f595a68aSyz147064 }
374*f595a68aSyz147064 
375*f595a68aSyz147064 /*
376*f595a68aSyz147064  * Do a "hold" operation to a link.
377*f595a68aSyz147064  */
378*f595a68aSyz147064 int
379*f595a68aSyz147064 dladm_hold_link(const char *name, zoneid_t zoneid, boolean_t docheck)
380*f595a68aSyz147064 {
381*f595a68aSyz147064 	return (i_dladm_hold_link(name, zoneid, docheck));
382*f595a68aSyz147064 }
383*f595a68aSyz147064 
384*f595a68aSyz147064 /*
385*f595a68aSyz147064  * Do a "release" operation to a link.
386*f595a68aSyz147064  */
387*f595a68aSyz147064 int
388*f595a68aSyz147064 dladm_rele_link(const char *name, zoneid_t zoneid, boolean_t docheck)
389*f595a68aSyz147064 {
390*f595a68aSyz147064 	return (i_dladm_rele_link(name, zoneid, docheck));
391*f595a68aSyz147064 }
392