PSARC 2008/473 Fine-Grained Privileges for Datalink Administration
[unleashed.git] / usr / src / lib / libdladm / common / libdlvnic.c
blobac97372785d4133a576c3e9bde6dec7f8e2b2575
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #include <stdio.h>
27 #include <sys/types.h>
28 #include <sys/stat.h>
29 #include <string.h>
30 #include <fcntl.h>
31 #include <unistd.h>
32 #include <stropts.h>
33 #include <stdlib.h>
34 #include <errno.h>
35 #include <strings.h>
36 #include <libintl.h>
37 #include <net/if_types.h>
38 #include <net/if_dl.h>
39 #include <libdladm_impl.h>
40 #include <libdllink.h>
41 #include <libdlvnic.h>
44 * VNIC administration library.
47 /* Limits on buffer size for VNIC_IOC_INFO request */
48 #define MIN_INFO_SIZE (4*1024)
49 #define MAX_INFO_SIZE (128*1024)
51 /* configuration database entry */
52 typedef struct dladm_vnic_attr_db {
53 datalink_id_t vt_vnic_id;
54 datalink_id_t vt_link_id;
55 vnic_mac_addr_type_t vt_mac_addr_type;
56 uint_t vt_mac_len;
57 uchar_t vt_mac_addr[MAXMACADDRLEN];
58 } dladm_vnic_attr_db_t;
60 typedef struct dladm_vnic_modify_attr {
61 vnic_mac_addr_type_t vm_mac_addr_type;
62 int vm_mac_len;
63 uchar_t vm_mac_addr[MAXMACADDRLEN];
64 } dladm_vnic_modify_attr_t;
67 * Send a create command to the VNIC driver.
69 static dladm_status_t
70 i_dladm_vnic_create_sys(int fd, dladm_vnic_attr_db_t *attr)
72 vnic_ioc_create_t ioc;
74 ioc.vc_vnic_id = attr->vt_vnic_id;
75 ioc.vc_link_id = attr->vt_link_id;
76 ioc.vc_mac_addr_type = attr->vt_mac_addr_type;
77 ioc.vc_mac_len = attr->vt_mac_len;
78 bcopy(attr->vt_mac_addr, ioc.vc_mac_addr, attr->vt_mac_len);
80 if (ioctl(fd, VNIC_IOC_CREATE, &ioc) < 0)
81 return (dladm_errno2status(errno));
83 return (DLADM_STATUS_OK);
87 * Send a modify command to the VNIC driver.
89 static dladm_status_t
90 i_dladm_vnic_modify_sys(datalink_id_t vnic_id, uint32_t modify_mask,
91 dladm_vnic_modify_attr_t *attr)
93 dladm_status_t status = DLADM_STATUS_OK;
94 int fd;
95 vnic_ioc_modify_t ioc;
97 ioc.vm_vnic_id = vnic_id;
99 ioc.vm_modify_mask = 0;
100 if (modify_mask & DLADM_VNIC_MODIFY_ADDR)
101 ioc.vm_modify_mask |= VNIC_IOC_MODIFY_ADDR;
103 ioc.vm_mac_addr_type = attr->vm_mac_addr_type;
104 ioc.vm_mac_len = attr->vm_mac_len;
105 bcopy(attr->vm_mac_addr, ioc.vm_mac_addr, MAXMACADDRLEN);
107 if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0)
108 return (dladm_errno2status(errno));
110 if (ioctl(fd, VNIC_IOC_MODIFY, &ioc) < 0)
111 status = dladm_errno2status(errno);
113 (void) close(fd);
114 return (status);
118 * Get the configuration information of the given VNIC.
120 dladm_status_t
121 dladm_vnic_info(datalink_id_t vnic_id, dladm_vnic_attr_sys_t *attrp,
122 uint32_t flags)
124 vnic_ioc_info_t *ioc;
125 vnic_ioc_info_vnic_t *vnic;
126 int bufsize, fd;
127 dladm_status_t status = DLADM_STATUS_OK;
129 /* for now, only temporary creations are supported */
130 if (flags & DLADM_OPT_PERSIST)
131 return (dladm_errno2status(ENOTSUP));
133 if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) == -1)
134 return (dladm_errno2status(errno));
136 bufsize = sizeof (vnic_ioc_info_t) + sizeof (vnic_ioc_info_vnic_t);
137 ioc = (vnic_ioc_info_t *)calloc(1, bufsize);
138 if (ioc == NULL) {
139 (void) close(fd);
140 return (dladm_errno2status(ENOMEM));
143 ioc->vi_vnic_id = vnic_id;
144 ioc->vi_size = bufsize - sizeof (vnic_ioc_info_t);
145 if (ioctl(fd, VNIC_IOC_INFO, ioc) != 0) {
146 status = dladm_errno2status(errno);
147 goto bail;
150 vnic = (vnic_ioc_info_vnic_t *)(ioc + 1);
152 attrp->va_vnic_id = vnic->vn_vnic_id;
153 attrp->va_link_id = vnic->vn_link_id;
154 attrp->va_mac_addr_type = vnic->vn_mac_addr_type;
155 bcopy(vnic->vn_mac_addr, attrp->va_mac_addr, ETHERADDRL);
156 attrp->va_mac_len = vnic->vn_mac_len;
158 bail:
159 free(ioc);
160 (void) close(fd);
161 return (status);
165 * Remove a VNIC from the kernel.
167 static dladm_status_t
168 i_dladm_vnic_delete_sys(int fd, dladm_vnic_attr_sys_t *attr)
170 vnic_ioc_delete_t ioc;
172 ioc.vd_vnic_id = attr->va_vnic_id;
174 if (ioctl(fd, VNIC_IOC_DELETE, &ioc) < 0)
175 return (dladm_errno2status(errno));
177 return (DLADM_STATUS_OK);
181 * Convert between MAC address types and their string representations.
184 typedef struct dladm_vnic_addr_type_s {
185 char *va_str;
186 vnic_mac_addr_type_t va_type;
187 } dladm_vnic_addr_type_t;
189 static dladm_vnic_addr_type_t addr_types[] = {
190 {"fixed", VNIC_MAC_ADDR_TYPE_FIXED},
193 #define NADDR_TYPES (sizeof (addr_types) / sizeof (dladm_vnic_addr_type_t))
196 * Return DLADM_STATUS_OK if a matching type was found,
197 * DLADM_STATUS_BADARG otherwise
199 dladm_status_t
200 dladm_vnic_str2macaddrtype(const char *str, vnic_mac_addr_type_t *val)
202 int i;
203 dladm_vnic_addr_type_t *type;
205 for (i = 0; i < NADDR_TYPES; i++) {
206 type = &addr_types[i];
207 if (strncmp(str, type->va_str, strlen(type->va_str)) == 0) {
208 *val = type->va_type;
209 return (DLADM_STATUS_OK);
213 return (DLADM_STATUS_BADARG);
217 * Create a new VNIC. Update the configuration file and bring it up.
219 dladm_status_t
220 dladm_vnic_create(const char *vnic, datalink_id_t linkid,
221 vnic_mac_addr_type_t mac_addr_type, uchar_t *mac_addr, int mac_len,
222 datalink_id_t *vnic_id_out, uint32_t flags)
224 dladm_vnic_attr_db_t attr;
225 int i, fd;
226 datalink_id_t vnic_id;
227 datalink_class_t class;
228 uint32_t media;
229 char *name = (char *)vnic;
230 dladm_status_t status;
233 * Sanity test arguments.
235 if (flags & DLADM_OPT_PERSIST)
236 return (dladm_errno2status(ENOTSUP));
238 if (mac_len > MAXMACADDRLEN)
239 return (DLADM_STATUS_INVALIDMACADDRLEN);
241 for (i = 0; i < NADDR_TYPES; i++) {
242 if (mac_addr_type == addr_types[i].va_type)
243 break;
245 if (i == NADDR_TYPES)
246 return (DLADM_STATUS_INVALIDMACADDRTYPE);
248 if ((status = dladm_datalink_id2info(linkid, NULL, &class, &media,
249 NULL, 0)) != DLADM_STATUS_OK) {
250 return (status);
253 if (class == DATALINK_CLASS_VNIC)
254 return (DLADM_STATUS_BADARG);
256 if (vnic == NULL) {
257 flags |= DLADM_OPT_PREFIX;
258 name = "vnic";
261 if ((status = dladm_create_datalink_id(name, DATALINK_CLASS_VNIC,
262 media, flags, &vnic_id)) != DLADM_STATUS_OK) {
263 return (status);
266 bzero(&attr, sizeof (attr));
267 attr.vt_vnic_id = vnic_id;
268 attr.vt_link_id = linkid;
269 attr.vt_mac_addr_type = mac_addr_type;
270 attr.vt_mac_len = mac_len;
271 bcopy(mac_addr, attr.vt_mac_addr, mac_len);
273 if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0) {
274 status = dladm_errno2status(errno);
275 goto done;
278 status = i_dladm_vnic_create_sys(fd, &attr);
279 (void) close(fd);
281 done:
282 if (status != DLADM_STATUS_OK) {
283 (void) dladm_destroy_datalink_id(vnic_id,
284 flags & ~DLADM_OPT_PREFIX);
285 } else {
286 *vnic_id_out = vnic_id;
289 return (status);
293 * Modify the properties of a VNIC.
295 dladm_status_t
296 dladm_vnic_modify(datalink_id_t vnic_id, uint32_t modify_mask,
297 vnic_mac_addr_type_t mac_addr_type, uint_t mac_len, uchar_t *mac_addr,
298 uint32_t flags)
300 dladm_vnic_modify_attr_t new_attr;
302 /* for now, only temporary creations are supported */
303 if (flags & DLADM_OPT_PERSIST)
304 return (dladm_errno2status(ENOTSUP));
306 bzero(&new_attr, sizeof (new_attr));
308 if (modify_mask & DLADM_VNIC_MODIFY_ADDR) {
309 new_attr.vm_mac_addr_type = mac_addr_type;
310 new_attr.vm_mac_len = mac_len;
311 bcopy(mac_addr, new_attr.vm_mac_addr, MAXMACADDRLEN);
314 /* update the properties of the existing VNIC */
315 return (i_dladm_vnic_modify_sys(vnic_id, modify_mask, &new_attr));
319 * Delete a VNIC.
321 dladm_status_t
322 dladm_vnic_delete(datalink_id_t vnic_id, uint32_t flags)
324 dladm_status_t status;
325 dladm_vnic_attr_sys_t sys_attr;
326 int fd;
328 /* for now, only temporary deletes are supported */
329 if (flags & DLADM_OPT_PERSIST)
330 return (dladm_errno2status(ENOTSUP));
332 if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0)
333 return (dladm_errno2status(errno));
335 sys_attr.va_vnic_id = vnic_id;
336 status = i_dladm_vnic_delete_sys(fd, &sys_attr);
337 (void) close(fd);
339 if (status != DLADM_STATUS_OK)
340 return (status);
342 (void) dladm_destroy_datalink_id(vnic_id, flags);
343 return (status);