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> 39*da14cebeSEric Cheng #include <sys/dld.h> 40843e1988Sjohnlev #include <libdladm_impl.h> 41d62bc4baSyz147064 #include <libdllink.h> 42843e1988Sjohnlev #include <libdlvnic.h> 43843e1988Sjohnlev 44843e1988Sjohnlev /* 45843e1988Sjohnlev * VNIC administration library. 46843e1988Sjohnlev */ 47843e1988Sjohnlev 48*da14cebeSEric Cheng /* 49*da14cebeSEric Cheng * Default random MAC address prefix (locally administered). 50*da14cebeSEric Cheng */ 51*da14cebeSEric Cheng static char dladm_vnic_def_prefix[] = {0x02, 0x08, 0x20}; 52843e1988Sjohnlev 53*da14cebeSEric Cheng static dladm_status_t dladm_vnic_persist_conf(const char *name, 54*da14cebeSEric Cheng dladm_vnic_attr_t *, datalink_class_t); 55*da14cebeSEric Cheng static const char *dladm_vnic_macaddr2str(const uchar_t *, char *); 56*da14cebeSEric Cheng static dladm_status_t dladm_vnic_str2macaddr(const char *, uchar_t *); 57843e1988Sjohnlev 58843e1988Sjohnlev /* 59*da14cebeSEric Cheng * Convert a diagnostic returned by the kernel into a dladm_status_t. 60843e1988Sjohnlev */ 61843e1988Sjohnlev static dladm_status_t 62*da14cebeSEric Cheng dladm_vnic_diag2status(vnic_ioc_diag_t ioc_diag) 63843e1988Sjohnlev { 64*da14cebeSEric Cheng switch (ioc_diag) { 65*da14cebeSEric Cheng case VNIC_IOC_DIAG_MACADDR_INVALID: 66*da14cebeSEric Cheng return (DLADM_STATUS_INVALIDMACADDR); 67*da14cebeSEric Cheng case VNIC_IOC_DIAG_MACADDRLEN_INVALID: 68*da14cebeSEric Cheng return (DLADM_STATUS_INVALIDMACADDRLEN); 69*da14cebeSEric Cheng case VNIC_IOC_DIAG_MACADDR_NIC: 70*da14cebeSEric Cheng return (DLADM_STATUS_INVALIDMACADDRNIC); 71*da14cebeSEric Cheng case VNIC_IOC_DIAG_MACADDR_INUSE: 72*da14cebeSEric Cheng return (DLADM_STATUS_INVALIDMACADDRINUSE); 73*da14cebeSEric Cheng case VNIC_IOC_DIAG_MACFACTORYSLOTINVALID: 74*da14cebeSEric Cheng return (DLADM_STATUS_MACFACTORYSLOTINVALID); 75*da14cebeSEric Cheng case VNIC_IOC_DIAG_MACFACTORYSLOTUSED: 76*da14cebeSEric Cheng return (DLADM_STATUS_MACFACTORYSLOTUSED); 77*da14cebeSEric Cheng case VNIC_IOC_DIAG_MACFACTORYSLOTALLUSED: 78*da14cebeSEric Cheng return (DLADM_STATUS_MACFACTORYSLOTALLUSED); 79*da14cebeSEric Cheng case VNIC_IOC_DIAG_MACFACTORYNOTSUP: 80*da14cebeSEric Cheng return (DLADM_STATUS_MACFACTORYNOTSUP); 81*da14cebeSEric Cheng case VNIC_IOC_DIAG_MACPREFIX_INVALID: 82*da14cebeSEric Cheng return (DLADM_STATUS_INVALIDMACPREFIX); 83*da14cebeSEric Cheng case VNIC_IOC_DIAG_MACPREFIXLEN_INVALID: 84*da14cebeSEric Cheng return (DLADM_STATUS_INVALIDMACPREFIXLEN); 85*da14cebeSEric Cheng case VNIC_IOC_DIAG_MACMARGIN_INVALID: 86*da14cebeSEric Cheng return (DLADM_STATUS_INVALID_MACMARGIN); 87*da14cebeSEric Cheng case VNIC_IOC_DIAG_NO_HWRINGS: 88*da14cebeSEric Cheng return (DLADM_STATUS_NO_HWRINGS); 89*da14cebeSEric Cheng } 90843e1988Sjohnlev return (DLADM_STATUS_OK); 91843e1988Sjohnlev } 92843e1988Sjohnlev 93843e1988Sjohnlev /* 94*da14cebeSEric Cheng * Send a create command to the VNIC driver. 95843e1988Sjohnlev */ 96*da14cebeSEric Cheng dladm_status_t 97*da14cebeSEric Cheng i_dladm_vnic_create_sys(dladm_vnic_attr_t *attr) 98843e1988Sjohnlev { 99*da14cebeSEric Cheng int rc, fd; 100*da14cebeSEric Cheng vnic_ioc_create_t ioc; 101eae72b5bSSebastien Roy dladm_status_t status = DLADM_STATUS_OK; 102843e1988Sjohnlev 103*da14cebeSEric Cheng bzero(&ioc, sizeof (ioc)); 104*da14cebeSEric Cheng ioc.vc_vnic_id = attr->va_vnic_id; 105*da14cebeSEric Cheng ioc.vc_link_id = attr->va_link_id; 106*da14cebeSEric Cheng ioc.vc_mac_addr_type = attr->va_mac_addr_type; 107*da14cebeSEric Cheng ioc.vc_mac_len = attr->va_mac_len; 108*da14cebeSEric Cheng ioc.vc_mac_slot = attr->va_mac_slot; 109*da14cebeSEric Cheng ioc.vc_mac_prefix_len = attr->va_mac_prefix_len; 110*da14cebeSEric Cheng ioc.vc_vid = attr->va_vid; 111*da14cebeSEric Cheng ioc.vc_flags = attr->va_force ? VNIC_IOC_CREATE_FORCE : 0; 112*da14cebeSEric Cheng ioc.vc_flags |= attr->va_hwrings ? VNIC_IOC_CREATE_REQ_HWRINGS : 0; 113843e1988Sjohnlev 114*da14cebeSEric Cheng if (attr->va_mac_len > 0 || ioc.vc_mac_prefix_len > 0) 115*da14cebeSEric Cheng bcopy(attr->va_mac_addr, ioc.vc_mac_addr, MAXMACADDRLEN); 116*da14cebeSEric Cheng bcopy(&attr->va_resource_props, &ioc.vc_resource_props, 117*da14cebeSEric Cheng sizeof (mac_resource_props_t)); 118*da14cebeSEric Cheng if (attr->va_link_id == DATALINK_INVALID_LINKID) 119*da14cebeSEric Cheng ioc.vc_flags |= VNIC_IOC_CREATE_ANCHOR; 120843e1988Sjohnlev 121eae72b5bSSebastien Roy if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0) 122843e1988Sjohnlev return (dladm_errno2status(errno)); 123843e1988Sjohnlev 124*da14cebeSEric Cheng rc = ioctl(fd, VNIC_IOC_CREATE, &ioc); 125*da14cebeSEric Cheng if (rc < 0) 126eae72b5bSSebastien Roy status = dladm_errno2status(errno); 127843e1988Sjohnlev 128843e1988Sjohnlev (void) close(fd); 129*da14cebeSEric Cheng if (status != DLADM_STATUS_OK) { 130*da14cebeSEric Cheng if (ioc.vc_diag != VNIC_IOC_DIAG_NONE) 131*da14cebeSEric Cheng status = dladm_vnic_diag2status(ioc.vc_diag); 132*da14cebeSEric Cheng } 133*da14cebeSEric Cheng if (status != DLADM_STATUS_OK) 134*da14cebeSEric Cheng return (status); 135*da14cebeSEric Cheng 136*da14cebeSEric Cheng attr->va_mac_addr_type = ioc.vc_mac_addr_type; 137*da14cebeSEric Cheng switch (ioc.vc_mac_addr_type) { 138*da14cebeSEric Cheng case VNIC_MAC_ADDR_TYPE_FACTORY: 139*da14cebeSEric Cheng attr->va_mac_slot = ioc.vc_mac_slot; 140*da14cebeSEric Cheng break; 141*da14cebeSEric Cheng case VNIC_MAC_ADDR_TYPE_RANDOM: 142*da14cebeSEric Cheng bcopy(ioc.vc_mac_addr, attr->va_mac_addr, MAXMACADDRLEN); 143*da14cebeSEric Cheng attr->va_mac_len = ioc.vc_mac_len; 144*da14cebeSEric Cheng break; 145*da14cebeSEric Cheng } 146eae72b5bSSebastien Roy return (status); 147843e1988Sjohnlev } 148843e1988Sjohnlev 149843e1988Sjohnlev /* 150d62bc4baSyz147064 * Get the configuration information of the given VNIC. 151843e1988Sjohnlev */ 152*da14cebeSEric Cheng static dladm_status_t 153*da14cebeSEric Cheng i_dladm_vnic_info_active(datalink_id_t linkid, dladm_vnic_attr_t *attrp) 154843e1988Sjohnlev { 155*da14cebeSEric Cheng vnic_ioc_info_t ioc; 156*da14cebeSEric Cheng vnic_info_t *vnic; 157*da14cebeSEric Cheng int rc, fd; 158843e1988Sjohnlev dladm_status_t status = DLADM_STATUS_OK; 159843e1988Sjohnlev 160eae72b5bSSebastien Roy if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) == -1) 161843e1988Sjohnlev return (dladm_errno2status(errno)); 162843e1988Sjohnlev 163*da14cebeSEric Cheng bzero(&ioc, sizeof (ioc)); 164*da14cebeSEric Cheng vnic = &ioc.vi_info; 165*da14cebeSEric Cheng vnic->vn_vnic_id = linkid; 166843e1988Sjohnlev 167*da14cebeSEric Cheng rc = ioctl(fd, VNIC_IOC_INFO, &ioc); 168*da14cebeSEric Cheng if (rc != 0) { 169843e1988Sjohnlev status = dladm_errno2status(errno); 170843e1988Sjohnlev goto bail; 171843e1988Sjohnlev } 172843e1988Sjohnlev 173d62bc4baSyz147064 attrp->va_vnic_id = vnic->vn_vnic_id; 174d62bc4baSyz147064 attrp->va_link_id = vnic->vn_link_id; 175d62bc4baSyz147064 attrp->va_mac_addr_type = vnic->vn_mac_addr_type; 176*da14cebeSEric Cheng bcopy(vnic->vn_mac_addr, attrp->va_mac_addr, MAXMACADDRLEN); 177d62bc4baSyz147064 attrp->va_mac_len = vnic->vn_mac_len; 178*da14cebeSEric Cheng attrp->va_mac_slot = vnic->vn_mac_slot; 179*da14cebeSEric Cheng attrp->va_mac_prefix_len = vnic->vn_mac_prefix_len; 180*da14cebeSEric Cheng attrp->va_vid = vnic->vn_vid; 181*da14cebeSEric Cheng attrp->va_force = vnic->vn_force; 182843e1988Sjohnlev 183843e1988Sjohnlev bail: 184843e1988Sjohnlev (void) close(fd); 185843e1988Sjohnlev return (status); 186843e1988Sjohnlev } 187843e1988Sjohnlev 188*da14cebeSEric Cheng static dladm_status_t 189*da14cebeSEric Cheng i_dladm_vnic_info_persist(datalink_id_t linkid, dladm_vnic_attr_t *attrp) 190*da14cebeSEric Cheng { 191*da14cebeSEric Cheng dladm_conf_t conf; 192*da14cebeSEric Cheng dladm_status_t status; 193*da14cebeSEric Cheng char macstr[ETHERADDRL * 3]; 194*da14cebeSEric Cheng uint64_t u64; 195*da14cebeSEric Cheng datalink_class_t class; 196*da14cebeSEric Cheng 197*da14cebeSEric Cheng attrp->va_vnic_id = linkid; 198*da14cebeSEric Cheng if ((status = dladm_read_conf(linkid, &conf)) != DLADM_STATUS_OK) 199*da14cebeSEric Cheng return (status); 200*da14cebeSEric Cheng 201*da14cebeSEric Cheng status = dladm_get_conf_field(conf, FLINKOVER, &u64, sizeof (u64)); 202*da14cebeSEric Cheng attrp->va_link_id = ((status == DLADM_STATUS_OK) ? 203*da14cebeSEric Cheng (datalink_id_t)u64 : DATALINK_INVALID_LINKID); 204*da14cebeSEric Cheng 205*da14cebeSEric Cheng status = dladm_get_conf_field(conf, FHWRINGS, &attrp->va_hwrings, 206*da14cebeSEric Cheng sizeof (boolean_t)); 207*da14cebeSEric Cheng 208*da14cebeSEric Cheng if (status != DLADM_STATUS_OK && status != DLADM_STATUS_NOTFOUND) 209*da14cebeSEric Cheng goto done; 210*da14cebeSEric Cheng if (status == DLADM_STATUS_NOTFOUND) 211*da14cebeSEric Cheng attrp->va_hwrings = B_FALSE; 212*da14cebeSEric Cheng 213*da14cebeSEric Cheng if ((status = dladm_datalink_id2info(linkid, NULL, &class, 214*da14cebeSEric Cheng NULL, NULL, 0)) != DLADM_STATUS_OK) 215*da14cebeSEric Cheng goto done; 216*da14cebeSEric Cheng 217*da14cebeSEric Cheng if (class == DATALINK_CLASS_VLAN) { 218*da14cebeSEric Cheng if (attrp->va_link_id == DATALINK_INVALID_LINKID) { 219*da14cebeSEric Cheng status = DLADM_STATUS_BADARG; 220*da14cebeSEric Cheng goto done; 221*da14cebeSEric Cheng } 222*da14cebeSEric Cheng attrp->va_mac_addr_type = VNIC_MAC_ADDR_TYPE_PRIMARY; 223*da14cebeSEric Cheng attrp->va_mac_len = 0; 224*da14cebeSEric Cheng } else { 225*da14cebeSEric Cheng status = dladm_get_conf_field(conf, FMADDRTYPE, &u64, 226*da14cebeSEric Cheng sizeof (u64)); 227*da14cebeSEric Cheng if (status != DLADM_STATUS_OK) 228*da14cebeSEric Cheng goto done; 229*da14cebeSEric Cheng 230*da14cebeSEric Cheng attrp->va_mac_addr_type = (vnic_mac_addr_type_t)u64; 231*da14cebeSEric Cheng 232*da14cebeSEric Cheng status = dladm_get_conf_field(conf, FMADDRLEN, &u64, 233*da14cebeSEric Cheng sizeof (u64)); 234*da14cebeSEric Cheng attrp->va_mac_len = ((status == DLADM_STATUS_OK) ? 235*da14cebeSEric Cheng (uint_t)u64 : ETHERADDRL); 236*da14cebeSEric Cheng 237*da14cebeSEric Cheng status = dladm_get_conf_field(conf, FMADDRSLOT, &u64, 238*da14cebeSEric Cheng sizeof (u64)); 239*da14cebeSEric Cheng attrp->va_mac_slot = ((status == DLADM_STATUS_OK) ? 240*da14cebeSEric Cheng (int)u64 : -1); 241*da14cebeSEric Cheng 242*da14cebeSEric Cheng status = dladm_get_conf_field(conf, FMADDRPREFIXLEN, &u64, 243*da14cebeSEric Cheng sizeof (u64)); 244*da14cebeSEric Cheng attrp->va_mac_prefix_len = ((status == DLADM_STATUS_OK) ? 245*da14cebeSEric Cheng (uint_t)u64 : sizeof (dladm_vnic_def_prefix)); 246*da14cebeSEric Cheng 247*da14cebeSEric Cheng status = dladm_get_conf_field(conf, FMACADDR, macstr, 248*da14cebeSEric Cheng sizeof (macstr)); 249*da14cebeSEric Cheng if (status != DLADM_STATUS_OK) 250*da14cebeSEric Cheng goto done; 251*da14cebeSEric Cheng 252*da14cebeSEric Cheng status = dladm_vnic_str2macaddr(macstr, attrp->va_mac_addr); 253*da14cebeSEric Cheng if (status != DLADM_STATUS_OK) 254*da14cebeSEric Cheng goto done; 255*da14cebeSEric Cheng } 256*da14cebeSEric Cheng 257*da14cebeSEric Cheng status = dladm_get_conf_field(conf, FVLANID, &u64, sizeof (u64)); 258*da14cebeSEric Cheng attrp->va_vid = ((status == DLADM_STATUS_OK) ? (uint16_t)u64 : 0); 259*da14cebeSEric Cheng 260*da14cebeSEric Cheng 261*da14cebeSEric Cheng status = DLADM_STATUS_OK; 262*da14cebeSEric Cheng done: 263*da14cebeSEric Cheng dladm_destroy_conf(conf); 264*da14cebeSEric Cheng return (status); 265*da14cebeSEric Cheng } 266*da14cebeSEric Cheng 267*da14cebeSEric Cheng dladm_status_t 268*da14cebeSEric Cheng dladm_vnic_info(datalink_id_t linkid, dladm_vnic_attr_t *attrp, 269*da14cebeSEric Cheng uint32_t flags) 270*da14cebeSEric Cheng { 271*da14cebeSEric Cheng if (flags == DLADM_OPT_ACTIVE) 272*da14cebeSEric Cheng return (i_dladm_vnic_info_active(linkid, attrp)); 273*da14cebeSEric Cheng else if (flags == DLADM_OPT_PERSIST) 274*da14cebeSEric Cheng return (i_dladm_vnic_info_persist(linkid, attrp)); 275*da14cebeSEric Cheng else 276*da14cebeSEric Cheng return (DLADM_STATUS_BADARG); 277*da14cebeSEric Cheng } 278*da14cebeSEric Cheng 279843e1988Sjohnlev /* 280843e1988Sjohnlev * Remove a VNIC from the kernel. 281843e1988Sjohnlev */ 282*da14cebeSEric Cheng dladm_status_t 283*da14cebeSEric Cheng i_dladm_vnic_delete_sys(datalink_id_t linkid) 284843e1988Sjohnlev { 285843e1988Sjohnlev vnic_ioc_delete_t ioc; 286*da14cebeSEric Cheng dladm_status_t status = DLADM_STATUS_OK; 287*da14cebeSEric Cheng int rc, fd; 288843e1988Sjohnlev 289*da14cebeSEric Cheng if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0) 290843e1988Sjohnlev return (dladm_errno2status(errno)); 291843e1988Sjohnlev 292*da14cebeSEric Cheng ioc.vd_vnic_id = linkid; 293*da14cebeSEric Cheng 294*da14cebeSEric Cheng rc = ioctl(fd, VNIC_IOC_DELETE, &ioc); 295*da14cebeSEric Cheng if (rc < 0) 296*da14cebeSEric Cheng status = dladm_errno2status(errno); 297*da14cebeSEric Cheng 298*da14cebeSEric Cheng (void) close(fd); 299*da14cebeSEric Cheng return (status); 300843e1988Sjohnlev } 301843e1988Sjohnlev 302843e1988Sjohnlev /* 303843e1988Sjohnlev * Convert between MAC address types and their string representations. 304843e1988Sjohnlev */ 305843e1988Sjohnlev 306843e1988Sjohnlev typedef struct dladm_vnic_addr_type_s { 307*da14cebeSEric Cheng const char *va_str; 308843e1988Sjohnlev vnic_mac_addr_type_t va_type; 309843e1988Sjohnlev } dladm_vnic_addr_type_t; 310843e1988Sjohnlev 311843e1988Sjohnlev static dladm_vnic_addr_type_t addr_types[] = { 312843e1988Sjohnlev {"fixed", VNIC_MAC_ADDR_TYPE_FIXED}, 313*da14cebeSEric Cheng {"random", VNIC_MAC_ADDR_TYPE_RANDOM}, 314*da14cebeSEric Cheng {"factory", VNIC_MAC_ADDR_TYPE_FACTORY}, 315*da14cebeSEric Cheng {"auto", VNIC_MAC_ADDR_TYPE_AUTO}, 316*da14cebeSEric Cheng {"fixed", VNIC_MAC_ADDR_TYPE_PRIMARY} 317843e1988Sjohnlev }; 318843e1988Sjohnlev 319843e1988Sjohnlev #define NADDR_TYPES (sizeof (addr_types) / sizeof (dladm_vnic_addr_type_t)) 320843e1988Sjohnlev 321*da14cebeSEric Cheng static const char * 322*da14cebeSEric Cheng dladm_vnic_macaddrtype2str(vnic_mac_addr_type_t type) 323*da14cebeSEric Cheng { 324*da14cebeSEric Cheng int i; 325*da14cebeSEric Cheng 326*da14cebeSEric Cheng for (i = 0; i < NADDR_TYPES; i++) { 327*da14cebeSEric Cheng if (type == addr_types[i].va_type) 328*da14cebeSEric Cheng return (addr_types[i].va_str); 329*da14cebeSEric Cheng } 330*da14cebeSEric Cheng return (NULL); 331*da14cebeSEric Cheng } 332*da14cebeSEric Cheng 333d62bc4baSyz147064 dladm_status_t 334d62bc4baSyz147064 dladm_vnic_str2macaddrtype(const char *str, vnic_mac_addr_type_t *val) 335843e1988Sjohnlev { 336843e1988Sjohnlev int i; 337843e1988Sjohnlev dladm_vnic_addr_type_t *type; 338843e1988Sjohnlev 339843e1988Sjohnlev for (i = 0; i < NADDR_TYPES; i++) { 340843e1988Sjohnlev type = &addr_types[i]; 341843e1988Sjohnlev if (strncmp(str, type->va_str, strlen(type->va_str)) == 0) { 342843e1988Sjohnlev *val = type->va_type; 343843e1988Sjohnlev return (DLADM_STATUS_OK); 344843e1988Sjohnlev } 345843e1988Sjohnlev } 346d62bc4baSyz147064 return (DLADM_STATUS_BADARG); 347843e1988Sjohnlev } 348843e1988Sjohnlev 349*da14cebeSEric Cheng 350*da14cebeSEric Cheng 351843e1988Sjohnlev /* 352*da14cebeSEric Cheng * Create a new VNIC / VLAN. Update the configuration file and bring it up. 353843e1988Sjohnlev */ 354843e1988Sjohnlev dladm_status_t 355d62bc4baSyz147064 dladm_vnic_create(const char *vnic, datalink_id_t linkid, 356843e1988Sjohnlev vnic_mac_addr_type_t mac_addr_type, uchar_t *mac_addr, int mac_len, 357*da14cebeSEric Cheng int *mac_slot, uint_t mac_prefix_len, uint16_t vid, 358*da14cebeSEric Cheng datalink_id_t *vnic_id_out, dladm_arg_list_t *proplist, uint32_t flags) 359843e1988Sjohnlev { 360*da14cebeSEric Cheng dladm_vnic_attr_t attr; 361d62bc4baSyz147064 datalink_id_t vnic_id; 362d62bc4baSyz147064 datalink_class_t class; 363*da14cebeSEric Cheng uint32_t media = DL_ETHER; 364*da14cebeSEric Cheng char name[MAXLINKNAMELEN]; 365*da14cebeSEric Cheng uchar_t tmp_addr[MAXMACADDRLEN]; 366843e1988Sjohnlev dladm_status_t status; 367*da14cebeSEric Cheng boolean_t is_vlan; 368*da14cebeSEric Cheng boolean_t is_etherstub; 369*da14cebeSEric Cheng int i; 370843e1988Sjohnlev 371843e1988Sjohnlev /* 372843e1988Sjohnlev * Sanity test arguments. 373843e1988Sjohnlev */ 374*da14cebeSEric Cheng if ((flags & DLADM_OPT_ACTIVE) == 0) 375*da14cebeSEric Cheng return (DLADM_STATUS_NOTSUP); 376*da14cebeSEric Cheng 377*da14cebeSEric Cheng is_vlan = ((flags & DLADM_OPT_VLAN) != 0); 378*da14cebeSEric Cheng if (is_vlan && ((vid < 1 || vid > 4094))) 379*da14cebeSEric Cheng return (DLADM_STATUS_VIDINVAL); 380*da14cebeSEric Cheng 381*da14cebeSEric Cheng is_etherstub = (linkid == DATALINK_INVALID_LINKID); 382843e1988Sjohnlev 383843e1988Sjohnlev if (mac_len > MAXMACADDRLEN) 384843e1988Sjohnlev return (DLADM_STATUS_INVALIDMACADDRLEN); 385843e1988Sjohnlev 386*da14cebeSEric Cheng if (!dladm_vnic_macaddrtype2str(mac_addr_type)) 387843e1988Sjohnlev return (DLADM_STATUS_INVALIDMACADDRTYPE); 388843e1988Sjohnlev 389*da14cebeSEric Cheng /* 390*da14cebeSEric Cheng * If a random address might be generated, but no prefix 391*da14cebeSEric Cheng * was specified by the caller, use the default MAC address 392*da14cebeSEric Cheng * prefix. 393*da14cebeSEric Cheng */ 394*da14cebeSEric Cheng if ((mac_addr_type == VNIC_MAC_ADDR_TYPE_RANDOM || 395*da14cebeSEric Cheng mac_addr_type == VNIC_MAC_ADDR_TYPE_AUTO) && 396*da14cebeSEric Cheng mac_prefix_len == 0) { 397*da14cebeSEric Cheng mac_prefix_len = sizeof (dladm_vnic_def_prefix); 398*da14cebeSEric Cheng mac_addr = tmp_addr; 399*da14cebeSEric Cheng bcopy(dladm_vnic_def_prefix, mac_addr, mac_prefix_len); 400d62bc4baSyz147064 } 401d62bc4baSyz147064 402*da14cebeSEric Cheng if ((flags & DLADM_OPT_ANCHOR) == 0) { 403*da14cebeSEric Cheng if ((status = dladm_datalink_id2info(linkid, NULL, &class, 404*da14cebeSEric Cheng &media, NULL, 0)) != DLADM_STATUS_OK) 405*da14cebeSEric Cheng return (status); 406*da14cebeSEric Cheng 407*da14cebeSEric Cheng if (class == DATALINK_CLASS_VNIC || 408*da14cebeSEric Cheng class == DATALINK_CLASS_VLAN) 409d62bc4baSyz147064 return (DLADM_STATUS_BADARG); 410*da14cebeSEric Cheng } else { 411*da14cebeSEric Cheng /* it's an anchor VNIC */ 412*da14cebeSEric Cheng if (linkid != DATALINK_INVALID_LINKID || vid != 0) 413*da14cebeSEric Cheng return (DLADM_STATUS_BADARG); 414*da14cebeSEric Cheng } 415d62bc4baSyz147064 416d62bc4baSyz147064 if (vnic == NULL) { 417d62bc4baSyz147064 flags |= DLADM_OPT_PREFIX; 418*da14cebeSEric Cheng (void) strlcpy(name, "vnic", sizeof (name)); 419*da14cebeSEric Cheng } else { 420*da14cebeSEric Cheng (void) strlcpy(name, vnic, sizeof (name)); 421d62bc4baSyz147064 } 422d62bc4baSyz147064 423*da14cebeSEric Cheng class = is_vlan ? DATALINK_CLASS_VLAN : 424*da14cebeSEric Cheng (is_etherstub ? DATALINK_CLASS_ETHERSTUB : DATALINK_CLASS_VNIC); 425*da14cebeSEric Cheng if ((status = dladm_create_datalink_id(name, class, 426*da14cebeSEric Cheng media, flags, &vnic_id)) != DLADM_STATUS_OK) 427d62bc4baSyz147064 return (status); 428*da14cebeSEric Cheng 429*da14cebeSEric Cheng if ((flags & DLADM_OPT_PREFIX) != 0) { 430*da14cebeSEric Cheng (void) snprintf(name + 4, sizeof (name), "%llu", vnic_id); 431*da14cebeSEric Cheng flags &= ~DLADM_OPT_PREFIX; 432843e1988Sjohnlev } 433843e1988Sjohnlev 434843e1988Sjohnlev bzero(&attr, sizeof (attr)); 435843e1988Sjohnlev 436*da14cebeSEric Cheng /* Extract resource_ctl and cpu_list from proplist */ 437*da14cebeSEric Cheng if (proplist != NULL) { 438*da14cebeSEric Cheng status = dladm_link_proplist_extract(proplist, 439*da14cebeSEric Cheng &attr.va_resource_props); 440*da14cebeSEric Cheng if (status != DLADM_STATUS_OK) 441d62bc4baSyz147064 goto done; 442d62bc4baSyz147064 } 443843e1988Sjohnlev 444*da14cebeSEric Cheng attr.va_vnic_id = vnic_id; 445*da14cebeSEric Cheng attr.va_link_id = linkid; 446*da14cebeSEric Cheng attr.va_mac_addr_type = mac_addr_type; 447*da14cebeSEric Cheng attr.va_mac_len = mac_len; 448*da14cebeSEric Cheng if (mac_slot != NULL) 449*da14cebeSEric Cheng attr.va_mac_slot = *mac_slot; 450*da14cebeSEric Cheng if (mac_len > 0) 451*da14cebeSEric Cheng bcopy(mac_addr, attr.va_mac_addr, mac_len); 452*da14cebeSEric Cheng else if (mac_prefix_len > 0) 453*da14cebeSEric Cheng bcopy(mac_addr, attr.va_mac_addr, mac_prefix_len); 454*da14cebeSEric Cheng attr.va_mac_prefix_len = mac_prefix_len; 455*da14cebeSEric Cheng attr.va_vid = vid; 456*da14cebeSEric Cheng attr.va_force = (flags & DLADM_OPT_FORCE) != 0; 457*da14cebeSEric Cheng attr.va_hwrings = (flags & DLADM_OPT_HWRINGS) != 0; 458*da14cebeSEric Cheng 459*da14cebeSEric Cheng status = i_dladm_vnic_create_sys(&attr); 460*da14cebeSEric Cheng if (status != DLADM_STATUS_OK) 461*da14cebeSEric Cheng goto done; 462*da14cebeSEric Cheng 463*da14cebeSEric Cheng /* Save vnic configuration and its properties */ 464*da14cebeSEric Cheng if (!(flags & DLADM_OPT_PERSIST)) 465*da14cebeSEric Cheng goto done; 466*da14cebeSEric Cheng 467*da14cebeSEric Cheng status = dladm_vnic_persist_conf(name, &attr, class); 468*da14cebeSEric Cheng if (status != DLADM_STATUS_OK) { 469*da14cebeSEric Cheng (void) i_dladm_vnic_delete_sys(vnic_id); 470*da14cebeSEric Cheng goto done; 471*da14cebeSEric Cheng } 472*da14cebeSEric Cheng 473*da14cebeSEric Cheng if (proplist != NULL) { 474*da14cebeSEric Cheng for (i = 0; i < proplist->al_count; i++) { 475*da14cebeSEric Cheng dladm_arg_info_t *aip = &proplist->al_info[i]; 476*da14cebeSEric Cheng 477*da14cebeSEric Cheng status = dladm_set_linkprop(vnic_id, aip->ai_name, 478*da14cebeSEric Cheng aip->ai_val, aip->ai_count, DLADM_OPT_PERSIST); 479*da14cebeSEric Cheng if (status != DLADM_STATUS_OK) 480*da14cebeSEric Cheng break; 481*da14cebeSEric Cheng } 482*da14cebeSEric Cheng 483*da14cebeSEric Cheng if (status != DLADM_STATUS_OK) { 484*da14cebeSEric Cheng (void) dladm_remove_conf(vnic_id); 485*da14cebeSEric Cheng (void) i_dladm_vnic_delete_sys(vnic_id); 486*da14cebeSEric Cheng } 487*da14cebeSEric Cheng } 488843e1988Sjohnlev 489d62bc4baSyz147064 done: 490d62bc4baSyz147064 if (status != DLADM_STATUS_OK) { 491*da14cebeSEric Cheng (void) dladm_destroy_datalink_id(vnic_id, flags); 492d62bc4baSyz147064 } else { 493*da14cebeSEric Cheng if (vnic_id_out != NULL) 494d62bc4baSyz147064 *vnic_id_out = vnic_id; 495*da14cebeSEric Cheng if (mac_slot != NULL) 496*da14cebeSEric Cheng *mac_slot = attr.va_mac_slot; 497d62bc4baSyz147064 } 498843e1988Sjohnlev return (status); 499843e1988Sjohnlev } 500843e1988Sjohnlev 501843e1988Sjohnlev /* 502*da14cebeSEric Cheng * Delete a VNIC / VLAN. 503843e1988Sjohnlev */ 504843e1988Sjohnlev dladm_status_t 505*da14cebeSEric Cheng dladm_vnic_delete(datalink_id_t linkid, uint32_t flags) 506843e1988Sjohnlev { 507d62bc4baSyz147064 dladm_status_t status; 508*da14cebeSEric Cheng datalink_class_t class; 509843e1988Sjohnlev 510*da14cebeSEric Cheng if (flags == 0) 511*da14cebeSEric Cheng return (DLADM_STATUS_BADARG); 512843e1988Sjohnlev 513*da14cebeSEric Cheng if ((dladm_datalink_id2info(linkid, NULL, &class, NULL, NULL, 0) != 514*da14cebeSEric Cheng DLADM_STATUS_OK)) 515*da14cebeSEric Cheng return (DLADM_STATUS_BADARG); 516d62bc4baSyz147064 517*da14cebeSEric Cheng if ((flags & DLADM_OPT_VLAN) != 0) { 518*da14cebeSEric Cheng if (class != DATALINK_CLASS_VLAN) 519*da14cebeSEric Cheng return (DLADM_STATUS_BADARG); 520*da14cebeSEric Cheng } else { 521*da14cebeSEric Cheng if (class != DATALINK_CLASS_VNIC && 522*da14cebeSEric Cheng class != DATALINK_CLASS_ETHERSTUB) 523*da14cebeSEric Cheng return (DLADM_STATUS_BADARG); 524*da14cebeSEric Cheng } 525d62bc4baSyz147064 526*da14cebeSEric Cheng if ((flags & DLADM_OPT_ACTIVE) != 0) { 527*da14cebeSEric Cheng status = i_dladm_vnic_delete_sys(linkid); 528*da14cebeSEric Cheng if (status == DLADM_STATUS_OK) { 529*da14cebeSEric Cheng (void) dladm_set_linkprop(linkid, NULL, NULL, 0, 530*da14cebeSEric Cheng DLADM_OPT_ACTIVE); 531*da14cebeSEric Cheng (void) dladm_destroy_datalink_id(linkid, 532*da14cebeSEric Cheng DLADM_OPT_ACTIVE); 533*da14cebeSEric Cheng } else if (status != DLADM_STATUS_NOTFOUND || 534*da14cebeSEric Cheng !(flags & DLADM_OPT_PERSIST)) { 535*da14cebeSEric Cheng return (status); 536*da14cebeSEric Cheng } 537*da14cebeSEric Cheng } 538*da14cebeSEric Cheng if ((flags & DLADM_OPT_PERSIST) != 0) { 539*da14cebeSEric Cheng (void) dladm_destroy_datalink_id(linkid, DLADM_OPT_PERSIST); 540*da14cebeSEric Cheng (void) dladm_remove_conf(linkid); 541*da14cebeSEric Cheng } 542*da14cebeSEric Cheng return (DLADM_STATUS_OK); 543*da14cebeSEric Cheng } 544*da14cebeSEric Cheng 545*da14cebeSEric Cheng static const char * 546*da14cebeSEric Cheng dladm_vnic_macaddr2str(const uchar_t *mac, char *buf) 547*da14cebeSEric Cheng { 548*da14cebeSEric Cheng static char unknown_mac[] = {0, 0, 0, 0, 0, 0}; 549*da14cebeSEric Cheng 550*da14cebeSEric Cheng if (buf == NULL) 551*da14cebeSEric Cheng return (NULL); 552*da14cebeSEric Cheng 553*da14cebeSEric Cheng if (bcmp(unknown_mac, mac, ETHERADDRL) == 0) 554*da14cebeSEric Cheng (void) strlcpy(buf, "unknown", DLADM_STRSIZE); 555*da14cebeSEric Cheng else 556*da14cebeSEric Cheng return (_link_ntoa(mac, buf, ETHERADDRL, IFT_OTHER)); 557*da14cebeSEric Cheng 558*da14cebeSEric Cheng return (buf); 559*da14cebeSEric Cheng } 560*da14cebeSEric Cheng 561*da14cebeSEric Cheng static dladm_status_t 562*da14cebeSEric Cheng dladm_vnic_str2macaddr(const char *str, uchar_t *buf) 563*da14cebeSEric Cheng { 564*da14cebeSEric Cheng int len = 0; 565*da14cebeSEric Cheng uchar_t *b = _link_aton(str, &len); 566*da14cebeSEric Cheng 567*da14cebeSEric Cheng if (b == NULL || len >= MAXMACADDRLEN) 568*da14cebeSEric Cheng return (DLADM_STATUS_BADARG); 569*da14cebeSEric Cheng 570*da14cebeSEric Cheng bcopy(b, buf, len); 571*da14cebeSEric Cheng free(b); 572*da14cebeSEric Cheng return (DLADM_STATUS_OK); 573*da14cebeSEric Cheng } 574*da14cebeSEric Cheng 575*da14cebeSEric Cheng 576*da14cebeSEric Cheng static dladm_status_t 577*da14cebeSEric Cheng dladm_vnic_persist_conf(const char *name, dladm_vnic_attr_t *attrp, 578*da14cebeSEric Cheng datalink_class_t class) 579*da14cebeSEric Cheng { 580*da14cebeSEric Cheng dladm_conf_t conf = DLADM_INVALID_CONF; 581*da14cebeSEric Cheng dladm_status_t status; 582*da14cebeSEric Cheng char macstr[ETHERADDRL * 3]; 583*da14cebeSEric Cheng uint64_t u64; 584*da14cebeSEric Cheng 585*da14cebeSEric Cheng if ((status = dladm_create_conf(name, attrp->va_vnic_id, 586*da14cebeSEric Cheng class, DL_ETHER, &conf)) != DLADM_STATUS_OK) 587*da14cebeSEric Cheng return (status); 588*da14cebeSEric Cheng 589*da14cebeSEric Cheng if (attrp->va_link_id != DATALINK_INVALID_LINKID) { 590*da14cebeSEric Cheng u64 = attrp->va_link_id; 591*da14cebeSEric Cheng status = dladm_set_conf_field(conf, FLINKOVER, 592*da14cebeSEric Cheng DLADM_TYPE_UINT64, &u64); 593d62bc4baSyz147064 if (status != DLADM_STATUS_OK) 594*da14cebeSEric Cheng goto done; 595*da14cebeSEric Cheng } 596d62bc4baSyz147064 597*da14cebeSEric Cheng if (class != DATALINK_CLASS_VLAN) { 598*da14cebeSEric Cheng u64 = attrp->va_mac_addr_type; 599*da14cebeSEric Cheng status = dladm_set_conf_field(conf, FMADDRTYPE, 600*da14cebeSEric Cheng DLADM_TYPE_UINT64, &u64); 601*da14cebeSEric Cheng if (status != DLADM_STATUS_OK) 602*da14cebeSEric Cheng goto done; 603*da14cebeSEric Cheng 604*da14cebeSEric Cheng if (attrp->va_mac_len != ETHERADDRL) { 605*da14cebeSEric Cheng u64 = attrp->va_mac_len; 606*da14cebeSEric Cheng status = dladm_set_conf_field(conf, FMADDRLEN, 607*da14cebeSEric Cheng DLADM_TYPE_UINT64, &u64); 608*da14cebeSEric Cheng if (status != DLADM_STATUS_OK) 609*da14cebeSEric Cheng goto done; 610*da14cebeSEric Cheng } 611*da14cebeSEric Cheng } 612*da14cebeSEric Cheng 613*da14cebeSEric Cheng if (attrp->va_hwrings) { 614*da14cebeSEric Cheng boolean_t hwrings = attrp->va_hwrings; 615*da14cebeSEric Cheng status = dladm_set_conf_field(conf, FHWRINGS, 616*da14cebeSEric Cheng DLADM_TYPE_BOOLEAN, &hwrings); 617*da14cebeSEric Cheng if (status != DLADM_STATUS_OK) 618*da14cebeSEric Cheng goto done; 619*da14cebeSEric Cheng } 620*da14cebeSEric Cheng 621*da14cebeSEric Cheng if (class != DATALINK_CLASS_VLAN) { 622*da14cebeSEric Cheng if (attrp->va_mac_slot != -1) { 623*da14cebeSEric Cheng u64 = attrp->va_mac_slot; 624*da14cebeSEric Cheng status = dladm_set_conf_field(conf, FMADDRSLOT, 625*da14cebeSEric Cheng DLADM_TYPE_UINT64, &u64); 626*da14cebeSEric Cheng if (status != DLADM_STATUS_OK) 627*da14cebeSEric Cheng goto done; 628*da14cebeSEric Cheng } 629*da14cebeSEric Cheng 630*da14cebeSEric Cheng if (attrp->va_mac_prefix_len != 631*da14cebeSEric Cheng sizeof (dladm_vnic_def_prefix)) { 632*da14cebeSEric Cheng u64 = attrp->va_mac_prefix_len; 633*da14cebeSEric Cheng status = dladm_set_conf_field(conf, FMADDRPREFIXLEN, 634*da14cebeSEric Cheng DLADM_TYPE_UINT64, &u64); 635*da14cebeSEric Cheng if (status != DLADM_STATUS_OK) 636*da14cebeSEric Cheng goto done; 637*da14cebeSEric Cheng } 638*da14cebeSEric Cheng 639*da14cebeSEric Cheng (void) dladm_vnic_macaddr2str(attrp->va_mac_addr, macstr); 640*da14cebeSEric Cheng status = dladm_set_conf_field(conf, FMACADDR, DLADM_TYPE_STR, 641*da14cebeSEric Cheng macstr); 642*da14cebeSEric Cheng if (status != DLADM_STATUS_OK) 643*da14cebeSEric Cheng goto done; 644*da14cebeSEric Cheng } 645*da14cebeSEric Cheng 646*da14cebeSEric Cheng if (attrp->va_vid != 0) { 647*da14cebeSEric Cheng u64 = attrp->va_vid; 648*da14cebeSEric Cheng status = dladm_set_conf_field(conf, FVLANID, 649*da14cebeSEric Cheng DLADM_TYPE_UINT64, &u64); 650*da14cebeSEric Cheng if (status != DLADM_STATUS_OK) 651*da14cebeSEric Cheng goto done; 652*da14cebeSEric Cheng } 653*da14cebeSEric Cheng 654*da14cebeSEric Cheng /* 655*da14cebeSEric Cheng * Commit the link configuration. 656*da14cebeSEric Cheng */ 657*da14cebeSEric Cheng status = dladm_write_conf(conf); 658*da14cebeSEric Cheng 659*da14cebeSEric Cheng done: 660*da14cebeSEric Cheng dladm_destroy_conf(conf); 661d62bc4baSyz147064 return (status); 662843e1988Sjohnlev } 663*da14cebeSEric Cheng 664*da14cebeSEric Cheng typedef struct dladm_vnic_up_arg_s { 665*da14cebeSEric Cheng uint32_t flags; 666*da14cebeSEric Cheng dladm_status_t status; 667*da14cebeSEric Cheng } dladm_vnic_up_arg_t; 668*da14cebeSEric Cheng 669*da14cebeSEric Cheng #define DLADM_VNIC_UP_FIRST_WALK 0x1 670*da14cebeSEric Cheng #define DLADM_VNIC_UP_SECOND_WALK 0x2 671*da14cebeSEric Cheng 672*da14cebeSEric Cheng static int 673*da14cebeSEric Cheng i_dladm_vnic_up(datalink_id_t linkid, void *arg) 674*da14cebeSEric Cheng { 675*da14cebeSEric Cheng dladm_status_t *statusp = &(((dladm_vnic_up_arg_t *)arg)->status); 676*da14cebeSEric Cheng dladm_vnic_attr_t attr; 677*da14cebeSEric Cheng dladm_status_t status; 678*da14cebeSEric Cheng dladm_arg_list_t *proplist; 679*da14cebeSEric Cheng uint32_t flags = ((dladm_vnic_up_arg_t *)arg)->flags; 680*da14cebeSEric Cheng 681*da14cebeSEric Cheng bzero(&attr, sizeof (attr)); 682*da14cebeSEric Cheng 683*da14cebeSEric Cheng status = dladm_vnic_info(linkid, &attr, DLADM_OPT_PERSIST); 684*da14cebeSEric Cheng if (status != DLADM_STATUS_OK) 685*da14cebeSEric Cheng goto done; 686*da14cebeSEric Cheng 687*da14cebeSEric Cheng /* 688*da14cebeSEric Cheng * Create the vnics that request hardware group first 689*da14cebeSEric Cheng * Create the vnics that don't request hardware group in the second walk 690*da14cebeSEric Cheng */ 691*da14cebeSEric Cheng if ((flags == DLADM_VNIC_UP_FIRST_WALK && !attr.va_hwrings) || 692*da14cebeSEric Cheng (flags == DLADM_VNIC_UP_SECOND_WALK && attr.va_hwrings)) 693*da14cebeSEric Cheng goto done; 694*da14cebeSEric Cheng 695*da14cebeSEric Cheng /* Get all properties for this vnic */ 696*da14cebeSEric Cheng status = dladm_link_get_proplist(linkid, &proplist); 697*da14cebeSEric Cheng if (status != DLADM_STATUS_OK) 698*da14cebeSEric Cheng goto done; 699*da14cebeSEric Cheng 700*da14cebeSEric Cheng if (proplist != NULL) { 701*da14cebeSEric Cheng status = dladm_link_proplist_extract(proplist, 702*da14cebeSEric Cheng &attr.va_resource_props); 703*da14cebeSEric Cheng } 704*da14cebeSEric Cheng 705*da14cebeSEric Cheng status = i_dladm_vnic_create_sys(&attr); 706*da14cebeSEric Cheng if (status != DLADM_STATUS_OK) 707*da14cebeSEric Cheng goto done; 708*da14cebeSEric Cheng 709*da14cebeSEric Cheng if ((status = dladm_up_datalink_id(linkid)) != DLADM_STATUS_OK) { 710*da14cebeSEric Cheng (void) i_dladm_vnic_delete_sys(linkid); 711*da14cebeSEric Cheng goto done; 712*da14cebeSEric Cheng } 713*da14cebeSEric Cheng done: 714*da14cebeSEric Cheng *statusp = status; 715*da14cebeSEric Cheng return (DLADM_WALK_CONTINUE); 716*da14cebeSEric Cheng } 717*da14cebeSEric Cheng 718*da14cebeSEric Cheng dladm_status_t 719*da14cebeSEric Cheng dladm_vnic_up(datalink_id_t linkid, uint32_t flags) 720*da14cebeSEric Cheng { 721*da14cebeSEric Cheng dladm_vnic_up_arg_t vnic_arg; 722*da14cebeSEric Cheng datalink_class_t class; 723*da14cebeSEric Cheng 724*da14cebeSEric Cheng class = ((flags & DLADM_OPT_VLAN) != 0) ? DATALINK_CLASS_VLAN : 725*da14cebeSEric Cheng (DATALINK_CLASS_VNIC | DATALINK_CLASS_ETHERSTUB); 726*da14cebeSEric Cheng 727*da14cebeSEric Cheng if (linkid == DATALINK_ALL_LINKID) { 728*da14cebeSEric Cheng vnic_arg.flags = DLADM_VNIC_UP_FIRST_WALK; 729*da14cebeSEric Cheng (void) dladm_walk_datalink_id(i_dladm_vnic_up, &vnic_arg, 730*da14cebeSEric Cheng class, DATALINK_ANY_MEDIATYPE, DLADM_OPT_PERSIST); 731*da14cebeSEric Cheng vnic_arg.flags = DLADM_VNIC_UP_SECOND_WALK; 732*da14cebeSEric Cheng (void) dladm_walk_datalink_id(i_dladm_vnic_up, &vnic_arg, 733*da14cebeSEric Cheng class, DATALINK_ANY_MEDIATYPE, DLADM_OPT_PERSIST); 734*da14cebeSEric Cheng return (DLADM_STATUS_OK); 735*da14cebeSEric Cheng } else { 736*da14cebeSEric Cheng (void) i_dladm_vnic_up(linkid, &vnic_arg); 737*da14cebeSEric Cheng return (vnic_arg.status); 738*da14cebeSEric Cheng } 739*da14cebeSEric Cheng } 740