1843e1988Sjohnlev /* 2843e1988Sjohnlev * CDDL HEADER START 3843e1988Sjohnlev * 4843e1988Sjohnlev * The contents of this file are subject to the terms of the 5843e1988Sjohnlev * Common Development and Distribution License (the "License"). 6843e1988Sjohnlev * You may not use this file except in compliance with the License. 7843e1988Sjohnlev * 8843e1988Sjohnlev * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9843e1988Sjohnlev * or http://www.opensolaris.org/os/licensing. 10843e1988Sjohnlev * See the License for the specific language governing permissions 11843e1988Sjohnlev * and limitations under the License. 12843e1988Sjohnlev * 13843e1988Sjohnlev * When distributing Covered Code, include this CDDL HEADER in each 14843e1988Sjohnlev * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15843e1988Sjohnlev * If applicable, add the following below this CDDL HEADER, with the 16843e1988Sjohnlev * fields enclosed by brackets "[]" replaced with your own identifying 17843e1988Sjohnlev * information: Portions Copyright [yyyy] [name of copyright owner] 18843e1988Sjohnlev * 19843e1988Sjohnlev * CDDL HEADER END 20843e1988Sjohnlev */ 21843e1988Sjohnlev /* 229056fcebSCathy Zhou * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. 23bf773d37SRobert Mustacchi * Copyright 2015 Joyent, Inc. 24238d8f47SDale Ghent * Copyright 2016 OmniTI Computer Consulting, Inc. All rights reserved. 25843e1988Sjohnlev */ 26843e1988Sjohnlev 27843e1988Sjohnlev #include <sys/types.h> 282b24ab6bSSebastien Roy #include <sys/cred.h> 29843e1988Sjohnlev #include <sys/sysmacros.h> 30843e1988Sjohnlev #include <sys/conf.h> 31843e1988Sjohnlev #include <sys/cmn_err.h> 32843e1988Sjohnlev #include <sys/list.h> 33843e1988Sjohnlev #include <sys/ksynch.h> 34843e1988Sjohnlev #include <sys/kmem.h> 35843e1988Sjohnlev #include <sys/stream.h> 36843e1988Sjohnlev #include <sys/modctl.h> 37843e1988Sjohnlev #include <sys/ddi.h> 38843e1988Sjohnlev #include <sys/sunddi.h> 39843e1988Sjohnlev #include <sys/atomic.h> 40843e1988Sjohnlev #include <sys/stat.h> 41843e1988Sjohnlev #include <sys/modhash.h> 42843e1988Sjohnlev #include <sys/strsubr.h> 43843e1988Sjohnlev #include <sys/strsun.h> 44843e1988Sjohnlev #include <sys/dlpi.h> 45843e1988Sjohnlev #include <sys/mac.h> 46da14cebeSEric Cheng #include <sys/mac_provider.h> 47da14cebeSEric Cheng #include <sys/mac_client.h> 48da14cebeSEric Cheng #include <sys/mac_client_priv.h> 49843e1988Sjohnlev #include <sys/mac_ether.h> 50d62bc4baSyz147064 #include <sys/dls.h> 51843e1988Sjohnlev #include <sys/pattr.h> 52da14cebeSEric Cheng #include <sys/time.h> 53da14cebeSEric Cheng #include <sys/vlan.h> 54843e1988Sjohnlev #include <sys/vnic.h> 55843e1988Sjohnlev #include <sys/vnic_impl.h> 56*098d2c75SRobert Mustacchi #include <sys/mac_impl.h> 57da14cebeSEric Cheng #include <sys/mac_flow_impl.h> 58843e1988Sjohnlev #include <inet/ip_impl.h> 59843e1988Sjohnlev 60da14cebeSEric Cheng /* 61da14cebeSEric Cheng * Note that for best performance, the VNIC is a passthrough design. 62da14cebeSEric Cheng * For each VNIC corresponds a MAC client of the underlying MAC (lower MAC). 63da14cebeSEric Cheng * This MAC client is opened by the VNIC driver at VNIC creation, 64da14cebeSEric Cheng * and closed when the VNIC is deleted. 65da14cebeSEric Cheng * When a MAC client of the VNIC itself opens a VNIC, the MAC layer 66da14cebeSEric Cheng * (upper MAC) detects that the MAC being opened is a VNIC. Instead 67da14cebeSEric Cheng * of allocating a new MAC client, it asks the VNIC driver to return 68da14cebeSEric Cheng * the lower MAC client handle associated with the VNIC, and that handle 69da14cebeSEric Cheng * is returned to the upper MAC client directly. This allows access 70da14cebeSEric Cheng * by upper MAC clients of the VNIC to have direct access to the lower 71da14cebeSEric Cheng * MAC client for the control path and data path. 72da14cebeSEric Cheng * 73da14cebeSEric Cheng * Due to this passthrough, some of the entry points exported by the 74da14cebeSEric Cheng * VNIC driver are never directly invoked. These entry points include 75da14cebeSEric Cheng * vnic_m_start, vnic_m_stop, vnic_m_promisc, vnic_m_multicst, etc. 761a41ca23SJerry Jelinek * 771a41ca23SJerry Jelinek * VNICs support multiple upper mac clients to enable support for 781a41ca23SJerry Jelinek * multiple MAC addresses on the VNIC. When the VNIC is created the 791a41ca23SJerry Jelinek * initial mac client is the primary upper mac. Any additional mac 801a41ca23SJerry Jelinek * clients are secondary macs. 81da14cebeSEric Cheng */ 82da14cebeSEric Cheng 83843e1988Sjohnlev static int vnic_m_start(void *); 84843e1988Sjohnlev static void vnic_m_stop(void *); 85843e1988Sjohnlev static int vnic_m_promisc(void *, boolean_t); 86843e1988Sjohnlev static int vnic_m_multicst(void *, boolean_t, const uint8_t *); 87843e1988Sjohnlev static int vnic_m_unicst(void *, const uint8_t *); 88843e1988Sjohnlev static int vnic_m_stat(void *, uint_t, uint64_t *); 89da14cebeSEric Cheng static void vnic_m_ioctl(void *, queue_t *, mblk_t *); 90ab6f61efSGirish Moodalbail static int vnic_m_setprop(void *, const char *, mac_prop_id_t, uint_t, 91ab6f61efSGirish Moodalbail const void *); 921a41ca23SJerry Jelinek static int vnic_m_getprop(void *, const char *, mac_prop_id_t, uint_t, void *); 930dc2366fSVenugopal Iyer static void vnic_m_propinfo(void *, const char *, mac_prop_id_t, 940dc2366fSVenugopal Iyer mac_prop_info_handle_t); 95843e1988Sjohnlev static mblk_t *vnic_m_tx(void *, mblk_t *); 96843e1988Sjohnlev static boolean_t vnic_m_capab_get(void *, mac_capab_t, void *); 97843e1988Sjohnlev static void vnic_notify_cb(void *, mac_notify_type_t); 981a41ca23SJerry Jelinek static void vnic_cleanup_secondary_macs(vnic_t *, int); 99843e1988Sjohnlev 100843e1988Sjohnlev static kmem_cache_t *vnic_cache; 101843e1988Sjohnlev static krwlock_t vnic_lock; 102843e1988Sjohnlev static uint_t vnic_count; 103843e1988Sjohnlev 104f0f2c3a5SGirish Moodalbail #define ANCHOR_VNIC_MIN_MTU 576 105f0f2c3a5SGirish Moodalbail #define ANCHOR_VNIC_MAX_MTU 9000 106f0f2c3a5SGirish Moodalbail 107843e1988Sjohnlev /* hash of VNICs (vnic_t's), keyed by VNIC id */ 108843e1988Sjohnlev static mod_hash_t *vnic_hash; 109843e1988Sjohnlev #define VNIC_HASHSZ 64 110843e1988Sjohnlev #define VNIC_HASH_KEY(vnic_id) ((mod_hash_key_t)(uintptr_t)vnic_id) 111843e1988Sjohnlev 112ab6f61efSGirish Moodalbail #define VNIC_M_CALLBACK_FLAGS \ 1131a41ca23SJerry Jelinek (MC_IOCTL | MC_GETCAPAB | MC_SETPROP | MC_GETPROP | MC_PROPINFO) 114843e1988Sjohnlev 115843e1988Sjohnlev static mac_callbacks_t vnic_m_callbacks = { 116843e1988Sjohnlev VNIC_M_CALLBACK_FLAGS, 117843e1988Sjohnlev vnic_m_stat, 118843e1988Sjohnlev vnic_m_start, 119843e1988Sjohnlev vnic_m_stop, 120843e1988Sjohnlev vnic_m_promisc, 121843e1988Sjohnlev vnic_m_multicst, 122843e1988Sjohnlev vnic_m_unicst, 123843e1988Sjohnlev vnic_m_tx, 1240dc2366fSVenugopal Iyer NULL, 125da14cebeSEric Cheng vnic_m_ioctl, 126ab6f61efSGirish Moodalbail vnic_m_capab_get, 127ab6f61efSGirish Moodalbail NULL, 128ab6f61efSGirish Moodalbail NULL, 129ab6f61efSGirish Moodalbail vnic_m_setprop, 1301a41ca23SJerry Jelinek vnic_m_getprop, 1310dc2366fSVenugopal Iyer vnic_m_propinfo 132843e1988Sjohnlev }; 133843e1988Sjohnlev 134843e1988Sjohnlev void 135843e1988Sjohnlev vnic_dev_init(void) 136843e1988Sjohnlev { 137843e1988Sjohnlev vnic_cache = kmem_cache_create("vnic_cache", 138843e1988Sjohnlev sizeof (vnic_t), 0, NULL, NULL, NULL, NULL, NULL, 0); 139843e1988Sjohnlev 140843e1988Sjohnlev vnic_hash = mod_hash_create_idhash("vnic_hash", 141843e1988Sjohnlev VNIC_HASHSZ, mod_hash_null_valdtor); 142843e1988Sjohnlev 143843e1988Sjohnlev rw_init(&vnic_lock, NULL, RW_DEFAULT, NULL); 144843e1988Sjohnlev 145843e1988Sjohnlev vnic_count = 0; 146843e1988Sjohnlev } 147843e1988Sjohnlev 148843e1988Sjohnlev void 149843e1988Sjohnlev vnic_dev_fini(void) 150843e1988Sjohnlev { 151843e1988Sjohnlev ASSERT(vnic_count == 0); 152843e1988Sjohnlev 153843e1988Sjohnlev rw_destroy(&vnic_lock); 154843e1988Sjohnlev mod_hash_destroy_idhash(vnic_hash); 155843e1988Sjohnlev kmem_cache_destroy(vnic_cache); 156843e1988Sjohnlev } 157843e1988Sjohnlev 158843e1988Sjohnlev uint_t 159843e1988Sjohnlev vnic_dev_count(void) 160843e1988Sjohnlev { 161843e1988Sjohnlev return (vnic_count); 162843e1988Sjohnlev } 163843e1988Sjohnlev 164da14cebeSEric Cheng static vnic_ioc_diag_t 165da14cebeSEric Cheng vnic_mac2vnic_diag(mac_diag_t diag) 166843e1988Sjohnlev { 167da14cebeSEric Cheng switch (diag) { 168da14cebeSEric Cheng case MAC_DIAG_MACADDR_NIC: 169da14cebeSEric Cheng return (VNIC_IOC_DIAG_MACADDR_NIC); 170da14cebeSEric Cheng case MAC_DIAG_MACADDR_INUSE: 171da14cebeSEric Cheng return (VNIC_IOC_DIAG_MACADDR_INUSE); 172da14cebeSEric Cheng case MAC_DIAG_MACADDR_INVALID: 173da14cebeSEric Cheng return (VNIC_IOC_DIAG_MACADDR_INVALID); 174da14cebeSEric Cheng case MAC_DIAG_MACADDRLEN_INVALID: 175da14cebeSEric Cheng return (VNIC_IOC_DIAG_MACADDRLEN_INVALID); 176da14cebeSEric Cheng case MAC_DIAG_MACFACTORYSLOTINVALID: 177da14cebeSEric Cheng return (VNIC_IOC_DIAG_MACFACTORYSLOTINVALID); 178da14cebeSEric Cheng case MAC_DIAG_MACFACTORYSLOTUSED: 179da14cebeSEric Cheng return (VNIC_IOC_DIAG_MACFACTORYSLOTUSED); 180da14cebeSEric Cheng case MAC_DIAG_MACFACTORYSLOTALLUSED: 181da14cebeSEric Cheng return (VNIC_IOC_DIAG_MACFACTORYSLOTALLUSED); 182da14cebeSEric Cheng case MAC_DIAG_MACFACTORYNOTSUP: 183da14cebeSEric Cheng return (VNIC_IOC_DIAG_MACFACTORYNOTSUP); 184da14cebeSEric Cheng case MAC_DIAG_MACPREFIX_INVALID: 185da14cebeSEric Cheng return (VNIC_IOC_DIAG_MACPREFIX_INVALID); 186da14cebeSEric Cheng case MAC_DIAG_MACPREFIXLEN_INVALID: 187da14cebeSEric Cheng return (VNIC_IOC_DIAG_MACPREFIXLEN_INVALID); 188da14cebeSEric Cheng case MAC_DIAG_MACNO_HWRINGS: 189da14cebeSEric Cheng return (VNIC_IOC_DIAG_NO_HWRINGS); 190da14cebeSEric Cheng default: 191da14cebeSEric Cheng return (VNIC_IOC_DIAG_NONE); 192da14cebeSEric Cheng } 193da14cebeSEric Cheng } 194da14cebeSEric Cheng 195da14cebeSEric Cheng static int 196da14cebeSEric Cheng vnic_unicast_add(vnic_t *vnic, vnic_mac_addr_type_t vnic_addr_type, 197da14cebeSEric Cheng int *addr_slot, uint_t prefix_len, int *addr_len_ptr_arg, 198da14cebeSEric Cheng uint8_t *mac_addr_arg, uint16_t flags, vnic_ioc_diag_t *diag, 1990dc2366fSVenugopal Iyer uint16_t vid, boolean_t req_hwgrp_flag) 200da14cebeSEric Cheng { 201da14cebeSEric Cheng mac_diag_t mac_diag; 202da14cebeSEric Cheng uint16_t mac_flags = 0; 203843e1988Sjohnlev int err; 204da14cebeSEric Cheng uint_t addr_len; 205843e1988Sjohnlev 206da14cebeSEric Cheng if (flags & VNIC_IOC_CREATE_NODUPCHECK) 207da14cebeSEric Cheng mac_flags |= MAC_UNICAST_NODUPCHECK; 208843e1988Sjohnlev 209da14cebeSEric Cheng switch (vnic_addr_type) { 210da14cebeSEric Cheng case VNIC_MAC_ADDR_TYPE_FIXED: 2111cb875aeSCathy Zhou case VNIC_MAC_ADDR_TYPE_VRID: 212da14cebeSEric Cheng /* 213da14cebeSEric Cheng * The MAC address value to assign to the VNIC 214da14cebeSEric Cheng * is already provided in mac_addr_arg. addr_len_ptr_arg 215da14cebeSEric Cheng * already contains the MAC address length. 216da14cebeSEric Cheng */ 217da14cebeSEric Cheng break; 218843e1988Sjohnlev 219da14cebeSEric Cheng case VNIC_MAC_ADDR_TYPE_RANDOM: 220da14cebeSEric Cheng /* 221da14cebeSEric Cheng * Random MAC address. There are two sub-cases: 222da14cebeSEric Cheng * 223da14cebeSEric Cheng * 1 - If mac_len == 0, a new MAC address is generated. 224da14cebeSEric Cheng * The length of the MAC address to generated depends 225da14cebeSEric Cheng * on the type of MAC used. The prefix to use for the MAC 226da14cebeSEric Cheng * address is stored in the most significant bytes 227da14cebeSEric Cheng * of the mac_addr argument, and its length is specified 228da14cebeSEric Cheng * by the mac_prefix_len argument. This prefix can 229da14cebeSEric Cheng * correspond to a IEEE OUI in the case of Ethernet, 230da14cebeSEric Cheng * for example. 231da14cebeSEric Cheng * 232da14cebeSEric Cheng * 2 - If mac_len > 0, the address was already picked 233da14cebeSEric Cheng * randomly, and is now passed back during VNIC 234da14cebeSEric Cheng * re-creation. The mac_addr argument contains the MAC 235da14cebeSEric Cheng * address that was generated. We distinguish this 236da14cebeSEric Cheng * case from the fixed MAC address case, since we 237da14cebeSEric Cheng * want the user consumers to know, when they query 238da14cebeSEric Cheng * the list of VNICs, that a VNIC was assigned a 239da14cebeSEric Cheng * random MAC address vs assigned a fixed address 240da14cebeSEric Cheng * specified by the user. 241da14cebeSEric Cheng */ 242843e1988Sjohnlev 243d62bc4baSyz147064 /* 244da14cebeSEric Cheng * If it's a pre-generated address, we're done. mac_addr_arg 245da14cebeSEric Cheng * and addr_len_ptr_arg already contain the MAC address 246da14cebeSEric Cheng * value and length. 247d62bc4baSyz147064 */ 248da14cebeSEric Cheng if (*addr_len_ptr_arg > 0) 249da14cebeSEric Cheng break; 250d62bc4baSyz147064 251da14cebeSEric Cheng /* generate a new random MAC address */ 252da14cebeSEric Cheng if ((err = mac_addr_random(vnic->vn_mch, 253da14cebeSEric Cheng prefix_len, mac_addr_arg, &mac_diag)) != 0) { 254da14cebeSEric Cheng *diag = vnic_mac2vnic_diag(mac_diag); 255843e1988Sjohnlev return (err); 256843e1988Sjohnlev } 257da14cebeSEric Cheng *addr_len_ptr_arg = mac_addr_len(vnic->vn_lower_mh); 258da14cebeSEric Cheng break; 259843e1988Sjohnlev 260da14cebeSEric Cheng case VNIC_MAC_ADDR_TYPE_FACTORY: 261da14cebeSEric Cheng err = mac_addr_factory_reserve(vnic->vn_mch, addr_slot); 262843e1988Sjohnlev if (err != 0) { 263da14cebeSEric Cheng if (err == EINVAL) 264da14cebeSEric Cheng *diag = VNIC_IOC_DIAG_MACFACTORYSLOTINVALID; 265da14cebeSEric Cheng if (err == EBUSY) 266da14cebeSEric Cheng *diag = VNIC_IOC_DIAG_MACFACTORYSLOTUSED; 267da14cebeSEric Cheng if (err == ENOSPC) 268da14cebeSEric Cheng *diag = VNIC_IOC_DIAG_MACFACTORYSLOTALLUSED; 269843e1988Sjohnlev return (err); 270843e1988Sjohnlev } 271843e1988Sjohnlev 272da14cebeSEric Cheng mac_addr_factory_value(vnic->vn_lower_mh, *addr_slot, 273da14cebeSEric Cheng mac_addr_arg, &addr_len, NULL, NULL); 274da14cebeSEric Cheng *addr_len_ptr_arg = addr_len; 275da14cebeSEric Cheng break; 276843e1988Sjohnlev 277da14cebeSEric Cheng case VNIC_MAC_ADDR_TYPE_AUTO: 278da14cebeSEric Cheng /* first try to allocate a factory MAC address */ 279da14cebeSEric Cheng err = mac_addr_factory_reserve(vnic->vn_mch, addr_slot); 280da14cebeSEric Cheng if (err == 0) { 281da14cebeSEric Cheng mac_addr_factory_value(vnic->vn_lower_mh, *addr_slot, 282da14cebeSEric Cheng mac_addr_arg, &addr_len, NULL, NULL); 283da14cebeSEric Cheng vnic_addr_type = VNIC_MAC_ADDR_TYPE_FACTORY; 284da14cebeSEric Cheng *addr_len_ptr_arg = addr_len; 285da14cebeSEric Cheng break; 286843e1988Sjohnlev } 287843e1988Sjohnlev 288843e1988Sjohnlev /* 289da14cebeSEric Cheng * Allocating a factory MAC address failed, generate a 290da14cebeSEric Cheng * random MAC address instead. 291843e1988Sjohnlev */ 292da14cebeSEric Cheng if ((err = mac_addr_random(vnic->vn_mch, 293da14cebeSEric Cheng prefix_len, mac_addr_arg, &mac_diag)) != 0) { 294da14cebeSEric Cheng *diag = vnic_mac2vnic_diag(mac_diag); 295da14cebeSEric Cheng return (err); 296da14cebeSEric Cheng } 297da14cebeSEric Cheng *addr_len_ptr_arg = mac_addr_len(vnic->vn_lower_mh); 298da14cebeSEric Cheng vnic_addr_type = VNIC_MAC_ADDR_TYPE_RANDOM; 299da14cebeSEric Cheng break; 300da14cebeSEric Cheng case VNIC_MAC_ADDR_TYPE_PRIMARY: 301da14cebeSEric Cheng /* 302da14cebeSEric Cheng * We get the address here since we copy it in the 303da14cebeSEric Cheng * vnic's vn_addr. 3040dc2366fSVenugopal Iyer * We can't ask for hardware resources since we 3050dc2366fSVenugopal Iyer * don't currently support hardware classification 3060dc2366fSVenugopal Iyer * for these MAC clients. 307da14cebeSEric Cheng */ 3080dc2366fSVenugopal Iyer if (req_hwgrp_flag) { 3090dc2366fSVenugopal Iyer *diag = VNIC_IOC_DIAG_NO_HWRINGS; 3100dc2366fSVenugopal Iyer return (ENOTSUP); 3110dc2366fSVenugopal Iyer } 312da14cebeSEric Cheng mac_unicast_primary_get(vnic->vn_lower_mh, mac_addr_arg); 313da14cebeSEric Cheng *addr_len_ptr_arg = mac_addr_len(vnic->vn_lower_mh); 314da14cebeSEric Cheng mac_flags |= MAC_UNICAST_VNIC_PRIMARY; 315da14cebeSEric Cheng break; 316843e1988Sjohnlev } 317843e1988Sjohnlev 318da14cebeSEric Cheng vnic->vn_addr_type = vnic_addr_type; 319da14cebeSEric Cheng 320da14cebeSEric Cheng err = mac_unicast_add(vnic->vn_mch, mac_addr_arg, mac_flags, 321da14cebeSEric Cheng &vnic->vn_muh, vid, &mac_diag); 322da14cebeSEric Cheng if (err != 0) { 323da14cebeSEric Cheng if (vnic_addr_type == VNIC_MAC_ADDR_TYPE_FACTORY) { 324da14cebeSEric Cheng /* release factory MAC address */ 325da14cebeSEric Cheng mac_addr_factory_release(vnic->vn_mch, *addr_slot); 326da14cebeSEric Cheng } 327da14cebeSEric Cheng *diag = vnic_mac2vnic_diag(mac_diag); 328843e1988Sjohnlev } 329843e1988Sjohnlev 330843e1988Sjohnlev return (err); 331843e1988Sjohnlev } 332843e1988Sjohnlev 333843e1988Sjohnlev /* 334843e1988Sjohnlev * Create a new VNIC upon request from administrator. 335843e1988Sjohnlev * Returns 0 on success, an errno on failure. 336843e1988Sjohnlev */ 337da14cebeSEric Cheng /* ARGSUSED */ 338843e1988Sjohnlev int 339da14cebeSEric Cheng vnic_dev_create(datalink_id_t vnic_id, datalink_id_t linkid, 340da14cebeSEric Cheng vnic_mac_addr_type_t *vnic_addr_type, int *mac_len, uchar_t *mac_addr, 3411cb875aeSCathy Zhou int *mac_slot, uint_t mac_prefix_len, uint16_t vid, vrid_t vrid, 3421cb875aeSCathy Zhou int af, mac_resource_props_t *mrp, uint32_t flags, vnic_ioc_diag_t *diag, 3432b24ab6bSSebastien Roy cred_t *credp) 344843e1988Sjohnlev { 345da14cebeSEric Cheng vnic_t *vnic; 346843e1988Sjohnlev mac_register_t *mac; 347843e1988Sjohnlev int err; 348da14cebeSEric Cheng boolean_t is_anchor = ((flags & VNIC_IOC_CREATE_ANCHOR) != 0); 349da14cebeSEric Cheng char vnic_name[MAXNAMELEN]; 350da14cebeSEric Cheng const mac_info_t *minfop; 3510dc2366fSVenugopal Iyer uint32_t req_hwgrp_flag = B_FALSE; 352843e1988Sjohnlev 353da14cebeSEric Cheng *diag = VNIC_IOC_DIAG_NONE; 354843e1988Sjohnlev 355843e1988Sjohnlev rw_enter(&vnic_lock, RW_WRITER); 356843e1988Sjohnlev 357843e1988Sjohnlev /* does a VNIC with the same id already exist? */ 358843e1988Sjohnlev err = mod_hash_find(vnic_hash, VNIC_HASH_KEY(vnic_id), 359843e1988Sjohnlev (mod_hash_val_t *)&vnic); 360843e1988Sjohnlev if (err == 0) { 361843e1988Sjohnlev rw_exit(&vnic_lock); 362843e1988Sjohnlev return (EEXIST); 363843e1988Sjohnlev } 364843e1988Sjohnlev 365843e1988Sjohnlev vnic = kmem_cache_alloc(vnic_cache, KM_NOSLEEP); 366843e1988Sjohnlev if (vnic == NULL) { 367843e1988Sjohnlev rw_exit(&vnic_lock); 368843e1988Sjohnlev return (ENOMEM); 369843e1988Sjohnlev } 370843e1988Sjohnlev 371da14cebeSEric Cheng bzero(vnic, sizeof (*vnic)); 372da14cebeSEric Cheng 373da14cebeSEric Cheng vnic->vn_id = vnic_id; 374da14cebeSEric Cheng vnic->vn_link_id = linkid; 3751cb875aeSCathy Zhou vnic->vn_vrid = vrid; 3761cb875aeSCathy Zhou vnic->vn_af = af; 377da14cebeSEric Cheng 378da14cebeSEric Cheng if (!is_anchor) { 379da14cebeSEric Cheng if (linkid == DATALINK_INVALID_LINKID) { 380da14cebeSEric Cheng err = EINVAL; 381da14cebeSEric Cheng goto bail; 382843e1988Sjohnlev } 383843e1988Sjohnlev 384da14cebeSEric Cheng /* 385da14cebeSEric Cheng * Open the lower MAC and assign its initial bandwidth and 386da14cebeSEric Cheng * MAC address. We do this here during VNIC creation and 387da14cebeSEric Cheng * do not wait until the upper MAC client open so that we 388da14cebeSEric Cheng * can validate the VNIC creation parameters (bandwidth, 389da14cebeSEric Cheng * MAC address, etc) and reserve a factory MAC address if 390da14cebeSEric Cheng * one was requested. 391da14cebeSEric Cheng */ 392da14cebeSEric Cheng err = mac_open_by_linkid(linkid, &vnic->vn_lower_mh); 393da14cebeSEric Cheng if (err != 0) 394843e1988Sjohnlev goto bail; 395da14cebeSEric Cheng 396da14cebeSEric Cheng /* 397da14cebeSEric Cheng * VNIC(vlan) over VNICs(vlans) is not supported. 398da14cebeSEric Cheng */ 399da14cebeSEric Cheng if (mac_is_vnic(vnic->vn_lower_mh)) { 400da14cebeSEric Cheng err = EINVAL; 401da14cebeSEric Cheng goto bail; 402da14cebeSEric Cheng } 403da14cebeSEric Cheng 404da14cebeSEric Cheng /* only ethernet support for now */ 405da14cebeSEric Cheng minfop = mac_info(vnic->vn_lower_mh); 406da14cebeSEric Cheng if (minfop->mi_nativemedia != DL_ETHER) { 407da14cebeSEric Cheng err = ENOTSUP; 408da14cebeSEric Cheng goto bail; 409da14cebeSEric Cheng } 410da14cebeSEric Cheng 411da14cebeSEric Cheng (void) dls_mgmt_get_linkinfo(vnic_id, vnic_name, NULL, NULL, 412da14cebeSEric Cheng NULL); 413da14cebeSEric Cheng err = mac_client_open(vnic->vn_lower_mh, &vnic->vn_mch, 4140dc2366fSVenugopal Iyer vnic_name, MAC_OPEN_FLAGS_IS_VNIC); 415da14cebeSEric Cheng if (err != 0) 416da14cebeSEric Cheng goto bail; 417da14cebeSEric Cheng 418da14cebeSEric Cheng /* assign a MAC address to the VNIC */ 419da14cebeSEric Cheng 420da14cebeSEric Cheng err = vnic_unicast_add(vnic, *vnic_addr_type, mac_slot, 4210dc2366fSVenugopal Iyer mac_prefix_len, mac_len, mac_addr, flags, diag, vid, 4220dc2366fSVenugopal Iyer req_hwgrp_flag); 423da14cebeSEric Cheng if (err != 0) { 424da14cebeSEric Cheng vnic->vn_muh = NULL; 4250dc2366fSVenugopal Iyer if (diag != NULL && req_hwgrp_flag) 426da14cebeSEric Cheng *diag = VNIC_IOC_DIAG_NO_HWRINGS; 427da14cebeSEric Cheng goto bail; 428da14cebeSEric Cheng } 429da14cebeSEric Cheng 430da14cebeSEric Cheng /* register to receive notification from underlying MAC */ 431da14cebeSEric Cheng vnic->vn_mnh = mac_notify_add(vnic->vn_lower_mh, vnic_notify_cb, 432da14cebeSEric Cheng vnic); 433da14cebeSEric Cheng 434da14cebeSEric Cheng *vnic_addr_type = vnic->vn_addr_type; 435da14cebeSEric Cheng vnic->vn_addr_len = *mac_len; 436da14cebeSEric Cheng vnic->vn_vid = vid; 437da14cebeSEric Cheng 438da14cebeSEric Cheng bcopy(mac_addr, vnic->vn_addr, vnic->vn_addr_len); 439da14cebeSEric Cheng 440da14cebeSEric Cheng if (vnic->vn_addr_type == VNIC_MAC_ADDR_TYPE_FACTORY) 441da14cebeSEric Cheng vnic->vn_slot_id = *mac_slot; 442843e1988Sjohnlev 4439056fcebSCathy Zhou /* 4449056fcebSCathy Zhou * Set the initial VNIC capabilities. If the VNIC is created 4459056fcebSCathy Zhou * over MACs which does not support nactive vlan, disable 4469056fcebSCathy Zhou * VNIC's hardware checksum capability if its VID is not 0, 4479056fcebSCathy Zhou * since the underlying MAC would get the hardware checksum 4489056fcebSCathy Zhou * offset wrong in case of VLAN packets. 4499056fcebSCathy Zhou */ 4509056fcebSCathy Zhou if (vid == 0 || !mac_capab_get(vnic->vn_lower_mh, 4519056fcebSCathy Zhou MAC_CAPAB_NO_NATIVEVLAN, NULL)) { 452da14cebeSEric Cheng if (!mac_capab_get(vnic->vn_lower_mh, MAC_CAPAB_HCKSUM, 453843e1988Sjohnlev &vnic->vn_hcksum_txflags)) 454843e1988Sjohnlev vnic->vn_hcksum_txflags = 0; 4559056fcebSCathy Zhou } else { 4569056fcebSCathy Zhou vnic->vn_hcksum_txflags = 0; 4579056fcebSCathy Zhou } 458da14cebeSEric Cheng } 459843e1988Sjohnlev 460843e1988Sjohnlev /* register with the MAC module */ 461843e1988Sjohnlev if ((mac = mac_alloc(MAC_VERSION)) == NULL) 462843e1988Sjohnlev goto bail; 463843e1988Sjohnlev 464843e1988Sjohnlev mac->m_type_ident = MAC_PLUGIN_IDENT_ETHER; 465843e1988Sjohnlev mac->m_driver = vnic; 466843e1988Sjohnlev mac->m_dip = vnic_get_dip(); 467d62bc4baSyz147064 mac->m_instance = (uint_t)-1; 468843e1988Sjohnlev mac->m_src_addr = vnic->vn_addr; 469843e1988Sjohnlev mac->m_callbacks = &vnic_m_callbacks; 470843e1988Sjohnlev 471da14cebeSEric Cheng if (!is_anchor) { 472d62bc4baSyz147064 /* 473da14cebeSEric Cheng * If this is a VNIC based VLAN, then we check for the 474da14cebeSEric Cheng * margin unless it has been created with the force 475da14cebeSEric Cheng * flag. If we are configuring a VLAN over an etherstub, 476da14cebeSEric Cheng * we don't check the margin even if force is not set. 477d62bc4baSyz147064 */ 478da14cebeSEric Cheng if (vid == 0 || (flags & VNIC_IOC_CREATE_FORCE) != 0) { 479da14cebeSEric Cheng if (vid != VLAN_ID_NONE) 480da14cebeSEric Cheng vnic->vn_force = B_TRUE; 481da14cebeSEric Cheng /* 482da14cebeSEric Cheng * As the current margin size of the underlying mac is 483da14cebeSEric Cheng * used to determine the margin size of the VNIC 484da14cebeSEric Cheng * itself, request the underlying mac not to change 485da14cebeSEric Cheng * to a smaller margin size. 486da14cebeSEric Cheng */ 487da14cebeSEric Cheng err = mac_margin_add(vnic->vn_lower_mh, 488da14cebeSEric Cheng &vnic->vn_margin, B_TRUE); 489da14cebeSEric Cheng ASSERT(err == 0); 490da14cebeSEric Cheng } else { 491da14cebeSEric Cheng vnic->vn_margin = VLAN_TAGSZ; 492da14cebeSEric Cheng err = mac_margin_add(vnic->vn_lower_mh, 493da14cebeSEric Cheng &vnic->vn_margin, B_FALSE); 494da14cebeSEric Cheng if (err != 0) { 495da14cebeSEric Cheng mac_free(mac); 496da14cebeSEric Cheng if (diag != NULL) 497da14cebeSEric Cheng *diag = VNIC_IOC_DIAG_MACMARGIN_INVALID; 498843e1988Sjohnlev goto bail; 499da14cebeSEric Cheng } 500da14cebeSEric Cheng } 501da14cebeSEric Cheng 502da14cebeSEric Cheng mac_sdu_get(vnic->vn_lower_mh, &mac->m_min_sdu, 503da14cebeSEric Cheng &mac->m_max_sdu); 504a776d98eSRobert Mustacchi err = mac_mtu_add(vnic->vn_lower_mh, &mac->m_max_sdu, B_FALSE); 505a776d98eSRobert Mustacchi if (err != 0) { 506a776d98eSRobert Mustacchi VERIFY(mac_margin_remove(vnic->vn_lower_mh, 507a776d98eSRobert Mustacchi vnic->vn_margin) == 0); 508a776d98eSRobert Mustacchi mac_free(mac); 509a776d98eSRobert Mustacchi if (diag != NULL) 510a776d98eSRobert Mustacchi *diag = VNIC_IOC_DIAG_MACMTU_INVALID; 511a776d98eSRobert Mustacchi goto bail; 512a776d98eSRobert Mustacchi } 513a776d98eSRobert Mustacchi vnic->vn_mtu = mac->m_max_sdu; 514da14cebeSEric Cheng } else { 515da14cebeSEric Cheng vnic->vn_margin = VLAN_TAGSZ; 516dcb12fb7SRobert Mustacchi mac->m_min_sdu = 1; 517f0f2c3a5SGirish Moodalbail mac->m_max_sdu = ANCHOR_VNIC_MAX_MTU; 518a776d98eSRobert Mustacchi vnic->vn_mtu = ANCHOR_VNIC_MAX_MTU; 519da14cebeSEric Cheng } 520da14cebeSEric Cheng 521d62bc4baSyz147064 mac->m_margin = vnic->vn_margin; 522da14cebeSEric Cheng 523d62bc4baSyz147064 err = mac_register(mac, &vnic->vn_mh); 524d62bc4baSyz147064 mac_free(mac); 525d62bc4baSyz147064 if (err != 0) { 526a776d98eSRobert Mustacchi if (!is_anchor) { 527a776d98eSRobert Mustacchi VERIFY(mac_mtu_remove(vnic->vn_lower_mh, 528a776d98eSRobert Mustacchi vnic->vn_mtu) == 0); 529a776d98eSRobert Mustacchi VERIFY(mac_margin_remove(vnic->vn_lower_mh, 530d62bc4baSyz147064 vnic->vn_margin) == 0); 531a776d98eSRobert Mustacchi } 532d62bc4baSyz147064 goto bail; 533d62bc4baSyz147064 } 534d62bc4baSyz147064 535da14cebeSEric Cheng /* Set the VNIC's MAC in the client */ 53654ba2481SMax Bruning if (!is_anchor) { 5370dc2366fSVenugopal Iyer mac_set_upper_mac(vnic->vn_mch, vnic->vn_mh, mrp); 538da14cebeSEric Cheng 53954ba2481SMax Bruning if (mrp != NULL) { 54054ba2481SMax Bruning if ((mrp->mrp_mask & MRP_RX_RINGS) != 0 || 54154ba2481SMax Bruning (mrp->mrp_mask & MRP_TX_RINGS) != 0) { 54254ba2481SMax Bruning req_hwgrp_flag = B_TRUE; 54354ba2481SMax Bruning } 54454ba2481SMax Bruning err = mac_client_set_resources(vnic->vn_mch, mrp); 54554ba2481SMax Bruning if (err != 0) { 546a776d98eSRobert Mustacchi VERIFY(mac_mtu_remove(vnic->vn_lower_mh, 547a776d98eSRobert Mustacchi vnic->vn_mtu) == 0); 548a776d98eSRobert Mustacchi VERIFY(mac_margin_remove(vnic->vn_lower_mh, 549a776d98eSRobert Mustacchi vnic->vn_margin) == 0); 55054ba2481SMax Bruning (void) mac_unregister(vnic->vn_mh); 55154ba2481SMax Bruning goto bail; 55254ba2481SMax Bruning } 55354ba2481SMax Bruning } 55454ba2481SMax Bruning } 55554ba2481SMax Bruning 5562b24ab6bSSebastien Roy err = dls_devnet_create(vnic->vn_mh, vnic->vn_id, crgetzoneid(credp)); 5572b24ab6bSSebastien Roy if (err != 0) { 558da14cebeSEric Cheng VERIFY(is_anchor || mac_margin_remove(vnic->vn_lower_mh, 559d62bc4baSyz147064 vnic->vn_margin) == 0); 560a776d98eSRobert Mustacchi if (!is_anchor) { 561a776d98eSRobert Mustacchi VERIFY(mac_mtu_remove(vnic->vn_lower_mh, 562a776d98eSRobert Mustacchi vnic->vn_mtu) == 0); 563a776d98eSRobert Mustacchi VERIFY(mac_margin_remove(vnic->vn_lower_mh, 564a776d98eSRobert Mustacchi vnic->vn_margin) == 0); 565a776d98eSRobert Mustacchi } 566d62bc4baSyz147064 (void) mac_unregister(vnic->vn_mh); 567d62bc4baSyz147064 goto bail; 568d62bc4baSyz147064 } 569843e1988Sjohnlev 570843e1988Sjohnlev /* add new VNIC to hash table */ 571843e1988Sjohnlev err = mod_hash_insert(vnic_hash, VNIC_HASH_KEY(vnic_id), 572843e1988Sjohnlev (mod_hash_val_t)vnic); 573843e1988Sjohnlev ASSERT(err == 0); 574843e1988Sjohnlev vnic_count++; 575843e1988Sjohnlev 576bf773d37SRobert Mustacchi /* 577bf773d37SRobert Mustacchi * Now that we've enabled this VNIC, we should go through and update the 578bf773d37SRobert Mustacchi * link state by setting it to our parents. 579bf773d37SRobert Mustacchi */ 5802c4ec682SEric Cheng vnic->vn_enabled = B_TRUE; 581bf773d37SRobert Mustacchi 582bf773d37SRobert Mustacchi if (is_anchor) { 583bf773d37SRobert Mustacchi mac_link_update(vnic->vn_mh, LINK_STATE_UP); 584bf773d37SRobert Mustacchi } else { 585bf773d37SRobert Mustacchi mac_link_update(vnic->vn_mh, 586bf773d37SRobert Mustacchi mac_client_stat_get(vnic->vn_mch, MAC_STAT_LINK_STATE)); 587bf773d37SRobert Mustacchi } 588bf773d37SRobert Mustacchi 589843e1988Sjohnlev rw_exit(&vnic_lock); 590843e1988Sjohnlev 591843e1988Sjohnlev return (0); 592843e1988Sjohnlev 593843e1988Sjohnlev bail: 594843e1988Sjohnlev rw_exit(&vnic_lock); 595da14cebeSEric Cheng if (!is_anchor) { 596da14cebeSEric Cheng if (vnic->vn_mnh != NULL) 597da14cebeSEric Cheng (void) mac_notify_remove(vnic->vn_mnh, B_TRUE); 598da14cebeSEric Cheng if (vnic->vn_muh != NULL) 599da14cebeSEric Cheng (void) mac_unicast_remove(vnic->vn_mch, vnic->vn_muh); 600da14cebeSEric Cheng if (vnic->vn_mch != NULL) 601da14cebeSEric Cheng mac_client_close(vnic->vn_mch, MAC_CLOSE_FLAGS_IS_VNIC); 602da14cebeSEric Cheng if (vnic->vn_lower_mh != NULL) 603da14cebeSEric Cheng mac_close(vnic->vn_lower_mh); 604843e1988Sjohnlev } 605843e1988Sjohnlev 606da14cebeSEric Cheng kmem_cache_free(vnic_cache, vnic); 607843e1988Sjohnlev return (err); 608843e1988Sjohnlev } 609843e1988Sjohnlev 610843e1988Sjohnlev /* 611843e1988Sjohnlev * Modify the properties of an existing VNIC. 612843e1988Sjohnlev */ 613843e1988Sjohnlev /* ARGSUSED */ 614843e1988Sjohnlev int 615d62bc4baSyz147064 vnic_dev_modify(datalink_id_t vnic_id, uint_t modify_mask, 616da14cebeSEric Cheng vnic_mac_addr_type_t mac_addr_type, uint_t mac_len, uchar_t *mac_addr, 617da14cebeSEric Cheng uint_t mac_slot, mac_resource_props_t *mrp) 618843e1988Sjohnlev { 619843e1988Sjohnlev vnic_t *vnic = NULL; 620843e1988Sjohnlev 621843e1988Sjohnlev rw_enter(&vnic_lock, RW_WRITER); 622843e1988Sjohnlev 623843e1988Sjohnlev if (mod_hash_find(vnic_hash, VNIC_HASH_KEY(vnic_id), 624843e1988Sjohnlev (mod_hash_val_t *)&vnic) != 0) { 625843e1988Sjohnlev rw_exit(&vnic_lock); 626843e1988Sjohnlev return (ENOENT); 627843e1988Sjohnlev } 628843e1988Sjohnlev 629843e1988Sjohnlev rw_exit(&vnic_lock); 630843e1988Sjohnlev 631da14cebeSEric Cheng return (0); 632843e1988Sjohnlev } 633843e1988Sjohnlev 634da14cebeSEric Cheng /* ARGSUSED */ 635843e1988Sjohnlev int 6362b24ab6bSSebastien Roy vnic_dev_delete(datalink_id_t vnic_id, uint32_t flags, cred_t *credp) 637843e1988Sjohnlev { 638843e1988Sjohnlev vnic_t *vnic = NULL; 639843e1988Sjohnlev mod_hash_val_t val; 640d62bc4baSyz147064 datalink_id_t tmpid; 641843e1988Sjohnlev int rc; 642843e1988Sjohnlev 643843e1988Sjohnlev rw_enter(&vnic_lock, RW_WRITER); 644843e1988Sjohnlev 645843e1988Sjohnlev if (mod_hash_find(vnic_hash, VNIC_HASH_KEY(vnic_id), 646843e1988Sjohnlev (mod_hash_val_t *)&vnic) != 0) { 647843e1988Sjohnlev rw_exit(&vnic_lock); 648843e1988Sjohnlev return (ENOENT); 649843e1988Sjohnlev } 650843e1988Sjohnlev 651da14cebeSEric Cheng if ((rc = dls_devnet_destroy(vnic->vn_mh, &tmpid, B_TRUE)) != 0) { 652d62bc4baSyz147064 rw_exit(&vnic_lock); 653d62bc4baSyz147064 return (rc); 654d62bc4baSyz147064 } 655d62bc4baSyz147064 656d62bc4baSyz147064 ASSERT(vnic_id == tmpid); 657d62bc4baSyz147064 658843e1988Sjohnlev /* 659843e1988Sjohnlev * We cannot unregister the MAC yet. Unregistering would 660843e1988Sjohnlev * free up mac_impl_t which should not happen at this time. 661da14cebeSEric Cheng * So disable mac_impl_t by calling mac_disable(). This will prevent 662da14cebeSEric Cheng * any new claims on mac_impl_t. 663843e1988Sjohnlev */ 664da14cebeSEric Cheng if ((rc = mac_disable(vnic->vn_mh)) != 0) { 6652b24ab6bSSebastien Roy (void) dls_devnet_create(vnic->vn_mh, vnic_id, 6662b24ab6bSSebastien Roy crgetzoneid(credp)); 667843e1988Sjohnlev rw_exit(&vnic_lock); 668da14cebeSEric Cheng return (rc); 669843e1988Sjohnlev } 670843e1988Sjohnlev 6711a41ca23SJerry Jelinek vnic_cleanup_secondary_macs(vnic, vnic->vn_nhandles); 6721a41ca23SJerry Jelinek 6732c4ec682SEric Cheng vnic->vn_enabled = B_FALSE; 674843e1988Sjohnlev (void) mod_hash_remove(vnic_hash, VNIC_HASH_KEY(vnic_id), &val); 675843e1988Sjohnlev ASSERT(vnic == (vnic_t *)val); 676843e1988Sjohnlev vnic_count--; 677843e1988Sjohnlev rw_exit(&vnic_lock); 678da14cebeSEric Cheng 679da14cebeSEric Cheng /* 680da14cebeSEric Cheng * XXX-nicolas shouldn't have a void cast here, if it's 681da14cebeSEric Cheng * expected that the function will never fail, then we should 682da14cebeSEric Cheng * have an ASSERT(). 683da14cebeSEric Cheng */ 684da14cebeSEric Cheng (void) mac_unregister(vnic->vn_mh); 685da14cebeSEric Cheng 686da14cebeSEric Cheng if (vnic->vn_lower_mh != NULL) { 687da14cebeSEric Cheng /* 688da14cebeSEric Cheng * Check if MAC address for the vnic was obtained from the 689da14cebeSEric Cheng * factory MAC addresses. If yes, release it. 690da14cebeSEric Cheng */ 691da14cebeSEric Cheng if (vnic->vn_addr_type == VNIC_MAC_ADDR_TYPE_FACTORY) { 692da14cebeSEric Cheng (void) mac_addr_factory_release(vnic->vn_mch, 693da14cebeSEric Cheng vnic->vn_slot_id); 694da14cebeSEric Cheng } 695da14cebeSEric Cheng (void) mac_margin_remove(vnic->vn_lower_mh, vnic->vn_margin); 696a776d98eSRobert Mustacchi (void) mac_mtu_remove(vnic->vn_lower_mh, vnic->vn_mtu); 697da14cebeSEric Cheng (void) mac_notify_remove(vnic->vn_mnh, B_TRUE); 698da14cebeSEric Cheng (void) mac_unicast_remove(vnic->vn_mch, vnic->vn_muh); 699da14cebeSEric Cheng mac_client_close(vnic->vn_mch, MAC_CLOSE_FLAGS_IS_VNIC); 700da14cebeSEric Cheng mac_close(vnic->vn_lower_mh); 701da14cebeSEric Cheng } 702da14cebeSEric Cheng 703da14cebeSEric Cheng kmem_cache_free(vnic_cache, vnic); 704843e1988Sjohnlev return (0); 705843e1988Sjohnlev } 706843e1988Sjohnlev 707da14cebeSEric Cheng /* ARGSUSED */ 708843e1988Sjohnlev mblk_t * 709843e1988Sjohnlev vnic_m_tx(void *arg, mblk_t *mp_chain) 710843e1988Sjohnlev { 711843e1988Sjohnlev /* 712da14cebeSEric Cheng * This function could be invoked for an anchor VNIC when sending 713da14cebeSEric Cheng * broadcast and multicast packets, and unicast packets which did 714da14cebeSEric Cheng * not match any local known destination. 715843e1988Sjohnlev */ 716da14cebeSEric Cheng freemsgchain(mp_chain); 717da14cebeSEric Cheng return (NULL); 718843e1988Sjohnlev } 719843e1988Sjohnlev 720843e1988Sjohnlev /*ARGSUSED*/ 721843e1988Sjohnlev static void 722da14cebeSEric Cheng vnic_m_ioctl(void *arg, queue_t *q, mblk_t *mp) 723843e1988Sjohnlev { 724da14cebeSEric Cheng miocnak(q, mp, 0, ENOTSUP); 725843e1988Sjohnlev } 726843e1988Sjohnlev 727da14cebeSEric Cheng /* 728da14cebeSEric Cheng * This entry point cannot be passed-through, since it is invoked 729da14cebeSEric Cheng * for the per-VNIC kstats which must be exported independently 730da14cebeSEric Cheng * of the existence of VNIC MAC clients. 731da14cebeSEric Cheng */ 732843e1988Sjohnlev static int 733843e1988Sjohnlev vnic_m_stat(void *arg, uint_t stat, uint64_t *val) 734843e1988Sjohnlev { 735843e1988Sjohnlev vnic_t *vnic = arg; 736843e1988Sjohnlev int rval = 0; 737843e1988Sjohnlev 738da14cebeSEric Cheng if (vnic->vn_lower_mh == NULL) { 739da14cebeSEric Cheng /* 740da14cebeSEric Cheng * It's an anchor VNIC, which does not have any 741da14cebeSEric Cheng * statistics in itself. 742da14cebeSEric Cheng */ 743da14cebeSEric Cheng return (ENOTSUP); 744da14cebeSEric Cheng } 745da14cebeSEric Cheng 746da14cebeSEric Cheng /* 747da14cebeSEric Cheng * ENOTSUP must be reported for unsupported stats, the VNIC 748da14cebeSEric Cheng * driver reports a subset of the stats that would 749da14cebeSEric Cheng * be returned by a real piece of hardware. 750da14cebeSEric Cheng */ 751843e1988Sjohnlev 752843e1988Sjohnlev switch (stat) { 753da14cebeSEric Cheng case MAC_STAT_LINK_STATE: 754da14cebeSEric Cheng case MAC_STAT_LINK_UP: 755da14cebeSEric Cheng case MAC_STAT_PROMISC: 756843e1988Sjohnlev case MAC_STAT_IFSPEED: 757843e1988Sjohnlev case MAC_STAT_MULTIRCV: 758843e1988Sjohnlev case MAC_STAT_MULTIXMT: 759da14cebeSEric Cheng case MAC_STAT_BRDCSTRCV: 760843e1988Sjohnlev case MAC_STAT_BRDCSTXMT: 761843e1988Sjohnlev case MAC_STAT_OPACKETS: 762da14cebeSEric Cheng case MAC_STAT_OBYTES: 763da14cebeSEric Cheng case MAC_STAT_IERRORS: 764da14cebeSEric Cheng case MAC_STAT_OERRORS: 765da14cebeSEric Cheng case MAC_STAT_RBYTES: 766da14cebeSEric Cheng case MAC_STAT_IPACKETS: 767da14cebeSEric Cheng *val = mac_client_stat_get(vnic->vn_mch, stat); 768843e1988Sjohnlev break; 769843e1988Sjohnlev default: 770843e1988Sjohnlev rval = ENOTSUP; 771843e1988Sjohnlev } 772843e1988Sjohnlev 773843e1988Sjohnlev return (rval); 774843e1988Sjohnlev } 775843e1988Sjohnlev 776843e1988Sjohnlev /* 777da14cebeSEric Cheng * Invoked by the upper MAC to retrieve the lower MAC client handle 778da14cebeSEric Cheng * corresponding to a VNIC. A pointer to this function is obtained 779da14cebeSEric Cheng * by the upper MAC via capability query. 780da14cebeSEric Cheng * 781da14cebeSEric Cheng * XXX-nicolas Note: this currently causes all VNIC MAC clients to 782da14cebeSEric Cheng * receive the same MAC client handle for the same VNIC. This is ok 783da14cebeSEric Cheng * as long as we have only one VNIC MAC client which sends and 784da14cebeSEric Cheng * receives data, but we don't currently enforce this at the MAC layer. 785da14cebeSEric Cheng */ 786da14cebeSEric Cheng static void * 787da14cebeSEric Cheng vnic_mac_client_handle(void *vnic_arg) 788da14cebeSEric Cheng { 789da14cebeSEric Cheng vnic_t *vnic = vnic_arg; 790da14cebeSEric Cheng 791da14cebeSEric Cheng return (vnic->vn_mch); 792da14cebeSEric Cheng } 793da14cebeSEric Cheng 7941a41ca23SJerry Jelinek /* 7951a41ca23SJerry Jelinek * Invoked when updating the primary MAC so that the secondary MACs are 7961a41ca23SJerry Jelinek * kept in sync. 7971a41ca23SJerry Jelinek */ 7981a41ca23SJerry Jelinek static void 7991a41ca23SJerry Jelinek vnic_mac_secondary_update(void *vnic_arg) 8001a41ca23SJerry Jelinek { 8011a41ca23SJerry Jelinek vnic_t *vn = vnic_arg; 8021a41ca23SJerry Jelinek int i; 8031a41ca23SJerry Jelinek 8041a41ca23SJerry Jelinek for (i = 1; i <= vn->vn_nhandles; i++) { 8051a41ca23SJerry Jelinek mac_secondary_dup(vn->vn_mc_handles[0], vn->vn_mc_handles[i]); 8061a41ca23SJerry Jelinek } 8071a41ca23SJerry Jelinek } 808da14cebeSEric Cheng 809da14cebeSEric Cheng /* 810843e1988Sjohnlev * Return information about the specified capability. 811843e1988Sjohnlev */ 812843e1988Sjohnlev /* ARGSUSED */ 813843e1988Sjohnlev static boolean_t 814843e1988Sjohnlev vnic_m_capab_get(void *arg, mac_capab_t cap, void *cap_data) 815843e1988Sjohnlev { 816843e1988Sjohnlev vnic_t *vnic = arg; 817843e1988Sjohnlev 818843e1988Sjohnlev switch (cap) { 819843e1988Sjohnlev case MAC_CAPAB_HCKSUM: { 820843e1988Sjohnlev uint32_t *hcksum_txflags = cap_data; 821843e1988Sjohnlev 822843e1988Sjohnlev *hcksum_txflags = vnic->vn_hcksum_txflags & 823843e1988Sjohnlev (HCKSUM_INET_FULL_V4 | HCKSUM_IPHDRCKSUM | 824843e1988Sjohnlev HCKSUM_INET_PARTIAL); 825843e1988Sjohnlev break; 826843e1988Sjohnlev } 827da14cebeSEric Cheng case MAC_CAPAB_VNIC: { 828da14cebeSEric Cheng mac_capab_vnic_t *vnic_capab = cap_data; 829da14cebeSEric Cheng 830da14cebeSEric Cheng if (vnic->vn_lower_mh == NULL) { 831da14cebeSEric Cheng /* 832da14cebeSEric Cheng * It's an anchor VNIC, we don't have an underlying 833da14cebeSEric Cheng * NIC and MAC client handle. 834da14cebeSEric Cheng */ 835da14cebeSEric Cheng return (B_FALSE); 836da14cebeSEric Cheng } 837da14cebeSEric Cheng 838da14cebeSEric Cheng if (vnic_capab != NULL) { 839da14cebeSEric Cheng vnic_capab->mcv_arg = vnic; 840da14cebeSEric Cheng vnic_capab->mcv_mac_client_handle = 841da14cebeSEric Cheng vnic_mac_client_handle; 8421a41ca23SJerry Jelinek vnic_capab->mcv_mac_secondary_update = 8431a41ca23SJerry Jelinek vnic_mac_secondary_update; 844da14cebeSEric Cheng } 845da14cebeSEric Cheng break; 846da14cebeSEric Cheng } 847da14cebeSEric Cheng case MAC_CAPAB_ANCHOR_VNIC: { 848da14cebeSEric Cheng /* since it's an anchor VNIC we don't have lower mac handle */ 849da14cebeSEric Cheng if (vnic->vn_lower_mh == NULL) { 850da14cebeSEric Cheng ASSERT(vnic->vn_link_id == 0); 851da14cebeSEric Cheng return (B_TRUE); 852da14cebeSEric Cheng } 853da14cebeSEric Cheng return (B_FALSE); 854da14cebeSEric Cheng } 855da14cebeSEric Cheng case MAC_CAPAB_NO_NATIVEVLAN: 8569056fcebSCathy Zhou return (B_FALSE); 857da14cebeSEric Cheng case MAC_CAPAB_NO_ZCOPY: 858da14cebeSEric Cheng return (B_TRUE); 8591cb875aeSCathy Zhou case MAC_CAPAB_VRRP: { 8601cb875aeSCathy Zhou mac_capab_vrrp_t *vrrp_capab = cap_data; 8611cb875aeSCathy Zhou 8621cb875aeSCathy Zhou if (vnic->vn_vrid != 0) { 8631cb875aeSCathy Zhou if (vrrp_capab != NULL) 8641cb875aeSCathy Zhou vrrp_capab->mcv_af = vnic->vn_af; 8651cb875aeSCathy Zhou return (B_TRUE); 8661cb875aeSCathy Zhou } 8671cb875aeSCathy Zhou return (B_FALSE); 8681cb875aeSCathy Zhou } 869843e1988Sjohnlev default: 870843e1988Sjohnlev return (B_FALSE); 871843e1988Sjohnlev } 872843e1988Sjohnlev return (B_TRUE); 873843e1988Sjohnlev } 874843e1988Sjohnlev 875da14cebeSEric Cheng /* ARGSUSED */ 876843e1988Sjohnlev static int 877843e1988Sjohnlev vnic_m_start(void *arg) 878843e1988Sjohnlev { 879843e1988Sjohnlev return (0); 880843e1988Sjohnlev } 881843e1988Sjohnlev 882da14cebeSEric Cheng /* ARGSUSED */ 883843e1988Sjohnlev static void 884843e1988Sjohnlev vnic_m_stop(void *arg) 885843e1988Sjohnlev { 886843e1988Sjohnlev } 887843e1988Sjohnlev 888843e1988Sjohnlev /* ARGSUSED */ 889843e1988Sjohnlev static int 890843e1988Sjohnlev vnic_m_promisc(void *arg, boolean_t on) 891843e1988Sjohnlev { 892843e1988Sjohnlev return (0); 893843e1988Sjohnlev } 894843e1988Sjohnlev 895da14cebeSEric Cheng /* ARGSUSED */ 896da14cebeSEric Cheng static int 897da14cebeSEric Cheng vnic_m_multicst(void *arg, boolean_t add, const uint8_t *addrp) 898843e1988Sjohnlev { 899da14cebeSEric Cheng return (0); 900843e1988Sjohnlev } 901843e1988Sjohnlev 902da14cebeSEric Cheng static int 903da14cebeSEric Cheng vnic_m_unicst(void *arg, const uint8_t *macaddr) 904da14cebeSEric Cheng { 905da14cebeSEric Cheng vnic_t *vnic = arg; 906da14cebeSEric Cheng 907da14cebeSEric Cheng return (mac_vnic_unicast_set(vnic->vn_mch, macaddr)); 908da14cebeSEric Cheng } 909da14cebeSEric Cheng 9101a41ca23SJerry Jelinek static void 9111a41ca23SJerry Jelinek vnic_cleanup_secondary_macs(vnic_t *vn, int cnt) 9121a41ca23SJerry Jelinek { 9131a41ca23SJerry Jelinek int i; 9141a41ca23SJerry Jelinek 9151a41ca23SJerry Jelinek /* Remove existing secondaries (primary is at 0) */ 9161a41ca23SJerry Jelinek for (i = 1; i <= cnt; i++) { 9171a41ca23SJerry Jelinek mac_rx_clear(vn->vn_mc_handles[i]); 9181a41ca23SJerry Jelinek 9191a41ca23SJerry Jelinek /* unicast handle might not have been set yet */ 9201a41ca23SJerry Jelinek if (vn->vn_mu_handles[i] != NULL) 9211a41ca23SJerry Jelinek (void) mac_unicast_remove(vn->vn_mc_handles[i], 9221a41ca23SJerry Jelinek vn->vn_mu_handles[i]); 9231a41ca23SJerry Jelinek 9241a41ca23SJerry Jelinek mac_secondary_cleanup(vn->vn_mc_handles[i]); 9251a41ca23SJerry Jelinek 9261a41ca23SJerry Jelinek mac_client_close(vn->vn_mc_handles[i], MAC_CLOSE_FLAGS_IS_VNIC); 9271a41ca23SJerry Jelinek 9281a41ca23SJerry Jelinek vn->vn_mu_handles[i] = NULL; 9291a41ca23SJerry Jelinek vn->vn_mc_handles[i] = NULL; 9301a41ca23SJerry Jelinek } 9311a41ca23SJerry Jelinek 9321a41ca23SJerry Jelinek vn->vn_nhandles = 0; 9331a41ca23SJerry Jelinek } 9341a41ca23SJerry Jelinek 9351a41ca23SJerry Jelinek /* 9361a41ca23SJerry Jelinek * Setup secondary MAC addresses on the vnic. Due to limitations in the mac 9371a41ca23SJerry Jelinek * code, each mac address must be associated with a mac_client (and the 9381a41ca23SJerry Jelinek * flow that goes along with the client) so we need to create those clients 9391a41ca23SJerry Jelinek * here. 9401a41ca23SJerry Jelinek */ 9411a41ca23SJerry Jelinek static int 9421a41ca23SJerry Jelinek vnic_set_secondary_macs(vnic_t *vn, mac_secondary_addr_t *msa) 9431a41ca23SJerry Jelinek { 9441a41ca23SJerry Jelinek int i, err; 9451a41ca23SJerry Jelinek char primary_name[MAXNAMELEN]; 9461a41ca23SJerry Jelinek 9471a41ca23SJerry Jelinek /* First, remove pre-existing secondaries */ 9481a41ca23SJerry Jelinek ASSERT(vn->vn_nhandles < MPT_MAXMACADDR); 9491a41ca23SJerry Jelinek vnic_cleanup_secondary_macs(vn, vn->vn_nhandles); 9501a41ca23SJerry Jelinek 9511a41ca23SJerry Jelinek if (msa->ms_addrcnt == (uint32_t)-1) 9521a41ca23SJerry Jelinek msa->ms_addrcnt = 0; 9531a41ca23SJerry Jelinek 9541a41ca23SJerry Jelinek vn->vn_nhandles = msa->ms_addrcnt; 9551a41ca23SJerry Jelinek 9561a41ca23SJerry Jelinek (void) dls_mgmt_get_linkinfo(vn->vn_id, primary_name, NULL, NULL, NULL); 9571a41ca23SJerry Jelinek 9581a41ca23SJerry Jelinek /* 9591a41ca23SJerry Jelinek * Now add the new secondary MACs 9601a41ca23SJerry Jelinek * Recall that the primary MAC address is the first element. 9611a41ca23SJerry Jelinek * The secondary clients are named after the primary with their 9621a41ca23SJerry Jelinek * index to distinguish them. 9631a41ca23SJerry Jelinek */ 9641a41ca23SJerry Jelinek for (i = 1; i <= vn->vn_nhandles; i++) { 9651a41ca23SJerry Jelinek uint8_t *addr; 9661a41ca23SJerry Jelinek mac_diag_t mac_diag; 9671a41ca23SJerry Jelinek char secondary_name[MAXNAMELEN]; 9681a41ca23SJerry Jelinek 9691a41ca23SJerry Jelinek (void) snprintf(secondary_name, sizeof (secondary_name), 9701a41ca23SJerry Jelinek "%s%02d", primary_name, i); 9711a41ca23SJerry Jelinek 9721a41ca23SJerry Jelinek err = mac_client_open(vn->vn_lower_mh, &vn->vn_mc_handles[i], 9731a41ca23SJerry Jelinek secondary_name, MAC_OPEN_FLAGS_IS_VNIC); 9741a41ca23SJerry Jelinek if (err != 0) { 9751a41ca23SJerry Jelinek /* Remove any that we successfully added */ 9761a41ca23SJerry Jelinek vnic_cleanup_secondary_macs(vn, --i); 9771a41ca23SJerry Jelinek return (err); 9781a41ca23SJerry Jelinek } 9791a41ca23SJerry Jelinek 9801a41ca23SJerry Jelinek /* 9811a41ca23SJerry Jelinek * Assign a MAC address to the VNIC 9821a41ca23SJerry Jelinek * 9831a41ca23SJerry Jelinek * Normally this would be done with vnic_unicast_add but since 9841a41ca23SJerry Jelinek * we know these are fixed adddresses, and since we need to 9851a41ca23SJerry Jelinek * save this in the proper array slot, we bypass that function 9861a41ca23SJerry Jelinek * and go direct. 9871a41ca23SJerry Jelinek */ 9881a41ca23SJerry Jelinek addr = msa->ms_addrs[i - 1]; 9891a41ca23SJerry Jelinek err = mac_unicast_add(vn->vn_mc_handles[i], addr, 0, 9901a41ca23SJerry Jelinek &vn->vn_mu_handles[i], vn->vn_vid, &mac_diag); 9911a41ca23SJerry Jelinek if (err != 0) { 9921a41ca23SJerry Jelinek /* Remove any that we successfully added */ 9931a41ca23SJerry Jelinek vnic_cleanup_secondary_macs(vn, i); 9941a41ca23SJerry Jelinek return (err); 9951a41ca23SJerry Jelinek } 9961a41ca23SJerry Jelinek 9971a41ca23SJerry Jelinek /* 9981a41ca23SJerry Jelinek * Setup the secondary the same way as the primary (i.e. 9991a41ca23SJerry Jelinek * receiver function/argument (e.g. i_dls_link_rx, mac_pkt_drop, 10001a41ca23SJerry Jelinek * etc.), the promisc list, and the resource controls). 10011a41ca23SJerry Jelinek */ 10021a41ca23SJerry Jelinek mac_secondary_dup(vn->vn_mc_handles[0], vn->vn_mc_handles[i]); 10031a41ca23SJerry Jelinek } 10041a41ca23SJerry Jelinek 10051a41ca23SJerry Jelinek return (0); 10061a41ca23SJerry Jelinek } 10071a41ca23SJerry Jelinek 10081a41ca23SJerry Jelinek static int 10091a41ca23SJerry Jelinek vnic_get_secondary_macs(vnic_t *vn, uint_t pr_valsize, void *pr_val) 10101a41ca23SJerry Jelinek { 10111a41ca23SJerry Jelinek int i; 10121a41ca23SJerry Jelinek mac_secondary_addr_t msa; 10131a41ca23SJerry Jelinek 10141a41ca23SJerry Jelinek if (pr_valsize < sizeof (msa)) 10151a41ca23SJerry Jelinek return (EINVAL); 10161a41ca23SJerry Jelinek 10171a41ca23SJerry Jelinek /* Get existing addresses (primary is at 0) */ 10181a41ca23SJerry Jelinek ASSERT(vn->vn_nhandles < MPT_MAXMACADDR); 10191a41ca23SJerry Jelinek for (i = 1; i <= vn->vn_nhandles; i++) { 10201a41ca23SJerry Jelinek ASSERT(vn->vn_mc_handles[i] != NULL); 10211a41ca23SJerry Jelinek mac_unicast_secondary_get(vn->vn_mc_handles[i], 10221a41ca23SJerry Jelinek msa.ms_addrs[i - 1]); 10231a41ca23SJerry Jelinek } 10241a41ca23SJerry Jelinek msa.ms_addrcnt = vn->vn_nhandles; 10251a41ca23SJerry Jelinek 10261a41ca23SJerry Jelinek bcopy(&msa, pr_val, sizeof (msa)); 10271a41ca23SJerry Jelinek return (0); 10281a41ca23SJerry Jelinek } 10291a41ca23SJerry Jelinek 1030ab6f61efSGirish Moodalbail /* 1031ab6f61efSGirish Moodalbail * Callback functions for set/get of properties 1032ab6f61efSGirish Moodalbail */ 1033ab6f61efSGirish Moodalbail /*ARGSUSED*/ 1034ab6f61efSGirish Moodalbail static int 1035ab6f61efSGirish Moodalbail vnic_m_setprop(void *m_driver, const char *pr_name, mac_prop_id_t pr_num, 1036ab6f61efSGirish Moodalbail uint_t pr_valsize, const void *pr_val) 1037ab6f61efSGirish Moodalbail { 10381a41ca23SJerry Jelinek int err = 0; 1039ab6f61efSGirish Moodalbail vnic_t *vn = m_driver; 1040ab6f61efSGirish Moodalbail 1041ab6f61efSGirish Moodalbail switch (pr_num) { 1042ab6f61efSGirish Moodalbail case MAC_PROP_MTU: { 1043ab6f61efSGirish Moodalbail uint32_t mtu; 1044ab6f61efSGirish Moodalbail 1045ab6f61efSGirish Moodalbail if (pr_valsize < sizeof (mtu)) { 1046ab6f61efSGirish Moodalbail err = EINVAL; 1047ab6f61efSGirish Moodalbail break; 1048ab6f61efSGirish Moodalbail } 1049ab6f61efSGirish Moodalbail bcopy(pr_val, &mtu, sizeof (mtu)); 1050a776d98eSRobert Mustacchi 1051a776d98eSRobert Mustacchi if (vn->vn_link_id == DATALINK_INVALID_LINKID) { 1052a776d98eSRobert Mustacchi if (mtu < ANCHOR_VNIC_MIN_MTU || 1053a776d98eSRobert Mustacchi mtu > ANCHOR_VNIC_MAX_MTU) { 1054f0f2c3a5SGirish Moodalbail err = EINVAL; 1055f0f2c3a5SGirish Moodalbail break; 1056f0f2c3a5SGirish Moodalbail } 1057a776d98eSRobert Mustacchi } else { 1058a776d98eSRobert Mustacchi err = mac_mtu_add(vn->vn_lower_mh, &mtu, B_FALSE); 1059a776d98eSRobert Mustacchi /* 1060a776d98eSRobert Mustacchi * If it's not supported to set a value here, translate 1061a776d98eSRobert Mustacchi * that to EINVAL, so user land gets a better idea of 1062a776d98eSRobert Mustacchi * what went wrong. This realistically means that they 1063a776d98eSRobert Mustacchi * violated the output of prop info. 1064a776d98eSRobert Mustacchi */ 1065a776d98eSRobert Mustacchi if (err == ENOTSUP) 1066a776d98eSRobert Mustacchi err = EINVAL; 1067a776d98eSRobert Mustacchi if (err != 0) 1068a776d98eSRobert Mustacchi break; 1069a776d98eSRobert Mustacchi VERIFY(mac_mtu_remove(vn->vn_lower_mh, 1070a776d98eSRobert Mustacchi vn->vn_mtu) == 0); 1071a776d98eSRobert Mustacchi } 1072a776d98eSRobert Mustacchi vn->vn_mtu = mtu; 1073ab6f61efSGirish Moodalbail err = mac_maxsdu_update(vn->vn_mh, mtu); 1074ab6f61efSGirish Moodalbail break; 1075ab6f61efSGirish Moodalbail } 1076*098d2c75SRobert Mustacchi case MAC_PROP_VN_PROMISC_FILTERED: { 1077*098d2c75SRobert Mustacchi boolean_t filtered; 1078*098d2c75SRobert Mustacchi 1079*098d2c75SRobert Mustacchi if (pr_valsize < sizeof (filtered)) { 1080*098d2c75SRobert Mustacchi err = EINVAL; 1081*098d2c75SRobert Mustacchi break; 1082*098d2c75SRobert Mustacchi } 1083*098d2c75SRobert Mustacchi 1084*098d2c75SRobert Mustacchi bcopy(pr_val, &filtered, sizeof (filtered)); 1085*098d2c75SRobert Mustacchi mac_set_promisc_filtered(vn->vn_mch, filtered); 1086*098d2c75SRobert Mustacchi break; 1087*098d2c75SRobert Mustacchi } 10881a41ca23SJerry Jelinek case MAC_PROP_SECONDARY_ADDRS: { 10891a41ca23SJerry Jelinek mac_secondary_addr_t msa; 10901a41ca23SJerry Jelinek 10911a41ca23SJerry Jelinek bcopy(pr_val, &msa, sizeof (msa)); 10921a41ca23SJerry Jelinek err = vnic_set_secondary_macs(vn, &msa); 10931a41ca23SJerry Jelinek break; 10941a41ca23SJerry Jelinek } 1095ab6f61efSGirish Moodalbail default: 10961a41ca23SJerry Jelinek err = ENOTSUP; 1097ab6f61efSGirish Moodalbail break; 1098ab6f61efSGirish Moodalbail } 1099ab6f61efSGirish Moodalbail return (err); 1100ab6f61efSGirish Moodalbail } 1101ab6f61efSGirish Moodalbail 1102ab6f61efSGirish Moodalbail /* ARGSUSED */ 11031a41ca23SJerry Jelinek static int 11041a41ca23SJerry Jelinek vnic_m_getprop(void *arg, const char *pr_name, mac_prop_id_t pr_num, 11051a41ca23SJerry Jelinek uint_t pr_valsize, void *pr_val) 11061a41ca23SJerry Jelinek { 11071a41ca23SJerry Jelinek vnic_t *vn = arg; 11081a41ca23SJerry Jelinek int ret = 0; 1109*098d2c75SRobert Mustacchi boolean_t out; 11101a41ca23SJerry Jelinek 11111a41ca23SJerry Jelinek switch (pr_num) { 1112*098d2c75SRobert Mustacchi case MAC_PROP_VN_PROMISC_FILTERED: 1113*098d2c75SRobert Mustacchi out = mac_get_promisc_filtered(vn->vn_mch); 1114*098d2c75SRobert Mustacchi ASSERT(pr_valsize >= sizeof (boolean_t)); 1115*098d2c75SRobert Mustacchi bcopy(&out, pr_val, sizeof (boolean_t)); 1116*098d2c75SRobert Mustacchi break; 11171a41ca23SJerry Jelinek case MAC_PROP_SECONDARY_ADDRS: 11181a41ca23SJerry Jelinek ret = vnic_get_secondary_macs(vn, pr_valsize, pr_val); 11191a41ca23SJerry Jelinek break; 11201a41ca23SJerry Jelinek default: 1121238d8f47SDale Ghent ret = ENOTSUP; 11221a41ca23SJerry Jelinek break; 11231a41ca23SJerry Jelinek } 11241a41ca23SJerry Jelinek 11251a41ca23SJerry Jelinek return (ret); 11261a41ca23SJerry Jelinek } 11271a41ca23SJerry Jelinek 11281a41ca23SJerry Jelinek /* ARGSUSED */ 11290dc2366fSVenugopal Iyer static void vnic_m_propinfo(void *m_driver, const char *pr_name, 11300dc2366fSVenugopal Iyer mac_prop_id_t pr_num, mac_prop_info_handle_t prh) 1131ab6f61efSGirish Moodalbail { 1132f0f2c3a5SGirish Moodalbail vnic_t *vn = m_driver; 1133f0f2c3a5SGirish Moodalbail 1134f0f2c3a5SGirish Moodalbail switch (pr_num) { 1135f0f2c3a5SGirish Moodalbail case MAC_PROP_MTU: 1136a776d98eSRobert Mustacchi if (vn->vn_link_id == DATALINK_INVALID_LINKID) { 11370dc2366fSVenugopal Iyer mac_prop_info_set_range_uint32(prh, 11380dc2366fSVenugopal Iyer ANCHOR_VNIC_MIN_MTU, ANCHOR_VNIC_MAX_MTU); 1139a776d98eSRobert Mustacchi } else { 1140a776d98eSRobert Mustacchi uint32_t max; 1141a776d98eSRobert Mustacchi mac_perim_handle_t mph; 1142a776d98eSRobert Mustacchi mac_propval_range_t range; 1143a776d98eSRobert Mustacchi 1144a776d98eSRobert Mustacchi /* 1145a776d98eSRobert Mustacchi * The valid range for a VNIC's MTU is the minimum that 1146a776d98eSRobert Mustacchi * the device supports and the current value of the 1147a776d98eSRobert Mustacchi * device. A VNIC cannot increase the current MTU of the 1148a776d98eSRobert Mustacchi * device. Therefore we need to get the range from the 1149a776d98eSRobert Mustacchi * propinfo endpoint and current mtu from the 1150a776d98eSRobert Mustacchi * traditional property endpoint. 1151a776d98eSRobert Mustacchi */ 1152a776d98eSRobert Mustacchi mac_perim_enter_by_mh(vn->vn_lower_mh, &mph); 1153a776d98eSRobert Mustacchi if (mac_get_prop(vn->vn_lower_mh, MAC_PROP_MTU, "mtu", 1154a776d98eSRobert Mustacchi &max, sizeof (uint32_t)) != 0) { 1155a776d98eSRobert Mustacchi mac_perim_exit(mph); 1156a776d98eSRobert Mustacchi return; 1157a776d98eSRobert Mustacchi } 1158a776d98eSRobert Mustacchi 1159a776d98eSRobert Mustacchi range.mpr_count = 1; 1160a776d98eSRobert Mustacchi if (mac_prop_info(vn->vn_lower_mh, MAC_PROP_MTU, "mtu", 1161a776d98eSRobert Mustacchi NULL, 0, &range, NULL) != 0) { 1162a776d98eSRobert Mustacchi mac_perim_exit(mph); 1163a776d98eSRobert Mustacchi return; 1164a776d98eSRobert Mustacchi } 1165a776d98eSRobert Mustacchi 1166a776d98eSRobert Mustacchi mac_prop_info_set_default_uint32(prh, max); 1167a776d98eSRobert Mustacchi mac_prop_info_set_range_uint32(prh, 1168a776d98eSRobert Mustacchi range.mpr_range_uint32[0].mpur_min, max); 1169a776d98eSRobert Mustacchi mac_perim_exit(mph); 1170a776d98eSRobert Mustacchi } 1171f0f2c3a5SGirish Moodalbail break; 1172ab6f61efSGirish Moodalbail } 1173f0f2c3a5SGirish Moodalbail } 1174ab6f61efSGirish Moodalbail 11750dc2366fSVenugopal Iyer 1176da14cebeSEric Cheng int 11772b24ab6bSSebastien Roy vnic_info(vnic_info_t *info, cred_t *credp) 1178843e1988Sjohnlev { 1179843e1988Sjohnlev vnic_t *vnic; 1180da14cebeSEric Cheng int err; 1181843e1988Sjohnlev 11822b24ab6bSSebastien Roy /* Make sure that the VNIC link is visible from the caller's zone. */ 11832b24ab6bSSebastien Roy if (!dls_devnet_islinkvisible(info->vn_vnic_id, crgetzoneid(credp))) 11842b24ab6bSSebastien Roy return (ENOENT); 11852b24ab6bSSebastien Roy 1186da14cebeSEric Cheng rw_enter(&vnic_lock, RW_WRITER); 1187843e1988Sjohnlev 1188da14cebeSEric Cheng err = mod_hash_find(vnic_hash, VNIC_HASH_KEY(info->vn_vnic_id), 1189da14cebeSEric Cheng (mod_hash_val_t *)&vnic); 1190da14cebeSEric Cheng if (err != 0) { 1191da14cebeSEric Cheng rw_exit(&vnic_lock); 1192da14cebeSEric Cheng return (ENOENT); 1193d62bc4baSyz147064 } 1194843e1988Sjohnlev 1195da14cebeSEric Cheng info->vn_link_id = vnic->vn_link_id; 1196da14cebeSEric Cheng info->vn_mac_addr_type = vnic->vn_addr_type; 1197da14cebeSEric Cheng info->vn_mac_len = vnic->vn_addr_len; 1198da14cebeSEric Cheng bcopy(vnic->vn_addr, info->vn_mac_addr, MAXMACADDRLEN); 1199da14cebeSEric Cheng info->vn_mac_slot = vnic->vn_slot_id; 1200da14cebeSEric Cheng info->vn_mac_prefix_len = 0; 1201da14cebeSEric Cheng info->vn_vid = vnic->vn_vid; 1202da14cebeSEric Cheng info->vn_force = vnic->vn_force; 12031cb875aeSCathy Zhou info->vn_vrid = vnic->vn_vrid; 12041cb875aeSCathy Zhou info->vn_af = vnic->vn_af; 1205843e1988Sjohnlev 1206da14cebeSEric Cheng bzero(&info->vn_resource_props, sizeof (mac_resource_props_t)); 1207da14cebeSEric Cheng if (vnic->vn_mch != NULL) 12081a41ca23SJerry Jelinek mac_client_get_resources(vnic->vn_mch, 12091a41ca23SJerry Jelinek &info->vn_resource_props); 1210843e1988Sjohnlev 1211da14cebeSEric Cheng rw_exit(&vnic_lock); 1212da14cebeSEric Cheng return (0); 1213843e1988Sjohnlev } 1214843e1988Sjohnlev 1215843e1988Sjohnlev static void 1216843e1988Sjohnlev vnic_notify_cb(void *arg, mac_notify_type_t type) 1217843e1988Sjohnlev { 1218da14cebeSEric Cheng vnic_t *vnic = arg; 1219843e1988Sjohnlev 1220843e1988Sjohnlev /* 12212c4ec682SEric Cheng * Do not deliver notifications if the vnic is not fully initialized 12222c4ec682SEric Cheng * or is in process of being torn down. 12232c4ec682SEric Cheng */ 12242c4ec682SEric Cheng if (!vnic->vn_enabled) 12252c4ec682SEric Cheng return; 12262c4ec682SEric Cheng 12272c4ec682SEric Cheng switch (type) { 12282c4ec682SEric Cheng case MAC_NOTE_UNICST: 12292c4ec682SEric Cheng /* 1230da14cebeSEric Cheng * Only the VLAN VNIC needs to be notified with primary MAC 1231da14cebeSEric Cheng * address change. 1232843e1988Sjohnlev */ 1233da14cebeSEric Cheng if (vnic->vn_addr_type != VNIC_MAC_ADDR_TYPE_PRIMARY) 1234da14cebeSEric Cheng return; 1235843e1988Sjohnlev 1236da14cebeSEric Cheng /* the unicast MAC address value */ 1237da14cebeSEric Cheng mac_unicast_primary_get(vnic->vn_lower_mh, vnic->vn_addr); 1238843e1988Sjohnlev 1239da14cebeSEric Cheng /* notify its upper layer MAC about MAC address change */ 1240da14cebeSEric Cheng mac_unicst_update(vnic->vn_mh, (const uint8_t *)vnic->vn_addr); 12411d03c31eSjohnlev break; 12422c4ec682SEric Cheng 12432c4ec682SEric Cheng case MAC_NOTE_LINK: 12442c4ec682SEric Cheng mac_link_update(vnic->vn_mh, 12452c4ec682SEric Cheng mac_client_stat_get(vnic->vn_mch, MAC_STAT_LINK_STATE)); 12462c4ec682SEric Cheng break; 12472c4ec682SEric Cheng 1248da14cebeSEric Cheng default: 1249843e1988Sjohnlev break; 1250843e1988Sjohnlev } 1251843e1988Sjohnlev } 1252