1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
  23  * Copyright 2015 Joyent, Inc.
  24  * Copyright 2016 OmniTI Computer Consulting, Inc. All rights reserved.
  25  */
  26 
  27 #include <sys/types.h>
  28 #include <sys/cred.h>
  29 #include <sys/sysmacros.h>
  30 #include <sys/conf.h>
  31 #include <sys/cmn_err.h>
  32 #include <sys/list.h>
  33 #include <sys/ksynch.h>
  34 #include <sys/kmem.h>
  35 #include <sys/stream.h>
  36 #include <sys/modctl.h>
  37 #include <sys/ddi.h>
  38 #include <sys/sunddi.h>
  39 #include <sys/atomic.h>
  40 #include <sys/stat.h>
  41 #include <sys/modhash.h>
  42 #include <sys/strsubr.h>
  43 #include <sys/strsun.h>
  44 #include <sys/dlpi.h>
  45 #include <sys/mac.h>
  46 #include <sys/mac_provider.h>
  47 #include <sys/mac_client.h>
  48 #include <sys/mac_client_priv.h>
  49 #include <sys/mac_ether.h>
  50 #include <sys/dls.h>
  51 #include <sys/pattr.h>
  52 #include <sys/time.h>
  53 #include <sys/vlan.h>
  54 #include <sys/vnic.h>
  55 #include <sys/vnic_impl.h>
  56 #include <sys/mac_flow_impl.h>
  57 #include <inet/ip_impl.h>
  58 
  59 /*
  60  * Note that for best performance, the VNIC is a passthrough design.
  61  * For each VNIC corresponds a MAC client of the underlying MAC (lower MAC).
  62  * This MAC client is opened by the VNIC driver at VNIC creation,
  63  * and closed when the VNIC is deleted.
  64  * When a MAC client of the VNIC itself opens a VNIC, the MAC layer
  65  * (upper MAC) detects that the MAC being opened is a VNIC. Instead
  66  * of allocating a new MAC client, it asks the VNIC driver to return
  67  * the lower MAC client handle associated with the VNIC, and that handle
  68  * is returned to the upper MAC client directly. This allows access
  69  * by upper MAC clients of the VNIC to have direct access to the lower
  70  * MAC client for the control path and data path.
  71  *
  72  * Due to this passthrough, some of the entry points exported by the
  73  * VNIC driver are never directly invoked. These entry points include
  74  * vnic_m_start, vnic_m_stop, vnic_m_promisc, vnic_m_multicst, etc.
  75  *
  76  * VNICs support multiple upper mac clients to enable support for
  77  * multiple MAC addresses on the VNIC. When the VNIC is created the
  78  * initial mac client is the primary upper mac. Any additional mac
  79  * clients are secondary macs.
  80  */
  81 
  82 static int vnic_m_start(void *);
  83 static void vnic_m_stop(void *);
  84 static int vnic_m_promisc(void *, boolean_t);
  85 static int vnic_m_multicst(void *, boolean_t, const uint8_t *);
  86 static int vnic_m_unicst(void *, const uint8_t *);
  87 static int vnic_m_stat(void *, uint_t, uint64_t *);
  88 static void vnic_m_ioctl(void *, queue_t *, mblk_t *);
  89 static int vnic_m_setprop(void *, const char *, mac_prop_id_t, uint_t,
  90     const void *);
  91 static int vnic_m_getprop(void *, const char *, mac_prop_id_t, uint_t, void *);
  92 static void vnic_m_propinfo(void *, const char *, mac_prop_id_t,
  93     mac_prop_info_handle_t);
  94 static mblk_t *vnic_m_tx(void *, mblk_t *);
  95 static boolean_t vnic_m_capab_get(void *, mac_capab_t, void *);
  96 static void vnic_notify_cb(void *, mac_notify_type_t);
  97 static void vnic_cleanup_secondary_macs(vnic_t *, int);
  98 
  99 static kmem_cache_t     *vnic_cache;
 100 static krwlock_t        vnic_lock;
 101 static uint_t           vnic_count;
 102 
 103 #define ANCHOR_VNIC_MIN_MTU     576
 104 #define ANCHOR_VNIC_MAX_MTU     9000
 105 
 106 /* hash of VNICs (vnic_t's), keyed by VNIC id */
 107 static mod_hash_t       *vnic_hash;
 108 #define VNIC_HASHSZ     64
 109 #define VNIC_HASH_KEY(vnic_id)  ((mod_hash_key_t)(uintptr_t)vnic_id)
 110 
 111 #define VNIC_M_CALLBACK_FLAGS   \
 112         (MC_IOCTL | MC_GETCAPAB | MC_SETPROP | MC_GETPROP | MC_PROPINFO)
 113 
 114 static mac_callbacks_t vnic_m_callbacks = {
 115         VNIC_M_CALLBACK_FLAGS,
 116         vnic_m_stat,
 117         vnic_m_start,
 118         vnic_m_stop,
 119         vnic_m_promisc,
 120         vnic_m_multicst,
 121         vnic_m_unicst,
 122         vnic_m_tx,
 123         NULL,
 124         vnic_m_ioctl,
 125         vnic_m_capab_get,
 126         NULL,
 127         NULL,
 128         vnic_m_setprop,
 129         vnic_m_getprop,
 130         vnic_m_propinfo
 131 };
 132 
 133 void
 134 vnic_dev_init(void)
 135 {
 136         vnic_cache = kmem_cache_create("vnic_cache",
 137             sizeof (vnic_t), 0, NULL, NULL, NULL, NULL, NULL, 0);
 138 
 139         vnic_hash = mod_hash_create_idhash("vnic_hash",
 140             VNIC_HASHSZ, mod_hash_null_valdtor);
 141 
 142         rw_init(&vnic_lock, NULL, RW_DEFAULT, NULL);
 143 
 144         vnic_count = 0;
 145 }
 146 
 147 void
 148 vnic_dev_fini(void)
 149 {
 150         ASSERT(vnic_count == 0);
 151 
 152         rw_destroy(&vnic_lock);
 153         mod_hash_destroy_idhash(vnic_hash);
 154         kmem_cache_destroy(vnic_cache);
 155 }
 156 
 157 uint_t
 158 vnic_dev_count(void)
 159 {
 160         return (vnic_count);
 161 }
 162 
 163 static vnic_ioc_diag_t
 164 vnic_mac2vnic_diag(mac_diag_t diag)
 165 {
 166         switch (diag) {
 167         case MAC_DIAG_MACADDR_NIC:
 168                 return (VNIC_IOC_DIAG_MACADDR_NIC);
 169         case MAC_DIAG_MACADDR_INUSE:
 170                 return (VNIC_IOC_DIAG_MACADDR_INUSE);
 171         case MAC_DIAG_MACADDR_INVALID:
 172                 return (VNIC_IOC_DIAG_MACADDR_INVALID);
 173         case MAC_DIAG_MACADDRLEN_INVALID:
 174                 return (VNIC_IOC_DIAG_MACADDRLEN_INVALID);
 175         case MAC_DIAG_MACFACTORYSLOTINVALID:
 176                 return (VNIC_IOC_DIAG_MACFACTORYSLOTINVALID);
 177         case MAC_DIAG_MACFACTORYSLOTUSED:
 178                 return (VNIC_IOC_DIAG_MACFACTORYSLOTUSED);
 179         case MAC_DIAG_MACFACTORYSLOTALLUSED:
 180                 return (VNIC_IOC_DIAG_MACFACTORYSLOTALLUSED);
 181         case MAC_DIAG_MACFACTORYNOTSUP:
 182                 return (VNIC_IOC_DIAG_MACFACTORYNOTSUP);
 183         case MAC_DIAG_MACPREFIX_INVALID:
 184                 return (VNIC_IOC_DIAG_MACPREFIX_INVALID);
 185         case MAC_DIAG_MACPREFIXLEN_INVALID:
 186                 return (VNIC_IOC_DIAG_MACPREFIXLEN_INVALID);
 187         case MAC_DIAG_MACNO_HWRINGS:
 188                 return (VNIC_IOC_DIAG_NO_HWRINGS);
 189         default:
 190                 return (VNIC_IOC_DIAG_NONE);
 191         }
 192 }
 193 
 194 static int
 195 vnic_unicast_add(vnic_t *vnic, vnic_mac_addr_type_t vnic_addr_type,
 196     int *addr_slot, uint_t prefix_len, int *addr_len_ptr_arg,
 197     uint8_t *mac_addr_arg, uint16_t flags, vnic_ioc_diag_t *diag,
 198     uint16_t vid, boolean_t req_hwgrp_flag)
 199 {
 200         mac_diag_t mac_diag;
 201         uint16_t mac_flags = 0;
 202         int err;
 203         uint_t addr_len;
 204 
 205         if (flags & VNIC_IOC_CREATE_NODUPCHECK)
 206                 mac_flags |= MAC_UNICAST_NODUPCHECK;
 207 
 208         switch (vnic_addr_type) {
 209         case VNIC_MAC_ADDR_TYPE_FIXED:
 210         case VNIC_MAC_ADDR_TYPE_VRID:
 211                 /*
 212                  * The MAC address value to assign to the VNIC
 213                  * is already provided in mac_addr_arg. addr_len_ptr_arg
 214                  * already contains the MAC address length.
 215                  */
 216                 break;
 217 
 218         case VNIC_MAC_ADDR_TYPE_RANDOM:
 219                 /*
 220                  * Random MAC address. There are two sub-cases:
 221                  *
 222                  * 1 - If mac_len == 0, a new MAC address is generated.
 223                  *      The length of the MAC address to generated depends
 224                  *      on the type of MAC used. The prefix to use for the MAC
 225                  *      address is stored in the most significant bytes
 226                  *      of the mac_addr argument, and its length is specified
 227                  *      by the mac_prefix_len argument. This prefix can
 228                  *      correspond to a IEEE OUI in the case of Ethernet,
 229                  *      for example.
 230                  *
 231                  * 2 - If mac_len > 0, the address was already picked
 232                  *      randomly, and is now passed back during VNIC
 233                  *      re-creation. The mac_addr argument contains the MAC
 234                  *      address that was generated. We distinguish this
 235                  *      case from the fixed MAC address case, since we
 236                  *      want the user consumers to know, when they query
 237                  *      the list of VNICs, that a VNIC was assigned a
 238                  *      random MAC address vs assigned a fixed address
 239                  *      specified by the user.
 240                  */
 241 
 242                 /*
 243                  * If it's a pre-generated address, we're done. mac_addr_arg
 244                  * and addr_len_ptr_arg already contain the MAC address
 245                  * value and length.
 246                  */
 247                 if (*addr_len_ptr_arg > 0)
 248                         break;
 249 
 250                 /* generate a new random MAC address */
 251                 if ((err = mac_addr_random(vnic->vn_mch,
 252                     prefix_len, mac_addr_arg, &mac_diag)) != 0) {
 253                         *diag = vnic_mac2vnic_diag(mac_diag);
 254                         return (err);
 255                 }
 256                 *addr_len_ptr_arg = mac_addr_len(vnic->vn_lower_mh);
 257                 break;
 258 
 259         case VNIC_MAC_ADDR_TYPE_FACTORY:
 260                 err = mac_addr_factory_reserve(vnic->vn_mch, addr_slot);
 261                 if (err != 0) {
 262                         if (err == EINVAL)
 263                                 *diag = VNIC_IOC_DIAG_MACFACTORYSLOTINVALID;
 264                         if (err == EBUSY)
 265                                 *diag = VNIC_IOC_DIAG_MACFACTORYSLOTUSED;
 266                         if (err == ENOSPC)
 267                                 *diag = VNIC_IOC_DIAG_MACFACTORYSLOTALLUSED;
 268                         return (err);
 269                 }
 270 
 271                 mac_addr_factory_value(vnic->vn_lower_mh, *addr_slot,
 272                     mac_addr_arg, &addr_len, NULL, NULL);
 273                 *addr_len_ptr_arg = addr_len;
 274                 break;
 275 
 276         case VNIC_MAC_ADDR_TYPE_AUTO:
 277                 /* first try to allocate a factory MAC address */
 278                 err = mac_addr_factory_reserve(vnic->vn_mch, addr_slot);
 279                 if (err == 0) {
 280                         mac_addr_factory_value(vnic->vn_lower_mh, *addr_slot,
 281                             mac_addr_arg, &addr_len, NULL, NULL);
 282                         vnic_addr_type = VNIC_MAC_ADDR_TYPE_FACTORY;
 283                         *addr_len_ptr_arg = addr_len;
 284                         break;
 285                 }
 286 
 287                 /*
 288                  * Allocating a factory MAC address failed, generate a
 289                  * random MAC address instead.
 290                  */
 291                 if ((err = mac_addr_random(vnic->vn_mch,
 292                     prefix_len, mac_addr_arg, &mac_diag)) != 0) {
 293                         *diag = vnic_mac2vnic_diag(mac_diag);
 294                         return (err);
 295                 }
 296                 *addr_len_ptr_arg = mac_addr_len(vnic->vn_lower_mh);
 297                 vnic_addr_type = VNIC_MAC_ADDR_TYPE_RANDOM;
 298                 break;
 299         case VNIC_MAC_ADDR_TYPE_PRIMARY:
 300                 /*
 301                  * We get the address here since we copy it in the
 302                  * vnic's vn_addr.
 303                  * We can't ask for hardware resources since we
 304                  * don't currently support hardware classification
 305                  * for these MAC clients.
 306                  */
 307                 if (req_hwgrp_flag) {
 308                         *diag = VNIC_IOC_DIAG_NO_HWRINGS;
 309                         return (ENOTSUP);
 310                 }
 311                 mac_unicast_primary_get(vnic->vn_lower_mh, mac_addr_arg);
 312                 *addr_len_ptr_arg = mac_addr_len(vnic->vn_lower_mh);
 313                 mac_flags |= MAC_UNICAST_VNIC_PRIMARY;
 314                 break;
 315         }
 316 
 317         vnic->vn_addr_type = vnic_addr_type;
 318 
 319         err = mac_unicast_add(vnic->vn_mch, mac_addr_arg, mac_flags,
 320             &vnic->vn_muh, vid, &mac_diag);
 321         if (err != 0) {
 322                 if (vnic_addr_type == VNIC_MAC_ADDR_TYPE_FACTORY) {
 323                         /* release factory MAC address */
 324                         mac_addr_factory_release(vnic->vn_mch, *addr_slot);
 325                 }
 326                 *diag = vnic_mac2vnic_diag(mac_diag);
 327         }
 328 
 329         return (err);
 330 }
 331 
 332 /*
 333  * Create a new VNIC upon request from administrator.
 334  * Returns 0 on success, an errno on failure.
 335  */
 336 /* ARGSUSED */
 337 int
 338 vnic_dev_create(datalink_id_t vnic_id, datalink_id_t linkid,
 339     vnic_mac_addr_type_t *vnic_addr_type, int *mac_len, uchar_t *mac_addr,
 340     int *mac_slot, uint_t mac_prefix_len, uint16_t vid, vrid_t vrid,
 341     int af, mac_resource_props_t *mrp, uint32_t flags, vnic_ioc_diag_t *diag,
 342     cred_t *credp)
 343 {
 344         vnic_t *vnic;
 345         mac_register_t *mac;
 346         int err;
 347         boolean_t is_anchor = ((flags & VNIC_IOC_CREATE_ANCHOR) != 0);
 348         char vnic_name[MAXNAMELEN];
 349         const mac_info_t *minfop;
 350         uint32_t req_hwgrp_flag = B_FALSE;
 351 
 352         *diag = VNIC_IOC_DIAG_NONE;
 353 
 354         rw_enter(&vnic_lock, RW_WRITER);
 355 
 356         /* does a VNIC with the same id already exist? */
 357         err = mod_hash_find(vnic_hash, VNIC_HASH_KEY(vnic_id),
 358             (mod_hash_val_t *)&vnic);
 359         if (err == 0) {
 360                 rw_exit(&vnic_lock);
 361                 return (EEXIST);
 362         }
 363 
 364         vnic = kmem_cache_alloc(vnic_cache, KM_NOSLEEP);
 365         if (vnic == NULL) {
 366                 rw_exit(&vnic_lock);
 367                 return (ENOMEM);
 368         }
 369 
 370         bzero(vnic, sizeof (*vnic));
 371 
 372         vnic->vn_id = vnic_id;
 373         vnic->vn_link_id = linkid;
 374         vnic->vn_vrid = vrid;
 375         vnic->vn_af = af;
 376 
 377         if (!is_anchor) {
 378                 if (linkid == DATALINK_INVALID_LINKID) {
 379                         err = EINVAL;
 380                         goto bail;
 381                 }
 382 
 383                 /*
 384                  * Open the lower MAC and assign its initial bandwidth and
 385                  * MAC address. We do this here during VNIC creation and
 386                  * do not wait until the upper MAC client open so that we
 387                  * can validate the VNIC creation parameters (bandwidth,
 388                  * MAC address, etc) and reserve a factory MAC address if
 389                  * one was requested.
 390                  */
 391                 err = mac_open_by_linkid(linkid, &vnic->vn_lower_mh);
 392                 if (err != 0)
 393                         goto bail;
 394 
 395                 /*
 396                  * VNIC(vlan) over VNICs(vlans) is not supported.
 397                  */
 398                 if (mac_is_vnic(vnic->vn_lower_mh)) {
 399                         err = EINVAL;
 400                         goto bail;
 401                 }
 402 
 403                 /* only ethernet support for now */
 404                 minfop = mac_info(vnic->vn_lower_mh);
 405                 if (minfop->mi_nativemedia != DL_ETHER) {
 406                         err = ENOTSUP;
 407                         goto bail;
 408                 }
 409 
 410                 (void) dls_mgmt_get_linkinfo(vnic_id, vnic_name, NULL, NULL,
 411                     NULL);
 412                 err = mac_client_open(vnic->vn_lower_mh, &vnic->vn_mch,
 413                     vnic_name, MAC_OPEN_FLAGS_IS_VNIC);
 414                 if (err != 0)
 415                         goto bail;
 416 
 417                 /* assign a MAC address to the VNIC */
 418 
 419                 err = vnic_unicast_add(vnic, *vnic_addr_type, mac_slot,
 420                     mac_prefix_len, mac_len, mac_addr, flags, diag, vid,
 421                     req_hwgrp_flag);
 422                 if (err != 0) {
 423                         vnic->vn_muh = NULL;
 424                         if (diag != NULL && req_hwgrp_flag)
 425                                 *diag = VNIC_IOC_DIAG_NO_HWRINGS;
 426                         goto bail;
 427                 }
 428 
 429                 /* register to receive notification from underlying MAC */
 430                 vnic->vn_mnh = mac_notify_add(vnic->vn_lower_mh, vnic_notify_cb,
 431                     vnic);
 432 
 433                 *vnic_addr_type = vnic->vn_addr_type;
 434                 vnic->vn_addr_len = *mac_len;
 435                 vnic->vn_vid = vid;
 436 
 437                 bcopy(mac_addr, vnic->vn_addr, vnic->vn_addr_len);
 438 
 439                 if (vnic->vn_addr_type == VNIC_MAC_ADDR_TYPE_FACTORY)
 440                         vnic->vn_slot_id = *mac_slot;
 441 
 442                 /*
 443                  * Set the initial VNIC capabilities. If the VNIC is created
 444                  * over MACs which does not support nactive vlan, disable
 445                  * VNIC's hardware checksum capability if its VID is not 0,
 446                  * since the underlying MAC would get the hardware checksum
 447                  * offset wrong in case of VLAN packets.
 448                  */
 449                 if (vid == 0 || !mac_capab_get(vnic->vn_lower_mh,
 450                     MAC_CAPAB_NO_NATIVEVLAN, NULL)) {
 451                         if (!mac_capab_get(vnic->vn_lower_mh, MAC_CAPAB_HCKSUM,
 452                             &vnic->vn_hcksum_txflags))
 453                                 vnic->vn_hcksum_txflags = 0;
 454                 } else {
 455                         vnic->vn_hcksum_txflags = 0;
 456                 }
 457         }
 458 
 459         /* register with the MAC module */
 460         if ((mac = mac_alloc(MAC_VERSION)) == NULL)
 461                 goto bail;
 462 
 463         mac->m_type_ident = MAC_PLUGIN_IDENT_ETHER;
 464         mac->m_driver = vnic;
 465         mac->m_dip = vnic_get_dip();
 466         mac->m_instance = (uint_t)-1;
 467         mac->m_src_addr = vnic->vn_addr;
 468         mac->m_callbacks = &vnic_m_callbacks;
 469 
 470         if (!is_anchor) {
 471                 /*
 472                  * If this is a VNIC based VLAN, then we check for the
 473                  * margin unless it has been created with the force
 474                  * flag. If we are configuring a VLAN over an etherstub,
 475                  * we don't check the margin even if force is not set.
 476                  */
 477                 if (vid == 0 || (flags & VNIC_IOC_CREATE_FORCE) != 0) {
 478                         if (vid != VLAN_ID_NONE)
 479                                 vnic->vn_force = B_TRUE;
 480                         /*
 481                          * As the current margin size of the underlying mac is
 482                          * used to determine the margin size of the VNIC
 483                          * itself, request the underlying mac not to change
 484                          * to a smaller margin size.
 485                          */
 486                         err = mac_margin_add(vnic->vn_lower_mh,
 487                             &vnic->vn_margin, B_TRUE);
 488                         ASSERT(err == 0);
 489                 } else {
 490                         vnic->vn_margin = VLAN_TAGSZ;
 491                         err = mac_margin_add(vnic->vn_lower_mh,
 492                             &vnic->vn_margin, B_FALSE);
 493                         if (err != 0) {
 494                                 mac_free(mac);
 495                                 if (diag != NULL)
 496                                         *diag = VNIC_IOC_DIAG_MACMARGIN_INVALID;
 497                                 goto bail;
 498                         }
 499                 }
 500 
 501                 mac_sdu_get(vnic->vn_lower_mh, &mac->m_min_sdu,
 502                     &mac->m_max_sdu);
 503                 err = mac_mtu_add(vnic->vn_lower_mh, &mac->m_max_sdu, B_FALSE);
 504                 if (err != 0) {
 505                         VERIFY(mac_margin_remove(vnic->vn_lower_mh,
 506                             vnic->vn_margin) == 0);
 507                         mac_free(mac);
 508                         if (diag != NULL)
 509                                 *diag = VNIC_IOC_DIAG_MACMTU_INVALID;
 510                         goto bail;
 511                 }
 512                 vnic->vn_mtu = mac->m_max_sdu;
 513         } else {
 514                 vnic->vn_margin = VLAN_TAGSZ;
 515                 mac->m_min_sdu = 1;
 516                 mac->m_max_sdu = ANCHOR_VNIC_MAX_MTU;
 517                 vnic->vn_mtu = ANCHOR_VNIC_MAX_MTU;
 518         }
 519 
 520         mac->m_margin = vnic->vn_margin;
 521 
 522         err = mac_register(mac, &vnic->vn_mh);
 523         mac_free(mac);
 524         if (err != 0) {
 525                 if (!is_anchor) {
 526                         VERIFY(mac_mtu_remove(vnic->vn_lower_mh,
 527                             vnic->vn_mtu) == 0);
 528                         VERIFY(mac_margin_remove(vnic->vn_lower_mh,
 529                             vnic->vn_margin) == 0);
 530                 }
 531                 goto bail;
 532         }
 533 
 534         /* Set the VNIC's MAC in the client */
 535         if (!is_anchor) {
 536                 mac_set_upper_mac(vnic->vn_mch, vnic->vn_mh, mrp);
 537 
 538                 if (mrp != NULL) {
 539                         if ((mrp->mrp_mask & MRP_RX_RINGS) != 0 ||
 540                             (mrp->mrp_mask & MRP_TX_RINGS) != 0) {
 541                                 req_hwgrp_flag = B_TRUE;
 542                         }
 543                         err = mac_client_set_resources(vnic->vn_mch, mrp);
 544                         if (err != 0) {
 545                                 VERIFY(mac_mtu_remove(vnic->vn_lower_mh,
 546                                     vnic->vn_mtu) == 0);
 547                                 VERIFY(mac_margin_remove(vnic->vn_lower_mh,
 548                                     vnic->vn_margin) == 0);
 549                                 (void) mac_unregister(vnic->vn_mh);
 550                                 goto bail;
 551                         }
 552                 }
 553         }
 554 
 555         err = dls_devnet_create(vnic->vn_mh, vnic->vn_id, crgetzoneid(credp));
 556         if (err != 0) {
 557                 VERIFY(is_anchor || mac_margin_remove(vnic->vn_lower_mh,
 558                     vnic->vn_margin) == 0);
 559                 if (!is_anchor) {
 560                         VERIFY(mac_mtu_remove(vnic->vn_lower_mh,
 561                             vnic->vn_mtu) == 0);
 562                         VERIFY(mac_margin_remove(vnic->vn_lower_mh,
 563                             vnic->vn_margin) == 0);
 564                 }
 565                 (void) mac_unregister(vnic->vn_mh);
 566                 goto bail;
 567         }
 568 
 569         /* add new VNIC to hash table */
 570         err = mod_hash_insert(vnic_hash, VNIC_HASH_KEY(vnic_id),
 571             (mod_hash_val_t)vnic);
 572         ASSERT(err == 0);
 573         vnic_count++;
 574 
 575         /*
 576          * Now that we've enabled this VNIC, we should go through and update the
 577          * link state by setting it to our parents.
 578          */
 579         vnic->vn_enabled = B_TRUE;
 580 
 581         if (is_anchor) {
 582                 mac_link_update(vnic->vn_mh, LINK_STATE_UP);
 583         } else {
 584                 mac_link_update(vnic->vn_mh,
 585                     mac_client_stat_get(vnic->vn_mch, MAC_STAT_LINK_STATE));
 586         }
 587 
 588         rw_exit(&vnic_lock);
 589 
 590         return (0);
 591 
 592 bail:
 593         rw_exit(&vnic_lock);
 594         if (!is_anchor) {
 595                 if (vnic->vn_mnh != NULL)
 596                         (void) mac_notify_remove(vnic->vn_mnh, B_TRUE);
 597                 if (vnic->vn_muh != NULL)
 598                         (void) mac_unicast_remove(vnic->vn_mch, vnic->vn_muh);
 599                 if (vnic->vn_mch != NULL)
 600                         mac_client_close(vnic->vn_mch, MAC_CLOSE_FLAGS_IS_VNIC);
 601                 if (vnic->vn_lower_mh != NULL)
 602                         mac_close(vnic->vn_lower_mh);
 603         }
 604 
 605         kmem_cache_free(vnic_cache, vnic);
 606         return (err);
 607 }
 608 
 609 /*
 610  * Modify the properties of an existing VNIC.
 611  */
 612 /* ARGSUSED */
 613 int
 614 vnic_dev_modify(datalink_id_t vnic_id, uint_t modify_mask,
 615     vnic_mac_addr_type_t mac_addr_type, uint_t mac_len, uchar_t *mac_addr,
 616     uint_t mac_slot, mac_resource_props_t *mrp)
 617 {
 618         vnic_t *vnic = NULL;
 619 
 620         rw_enter(&vnic_lock, RW_WRITER);
 621 
 622         if (mod_hash_find(vnic_hash, VNIC_HASH_KEY(vnic_id),
 623             (mod_hash_val_t *)&vnic) != 0) {
 624                 rw_exit(&vnic_lock);
 625                 return (ENOENT);
 626         }
 627 
 628         rw_exit(&vnic_lock);
 629 
 630         return (0);
 631 }
 632 
 633 /* ARGSUSED */
 634 int
 635 vnic_dev_delete(datalink_id_t vnic_id, uint32_t flags, cred_t *credp)
 636 {
 637         vnic_t *vnic = NULL;
 638         mod_hash_val_t val;
 639         datalink_id_t tmpid;
 640         int rc;
 641 
 642         rw_enter(&vnic_lock, RW_WRITER);
 643 
 644         if (mod_hash_find(vnic_hash, VNIC_HASH_KEY(vnic_id),
 645             (mod_hash_val_t *)&vnic) != 0) {
 646                 rw_exit(&vnic_lock);
 647                 return (ENOENT);
 648         }
 649 
 650         if ((rc = dls_devnet_destroy(vnic->vn_mh, &tmpid, B_TRUE)) != 0) {
 651                 rw_exit(&vnic_lock);
 652                 return (rc);
 653         }
 654 
 655         ASSERT(vnic_id == tmpid);
 656 
 657         /*
 658          * We cannot unregister the MAC yet. Unregistering would
 659          * free up mac_impl_t which should not happen at this time.
 660          * So disable mac_impl_t by calling mac_disable(). This will prevent
 661          * any new claims on mac_impl_t.
 662          */
 663         if ((rc = mac_disable(vnic->vn_mh)) != 0) {
 664                 (void) dls_devnet_create(vnic->vn_mh, vnic_id,
 665                     crgetzoneid(credp));
 666                 rw_exit(&vnic_lock);
 667                 return (rc);
 668         }
 669 
 670         vnic_cleanup_secondary_macs(vnic, vnic->vn_nhandles);
 671 
 672         vnic->vn_enabled = B_FALSE;
 673         (void) mod_hash_remove(vnic_hash, VNIC_HASH_KEY(vnic_id), &val);
 674         ASSERT(vnic == (vnic_t *)val);
 675         vnic_count--;
 676         rw_exit(&vnic_lock);
 677 
 678         /*
 679          * XXX-nicolas shouldn't have a void cast here, if it's
 680          * expected that the function will never fail, then we should
 681          * have an ASSERT().
 682          */
 683         (void) mac_unregister(vnic->vn_mh);
 684 
 685         if (vnic->vn_lower_mh != NULL) {
 686                 /*
 687                  * Check if MAC address for the vnic was obtained from the
 688                  * factory MAC addresses. If yes, release it.
 689                  */
 690                 if (vnic->vn_addr_type == VNIC_MAC_ADDR_TYPE_FACTORY) {
 691                         (void) mac_addr_factory_release(vnic->vn_mch,
 692                             vnic->vn_slot_id);
 693                 }
 694                 (void) mac_margin_remove(vnic->vn_lower_mh, vnic->vn_margin);
 695                 (void) mac_mtu_remove(vnic->vn_lower_mh, vnic->vn_mtu);
 696                 (void) mac_notify_remove(vnic->vn_mnh, B_TRUE);
 697                 (void) mac_unicast_remove(vnic->vn_mch, vnic->vn_muh);
 698                 mac_client_close(vnic->vn_mch, MAC_CLOSE_FLAGS_IS_VNIC);
 699                 mac_close(vnic->vn_lower_mh);
 700         }
 701 
 702         kmem_cache_free(vnic_cache, vnic);
 703         return (0);
 704 }
 705 
 706 /* ARGSUSED */
 707 mblk_t *
 708 vnic_m_tx(void *arg, mblk_t *mp_chain)
 709 {
 710         /*
 711          * This function could be invoked for an anchor VNIC when sending
 712          * broadcast and multicast packets, and unicast packets which did
 713          * not match any local known destination.
 714          */
 715         freemsgchain(mp_chain);
 716         return (NULL);
 717 }
 718 
 719 /*ARGSUSED*/
 720 static void
 721 vnic_m_ioctl(void *arg, queue_t *q, mblk_t *mp)
 722 {
 723         miocnak(q, mp, 0, ENOTSUP);
 724 }
 725 
 726 /*
 727  * This entry point cannot be passed-through, since it is invoked
 728  * for the per-VNIC kstats which must be exported independently
 729  * of the existence of VNIC MAC clients.
 730  */
 731 static int
 732 vnic_m_stat(void *arg, uint_t stat, uint64_t *val)
 733 {
 734         vnic_t *vnic = arg;
 735         int rval = 0;
 736 
 737         if (vnic->vn_lower_mh == NULL) {
 738                 /*
 739                  * It's an anchor VNIC, which does not have any
 740                  * statistics in itself.
 741                  */
 742                 return (ENOTSUP);
 743         }
 744 
 745         /*
 746          * ENOTSUP must be reported for unsupported stats, the VNIC
 747          * driver reports a subset of the stats that would
 748          * be returned by a real piece of hardware.
 749          */
 750 
 751         switch (stat) {
 752         case MAC_STAT_LINK_STATE:
 753         case MAC_STAT_LINK_UP:
 754         case MAC_STAT_PROMISC:
 755         case MAC_STAT_IFSPEED:
 756         case MAC_STAT_MULTIRCV:
 757         case MAC_STAT_MULTIXMT:
 758         case MAC_STAT_BRDCSTRCV:
 759         case MAC_STAT_BRDCSTXMT:
 760         case MAC_STAT_OPACKETS:
 761         case MAC_STAT_OBYTES:
 762         case MAC_STAT_IERRORS:
 763         case MAC_STAT_OERRORS:
 764         case MAC_STAT_RBYTES:
 765         case MAC_STAT_IPACKETS:
 766                 *val = mac_client_stat_get(vnic->vn_mch, stat);
 767                 break;
 768         default:
 769                 rval = ENOTSUP;
 770         }
 771 
 772         return (rval);
 773 }
 774 
 775 /*
 776  * Invoked by the upper MAC to retrieve the lower MAC client handle
 777  * corresponding to a VNIC. A pointer to this function is obtained
 778  * by the upper MAC via capability query.
 779  *
 780  * XXX-nicolas Note: this currently causes all VNIC MAC clients to
 781  * receive the same MAC client handle for the same VNIC. This is ok
 782  * as long as we have only one VNIC MAC client which sends and
 783  * receives data, but we don't currently enforce this at the MAC layer.
 784  */
 785 static void *
 786 vnic_mac_client_handle(void *vnic_arg)
 787 {
 788         vnic_t *vnic = vnic_arg;
 789 
 790         return (vnic->vn_mch);
 791 }
 792 
 793 /*
 794  * Invoked when updating the primary MAC so that the secondary MACs are
 795  * kept in sync.
 796  */
 797 static void
 798 vnic_mac_secondary_update(void *vnic_arg)
 799 {
 800         vnic_t *vn = vnic_arg;
 801         int i;
 802 
 803         for (i = 1; i <= vn->vn_nhandles; i++) {
 804                 mac_secondary_dup(vn->vn_mc_handles[0], vn->vn_mc_handles[i]);
 805         }
 806 }
 807 
 808 /*
 809  * Return information about the specified capability.
 810  */
 811 /* ARGSUSED */
 812 static boolean_t
 813 vnic_m_capab_get(void *arg, mac_capab_t cap, void *cap_data)
 814 {
 815         vnic_t *vnic = arg;
 816 
 817         switch (cap) {
 818         case MAC_CAPAB_HCKSUM: {
 819                 uint32_t *hcksum_txflags = cap_data;
 820 
 821                 *hcksum_txflags = vnic->vn_hcksum_txflags &
 822                     (HCKSUM_INET_FULL_V4 | HCKSUM_IPHDRCKSUM |
 823                     HCKSUM_INET_PARTIAL);
 824                 break;
 825         }
 826         case MAC_CAPAB_VNIC: {
 827                 mac_capab_vnic_t *vnic_capab = cap_data;
 828 
 829                 if (vnic->vn_lower_mh == NULL) {
 830                         /*
 831                          * It's an anchor VNIC, we don't have an underlying
 832                          * NIC and MAC client handle.
 833                          */
 834                         return (B_FALSE);
 835                 }
 836 
 837                 if (vnic_capab != NULL) {
 838                         vnic_capab->mcv_arg = vnic;
 839                         vnic_capab->mcv_mac_client_handle =
 840                             vnic_mac_client_handle;
 841                         vnic_capab->mcv_mac_secondary_update =
 842                             vnic_mac_secondary_update;
 843                 }
 844                 break;
 845         }
 846         case MAC_CAPAB_ANCHOR_VNIC: {
 847                 /* since it's an anchor VNIC we don't have lower mac handle */
 848                 if (vnic->vn_lower_mh == NULL) {
 849                         ASSERT(vnic->vn_link_id == 0);
 850                         return (B_TRUE);
 851                 }
 852                 return (B_FALSE);
 853         }
 854         case MAC_CAPAB_NO_NATIVEVLAN:
 855                 return (B_FALSE);
 856         case MAC_CAPAB_NO_ZCOPY:
 857                 return (B_TRUE);
 858         case MAC_CAPAB_VRRP: {
 859                 mac_capab_vrrp_t *vrrp_capab = cap_data;
 860 
 861                 if (vnic->vn_vrid != 0) {
 862                         if (vrrp_capab != NULL)
 863                                 vrrp_capab->mcv_af = vnic->vn_af;
 864                         return (B_TRUE);
 865                 }
 866                 return (B_FALSE);
 867         }
 868         default:
 869                 return (B_FALSE);
 870         }
 871         return (B_TRUE);
 872 }
 873 
 874 /* ARGSUSED */
 875 static int
 876 vnic_m_start(void *arg)
 877 {
 878         return (0);
 879 }
 880 
 881 /* ARGSUSED */
 882 static void
 883 vnic_m_stop(void *arg)
 884 {
 885 }
 886 
 887 /* ARGSUSED */
 888 static int
 889 vnic_m_promisc(void *arg, boolean_t on)
 890 {
 891         return (0);
 892 }
 893 
 894 /* ARGSUSED */
 895 static int
 896 vnic_m_multicst(void *arg, boolean_t add, const uint8_t *addrp)
 897 {
 898         return (0);
 899 }
 900 
 901 static int
 902 vnic_m_unicst(void *arg, const uint8_t *macaddr)
 903 {
 904         vnic_t *vnic = arg;
 905 
 906         return (mac_vnic_unicast_set(vnic->vn_mch, macaddr));
 907 }
 908 
 909 static void
 910 vnic_cleanup_secondary_macs(vnic_t *vn, int cnt)
 911 {
 912         int i;
 913 
 914         /* Remove existing secondaries (primary is at 0) */
 915         for (i = 1; i <= cnt; i++) {
 916                 mac_rx_clear(vn->vn_mc_handles[i]);
 917 
 918                 /* unicast handle might not have been set yet */
 919                 if (vn->vn_mu_handles[i] != NULL)
 920                         (void) mac_unicast_remove(vn->vn_mc_handles[i],
 921                             vn->vn_mu_handles[i]);
 922 
 923                 mac_secondary_cleanup(vn->vn_mc_handles[i]);
 924 
 925                 mac_client_close(vn->vn_mc_handles[i], MAC_CLOSE_FLAGS_IS_VNIC);
 926 
 927                 vn->vn_mu_handles[i] = NULL;
 928                 vn->vn_mc_handles[i] = NULL;
 929         }
 930 
 931         vn->vn_nhandles = 0;
 932 }
 933 
 934 /*
 935  * Setup secondary MAC addresses on the vnic. Due to limitations in the mac
 936  * code, each mac address must be associated with a mac_client (and the
 937  * flow that goes along with the client) so we need to create those clients
 938  * here.
 939  */
 940 static int
 941 vnic_set_secondary_macs(vnic_t *vn, mac_secondary_addr_t *msa)
 942 {
 943         int i, err;
 944         char primary_name[MAXNAMELEN];
 945 
 946         /* First, remove pre-existing secondaries */
 947         ASSERT(vn->vn_nhandles < MPT_MAXMACADDR);
 948         vnic_cleanup_secondary_macs(vn, vn->vn_nhandles);
 949 
 950         if (msa->ms_addrcnt == (uint32_t)-1)
 951                 msa->ms_addrcnt = 0;
 952 
 953         vn->vn_nhandles = msa->ms_addrcnt;
 954 
 955         (void) dls_mgmt_get_linkinfo(vn->vn_id, primary_name, NULL, NULL, NULL);
 956 
 957         /*
 958          * Now add the new secondary MACs
 959          * Recall that the primary MAC address is the first element.
 960          * The secondary clients are named after the primary with their
 961          * index to distinguish them.
 962          */
 963         for (i = 1; i <= vn->vn_nhandles; i++) {
 964                 uint8_t *addr;
 965                 mac_diag_t mac_diag;
 966                 char secondary_name[MAXNAMELEN];
 967 
 968                 (void) snprintf(secondary_name, sizeof (secondary_name),
 969                     "%s%02d", primary_name, i);
 970 
 971                 err = mac_client_open(vn->vn_lower_mh, &vn->vn_mc_handles[i],
 972                     secondary_name, MAC_OPEN_FLAGS_IS_VNIC);
 973                 if (err != 0) {
 974                         /* Remove any that we successfully added */
 975                         vnic_cleanup_secondary_macs(vn, --i);
 976                         return (err);
 977                 }
 978 
 979                 /*
 980                  * Assign a MAC address to the VNIC
 981                  *
 982                  * Normally this would be done with vnic_unicast_add but since
 983                  * we know these are fixed adddresses, and since we need to
 984                  * save this in the proper array slot, we bypass that function
 985                  * and go direct.
 986                  */
 987                 addr = msa->ms_addrs[i - 1];
 988                 err = mac_unicast_add(vn->vn_mc_handles[i], addr, 0,
 989                     &vn->vn_mu_handles[i], vn->vn_vid, &mac_diag);
 990                 if (err != 0) {
 991                         /* Remove any that we successfully added */
 992                         vnic_cleanup_secondary_macs(vn, i);
 993                         return (err);
 994                 }
 995 
 996                 /*
 997                  * Setup the secondary the same way as the primary (i.e.
 998                  * receiver function/argument (e.g. i_dls_link_rx, mac_pkt_drop,
 999                  * etc.), the promisc list, and the resource controls).
1000                  */
1001                 mac_secondary_dup(vn->vn_mc_handles[0], vn->vn_mc_handles[i]);
1002         }
1003 
1004         return (0);
1005 }
1006 
1007 static int
1008 vnic_get_secondary_macs(vnic_t *vn, uint_t pr_valsize, void *pr_val)
1009 {
1010         int i;
1011         mac_secondary_addr_t msa;
1012 
1013         if (pr_valsize < sizeof (msa))
1014                 return (EINVAL);
1015 
1016         /* Get existing addresses (primary is at 0) */
1017         ASSERT(vn->vn_nhandles < MPT_MAXMACADDR);
1018         for (i = 1; i <= vn->vn_nhandles; i++) {
1019                 ASSERT(vn->vn_mc_handles[i] != NULL);
1020                 mac_unicast_secondary_get(vn->vn_mc_handles[i],
1021                     msa.ms_addrs[i - 1]);
1022         }
1023         msa.ms_addrcnt = vn->vn_nhandles;
1024 
1025         bcopy(&msa, pr_val, sizeof (msa));
1026         return (0);
1027 }
1028 
1029 /*
1030  * Callback functions for set/get of properties
1031  */
1032 /*ARGSUSED*/
1033 static int
1034 vnic_m_setprop(void *m_driver, const char *pr_name, mac_prop_id_t pr_num,
1035     uint_t pr_valsize, const void *pr_val)
1036 {
1037         int             err = 0;
1038         vnic_t          *vn = m_driver;
1039 
1040         switch (pr_num) {
1041         case MAC_PROP_MTU: {
1042                 uint32_t        mtu;
1043 
1044                 if (pr_valsize < sizeof (mtu)) {
1045                         err = EINVAL;
1046                         break;
1047                 }
1048                 bcopy(pr_val, &mtu, sizeof (mtu));
1049 
1050                 if (vn->vn_link_id == DATALINK_INVALID_LINKID) {
1051                         if (mtu < ANCHOR_VNIC_MIN_MTU ||
1052                             mtu > ANCHOR_VNIC_MAX_MTU) {
1053                                 err = EINVAL;
1054                                 break;
1055                         }
1056                 } else {
1057                         err = mac_mtu_add(vn->vn_lower_mh, &mtu, B_FALSE);
1058                         /*
1059                          * If it's not supported to set a value here, translate
1060                          * that to EINVAL, so user land gets a better idea of
1061                          * what went wrong. This realistically means that they
1062                          * violated the output of prop info.
1063                          */
1064                         if (err == ENOTSUP)
1065                                 err = EINVAL;
1066                         if (err != 0)
1067                                 break;
1068                         VERIFY(mac_mtu_remove(vn->vn_lower_mh,
1069                             vn->vn_mtu) == 0);
1070                 }
1071                 vn->vn_mtu = mtu;
1072                 err = mac_maxsdu_update(vn->vn_mh, mtu);
1073                 break;
1074         }
1075         case MAC_PROP_SECONDARY_ADDRS: {
1076                 mac_secondary_addr_t msa;
1077 
1078                 bcopy(pr_val, &msa, sizeof (msa));
1079                 err = vnic_set_secondary_macs(vn, &msa);
1080                 break;
1081         }
1082         default:
1083                 err = ENOTSUP;
1084                 break;
1085         }
1086         return (err);
1087 }
1088 
1089 /* ARGSUSED */
1090 static int
1091 vnic_m_getprop(void *arg, const char *pr_name, mac_prop_id_t pr_num,
1092     uint_t pr_valsize, void *pr_val)
1093 {
1094         vnic_t          *vn = arg;
1095         int             ret = 0;
1096 
1097         switch (pr_num) {
1098         case MAC_PROP_SECONDARY_ADDRS:
1099                 ret = vnic_get_secondary_macs(vn, pr_valsize, pr_val);
1100                 break;
1101         default:
1102                 ret = ENOTSUP;
1103                 break;
1104         }
1105 
1106         return (ret);
1107 }
1108 
1109 /* ARGSUSED */
1110 static void vnic_m_propinfo(void *m_driver, const char *pr_name,
1111     mac_prop_id_t pr_num, mac_prop_info_handle_t prh)
1112 {
1113         vnic_t          *vn = m_driver;
1114 
1115         switch (pr_num) {
1116         case MAC_PROP_MTU:
1117                 if (vn->vn_link_id == DATALINK_INVALID_LINKID) {
1118                         mac_prop_info_set_range_uint32(prh,
1119                             ANCHOR_VNIC_MIN_MTU, ANCHOR_VNIC_MAX_MTU);
1120                 } else {
1121                         uint32_t                max;
1122                         mac_perim_handle_t      mph;
1123                         mac_propval_range_t     range;
1124 
1125                         /*
1126                          * The valid range for a VNIC's MTU is the minimum that
1127                          * the device supports and the current value of the
1128                          * device. A VNIC cannot increase the current MTU of the
1129                          * device. Therefore we need to get the range from the
1130                          * propinfo endpoint and current mtu from the
1131                          * traditional property endpoint.
1132                          */
1133                         mac_perim_enter_by_mh(vn->vn_lower_mh, &mph);
1134                         if (mac_get_prop(vn->vn_lower_mh, MAC_PROP_MTU, "mtu",
1135                             &max, sizeof (uint32_t)) != 0) {
1136                                 mac_perim_exit(mph);
1137                                 return;
1138                         }
1139 
1140                         range.mpr_count = 1;
1141                         if (mac_prop_info(vn->vn_lower_mh, MAC_PROP_MTU, "mtu",
1142                             NULL, 0, &range, NULL) != 0) {
1143                                 mac_perim_exit(mph);
1144                                 return;
1145                         }
1146 
1147                         mac_prop_info_set_default_uint32(prh, max);
1148                         mac_prop_info_set_range_uint32(prh,
1149                             range.mpr_range_uint32[0].mpur_min, max);
1150                         mac_perim_exit(mph);
1151                 }
1152                 break;
1153         }
1154 }
1155 
1156 
1157 int
1158 vnic_info(vnic_info_t *info, cred_t *credp)
1159 {
1160         vnic_t          *vnic;
1161         int             err;
1162 
1163         /* Make sure that the VNIC link is visible from the caller's zone. */
1164         if (!dls_devnet_islinkvisible(info->vn_vnic_id, crgetzoneid(credp)))
1165                 return (ENOENT);
1166 
1167         rw_enter(&vnic_lock, RW_WRITER);
1168 
1169         err = mod_hash_find(vnic_hash, VNIC_HASH_KEY(info->vn_vnic_id),
1170             (mod_hash_val_t *)&vnic);
1171         if (err != 0) {
1172                 rw_exit(&vnic_lock);
1173                 return (ENOENT);
1174         }
1175 
1176         info->vn_link_id = vnic->vn_link_id;
1177         info->vn_mac_addr_type = vnic->vn_addr_type;
1178         info->vn_mac_len = vnic->vn_addr_len;
1179         bcopy(vnic->vn_addr, info->vn_mac_addr, MAXMACADDRLEN);
1180         info->vn_mac_slot = vnic->vn_slot_id;
1181         info->vn_mac_prefix_len = 0;
1182         info->vn_vid = vnic->vn_vid;
1183         info->vn_force = vnic->vn_force;
1184         info->vn_vrid = vnic->vn_vrid;
1185         info->vn_af = vnic->vn_af;
1186 
1187         bzero(&info->vn_resource_props, sizeof (mac_resource_props_t));
1188         if (vnic->vn_mch != NULL)
1189                 mac_client_get_resources(vnic->vn_mch,
1190                     &info->vn_resource_props);
1191 
1192         rw_exit(&vnic_lock);
1193         return (0);
1194 }
1195 
1196 static void
1197 vnic_notify_cb(void *arg, mac_notify_type_t type)
1198 {
1199         vnic_t *vnic = arg;
1200 
1201         /*
1202          * Do not deliver notifications if the vnic is not fully initialized
1203          * or is in process of being torn down.
1204          */
1205         if (!vnic->vn_enabled)
1206                 return;
1207 
1208         switch (type) {
1209         case MAC_NOTE_UNICST:
1210                 /*
1211                  * Only the VLAN VNIC needs to be notified with primary MAC
1212                  * address change.
1213                  */
1214                 if (vnic->vn_addr_type != VNIC_MAC_ADDR_TYPE_PRIMARY)
1215                         return;
1216 
1217                 /*  the unicast MAC address value */
1218                 mac_unicast_primary_get(vnic->vn_lower_mh, vnic->vn_addr);
1219 
1220                 /* notify its upper layer MAC about MAC address change */
1221                 mac_unicst_update(vnic->vn_mh, (const uint8_t *)vnic->vn_addr);
1222                 break;
1223 
1224         case MAC_NOTE_LINK:
1225                 mac_link_update(vnic->vn_mh,
1226                     mac_client_stat_get(vnic->vn_mch, MAC_STAT_LINK_STATE));
1227                 break;
1228 
1229         default:
1230                 break;
1231         }
1232 }