15084Sjohnlev /* 25084Sjohnlev * CDDL HEADER START 35084Sjohnlev * 45084Sjohnlev * The contents of this file are subject to the terms of the 55084Sjohnlev * Common Development and Distribution License (the "License"). 65084Sjohnlev * You may not use this file except in compliance with the License. 75084Sjohnlev * 85084Sjohnlev * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 95084Sjohnlev * or http://www.opensolaris.org/os/licensing. 105084Sjohnlev * See the License for the specific language governing permissions 115084Sjohnlev * and limitations under the License. 125084Sjohnlev * 135084Sjohnlev * When distributing Covered Code, include this CDDL HEADER in each 145084Sjohnlev * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 155084Sjohnlev * If applicable, add the following below this CDDL HEADER, with the 165084Sjohnlev * fields enclosed by brackets "[]" replaced with your own identifying 175084Sjohnlev * information: Portions Copyright [yyyy] [name of copyright owner] 185084Sjohnlev * 195084Sjohnlev * CDDL HEADER END 205084Sjohnlev */ 215084Sjohnlev /* 22*11878SVenu.Iyer@Sun.COM * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 235084Sjohnlev * Use is subject to license terms. 245084Sjohnlev */ 255084Sjohnlev 265084Sjohnlev #include <stdio.h> 275084Sjohnlev #include <sys/types.h> 285084Sjohnlev #include <sys/stat.h> 295084Sjohnlev #include <string.h> 305084Sjohnlev #include <fcntl.h> 315084Sjohnlev #include <unistd.h> 325084Sjohnlev #include <stropts.h> 335084Sjohnlev #include <stdlib.h> 345084Sjohnlev #include <errno.h> 355084Sjohnlev #include <strings.h> 365084Sjohnlev #include <libintl.h> 375084Sjohnlev #include <net/if_types.h> 385084Sjohnlev #include <net/if_dl.h> 398275SEric Cheng #include <sys/dld.h> 405084Sjohnlev #include <libdladm_impl.h> 4111076SCathy.Zhou@Sun.COM #include <libvrrpadm.h> 425895Syz147064 #include <libdllink.h> 4310491SRishi.Srivatsavai@Sun.COM #include <libdlbridge.h> 445084Sjohnlev #include <libdlvnic.h> 455084Sjohnlev 465084Sjohnlev /* 475084Sjohnlev * VNIC administration library. 485084Sjohnlev */ 495084Sjohnlev 508275SEric Cheng /* 518275SEric Cheng * Default random MAC address prefix (locally administered). 528275SEric Cheng */ 538275SEric Cheng static char dladm_vnic_def_prefix[] = {0x02, 0x08, 0x20}; 548275SEric Cheng 558453SAnurag.Maskey@Sun.COM static dladm_status_t dladm_vnic_persist_conf(dladm_handle_t, 568453SAnurag.Maskey@Sun.COM const char *name, dladm_vnic_attr_t *, 578453SAnurag.Maskey@Sun.COM datalink_class_t); 588275SEric Cheng static const char *dladm_vnic_macaddr2str(const uchar_t *, char *); 598275SEric Cheng static dladm_status_t dladm_vnic_str2macaddr(const char *, uchar_t *); 605084Sjohnlev 618275SEric Cheng /* 628275SEric Cheng * Convert a diagnostic returned by the kernel into a dladm_status_t. 638275SEric Cheng */ 648275SEric Cheng static dladm_status_t 658275SEric Cheng dladm_vnic_diag2status(vnic_ioc_diag_t ioc_diag) 668275SEric Cheng { 678275SEric Cheng switch (ioc_diag) { 6811076SCathy.Zhou@Sun.COM case VNIC_IOC_DIAG_NONE: 6911076SCathy.Zhou@Sun.COM return (DLADM_STATUS_OK); 708275SEric Cheng case VNIC_IOC_DIAG_MACADDRLEN_INVALID: 718275SEric Cheng return (DLADM_STATUS_INVALIDMACADDRLEN); 728275SEric Cheng case VNIC_IOC_DIAG_MACADDR_NIC: 738275SEric Cheng return (DLADM_STATUS_INVALIDMACADDRNIC); 748275SEric Cheng case VNIC_IOC_DIAG_MACADDR_INUSE: 758275SEric Cheng return (DLADM_STATUS_INVALIDMACADDRINUSE); 768275SEric Cheng case VNIC_IOC_DIAG_MACFACTORYSLOTINVALID: 778275SEric Cheng return (DLADM_STATUS_MACFACTORYSLOTINVALID); 788275SEric Cheng case VNIC_IOC_DIAG_MACFACTORYSLOTUSED: 798275SEric Cheng return (DLADM_STATUS_MACFACTORYSLOTUSED); 808275SEric Cheng case VNIC_IOC_DIAG_MACFACTORYSLOTALLUSED: 818275SEric Cheng return (DLADM_STATUS_MACFACTORYSLOTALLUSED); 828275SEric Cheng case VNIC_IOC_DIAG_MACFACTORYNOTSUP: 838275SEric Cheng return (DLADM_STATUS_MACFACTORYNOTSUP); 848275SEric Cheng case VNIC_IOC_DIAG_MACPREFIX_INVALID: 858275SEric Cheng return (DLADM_STATUS_INVALIDMACPREFIX); 868275SEric Cheng case VNIC_IOC_DIAG_MACPREFIXLEN_INVALID: 878275SEric Cheng return (DLADM_STATUS_INVALIDMACPREFIXLEN); 888275SEric Cheng case VNIC_IOC_DIAG_MACMARGIN_INVALID: 898275SEric Cheng return (DLADM_STATUS_INVALID_MACMARGIN); 908275SEric Cheng case VNIC_IOC_DIAG_NO_HWRINGS: 918275SEric Cheng return (DLADM_STATUS_NO_HWRINGS); 9211076SCathy.Zhou@Sun.COM case VNIC_IOC_DIAG_MACADDR_INVALID: 9311076SCathy.Zhou@Sun.COM return (DLADM_STATUS_INVALIDMACADDR); 9411076SCathy.Zhou@Sun.COM default: 9511076SCathy.Zhou@Sun.COM return (DLADM_STATUS_FAILED); 968275SEric Cheng } 978275SEric Cheng } 985084Sjohnlev 995084Sjohnlev /* 1005084Sjohnlev * Send a create command to the VNIC driver. 1015084Sjohnlev */ 1028275SEric Cheng dladm_status_t 1038453SAnurag.Maskey@Sun.COM i_dladm_vnic_create_sys(dladm_handle_t handle, dladm_vnic_attr_t *attr) 1045084Sjohnlev { 1058453SAnurag.Maskey@Sun.COM int rc; 1065084Sjohnlev vnic_ioc_create_t ioc; 1078275SEric Cheng dladm_status_t status = DLADM_STATUS_OK; 1085084Sjohnlev 1098275SEric Cheng bzero(&ioc, sizeof (ioc)); 1108275SEric Cheng ioc.vc_vnic_id = attr->va_vnic_id; 1118275SEric Cheng ioc.vc_link_id = attr->va_link_id; 1128275SEric Cheng ioc.vc_mac_addr_type = attr->va_mac_addr_type; 1138275SEric Cheng ioc.vc_mac_len = attr->va_mac_len; 1148275SEric Cheng ioc.vc_mac_slot = attr->va_mac_slot; 1158275SEric Cheng ioc.vc_mac_prefix_len = attr->va_mac_prefix_len; 1168275SEric Cheng ioc.vc_vid = attr->va_vid; 11711076SCathy.Zhou@Sun.COM ioc.vc_vrid = attr->va_vrid; 11811076SCathy.Zhou@Sun.COM ioc.vc_af = attr->va_af; 1198275SEric Cheng ioc.vc_flags = attr->va_force ? VNIC_IOC_CREATE_FORCE : 0; 1205084Sjohnlev 1218275SEric Cheng if (attr->va_mac_len > 0 || ioc.vc_mac_prefix_len > 0) 1228275SEric Cheng bcopy(attr->va_mac_addr, ioc.vc_mac_addr, MAXMACADDRLEN); 1238275SEric Cheng bcopy(&attr->va_resource_props, &ioc.vc_resource_props, 1248275SEric Cheng sizeof (mac_resource_props_t)); 1258275SEric Cheng if (attr->va_link_id == DATALINK_INVALID_LINKID) 1268275SEric Cheng ioc.vc_flags |= VNIC_IOC_CREATE_ANCHOR; 1275084Sjohnlev 1288453SAnurag.Maskey@Sun.COM rc = ioctl(dladm_dld_fd(handle), VNIC_IOC_CREATE, &ioc); 1298275SEric Cheng if (rc < 0) 1308275SEric Cheng status = dladm_errno2status(errno); 1318275SEric Cheng 1328275SEric Cheng if (status != DLADM_STATUS_OK) { 1338275SEric Cheng if (ioc.vc_diag != VNIC_IOC_DIAG_NONE) 1348275SEric Cheng status = dladm_vnic_diag2status(ioc.vc_diag); 1358275SEric Cheng } 1368275SEric Cheng if (status != DLADM_STATUS_OK) 1378275SEric Cheng return (status); 1388275SEric Cheng 1398275SEric Cheng attr->va_mac_addr_type = ioc.vc_mac_addr_type; 1408275SEric Cheng switch (ioc.vc_mac_addr_type) { 1418275SEric Cheng case VNIC_MAC_ADDR_TYPE_FACTORY: 1428275SEric Cheng attr->va_mac_slot = ioc.vc_mac_slot; 1438275SEric Cheng break; 1448275SEric Cheng case VNIC_MAC_ADDR_TYPE_RANDOM: 1458275SEric Cheng bcopy(ioc.vc_mac_addr, attr->va_mac_addr, MAXMACADDRLEN); 1468275SEric Cheng attr->va_mac_len = ioc.vc_mac_len; 1478275SEric Cheng break; 1488275SEric Cheng } 1498275SEric Cheng return (status); 1508275SEric Cheng } 1518275SEric Cheng 1528275SEric Cheng /* 1538275SEric Cheng * Get the configuration information of the given VNIC. 1548275SEric Cheng */ 1558275SEric Cheng static dladm_status_t 1568453SAnurag.Maskey@Sun.COM i_dladm_vnic_info_active(dladm_handle_t handle, datalink_id_t linkid, 1578453SAnurag.Maskey@Sun.COM dladm_vnic_attr_t *attrp) 1588275SEric Cheng { 1598275SEric Cheng vnic_ioc_info_t ioc; 1608275SEric Cheng vnic_info_t *vnic; 1618453SAnurag.Maskey@Sun.COM int rc; 1628275SEric Cheng dladm_status_t status = DLADM_STATUS_OK; 1638275SEric Cheng 1648275SEric Cheng bzero(&ioc, sizeof (ioc)); 1658275SEric Cheng vnic = &ioc.vi_info; 1668275SEric Cheng vnic->vn_vnic_id = linkid; 1678275SEric Cheng 1688453SAnurag.Maskey@Sun.COM rc = ioctl(dladm_dld_fd(handle), VNIC_IOC_INFO, &ioc); 1698275SEric Cheng if (rc != 0) { 1708275SEric Cheng status = dladm_errno2status(errno); 1718275SEric Cheng goto bail; 1728275SEric Cheng } 1738275SEric Cheng 1748275SEric Cheng attrp->va_vnic_id = vnic->vn_vnic_id; 1758275SEric Cheng attrp->va_link_id = vnic->vn_link_id; 1768275SEric Cheng attrp->va_mac_addr_type = vnic->vn_mac_addr_type; 1778275SEric Cheng bcopy(vnic->vn_mac_addr, attrp->va_mac_addr, MAXMACADDRLEN); 1788275SEric Cheng attrp->va_mac_len = vnic->vn_mac_len; 1798275SEric Cheng attrp->va_mac_slot = vnic->vn_mac_slot; 1808275SEric Cheng attrp->va_mac_prefix_len = vnic->vn_mac_prefix_len; 1818275SEric Cheng attrp->va_vid = vnic->vn_vid; 18211076SCathy.Zhou@Sun.COM attrp->va_vrid = vnic->vn_vrid; 18311076SCathy.Zhou@Sun.COM attrp->va_af = vnic->vn_af; 1848275SEric Cheng attrp->va_force = vnic->vn_force; 1858275SEric Cheng 1868275SEric Cheng bail: 1878275SEric Cheng return (status); 1888275SEric Cheng } 1898275SEric Cheng 1908275SEric Cheng static dladm_status_t 1918453SAnurag.Maskey@Sun.COM i_dladm_vnic_info_persist(dladm_handle_t handle, datalink_id_t linkid, 1928453SAnurag.Maskey@Sun.COM dladm_vnic_attr_t *attrp) 1938275SEric Cheng { 1948275SEric Cheng dladm_conf_t conf; 1958275SEric Cheng dladm_status_t status; 1968275SEric Cheng char macstr[ETHERADDRL * 3]; 19710616SSebastien.Roy@Sun.COM char linkover[MAXLINKNAMELEN]; 1988275SEric Cheng uint64_t u64; 1998275SEric Cheng datalink_class_t class; 2008275SEric Cheng 2018275SEric Cheng attrp->va_vnic_id = linkid; 2028453SAnurag.Maskey@Sun.COM if ((status = dladm_read_conf(handle, linkid, &conf)) != 2038453SAnurag.Maskey@Sun.COM DLADM_STATUS_OK) 2048275SEric Cheng return (status); 2058275SEric Cheng 20610616SSebastien.Roy@Sun.COM status = dladm_get_conf_field(handle, conf, FLINKOVER, linkover, 20710616SSebastien.Roy@Sun.COM sizeof (linkover)); 20810616SSebastien.Roy@Sun.COM if (status != DLADM_STATUS_OK) { 20910616SSebastien.Roy@Sun.COM /* 21010616SSebastien.Roy@Sun.COM * This isn't an error, etherstubs don't have a FLINKOVER 21110616SSebastien.Roy@Sun.COM * property. 21210616SSebastien.Roy@Sun.COM */ 21310616SSebastien.Roy@Sun.COM attrp->va_link_id = DATALINK_INVALID_LINKID; 21410616SSebastien.Roy@Sun.COM } else { 21510616SSebastien.Roy@Sun.COM if ((status = dladm_name2info(handle, linkover, 21610616SSebastien.Roy@Sun.COM &attrp->va_link_id, NULL, NULL, NULL)) != DLADM_STATUS_OK) 21710616SSebastien.Roy@Sun.COM goto done; 21810616SSebastien.Roy@Sun.COM } 2198275SEric Cheng 2208453SAnurag.Maskey@Sun.COM if ((status = dladm_datalink_id2info(handle, linkid, NULL, &class, 2218275SEric Cheng NULL, NULL, 0)) != DLADM_STATUS_OK) 2228275SEric Cheng goto done; 2238275SEric Cheng 2248275SEric Cheng if (class == DATALINK_CLASS_VLAN) { 2258275SEric Cheng if (attrp->va_link_id == DATALINK_INVALID_LINKID) { 2268275SEric Cheng status = DLADM_STATUS_BADARG; 2278275SEric Cheng goto done; 2288275SEric Cheng } 2298275SEric Cheng attrp->va_mac_addr_type = VNIC_MAC_ADDR_TYPE_PRIMARY; 2308275SEric Cheng attrp->va_mac_len = 0; 2318275SEric Cheng } else { 2328453SAnurag.Maskey@Sun.COM status = dladm_get_conf_field(handle, conf, FMADDRTYPE, &u64, 2338275SEric Cheng sizeof (u64)); 2348275SEric Cheng if (status != DLADM_STATUS_OK) 2358275SEric Cheng goto done; 2368275SEric Cheng 2378275SEric Cheng attrp->va_mac_addr_type = (vnic_mac_addr_type_t)u64; 2388275SEric Cheng 23911076SCathy.Zhou@Sun.COM if ((status = dladm_get_conf_field(handle, conf, FVRID, 24011076SCathy.Zhou@Sun.COM &u64, sizeof (u64))) != DLADM_STATUS_OK) { 24111076SCathy.Zhou@Sun.COM attrp->va_vrid = VRRP_VRID_NONE; 24211076SCathy.Zhou@Sun.COM } else { 24311076SCathy.Zhou@Sun.COM attrp->va_vrid = (vrid_t)u64; 24411076SCathy.Zhou@Sun.COM } 24511076SCathy.Zhou@Sun.COM 24611076SCathy.Zhou@Sun.COM if ((status = dladm_get_conf_field(handle, conf, FVRAF, 24711076SCathy.Zhou@Sun.COM &u64, sizeof (u64))) != DLADM_STATUS_OK) { 24811076SCathy.Zhou@Sun.COM attrp->va_af = AF_UNSPEC; 24911076SCathy.Zhou@Sun.COM } else { 25011076SCathy.Zhou@Sun.COM attrp->va_af = (int)u64; 25111076SCathy.Zhou@Sun.COM } 25211076SCathy.Zhou@Sun.COM 2538453SAnurag.Maskey@Sun.COM status = dladm_get_conf_field(handle, conf, FMADDRLEN, &u64, 2548275SEric Cheng sizeof (u64)); 2558275SEric Cheng attrp->va_mac_len = ((status == DLADM_STATUS_OK) ? 2568275SEric Cheng (uint_t)u64 : ETHERADDRL); 2578275SEric Cheng 2588453SAnurag.Maskey@Sun.COM status = dladm_get_conf_field(handle, conf, FMADDRSLOT, &u64, 2598275SEric Cheng sizeof (u64)); 2608275SEric Cheng attrp->va_mac_slot = ((status == DLADM_STATUS_OK) ? 2618275SEric Cheng (int)u64 : -1); 2628275SEric Cheng 2638453SAnurag.Maskey@Sun.COM status = dladm_get_conf_field(handle, conf, FMADDRPREFIXLEN, 2648453SAnurag.Maskey@Sun.COM &u64, sizeof (u64)); 2658275SEric Cheng attrp->va_mac_prefix_len = ((status == DLADM_STATUS_OK) ? 2668275SEric Cheng (uint_t)u64 : sizeof (dladm_vnic_def_prefix)); 2678275SEric Cheng 2688453SAnurag.Maskey@Sun.COM status = dladm_get_conf_field(handle, conf, FMACADDR, macstr, 2698275SEric Cheng sizeof (macstr)); 2708275SEric Cheng if (status != DLADM_STATUS_OK) 2718275SEric Cheng goto done; 2728275SEric Cheng 2738275SEric Cheng status = dladm_vnic_str2macaddr(macstr, attrp->va_mac_addr); 2748275SEric Cheng if (status != DLADM_STATUS_OK) 2758275SEric Cheng goto done; 2768275SEric Cheng } 2778275SEric Cheng 2788453SAnurag.Maskey@Sun.COM status = dladm_get_conf_field(handle, conf, FVLANID, &u64, 2798453SAnurag.Maskey@Sun.COM sizeof (u64)); 2808275SEric Cheng attrp->va_vid = ((status == DLADM_STATUS_OK) ? (uint16_t)u64 : 0); 2818275SEric Cheng 2828275SEric Cheng 2838275SEric Cheng status = DLADM_STATUS_OK; 2848275SEric Cheng done: 2858453SAnurag.Maskey@Sun.COM dladm_destroy_conf(handle, conf); 2868275SEric Cheng return (status); 2878275SEric Cheng } 2888275SEric Cheng 2898275SEric Cheng dladm_status_t 2908453SAnurag.Maskey@Sun.COM dladm_vnic_info(dladm_handle_t handle, datalink_id_t linkid, 2918453SAnurag.Maskey@Sun.COM dladm_vnic_attr_t *attrp, uint32_t flags) 2928275SEric Cheng { 2938275SEric Cheng if (flags == DLADM_OPT_ACTIVE) 2948453SAnurag.Maskey@Sun.COM return (i_dladm_vnic_info_active(handle, linkid, attrp)); 2958275SEric Cheng else if (flags == DLADM_OPT_PERSIST) 2968453SAnurag.Maskey@Sun.COM return (i_dladm_vnic_info_persist(handle, linkid, attrp)); 2978275SEric Cheng else 2988275SEric Cheng return (DLADM_STATUS_BADARG); 2998275SEric Cheng } 3008275SEric Cheng 3018275SEric Cheng /* 3028275SEric Cheng * Remove a VNIC from the kernel. 3038275SEric Cheng */ 3048275SEric Cheng dladm_status_t 3058453SAnurag.Maskey@Sun.COM i_dladm_vnic_delete_sys(dladm_handle_t handle, datalink_id_t linkid) 3068275SEric Cheng { 3078275SEric Cheng vnic_ioc_delete_t ioc; 3088275SEric Cheng dladm_status_t status = DLADM_STATUS_OK; 3098453SAnurag.Maskey@Sun.COM int rc; 3108275SEric Cheng 3118275SEric Cheng ioc.vd_vnic_id = linkid; 3128275SEric Cheng 3138453SAnurag.Maskey@Sun.COM rc = ioctl(dladm_dld_fd(handle), VNIC_IOC_DELETE, &ioc); 3148275SEric Cheng if (rc < 0) 3157408SSebastien.Roy@Sun.COM status = dladm_errno2status(errno); 3165084Sjohnlev 3177408SSebastien.Roy@Sun.COM return (status); 3185084Sjohnlev } 3195084Sjohnlev 3205084Sjohnlev /* 3215084Sjohnlev * Convert between MAC address types and their string representations. 3225084Sjohnlev */ 3235084Sjohnlev 3245084Sjohnlev typedef struct dladm_vnic_addr_type_s { 3258275SEric Cheng const char *va_str; 3268275SEric Cheng vnic_mac_addr_type_t va_type; 3275084Sjohnlev } dladm_vnic_addr_type_t; 3285084Sjohnlev 3295084Sjohnlev static dladm_vnic_addr_type_t addr_types[] = { 3305084Sjohnlev {"fixed", VNIC_MAC_ADDR_TYPE_FIXED}, 3318275SEric Cheng {"random", VNIC_MAC_ADDR_TYPE_RANDOM}, 3328275SEric Cheng {"factory", VNIC_MAC_ADDR_TYPE_FACTORY}, 3338275SEric Cheng {"auto", VNIC_MAC_ADDR_TYPE_AUTO}, 33411076SCathy.Zhou@Sun.COM {"fixed", VNIC_MAC_ADDR_TYPE_PRIMARY}, 33511076SCathy.Zhou@Sun.COM {"vrrp", VNIC_MAC_ADDR_TYPE_VRID} 3365084Sjohnlev }; 3375084Sjohnlev 3385084Sjohnlev #define NADDR_TYPES (sizeof (addr_types) / sizeof (dladm_vnic_addr_type_t)) 3395084Sjohnlev 3408275SEric Cheng static const char * 3418275SEric Cheng dladm_vnic_macaddrtype2str(vnic_mac_addr_type_t type) 3428275SEric Cheng { 3438275SEric Cheng int i; 3448275SEric Cheng 3458275SEric Cheng for (i = 0; i < NADDR_TYPES; i++) { 3468275SEric Cheng if (type == addr_types[i].va_type) 3478275SEric Cheng return (addr_types[i].va_str); 3488275SEric Cheng } 3498275SEric Cheng return (NULL); 3508275SEric Cheng } 3518275SEric Cheng 3525895Syz147064 dladm_status_t 3535895Syz147064 dladm_vnic_str2macaddrtype(const char *str, vnic_mac_addr_type_t *val) 3545084Sjohnlev { 3555084Sjohnlev int i; 3565084Sjohnlev dladm_vnic_addr_type_t *type; 3575084Sjohnlev 3585084Sjohnlev for (i = 0; i < NADDR_TYPES; i++) { 3595084Sjohnlev type = &addr_types[i]; 3605084Sjohnlev if (strncmp(str, type->va_str, strlen(type->va_str)) == 0) { 3615084Sjohnlev *val = type->va_type; 3625895Syz147064 return (DLADM_STATUS_OK); 3635084Sjohnlev } 3645084Sjohnlev } 3655895Syz147064 return (DLADM_STATUS_BADARG); 3665084Sjohnlev } 3675084Sjohnlev 3685084Sjohnlev /* 36911076SCathy.Zhou@Sun.COM * Based on the VRRP specification, the virtual router MAC address associated 37011076SCathy.Zhou@Sun.COM * with a virtual router is an IEEE 802 MAC address in the following format: 37111076SCathy.Zhou@Sun.COM * 37211076SCathy.Zhou@Sun.COM * IPv4 case: 00-00-5E-00-01-{VRID} (in hex in internet standard bit-order) 37311076SCathy.Zhou@Sun.COM * 37411076SCathy.Zhou@Sun.COM * IPv6 case: 00-00-5E-00-02-{VRID} (in hex in internet standard bit-order) 37511076SCathy.Zhou@Sun.COM */ 37611076SCathy.Zhou@Sun.COM static dladm_status_t 37711076SCathy.Zhou@Sun.COM i_dladm_vnic_vrrp_mac(vrid_t vrid, int af, uint8_t *mac, uint_t maclen) 37811076SCathy.Zhou@Sun.COM { 37911076SCathy.Zhou@Sun.COM if (maclen < ETHERADDRL || vrid < VRRP_VRID_MIN || 38011076SCathy.Zhou@Sun.COM vrid > VRRP_VRID_MAX || (af != AF_INET && af != AF_INET6)) { 38111076SCathy.Zhou@Sun.COM return (DLADM_STATUS_BADARG); 38211076SCathy.Zhou@Sun.COM } 38311076SCathy.Zhou@Sun.COM 38411076SCathy.Zhou@Sun.COM mac[0] = mac[1] = mac[3] = 0x0; 38511076SCathy.Zhou@Sun.COM mac[2] = 0x5e; 38611076SCathy.Zhou@Sun.COM mac[4] = (af == AF_INET) ? 0x01 : 0x02; 38711076SCathy.Zhou@Sun.COM mac[5] = vrid; 38811076SCathy.Zhou@Sun.COM return (DLADM_STATUS_OK); 38911076SCathy.Zhou@Sun.COM } 39011076SCathy.Zhou@Sun.COM 39111076SCathy.Zhou@Sun.COM /* 3928275SEric Cheng * Create a new VNIC / VLAN. Update the configuration file and bring it up. 39311076SCathy.Zhou@Sun.COM * The "vrid" and "af" arguments are only required if the mac_addr_type is 39411076SCathy.Zhou@Sun.COM * VNIC_MAC_ADDR_TYPE_VRID. In that case, the MAC address will be caculated 39511076SCathy.Zhou@Sun.COM * based on the above algorithm. 3965084Sjohnlev */ 3975084Sjohnlev dladm_status_t 3988453SAnurag.Maskey@Sun.COM dladm_vnic_create(dladm_handle_t handle, const char *vnic, datalink_id_t linkid, 39911076SCathy.Zhou@Sun.COM vnic_mac_addr_type_t mac_addr_type, uchar_t *mac_addr, uint_t mac_len, 40011076SCathy.Zhou@Sun.COM int *mac_slot, uint_t mac_prefix_len, uint16_t vid, vrid_t vrid, 40111076SCathy.Zhou@Sun.COM int af, datalink_id_t *vnic_id_out, dladm_arg_list_t *proplist, 40211076SCathy.Zhou@Sun.COM uint32_t flags) 4035084Sjohnlev { 4048275SEric Cheng dladm_vnic_attr_t attr; 4055895Syz147064 datalink_id_t vnic_id; 4065895Syz147064 datalink_class_t class; 4078275SEric Cheng uint32_t media = DL_ETHER; 4088275SEric Cheng char name[MAXLINKNAMELEN]; 4098275SEric Cheng uchar_t tmp_addr[MAXMACADDRLEN]; 4105084Sjohnlev dladm_status_t status; 4118275SEric Cheng boolean_t is_vlan; 4128275SEric Cheng boolean_t is_etherstub; 4138275SEric Cheng int i; 41410491SRishi.Srivatsavai@Sun.COM boolean_t vnic_created = B_FALSE; 41510491SRishi.Srivatsavai@Sun.COM boolean_t conf_set = B_FALSE; 4165084Sjohnlev 4175084Sjohnlev /* 4185084Sjohnlev * Sanity test arguments. 4195084Sjohnlev */ 4208275SEric Cheng if ((flags & DLADM_OPT_ACTIVE) == 0) 4218275SEric Cheng return (DLADM_STATUS_NOTSUP); 4228275SEric Cheng 4238275SEric Cheng is_vlan = ((flags & DLADM_OPT_VLAN) != 0); 4248275SEric Cheng if (is_vlan && ((vid < 1 || vid > 4094))) 4258275SEric Cheng return (DLADM_STATUS_VIDINVAL); 4268275SEric Cheng 4278275SEric Cheng is_etherstub = (linkid == DATALINK_INVALID_LINKID); 4285084Sjohnlev 4298275SEric Cheng if (!dladm_vnic_macaddrtype2str(mac_addr_type)) 4305084Sjohnlev return (DLADM_STATUS_INVALIDMACADDRTYPE); 4315084Sjohnlev 43211076SCathy.Zhou@Sun.COM if ((flags & DLADM_OPT_ANCHOR) == 0) { 43311076SCathy.Zhou@Sun.COM if ((status = dladm_datalink_id2info(handle, linkid, NULL, 43411076SCathy.Zhou@Sun.COM &class, &media, NULL, 0)) != DLADM_STATUS_OK) 43511076SCathy.Zhou@Sun.COM return (status); 43611076SCathy.Zhou@Sun.COM 43711076SCathy.Zhou@Sun.COM if (class == DATALINK_CLASS_VNIC || 43811076SCathy.Zhou@Sun.COM class == DATALINK_CLASS_VLAN) 43911076SCathy.Zhou@Sun.COM return (DLADM_STATUS_BADARG); 44011076SCathy.Zhou@Sun.COM } else { 44111076SCathy.Zhou@Sun.COM /* it's an anchor VNIC */ 44211076SCathy.Zhou@Sun.COM if (linkid != DATALINK_INVALID_LINKID || vid != 0) 44311076SCathy.Zhou@Sun.COM return (DLADM_STATUS_BADARG); 44411076SCathy.Zhou@Sun.COM } 44511076SCathy.Zhou@Sun.COM 44611076SCathy.Zhou@Sun.COM /* 44711076SCathy.Zhou@Sun.COM * Only VRRP VNIC need VRID and address family specified. 44811076SCathy.Zhou@Sun.COM */ 44911076SCathy.Zhou@Sun.COM if (mac_addr_type != VNIC_MAC_ADDR_TYPE_VRID && 45011076SCathy.Zhou@Sun.COM (af != AF_UNSPEC || vrid != VRRP_VRID_NONE)) { 45111076SCathy.Zhou@Sun.COM return (DLADM_STATUS_BADARG); 45211076SCathy.Zhou@Sun.COM } 45311076SCathy.Zhou@Sun.COM 4548275SEric Cheng /* 4558275SEric Cheng * If a random address might be generated, but no prefix 4568275SEric Cheng * was specified by the caller, use the default MAC address 4578275SEric Cheng * prefix. 4588275SEric Cheng */ 4598275SEric Cheng if ((mac_addr_type == VNIC_MAC_ADDR_TYPE_RANDOM || 4608275SEric Cheng mac_addr_type == VNIC_MAC_ADDR_TYPE_AUTO) && 4618275SEric Cheng mac_prefix_len == 0) { 4628275SEric Cheng mac_prefix_len = sizeof (dladm_vnic_def_prefix); 4638275SEric Cheng mac_addr = tmp_addr; 4648275SEric Cheng bcopy(dladm_vnic_def_prefix, mac_addr, mac_prefix_len); 4655895Syz147064 } 4665895Syz147064 46711076SCathy.Zhou@Sun.COM /* 46811076SCathy.Zhou@Sun.COM * If this is a VRRP VNIC, generate its MAC address using the given 46911076SCathy.Zhou@Sun.COM * VRID and address family. 47011076SCathy.Zhou@Sun.COM */ 47111076SCathy.Zhou@Sun.COM if (mac_addr_type == VNIC_MAC_ADDR_TYPE_VRID) { 47211076SCathy.Zhou@Sun.COM /* 47311076SCathy.Zhou@Sun.COM * VRRP VNICs must be created over ethernet data-links. 47411076SCathy.Zhou@Sun.COM */ 47511076SCathy.Zhou@Sun.COM if (vrid < VRRP_VRID_MIN || vrid > VRRP_VRID_MAX || 47611076SCathy.Zhou@Sun.COM (af != AF_INET && af != AF_INET6) || mac_addr != NULL || 47711076SCathy.Zhou@Sun.COM mac_len != 0 || mac_prefix_len != 0 || 47811076SCathy.Zhou@Sun.COM (mac_slot != NULL && *mac_slot != -1) || is_etherstub || 47911076SCathy.Zhou@Sun.COM media != DL_ETHER) { 48011076SCathy.Zhou@Sun.COM return (DLADM_STATUS_BADARG); 48111076SCathy.Zhou@Sun.COM } 48211076SCathy.Zhou@Sun.COM mac_len = ETHERADDRL; 48311076SCathy.Zhou@Sun.COM mac_addr = tmp_addr; 48411076SCathy.Zhou@Sun.COM status = i_dladm_vnic_vrrp_mac(vrid, af, mac_addr, mac_len); 48511076SCathy.Zhou@Sun.COM if (status != DLADM_STATUS_OK) 4868275SEric Cheng return (status); 48711076SCathy.Zhou@Sun.COM } 4888275SEric Cheng 48911076SCathy.Zhou@Sun.COM if (mac_len > MAXMACADDRLEN) 49011076SCathy.Zhou@Sun.COM return (DLADM_STATUS_INVALIDMACADDRLEN); 4915084Sjohnlev 4925895Syz147064 if (vnic == NULL) { 4935895Syz147064 flags |= DLADM_OPT_PREFIX; 4948275SEric Cheng (void) strlcpy(name, "vnic", sizeof (name)); 4958275SEric Cheng } else { 4968275SEric Cheng (void) strlcpy(name, vnic, sizeof (name)); 4975895Syz147064 } 4985895Syz147064 4998275SEric Cheng class = is_vlan ? DATALINK_CLASS_VLAN : 5008275SEric Cheng (is_etherstub ? DATALINK_CLASS_ETHERSTUB : DATALINK_CLASS_VNIC); 5018453SAnurag.Maskey@Sun.COM if ((status = dladm_create_datalink_id(handle, name, class, 5028275SEric Cheng media, flags, &vnic_id)) != DLADM_STATUS_OK) 5035895Syz147064 return (status); 5048275SEric Cheng 5058275SEric Cheng if ((flags & DLADM_OPT_PREFIX) != 0) { 5068275SEric Cheng (void) snprintf(name + 4, sizeof (name), "%llu", vnic_id); 5078275SEric Cheng flags &= ~DLADM_OPT_PREFIX; 5085084Sjohnlev } 5095084Sjohnlev 5105084Sjohnlev bzero(&attr, sizeof (attr)); 5118275SEric Cheng 5128275SEric Cheng /* Extract resource_ctl and cpu_list from proplist */ 5138275SEric Cheng if (proplist != NULL) { 5148453SAnurag.Maskey@Sun.COM status = dladm_link_proplist_extract(handle, proplist, 515*11878SVenu.Iyer@Sun.COM &attr.va_resource_props, 0); 5168275SEric Cheng if (status != DLADM_STATUS_OK) 5178275SEric Cheng goto done; 5188275SEric Cheng } 5195084Sjohnlev 5208275SEric Cheng attr.va_vnic_id = vnic_id; 5218275SEric Cheng attr.va_link_id = linkid; 5228275SEric Cheng attr.va_mac_addr_type = mac_addr_type; 5238275SEric Cheng attr.va_mac_len = mac_len; 5248275SEric Cheng if (mac_slot != NULL) 5258275SEric Cheng attr.va_mac_slot = *mac_slot; 5268275SEric Cheng if (mac_len > 0) 5278275SEric Cheng bcopy(mac_addr, attr.va_mac_addr, mac_len); 5288275SEric Cheng else if (mac_prefix_len > 0) 5298275SEric Cheng bcopy(mac_addr, attr.va_mac_addr, mac_prefix_len); 5308275SEric Cheng attr.va_mac_prefix_len = mac_prefix_len; 5318275SEric Cheng attr.va_vid = vid; 53211076SCathy.Zhou@Sun.COM attr.va_vrid = vrid; 53311076SCathy.Zhou@Sun.COM attr.va_af = af; 5348275SEric Cheng attr.va_force = (flags & DLADM_OPT_FORCE) != 0; 5358275SEric Cheng 5368453SAnurag.Maskey@Sun.COM status = i_dladm_vnic_create_sys(handle, &attr); 5378275SEric Cheng if (status != DLADM_STATUS_OK) 5388275SEric Cheng goto done; 53910491SRishi.Srivatsavai@Sun.COM vnic_created = B_TRUE; 5408275SEric Cheng 5418275SEric Cheng /* Save vnic configuration and its properties */ 5428275SEric Cheng if (!(flags & DLADM_OPT_PERSIST)) 5438275SEric Cheng goto done; 5448275SEric Cheng 5458453SAnurag.Maskey@Sun.COM status = dladm_vnic_persist_conf(handle, name, &attr, class); 54610491SRishi.Srivatsavai@Sun.COM if (status != DLADM_STATUS_OK) 5475895Syz147064 goto done; 54810491SRishi.Srivatsavai@Sun.COM conf_set = B_TRUE; 5495895Syz147064 5508275SEric Cheng if (proplist != NULL) { 5518275SEric Cheng for (i = 0; i < proplist->al_count; i++) { 5528275SEric Cheng dladm_arg_info_t *aip = &proplist->al_info[i]; 5538275SEric Cheng 5548453SAnurag.Maskey@Sun.COM status = dladm_set_linkprop(handle, vnic_id, 5558453SAnurag.Maskey@Sun.COM aip->ai_name, aip->ai_val, aip->ai_count, 5568453SAnurag.Maskey@Sun.COM DLADM_OPT_PERSIST); 5578275SEric Cheng if (status != DLADM_STATUS_OK) 5588275SEric Cheng break; 5598275SEric Cheng } 5608275SEric Cheng } 5615084Sjohnlev 5625895Syz147064 done: 5635895Syz147064 if (status != DLADM_STATUS_OK) { 56410491SRishi.Srivatsavai@Sun.COM if (conf_set) 56510491SRishi.Srivatsavai@Sun.COM (void) dladm_remove_conf(handle, vnic_id); 56610491SRishi.Srivatsavai@Sun.COM if (vnic_created) 56710491SRishi.Srivatsavai@Sun.COM (void) i_dladm_vnic_delete_sys(handle, vnic_id); 5688453SAnurag.Maskey@Sun.COM (void) dladm_destroy_datalink_id(handle, vnic_id, flags); 5695895Syz147064 } else { 5708275SEric Cheng if (vnic_id_out != NULL) 5718275SEric Cheng *vnic_id_out = vnic_id; 5728275SEric Cheng if (mac_slot != NULL) 5738275SEric Cheng *mac_slot = attr.va_mac_slot; 5745895Syz147064 } 57510491SRishi.Srivatsavai@Sun.COM 57610491SRishi.Srivatsavai@Sun.COM if (is_vlan) { 57710491SRishi.Srivatsavai@Sun.COM dladm_status_t stat2; 57810491SRishi.Srivatsavai@Sun.COM 57910491SRishi.Srivatsavai@Sun.COM stat2 = dladm_bridge_refresh(handle, linkid); 58010491SRishi.Srivatsavai@Sun.COM if (status == DLADM_STATUS_OK && stat2 != DLADM_STATUS_OK) 58110491SRishi.Srivatsavai@Sun.COM status = stat2; 58210491SRishi.Srivatsavai@Sun.COM } 5835084Sjohnlev return (status); 5845084Sjohnlev } 5855084Sjohnlev 5865084Sjohnlev /* 5878275SEric Cheng * Delete a VNIC / VLAN. 5885084Sjohnlev */ 5895084Sjohnlev dladm_status_t 5908453SAnurag.Maskey@Sun.COM dladm_vnic_delete(dladm_handle_t handle, datalink_id_t linkid, uint32_t flags) 5915084Sjohnlev { 5928275SEric Cheng dladm_status_t status; 5938275SEric Cheng datalink_class_t class; 5948275SEric Cheng 5958275SEric Cheng if (flags == 0) 5968275SEric Cheng return (DLADM_STATUS_BADARG); 5975084Sjohnlev 5988453SAnurag.Maskey@Sun.COM if ((dladm_datalink_id2info(handle, linkid, NULL, &class, NULL, NULL, 0) 5998453SAnurag.Maskey@Sun.COM != DLADM_STATUS_OK)) 6008275SEric Cheng return (DLADM_STATUS_BADARG); 6015084Sjohnlev 6028275SEric Cheng if ((flags & DLADM_OPT_VLAN) != 0) { 6038275SEric Cheng if (class != DATALINK_CLASS_VLAN) 6048275SEric Cheng return (DLADM_STATUS_BADARG); 6058275SEric Cheng } else { 6068275SEric Cheng if (class != DATALINK_CLASS_VNIC && 6078275SEric Cheng class != DATALINK_CLASS_ETHERSTUB) 6088275SEric Cheng return (DLADM_STATUS_BADARG); 6095084Sjohnlev } 6105084Sjohnlev 6118275SEric Cheng if ((flags & DLADM_OPT_ACTIVE) != 0) { 6128453SAnurag.Maskey@Sun.COM status = i_dladm_vnic_delete_sys(handle, linkid); 6138275SEric Cheng if (status == DLADM_STATUS_OK) { 6148453SAnurag.Maskey@Sun.COM (void) dladm_set_linkprop(handle, linkid, NULL, NULL, 0, 6158275SEric Cheng DLADM_OPT_ACTIVE); 6168453SAnurag.Maskey@Sun.COM (void) dladm_destroy_datalink_id(handle, linkid, 6178275SEric Cheng DLADM_OPT_ACTIVE); 6188275SEric Cheng } else if (status != DLADM_STATUS_NOTFOUND || 6198275SEric Cheng !(flags & DLADM_OPT_PERSIST)) { 6208275SEric Cheng return (status); 6218275SEric Cheng } 6228275SEric Cheng } 6238275SEric Cheng if ((flags & DLADM_OPT_PERSIST) != 0) { 62410616SSebastien.Roy@Sun.COM (void) dladm_remove_conf(handle, linkid); 6258453SAnurag.Maskey@Sun.COM (void) dladm_destroy_datalink_id(handle, linkid, 6268453SAnurag.Maskey@Sun.COM DLADM_OPT_PERSIST); 6278275SEric Cheng } 62810491SRishi.Srivatsavai@Sun.COM return (dladm_bridge_refresh(handle, linkid)); 6298275SEric Cheng } 6308275SEric Cheng 6318275SEric Cheng static const char * 6328275SEric Cheng dladm_vnic_macaddr2str(const uchar_t *mac, char *buf) 6338275SEric Cheng { 6348275SEric Cheng static char unknown_mac[] = {0, 0, 0, 0, 0, 0}; 6358275SEric Cheng 6368275SEric Cheng if (buf == NULL) 6378275SEric Cheng return (NULL); 6388275SEric Cheng 6398275SEric Cheng if (bcmp(unknown_mac, mac, ETHERADDRL) == 0) 6408275SEric Cheng (void) strlcpy(buf, "unknown", DLADM_STRSIZE); 6418275SEric Cheng else 6428275SEric Cheng return (_link_ntoa(mac, buf, ETHERADDRL, IFT_OTHER)); 6438275SEric Cheng 6448275SEric Cheng return (buf); 6458275SEric Cheng } 6468275SEric Cheng 6478275SEric Cheng static dladm_status_t 6488275SEric Cheng dladm_vnic_str2macaddr(const char *str, uchar_t *buf) 6498275SEric Cheng { 6508275SEric Cheng int len = 0; 6518275SEric Cheng uchar_t *b = _link_aton(str, &len); 6528275SEric Cheng 6538275SEric Cheng if (b == NULL || len >= MAXMACADDRLEN) 6548275SEric Cheng return (DLADM_STATUS_BADARG); 6558275SEric Cheng 6568275SEric Cheng bcopy(b, buf, len); 6578275SEric Cheng free(b); 6588275SEric Cheng return (DLADM_STATUS_OK); 6595084Sjohnlev } 6605084Sjohnlev 6615084Sjohnlev 6628275SEric Cheng static dladm_status_t 6638453SAnurag.Maskey@Sun.COM dladm_vnic_persist_conf(dladm_handle_t handle, const char *name, 6648453SAnurag.Maskey@Sun.COM dladm_vnic_attr_t *attrp, datalink_class_t class) 6658275SEric Cheng { 6668275SEric Cheng dladm_conf_t conf = DLADM_INVALID_CONF; 6678275SEric Cheng dladm_status_t status; 6688275SEric Cheng char macstr[ETHERADDRL * 3]; 66910616SSebastien.Roy@Sun.COM char linkover[MAXLINKNAMELEN]; 6708275SEric Cheng uint64_t u64; 6715084Sjohnlev 6728453SAnurag.Maskey@Sun.COM if ((status = dladm_create_conf(handle, name, attrp->va_vnic_id, 6738275SEric Cheng class, DL_ETHER, &conf)) != DLADM_STATUS_OK) 6745895Syz147064 return (status); 6755895Syz147064 6768275SEric Cheng if (attrp->va_link_id != DATALINK_INVALID_LINKID) { 67710616SSebastien.Roy@Sun.COM status = dladm_datalink_id2info(handle, attrp->va_link_id, NULL, 67810616SSebastien.Roy@Sun.COM NULL, NULL, linkover, sizeof (linkover)); 67910616SSebastien.Roy@Sun.COM if (status != DLADM_STATUS_OK) 68010616SSebastien.Roy@Sun.COM goto done; 6818453SAnurag.Maskey@Sun.COM status = dladm_set_conf_field(handle, conf, FLINKOVER, 68210616SSebastien.Roy@Sun.COM DLADM_TYPE_STR, linkover); 6838275SEric Cheng if (status != DLADM_STATUS_OK) 6848275SEric Cheng goto done; 6858275SEric Cheng } 6868275SEric Cheng 6878275SEric Cheng if (class != DATALINK_CLASS_VLAN) { 6888275SEric Cheng u64 = attrp->va_mac_addr_type; 6898453SAnurag.Maskey@Sun.COM status = dladm_set_conf_field(handle, conf, FMADDRTYPE, 6908275SEric Cheng DLADM_TYPE_UINT64, &u64); 6918275SEric Cheng if (status != DLADM_STATUS_OK) 6928275SEric Cheng goto done; 6938275SEric Cheng 69411076SCathy.Zhou@Sun.COM u64 = attrp->va_vrid; 69511076SCathy.Zhou@Sun.COM status = dladm_set_conf_field(handle, conf, FVRID, 69611076SCathy.Zhou@Sun.COM DLADM_TYPE_UINT64, &u64); 69711076SCathy.Zhou@Sun.COM if (status != DLADM_STATUS_OK) 69811076SCathy.Zhou@Sun.COM goto done; 69911076SCathy.Zhou@Sun.COM 70011076SCathy.Zhou@Sun.COM u64 = attrp->va_af; 70111076SCathy.Zhou@Sun.COM status = dladm_set_conf_field(handle, conf, FVRAF, 70211076SCathy.Zhou@Sun.COM DLADM_TYPE_UINT64, &u64); 70311076SCathy.Zhou@Sun.COM if (status != DLADM_STATUS_OK) 70411076SCathy.Zhou@Sun.COM goto done; 70511076SCathy.Zhou@Sun.COM 7068275SEric Cheng if (attrp->va_mac_len != ETHERADDRL) { 7078275SEric Cheng u64 = attrp->va_mac_len; 7088453SAnurag.Maskey@Sun.COM status = dladm_set_conf_field(handle, conf, FMADDRLEN, 7098275SEric Cheng DLADM_TYPE_UINT64, &u64); 7108275SEric Cheng if (status != DLADM_STATUS_OK) 7118275SEric Cheng goto done; 7128275SEric Cheng } 7138275SEric Cheng 7148275SEric Cheng if (attrp->va_mac_slot != -1) { 7158275SEric Cheng u64 = attrp->va_mac_slot; 71611076SCathy.Zhou@Sun.COM status = dladm_set_conf_field(handle, conf, 71711076SCathy.Zhou@Sun.COM FMADDRSLOT, DLADM_TYPE_UINT64, &u64); 7188275SEric Cheng if (status != DLADM_STATUS_OK) 7198275SEric Cheng goto done; 7208275SEric Cheng } 7218275SEric Cheng 7228275SEric Cheng if (attrp->va_mac_prefix_len != 7238275SEric Cheng sizeof (dladm_vnic_def_prefix)) { 7248275SEric Cheng u64 = attrp->va_mac_prefix_len; 7258453SAnurag.Maskey@Sun.COM status = dladm_set_conf_field(handle, conf, 7268453SAnurag.Maskey@Sun.COM FMADDRPREFIXLEN, DLADM_TYPE_UINT64, &u64); 7278275SEric Cheng if (status != DLADM_STATUS_OK) 7288275SEric Cheng goto done; 7298275SEric Cheng } 7308275SEric Cheng 7318275SEric Cheng (void) dladm_vnic_macaddr2str(attrp->va_mac_addr, macstr); 7328453SAnurag.Maskey@Sun.COM status = dladm_set_conf_field(handle, conf, FMACADDR, 7338453SAnurag.Maskey@Sun.COM DLADM_TYPE_STR, macstr); 7348275SEric Cheng if (status != DLADM_STATUS_OK) 7358275SEric Cheng goto done; 7368275SEric Cheng } 7378275SEric Cheng 7388275SEric Cheng if (attrp->va_vid != 0) { 7398275SEric Cheng u64 = attrp->va_vid; 7408453SAnurag.Maskey@Sun.COM status = dladm_set_conf_field(handle, conf, FVLANID, 7418275SEric Cheng DLADM_TYPE_UINT64, &u64); 7428275SEric Cheng if (status != DLADM_STATUS_OK) 7438275SEric Cheng goto done; 7448275SEric Cheng } 7458275SEric Cheng 7468275SEric Cheng /* 7478275SEric Cheng * Commit the link configuration. 7488275SEric Cheng */ 7498453SAnurag.Maskey@Sun.COM status = dladm_write_conf(handle, conf); 7508275SEric Cheng 7518275SEric Cheng done: 7528453SAnurag.Maskey@Sun.COM dladm_destroy_conf(handle, conf); 7535895Syz147064 return (status); 7545084Sjohnlev } 7558275SEric Cheng 7568275SEric Cheng typedef struct dladm_vnic_up_arg_s { 7578275SEric Cheng uint32_t flags; 7588275SEric Cheng dladm_status_t status; 7598275SEric Cheng } dladm_vnic_up_arg_t; 7608275SEric Cheng 7618275SEric Cheng static int 7628453SAnurag.Maskey@Sun.COM i_dladm_vnic_up(dladm_handle_t handle, datalink_id_t linkid, void *arg) 7638275SEric Cheng { 7648275SEric Cheng dladm_status_t *statusp = &(((dladm_vnic_up_arg_t *)arg)->status); 7658275SEric Cheng dladm_vnic_attr_t attr; 7668275SEric Cheng dladm_status_t status; 7678275SEric Cheng dladm_arg_list_t *proplist; 7688275SEric Cheng 7698275SEric Cheng bzero(&attr, sizeof (attr)); 7708275SEric Cheng 7718453SAnurag.Maskey@Sun.COM status = dladm_vnic_info(handle, linkid, &attr, DLADM_OPT_PERSIST); 7728275SEric Cheng if (status != DLADM_STATUS_OK) 7738275SEric Cheng goto done; 7748275SEric Cheng 7758275SEric Cheng /* Get all properties for this vnic */ 7768453SAnurag.Maskey@Sun.COM status = dladm_link_get_proplist(handle, linkid, &proplist); 7778275SEric Cheng if (status != DLADM_STATUS_OK) 7788275SEric Cheng goto done; 7798275SEric Cheng 7808275SEric Cheng if (proplist != NULL) { 7818453SAnurag.Maskey@Sun.COM status = dladm_link_proplist_extract(handle, proplist, 782*11878SVenu.Iyer@Sun.COM &attr.va_resource_props, DLADM_OPT_BOOT); 7838275SEric Cheng } 7848275SEric Cheng 7858453SAnurag.Maskey@Sun.COM status = i_dladm_vnic_create_sys(handle, &attr); 78610491SRishi.Srivatsavai@Sun.COM if (status == DLADM_STATUS_OK) { 78710491SRishi.Srivatsavai@Sun.COM status = dladm_up_datalink_id(handle, linkid); 78810491SRishi.Srivatsavai@Sun.COM if (status != DLADM_STATUS_OK) 78910491SRishi.Srivatsavai@Sun.COM (void) i_dladm_vnic_delete_sys(handle, linkid); 79010491SRishi.Srivatsavai@Sun.COM } 7918275SEric Cheng 7928275SEric Cheng done: 7938275SEric Cheng *statusp = status; 7948275SEric Cheng return (DLADM_WALK_CONTINUE); 7958275SEric Cheng } 7968275SEric Cheng 7978275SEric Cheng dladm_status_t 7988453SAnurag.Maskey@Sun.COM dladm_vnic_up(dladm_handle_t handle, datalink_id_t linkid, uint32_t flags) 7998275SEric Cheng { 8008275SEric Cheng dladm_vnic_up_arg_t vnic_arg; 8018275SEric Cheng datalink_class_t class; 8028275SEric Cheng 8038275SEric Cheng class = ((flags & DLADM_OPT_VLAN) != 0) ? DATALINK_CLASS_VLAN : 8048275SEric Cheng (DATALINK_CLASS_VNIC | DATALINK_CLASS_ETHERSTUB); 8058275SEric Cheng 8068275SEric Cheng if (linkid == DATALINK_ALL_LINKID) { 8078453SAnurag.Maskey@Sun.COM (void) dladm_walk_datalink_id(i_dladm_vnic_up, handle, 8088453SAnurag.Maskey@Sun.COM &vnic_arg, class, DATALINK_ANY_MEDIATYPE, 8098453SAnurag.Maskey@Sun.COM DLADM_OPT_PERSIST); 8108275SEric Cheng return (DLADM_STATUS_OK); 8118275SEric Cheng } else { 8128453SAnurag.Maskey@Sun.COM (void) i_dladm_vnic_up(handle, linkid, &vnic_arg); 8138275SEric Cheng return (vnic_arg.status); 8148275SEric Cheng } 8158275SEric Cheng } 816