xref: /illumos-gate/usr/src/lib/libdladm/common/libdladm.c (revision aae21359c9c25c5100c4853afd7334521ede3276)
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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <stdio.h>
30 #include <sys/types.h>
31 #include <string.h>
32 #include <fcntl.h>
33 #include <unistd.h>
34 #include <stropts.h>
35 #include <stdlib.h>
36 #include <errno.h>
37 #include <libdevinfo.h>
38 #include <libdlpi.h>
39 #include <libdladm.h>
40 #include <sys/dld.h>
41 #include <net/if.h>
42 
43 typedef struct dladm_dev {
44 	char			dd_name[IFNAMSIZ];
45 	struct dladm_dev	*dd_next;
46 } dladm_dev_t;
47 
48 typedef struct dladm_walk {
49 	dladm_dev_t		*dw_dev_list;
50 } dladm_walk_t;
51 
52 /*
53  * Issue an ioctl to the specified file descriptor attached to the
54  * DLD control driver interface.
55  */
56 static int
57 i_dladm_ioctl(int fd, int ic_cmd, void *ic_dp, int ic_len)
58 {
59 	struct strioctl	iocb;
60 
61 	iocb.ic_cmd = ic_cmd;
62 	iocb.ic_timout = 0;
63 	iocb.ic_len = ic_len;
64 	iocb.ic_dp = (char *)ic_dp;
65 
66 	return (ioctl(fd, I_STR, &iocb));
67 }
68 
69 /*
70  * Return the attributes of the specified datalink from the DLD driver.
71  */
72 static int
73 i_dladm_info(int fd, const char *name, dladm_attr_t *dap)
74 {
75 	dld_ioc_attr_t	dia;
76 
77 	if (strlen(name) >= IFNAMSIZ) {
78 		errno = EINVAL;
79 		return (-1);
80 	}
81 
82 	(void) strlcpy(dia.dia_name, name, IFNAMSIZ);
83 
84 	if (i_dladm_ioctl(fd, DLDIOCATTR, &dia, sizeof (dia)) < 0)
85 		return (-1);
86 
87 	(void) strlcpy(dap->da_dev, dia.dia_dev, MAXNAMELEN);
88 	dap->da_max_sdu = dia.dia_max_sdu;
89 	dap->da_port = dia.dia_port;
90 	dap->da_vid = dia.dia_vid;
91 
92 	return (0);
93 }
94 
95 /*
96  * Adds a datalink to the array corresponding to arg.
97  */
98 static void
99 i_dladm_nt_net_add(void *arg, char *name)
100 {
101 	dladm_walk_t	*dwp = arg;
102 	dladm_dev_t	*ddp = dwp->dw_dev_list;
103 	dladm_dev_t	**lastp = &dwp->dw_dev_list;
104 
105 	while (ddp) {
106 		/*
107 		 * Skip duplicates.
108 		 */
109 		if (strcmp(ddp->dd_name, name) == 0)
110 			return;
111 
112 		lastp = &ddp->dd_next;
113 		ddp = ddp->dd_next;
114 	}
115 
116 	if ((ddp = malloc(sizeof (*ddp))) == NULL)
117 		return;
118 
119 	(void) strlcpy(ddp->dd_name, name, IFNAMSIZ);
120 	ddp->dd_next = NULL;
121 	*lastp = ddp;
122 }
123 
124 /*
125  * Walker callback invoked for each DDI_NT_NET node.
126  */
127 static int
128 i_dladm_nt_net_walk(di_node_t node, di_minor_t minor, void *arg)
129 {
130 	dl_info_ack_t	dlia;
131 	char		name[IFNAMSIZ];
132 	int		fd;
133 	char		*provider;
134 	uint_t		ppa;
135 
136 	provider = di_minor_name(minor);
137 
138 	if ((fd = dlpi_open(provider)) < 0)
139 		return (DI_WALK_CONTINUE);
140 
141 	if (dlpi_info(fd, -1, &dlia, NULL, NULL, NULL, NULL, NULL, NULL) < 0) {
142 		(void) dlpi_close(fd);
143 		return (DI_WALK_CONTINUE);
144 	}
145 
146 	if (dlia.dl_provider_style == DL_STYLE1) {
147 		i_dladm_nt_net_add(arg, provider);
148 		(void) dlpi_close(fd);
149 		return (DI_WALK_CONTINUE);
150 	}
151 
152 	ppa = di_instance(node);
153 
154 	if (dlpi_attach(fd, -1, ppa) < 0) {
155 		(void) dlpi_close(fd);
156 		return (DI_WALK_CONTINUE);
157 	}
158 	(void) snprintf(name, IFNAMSIZ - 1, "%s%d", provider, ppa);
159 	i_dladm_nt_net_add(arg, name);
160 	(void) dlpi_close(fd);
161 	return (DI_WALK_CONTINUE);
162 }
163 
164 /*
165  * Invoke the specified callback function for each active DDI_NT_NET
166  * node.
167  */
168 int
169 dladm_walk(void (*fn)(void *, const char *), void *arg)
170 {
171 	di_node_t	root;
172 	dladm_walk_t	dw;
173 	dladm_dev_t	*ddp, *last_ddp;
174 
175 	if ((root = di_init("/", DINFOCACHE)) == DI_NODE_NIL) {
176 		errno = EFAULT;
177 		return (-1);
178 	}
179 	dw.dw_dev_list = NULL;
180 
181 	(void) di_walk_minor(root, DDI_NT_NET, DI_CHECK_ALIAS, &dw,
182 	    i_dladm_nt_net_walk);
183 
184 	di_fini(root);
185 
186 	ddp = dw.dw_dev_list;
187 	while (ddp) {
188 		fn(arg, ddp->dd_name);
189 		dladm_walk_vlan(fn, arg, ddp->dd_name);
190 		last_ddp = ddp;
191 		ddp = ddp->dd_next;
192 		free(last_ddp);
193 	}
194 
195 	return (0);
196 }
197 
198 /*
199  * Invoke the specified callback function for each vlan managed by dld
200  */
201 int
202 dladm_walk_vlan(void (*fn)(void *, const char *), void *arg, const char *name)
203 {
204 	int		fd, bufsize, i;
205 	int		nvlan = 4094;
206 	dld_ioc_vlan_t	*iocp = NULL;
207 	dld_vlan_info_t	*dvip;
208 
209 	if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0)
210 		return (-1);
211 
212 	bufsize = sizeof (dld_ioc_vlan_t) + nvlan * sizeof (dld_vlan_info_t);
213 
214 	if ((iocp = (dld_ioc_vlan_t *)calloc(1, bufsize)) == NULL)
215 		return (-1);
216 
217 	if (strncmp(name, "aggr", 4) == 0) {
218 		(void) strlcpy((char *)iocp->div_name, "aggr0", IFNAMSIZ);
219 		iocp->div_port = atoi(strpbrk(name, "0123456789"));
220 	} else {
221 		(void) strlcpy((char *)iocp->div_name, name, IFNAMSIZ);
222 		iocp->div_port = 0;
223 	}
224 	if (i_dladm_ioctl(fd, DLDIOCVLAN, iocp, bufsize) == 0) {
225 		dvip = (dld_vlan_info_t *)(iocp + 1);
226 		for (i = 0; i < iocp->div_count; i++)
227 			(*fn)(arg, dvip[i].dvi_name);
228 	}
229 	/*
230 	 * Note: Callers of dladm_walk_vlan() ignore the return
231 	 * value of this routine. So ignoring ioctl failure case
232 	 * and just returning 0.
233 	 */
234 	free(iocp);
235 	(void) close(fd);
236 	return (0);
237 }
238 
239 
240 /*
241  * Returns the current attributes of the specified datalink.
242  */
243 int
244 dladm_info(const char *name, dladm_attr_t *dap)
245 {
246 	int		fd;
247 
248 	if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0)
249 		return (-1);
250 
251 	if (i_dladm_info(fd, name, dap) < 0)
252 		goto failed;
253 
254 	(void) close(fd);
255 	return (0);
256 
257 failed:
258 	(void) close(fd);
259 	return (-1);
260 }
261