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