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