1*843e1988Sjohnlev /* 2*843e1988Sjohnlev * CDDL HEADER START 3*843e1988Sjohnlev * 4*843e1988Sjohnlev * The contents of this file are subject to the terms of the 5*843e1988Sjohnlev * Common Development and Distribution License (the "License"). 6*843e1988Sjohnlev * You may not use this file except in compliance with the License. 7*843e1988Sjohnlev * 8*843e1988Sjohnlev * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*843e1988Sjohnlev * or http://www.opensolaris.org/os/licensing. 10*843e1988Sjohnlev * See the License for the specific language governing permissions 11*843e1988Sjohnlev * and limitations under the License. 12*843e1988Sjohnlev * 13*843e1988Sjohnlev * When distributing Covered Code, include this CDDL HEADER in each 14*843e1988Sjohnlev * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*843e1988Sjohnlev * If applicable, add the following below this CDDL HEADER, with the 16*843e1988Sjohnlev * fields enclosed by brackets "[]" replaced with your own identifying 17*843e1988Sjohnlev * information: Portions Copyright [yyyy] [name of copyright owner] 18*843e1988Sjohnlev * 19*843e1988Sjohnlev * CDDL HEADER END 20*843e1988Sjohnlev */ 21*843e1988Sjohnlev /* 22*843e1988Sjohnlev * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 23*843e1988Sjohnlev * Use is subject to license terms. 24*843e1988Sjohnlev */ 25*843e1988Sjohnlev 26*843e1988Sjohnlev #pragma ident "%Z%%M% %I% %E% SMI" 27*843e1988Sjohnlev 28*843e1988Sjohnlev #include <stdio.h> 29*843e1988Sjohnlev #include <sys/types.h> 30*843e1988Sjohnlev #include <sys/stat.h> 31*843e1988Sjohnlev #include <string.h> 32*843e1988Sjohnlev #include <fcntl.h> 33*843e1988Sjohnlev #include <unistd.h> 34*843e1988Sjohnlev #include <stropts.h> 35*843e1988Sjohnlev #include <stdlib.h> 36*843e1988Sjohnlev #include <errno.h> 37*843e1988Sjohnlev #include <strings.h> 38*843e1988Sjohnlev #include <libintl.h> 39*843e1988Sjohnlev #include <net/if_types.h> 40*843e1988Sjohnlev #include <net/if_dl.h> 41*843e1988Sjohnlev #include <libdladm_impl.h> 42*843e1988Sjohnlev #include <libdlvnic.h> 43*843e1988Sjohnlev 44*843e1988Sjohnlev /* 45*843e1988Sjohnlev * VNIC administration library. 46*843e1988Sjohnlev */ 47*843e1988Sjohnlev 48*843e1988Sjohnlev #define VNIC_DEV "/devices/pseudo/vnic@0:" VNIC_CTL_NODE_NAME 49*843e1988Sjohnlev 50*843e1988Sjohnlev /* 51*843e1988Sjohnlev * Because by default the id is used as the DLPI device PPA and default 52*843e1988Sjohnlev * VLAN PPA's are calculated as ((1000 * vid) + PPA), the largest id 53*843e1988Sjohnlev * can't be > 999. We reserve the last 100 VNIC ids for automatic 54*843e1988Sjohnlev * VNIC id assignment. 55*843e1988Sjohnlev */ 56*843e1988Sjohnlev #define DLADM_VNIC_MIN_VNIC_ID 1 /* total range */ 57*843e1988Sjohnlev #define DLADM_VNIC_MAX_VNIC_ID 999 58*843e1988Sjohnlev #define DLADM_VNIC_MIN_VNIC_SPEC_ID 1 /* specified by user */ 59*843e1988Sjohnlev #define DLADM_VNIC_MAX_VNIC_SPEC_ID 899 60*843e1988Sjohnlev #define DLADM_VNIC_MIN_VNIC_AUTO_ID 900 /* picked automatically */ 61*843e1988Sjohnlev #define DLADM_VNIC_MAX_VNIC_AUTO_ID 999 62*843e1988Sjohnlev 63*843e1988Sjohnlev #define DLADM_VNIC_NUM_VNIC_AUTO_ID (DLADM_VNIC_MAX_VNIC_AUTO_ID - \ 64*843e1988Sjohnlev DLADM_VNIC_MIN_VNIC_AUTO_ID + 1) 65*843e1988Sjohnlev 66*843e1988Sjohnlev /* Limits on buffer size for VNIC_IOC_INFO request */ 67*843e1988Sjohnlev #define MIN_INFO_SIZE (4*1024) 68*843e1988Sjohnlev #define MAX_INFO_SIZE (128*1024) 69*843e1988Sjohnlev 70*843e1988Sjohnlev /* configuration database entry */ 71*843e1988Sjohnlev typedef struct dladm_vnic_attr_db { 72*843e1988Sjohnlev uint_t vt_vnic_id; 73*843e1988Sjohnlev char vt_dev_name[MAXNAMELEN]; 74*843e1988Sjohnlev vnic_mac_addr_type_t vt_mac_addr_type; 75*843e1988Sjohnlev uint_t vt_mac_len; 76*843e1988Sjohnlev uchar_t vt_mac_addr[MAXMACADDRLEN]; 77*843e1988Sjohnlev } dladm_vnic_attr_db_t; 78*843e1988Sjohnlev 79*843e1988Sjohnlev typedef struct dladm_vnic_up { 80*843e1988Sjohnlev uint_t vu_vnic_id; 81*843e1988Sjohnlev boolean_t vu_found; 82*843e1988Sjohnlev int vu_fd; 83*843e1988Sjohnlev } dladm_vnic_up_t; 84*843e1988Sjohnlev 85*843e1988Sjohnlev typedef struct dladm_vnic_down { 86*843e1988Sjohnlev uint32_t vd_vnic_id; 87*843e1988Sjohnlev boolean_t vd_found; 88*843e1988Sjohnlev } dladm_vnic_down_t; 89*843e1988Sjohnlev 90*843e1988Sjohnlev typedef struct dladm_vnic_modify { 91*843e1988Sjohnlev uint32_t vm_vnic_id; 92*843e1988Sjohnlev boolean_t vm_found; 93*843e1988Sjohnlev } dladm_vnic_modify_t; 94*843e1988Sjohnlev 95*843e1988Sjohnlev typedef struct dladm_vnic_modify_attr { 96*843e1988Sjohnlev vnic_mac_addr_type_t vm_mac_addr_type; 97*843e1988Sjohnlev int vm_mac_len; 98*843e1988Sjohnlev uchar_t vm_mac_addr[MAXMACADDRLEN]; 99*843e1988Sjohnlev } dladm_vnic_modify_attr_t; 100*843e1988Sjohnlev 101*843e1988Sjohnlev /* 102*843e1988Sjohnlev * Send a create command to the VNIC driver. 103*843e1988Sjohnlev */ 104*843e1988Sjohnlev static dladm_status_t 105*843e1988Sjohnlev i_dladm_vnic_create_sys(int fd, dladm_vnic_attr_db_t *attr) 106*843e1988Sjohnlev { 107*843e1988Sjohnlev int rc; 108*843e1988Sjohnlev vnic_ioc_create_t ioc; 109*843e1988Sjohnlev 110*843e1988Sjohnlev ioc.vc_vnic_id = attr->vt_vnic_id; 111*843e1988Sjohnlev bcopy(attr->vt_dev_name, ioc.vc_dev_name, MAXNAMELEN); 112*843e1988Sjohnlev ioc.vc_mac_addr_type = attr->vt_mac_addr_type; 113*843e1988Sjohnlev ioc.vc_mac_len = attr->vt_mac_len; 114*843e1988Sjohnlev bcopy(attr->vt_mac_addr, ioc.vc_mac_addr, attr->vt_mac_len); 115*843e1988Sjohnlev 116*843e1988Sjohnlev rc = i_dladm_ioctl(fd, VNIC_IOC_CREATE, &ioc, sizeof (ioc)); 117*843e1988Sjohnlev 118*843e1988Sjohnlev if (rc < 0) 119*843e1988Sjohnlev return (dladm_errno2status(errno)); 120*843e1988Sjohnlev 121*843e1988Sjohnlev return (DLADM_STATUS_OK); 122*843e1988Sjohnlev } 123*843e1988Sjohnlev 124*843e1988Sjohnlev /* 125*843e1988Sjohnlev * Invoked to bring up a VNIC. 126*843e1988Sjohnlev */ 127*843e1988Sjohnlev static dladm_status_t 128*843e1988Sjohnlev i_dladm_vnic_up(void *arg, dladm_vnic_attr_db_t *attr) 129*843e1988Sjohnlev { 130*843e1988Sjohnlev dladm_vnic_up_t *up = (dladm_vnic_up_t *)arg; 131*843e1988Sjohnlev dladm_status_t status; 132*843e1988Sjohnlev 133*843e1988Sjohnlev if (up->vu_vnic_id != 0 && up->vu_vnic_id != attr->vt_vnic_id) 134*843e1988Sjohnlev return (DLADM_STATUS_OK); 135*843e1988Sjohnlev 136*843e1988Sjohnlev up->vu_found = B_TRUE; 137*843e1988Sjohnlev 138*843e1988Sjohnlev status = i_dladm_vnic_create_sys(up->vu_fd, attr); 139*843e1988Sjohnlev if ((status != DLADM_STATUS_OK) && (up->vu_vnic_id != 0)) 140*843e1988Sjohnlev return (status); 141*843e1988Sjohnlev 142*843e1988Sjohnlev return (DLADM_STATUS_OK); 143*843e1988Sjohnlev } 144*843e1988Sjohnlev 145*843e1988Sjohnlev /* 146*843e1988Sjohnlev * Send a modify command to the VNIC driver. 147*843e1988Sjohnlev */ 148*843e1988Sjohnlev static dladm_status_t 149*843e1988Sjohnlev i_dladm_vnic_modify_sys(uint_t vnic_id, uint32_t modify_mask, 150*843e1988Sjohnlev dladm_vnic_modify_attr_t *attr) 151*843e1988Sjohnlev { 152*843e1988Sjohnlev int rc; 153*843e1988Sjohnlev int fd; 154*843e1988Sjohnlev vnic_ioc_modify_t ioc; 155*843e1988Sjohnlev 156*843e1988Sjohnlev ioc.vm_vnic_id = vnic_id; 157*843e1988Sjohnlev 158*843e1988Sjohnlev ioc.vm_modify_mask = 0; 159*843e1988Sjohnlev if (modify_mask & DLADM_VNIC_MODIFY_ADDR) 160*843e1988Sjohnlev ioc.vm_modify_mask |= VNIC_IOC_MODIFY_ADDR; 161*843e1988Sjohnlev 162*843e1988Sjohnlev ioc.vm_mac_addr_type = attr->vm_mac_addr_type; 163*843e1988Sjohnlev ioc.vm_mac_len = attr->vm_mac_len; 164*843e1988Sjohnlev bcopy(attr->vm_mac_addr, ioc.vm_mac_addr, MAXMACADDRLEN); 165*843e1988Sjohnlev 166*843e1988Sjohnlev if ((fd = open(VNIC_DEV, O_RDWR)) < 0) 167*843e1988Sjohnlev return (dladm_errno2status(errno)); 168*843e1988Sjohnlev 169*843e1988Sjohnlev rc = i_dladm_ioctl(fd, VNIC_IOC_MODIFY, &ioc, sizeof (ioc)); 170*843e1988Sjohnlev 171*843e1988Sjohnlev (void) close(fd); 172*843e1988Sjohnlev 173*843e1988Sjohnlev if (rc < 0) 174*843e1988Sjohnlev return (dladm_errno2status(errno)); 175*843e1988Sjohnlev 176*843e1988Sjohnlev return (DLADM_STATUS_OK); 177*843e1988Sjohnlev } 178*843e1988Sjohnlev 179*843e1988Sjohnlev /* 180*843e1988Sjohnlev * Walk through the vnics defined on the system and for each vnic <vnic>, 181*843e1988Sjohnlev * invoke <fn>(<arg>, <vnic>); 182*843e1988Sjohnlev */ 183*843e1988Sjohnlev dladm_status_t 184*843e1988Sjohnlev dladm_vnic_walk_sys(dladm_status_t (*fn)(void *, dladm_vnic_attr_sys_t *), 185*843e1988Sjohnlev void *arg) 186*843e1988Sjohnlev { 187*843e1988Sjohnlev vnic_ioc_info_t *ioc; 188*843e1988Sjohnlev vnic_ioc_info_vnic_t *vnic; 189*843e1988Sjohnlev dladm_vnic_attr_sys_t attr; 190*843e1988Sjohnlev int rc, i, bufsize, fd; 191*843e1988Sjohnlev char *where; 192*843e1988Sjohnlev dladm_status_t status = DLADM_STATUS_OK; 193*843e1988Sjohnlev 194*843e1988Sjohnlev if ((fd = open(VNIC_DEV, O_RDWR)) == -1) 195*843e1988Sjohnlev return (dladm_errno2status(errno)); 196*843e1988Sjohnlev 197*843e1988Sjohnlev bufsize = MIN_INFO_SIZE; 198*843e1988Sjohnlev ioc = (vnic_ioc_info_t *)calloc(1, bufsize); 199*843e1988Sjohnlev if (ioc == NULL) { 200*843e1988Sjohnlev (void) close(fd); 201*843e1988Sjohnlev return (dladm_errno2status(ENOMEM)); 202*843e1988Sjohnlev } 203*843e1988Sjohnlev 204*843e1988Sjohnlev tryagain: 205*843e1988Sjohnlev 206*843e1988Sjohnlev rc = i_dladm_ioctl(fd, VNIC_IOC_INFO, ioc, bufsize); 207*843e1988Sjohnlev 208*843e1988Sjohnlev if (rc != 0) { 209*843e1988Sjohnlev if (errno == ENOSPC) { 210*843e1988Sjohnlev bufsize *= 2; 211*843e1988Sjohnlev if (bufsize <= MAX_INFO_SIZE) { 212*843e1988Sjohnlev ioc = (vnic_ioc_info_t *)realloc(ioc, bufsize); 213*843e1988Sjohnlev if (ioc != NULL) { 214*843e1988Sjohnlev bzero(ioc, bufsize); 215*843e1988Sjohnlev goto tryagain; 216*843e1988Sjohnlev } 217*843e1988Sjohnlev } 218*843e1988Sjohnlev } 219*843e1988Sjohnlev status = dladm_errno2status(errno); 220*843e1988Sjohnlev goto bail; 221*843e1988Sjohnlev } 222*843e1988Sjohnlev 223*843e1988Sjohnlev /* 224*843e1988Sjohnlev * Go through each vnic returned by the vnic driver 225*843e1988Sjohnlev */ 226*843e1988Sjohnlev where = (char *)(ioc + 1); 227*843e1988Sjohnlev 228*843e1988Sjohnlev for (i = 0; i < ioc->vi_nvnics; i++) { 229*843e1988Sjohnlev /* LINTED E_BAD_PTR_CAST_ALIGN */ 230*843e1988Sjohnlev vnic = (vnic_ioc_info_vnic_t *)where; 231*843e1988Sjohnlev 232*843e1988Sjohnlev attr.va_vnic_id = vnic->vn_vnic_id; 233*843e1988Sjohnlev bcopy(vnic->vn_dev_name, attr.va_dev_name, 234*843e1988Sjohnlev MAXNAMELEN); 235*843e1988Sjohnlev attr.va_mac_addr_type = vnic->vn_mac_addr_type; 236*843e1988Sjohnlev bcopy(vnic->vn_mac_addr, attr.va_mac_addr, ETHERADDRL); 237*843e1988Sjohnlev attr.va_mac_len = vnic->vn_mac_len; 238*843e1988Sjohnlev where = (char *)(vnic + 1); 239*843e1988Sjohnlev 240*843e1988Sjohnlev status = fn(arg, &attr); 241*843e1988Sjohnlev if (status != DLADM_STATUS_OK) 242*843e1988Sjohnlev goto bail; 243*843e1988Sjohnlev } 244*843e1988Sjohnlev 245*843e1988Sjohnlev bail: 246*843e1988Sjohnlev free(ioc); 247*843e1988Sjohnlev (void) close(fd); 248*843e1988Sjohnlev 249*843e1988Sjohnlev return (status); 250*843e1988Sjohnlev } 251*843e1988Sjohnlev 252*843e1988Sjohnlev /* 253*843e1988Sjohnlev * Remove a VNIC from the kernel. 254*843e1988Sjohnlev */ 255*843e1988Sjohnlev static dladm_status_t 256*843e1988Sjohnlev i_dladm_vnic_delete_sys(int fd, dladm_vnic_attr_sys_t *attr) 257*843e1988Sjohnlev { 258*843e1988Sjohnlev vnic_ioc_delete_t ioc; 259*843e1988Sjohnlev int rc; 260*843e1988Sjohnlev 261*843e1988Sjohnlev ioc.vd_vnic_id = attr->va_vnic_id; 262*843e1988Sjohnlev 263*843e1988Sjohnlev rc = i_dladm_ioctl(fd, VNIC_IOC_DELETE, &ioc, sizeof (ioc)); 264*843e1988Sjohnlev 265*843e1988Sjohnlev if (rc < 0) 266*843e1988Sjohnlev return (dladm_errno2status(errno)); 267*843e1988Sjohnlev 268*843e1988Sjohnlev return (DLADM_STATUS_OK); 269*843e1988Sjohnlev } 270*843e1988Sjohnlev 271*843e1988Sjohnlev /* 272*843e1988Sjohnlev * Invoked to bring down a VNIC. 273*843e1988Sjohnlev */ 274*843e1988Sjohnlev static dladm_status_t 275*843e1988Sjohnlev i_dladm_vnic_down(void *arg, dladm_vnic_attr_sys_t *attr) 276*843e1988Sjohnlev { 277*843e1988Sjohnlev dladm_vnic_down_t *down = (dladm_vnic_down_t *)arg; 278*843e1988Sjohnlev int fd; 279*843e1988Sjohnlev dladm_status_t status; 280*843e1988Sjohnlev 281*843e1988Sjohnlev if (down->vd_vnic_id != 0 && down->vd_vnic_id != attr->va_vnic_id) 282*843e1988Sjohnlev return (DLADM_STATUS_OK); 283*843e1988Sjohnlev 284*843e1988Sjohnlev down->vd_found = B_TRUE; 285*843e1988Sjohnlev 286*843e1988Sjohnlev if ((fd = open(VNIC_DEV, O_RDWR)) < 0) 287*843e1988Sjohnlev return (dladm_errno2status(errno)); 288*843e1988Sjohnlev 289*843e1988Sjohnlev status = i_dladm_vnic_delete_sys(fd, attr); 290*843e1988Sjohnlev if ((status != DLADM_STATUS_OK) && (down->vd_vnic_id != 0)) { 291*843e1988Sjohnlev (void) close(fd); 292*843e1988Sjohnlev return (status); 293*843e1988Sjohnlev } 294*843e1988Sjohnlev 295*843e1988Sjohnlev (void) close(fd); 296*843e1988Sjohnlev return (DLADM_STATUS_OK); 297*843e1988Sjohnlev } 298*843e1988Sjohnlev 299*843e1988Sjohnlev /* 300*843e1988Sjohnlev * Convert between MAC address types and their string representations. 301*843e1988Sjohnlev */ 302*843e1988Sjohnlev 303*843e1988Sjohnlev typedef struct dladm_vnic_addr_type_s { 304*843e1988Sjohnlev char *va_str; 305*843e1988Sjohnlev vnic_mac_addr_type_t va_type; 306*843e1988Sjohnlev } dladm_vnic_addr_type_t; 307*843e1988Sjohnlev 308*843e1988Sjohnlev static dladm_vnic_addr_type_t addr_types[] = { 309*843e1988Sjohnlev {"fixed", VNIC_MAC_ADDR_TYPE_FIXED}, 310*843e1988Sjohnlev }; 311*843e1988Sjohnlev 312*843e1988Sjohnlev #define NADDR_TYPES (sizeof (addr_types) / sizeof (dladm_vnic_addr_type_t)) 313*843e1988Sjohnlev 314*843e1988Sjohnlev /* returns B_TRUE if a matching type was found, B_FALSE otherwise */ 315*843e1988Sjohnlev boolean_t 316*843e1988Sjohnlev dladm_vnic_mac_addr_str_to_type(const char *str, vnic_mac_addr_type_t *val) 317*843e1988Sjohnlev { 318*843e1988Sjohnlev int i; 319*843e1988Sjohnlev dladm_vnic_addr_type_t *type; 320*843e1988Sjohnlev 321*843e1988Sjohnlev for (i = 0; i < NADDR_TYPES; i++) { 322*843e1988Sjohnlev type = &addr_types[i]; 323*843e1988Sjohnlev if (strncmp(str, type->va_str, strlen(type->va_str)) == 0) { 324*843e1988Sjohnlev *val = type->va_type; 325*843e1988Sjohnlev return (B_TRUE); 326*843e1988Sjohnlev } 327*843e1988Sjohnlev } 328*843e1988Sjohnlev 329*843e1988Sjohnlev return (B_FALSE); 330*843e1988Sjohnlev } 331*843e1988Sjohnlev 332*843e1988Sjohnlev /* 333*843e1988Sjohnlev * Select a VNIC id automatically. 334*843e1988Sjohnlev */ 335*843e1988Sjohnlev 336*843e1988Sjohnlev typedef struct dladm_vnic_auto_state_s { 337*843e1988Sjohnlev uint_t as_nslots; 338*843e1988Sjohnlev uint_t *as_slots; 339*843e1988Sjohnlev } dladm_vnic_auto_state_t; 340*843e1988Sjohnlev 341*843e1988Sjohnlev static dladm_status_t 342*843e1988Sjohnlev i_dladm_vnic_create_auto_walker(void *arg, dladm_vnic_attr_sys_t *attr) 343*843e1988Sjohnlev { 344*843e1988Sjohnlev dladm_vnic_auto_state_t *state = arg; 345*843e1988Sjohnlev 346*843e1988Sjohnlev if (attr->va_vnic_id < DLADM_VNIC_MIN_VNIC_AUTO_ID || 347*843e1988Sjohnlev attr->va_vnic_id > DLADM_VNIC_MAX_VNIC_AUTO_ID) 348*843e1988Sjohnlev return (DLADM_STATUS_OK); 349*843e1988Sjohnlev 350*843e1988Sjohnlev state->as_slots[state->as_nslots++] = attr->va_vnic_id; 351*843e1988Sjohnlev 352*843e1988Sjohnlev return (DLADM_STATUS_OK); 353*843e1988Sjohnlev } 354*843e1988Sjohnlev 355*843e1988Sjohnlev static int 356*843e1988Sjohnlev i_dladm_vnic_compare(const void *p1, const void *p2) 357*843e1988Sjohnlev { 358*843e1988Sjohnlev uint_t i = *((uint_t *)p1); 359*843e1988Sjohnlev uint_t j = *((uint_t *)p2); 360*843e1988Sjohnlev 361*843e1988Sjohnlev if (i > j) 362*843e1988Sjohnlev return (1); 363*843e1988Sjohnlev if (i < j) 364*843e1988Sjohnlev return (-1); 365*843e1988Sjohnlev return (0); 366*843e1988Sjohnlev } 367*843e1988Sjohnlev 368*843e1988Sjohnlev /*ARGSUSED*/ 369*843e1988Sjohnlev static dladm_status_t 370*843e1988Sjohnlev i_dladm_vnic_get_auto_id(dladm_vnic_attr_db_t *attr, uint32_t *vnic_id_out) 371*843e1988Sjohnlev { 372*843e1988Sjohnlev dladm_vnic_auto_state_t state; 373*843e1988Sjohnlev uint_t vnic_ids[DLADM_VNIC_NUM_VNIC_AUTO_ID]; 374*843e1988Sjohnlev int i; 375*843e1988Sjohnlev uint_t last_id, vnic_id; 376*843e1988Sjohnlev dladm_status_t status; 377*843e1988Sjohnlev 378*843e1988Sjohnlev /* 379*843e1988Sjohnlev * Build a sorted array containing the existing VNIC ids in the range 380*843e1988Sjohnlev * allocated for automatic allocation. 381*843e1988Sjohnlev */ 382*843e1988Sjohnlev state.as_nslots = 0; 383*843e1988Sjohnlev state.as_slots = vnic_ids; 384*843e1988Sjohnlev 385*843e1988Sjohnlev status = dladm_vnic_walk_sys(i_dladm_vnic_create_auto_walker, &state); 386*843e1988Sjohnlev if (status != DLADM_STATUS_OK) 387*843e1988Sjohnlev return (status); 388*843e1988Sjohnlev 389*843e1988Sjohnlev qsort(vnic_ids, state.as_nslots, sizeof (uint_t), 390*843e1988Sjohnlev i_dladm_vnic_compare); 391*843e1988Sjohnlev 392*843e1988Sjohnlev /* 393*843e1988Sjohnlev * Find a gap in the sequence of existing VNIC ids. 394*843e1988Sjohnlev */ 395*843e1988Sjohnlev last_id = DLADM_VNIC_MIN_VNIC_AUTO_ID - 1; 396*843e1988Sjohnlev vnic_id = 0; 397*843e1988Sjohnlev for (i = 0; i < state.as_nslots; i++) { 398*843e1988Sjohnlev if (vnic_ids[i] > (last_id + 1)) { 399*843e1988Sjohnlev vnic_id = last_id + 1; 400*843e1988Sjohnlev break; 401*843e1988Sjohnlev } 402*843e1988Sjohnlev last_id = vnic_ids[i]; 403*843e1988Sjohnlev } 404*843e1988Sjohnlev 405*843e1988Sjohnlev if (vnic_id == 0) { 406*843e1988Sjohnlev /* 407*843e1988Sjohnlev * Did not find a gap between existing entries, see if we 408*843e1988Sjohnlev * can add one. 409*843e1988Sjohnlev */ 410*843e1988Sjohnlev if (last_id + 1 > DLADM_VNIC_MAX_VNIC_AUTO_ID) 411*843e1988Sjohnlev return (DLADM_STATUS_AUTOIDNOAVAILABLEID); 412*843e1988Sjohnlev 413*843e1988Sjohnlev /* still have room for one more VNIC */ 414*843e1988Sjohnlev vnic_id = last_id + 1; 415*843e1988Sjohnlev } 416*843e1988Sjohnlev 417*843e1988Sjohnlev *vnic_id_out = vnic_id; 418*843e1988Sjohnlev 419*843e1988Sjohnlev return (DLADM_STATUS_OK); 420*843e1988Sjohnlev } 421*843e1988Sjohnlev 422*843e1988Sjohnlev /* 423*843e1988Sjohnlev * Create a new VNIC. Update the configuration file and bring it up. 424*843e1988Sjohnlev */ 425*843e1988Sjohnlev dladm_status_t 426*843e1988Sjohnlev dladm_vnic_create(uint_t vnic_id, char *dev_name, 427*843e1988Sjohnlev vnic_mac_addr_type_t mac_addr_type, uchar_t *mac_addr, int mac_len, 428*843e1988Sjohnlev uint_t *vnic_id_out, uint32_t flags) 429*843e1988Sjohnlev { 430*843e1988Sjohnlev dladm_vnic_attr_db_t attr; 431*843e1988Sjohnlev int i; 432*843e1988Sjohnlev boolean_t tempop = ((flags & DLADM_VNIC_OPT_TEMP) != 0); 433*843e1988Sjohnlev boolean_t autoid = ((flags & DLADM_VNIC_OPT_AUTOID) != 0); 434*843e1988Sjohnlev dladm_vnic_up_t up; 435*843e1988Sjohnlev dladm_status_t status; 436*843e1988Sjohnlev 437*843e1988Sjohnlev /* 438*843e1988Sjohnlev * Sanity test arguments. 439*843e1988Sjohnlev */ 440*843e1988Sjohnlev if (autoid && !tempop) 441*843e1988Sjohnlev return (DLADM_STATUS_AUTOIDNOTEMP); 442*843e1988Sjohnlev 443*843e1988Sjohnlev if (!autoid && ((vnic_id < DLADM_VNIC_MIN_VNIC_SPEC_ID) || 444*843e1988Sjohnlev (vnic_id > DLADM_VNIC_MAX_VNIC_SPEC_ID))) 445*843e1988Sjohnlev return (DLADM_STATUS_INVALIDID); 446*843e1988Sjohnlev 447*843e1988Sjohnlev if (mac_len > MAXMACADDRLEN) 448*843e1988Sjohnlev return (DLADM_STATUS_INVALIDMACADDRLEN); 449*843e1988Sjohnlev 450*843e1988Sjohnlev for (i = 0; i < NADDR_TYPES; i++) { 451*843e1988Sjohnlev if (mac_addr_type == addr_types[i].va_type) 452*843e1988Sjohnlev break; 453*843e1988Sjohnlev } 454*843e1988Sjohnlev if (i == NADDR_TYPES) 455*843e1988Sjohnlev return (DLADM_STATUS_INVALIDMACADDRTYPE); 456*843e1988Sjohnlev 457*843e1988Sjohnlev /* for now, only temporary creations are supported */ 458*843e1988Sjohnlev if (!tempop) 459*843e1988Sjohnlev return (dladm_errno2status(ENOTSUP)); 460*843e1988Sjohnlev 461*843e1988Sjohnlev auto_again: 462*843e1988Sjohnlev if (autoid) { 463*843e1988Sjohnlev /* 464*843e1988Sjohnlev * Find an unused VNIC id. 465*843e1988Sjohnlev */ 466*843e1988Sjohnlev status = i_dladm_vnic_get_auto_id(&attr, vnic_id_out); 467*843e1988Sjohnlev if (status != DLADM_STATUS_OK) 468*843e1988Sjohnlev return (status); 469*843e1988Sjohnlev vnic_id = *vnic_id_out; 470*843e1988Sjohnlev } 471*843e1988Sjohnlev 472*843e1988Sjohnlev bzero(&attr, sizeof (attr)); 473*843e1988Sjohnlev attr.vt_vnic_id = vnic_id; 474*843e1988Sjohnlev (void) strncpy(attr.vt_dev_name, dev_name, 475*843e1988Sjohnlev sizeof (attr.vt_dev_name) - 1); 476*843e1988Sjohnlev attr.vt_mac_addr_type = mac_addr_type; 477*843e1988Sjohnlev attr.vt_mac_len = mac_len; 478*843e1988Sjohnlev bcopy(mac_addr, attr.vt_mac_addr, mac_len); 479*843e1988Sjohnlev 480*843e1988Sjohnlev up.vu_vnic_id = vnic_id; 481*843e1988Sjohnlev up.vu_found = B_FALSE; 482*843e1988Sjohnlev up.vu_fd = open(VNIC_DEV, O_RDWR); 483*843e1988Sjohnlev if (up.vu_fd < 0) 484*843e1988Sjohnlev return (dladm_errno2status(errno)); 485*843e1988Sjohnlev 486*843e1988Sjohnlev status = i_dladm_vnic_up((void *)&up, &attr); 487*843e1988Sjohnlev (void) close(up.vu_fd); 488*843e1988Sjohnlev 489*843e1988Sjohnlev if ((status == DLADM_STATUS_EXIST) && autoid) 490*843e1988Sjohnlev goto auto_again; 491*843e1988Sjohnlev 492*843e1988Sjohnlev return (status); 493*843e1988Sjohnlev } 494*843e1988Sjohnlev 495*843e1988Sjohnlev /* 496*843e1988Sjohnlev * Modify the properties of a VNIC. 497*843e1988Sjohnlev */ 498*843e1988Sjohnlev dladm_status_t 499*843e1988Sjohnlev dladm_vnic_modify(uint_t vnic_id, uint32_t modify_mask, 500*843e1988Sjohnlev vnic_mac_addr_type_t mac_addr_type, uint_t mac_len, uchar_t *mac_addr, 501*843e1988Sjohnlev uint32_t flags) 502*843e1988Sjohnlev { 503*843e1988Sjohnlev dladm_vnic_modify_attr_t new_attr; 504*843e1988Sjohnlev boolean_t tempop = ((flags & DLADM_VNIC_OPT_TEMP) != 0); 505*843e1988Sjohnlev 506*843e1988Sjohnlev if ((vnic_id < DLADM_VNIC_MIN_VNIC_ID) || 507*843e1988Sjohnlev (vnic_id > DLADM_VNIC_MAX_VNIC_ID)) 508*843e1988Sjohnlev return (DLADM_STATUS_INVALIDID); 509*843e1988Sjohnlev 510*843e1988Sjohnlev /* for now, only temporary creations are supported */ 511*843e1988Sjohnlev if (!tempop) 512*843e1988Sjohnlev return (dladm_errno2status(ENOTSUP)); 513*843e1988Sjohnlev 514*843e1988Sjohnlev bzero(&new_attr, sizeof (new_attr)); 515*843e1988Sjohnlev 516*843e1988Sjohnlev if (modify_mask & DLADM_VNIC_MODIFY_ADDR) { 517*843e1988Sjohnlev new_attr.vm_mac_addr_type = mac_addr_type; 518*843e1988Sjohnlev new_attr.vm_mac_len = mac_len; 519*843e1988Sjohnlev bcopy(mac_addr, new_attr.vm_mac_addr, MAXMACADDRLEN); 520*843e1988Sjohnlev } 521*843e1988Sjohnlev 522*843e1988Sjohnlev /* update the properties of the existing VNIC */ 523*843e1988Sjohnlev return (i_dladm_vnic_modify_sys(vnic_id, modify_mask, &new_attr)); 524*843e1988Sjohnlev } 525*843e1988Sjohnlev 526*843e1988Sjohnlev 527*843e1988Sjohnlev /* 528*843e1988Sjohnlev * Delete a VNIC. 529*843e1988Sjohnlev */ 530*843e1988Sjohnlev dladm_status_t 531*843e1988Sjohnlev dladm_vnic_delete(uint_t vnic_id, uint32_t flags) 532*843e1988Sjohnlev { 533*843e1988Sjohnlev boolean_t tempop = ((flags & DLADM_VNIC_OPT_TEMP) != 0); 534*843e1988Sjohnlev dladm_vnic_down_t down; 535*843e1988Sjohnlev dladm_vnic_attr_sys_t sys_attr; 536*843e1988Sjohnlev 537*843e1988Sjohnlev if ((vnic_id < DLADM_VNIC_MIN_VNIC_ID) || 538*843e1988Sjohnlev (vnic_id > DLADM_VNIC_MAX_VNIC_ID)) 539*843e1988Sjohnlev return (DLADM_STATUS_INVALIDID); 540*843e1988Sjohnlev 541*843e1988Sjohnlev /* for now, only temporary deletes are supported */ 542*843e1988Sjohnlev if (!tempop) 543*843e1988Sjohnlev return (dladm_errno2status(ENOTSUP)); 544*843e1988Sjohnlev 545*843e1988Sjohnlev down.vd_vnic_id = vnic_id; 546*843e1988Sjohnlev down.vd_found = B_FALSE; 547*843e1988Sjohnlev sys_attr.va_vnic_id = vnic_id; 548*843e1988Sjohnlev return (i_dladm_vnic_down((void *)&down, &sys_attr)); 549*843e1988Sjohnlev } 550