xref: /illumos-gate/usr/src/lib/libdladm/common/libdladm.c (revision ba2e4443695ee6a6f420a35cd4fc3d3346d22932)
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 2006 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 <stdio.h>
29 #include <sys/types.h>
30 #include <string.h>
31 #include <fcntl.h>
32 #include <unistd.h>
33 #include <stropts.h>
34 #include <stdlib.h>
35 #include <errno.h>
36 #include <libdevinfo.h>
37 #include <libdlpi.h>
38 #include <libdladm.h>
39 #include <sys/dld.h>
40 #include <net/if.h>
41 
42 typedef struct dladm_dev {
43 	char			dd_name[IFNAMSIZ];
44 	struct dladm_dev	*dd_next;
45 } dladm_dev_t;
46 
47 typedef struct dladm_walk {
48 	dladm_dev_t		*dw_dev_list;
49 } dladm_walk_t;
50 
51 /*
52  * Issue an ioctl to the specified file descriptor attached to the
53  * DLD control driver interface.
54  */
55 static int
56 i_dladm_ioctl(int fd, int ic_cmd, void *ic_dp, int ic_len)
57 {
58 	struct strioctl	iocb;
59 
60 	iocb.ic_cmd = ic_cmd;
61 	iocb.ic_timout = 0;
62 	iocb.ic_len = ic_len;
63 	iocb.ic_dp = (char *)ic_dp;
64 
65 	return (ioctl(fd, I_STR, &iocb));
66 }
67 
68 /*
69  * Return the attributes of the specified datalink from the DLD driver.
70  */
71 static int
72 i_dladm_info(int fd, const char *name, dladm_attr_t *dap)
73 {
74 	dld_ioc_attr_t	dia;
75 
76 	if (strlen(name) >= IFNAMSIZ) {
77 		errno = EINVAL;
78 		return (-1);
79 	}
80 
81 	(void) strlcpy(dia.dia_name, name, IFNAMSIZ);
82 
83 	if (i_dladm_ioctl(fd, DLDIOCATTR, &dia, sizeof (dia)) < 0)
84 		return (-1);
85 
86 	(void) strlcpy(dap->da_dev, dia.dia_dev, MAXNAMELEN);
87 	dap->da_max_sdu = dia.dia_max_sdu;
88 	dap->da_vid = dia.dia_vid;
89 
90 	return (0);
91 }
92 
93 /*
94  * Adds a datalink to the array corresponding to arg.
95  */
96 static void
97 i_dladm_nt_net_add(void *arg, char *name)
98 {
99 	dladm_walk_t	*dwp = arg;
100 	dladm_dev_t	*ddp = dwp->dw_dev_list;
101 	dladm_dev_t	**lastp = &dwp->dw_dev_list;
102 
103 	while (ddp) {
104 		/*
105 		 * Skip duplicates.
106 		 */
107 		if (strcmp(ddp->dd_name, name) == 0)
108 			return;
109 
110 		lastp = &ddp->dd_next;
111 		ddp = ddp->dd_next;
112 	}
113 
114 	if ((ddp = malloc(sizeof (*ddp))) == NULL)
115 		return;
116 
117 	(void) strlcpy(ddp->dd_name, name, IFNAMSIZ);
118 	ddp->dd_next = NULL;
119 	*lastp = ddp;
120 }
121 
122 /*
123  * Walker callback invoked for each DDI_NT_NET node.
124  */
125 static int
126 i_dladm_nt_net_walk(di_node_t node, di_minor_t minor, void *arg)
127 {
128 	dl_info_ack_t	dlia;
129 	char		name[IFNAMSIZ];
130 	int		fd;
131 	char		*provider;
132 	uint_t		ppa;
133 
134 	provider = di_minor_name(minor);
135 
136 	if ((fd = dlpi_open(provider)) < 0)
137 		return (DI_WALK_CONTINUE);
138 
139 	if (dlpi_info(fd, -1, &dlia, NULL, NULL, NULL, NULL, NULL, NULL) < 0) {
140 		(void) dlpi_close(fd);
141 		return (DI_WALK_CONTINUE);
142 	}
143 
144 	if (dlia.dl_provider_style == DL_STYLE1) {
145 		i_dladm_nt_net_add(arg, provider);
146 		(void) dlpi_close(fd);
147 		return (DI_WALK_CONTINUE);
148 	}
149 
150 	ppa = di_instance(node);
151 
152 	if (dlpi_attach(fd, -1, ppa) < 0) {
153 		(void) dlpi_close(fd);
154 		return (DI_WALK_CONTINUE);
155 	}
156 	(void) snprintf(name, IFNAMSIZ - 1, "%s%d", provider, ppa);
157 	i_dladm_nt_net_add(arg, name);
158 	(void) dlpi_close(fd);
159 	return (DI_WALK_CONTINUE);
160 }
161 
162 /*
163  * Invoke the specified callback function for each active DDI_NT_NET
164  * node.
165  */
166 int
167 dladm_walk(void (*fn)(void *, const char *), void *arg)
168 {
169 	di_node_t	root;
170 	dladm_walk_t	dw;
171 	dladm_dev_t	*ddp, *last_ddp;
172 
173 	if ((root = di_init("/", DINFOCACHE)) == DI_NODE_NIL) {
174 		errno = EFAULT;
175 		return (-1);
176 	}
177 	dw.dw_dev_list = NULL;
178 
179 	(void) di_walk_minor(root, DDI_NT_NET, DI_CHECK_ALIAS, &dw,
180 	    i_dladm_nt_net_walk);
181 
182 	di_fini(root);
183 
184 	ddp = dw.dw_dev_list;
185 	while (ddp) {
186 		fn(arg, ddp->dd_name);
187 		(void) dladm_walk_vlan(fn, arg, ddp->dd_name);
188 		last_ddp = ddp;
189 		ddp = ddp->dd_next;
190 		free(last_ddp);
191 	}
192 
193 	return (0);
194 }
195 
196 /*
197  * Invoke the specified callback function for each vlan managed by dld
198  */
199 int
200 dladm_walk_vlan(void (*fn)(void *, const char *), void *arg, const char *name)
201 {
202 	int		fd, bufsize, i;
203 	int		nvlan = 4094;
204 	dld_ioc_vlan_t	*iocp = NULL;
205 	dld_vlan_info_t	*dvip;
206 
207 	if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0)
208 		return (-1);
209 
210 	bufsize = sizeof (dld_ioc_vlan_t) + nvlan * sizeof (dld_vlan_info_t);
211 
212 	if ((iocp = (dld_ioc_vlan_t *)calloc(1, bufsize)) == NULL)
213 		return (-1);
214 
215 	(void) strlcpy((char *)iocp->div_name, name, IFNAMSIZ);
216 	if (i_dladm_ioctl(fd, DLDIOCVLAN, iocp, bufsize) == 0) {
217 		dvip = (dld_vlan_info_t *)(iocp + 1);
218 		for (i = 0; i < iocp->div_count; i++)
219 			(*fn)(arg, dvip[i].dvi_name);
220 	}
221 	/*
222 	 * Note: Callers of dladm_walk_vlan() ignore the return
223 	 * value of this routine. So ignoring ioctl failure case
224 	 * and just returning 0.
225 	 */
226 	free(iocp);
227 	(void) close(fd);
228 	return (0);
229 }
230 
231 
232 /*
233  * Returns the current attributes of the specified datalink.
234  */
235 int
236 dladm_info(const char *name, dladm_attr_t *dap)
237 {
238 	int		fd;
239 
240 	if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0)
241 		return (-1);
242 
243 	if (i_dladm_info(fd, name, dap) < 0)
244 		goto failed;
245 
246 	(void) close(fd);
247 	return (0);
248 
249 failed:
250 	(void) close(fd);
251 	return (-1);
252 }
253