1843e1988Sjohnlev /* 2843e1988Sjohnlev * CDDL HEADER START 3843e1988Sjohnlev * 4843e1988Sjohnlev * The contents of this file are subject to the terms of the 5843e1988Sjohnlev * Common Development and Distribution License (the "License"). 6843e1988Sjohnlev * You may not use this file except in compliance with the License. 7843e1988Sjohnlev * 8843e1988Sjohnlev * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9843e1988Sjohnlev * or http://www.opensolaris.org/os/licensing. 10843e1988Sjohnlev * See the License for the specific language governing permissions 11843e1988Sjohnlev * and limitations under the License. 12843e1988Sjohnlev * 13843e1988Sjohnlev * When distributing Covered Code, include this CDDL HEADER in each 14843e1988Sjohnlev * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15843e1988Sjohnlev * If applicable, add the following below this CDDL HEADER, with the 16843e1988Sjohnlev * fields enclosed by brackets "[]" replaced with your own identifying 17843e1988Sjohnlev * information: Portions Copyright [yyyy] [name of copyright owner] 18843e1988Sjohnlev * 19843e1988Sjohnlev * CDDL HEADER END 20843e1988Sjohnlev */ 21843e1988Sjohnlev /* 22d62bc4baSyz147064 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23843e1988Sjohnlev * Use is subject to license terms. 24843e1988Sjohnlev */ 25843e1988Sjohnlev 26843e1988Sjohnlev #include <stdio.h> 27843e1988Sjohnlev #include <sys/types.h> 28843e1988Sjohnlev #include <sys/stat.h> 29843e1988Sjohnlev #include <string.h> 30843e1988Sjohnlev #include <fcntl.h> 31843e1988Sjohnlev #include <unistd.h> 32843e1988Sjohnlev #include <stropts.h> 33843e1988Sjohnlev #include <stdlib.h> 34843e1988Sjohnlev #include <errno.h> 35843e1988Sjohnlev #include <strings.h> 36843e1988Sjohnlev #include <libintl.h> 37843e1988Sjohnlev #include <net/if_types.h> 38843e1988Sjohnlev #include <net/if_dl.h> 39843e1988Sjohnlev #include <libdladm_impl.h> 40d62bc4baSyz147064 #include <libdllink.h> 41843e1988Sjohnlev #include <libdlvnic.h> 42843e1988Sjohnlev 43843e1988Sjohnlev /* 44843e1988Sjohnlev * VNIC administration library. 45843e1988Sjohnlev */ 46843e1988Sjohnlev 47843e1988Sjohnlev /* Limits on buffer size for VNIC_IOC_INFO request */ 48843e1988Sjohnlev #define MIN_INFO_SIZE (4*1024) 49843e1988Sjohnlev #define MAX_INFO_SIZE (128*1024) 50843e1988Sjohnlev 51843e1988Sjohnlev /* configuration database entry */ 52843e1988Sjohnlev typedef struct dladm_vnic_attr_db { 53d62bc4baSyz147064 datalink_id_t vt_vnic_id; 54d62bc4baSyz147064 datalink_id_t vt_link_id; 55843e1988Sjohnlev vnic_mac_addr_type_t vt_mac_addr_type; 56843e1988Sjohnlev uint_t vt_mac_len; 57843e1988Sjohnlev uchar_t vt_mac_addr[MAXMACADDRLEN]; 58843e1988Sjohnlev } dladm_vnic_attr_db_t; 59843e1988Sjohnlev 60843e1988Sjohnlev typedef struct dladm_vnic_modify_attr { 61843e1988Sjohnlev vnic_mac_addr_type_t vm_mac_addr_type; 62843e1988Sjohnlev int vm_mac_len; 63843e1988Sjohnlev uchar_t vm_mac_addr[MAXMACADDRLEN]; 64843e1988Sjohnlev } dladm_vnic_modify_attr_t; 65843e1988Sjohnlev 66843e1988Sjohnlev /* 67843e1988Sjohnlev * Send a create command to the VNIC driver. 68843e1988Sjohnlev */ 69843e1988Sjohnlev static dladm_status_t 70843e1988Sjohnlev i_dladm_vnic_create_sys(int fd, dladm_vnic_attr_db_t *attr) 71843e1988Sjohnlev { 72843e1988Sjohnlev vnic_ioc_create_t ioc; 73843e1988Sjohnlev 74843e1988Sjohnlev ioc.vc_vnic_id = attr->vt_vnic_id; 75d62bc4baSyz147064 ioc.vc_link_id = attr->vt_link_id; 76843e1988Sjohnlev ioc.vc_mac_addr_type = attr->vt_mac_addr_type; 77843e1988Sjohnlev ioc.vc_mac_len = attr->vt_mac_len; 78843e1988Sjohnlev bcopy(attr->vt_mac_addr, ioc.vc_mac_addr, attr->vt_mac_len); 79843e1988Sjohnlev 80*eae72b5bSSebastien Roy if (ioctl(fd, VNIC_IOC_CREATE, &ioc) < 0) 81843e1988Sjohnlev return (dladm_errno2status(errno)); 82843e1988Sjohnlev 83843e1988Sjohnlev return (DLADM_STATUS_OK); 84843e1988Sjohnlev } 85843e1988Sjohnlev 86843e1988Sjohnlev /* 87843e1988Sjohnlev * Send a modify command to the VNIC driver. 88843e1988Sjohnlev */ 89843e1988Sjohnlev static dladm_status_t 90d62bc4baSyz147064 i_dladm_vnic_modify_sys(datalink_id_t vnic_id, uint32_t modify_mask, 91843e1988Sjohnlev dladm_vnic_modify_attr_t *attr) 92843e1988Sjohnlev { 93*eae72b5bSSebastien Roy dladm_status_t status = DLADM_STATUS_OK; 94843e1988Sjohnlev int fd; 95843e1988Sjohnlev vnic_ioc_modify_t ioc; 96843e1988Sjohnlev 97843e1988Sjohnlev ioc.vm_vnic_id = vnic_id; 98843e1988Sjohnlev 99843e1988Sjohnlev ioc.vm_modify_mask = 0; 100843e1988Sjohnlev if (modify_mask & DLADM_VNIC_MODIFY_ADDR) 101843e1988Sjohnlev ioc.vm_modify_mask |= VNIC_IOC_MODIFY_ADDR; 102843e1988Sjohnlev 103843e1988Sjohnlev ioc.vm_mac_addr_type = attr->vm_mac_addr_type; 104843e1988Sjohnlev ioc.vm_mac_len = attr->vm_mac_len; 105843e1988Sjohnlev bcopy(attr->vm_mac_addr, ioc.vm_mac_addr, MAXMACADDRLEN); 106843e1988Sjohnlev 107*eae72b5bSSebastien Roy if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0) 108843e1988Sjohnlev return (dladm_errno2status(errno)); 109843e1988Sjohnlev 110*eae72b5bSSebastien Roy if (ioctl(fd, VNIC_IOC_MODIFY, &ioc) < 0) 111*eae72b5bSSebastien Roy status = dladm_errno2status(errno); 112843e1988Sjohnlev 113843e1988Sjohnlev (void) close(fd); 114*eae72b5bSSebastien Roy return (status); 115843e1988Sjohnlev } 116843e1988Sjohnlev 117843e1988Sjohnlev /* 118d62bc4baSyz147064 * Get the configuration information of the given VNIC. 119843e1988Sjohnlev */ 120843e1988Sjohnlev dladm_status_t 121d62bc4baSyz147064 dladm_vnic_info(datalink_id_t vnic_id, dladm_vnic_attr_sys_t *attrp, 122d62bc4baSyz147064 uint32_t flags) 123843e1988Sjohnlev { 124843e1988Sjohnlev vnic_ioc_info_t *ioc; 125843e1988Sjohnlev vnic_ioc_info_vnic_t *vnic; 126*eae72b5bSSebastien Roy int bufsize, fd; 127843e1988Sjohnlev dladm_status_t status = DLADM_STATUS_OK; 128843e1988Sjohnlev 129d62bc4baSyz147064 /* for now, only temporary creations are supported */ 130d62bc4baSyz147064 if (flags & DLADM_OPT_PERSIST) 131d62bc4baSyz147064 return (dladm_errno2status(ENOTSUP)); 132d62bc4baSyz147064 133*eae72b5bSSebastien Roy if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) == -1) 134843e1988Sjohnlev return (dladm_errno2status(errno)); 135843e1988Sjohnlev 136d62bc4baSyz147064 bufsize = sizeof (vnic_ioc_info_t) + sizeof (vnic_ioc_info_vnic_t); 137843e1988Sjohnlev ioc = (vnic_ioc_info_t *)calloc(1, bufsize); 138843e1988Sjohnlev if (ioc == NULL) { 139843e1988Sjohnlev (void) close(fd); 140843e1988Sjohnlev return (dladm_errno2status(ENOMEM)); 141843e1988Sjohnlev } 142843e1988Sjohnlev 143d62bc4baSyz147064 ioc->vi_vnic_id = vnic_id; 144*eae72b5bSSebastien Roy ioc->vi_size = bufsize - sizeof (vnic_ioc_info_t); 145*eae72b5bSSebastien Roy if (ioctl(fd, VNIC_IOC_INFO, ioc) != 0) { 146843e1988Sjohnlev status = dladm_errno2status(errno); 147843e1988Sjohnlev goto bail; 148843e1988Sjohnlev } 149843e1988Sjohnlev 150d62bc4baSyz147064 vnic = (vnic_ioc_info_vnic_t *)(ioc + 1); 151843e1988Sjohnlev 152d62bc4baSyz147064 attrp->va_vnic_id = vnic->vn_vnic_id; 153d62bc4baSyz147064 attrp->va_link_id = vnic->vn_link_id; 154d62bc4baSyz147064 attrp->va_mac_addr_type = vnic->vn_mac_addr_type; 155d62bc4baSyz147064 bcopy(vnic->vn_mac_addr, attrp->va_mac_addr, ETHERADDRL); 156d62bc4baSyz147064 attrp->va_mac_len = vnic->vn_mac_len; 157843e1988Sjohnlev 158843e1988Sjohnlev bail: 159843e1988Sjohnlev free(ioc); 160843e1988Sjohnlev (void) close(fd); 161843e1988Sjohnlev return (status); 162843e1988Sjohnlev } 163843e1988Sjohnlev 164843e1988Sjohnlev /* 165843e1988Sjohnlev * Remove a VNIC from the kernel. 166843e1988Sjohnlev */ 167843e1988Sjohnlev static dladm_status_t 168843e1988Sjohnlev i_dladm_vnic_delete_sys(int fd, dladm_vnic_attr_sys_t *attr) 169843e1988Sjohnlev { 170843e1988Sjohnlev vnic_ioc_delete_t ioc; 171843e1988Sjohnlev 172843e1988Sjohnlev ioc.vd_vnic_id = attr->va_vnic_id; 173843e1988Sjohnlev 174*eae72b5bSSebastien Roy if (ioctl(fd, VNIC_IOC_DELETE, &ioc) < 0) 175843e1988Sjohnlev return (dladm_errno2status(errno)); 176843e1988Sjohnlev 177843e1988Sjohnlev return (DLADM_STATUS_OK); 178843e1988Sjohnlev } 179843e1988Sjohnlev 180843e1988Sjohnlev /* 181843e1988Sjohnlev * Convert between MAC address types and their string representations. 182843e1988Sjohnlev */ 183843e1988Sjohnlev 184843e1988Sjohnlev typedef struct dladm_vnic_addr_type_s { 185843e1988Sjohnlev char *va_str; 186843e1988Sjohnlev vnic_mac_addr_type_t va_type; 187843e1988Sjohnlev } dladm_vnic_addr_type_t; 188843e1988Sjohnlev 189843e1988Sjohnlev static dladm_vnic_addr_type_t addr_types[] = { 190843e1988Sjohnlev {"fixed", VNIC_MAC_ADDR_TYPE_FIXED}, 191843e1988Sjohnlev }; 192843e1988Sjohnlev 193843e1988Sjohnlev #define NADDR_TYPES (sizeof (addr_types) / sizeof (dladm_vnic_addr_type_t)) 194843e1988Sjohnlev 195d62bc4baSyz147064 /* 196d62bc4baSyz147064 * Return DLADM_STATUS_OK if a matching type was found, 197d62bc4baSyz147064 * DLADM_STATUS_BADARG otherwise 198d62bc4baSyz147064 */ 199d62bc4baSyz147064 dladm_status_t 200d62bc4baSyz147064 dladm_vnic_str2macaddrtype(const char *str, vnic_mac_addr_type_t *val) 201843e1988Sjohnlev { 202843e1988Sjohnlev int i; 203843e1988Sjohnlev dladm_vnic_addr_type_t *type; 204843e1988Sjohnlev 205843e1988Sjohnlev for (i = 0; i < NADDR_TYPES; i++) { 206843e1988Sjohnlev type = &addr_types[i]; 207843e1988Sjohnlev if (strncmp(str, type->va_str, strlen(type->va_str)) == 0) { 208843e1988Sjohnlev *val = type->va_type; 209843e1988Sjohnlev return (DLADM_STATUS_OK); 210843e1988Sjohnlev } 211843e1988Sjohnlev } 212843e1988Sjohnlev 213d62bc4baSyz147064 return (DLADM_STATUS_BADARG); 214843e1988Sjohnlev } 215843e1988Sjohnlev 216843e1988Sjohnlev /* 217843e1988Sjohnlev * Create a new VNIC. Update the configuration file and bring it up. 218843e1988Sjohnlev */ 219843e1988Sjohnlev dladm_status_t 220d62bc4baSyz147064 dladm_vnic_create(const char *vnic, datalink_id_t linkid, 221843e1988Sjohnlev vnic_mac_addr_type_t mac_addr_type, uchar_t *mac_addr, int mac_len, 222d62bc4baSyz147064 datalink_id_t *vnic_id_out, uint32_t flags) 223843e1988Sjohnlev { 224843e1988Sjohnlev dladm_vnic_attr_db_t attr; 225d62bc4baSyz147064 int i, fd; 226d62bc4baSyz147064 datalink_id_t vnic_id; 227d62bc4baSyz147064 datalink_class_t class; 228d62bc4baSyz147064 uint32_t media; 229d62bc4baSyz147064 char *name = (char *)vnic; 230843e1988Sjohnlev dladm_status_t status; 231843e1988Sjohnlev 232843e1988Sjohnlev /* 233843e1988Sjohnlev * Sanity test arguments. 234843e1988Sjohnlev */ 235d62bc4baSyz147064 if (flags & DLADM_OPT_PERSIST) 236d62bc4baSyz147064 return (dladm_errno2status(ENOTSUP)); 237843e1988Sjohnlev 238843e1988Sjohnlev if (mac_len > MAXMACADDRLEN) 239843e1988Sjohnlev return (DLADM_STATUS_INVALIDMACADDRLEN); 240843e1988Sjohnlev 241843e1988Sjohnlev for (i = 0; i < NADDR_TYPES; i++) { 242843e1988Sjohnlev if (mac_addr_type == addr_types[i].va_type) 243843e1988Sjohnlev break; 244843e1988Sjohnlev } 245843e1988Sjohnlev if (i == NADDR_TYPES) 246843e1988Sjohnlev return (DLADM_STATUS_INVALIDMACADDRTYPE); 247843e1988Sjohnlev 248d62bc4baSyz147064 if ((status = dladm_datalink_id2info(linkid, NULL, &class, &media, 249d62bc4baSyz147064 NULL, 0)) != DLADM_STATUS_OK) { 250843e1988Sjohnlev return (status); 251d62bc4baSyz147064 } 252d62bc4baSyz147064 253d62bc4baSyz147064 if (class == DATALINK_CLASS_VNIC) 254d62bc4baSyz147064 return (DLADM_STATUS_BADARG); 255d62bc4baSyz147064 256d62bc4baSyz147064 if (vnic == NULL) { 257d62bc4baSyz147064 flags |= DLADM_OPT_PREFIX; 258d62bc4baSyz147064 name = "vnic"; 259d62bc4baSyz147064 } 260d62bc4baSyz147064 261d62bc4baSyz147064 if ((status = dladm_create_datalink_id(name, DATALINK_CLASS_VNIC, 262d62bc4baSyz147064 media, flags, &vnic_id)) != DLADM_STATUS_OK) { 263d62bc4baSyz147064 return (status); 264843e1988Sjohnlev } 265843e1988Sjohnlev 266843e1988Sjohnlev bzero(&attr, sizeof (attr)); 267843e1988Sjohnlev attr.vt_vnic_id = vnic_id; 268d62bc4baSyz147064 attr.vt_link_id = linkid; 269843e1988Sjohnlev attr.vt_mac_addr_type = mac_addr_type; 270843e1988Sjohnlev attr.vt_mac_len = mac_len; 271843e1988Sjohnlev bcopy(mac_addr, attr.vt_mac_addr, mac_len); 272843e1988Sjohnlev 273*eae72b5bSSebastien Roy if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0) { 274d62bc4baSyz147064 status = dladm_errno2status(errno); 275d62bc4baSyz147064 goto done; 276d62bc4baSyz147064 } 277843e1988Sjohnlev 278d62bc4baSyz147064 status = i_dladm_vnic_create_sys(fd, &attr); 279d62bc4baSyz147064 (void) close(fd); 280843e1988Sjohnlev 281d62bc4baSyz147064 done: 282d62bc4baSyz147064 if (status != DLADM_STATUS_OK) { 283d62bc4baSyz147064 (void) dladm_destroy_datalink_id(vnic_id, 284d62bc4baSyz147064 flags & ~DLADM_OPT_PREFIX); 285d62bc4baSyz147064 } else { 286d62bc4baSyz147064 *vnic_id_out = vnic_id; 287d62bc4baSyz147064 } 288843e1988Sjohnlev 289843e1988Sjohnlev return (status); 290843e1988Sjohnlev } 291843e1988Sjohnlev 292843e1988Sjohnlev /* 293843e1988Sjohnlev * Modify the properties of a VNIC. 294843e1988Sjohnlev */ 295843e1988Sjohnlev dladm_status_t 296d62bc4baSyz147064 dladm_vnic_modify(datalink_id_t vnic_id, uint32_t modify_mask, 297843e1988Sjohnlev vnic_mac_addr_type_t mac_addr_type, uint_t mac_len, uchar_t *mac_addr, 298843e1988Sjohnlev uint32_t flags) 299843e1988Sjohnlev { 300843e1988Sjohnlev dladm_vnic_modify_attr_t new_attr; 301843e1988Sjohnlev 302843e1988Sjohnlev /* for now, only temporary creations are supported */ 303d62bc4baSyz147064 if (flags & DLADM_OPT_PERSIST) 304843e1988Sjohnlev return (dladm_errno2status(ENOTSUP)); 305843e1988Sjohnlev 306843e1988Sjohnlev bzero(&new_attr, sizeof (new_attr)); 307843e1988Sjohnlev 308843e1988Sjohnlev if (modify_mask & DLADM_VNIC_MODIFY_ADDR) { 309843e1988Sjohnlev new_attr.vm_mac_addr_type = mac_addr_type; 310843e1988Sjohnlev new_attr.vm_mac_len = mac_len; 311843e1988Sjohnlev bcopy(mac_addr, new_attr.vm_mac_addr, MAXMACADDRLEN); 312843e1988Sjohnlev } 313843e1988Sjohnlev 314843e1988Sjohnlev /* update the properties of the existing VNIC */ 315843e1988Sjohnlev return (i_dladm_vnic_modify_sys(vnic_id, modify_mask, &new_attr)); 316843e1988Sjohnlev } 317843e1988Sjohnlev 318843e1988Sjohnlev /* 319843e1988Sjohnlev * Delete a VNIC. 320843e1988Sjohnlev */ 321843e1988Sjohnlev dladm_status_t 322d62bc4baSyz147064 dladm_vnic_delete(datalink_id_t vnic_id, uint32_t flags) 323843e1988Sjohnlev { 324d62bc4baSyz147064 dladm_status_t status; 325843e1988Sjohnlev dladm_vnic_attr_sys_t sys_attr; 326d62bc4baSyz147064 int fd; 327843e1988Sjohnlev 328843e1988Sjohnlev /* for now, only temporary deletes are supported */ 329d62bc4baSyz147064 if (flags & DLADM_OPT_PERSIST) 330843e1988Sjohnlev return (dladm_errno2status(ENOTSUP)); 331843e1988Sjohnlev 332*eae72b5bSSebastien Roy if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0) 333d62bc4baSyz147064 return (dladm_errno2status(errno)); 334d62bc4baSyz147064 335843e1988Sjohnlev sys_attr.va_vnic_id = vnic_id; 336d62bc4baSyz147064 status = i_dladm_vnic_delete_sys(fd, &sys_attr); 337d62bc4baSyz147064 (void) close(fd); 338d62bc4baSyz147064 339d62bc4baSyz147064 if (status != DLADM_STATUS_OK) 340d62bc4baSyz147064 return (status); 341d62bc4baSyz147064 342d62bc4baSyz147064 (void) dladm_destroy_datalink_id(vnic_id, flags); 343d62bc4baSyz147064 return (status); 344843e1988Sjohnlev } 345