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