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