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 /* 228927SGirish.Moodalbail@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 235084Sjohnlev * Use is subject to license terms. 245084Sjohnlev */ 255084Sjohnlev 265084Sjohnlev #include <sys/types.h> 27*10616SSebastien.Roy@Sun.COM #include <sys/cred.h> 285084Sjohnlev #include <sys/sysmacros.h> 295084Sjohnlev #include <sys/conf.h> 305084Sjohnlev #include <sys/cmn_err.h> 315084Sjohnlev #include <sys/list.h> 325084Sjohnlev #include <sys/ksynch.h> 335084Sjohnlev #include <sys/kmem.h> 345084Sjohnlev #include <sys/stream.h> 355084Sjohnlev #include <sys/modctl.h> 365084Sjohnlev #include <sys/ddi.h> 375084Sjohnlev #include <sys/sunddi.h> 385084Sjohnlev #include <sys/atomic.h> 395084Sjohnlev #include <sys/stat.h> 405084Sjohnlev #include <sys/modhash.h> 415084Sjohnlev #include <sys/strsubr.h> 425084Sjohnlev #include <sys/strsun.h> 435084Sjohnlev #include <sys/dlpi.h> 445084Sjohnlev #include <sys/mac.h> 458275SEric Cheng #include <sys/mac_provider.h> 468275SEric Cheng #include <sys/mac_client.h> 478275SEric Cheng #include <sys/mac_client_priv.h> 485084Sjohnlev #include <sys/mac_ether.h> 495895Syz147064 #include <sys/dls.h> 505084Sjohnlev #include <sys/pattr.h> 518275SEric Cheng #include <sys/time.h> 528275SEric Cheng #include <sys/vlan.h> 535084Sjohnlev #include <sys/vnic.h> 545084Sjohnlev #include <sys/vnic_impl.h> 558275SEric Cheng #include <sys/mac_flow_impl.h> 565084Sjohnlev #include <inet/ip_impl.h> 575084Sjohnlev 588275SEric Cheng /* 598275SEric Cheng * Note that for best performance, the VNIC is a passthrough design. 608275SEric Cheng * For each VNIC corresponds a MAC client of the underlying MAC (lower MAC). 618275SEric Cheng * This MAC client is opened by the VNIC driver at VNIC creation, 628275SEric Cheng * and closed when the VNIC is deleted. 638275SEric Cheng * When a MAC client of the VNIC itself opens a VNIC, the MAC layer 648275SEric Cheng * (upper MAC) detects that the MAC being opened is a VNIC. Instead 658275SEric Cheng * of allocating a new MAC client, it asks the VNIC driver to return 668275SEric Cheng * the lower MAC client handle associated with the VNIC, and that handle 678275SEric Cheng * is returned to the upper MAC client directly. This allows access 688275SEric Cheng * by upper MAC clients of the VNIC to have direct access to the lower 698275SEric Cheng * MAC client for the control path and data path. 708275SEric Cheng * 718275SEric Cheng * Due to this passthrough, some of the entry points exported by the 728275SEric Cheng * VNIC driver are never directly invoked. These entry points include 738275SEric Cheng * vnic_m_start, vnic_m_stop, vnic_m_promisc, vnic_m_multicst, etc. 748275SEric Cheng */ 758275SEric Cheng 765084Sjohnlev static int vnic_m_start(void *); 775084Sjohnlev static void vnic_m_stop(void *); 785084Sjohnlev static int vnic_m_promisc(void *, boolean_t); 795084Sjohnlev static int vnic_m_multicst(void *, boolean_t, const uint8_t *); 805084Sjohnlev static int vnic_m_unicst(void *, const uint8_t *); 815084Sjohnlev static int vnic_m_stat(void *, uint_t, uint64_t *); 828275SEric Cheng static void vnic_m_ioctl(void *, queue_t *, mblk_t *); 838927SGirish.Moodalbail@Sun.COM static int vnic_m_setprop(void *, const char *, mac_prop_id_t, uint_t, 848927SGirish.Moodalbail@Sun.COM const void *); 858927SGirish.Moodalbail@Sun.COM static int vnic_m_getprop(void *, const char *, mac_prop_id_t, uint_t, 868927SGirish.Moodalbail@Sun.COM uint_t, void *, uint_t *); 875084Sjohnlev static mblk_t *vnic_m_tx(void *, mblk_t *); 885084Sjohnlev static boolean_t vnic_m_capab_get(void *, mac_capab_t, void *); 895084Sjohnlev static void vnic_notify_cb(void *, mac_notify_type_t); 905084Sjohnlev 915084Sjohnlev static kmem_cache_t *vnic_cache; 925084Sjohnlev static krwlock_t vnic_lock; 935084Sjohnlev static uint_t vnic_count; 945084Sjohnlev 959514SGirish.Moodalbail@Sun.COM #define ANCHOR_VNIC_MIN_MTU 576 969514SGirish.Moodalbail@Sun.COM #define ANCHOR_VNIC_MAX_MTU 9000 979514SGirish.Moodalbail@Sun.COM 985084Sjohnlev /* hash of VNICs (vnic_t's), keyed by VNIC id */ 995084Sjohnlev static mod_hash_t *vnic_hash; 1005084Sjohnlev #define VNIC_HASHSZ 64 1015084Sjohnlev #define VNIC_HASH_KEY(vnic_id) ((mod_hash_key_t)(uintptr_t)vnic_id) 1025084Sjohnlev 1038927SGirish.Moodalbail@Sun.COM #define VNIC_M_CALLBACK_FLAGS \ 1048927SGirish.Moodalbail@Sun.COM (MC_IOCTL | MC_GETCAPAB | MC_SETPROP | MC_GETPROP) 1055084Sjohnlev 1065084Sjohnlev static mac_callbacks_t vnic_m_callbacks = { 1075084Sjohnlev VNIC_M_CALLBACK_FLAGS, 1085084Sjohnlev vnic_m_stat, 1095084Sjohnlev vnic_m_start, 1105084Sjohnlev vnic_m_stop, 1115084Sjohnlev vnic_m_promisc, 1125084Sjohnlev vnic_m_multicst, 1135084Sjohnlev vnic_m_unicst, 1145084Sjohnlev vnic_m_tx, 1158275SEric Cheng vnic_m_ioctl, 1168927SGirish.Moodalbail@Sun.COM vnic_m_capab_get, 1178927SGirish.Moodalbail@Sun.COM NULL, 1188927SGirish.Moodalbail@Sun.COM NULL, 1198927SGirish.Moodalbail@Sun.COM vnic_m_setprop, 1208927SGirish.Moodalbail@Sun.COM vnic_m_getprop 1215084Sjohnlev }; 1225084Sjohnlev 1235084Sjohnlev void 1245084Sjohnlev vnic_dev_init(void) 1255084Sjohnlev { 1265084Sjohnlev vnic_cache = kmem_cache_create("vnic_cache", 1275084Sjohnlev sizeof (vnic_t), 0, NULL, NULL, NULL, NULL, NULL, 0); 1285084Sjohnlev 1295084Sjohnlev vnic_hash = mod_hash_create_idhash("vnic_hash", 1305084Sjohnlev VNIC_HASHSZ, mod_hash_null_valdtor); 1315084Sjohnlev 1325084Sjohnlev rw_init(&vnic_lock, NULL, RW_DEFAULT, NULL); 1335084Sjohnlev 1345084Sjohnlev vnic_count = 0; 1355084Sjohnlev } 1365084Sjohnlev 1375084Sjohnlev void 1385084Sjohnlev vnic_dev_fini(void) 1395084Sjohnlev { 1405084Sjohnlev ASSERT(vnic_count == 0); 1415084Sjohnlev 1425084Sjohnlev rw_destroy(&vnic_lock); 1435084Sjohnlev mod_hash_destroy_idhash(vnic_hash); 1445084Sjohnlev kmem_cache_destroy(vnic_cache); 1455084Sjohnlev } 1465084Sjohnlev 1475084Sjohnlev uint_t 1485084Sjohnlev vnic_dev_count(void) 1495084Sjohnlev { 1505084Sjohnlev return (vnic_count); 1515084Sjohnlev } 1525084Sjohnlev 1538275SEric Cheng static vnic_ioc_diag_t 1548275SEric Cheng vnic_mac2vnic_diag(mac_diag_t diag) 1555084Sjohnlev { 1568275SEric Cheng switch (diag) { 1578275SEric Cheng case MAC_DIAG_MACADDR_NIC: 1588275SEric Cheng return (VNIC_IOC_DIAG_MACADDR_NIC); 1598275SEric Cheng case MAC_DIAG_MACADDR_INUSE: 1608275SEric Cheng return (VNIC_IOC_DIAG_MACADDR_INUSE); 1618275SEric Cheng case MAC_DIAG_MACADDR_INVALID: 1628275SEric Cheng return (VNIC_IOC_DIAG_MACADDR_INVALID); 1638275SEric Cheng case MAC_DIAG_MACADDRLEN_INVALID: 1648275SEric Cheng return (VNIC_IOC_DIAG_MACADDRLEN_INVALID); 1658275SEric Cheng case MAC_DIAG_MACFACTORYSLOTINVALID: 1668275SEric Cheng return (VNIC_IOC_DIAG_MACFACTORYSLOTINVALID); 1678275SEric Cheng case MAC_DIAG_MACFACTORYSLOTUSED: 1688275SEric Cheng return (VNIC_IOC_DIAG_MACFACTORYSLOTUSED); 1698275SEric Cheng case MAC_DIAG_MACFACTORYSLOTALLUSED: 1708275SEric Cheng return (VNIC_IOC_DIAG_MACFACTORYSLOTALLUSED); 1718275SEric Cheng case MAC_DIAG_MACFACTORYNOTSUP: 1728275SEric Cheng return (VNIC_IOC_DIAG_MACFACTORYNOTSUP); 1738275SEric Cheng case MAC_DIAG_MACPREFIX_INVALID: 1748275SEric Cheng return (VNIC_IOC_DIAG_MACPREFIX_INVALID); 1758275SEric Cheng case MAC_DIAG_MACPREFIXLEN_INVALID: 1768275SEric Cheng return (VNIC_IOC_DIAG_MACPREFIXLEN_INVALID); 1778275SEric Cheng case MAC_DIAG_MACNO_HWRINGS: 1788275SEric Cheng return (VNIC_IOC_DIAG_NO_HWRINGS); 1798275SEric Cheng default: 1808275SEric Cheng return (VNIC_IOC_DIAG_NONE); 1815084Sjohnlev } 1825084Sjohnlev } 1835084Sjohnlev 1845084Sjohnlev static int 1858275SEric Cheng vnic_unicast_add(vnic_t *vnic, vnic_mac_addr_type_t vnic_addr_type, 1868275SEric Cheng int *addr_slot, uint_t prefix_len, int *addr_len_ptr_arg, 1878275SEric Cheng uint8_t *mac_addr_arg, uint16_t flags, vnic_ioc_diag_t *diag, 1888275SEric Cheng uint16_t vid) 1895084Sjohnlev { 1908275SEric Cheng mac_diag_t mac_diag; 1918275SEric Cheng uint16_t mac_flags = 0; 1928275SEric Cheng int err; 1938275SEric Cheng uint_t addr_len; 1945084Sjohnlev 1958275SEric Cheng if (flags & VNIC_IOC_CREATE_NODUPCHECK) 1968275SEric Cheng mac_flags |= MAC_UNICAST_NODUPCHECK; 1975084Sjohnlev 1988275SEric Cheng switch (vnic_addr_type) { 1998275SEric Cheng case VNIC_MAC_ADDR_TYPE_FIXED: 2008275SEric Cheng /* 2018275SEric Cheng * The MAC address value to assign to the VNIC 2028275SEric Cheng * is already provided in mac_addr_arg. addr_len_ptr_arg 2038275SEric Cheng * already contains the MAC address length. 2048275SEric Cheng */ 2058275SEric Cheng break; 2065084Sjohnlev 2078275SEric Cheng case VNIC_MAC_ADDR_TYPE_RANDOM: 2088275SEric Cheng /* 2098275SEric Cheng * Random MAC address. There are two sub-cases: 2108275SEric Cheng * 2118275SEric Cheng * 1 - If mac_len == 0, a new MAC address is generated. 2128275SEric Cheng * The length of the MAC address to generated depends 2138275SEric Cheng * on the type of MAC used. The prefix to use for the MAC 2148275SEric Cheng * address is stored in the most significant bytes 2158275SEric Cheng * of the mac_addr argument, and its length is specified 2168275SEric Cheng * by the mac_prefix_len argument. This prefix can 2178275SEric Cheng * correspond to a IEEE OUI in the case of Ethernet, 2188275SEric Cheng * for example. 2198275SEric Cheng * 2208275SEric Cheng * 2 - If mac_len > 0, the address was already picked 2218275SEric Cheng * randomly, and is now passed back during VNIC 2228275SEric Cheng * re-creation. The mac_addr argument contains the MAC 2238275SEric Cheng * address that was generated. We distinguish this 2248275SEric Cheng * case from the fixed MAC address case, since we 2258275SEric Cheng * want the user consumers to know, when they query 2268275SEric Cheng * the list of VNICs, that a VNIC was assigned a 2278275SEric Cheng * random MAC address vs assigned a fixed address 2288275SEric Cheng * specified by the user. 2298275SEric Cheng */ 2305084Sjohnlev 2318275SEric Cheng /* 2328275SEric Cheng * If it's a pre-generated address, we're done. mac_addr_arg 2338275SEric Cheng * and addr_len_ptr_arg already contain the MAC address 2348275SEric Cheng * value and length. 2358275SEric Cheng */ 2368275SEric Cheng if (*addr_len_ptr_arg > 0) 2378275SEric Cheng break; 2385084Sjohnlev 2398275SEric Cheng /* generate a new random MAC address */ 2408275SEric Cheng if ((err = mac_addr_random(vnic->vn_mch, 2418275SEric Cheng prefix_len, mac_addr_arg, &mac_diag)) != 0) { 2428275SEric Cheng *diag = vnic_mac2vnic_diag(mac_diag); 2438275SEric Cheng return (err); 2448275SEric Cheng } 2458275SEric Cheng *addr_len_ptr_arg = mac_addr_len(vnic->vn_lower_mh); 2468275SEric Cheng break; 2478275SEric Cheng 2488275SEric Cheng case VNIC_MAC_ADDR_TYPE_FACTORY: 2498275SEric Cheng err = mac_addr_factory_reserve(vnic->vn_mch, addr_slot); 2508275SEric Cheng if (err != 0) { 2518275SEric Cheng if (err == EINVAL) 2528275SEric Cheng *diag = VNIC_IOC_DIAG_MACFACTORYSLOTINVALID; 2538275SEric Cheng if (err == EBUSY) 2548275SEric Cheng *diag = VNIC_IOC_DIAG_MACFACTORYSLOTUSED; 2558275SEric Cheng if (err == ENOSPC) 2568275SEric Cheng *diag = VNIC_IOC_DIAG_MACFACTORYSLOTALLUSED; 2578275SEric Cheng return (err); 2585084Sjohnlev } 2595084Sjohnlev 2608275SEric Cheng mac_addr_factory_value(vnic->vn_lower_mh, *addr_slot, 2618275SEric Cheng mac_addr_arg, &addr_len, NULL, NULL); 2628275SEric Cheng *addr_len_ptr_arg = addr_len; 2638275SEric Cheng break; 2645084Sjohnlev 2658275SEric Cheng case VNIC_MAC_ADDR_TYPE_AUTO: 2668275SEric Cheng /* first try to allocate a factory MAC address */ 2678275SEric Cheng err = mac_addr_factory_reserve(vnic->vn_mch, addr_slot); 2688275SEric Cheng if (err == 0) { 2698275SEric Cheng mac_addr_factory_value(vnic->vn_lower_mh, *addr_slot, 2708275SEric Cheng mac_addr_arg, &addr_len, NULL, NULL); 2718275SEric Cheng vnic_addr_type = VNIC_MAC_ADDR_TYPE_FACTORY; 2728275SEric Cheng *addr_len_ptr_arg = addr_len; 2738275SEric Cheng break; 2745084Sjohnlev } 2755084Sjohnlev 2765084Sjohnlev /* 2778275SEric Cheng * Allocating a factory MAC address failed, generate a 2788275SEric Cheng * random MAC address instead. 2795084Sjohnlev */ 2808275SEric Cheng if ((err = mac_addr_random(vnic->vn_mch, 2818275SEric Cheng prefix_len, mac_addr_arg, &mac_diag)) != 0) { 2828275SEric Cheng *diag = vnic_mac2vnic_diag(mac_diag); 2838275SEric Cheng return (err); 2845084Sjohnlev } 2858275SEric Cheng *addr_len_ptr_arg = mac_addr_len(vnic->vn_lower_mh); 2868275SEric Cheng vnic_addr_type = VNIC_MAC_ADDR_TYPE_RANDOM; 2878275SEric Cheng break; 2888275SEric Cheng case VNIC_MAC_ADDR_TYPE_PRIMARY: 2898275SEric Cheng /* 2908275SEric Cheng * We get the address here since we copy it in the 2918275SEric Cheng * vnic's vn_addr. 2928275SEric Cheng */ 2938275SEric Cheng mac_unicast_primary_get(vnic->vn_lower_mh, mac_addr_arg); 2948275SEric Cheng *addr_len_ptr_arg = mac_addr_len(vnic->vn_lower_mh); 2958275SEric Cheng mac_flags |= MAC_UNICAST_VNIC_PRIMARY; 2968275SEric Cheng break; 2975084Sjohnlev } 2985084Sjohnlev 2998275SEric Cheng vnic->vn_addr_type = vnic_addr_type; 3005084Sjohnlev 3018275SEric Cheng err = mac_unicast_add(vnic->vn_mch, mac_addr_arg, mac_flags, 3028275SEric Cheng &vnic->vn_muh, vid, &mac_diag); 3038275SEric Cheng if (err != 0) { 3048275SEric Cheng if (vnic_addr_type == VNIC_MAC_ADDR_TYPE_FACTORY) { 3058275SEric Cheng /* release factory MAC address */ 3068275SEric Cheng mac_addr_factory_release(vnic->vn_mch, *addr_slot); 3075084Sjohnlev } 3088275SEric Cheng *diag = vnic_mac2vnic_diag(mac_diag); 3095084Sjohnlev } 3105084Sjohnlev 3115084Sjohnlev return (err); 3125084Sjohnlev } 3135084Sjohnlev 3145084Sjohnlev /* 3155084Sjohnlev * Create a new VNIC upon request from administrator. 3165084Sjohnlev * Returns 0 on success, an errno on failure. 3175084Sjohnlev */ 3188275SEric Cheng /* ARGSUSED */ 3195084Sjohnlev int 3208275SEric Cheng vnic_dev_create(datalink_id_t vnic_id, datalink_id_t linkid, 3218275SEric Cheng vnic_mac_addr_type_t *vnic_addr_type, int *mac_len, uchar_t *mac_addr, 3228275SEric Cheng int *mac_slot, uint_t mac_prefix_len, uint16_t vid, 323*10616SSebastien.Roy@Sun.COM mac_resource_props_t *mrp, uint32_t flags, vnic_ioc_diag_t *diag, 324*10616SSebastien.Roy@Sun.COM cred_t *credp) 3255084Sjohnlev { 3268275SEric Cheng vnic_t *vnic; 3275084Sjohnlev mac_register_t *mac; 3285084Sjohnlev int err; 3298275SEric Cheng boolean_t is_anchor = ((flags & VNIC_IOC_CREATE_ANCHOR) != 0); 3308275SEric Cheng char vnic_name[MAXNAMELEN]; 3318275SEric Cheng const mac_info_t *minfop; 3328275SEric Cheng uint32_t req_hwgrp_flag = ((flags & VNIC_IOC_CREATE_REQ_HWRINGS) != 0) ? 3338275SEric Cheng MAC_OPEN_FLAGS_REQ_HWRINGS : 0; 3345084Sjohnlev 3358275SEric Cheng *diag = VNIC_IOC_DIAG_NONE; 3365084Sjohnlev 3375084Sjohnlev rw_enter(&vnic_lock, RW_WRITER); 3385084Sjohnlev 3395084Sjohnlev /* does a VNIC with the same id already exist? */ 3405084Sjohnlev err = mod_hash_find(vnic_hash, VNIC_HASH_KEY(vnic_id), 3415084Sjohnlev (mod_hash_val_t *)&vnic); 3425084Sjohnlev if (err == 0) { 3435084Sjohnlev rw_exit(&vnic_lock); 3445084Sjohnlev return (EEXIST); 3455084Sjohnlev } 3465084Sjohnlev 3475084Sjohnlev vnic = kmem_cache_alloc(vnic_cache, KM_NOSLEEP); 3485084Sjohnlev if (vnic == NULL) { 3495084Sjohnlev rw_exit(&vnic_lock); 3505084Sjohnlev return (ENOMEM); 3515084Sjohnlev } 3525084Sjohnlev 3538275SEric Cheng bzero(vnic, sizeof (*vnic)); 3545084Sjohnlev 3555084Sjohnlev vnic->vn_id = vnic_id; 3568275SEric Cheng vnic->vn_link_id = linkid; 3578275SEric Cheng 3588275SEric Cheng if (!is_anchor) { 3598275SEric Cheng if (linkid == DATALINK_INVALID_LINKID) { 3608275SEric Cheng err = EINVAL; 3618275SEric Cheng goto bail; 3628275SEric Cheng } 3638275SEric Cheng 3648275SEric Cheng /* 3658275SEric Cheng * Open the lower MAC and assign its initial bandwidth and 3668275SEric Cheng * MAC address. We do this here during VNIC creation and 3678275SEric Cheng * do not wait until the upper MAC client open so that we 3688275SEric Cheng * can validate the VNIC creation parameters (bandwidth, 3698275SEric Cheng * MAC address, etc) and reserve a factory MAC address if 3708275SEric Cheng * one was requested. 3718275SEric Cheng */ 3728275SEric Cheng err = mac_open_by_linkid(linkid, &vnic->vn_lower_mh); 3738275SEric Cheng if (err != 0) 3748275SEric Cheng goto bail; 3758275SEric Cheng 3768275SEric Cheng /* 3778275SEric Cheng * VNIC(vlan) over VNICs(vlans) is not supported. 3788275SEric Cheng */ 3798275SEric Cheng if (mac_is_vnic(vnic->vn_lower_mh)) { 3808275SEric Cheng err = EINVAL; 3818275SEric Cheng goto bail; 3828275SEric Cheng } 3838275SEric Cheng 3848275SEric Cheng /* only ethernet support for now */ 3858275SEric Cheng minfop = mac_info(vnic->vn_lower_mh); 3868275SEric Cheng if (minfop->mi_nativemedia != DL_ETHER) { 3878275SEric Cheng err = ENOTSUP; 3888275SEric Cheng goto bail; 3898275SEric Cheng } 3905084Sjohnlev 3918275SEric Cheng (void) dls_mgmt_get_linkinfo(vnic_id, vnic_name, NULL, NULL, 3928275SEric Cheng NULL); 3938275SEric Cheng err = mac_client_open(vnic->vn_lower_mh, &vnic->vn_mch, 3948275SEric Cheng vnic_name, MAC_OPEN_FLAGS_IS_VNIC | req_hwgrp_flag); 3958275SEric Cheng if (err != 0) 3968275SEric Cheng goto bail; 3978275SEric Cheng 3988275SEric Cheng if (mrp != NULL) { 3998275SEric Cheng err = mac_client_set_resources(vnic->vn_mch, mrp); 4008275SEric Cheng if (err != 0) 4018275SEric Cheng goto bail; 4028275SEric Cheng } 4038275SEric Cheng /* assign a MAC address to the VNIC */ 4045084Sjohnlev 4058275SEric Cheng err = vnic_unicast_add(vnic, *vnic_addr_type, mac_slot, 4068275SEric Cheng mac_prefix_len, mac_len, mac_addr, flags, diag, vid); 4078275SEric Cheng if (err != 0) { 4088275SEric Cheng vnic->vn_muh = NULL; 4098275SEric Cheng if (diag != NULL && req_hwgrp_flag != 0) 4108275SEric Cheng *diag = VNIC_IOC_DIAG_NO_HWRINGS; 4118275SEric Cheng goto bail; 4128275SEric Cheng } 4138275SEric Cheng 4148275SEric Cheng /* register to receive notification from underlying MAC */ 4158275SEric Cheng vnic->vn_mnh = mac_notify_add(vnic->vn_lower_mh, vnic_notify_cb, 4168275SEric Cheng vnic); 4178275SEric Cheng 4188275SEric Cheng *vnic_addr_type = vnic->vn_addr_type; 4198275SEric Cheng vnic->vn_addr_len = *mac_len; 4208275SEric Cheng vnic->vn_vid = vid; 4218275SEric Cheng 4228275SEric Cheng bcopy(mac_addr, vnic->vn_addr, vnic->vn_addr_len); 4238275SEric Cheng 4248275SEric Cheng if (vnic->vn_addr_type == VNIC_MAC_ADDR_TYPE_FACTORY) 4258275SEric Cheng vnic->vn_slot_id = *mac_slot; 4268275SEric Cheng 4278275SEric Cheng /* set the initial VNIC capabilities */ 4288275SEric Cheng if (!mac_capab_get(vnic->vn_lower_mh, MAC_CAPAB_HCKSUM, 4298275SEric Cheng &vnic->vn_hcksum_txflags)) 4308275SEric Cheng vnic->vn_hcksum_txflags = 0; 4318275SEric Cheng } 4325084Sjohnlev 4335084Sjohnlev /* register with the MAC module */ 4345084Sjohnlev if ((mac = mac_alloc(MAC_VERSION)) == NULL) 4355084Sjohnlev goto bail; 4365084Sjohnlev 4375084Sjohnlev mac->m_type_ident = MAC_PLUGIN_IDENT_ETHER; 4385084Sjohnlev mac->m_driver = vnic; 4395084Sjohnlev mac->m_dip = vnic_get_dip(); 4405895Syz147064 mac->m_instance = (uint_t)-1; 4415084Sjohnlev mac->m_src_addr = vnic->vn_addr; 4425084Sjohnlev mac->m_callbacks = &vnic_m_callbacks; 4435084Sjohnlev 4448275SEric Cheng if (!is_anchor) { 4458275SEric Cheng /* 4468275SEric Cheng * If this is a VNIC based VLAN, then we check for the 4478275SEric Cheng * margin unless it has been created with the force 4488275SEric Cheng * flag. If we are configuring a VLAN over an etherstub, 4498275SEric Cheng * we don't check the margin even if force is not set. 4508275SEric Cheng */ 4518275SEric Cheng if (vid == 0 || (flags & VNIC_IOC_CREATE_FORCE) != 0) { 4528275SEric Cheng if (vid != VLAN_ID_NONE) 4538275SEric Cheng vnic->vn_force = B_TRUE; 4548275SEric Cheng /* 4558275SEric Cheng * As the current margin size of the underlying mac is 4568275SEric Cheng * used to determine the margin size of the VNIC 4578275SEric Cheng * itself, request the underlying mac not to change 4588275SEric Cheng * to a smaller margin size. 4598275SEric Cheng */ 4608275SEric Cheng err = mac_margin_add(vnic->vn_lower_mh, 4618275SEric Cheng &vnic->vn_margin, B_TRUE); 4628275SEric Cheng ASSERT(err == 0); 4638275SEric Cheng } else { 4648275SEric Cheng vnic->vn_margin = VLAN_TAGSZ; 4658275SEric Cheng err = mac_margin_add(vnic->vn_lower_mh, 4668275SEric Cheng &vnic->vn_margin, B_FALSE); 4678275SEric Cheng if (err != 0) { 4688275SEric Cheng mac_free(mac); 4698275SEric Cheng if (diag != NULL) 4708275SEric Cheng *diag = VNIC_IOC_DIAG_MACMARGIN_INVALID; 4718275SEric Cheng goto bail; 4728275SEric Cheng } 4738275SEric Cheng } 4745084Sjohnlev 4758275SEric Cheng mac_sdu_get(vnic->vn_lower_mh, &mac->m_min_sdu, 4768275SEric Cheng &mac->m_max_sdu); 4778275SEric Cheng } else { 4788275SEric Cheng vnic->vn_margin = VLAN_TAGSZ; 4799514SGirish.Moodalbail@Sun.COM mac->m_min_sdu = ANCHOR_VNIC_MIN_MTU; 4809514SGirish.Moodalbail@Sun.COM mac->m_max_sdu = ANCHOR_VNIC_MAX_MTU; 4818275SEric Cheng } 4828275SEric Cheng 4835895Syz147064 mac->m_margin = vnic->vn_margin; 4848275SEric Cheng 4855084Sjohnlev err = mac_register(mac, &vnic->vn_mh); 4865084Sjohnlev mac_free(mac); 4875895Syz147064 if (err != 0) { 4888275SEric Cheng VERIFY(is_anchor || mac_margin_remove(vnic->vn_lower_mh, 4895895Syz147064 vnic->vn_margin) == 0); 4905084Sjohnlev goto bail; 4915895Syz147064 } 4925895Syz147064 4938275SEric Cheng /* Set the VNIC's MAC in the client */ 4948275SEric Cheng if (!is_anchor) 4958275SEric Cheng mac_set_upper_mac(vnic->vn_mch, vnic->vn_mh); 4968275SEric Cheng 497*10616SSebastien.Roy@Sun.COM err = dls_devnet_create(vnic->vn_mh, vnic->vn_id, crgetzoneid(credp)); 498*10616SSebastien.Roy@Sun.COM if (err != 0) { 4998275SEric Cheng VERIFY(is_anchor || mac_margin_remove(vnic->vn_lower_mh, 5005895Syz147064 vnic->vn_margin) == 0); 5015895Syz147064 (void) mac_unregister(vnic->vn_mh); 5025895Syz147064 goto bail; 5035895Syz147064 } 5045084Sjohnlev 5055084Sjohnlev /* add new VNIC to hash table */ 5065084Sjohnlev err = mod_hash_insert(vnic_hash, VNIC_HASH_KEY(vnic_id), 5075084Sjohnlev (mod_hash_val_t)vnic); 5085084Sjohnlev ASSERT(err == 0); 5095084Sjohnlev vnic_count++; 5105084Sjohnlev 5119052SEric Cheng vnic->vn_enabled = B_TRUE; 5125084Sjohnlev rw_exit(&vnic_lock); 5135084Sjohnlev 5145084Sjohnlev return (0); 5155084Sjohnlev 5165084Sjohnlev bail: 5175084Sjohnlev rw_exit(&vnic_lock); 5188275SEric Cheng if (!is_anchor) { 5198275SEric Cheng if (vnic->vn_mnh != NULL) 5208275SEric Cheng (void) mac_notify_remove(vnic->vn_mnh, B_TRUE); 5218275SEric Cheng if (vnic->vn_muh != NULL) 5228275SEric Cheng (void) mac_unicast_remove(vnic->vn_mch, vnic->vn_muh); 5238275SEric Cheng if (vnic->vn_mch != NULL) 5248275SEric Cheng mac_client_close(vnic->vn_mch, MAC_CLOSE_FLAGS_IS_VNIC); 5258275SEric Cheng if (vnic->vn_lower_mh != NULL) 5268275SEric Cheng mac_close(vnic->vn_lower_mh); 5275084Sjohnlev } 5285084Sjohnlev 5298275SEric Cheng kmem_cache_free(vnic_cache, vnic); 5305084Sjohnlev return (err); 5315084Sjohnlev } 5325084Sjohnlev 5335084Sjohnlev /* 5345084Sjohnlev * Modify the properties of an existing VNIC. 5355084Sjohnlev */ 5365084Sjohnlev /* ARGSUSED */ 5375084Sjohnlev int 5385895Syz147064 vnic_dev_modify(datalink_id_t vnic_id, uint_t modify_mask, 5398275SEric Cheng vnic_mac_addr_type_t mac_addr_type, uint_t mac_len, uchar_t *mac_addr, 5408275SEric Cheng uint_t mac_slot, mac_resource_props_t *mrp) 5415084Sjohnlev { 5425084Sjohnlev vnic_t *vnic = NULL; 5435084Sjohnlev 5445084Sjohnlev rw_enter(&vnic_lock, RW_WRITER); 5455084Sjohnlev 5465084Sjohnlev if (mod_hash_find(vnic_hash, VNIC_HASH_KEY(vnic_id), 5475084Sjohnlev (mod_hash_val_t *)&vnic) != 0) { 5485084Sjohnlev rw_exit(&vnic_lock); 5495084Sjohnlev return (ENOENT); 5505084Sjohnlev } 5515084Sjohnlev 5525084Sjohnlev rw_exit(&vnic_lock); 5535084Sjohnlev 5548275SEric Cheng return (0); 5555084Sjohnlev } 5565084Sjohnlev 5578275SEric Cheng /* ARGSUSED */ 5585084Sjohnlev int 559*10616SSebastien.Roy@Sun.COM vnic_dev_delete(datalink_id_t vnic_id, uint32_t flags, cred_t *credp) 5605084Sjohnlev { 5615084Sjohnlev vnic_t *vnic = NULL; 5625084Sjohnlev mod_hash_val_t val; 5635895Syz147064 datalink_id_t tmpid; 5645084Sjohnlev int rc; 5655084Sjohnlev 5665084Sjohnlev rw_enter(&vnic_lock, RW_WRITER); 5675084Sjohnlev 5685084Sjohnlev if (mod_hash_find(vnic_hash, VNIC_HASH_KEY(vnic_id), 5695084Sjohnlev (mod_hash_val_t *)&vnic) != 0) { 5705084Sjohnlev rw_exit(&vnic_lock); 5715084Sjohnlev return (ENOENT); 5725084Sjohnlev } 5735084Sjohnlev 5748275SEric Cheng if ((rc = dls_devnet_destroy(vnic->vn_mh, &tmpid, B_TRUE)) != 0) { 5755895Syz147064 rw_exit(&vnic_lock); 5765895Syz147064 return (rc); 5775895Syz147064 } 5785895Syz147064 5795895Syz147064 ASSERT(vnic_id == tmpid); 5805895Syz147064 5815084Sjohnlev /* 5825084Sjohnlev * We cannot unregister the MAC yet. Unregistering would 5835084Sjohnlev * free up mac_impl_t which should not happen at this time. 5848275SEric Cheng * So disable mac_impl_t by calling mac_disable(). This will prevent 5858275SEric Cheng * any new claims on mac_impl_t. 5865084Sjohnlev */ 5878275SEric Cheng if ((rc = mac_disable(vnic->vn_mh)) != 0) { 588*10616SSebastien.Roy@Sun.COM (void) dls_devnet_create(vnic->vn_mh, vnic_id, 589*10616SSebastien.Roy@Sun.COM crgetzoneid(credp)); 5905084Sjohnlev rw_exit(&vnic_lock); 5918275SEric Cheng return (rc); 5925084Sjohnlev } 5935084Sjohnlev 5949052SEric Cheng vnic->vn_enabled = B_FALSE; 5955084Sjohnlev (void) mod_hash_remove(vnic_hash, VNIC_HASH_KEY(vnic_id), &val); 5965084Sjohnlev ASSERT(vnic == (vnic_t *)val); 5978275SEric Cheng vnic_count--; 5988275SEric Cheng rw_exit(&vnic_lock); 5995084Sjohnlev 6008275SEric Cheng /* 6018275SEric Cheng * XXX-nicolas shouldn't have a void cast here, if it's 6028275SEric Cheng * expected that the function will never fail, then we should 6038275SEric Cheng * have an ASSERT(). 6048275SEric Cheng */ 6058275SEric Cheng (void) mac_unregister(vnic->vn_mh); 6065084Sjohnlev 6078275SEric Cheng if (vnic->vn_lower_mh != NULL) { 6085084Sjohnlev /* 6098275SEric Cheng * Check if MAC address for the vnic was obtained from the 6108275SEric Cheng * factory MAC addresses. If yes, release it. 6115084Sjohnlev */ 6128275SEric Cheng if (vnic->vn_addr_type == VNIC_MAC_ADDR_TYPE_FACTORY) { 6138275SEric Cheng (void) mac_addr_factory_release(vnic->vn_mch, 6148275SEric Cheng vnic->vn_slot_id); 6158275SEric Cheng } 6168275SEric Cheng (void) mac_margin_remove(vnic->vn_lower_mh, vnic->vn_margin); 6178275SEric Cheng (void) mac_notify_remove(vnic->vn_mnh, B_TRUE); 6188275SEric Cheng (void) mac_unicast_remove(vnic->vn_mch, vnic->vn_muh); 6198275SEric Cheng mac_client_close(vnic->vn_mch, MAC_CLOSE_FLAGS_IS_VNIC); 6208275SEric Cheng mac_close(vnic->vn_lower_mh); 6215084Sjohnlev } 6225084Sjohnlev 6235084Sjohnlev kmem_cache_free(vnic_cache, vnic); 6245084Sjohnlev return (0); 6255084Sjohnlev } 6265084Sjohnlev 6278275SEric Cheng /* ARGSUSED */ 6288275SEric Cheng mblk_t * 6298275SEric Cheng vnic_m_tx(void *arg, mblk_t *mp_chain) 6305084Sjohnlev { 6318275SEric Cheng /* 6328275SEric Cheng * This function could be invoked for an anchor VNIC when sending 6338275SEric Cheng * broadcast and multicast packets, and unicast packets which did 6348275SEric Cheng * not match any local known destination. 6358275SEric Cheng */ 6368275SEric Cheng freemsgchain(mp_chain); 6378275SEric Cheng return (NULL); 6385084Sjohnlev } 6395084Sjohnlev 6408275SEric Cheng /*ARGSUSED*/ 6415084Sjohnlev static void 6428275SEric Cheng vnic_m_ioctl(void *arg, queue_t *q, mblk_t *mp) 6435084Sjohnlev { 6448275SEric Cheng miocnak(q, mp, 0, ENOTSUP); 6455084Sjohnlev } 6465084Sjohnlev 6475084Sjohnlev /* 6488275SEric Cheng * This entry point cannot be passed-through, since it is invoked 6498275SEric Cheng * for the per-VNIC kstats which must be exported independently 6508275SEric Cheng * of the existence of VNIC MAC clients. 6515084Sjohnlev */ 6525084Sjohnlev static int 6535084Sjohnlev vnic_m_stat(void *arg, uint_t stat, uint64_t *val) 6545084Sjohnlev { 6555084Sjohnlev vnic_t *vnic = arg; 6565084Sjohnlev int rval = 0; 6575084Sjohnlev 6588275SEric Cheng if (vnic->vn_lower_mh == NULL) { 6598275SEric Cheng /* 6608275SEric Cheng * It's an anchor VNIC, which does not have any 6618275SEric Cheng * statistics in itself. 6628275SEric Cheng */ 6638275SEric Cheng return (ENOTSUP); 6648275SEric Cheng } 6658275SEric Cheng 6668275SEric Cheng /* 6678275SEric Cheng * ENOTSUP must be reported for unsupported stats, the VNIC 6688275SEric Cheng * driver reports a subset of the stats that would 6698275SEric Cheng * be returned by a real piece of hardware. 6708275SEric Cheng */ 6715084Sjohnlev 6725084Sjohnlev switch (stat) { 6738275SEric Cheng case MAC_STAT_LINK_STATE: 6748275SEric Cheng case MAC_STAT_LINK_UP: 6758275SEric Cheng case MAC_STAT_PROMISC: 6765084Sjohnlev case MAC_STAT_IFSPEED: 6775084Sjohnlev case MAC_STAT_MULTIRCV: 6788275SEric Cheng case MAC_STAT_MULTIXMT: 6795084Sjohnlev case MAC_STAT_BRDCSTRCV: 6805084Sjohnlev case MAC_STAT_BRDCSTXMT: 6818275SEric Cheng case MAC_STAT_OPACKETS: 6828275SEric Cheng case MAC_STAT_OBYTES: 6835084Sjohnlev case MAC_STAT_IERRORS: 6845084Sjohnlev case MAC_STAT_OERRORS: 6855084Sjohnlev case MAC_STAT_RBYTES: 6865084Sjohnlev case MAC_STAT_IPACKETS: 6878275SEric Cheng *val = mac_client_stat_get(vnic->vn_mch, stat); 6885084Sjohnlev break; 6895084Sjohnlev default: 6905084Sjohnlev rval = ENOTSUP; 6915084Sjohnlev } 6925084Sjohnlev 6935084Sjohnlev return (rval); 6945084Sjohnlev } 6955084Sjohnlev 6965084Sjohnlev /* 6978275SEric Cheng * Invoked by the upper MAC to retrieve the lower MAC client handle 6988275SEric Cheng * corresponding to a VNIC. A pointer to this function is obtained 6998275SEric Cheng * by the upper MAC via capability query. 7008275SEric Cheng * 7018275SEric Cheng * XXX-nicolas Note: this currently causes all VNIC MAC clients to 7028275SEric Cheng * receive the same MAC client handle for the same VNIC. This is ok 7038275SEric Cheng * as long as we have only one VNIC MAC client which sends and 7048275SEric Cheng * receives data, but we don't currently enforce this at the MAC layer. 7058275SEric Cheng */ 7068275SEric Cheng static void * 7078275SEric Cheng vnic_mac_client_handle(void *vnic_arg) 7088275SEric Cheng { 7098275SEric Cheng vnic_t *vnic = vnic_arg; 7108275SEric Cheng 7118275SEric Cheng return (vnic->vn_mch); 7128275SEric Cheng } 7138275SEric Cheng 7148275SEric Cheng 7158275SEric Cheng /* 7165084Sjohnlev * Return information about the specified capability. 7175084Sjohnlev */ 7185084Sjohnlev /* ARGSUSED */ 7195084Sjohnlev static boolean_t 7205084Sjohnlev vnic_m_capab_get(void *arg, mac_capab_t cap, void *cap_data) 7215084Sjohnlev { 7225084Sjohnlev vnic_t *vnic = arg; 7235084Sjohnlev 7245084Sjohnlev switch (cap) { 7255084Sjohnlev case MAC_CAPAB_HCKSUM: { 7265084Sjohnlev uint32_t *hcksum_txflags = cap_data; 7275084Sjohnlev 7285084Sjohnlev *hcksum_txflags = vnic->vn_hcksum_txflags & 7295084Sjohnlev (HCKSUM_INET_FULL_V4 | HCKSUM_IPHDRCKSUM | 7305084Sjohnlev HCKSUM_INET_PARTIAL); 7315084Sjohnlev break; 7325084Sjohnlev } 7338275SEric Cheng case MAC_CAPAB_VNIC: { 7348275SEric Cheng mac_capab_vnic_t *vnic_capab = cap_data; 7358275SEric Cheng 7368275SEric Cheng if (vnic->vn_lower_mh == NULL) { 7378275SEric Cheng /* 7388275SEric Cheng * It's an anchor VNIC, we don't have an underlying 7398275SEric Cheng * NIC and MAC client handle. 7408275SEric Cheng */ 7418275SEric Cheng return (B_FALSE); 7428275SEric Cheng } 7438275SEric Cheng 7448275SEric Cheng if (vnic_capab != NULL) { 7458275SEric Cheng vnic_capab->mcv_arg = vnic; 7468275SEric Cheng vnic_capab->mcv_mac_client_handle = 7478275SEric Cheng vnic_mac_client_handle; 7488275SEric Cheng } 7498275SEric Cheng break; 7508275SEric Cheng } 7518275SEric Cheng case MAC_CAPAB_ANCHOR_VNIC: { 7528275SEric Cheng /* since it's an anchor VNIC we don't have lower mac handle */ 7538275SEric Cheng if (vnic->vn_lower_mh == NULL) { 7548275SEric Cheng ASSERT(vnic->vn_link_id == 0); 7558275SEric Cheng return (B_TRUE); 7568275SEric Cheng } 7578275SEric Cheng return (B_FALSE); 7588275SEric Cheng } 7598275SEric Cheng case MAC_CAPAB_NO_NATIVEVLAN: 7608275SEric Cheng case MAC_CAPAB_NO_ZCOPY: 7618275SEric Cheng return (B_TRUE); 7625084Sjohnlev default: 7635084Sjohnlev return (B_FALSE); 7645084Sjohnlev } 7655084Sjohnlev return (B_TRUE); 7665084Sjohnlev } 7675084Sjohnlev 7688275SEric Cheng /* ARGSUSED */ 7695084Sjohnlev static int 7705084Sjohnlev vnic_m_start(void *arg) 7715084Sjohnlev { 7725084Sjohnlev return (0); 7735084Sjohnlev } 7745084Sjohnlev 7758275SEric Cheng /* ARGSUSED */ 7765084Sjohnlev static void 7775084Sjohnlev vnic_m_stop(void *arg) 7785084Sjohnlev { 7795084Sjohnlev } 7805084Sjohnlev 7815084Sjohnlev /* ARGSUSED */ 7825084Sjohnlev static int 7835084Sjohnlev vnic_m_promisc(void *arg, boolean_t on) 7845084Sjohnlev { 7858275SEric Cheng return (0); 7865084Sjohnlev } 7875084Sjohnlev 7888275SEric Cheng /* ARGSUSED */ 7895084Sjohnlev static int 7905084Sjohnlev vnic_m_multicst(void *arg, boolean_t add, const uint8_t *addrp) 7915084Sjohnlev { 7928275SEric Cheng return (0); 7935084Sjohnlev } 7945084Sjohnlev 7955084Sjohnlev static int 7968275SEric Cheng vnic_m_unicst(void *arg, const uint8_t *macaddr) 7975084Sjohnlev { 7985084Sjohnlev vnic_t *vnic = arg; 7995084Sjohnlev 8008275SEric Cheng return (mac_vnic_unicast_set(vnic->vn_mch, macaddr)); 8015084Sjohnlev } 8025084Sjohnlev 8038927SGirish.Moodalbail@Sun.COM /* 8048927SGirish.Moodalbail@Sun.COM * Callback functions for set/get of properties 8058927SGirish.Moodalbail@Sun.COM */ 8068927SGirish.Moodalbail@Sun.COM /*ARGSUSED*/ 8078927SGirish.Moodalbail@Sun.COM static int 8088927SGirish.Moodalbail@Sun.COM vnic_m_setprop(void *m_driver, const char *pr_name, mac_prop_id_t pr_num, 8098927SGirish.Moodalbail@Sun.COM uint_t pr_valsize, const void *pr_val) 8108927SGirish.Moodalbail@Sun.COM { 8118927SGirish.Moodalbail@Sun.COM int err = ENOTSUP; 8128927SGirish.Moodalbail@Sun.COM vnic_t *vn = m_driver; 8138927SGirish.Moodalbail@Sun.COM 8148927SGirish.Moodalbail@Sun.COM /* allow setting MTU only on an etherstub */ 8158927SGirish.Moodalbail@Sun.COM if (vn->vn_link_id != DATALINK_INVALID_LINKID) 8168927SGirish.Moodalbail@Sun.COM return (err); 8178927SGirish.Moodalbail@Sun.COM 8188927SGirish.Moodalbail@Sun.COM switch (pr_num) { 8198927SGirish.Moodalbail@Sun.COM case MAC_PROP_MTU: { 8208927SGirish.Moodalbail@Sun.COM uint32_t mtu; 8218927SGirish.Moodalbail@Sun.COM 8228927SGirish.Moodalbail@Sun.COM if (pr_valsize < sizeof (mtu)) { 8238927SGirish.Moodalbail@Sun.COM err = EINVAL; 8248927SGirish.Moodalbail@Sun.COM break; 8258927SGirish.Moodalbail@Sun.COM } 8268927SGirish.Moodalbail@Sun.COM bcopy(pr_val, &mtu, sizeof (mtu)); 8279514SGirish.Moodalbail@Sun.COM if (mtu < ANCHOR_VNIC_MIN_MTU || mtu > ANCHOR_VNIC_MAX_MTU) { 8289514SGirish.Moodalbail@Sun.COM err = EINVAL; 8299514SGirish.Moodalbail@Sun.COM break; 8309514SGirish.Moodalbail@Sun.COM } 8318927SGirish.Moodalbail@Sun.COM err = mac_maxsdu_update(vn->vn_mh, mtu); 8328927SGirish.Moodalbail@Sun.COM break; 8338927SGirish.Moodalbail@Sun.COM } 8348927SGirish.Moodalbail@Sun.COM default: 8358927SGirish.Moodalbail@Sun.COM break; 8368927SGirish.Moodalbail@Sun.COM } 8378927SGirish.Moodalbail@Sun.COM return (err); 8388927SGirish.Moodalbail@Sun.COM } 8398927SGirish.Moodalbail@Sun.COM 8408927SGirish.Moodalbail@Sun.COM /*ARGSUSED*/ 8418927SGirish.Moodalbail@Sun.COM static int 8428927SGirish.Moodalbail@Sun.COM vnic_m_getprop(void *m_driver, const char *pr_name, mac_prop_id_t pr_num, 8438927SGirish.Moodalbail@Sun.COM uint_t pr_flags, uint_t pr_valsize, void *pr_val, uint_t *perm) 8448927SGirish.Moodalbail@Sun.COM { 8459514SGirish.Moodalbail@Sun.COM mac_propval_range_t range; 8469514SGirish.Moodalbail@Sun.COM vnic_t *vn = m_driver; 8479514SGirish.Moodalbail@Sun.COM int err = ENOTSUP; 8489514SGirish.Moodalbail@Sun.COM 8499514SGirish.Moodalbail@Sun.COM /* MTU setting allowed only on an etherstub */ 8509514SGirish.Moodalbail@Sun.COM if (vn->vn_link_id != DATALINK_INVALID_LINKID) 8519514SGirish.Moodalbail@Sun.COM return (err); 8529514SGirish.Moodalbail@Sun.COM 8539514SGirish.Moodalbail@Sun.COM switch (pr_num) { 8549514SGirish.Moodalbail@Sun.COM case MAC_PROP_MTU: 8559514SGirish.Moodalbail@Sun.COM if (!(pr_flags & MAC_PROP_POSSIBLE)) 8569514SGirish.Moodalbail@Sun.COM return (ENOTSUP); 8579514SGirish.Moodalbail@Sun.COM if (pr_valsize < sizeof (mac_propval_range_t)) 8589514SGirish.Moodalbail@Sun.COM return (EINVAL); 8599514SGirish.Moodalbail@Sun.COM range.mpr_count = 1; 8609514SGirish.Moodalbail@Sun.COM range.mpr_type = MAC_PROPVAL_UINT32; 8619514SGirish.Moodalbail@Sun.COM range.range_uint32[0].mpur_min = ANCHOR_VNIC_MIN_MTU; 8629514SGirish.Moodalbail@Sun.COM range.range_uint32[0].mpur_max = ANCHOR_VNIC_MAX_MTU; 8639514SGirish.Moodalbail@Sun.COM bcopy(&range, pr_val, sizeof (range)); 8649514SGirish.Moodalbail@Sun.COM return (0); 8659514SGirish.Moodalbail@Sun.COM default: 8669514SGirish.Moodalbail@Sun.COM break; 8679514SGirish.Moodalbail@Sun.COM } 8689514SGirish.Moodalbail@Sun.COM 8699514SGirish.Moodalbail@Sun.COM return (err); 8708927SGirish.Moodalbail@Sun.COM } 8718927SGirish.Moodalbail@Sun.COM 8725084Sjohnlev int 873*10616SSebastien.Roy@Sun.COM vnic_info(vnic_info_t *info, cred_t *credp) 8745084Sjohnlev { 8758275SEric Cheng vnic_t *vnic; 8768275SEric Cheng int err; 8775084Sjohnlev 878*10616SSebastien.Roy@Sun.COM /* Make sure that the VNIC link is visible from the caller's zone. */ 879*10616SSebastien.Roy@Sun.COM if (!dls_devnet_islinkvisible(info->vn_vnic_id, crgetzoneid(credp))) 880*10616SSebastien.Roy@Sun.COM return (ENOENT); 881*10616SSebastien.Roy@Sun.COM 8828275SEric Cheng rw_enter(&vnic_lock, RW_WRITER); 8835084Sjohnlev 8848275SEric Cheng err = mod_hash_find(vnic_hash, VNIC_HASH_KEY(info->vn_vnic_id), 8858275SEric Cheng (mod_hash_val_t *)&vnic); 8868275SEric Cheng if (err != 0) { 8878275SEric Cheng rw_exit(&vnic_lock); 8888275SEric Cheng return (ENOENT); 8895895Syz147064 } 8905084Sjohnlev 8918275SEric Cheng info->vn_link_id = vnic->vn_link_id; 8928275SEric Cheng info->vn_mac_addr_type = vnic->vn_addr_type; 8938275SEric Cheng info->vn_mac_len = vnic->vn_addr_len; 8948275SEric Cheng bcopy(vnic->vn_addr, info->vn_mac_addr, MAXMACADDRLEN); 8958275SEric Cheng info->vn_mac_slot = vnic->vn_slot_id; 8968275SEric Cheng info->vn_mac_prefix_len = 0; 8978275SEric Cheng info->vn_vid = vnic->vn_vid; 8988275SEric Cheng info->vn_force = vnic->vn_force; 8995084Sjohnlev 9008275SEric Cheng bzero(&info->vn_resource_props, sizeof (mac_resource_props_t)); 9018275SEric Cheng if (vnic->vn_mch != NULL) 9028275SEric Cheng mac_resource_ctl_get(vnic->vn_mch, &info->vn_resource_props); 9035084Sjohnlev 9048275SEric Cheng rw_exit(&vnic_lock); 9058275SEric Cheng return (0); 9065084Sjohnlev } 9075084Sjohnlev 9085084Sjohnlev static void 9095084Sjohnlev vnic_notify_cb(void *arg, mac_notify_type_t type) 9105084Sjohnlev { 9118275SEric Cheng vnic_t *vnic = arg; 9125084Sjohnlev 9138275SEric Cheng /* 9149052SEric Cheng * Do not deliver notifications if the vnic is not fully initialized 9159052SEric Cheng * or is in process of being torn down. 9168275SEric Cheng */ 9179052SEric Cheng if (!vnic->vn_enabled) 9188275SEric Cheng return; 9195084Sjohnlev 9208275SEric Cheng switch (type) { 9218275SEric Cheng case MAC_NOTE_UNICST: 9229052SEric Cheng /* 9239052SEric Cheng * Only the VLAN VNIC needs to be notified with primary MAC 9249052SEric Cheng * address change. 9259052SEric Cheng */ 9269052SEric Cheng if (vnic->vn_addr_type != VNIC_MAC_ADDR_TYPE_PRIMARY) 9279052SEric Cheng return; 9289052SEric Cheng 9298275SEric Cheng /* the unicast MAC address value */ 9308275SEric Cheng mac_unicast_primary_get(vnic->vn_lower_mh, vnic->vn_addr); 9315084Sjohnlev 9328275SEric Cheng /* notify its upper layer MAC about MAC address change */ 9338275SEric Cheng mac_unicst_update(vnic->vn_mh, (const uint8_t *)vnic->vn_addr); 9348275SEric Cheng break; 9359052SEric Cheng 9369052SEric Cheng case MAC_NOTE_LINK: 9379052SEric Cheng mac_link_update(vnic->vn_mh, 9389052SEric Cheng mac_client_stat_get(vnic->vn_mch, MAC_STAT_LINK_STATE)); 9399052SEric Cheng break; 9409052SEric Cheng 9418275SEric Cheng default: 9428275SEric Cheng break; 9435084Sjohnlev } 9445084Sjohnlev } 945