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*12824SCathy.Zhou@Sun.COM * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
235084Sjohnlev */
245084Sjohnlev
255084Sjohnlev #include <stdio.h>
265084Sjohnlev #include <sys/types.h>
275084Sjohnlev #include <sys/stat.h>
285084Sjohnlev #include <string.h>
295084Sjohnlev #include <fcntl.h>
305084Sjohnlev #include <unistd.h>
315084Sjohnlev #include <stropts.h>
325084Sjohnlev #include <stdlib.h>
335084Sjohnlev #include <errno.h>
345084Sjohnlev #include <strings.h>
355084Sjohnlev #include <libintl.h>
365084Sjohnlev #include <net/if_types.h>
375084Sjohnlev #include <net/if_dl.h>
388275SEric Cheng #include <sys/dld.h>
395084Sjohnlev #include <libdladm_impl.h>
4011076SCathy.Zhou@Sun.COM #include <libvrrpadm.h>
415895Syz147064 #include <libdllink.h>
4210491SRishi.Srivatsavai@Sun.COM #include <libdlbridge.h>
435084Sjohnlev #include <libdlvnic.h>
445084Sjohnlev
455084Sjohnlev /*
465084Sjohnlev * VNIC administration library.
475084Sjohnlev */
485084Sjohnlev
498275SEric Cheng /*
508275SEric Cheng * Default random MAC address prefix (locally administered).
518275SEric Cheng */
528275SEric Cheng static char dladm_vnic_def_prefix[] = {0x02, 0x08, 0x20};
538275SEric Cheng
548453SAnurag.Maskey@Sun.COM static dladm_status_t dladm_vnic_persist_conf(dladm_handle_t,
558453SAnurag.Maskey@Sun.COM const char *name, dladm_vnic_attr_t *,
568453SAnurag.Maskey@Sun.COM datalink_class_t);
578275SEric Cheng static const char *dladm_vnic_macaddr2str(const uchar_t *, char *);
588275SEric Cheng static dladm_status_t dladm_vnic_str2macaddr(const char *, uchar_t *);
595084Sjohnlev
608275SEric Cheng /*
618275SEric Cheng * Convert a diagnostic returned by the kernel into a dladm_status_t.
628275SEric Cheng */
638275SEric Cheng static dladm_status_t
dladm_vnic_diag2status(vnic_ioc_diag_t ioc_diag)648275SEric Cheng dladm_vnic_diag2status(vnic_ioc_diag_t ioc_diag)
658275SEric Cheng {
668275SEric Cheng switch (ioc_diag) {
6711076SCathy.Zhou@Sun.COM case VNIC_IOC_DIAG_NONE:
6811076SCathy.Zhou@Sun.COM return (DLADM_STATUS_OK);
698275SEric Cheng case VNIC_IOC_DIAG_MACADDRLEN_INVALID:
708275SEric Cheng return (DLADM_STATUS_INVALIDMACADDRLEN);
718275SEric Cheng case VNIC_IOC_DIAG_MACADDR_NIC:
728275SEric Cheng return (DLADM_STATUS_INVALIDMACADDRNIC);
738275SEric Cheng case VNIC_IOC_DIAG_MACADDR_INUSE:
748275SEric Cheng return (DLADM_STATUS_INVALIDMACADDRINUSE);
758275SEric Cheng case VNIC_IOC_DIAG_MACFACTORYSLOTINVALID:
768275SEric Cheng return (DLADM_STATUS_MACFACTORYSLOTINVALID);
778275SEric Cheng case VNIC_IOC_DIAG_MACFACTORYSLOTUSED:
788275SEric Cheng return (DLADM_STATUS_MACFACTORYSLOTUSED);
798275SEric Cheng case VNIC_IOC_DIAG_MACFACTORYSLOTALLUSED:
808275SEric Cheng return (DLADM_STATUS_MACFACTORYSLOTALLUSED);
818275SEric Cheng case VNIC_IOC_DIAG_MACFACTORYNOTSUP:
828275SEric Cheng return (DLADM_STATUS_MACFACTORYNOTSUP);
838275SEric Cheng case VNIC_IOC_DIAG_MACPREFIX_INVALID:
848275SEric Cheng return (DLADM_STATUS_INVALIDMACPREFIX);
858275SEric Cheng case VNIC_IOC_DIAG_MACPREFIXLEN_INVALID:
868275SEric Cheng return (DLADM_STATUS_INVALIDMACPREFIXLEN);
878275SEric Cheng case VNIC_IOC_DIAG_MACMARGIN_INVALID:
888275SEric Cheng return (DLADM_STATUS_INVALID_MACMARGIN);
898275SEric Cheng case VNIC_IOC_DIAG_NO_HWRINGS:
908275SEric Cheng return (DLADM_STATUS_NO_HWRINGS);
9111076SCathy.Zhou@Sun.COM case VNIC_IOC_DIAG_MACADDR_INVALID:
9211076SCathy.Zhou@Sun.COM return (DLADM_STATUS_INVALIDMACADDR);
9311076SCathy.Zhou@Sun.COM default:
9411076SCathy.Zhou@Sun.COM return (DLADM_STATUS_FAILED);
958275SEric Cheng }
968275SEric Cheng }
975084Sjohnlev
985084Sjohnlev /*
995084Sjohnlev * Send a create command to the VNIC driver.
1005084Sjohnlev */
1018275SEric Cheng dladm_status_t
i_dladm_vnic_create_sys(dladm_handle_t handle,dladm_vnic_attr_t * attr)1028453SAnurag.Maskey@Sun.COM i_dladm_vnic_create_sys(dladm_handle_t handle, dladm_vnic_attr_t *attr)
1035084Sjohnlev {
1048453SAnurag.Maskey@Sun.COM int rc;
1055084Sjohnlev vnic_ioc_create_t ioc;
1068275SEric Cheng dladm_status_t status = DLADM_STATUS_OK;
1075084Sjohnlev
1088275SEric Cheng bzero(&ioc, sizeof (ioc));
1098275SEric Cheng ioc.vc_vnic_id = attr->va_vnic_id;
1108275SEric Cheng ioc.vc_link_id = attr->va_link_id;
1118275SEric Cheng ioc.vc_mac_addr_type = attr->va_mac_addr_type;
1128275SEric Cheng ioc.vc_mac_len = attr->va_mac_len;
1138275SEric Cheng ioc.vc_mac_slot = attr->va_mac_slot;
1148275SEric Cheng ioc.vc_mac_prefix_len = attr->va_mac_prefix_len;
1158275SEric Cheng ioc.vc_vid = attr->va_vid;
11611076SCathy.Zhou@Sun.COM ioc.vc_vrid = attr->va_vrid;
11711076SCathy.Zhou@Sun.COM ioc.vc_af = attr->va_af;
1188275SEric Cheng ioc.vc_flags = attr->va_force ? VNIC_IOC_CREATE_FORCE : 0;
1195084Sjohnlev
1208275SEric Cheng if (attr->va_mac_len > 0 || ioc.vc_mac_prefix_len > 0)
1218275SEric Cheng bcopy(attr->va_mac_addr, ioc.vc_mac_addr, MAXMACADDRLEN);
1228275SEric Cheng bcopy(&attr->va_resource_props, &ioc.vc_resource_props,
1238275SEric Cheng sizeof (mac_resource_props_t));
1248275SEric Cheng if (attr->va_link_id == DATALINK_INVALID_LINKID)
1258275SEric Cheng ioc.vc_flags |= VNIC_IOC_CREATE_ANCHOR;
1265084Sjohnlev
1278453SAnurag.Maskey@Sun.COM rc = ioctl(dladm_dld_fd(handle), VNIC_IOC_CREATE, &ioc);
1288275SEric Cheng if (rc < 0)
1298275SEric Cheng status = dladm_errno2status(errno);
1308275SEric Cheng
1318275SEric Cheng if (status != DLADM_STATUS_OK) {
1328275SEric Cheng if (ioc.vc_diag != VNIC_IOC_DIAG_NONE)
1338275SEric Cheng status = dladm_vnic_diag2status(ioc.vc_diag);
1348275SEric Cheng }
1358275SEric Cheng if (status != DLADM_STATUS_OK)
1368275SEric Cheng return (status);
1378275SEric Cheng
1388275SEric Cheng attr->va_mac_addr_type = ioc.vc_mac_addr_type;
1398275SEric Cheng switch (ioc.vc_mac_addr_type) {
1408275SEric Cheng case VNIC_MAC_ADDR_TYPE_FACTORY:
1418275SEric Cheng attr->va_mac_slot = ioc.vc_mac_slot;
1428275SEric Cheng break;
1438275SEric Cheng case VNIC_MAC_ADDR_TYPE_RANDOM:
1448275SEric Cheng bcopy(ioc.vc_mac_addr, attr->va_mac_addr, MAXMACADDRLEN);
1458275SEric Cheng attr->va_mac_len = ioc.vc_mac_len;
1468275SEric Cheng break;
1478275SEric Cheng }
1488275SEric Cheng return (status);
1498275SEric Cheng }
1508275SEric Cheng
1518275SEric Cheng /*
1528275SEric Cheng * Get the configuration information of the given VNIC.
1538275SEric Cheng */
1548275SEric Cheng static dladm_status_t
i_dladm_vnic_info_active(dladm_handle_t handle,datalink_id_t linkid,dladm_vnic_attr_t * attrp)1558453SAnurag.Maskey@Sun.COM i_dladm_vnic_info_active(dladm_handle_t handle, datalink_id_t linkid,
1568453SAnurag.Maskey@Sun.COM dladm_vnic_attr_t *attrp)
1578275SEric Cheng {
1588275SEric Cheng vnic_ioc_info_t ioc;
1598275SEric Cheng vnic_info_t *vnic;
1608453SAnurag.Maskey@Sun.COM int rc;
1618275SEric Cheng dladm_status_t status = DLADM_STATUS_OK;
1628275SEric Cheng
1638275SEric Cheng bzero(&ioc, sizeof (ioc));
1648275SEric Cheng vnic = &ioc.vi_info;
1658275SEric Cheng vnic->vn_vnic_id = linkid;
1668275SEric Cheng
1678453SAnurag.Maskey@Sun.COM rc = ioctl(dladm_dld_fd(handle), VNIC_IOC_INFO, &ioc);
1688275SEric Cheng if (rc != 0) {
1698275SEric Cheng status = dladm_errno2status(errno);
1708275SEric Cheng goto bail;
1718275SEric Cheng }
1728275SEric Cheng
1738275SEric Cheng attrp->va_vnic_id = vnic->vn_vnic_id;
1748275SEric Cheng attrp->va_link_id = vnic->vn_link_id;
1758275SEric Cheng attrp->va_mac_addr_type = vnic->vn_mac_addr_type;
1768275SEric Cheng bcopy(vnic->vn_mac_addr, attrp->va_mac_addr, MAXMACADDRLEN);
1778275SEric Cheng attrp->va_mac_len = vnic->vn_mac_len;
1788275SEric Cheng attrp->va_mac_slot = vnic->vn_mac_slot;
1798275SEric Cheng attrp->va_mac_prefix_len = vnic->vn_mac_prefix_len;
1808275SEric Cheng attrp->va_vid = vnic->vn_vid;
18111076SCathy.Zhou@Sun.COM attrp->va_vrid = vnic->vn_vrid;
18211076SCathy.Zhou@Sun.COM attrp->va_af = vnic->vn_af;
1838275SEric Cheng attrp->va_force = vnic->vn_force;
1848275SEric Cheng
1858275SEric Cheng bail:
1868275SEric Cheng return (status);
1878275SEric Cheng }
1888275SEric Cheng
1898275SEric Cheng static dladm_status_t
i_dladm_vnic_info_persist(dladm_handle_t handle,datalink_id_t linkid,dladm_vnic_attr_t * attrp)1908453SAnurag.Maskey@Sun.COM i_dladm_vnic_info_persist(dladm_handle_t handle, datalink_id_t linkid,
1918453SAnurag.Maskey@Sun.COM dladm_vnic_attr_t *attrp)
1928275SEric Cheng {
1938275SEric Cheng dladm_conf_t conf;
1948275SEric Cheng dladm_status_t status;
1958275SEric Cheng char macstr[ETHERADDRL * 3];
19610616SSebastien.Roy@Sun.COM char linkover[MAXLINKNAMELEN];
1978275SEric Cheng uint64_t u64;
1988275SEric Cheng datalink_class_t class;
1998275SEric Cheng
2008275SEric Cheng attrp->va_vnic_id = linkid;
201*12824SCathy.Zhou@Sun.COM if ((status = dladm_getsnap_conf(handle, linkid, &conf)) !=
2028453SAnurag.Maskey@Sun.COM DLADM_STATUS_OK)
2038275SEric Cheng return (status);
2048275SEric Cheng
20510616SSebastien.Roy@Sun.COM status = dladm_get_conf_field(handle, conf, FLINKOVER, linkover,
20610616SSebastien.Roy@Sun.COM sizeof (linkover));
20710616SSebastien.Roy@Sun.COM if (status != DLADM_STATUS_OK) {
20810616SSebastien.Roy@Sun.COM /*
20910616SSebastien.Roy@Sun.COM * This isn't an error, etherstubs don't have a FLINKOVER
21010616SSebastien.Roy@Sun.COM * property.
21110616SSebastien.Roy@Sun.COM */
21210616SSebastien.Roy@Sun.COM attrp->va_link_id = DATALINK_INVALID_LINKID;
21310616SSebastien.Roy@Sun.COM } else {
21410616SSebastien.Roy@Sun.COM if ((status = dladm_name2info(handle, linkover,
21510616SSebastien.Roy@Sun.COM &attrp->va_link_id, NULL, NULL, NULL)) != DLADM_STATUS_OK)
21610616SSebastien.Roy@Sun.COM goto done;
21710616SSebastien.Roy@Sun.COM }
2188275SEric Cheng
2198453SAnurag.Maskey@Sun.COM if ((status = dladm_datalink_id2info(handle, linkid, NULL, &class,
2208275SEric Cheng NULL, NULL, 0)) != DLADM_STATUS_OK)
2218275SEric Cheng goto done;
2228275SEric Cheng
2238275SEric Cheng if (class == DATALINK_CLASS_VLAN) {
2248275SEric Cheng if (attrp->va_link_id == DATALINK_INVALID_LINKID) {
2258275SEric Cheng status = DLADM_STATUS_BADARG;
2268275SEric Cheng goto done;
2278275SEric Cheng }
2288275SEric Cheng attrp->va_mac_addr_type = VNIC_MAC_ADDR_TYPE_PRIMARY;
2298275SEric Cheng attrp->va_mac_len = 0;
2308275SEric Cheng } else {
2318453SAnurag.Maskey@Sun.COM status = dladm_get_conf_field(handle, conf, FMADDRTYPE, &u64,
2328275SEric Cheng sizeof (u64));
2338275SEric Cheng if (status != DLADM_STATUS_OK)
2348275SEric Cheng goto done;
2358275SEric Cheng
2368275SEric Cheng attrp->va_mac_addr_type = (vnic_mac_addr_type_t)u64;
2378275SEric Cheng
23811076SCathy.Zhou@Sun.COM if ((status = dladm_get_conf_field(handle, conf, FVRID,
23911076SCathy.Zhou@Sun.COM &u64, sizeof (u64))) != DLADM_STATUS_OK) {
24011076SCathy.Zhou@Sun.COM attrp->va_vrid = VRRP_VRID_NONE;
24111076SCathy.Zhou@Sun.COM } else {
24211076SCathy.Zhou@Sun.COM attrp->va_vrid = (vrid_t)u64;
24311076SCathy.Zhou@Sun.COM }
24411076SCathy.Zhou@Sun.COM
24511076SCathy.Zhou@Sun.COM if ((status = dladm_get_conf_field(handle, conf, FVRAF,
24611076SCathy.Zhou@Sun.COM &u64, sizeof (u64))) != DLADM_STATUS_OK) {
24711076SCathy.Zhou@Sun.COM attrp->va_af = AF_UNSPEC;
24811076SCathy.Zhou@Sun.COM } else {
24911076SCathy.Zhou@Sun.COM attrp->va_af = (int)u64;
25011076SCathy.Zhou@Sun.COM }
25111076SCathy.Zhou@Sun.COM
2528453SAnurag.Maskey@Sun.COM status = dladm_get_conf_field(handle, conf, FMADDRLEN, &u64,
2538275SEric Cheng sizeof (u64));
2548275SEric Cheng attrp->va_mac_len = ((status == DLADM_STATUS_OK) ?
2558275SEric Cheng (uint_t)u64 : ETHERADDRL);
2568275SEric Cheng
2578453SAnurag.Maskey@Sun.COM status = dladm_get_conf_field(handle, conf, FMADDRSLOT, &u64,
2588275SEric Cheng sizeof (u64));
2598275SEric Cheng attrp->va_mac_slot = ((status == DLADM_STATUS_OK) ?
2608275SEric Cheng (int)u64 : -1);
2618275SEric Cheng
2628453SAnurag.Maskey@Sun.COM status = dladm_get_conf_field(handle, conf, FMADDRPREFIXLEN,
2638453SAnurag.Maskey@Sun.COM &u64, sizeof (u64));
2648275SEric Cheng attrp->va_mac_prefix_len = ((status == DLADM_STATUS_OK) ?
2658275SEric Cheng (uint_t)u64 : sizeof (dladm_vnic_def_prefix));
2668275SEric Cheng
2678453SAnurag.Maskey@Sun.COM status = dladm_get_conf_field(handle, conf, FMACADDR, macstr,
2688275SEric Cheng sizeof (macstr));
2698275SEric Cheng if (status != DLADM_STATUS_OK)
2708275SEric Cheng goto done;
2718275SEric Cheng
2728275SEric Cheng status = dladm_vnic_str2macaddr(macstr, attrp->va_mac_addr);
2738275SEric Cheng if (status != DLADM_STATUS_OK)
2748275SEric Cheng goto done;
2758275SEric Cheng }
2768275SEric Cheng
2778453SAnurag.Maskey@Sun.COM status = dladm_get_conf_field(handle, conf, FVLANID, &u64,
2788453SAnurag.Maskey@Sun.COM sizeof (u64));
2798275SEric Cheng attrp->va_vid = ((status == DLADM_STATUS_OK) ? (uint16_t)u64 : 0);
2808275SEric Cheng
2818275SEric Cheng status = DLADM_STATUS_OK;
2828275SEric Cheng done:
2838453SAnurag.Maskey@Sun.COM dladm_destroy_conf(handle, conf);
2848275SEric Cheng return (status);
2858275SEric Cheng }
2868275SEric Cheng
2878275SEric Cheng dladm_status_t
dladm_vnic_info(dladm_handle_t handle,datalink_id_t linkid,dladm_vnic_attr_t * attrp,uint32_t flags)2888453SAnurag.Maskey@Sun.COM dladm_vnic_info(dladm_handle_t handle, datalink_id_t linkid,
2898453SAnurag.Maskey@Sun.COM dladm_vnic_attr_t *attrp, uint32_t flags)
2908275SEric Cheng {
2918275SEric Cheng if (flags == DLADM_OPT_ACTIVE)
2928453SAnurag.Maskey@Sun.COM return (i_dladm_vnic_info_active(handle, linkid, attrp));
2938275SEric Cheng else if (flags == DLADM_OPT_PERSIST)
2948453SAnurag.Maskey@Sun.COM return (i_dladm_vnic_info_persist(handle, linkid, attrp));
2958275SEric Cheng else
2968275SEric Cheng return (DLADM_STATUS_BADARG);
2978275SEric Cheng }
2988275SEric Cheng
2998275SEric Cheng /*
3008275SEric Cheng * Remove a VNIC from the kernel.
3018275SEric Cheng */
3028275SEric Cheng dladm_status_t
i_dladm_vnic_delete_sys(dladm_handle_t handle,datalink_id_t linkid)3038453SAnurag.Maskey@Sun.COM i_dladm_vnic_delete_sys(dladm_handle_t handle, datalink_id_t linkid)
3048275SEric Cheng {
3058275SEric Cheng vnic_ioc_delete_t ioc;
3068275SEric Cheng dladm_status_t status = DLADM_STATUS_OK;
3078453SAnurag.Maskey@Sun.COM int rc;
3088275SEric Cheng
3098275SEric Cheng ioc.vd_vnic_id = linkid;
3108275SEric Cheng
3118453SAnurag.Maskey@Sun.COM rc = ioctl(dladm_dld_fd(handle), VNIC_IOC_DELETE, &ioc);
3128275SEric Cheng if (rc < 0)
3137408SSebastien.Roy@Sun.COM status = dladm_errno2status(errno);
3145084Sjohnlev
3157408SSebastien.Roy@Sun.COM return (status);
3165084Sjohnlev }
3175084Sjohnlev
3185084Sjohnlev /*
3195084Sjohnlev * Convert between MAC address types and their string representations.
3205084Sjohnlev */
3215084Sjohnlev
3225084Sjohnlev typedef struct dladm_vnic_addr_type_s {
3238275SEric Cheng const char *va_str;
3248275SEric Cheng vnic_mac_addr_type_t va_type;
3255084Sjohnlev } dladm_vnic_addr_type_t;
3265084Sjohnlev
3275084Sjohnlev static dladm_vnic_addr_type_t addr_types[] = {
3285084Sjohnlev {"fixed", VNIC_MAC_ADDR_TYPE_FIXED},
3298275SEric Cheng {"random", VNIC_MAC_ADDR_TYPE_RANDOM},
3308275SEric Cheng {"factory", VNIC_MAC_ADDR_TYPE_FACTORY},
3318275SEric Cheng {"auto", VNIC_MAC_ADDR_TYPE_AUTO},
33211076SCathy.Zhou@Sun.COM {"fixed", VNIC_MAC_ADDR_TYPE_PRIMARY},
33311076SCathy.Zhou@Sun.COM {"vrrp", VNIC_MAC_ADDR_TYPE_VRID}
3345084Sjohnlev };
3355084Sjohnlev
3365084Sjohnlev #define NADDR_TYPES (sizeof (addr_types) / sizeof (dladm_vnic_addr_type_t))
3375084Sjohnlev
3388275SEric Cheng static const char *
dladm_vnic_macaddrtype2str(vnic_mac_addr_type_t type)3398275SEric Cheng dladm_vnic_macaddrtype2str(vnic_mac_addr_type_t type)
3408275SEric Cheng {
3418275SEric Cheng int i;
3428275SEric Cheng
3438275SEric Cheng for (i = 0; i < NADDR_TYPES; i++) {
3448275SEric Cheng if (type == addr_types[i].va_type)
3458275SEric Cheng return (addr_types[i].va_str);
3468275SEric Cheng }
3478275SEric Cheng return (NULL);
3488275SEric Cheng }
3498275SEric Cheng
3505895Syz147064 dladm_status_t
dladm_vnic_str2macaddrtype(const char * str,vnic_mac_addr_type_t * val)3515895Syz147064 dladm_vnic_str2macaddrtype(const char *str, vnic_mac_addr_type_t *val)
3525084Sjohnlev {
3535084Sjohnlev int i;
3545084Sjohnlev dladm_vnic_addr_type_t *type;
3555084Sjohnlev
3565084Sjohnlev for (i = 0; i < NADDR_TYPES; i++) {
3575084Sjohnlev type = &addr_types[i];
3585084Sjohnlev if (strncmp(str, type->va_str, strlen(type->va_str)) == 0) {
3595084Sjohnlev *val = type->va_type;
3605895Syz147064 return (DLADM_STATUS_OK);
3615084Sjohnlev }
3625084Sjohnlev }
3635895Syz147064 return (DLADM_STATUS_BADARG);
3645084Sjohnlev }
3655084Sjohnlev
3665084Sjohnlev /*
36711076SCathy.Zhou@Sun.COM * Based on the VRRP specification, the virtual router MAC address associated
36811076SCathy.Zhou@Sun.COM * with a virtual router is an IEEE 802 MAC address in the following format:
36911076SCathy.Zhou@Sun.COM *
37011076SCathy.Zhou@Sun.COM * IPv4 case: 00-00-5E-00-01-{VRID} (in hex in internet standard bit-order)
37111076SCathy.Zhou@Sun.COM *
37211076SCathy.Zhou@Sun.COM * IPv6 case: 00-00-5E-00-02-{VRID} (in hex in internet standard bit-order)
37311076SCathy.Zhou@Sun.COM */
37411076SCathy.Zhou@Sun.COM static dladm_status_t
i_dladm_vnic_vrrp_mac(vrid_t vrid,int af,uint8_t * mac,uint_t maclen)37511076SCathy.Zhou@Sun.COM i_dladm_vnic_vrrp_mac(vrid_t vrid, int af, uint8_t *mac, uint_t maclen)
37611076SCathy.Zhou@Sun.COM {
37711076SCathy.Zhou@Sun.COM if (maclen < ETHERADDRL || vrid < VRRP_VRID_MIN ||
37811076SCathy.Zhou@Sun.COM vrid > VRRP_VRID_MAX || (af != AF_INET && af != AF_INET6)) {
37911076SCathy.Zhou@Sun.COM return (DLADM_STATUS_BADARG);
38011076SCathy.Zhou@Sun.COM }
38111076SCathy.Zhou@Sun.COM
38211076SCathy.Zhou@Sun.COM mac[0] = mac[1] = mac[3] = 0x0;
38311076SCathy.Zhou@Sun.COM mac[2] = 0x5e;
38411076SCathy.Zhou@Sun.COM mac[4] = (af == AF_INET) ? 0x01 : 0x02;
38511076SCathy.Zhou@Sun.COM mac[5] = vrid;
38611076SCathy.Zhou@Sun.COM return (DLADM_STATUS_OK);
38711076SCathy.Zhou@Sun.COM }
38811076SCathy.Zhou@Sun.COM
38911076SCathy.Zhou@Sun.COM /*
3908275SEric Cheng * Create a new VNIC / VLAN. Update the configuration file and bring it up.
39111076SCathy.Zhou@Sun.COM * The "vrid" and "af" arguments are only required if the mac_addr_type is
39211076SCathy.Zhou@Sun.COM * VNIC_MAC_ADDR_TYPE_VRID. In that case, the MAC address will be caculated
39311076SCathy.Zhou@Sun.COM * based on the above algorithm.
3945084Sjohnlev */
3955084Sjohnlev dladm_status_t
dladm_vnic_create(dladm_handle_t handle,const char * vnic,datalink_id_t linkid,vnic_mac_addr_type_t mac_addr_type,uchar_t * mac_addr,uint_t mac_len,int * mac_slot,uint_t mac_prefix_len,uint16_t vid,vrid_t vrid,int af,datalink_id_t * vnic_id_out,dladm_arg_list_t * proplist,uint32_t flags)3968453SAnurag.Maskey@Sun.COM dladm_vnic_create(dladm_handle_t handle, const char *vnic, datalink_id_t linkid,
39711076SCathy.Zhou@Sun.COM vnic_mac_addr_type_t mac_addr_type, uchar_t *mac_addr, uint_t mac_len,
39811076SCathy.Zhou@Sun.COM int *mac_slot, uint_t mac_prefix_len, uint16_t vid, vrid_t vrid,
39911076SCathy.Zhou@Sun.COM int af, datalink_id_t *vnic_id_out, dladm_arg_list_t *proplist,
40011076SCathy.Zhou@Sun.COM uint32_t flags)
4015084Sjohnlev {
4028275SEric Cheng dladm_vnic_attr_t attr;
4035895Syz147064 datalink_id_t vnic_id;
4045895Syz147064 datalink_class_t class;
4058275SEric Cheng uint32_t media = DL_ETHER;
4068275SEric Cheng char name[MAXLINKNAMELEN];
4078275SEric Cheng uchar_t tmp_addr[MAXMACADDRLEN];
4085084Sjohnlev dladm_status_t status;
4098275SEric Cheng boolean_t is_vlan;
4108275SEric Cheng boolean_t is_etherstub;
4118275SEric Cheng int i;
41210491SRishi.Srivatsavai@Sun.COM boolean_t vnic_created = B_FALSE;
41310491SRishi.Srivatsavai@Sun.COM boolean_t conf_set = B_FALSE;
4145084Sjohnlev
4155084Sjohnlev /*
4165084Sjohnlev * Sanity test arguments.
4175084Sjohnlev */
4188275SEric Cheng if ((flags & DLADM_OPT_ACTIVE) == 0)
4198275SEric Cheng return (DLADM_STATUS_NOTSUP);
4208275SEric Cheng
4218275SEric Cheng is_vlan = ((flags & DLADM_OPT_VLAN) != 0);
4228275SEric Cheng if (is_vlan && ((vid < 1 || vid > 4094)))
4238275SEric Cheng return (DLADM_STATUS_VIDINVAL);
4248275SEric Cheng
4258275SEric Cheng is_etherstub = (linkid == DATALINK_INVALID_LINKID);
4265084Sjohnlev
4278275SEric Cheng if (!dladm_vnic_macaddrtype2str(mac_addr_type))
4285084Sjohnlev return (DLADM_STATUS_INVALIDMACADDRTYPE);
4295084Sjohnlev
43011076SCathy.Zhou@Sun.COM if ((flags & DLADM_OPT_ANCHOR) == 0) {
43111076SCathy.Zhou@Sun.COM if ((status = dladm_datalink_id2info(handle, linkid, NULL,
43211076SCathy.Zhou@Sun.COM &class, &media, NULL, 0)) != DLADM_STATUS_OK)
43311076SCathy.Zhou@Sun.COM return (status);
43411076SCathy.Zhou@Sun.COM
43511076SCathy.Zhou@Sun.COM if (class == DATALINK_CLASS_VNIC ||
43611076SCathy.Zhou@Sun.COM class == DATALINK_CLASS_VLAN)
43711076SCathy.Zhou@Sun.COM return (DLADM_STATUS_BADARG);
43811076SCathy.Zhou@Sun.COM } else {
43911076SCathy.Zhou@Sun.COM /* it's an anchor VNIC */
44011076SCathy.Zhou@Sun.COM if (linkid != DATALINK_INVALID_LINKID || vid != 0)
44111076SCathy.Zhou@Sun.COM return (DLADM_STATUS_BADARG);
44211076SCathy.Zhou@Sun.COM }
44311076SCathy.Zhou@Sun.COM
44411076SCathy.Zhou@Sun.COM /*
44511076SCathy.Zhou@Sun.COM * Only VRRP VNIC need VRID and address family specified.
44611076SCathy.Zhou@Sun.COM */
44711076SCathy.Zhou@Sun.COM if (mac_addr_type != VNIC_MAC_ADDR_TYPE_VRID &&
44811076SCathy.Zhou@Sun.COM (af != AF_UNSPEC || vrid != VRRP_VRID_NONE)) {
44911076SCathy.Zhou@Sun.COM return (DLADM_STATUS_BADARG);
45011076SCathy.Zhou@Sun.COM }
45111076SCathy.Zhou@Sun.COM
4528275SEric Cheng /*
4538275SEric Cheng * If a random address might be generated, but no prefix
4548275SEric Cheng * was specified by the caller, use the default MAC address
4558275SEric Cheng * prefix.
4568275SEric Cheng */
4578275SEric Cheng if ((mac_addr_type == VNIC_MAC_ADDR_TYPE_RANDOM ||
4588275SEric Cheng mac_addr_type == VNIC_MAC_ADDR_TYPE_AUTO) &&
4598275SEric Cheng mac_prefix_len == 0) {
4608275SEric Cheng mac_prefix_len = sizeof (dladm_vnic_def_prefix);
4618275SEric Cheng mac_addr = tmp_addr;
4628275SEric Cheng bcopy(dladm_vnic_def_prefix, mac_addr, mac_prefix_len);
4635895Syz147064 }
4645895Syz147064
46511076SCathy.Zhou@Sun.COM /*
46611076SCathy.Zhou@Sun.COM * If this is a VRRP VNIC, generate its MAC address using the given
46711076SCathy.Zhou@Sun.COM * VRID and address family.
46811076SCathy.Zhou@Sun.COM */
46911076SCathy.Zhou@Sun.COM if (mac_addr_type == VNIC_MAC_ADDR_TYPE_VRID) {
47011076SCathy.Zhou@Sun.COM /*
47111076SCathy.Zhou@Sun.COM * VRRP VNICs must be created over ethernet data-links.
47211076SCathy.Zhou@Sun.COM */
47311076SCathy.Zhou@Sun.COM if (vrid < VRRP_VRID_MIN || vrid > VRRP_VRID_MAX ||
47411076SCathy.Zhou@Sun.COM (af != AF_INET && af != AF_INET6) || mac_addr != NULL ||
47511076SCathy.Zhou@Sun.COM mac_len != 0 || mac_prefix_len != 0 ||
47611076SCathy.Zhou@Sun.COM (mac_slot != NULL && *mac_slot != -1) || is_etherstub ||
47711076SCathy.Zhou@Sun.COM media != DL_ETHER) {
47811076SCathy.Zhou@Sun.COM return (DLADM_STATUS_BADARG);
47911076SCathy.Zhou@Sun.COM }
48011076SCathy.Zhou@Sun.COM mac_len = ETHERADDRL;
48111076SCathy.Zhou@Sun.COM mac_addr = tmp_addr;
48211076SCathy.Zhou@Sun.COM status = i_dladm_vnic_vrrp_mac(vrid, af, mac_addr, mac_len);
48311076SCathy.Zhou@Sun.COM if (status != DLADM_STATUS_OK)
4848275SEric Cheng return (status);
48511076SCathy.Zhou@Sun.COM }
4868275SEric Cheng
48711076SCathy.Zhou@Sun.COM if (mac_len > MAXMACADDRLEN)
48811076SCathy.Zhou@Sun.COM return (DLADM_STATUS_INVALIDMACADDRLEN);
4895084Sjohnlev
4905895Syz147064 if (vnic == NULL) {
4915895Syz147064 flags |= DLADM_OPT_PREFIX;
4928275SEric Cheng (void) strlcpy(name, "vnic", sizeof (name));
4938275SEric Cheng } else {
4948275SEric Cheng (void) strlcpy(name, vnic, sizeof (name));
4955895Syz147064 }
4965895Syz147064
4978275SEric Cheng class = is_vlan ? DATALINK_CLASS_VLAN :
4988275SEric Cheng (is_etherstub ? DATALINK_CLASS_ETHERSTUB : DATALINK_CLASS_VNIC);
4998453SAnurag.Maskey@Sun.COM if ((status = dladm_create_datalink_id(handle, name, class,
5008275SEric Cheng media, flags, &vnic_id)) != DLADM_STATUS_OK)
5015895Syz147064 return (status);
5028275SEric Cheng
5038275SEric Cheng if ((flags & DLADM_OPT_PREFIX) != 0) {
5048275SEric Cheng (void) snprintf(name + 4, sizeof (name), "%llu", vnic_id);
5058275SEric Cheng flags &= ~DLADM_OPT_PREFIX;
5065084Sjohnlev }
5075084Sjohnlev
5085084Sjohnlev bzero(&attr, sizeof (attr));
5098275SEric Cheng
5108275SEric Cheng /* Extract resource_ctl and cpu_list from proplist */
5118275SEric Cheng if (proplist != NULL) {
5128453SAnurag.Maskey@Sun.COM status = dladm_link_proplist_extract(handle, proplist,
51311878SVenu.Iyer@Sun.COM &attr.va_resource_props, 0);
5148275SEric Cheng if (status != DLADM_STATUS_OK)
5158275SEric Cheng goto done;
5168275SEric Cheng }
5175084Sjohnlev
5188275SEric Cheng attr.va_vnic_id = vnic_id;
5198275SEric Cheng attr.va_link_id = linkid;
5208275SEric Cheng attr.va_mac_addr_type = mac_addr_type;
5218275SEric Cheng attr.va_mac_len = mac_len;
5228275SEric Cheng if (mac_slot != NULL)
5238275SEric Cheng attr.va_mac_slot = *mac_slot;
5248275SEric Cheng if (mac_len > 0)
5258275SEric Cheng bcopy(mac_addr, attr.va_mac_addr, mac_len);
5268275SEric Cheng else if (mac_prefix_len > 0)
5278275SEric Cheng bcopy(mac_addr, attr.va_mac_addr, mac_prefix_len);
5288275SEric Cheng attr.va_mac_prefix_len = mac_prefix_len;
5298275SEric Cheng attr.va_vid = vid;
53011076SCathy.Zhou@Sun.COM attr.va_vrid = vrid;
53111076SCathy.Zhou@Sun.COM attr.va_af = af;
5328275SEric Cheng attr.va_force = (flags & DLADM_OPT_FORCE) != 0;
5338275SEric Cheng
5348453SAnurag.Maskey@Sun.COM status = i_dladm_vnic_create_sys(handle, &attr);
5358275SEric Cheng if (status != DLADM_STATUS_OK)
5368275SEric Cheng goto done;
53710491SRishi.Srivatsavai@Sun.COM vnic_created = B_TRUE;
5388275SEric Cheng
5398275SEric Cheng /* Save vnic configuration and its properties */
5408275SEric Cheng if (!(flags & DLADM_OPT_PERSIST))
5418275SEric Cheng goto done;
5428275SEric Cheng
5438453SAnurag.Maskey@Sun.COM status = dladm_vnic_persist_conf(handle, name, &attr, class);
54410491SRishi.Srivatsavai@Sun.COM if (status != DLADM_STATUS_OK)
5455895Syz147064 goto done;
54610491SRishi.Srivatsavai@Sun.COM conf_set = B_TRUE;
5475895Syz147064
5488275SEric Cheng if (proplist != NULL) {
5498275SEric Cheng for (i = 0; i < proplist->al_count; i++) {
5508275SEric Cheng dladm_arg_info_t *aip = &proplist->al_info[i];
5518275SEric Cheng
5528453SAnurag.Maskey@Sun.COM status = dladm_set_linkprop(handle, vnic_id,
5538453SAnurag.Maskey@Sun.COM aip->ai_name, aip->ai_val, aip->ai_count,
5548453SAnurag.Maskey@Sun.COM DLADM_OPT_PERSIST);
5558275SEric Cheng if (status != DLADM_STATUS_OK)
5568275SEric Cheng break;
5578275SEric Cheng }
5588275SEric Cheng }
5595084Sjohnlev
5605895Syz147064 done:
5615895Syz147064 if (status != DLADM_STATUS_OK) {
56210491SRishi.Srivatsavai@Sun.COM if (conf_set)
56310491SRishi.Srivatsavai@Sun.COM (void) dladm_remove_conf(handle, vnic_id);
56410491SRishi.Srivatsavai@Sun.COM if (vnic_created)
56510491SRishi.Srivatsavai@Sun.COM (void) i_dladm_vnic_delete_sys(handle, vnic_id);
5668453SAnurag.Maskey@Sun.COM (void) dladm_destroy_datalink_id(handle, vnic_id, flags);
5675895Syz147064 } else {
5688275SEric Cheng if (vnic_id_out != NULL)
5698275SEric Cheng *vnic_id_out = vnic_id;
5708275SEric Cheng if (mac_slot != NULL)
5718275SEric Cheng *mac_slot = attr.va_mac_slot;
5725895Syz147064 }
57310491SRishi.Srivatsavai@Sun.COM
57410491SRishi.Srivatsavai@Sun.COM if (is_vlan) {
57510491SRishi.Srivatsavai@Sun.COM dladm_status_t stat2;
57610491SRishi.Srivatsavai@Sun.COM
57710491SRishi.Srivatsavai@Sun.COM stat2 = dladm_bridge_refresh(handle, linkid);
57810491SRishi.Srivatsavai@Sun.COM if (status == DLADM_STATUS_OK && stat2 != DLADM_STATUS_OK)
57910491SRishi.Srivatsavai@Sun.COM status = stat2;
58010491SRishi.Srivatsavai@Sun.COM }
5815084Sjohnlev return (status);
5825084Sjohnlev }
5835084Sjohnlev
5845084Sjohnlev /*
5858275SEric Cheng * Delete a VNIC / VLAN.
5865084Sjohnlev */
5875084Sjohnlev dladm_status_t
dladm_vnic_delete(dladm_handle_t handle,datalink_id_t linkid,uint32_t flags)5888453SAnurag.Maskey@Sun.COM dladm_vnic_delete(dladm_handle_t handle, datalink_id_t linkid, uint32_t flags)
5895084Sjohnlev {
5908275SEric Cheng dladm_status_t status;
5918275SEric Cheng datalink_class_t class;
5928275SEric Cheng
5938275SEric Cheng if (flags == 0)
5948275SEric Cheng return (DLADM_STATUS_BADARG);
5955084Sjohnlev
5968453SAnurag.Maskey@Sun.COM if ((dladm_datalink_id2info(handle, linkid, NULL, &class, NULL, NULL, 0)
5978453SAnurag.Maskey@Sun.COM != DLADM_STATUS_OK))
5988275SEric Cheng return (DLADM_STATUS_BADARG);
5995084Sjohnlev
6008275SEric Cheng if ((flags & DLADM_OPT_VLAN) != 0) {
6018275SEric Cheng if (class != DATALINK_CLASS_VLAN)
6028275SEric Cheng return (DLADM_STATUS_BADARG);
6038275SEric Cheng } else {
6048275SEric Cheng if (class != DATALINK_CLASS_VNIC &&
6058275SEric Cheng class != DATALINK_CLASS_ETHERSTUB)
6068275SEric Cheng return (DLADM_STATUS_BADARG);
6075084Sjohnlev }
6085084Sjohnlev
6098275SEric Cheng if ((flags & DLADM_OPT_ACTIVE) != 0) {
6108453SAnurag.Maskey@Sun.COM status = i_dladm_vnic_delete_sys(handle, linkid);
6118275SEric Cheng if (status == DLADM_STATUS_OK) {
6128453SAnurag.Maskey@Sun.COM (void) dladm_set_linkprop(handle, linkid, NULL, NULL, 0,
6138275SEric Cheng DLADM_OPT_ACTIVE);
6148453SAnurag.Maskey@Sun.COM (void) dladm_destroy_datalink_id(handle, linkid,
6158275SEric Cheng DLADM_OPT_ACTIVE);
6168275SEric Cheng } else if (status != DLADM_STATUS_NOTFOUND ||
6178275SEric Cheng !(flags & DLADM_OPT_PERSIST)) {
6188275SEric Cheng return (status);
6198275SEric Cheng }
6208275SEric Cheng }
6218275SEric Cheng if ((flags & DLADM_OPT_PERSIST) != 0) {
62210616SSebastien.Roy@Sun.COM (void) dladm_remove_conf(handle, linkid);
6238453SAnurag.Maskey@Sun.COM (void) dladm_destroy_datalink_id(handle, linkid,
6248453SAnurag.Maskey@Sun.COM DLADM_OPT_PERSIST);
6258275SEric Cheng }
62610491SRishi.Srivatsavai@Sun.COM return (dladm_bridge_refresh(handle, linkid));
6278275SEric Cheng }
6288275SEric Cheng
6298275SEric Cheng static const char *
dladm_vnic_macaddr2str(const uchar_t * mac,char * buf)6308275SEric Cheng dladm_vnic_macaddr2str(const uchar_t *mac, char *buf)
6318275SEric Cheng {
6328275SEric Cheng static char unknown_mac[] = {0, 0, 0, 0, 0, 0};
6338275SEric Cheng
6348275SEric Cheng if (buf == NULL)
6358275SEric Cheng return (NULL);
6368275SEric Cheng
6378275SEric Cheng if (bcmp(unknown_mac, mac, ETHERADDRL) == 0)
6388275SEric Cheng (void) strlcpy(buf, "unknown", DLADM_STRSIZE);
6398275SEric Cheng else
6408275SEric Cheng return (_link_ntoa(mac, buf, ETHERADDRL, IFT_OTHER));
6418275SEric Cheng
6428275SEric Cheng return (buf);
6438275SEric Cheng }
6448275SEric Cheng
6458275SEric Cheng static dladm_status_t
dladm_vnic_str2macaddr(const char * str,uchar_t * buf)6468275SEric Cheng dladm_vnic_str2macaddr(const char *str, uchar_t *buf)
6478275SEric Cheng {
6488275SEric Cheng int len = 0;
6498275SEric Cheng uchar_t *b = _link_aton(str, &len);
6508275SEric Cheng
6518275SEric Cheng if (b == NULL || len >= MAXMACADDRLEN)
6528275SEric Cheng return (DLADM_STATUS_BADARG);
6538275SEric Cheng
6548275SEric Cheng bcopy(b, buf, len);
6558275SEric Cheng free(b);
6568275SEric Cheng return (DLADM_STATUS_OK);
6575084Sjohnlev }
6585084Sjohnlev
6595084Sjohnlev
6608275SEric Cheng static dladm_status_t
dladm_vnic_persist_conf(dladm_handle_t handle,const char * name,dladm_vnic_attr_t * attrp,datalink_class_t class)6618453SAnurag.Maskey@Sun.COM dladm_vnic_persist_conf(dladm_handle_t handle, const char *name,
6628453SAnurag.Maskey@Sun.COM dladm_vnic_attr_t *attrp, datalink_class_t class)
6638275SEric Cheng {
664*12824SCathy.Zhou@Sun.COM dladm_conf_t conf;
6658275SEric Cheng dladm_status_t status;
6668275SEric Cheng char macstr[ETHERADDRL * 3];
66710616SSebastien.Roy@Sun.COM char linkover[MAXLINKNAMELEN];
6688275SEric Cheng uint64_t u64;
6695084Sjohnlev
6708453SAnurag.Maskey@Sun.COM if ((status = dladm_create_conf(handle, name, attrp->va_vnic_id,
6718275SEric Cheng class, DL_ETHER, &conf)) != DLADM_STATUS_OK)
6725895Syz147064 return (status);
6735895Syz147064
6748275SEric Cheng if (attrp->va_link_id != DATALINK_INVALID_LINKID) {
67510616SSebastien.Roy@Sun.COM status = dladm_datalink_id2info(handle, attrp->va_link_id, NULL,
67610616SSebastien.Roy@Sun.COM NULL, NULL, linkover, sizeof (linkover));
67710616SSebastien.Roy@Sun.COM if (status != DLADM_STATUS_OK)
67810616SSebastien.Roy@Sun.COM goto done;
6798453SAnurag.Maskey@Sun.COM status = dladm_set_conf_field(handle, conf, FLINKOVER,
68010616SSebastien.Roy@Sun.COM DLADM_TYPE_STR, linkover);
6818275SEric Cheng if (status != DLADM_STATUS_OK)
6828275SEric Cheng goto done;
6838275SEric Cheng }
6848275SEric Cheng
6858275SEric Cheng if (class != DATALINK_CLASS_VLAN) {
6868275SEric Cheng u64 = attrp->va_mac_addr_type;
6878453SAnurag.Maskey@Sun.COM status = dladm_set_conf_field(handle, conf, FMADDRTYPE,
6888275SEric Cheng DLADM_TYPE_UINT64, &u64);
6898275SEric Cheng if (status != DLADM_STATUS_OK)
6908275SEric Cheng goto done;
6918275SEric Cheng
69211076SCathy.Zhou@Sun.COM u64 = attrp->va_vrid;
69311076SCathy.Zhou@Sun.COM status = dladm_set_conf_field(handle, conf, FVRID,
69411076SCathy.Zhou@Sun.COM DLADM_TYPE_UINT64, &u64);
69511076SCathy.Zhou@Sun.COM if (status != DLADM_STATUS_OK)
69611076SCathy.Zhou@Sun.COM goto done;
69711076SCathy.Zhou@Sun.COM
69811076SCathy.Zhou@Sun.COM u64 = attrp->va_af;
69911076SCathy.Zhou@Sun.COM status = dladm_set_conf_field(handle, conf, FVRAF,
70011076SCathy.Zhou@Sun.COM DLADM_TYPE_UINT64, &u64);
70111076SCathy.Zhou@Sun.COM if (status != DLADM_STATUS_OK)
70211076SCathy.Zhou@Sun.COM goto done;
70311076SCathy.Zhou@Sun.COM
7048275SEric Cheng if (attrp->va_mac_len != ETHERADDRL) {
7058275SEric Cheng u64 = attrp->va_mac_len;
7068453SAnurag.Maskey@Sun.COM status = dladm_set_conf_field(handle, conf, FMADDRLEN,
7078275SEric Cheng DLADM_TYPE_UINT64, &u64);
7088275SEric Cheng if (status != DLADM_STATUS_OK)
7098275SEric Cheng goto done;
7108275SEric Cheng }
7118275SEric Cheng
7128275SEric Cheng if (attrp->va_mac_slot != -1) {
7138275SEric Cheng u64 = attrp->va_mac_slot;
71411076SCathy.Zhou@Sun.COM status = dladm_set_conf_field(handle, conf,
71511076SCathy.Zhou@Sun.COM FMADDRSLOT, DLADM_TYPE_UINT64, &u64);
7168275SEric Cheng if (status != DLADM_STATUS_OK)
7178275SEric Cheng goto done;
7188275SEric Cheng }
7198275SEric Cheng
7208275SEric Cheng if (attrp->va_mac_prefix_len !=
7218275SEric Cheng sizeof (dladm_vnic_def_prefix)) {
7228275SEric Cheng u64 = attrp->va_mac_prefix_len;
7238453SAnurag.Maskey@Sun.COM status = dladm_set_conf_field(handle, conf,
7248453SAnurag.Maskey@Sun.COM FMADDRPREFIXLEN, DLADM_TYPE_UINT64, &u64);
7258275SEric Cheng if (status != DLADM_STATUS_OK)
7268275SEric Cheng goto done;
7278275SEric Cheng }
7288275SEric Cheng
7298275SEric Cheng (void) dladm_vnic_macaddr2str(attrp->va_mac_addr, macstr);
7308453SAnurag.Maskey@Sun.COM status = dladm_set_conf_field(handle, conf, FMACADDR,
7318453SAnurag.Maskey@Sun.COM DLADM_TYPE_STR, macstr);
7328275SEric Cheng if (status != DLADM_STATUS_OK)
7338275SEric Cheng goto done;
7348275SEric Cheng }
7358275SEric Cheng
7368275SEric Cheng if (attrp->va_vid != 0) {
7378275SEric Cheng u64 = attrp->va_vid;
7388453SAnurag.Maskey@Sun.COM status = dladm_set_conf_field(handle, conf, FVLANID,
7398275SEric Cheng DLADM_TYPE_UINT64, &u64);
7408275SEric Cheng if (status != DLADM_STATUS_OK)
7418275SEric Cheng goto done;
7428275SEric Cheng }
7438275SEric Cheng
7448275SEric Cheng /*
7458275SEric Cheng * Commit the link configuration.
7468275SEric Cheng */
7478453SAnurag.Maskey@Sun.COM status = dladm_write_conf(handle, conf);
7488275SEric Cheng
7498275SEric Cheng done:
7508453SAnurag.Maskey@Sun.COM dladm_destroy_conf(handle, conf);
7515895Syz147064 return (status);
7525084Sjohnlev }
7538275SEric Cheng
7548275SEric Cheng typedef struct dladm_vnic_up_arg_s {
7558275SEric Cheng uint32_t flags;
7568275SEric Cheng dladm_status_t status;
7578275SEric Cheng } dladm_vnic_up_arg_t;
7588275SEric Cheng
7598275SEric Cheng static int
i_dladm_vnic_up(dladm_handle_t handle,datalink_id_t linkid,void * arg)7608453SAnurag.Maskey@Sun.COM i_dladm_vnic_up(dladm_handle_t handle, datalink_id_t linkid, void *arg)
7618275SEric Cheng {
7628275SEric Cheng dladm_status_t *statusp = &(((dladm_vnic_up_arg_t *)arg)->status);
7638275SEric Cheng dladm_vnic_attr_t attr;
7648275SEric Cheng dladm_status_t status;
7658275SEric Cheng dladm_arg_list_t *proplist;
7668275SEric Cheng
7678275SEric Cheng bzero(&attr, sizeof (attr));
7688275SEric Cheng
7698453SAnurag.Maskey@Sun.COM status = dladm_vnic_info(handle, linkid, &attr, DLADM_OPT_PERSIST);
7708275SEric Cheng if (status != DLADM_STATUS_OK)
7718275SEric Cheng goto done;
7728275SEric Cheng
7738275SEric Cheng /* Get all properties for this vnic */
7748453SAnurag.Maskey@Sun.COM status = dladm_link_get_proplist(handle, linkid, &proplist);
7758275SEric Cheng if (status != DLADM_STATUS_OK)
7768275SEric Cheng goto done;
7778275SEric Cheng
7788275SEric Cheng if (proplist != NULL) {
7798453SAnurag.Maskey@Sun.COM status = dladm_link_proplist_extract(handle, proplist,
78011878SVenu.Iyer@Sun.COM &attr.va_resource_props, DLADM_OPT_BOOT);
7818275SEric Cheng }
7828275SEric Cheng
7838453SAnurag.Maskey@Sun.COM status = i_dladm_vnic_create_sys(handle, &attr);
78410491SRishi.Srivatsavai@Sun.COM if (status == DLADM_STATUS_OK) {
78510491SRishi.Srivatsavai@Sun.COM status = dladm_up_datalink_id(handle, linkid);
78610491SRishi.Srivatsavai@Sun.COM if (status != DLADM_STATUS_OK)
78710491SRishi.Srivatsavai@Sun.COM (void) i_dladm_vnic_delete_sys(handle, linkid);
78810491SRishi.Srivatsavai@Sun.COM }
7898275SEric Cheng
7908275SEric Cheng done:
7918275SEric Cheng *statusp = status;
7928275SEric Cheng return (DLADM_WALK_CONTINUE);
7938275SEric Cheng }
7948275SEric Cheng
7958275SEric Cheng dladm_status_t
dladm_vnic_up(dladm_handle_t handle,datalink_id_t linkid,uint32_t flags)7968453SAnurag.Maskey@Sun.COM dladm_vnic_up(dladm_handle_t handle, datalink_id_t linkid, uint32_t flags)
7978275SEric Cheng {
7988275SEric Cheng dladm_vnic_up_arg_t vnic_arg;
7998275SEric Cheng datalink_class_t class;
8008275SEric Cheng
8018275SEric Cheng class = ((flags & DLADM_OPT_VLAN) != 0) ? DATALINK_CLASS_VLAN :
8028275SEric Cheng (DATALINK_CLASS_VNIC | DATALINK_CLASS_ETHERSTUB);
8038275SEric Cheng
8048275SEric Cheng if (linkid == DATALINK_ALL_LINKID) {
8058453SAnurag.Maskey@Sun.COM (void) dladm_walk_datalink_id(i_dladm_vnic_up, handle,
8068453SAnurag.Maskey@Sun.COM &vnic_arg, class, DATALINK_ANY_MEDIATYPE,
8078453SAnurag.Maskey@Sun.COM DLADM_OPT_PERSIST);
8088275SEric Cheng return (DLADM_STATUS_OK);
8098275SEric Cheng } else {
8108453SAnurag.Maskey@Sun.COM (void) i_dladm_vnic_up(handle, linkid, &vnic_arg);
8118275SEric Cheng return (vnic_arg.status);
8128275SEric Cheng }
8138275SEric Cheng }
814