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 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #include <sys/types.h> 27 #include <sys/sysmacros.h> 28 #include <sys/conf.h> 29 #include <sys/cmn_err.h> 30 #include <sys/list.h> 31 #include <sys/ksynch.h> 32 #include <sys/kmem.h> 33 #include <sys/stream.h> 34 #include <sys/modctl.h> 35 #include <sys/ddi.h> 36 #include <sys/sunddi.h> 37 #include <sys/atomic.h> 38 #include <sys/stat.h> 39 #include <sys/modhash.h> 40 #include <sys/strsubr.h> 41 #include <sys/strsun.h> 42 #include <sys/dlpi.h> 43 #include <sys/mac.h> 44 #include <sys/mac_provider.h> 45 #include <sys/mac_client.h> 46 #include <sys/mac_client_priv.h> 47 #include <sys/mac_ether.h> 48 #include <sys/dls.h> 49 #include <sys/pattr.h> 50 #include <sys/time.h> 51 #include <sys/vlan.h> 52 #include <sys/vnic.h> 53 #include <sys/vnic_impl.h> 54 #include <sys/mac_flow_impl.h> 55 #include <inet/ip_impl.h> 56 57 /* 58 * Note that for best performance, the VNIC is a passthrough design. 59 * For each VNIC corresponds a MAC client of the underlying MAC (lower MAC). 60 * This MAC client is opened by the VNIC driver at VNIC creation, 61 * and closed when the VNIC is deleted. 62 * When a MAC client of the VNIC itself opens a VNIC, the MAC layer 63 * (upper MAC) detects that the MAC being opened is a VNIC. Instead 64 * of allocating a new MAC client, it asks the VNIC driver to return 65 * the lower MAC client handle associated with the VNIC, and that handle 66 * is returned to the upper MAC client directly. This allows access 67 * by upper MAC clients of the VNIC to have direct access to the lower 68 * MAC client for the control path and data path. 69 * 70 * Due to this passthrough, some of the entry points exported by the 71 * VNIC driver are never directly invoked. These entry points include 72 * vnic_m_start, vnic_m_stop, vnic_m_promisc, vnic_m_multicst, etc. 73 */ 74 75 static int vnic_m_start(void *); 76 static void vnic_m_stop(void *); 77 static int vnic_m_promisc(void *, boolean_t); 78 static int vnic_m_multicst(void *, boolean_t, const uint8_t *); 79 static int vnic_m_unicst(void *, const uint8_t *); 80 static int vnic_m_stat(void *, uint_t, uint64_t *); 81 static void vnic_m_ioctl(void *, queue_t *, mblk_t *); 82 static int vnic_m_setprop(void *, const char *, mac_prop_id_t, uint_t, 83 const void *); 84 static int vnic_m_getprop(void *, const char *, mac_prop_id_t, uint_t, 85 uint_t, void *, uint_t *); 86 static mblk_t *vnic_m_tx(void *, mblk_t *); 87 static boolean_t vnic_m_capab_get(void *, mac_capab_t, void *); 88 static void vnic_notify_cb(void *, mac_notify_type_t); 89 90 static kmem_cache_t *vnic_cache; 91 static krwlock_t vnic_lock; 92 static uint_t vnic_count; 93 94 /* hash of VNICs (vnic_t's), keyed by VNIC id */ 95 static mod_hash_t *vnic_hash; 96 #define VNIC_HASHSZ 64 97 #define VNIC_HASH_KEY(vnic_id) ((mod_hash_key_t)(uintptr_t)vnic_id) 98 99 #define VNIC_M_CALLBACK_FLAGS \ 100 (MC_IOCTL | MC_GETCAPAB | MC_SETPROP | MC_GETPROP) 101 102 static mac_callbacks_t vnic_m_callbacks = { 103 VNIC_M_CALLBACK_FLAGS, 104 vnic_m_stat, 105 vnic_m_start, 106 vnic_m_stop, 107 vnic_m_promisc, 108 vnic_m_multicst, 109 vnic_m_unicst, 110 vnic_m_tx, 111 vnic_m_ioctl, 112 vnic_m_capab_get, 113 NULL, 114 NULL, 115 vnic_m_setprop, 116 vnic_m_getprop 117 }; 118 119 void 120 vnic_dev_init(void) 121 { 122 vnic_cache = kmem_cache_create("vnic_cache", 123 sizeof (vnic_t), 0, NULL, NULL, NULL, NULL, NULL, 0); 124 125 vnic_hash = mod_hash_create_idhash("vnic_hash", 126 VNIC_HASHSZ, mod_hash_null_valdtor); 127 128 rw_init(&vnic_lock, NULL, RW_DEFAULT, NULL); 129 130 vnic_count = 0; 131 } 132 133 void 134 vnic_dev_fini(void) 135 { 136 ASSERT(vnic_count == 0); 137 138 rw_destroy(&vnic_lock); 139 mod_hash_destroy_idhash(vnic_hash); 140 kmem_cache_destroy(vnic_cache); 141 } 142 143 uint_t 144 vnic_dev_count(void) 145 { 146 return (vnic_count); 147 } 148 149 static vnic_ioc_diag_t 150 vnic_mac2vnic_diag(mac_diag_t diag) 151 { 152 switch (diag) { 153 case MAC_DIAG_MACADDR_NIC: 154 return (VNIC_IOC_DIAG_MACADDR_NIC); 155 case MAC_DIAG_MACADDR_INUSE: 156 return (VNIC_IOC_DIAG_MACADDR_INUSE); 157 case MAC_DIAG_MACADDR_INVALID: 158 return (VNIC_IOC_DIAG_MACADDR_INVALID); 159 case MAC_DIAG_MACADDRLEN_INVALID: 160 return (VNIC_IOC_DIAG_MACADDRLEN_INVALID); 161 case MAC_DIAG_MACFACTORYSLOTINVALID: 162 return (VNIC_IOC_DIAG_MACFACTORYSLOTINVALID); 163 case MAC_DIAG_MACFACTORYSLOTUSED: 164 return (VNIC_IOC_DIAG_MACFACTORYSLOTUSED); 165 case MAC_DIAG_MACFACTORYSLOTALLUSED: 166 return (VNIC_IOC_DIAG_MACFACTORYSLOTALLUSED); 167 case MAC_DIAG_MACFACTORYNOTSUP: 168 return (VNIC_IOC_DIAG_MACFACTORYNOTSUP); 169 case MAC_DIAG_MACPREFIX_INVALID: 170 return (VNIC_IOC_DIAG_MACPREFIX_INVALID); 171 case MAC_DIAG_MACPREFIXLEN_INVALID: 172 return (VNIC_IOC_DIAG_MACPREFIXLEN_INVALID); 173 case MAC_DIAG_MACNO_HWRINGS: 174 return (VNIC_IOC_DIAG_NO_HWRINGS); 175 default: 176 return (VNIC_IOC_DIAG_NONE); 177 } 178 } 179 180 static int 181 vnic_unicast_add(vnic_t *vnic, vnic_mac_addr_type_t vnic_addr_type, 182 int *addr_slot, uint_t prefix_len, int *addr_len_ptr_arg, 183 uint8_t *mac_addr_arg, uint16_t flags, vnic_ioc_diag_t *diag, 184 uint16_t vid) 185 { 186 mac_diag_t mac_diag; 187 uint16_t mac_flags = 0; 188 int err; 189 uint_t addr_len; 190 191 if (flags & VNIC_IOC_CREATE_NODUPCHECK) 192 mac_flags |= MAC_UNICAST_NODUPCHECK; 193 194 switch (vnic_addr_type) { 195 case VNIC_MAC_ADDR_TYPE_FIXED: 196 /* 197 * The MAC address value to assign to the VNIC 198 * is already provided in mac_addr_arg. addr_len_ptr_arg 199 * already contains the MAC address length. 200 */ 201 break; 202 203 case VNIC_MAC_ADDR_TYPE_RANDOM: 204 /* 205 * Random MAC address. There are two sub-cases: 206 * 207 * 1 - If mac_len == 0, a new MAC address is generated. 208 * The length of the MAC address to generated depends 209 * on the type of MAC used. The prefix to use for the MAC 210 * address is stored in the most significant bytes 211 * of the mac_addr argument, and its length is specified 212 * by the mac_prefix_len argument. This prefix can 213 * correspond to a IEEE OUI in the case of Ethernet, 214 * for example. 215 * 216 * 2 - If mac_len > 0, the address was already picked 217 * randomly, and is now passed back during VNIC 218 * re-creation. The mac_addr argument contains the MAC 219 * address that was generated. We distinguish this 220 * case from the fixed MAC address case, since we 221 * want the user consumers to know, when they query 222 * the list of VNICs, that a VNIC was assigned a 223 * random MAC address vs assigned a fixed address 224 * specified by the user. 225 */ 226 227 /* 228 * If it's a pre-generated address, we're done. mac_addr_arg 229 * and addr_len_ptr_arg already contain the MAC address 230 * value and length. 231 */ 232 if (*addr_len_ptr_arg > 0) 233 break; 234 235 /* generate a new random MAC address */ 236 if ((err = mac_addr_random(vnic->vn_mch, 237 prefix_len, mac_addr_arg, &mac_diag)) != 0) { 238 *diag = vnic_mac2vnic_diag(mac_diag); 239 return (err); 240 } 241 *addr_len_ptr_arg = mac_addr_len(vnic->vn_lower_mh); 242 break; 243 244 case VNIC_MAC_ADDR_TYPE_FACTORY: 245 err = mac_addr_factory_reserve(vnic->vn_mch, addr_slot); 246 if (err != 0) { 247 if (err == EINVAL) 248 *diag = VNIC_IOC_DIAG_MACFACTORYSLOTINVALID; 249 if (err == EBUSY) 250 *diag = VNIC_IOC_DIAG_MACFACTORYSLOTUSED; 251 if (err == ENOSPC) 252 *diag = VNIC_IOC_DIAG_MACFACTORYSLOTALLUSED; 253 return (err); 254 } 255 256 mac_addr_factory_value(vnic->vn_lower_mh, *addr_slot, 257 mac_addr_arg, &addr_len, NULL, NULL); 258 *addr_len_ptr_arg = addr_len; 259 break; 260 261 case VNIC_MAC_ADDR_TYPE_AUTO: 262 /* first try to allocate a factory MAC address */ 263 err = mac_addr_factory_reserve(vnic->vn_mch, addr_slot); 264 if (err == 0) { 265 mac_addr_factory_value(vnic->vn_lower_mh, *addr_slot, 266 mac_addr_arg, &addr_len, NULL, NULL); 267 vnic_addr_type = VNIC_MAC_ADDR_TYPE_FACTORY; 268 *addr_len_ptr_arg = addr_len; 269 break; 270 } 271 272 /* 273 * Allocating a factory MAC address failed, generate a 274 * random MAC address instead. 275 */ 276 if ((err = mac_addr_random(vnic->vn_mch, 277 prefix_len, mac_addr_arg, &mac_diag)) != 0) { 278 *diag = vnic_mac2vnic_diag(mac_diag); 279 return (err); 280 } 281 *addr_len_ptr_arg = mac_addr_len(vnic->vn_lower_mh); 282 vnic_addr_type = VNIC_MAC_ADDR_TYPE_RANDOM; 283 break; 284 case VNIC_MAC_ADDR_TYPE_PRIMARY: 285 /* 286 * We get the address here since we copy it in the 287 * vnic's vn_addr. 288 */ 289 mac_unicast_primary_get(vnic->vn_lower_mh, mac_addr_arg); 290 *addr_len_ptr_arg = mac_addr_len(vnic->vn_lower_mh); 291 mac_flags |= MAC_UNICAST_VNIC_PRIMARY; 292 break; 293 } 294 295 vnic->vn_addr_type = vnic_addr_type; 296 297 err = mac_unicast_add(vnic->vn_mch, mac_addr_arg, mac_flags, 298 &vnic->vn_muh, vid, &mac_diag); 299 if (err != 0) { 300 if (vnic_addr_type == VNIC_MAC_ADDR_TYPE_FACTORY) { 301 /* release factory MAC address */ 302 mac_addr_factory_release(vnic->vn_mch, *addr_slot); 303 } 304 *diag = vnic_mac2vnic_diag(mac_diag); 305 } 306 307 return (err); 308 } 309 310 /* 311 * Create a new VNIC upon request from administrator. 312 * Returns 0 on success, an errno on failure. 313 */ 314 /* ARGSUSED */ 315 int 316 vnic_dev_create(datalink_id_t vnic_id, datalink_id_t linkid, 317 vnic_mac_addr_type_t *vnic_addr_type, int *mac_len, uchar_t *mac_addr, 318 int *mac_slot, uint_t mac_prefix_len, uint16_t vid, 319 mac_resource_props_t *mrp, uint32_t flags, vnic_ioc_diag_t *diag) 320 { 321 vnic_t *vnic; 322 mac_register_t *mac; 323 int err; 324 boolean_t is_anchor = ((flags & VNIC_IOC_CREATE_ANCHOR) != 0); 325 char vnic_name[MAXNAMELEN]; 326 const mac_info_t *minfop; 327 uint32_t req_hwgrp_flag = ((flags & VNIC_IOC_CREATE_REQ_HWRINGS) != 0) ? 328 MAC_OPEN_FLAGS_REQ_HWRINGS : 0; 329 330 *diag = VNIC_IOC_DIAG_NONE; 331 332 rw_enter(&vnic_lock, RW_WRITER); 333 334 /* does a VNIC with the same id already exist? */ 335 err = mod_hash_find(vnic_hash, VNIC_HASH_KEY(vnic_id), 336 (mod_hash_val_t *)&vnic); 337 if (err == 0) { 338 rw_exit(&vnic_lock); 339 return (EEXIST); 340 } 341 342 vnic = kmem_cache_alloc(vnic_cache, KM_NOSLEEP); 343 if (vnic == NULL) { 344 rw_exit(&vnic_lock); 345 return (ENOMEM); 346 } 347 348 bzero(vnic, sizeof (*vnic)); 349 350 vnic->vn_id = vnic_id; 351 vnic->vn_link_id = linkid; 352 353 if (!is_anchor) { 354 if (linkid == DATALINK_INVALID_LINKID) { 355 err = EINVAL; 356 goto bail; 357 } 358 359 /* 360 * Open the lower MAC and assign its initial bandwidth and 361 * MAC address. We do this here during VNIC creation and 362 * do not wait until the upper MAC client open so that we 363 * can validate the VNIC creation parameters (bandwidth, 364 * MAC address, etc) and reserve a factory MAC address if 365 * one was requested. 366 */ 367 err = mac_open_by_linkid(linkid, &vnic->vn_lower_mh); 368 if (err != 0) 369 goto bail; 370 371 /* 372 * VNIC(vlan) over VNICs(vlans) is not supported. 373 */ 374 if (mac_is_vnic(vnic->vn_lower_mh)) { 375 err = EINVAL; 376 goto bail; 377 } 378 379 /* only ethernet support for now */ 380 minfop = mac_info(vnic->vn_lower_mh); 381 if (minfop->mi_nativemedia != DL_ETHER) { 382 err = ENOTSUP; 383 goto bail; 384 } 385 386 (void) dls_mgmt_get_linkinfo(vnic_id, vnic_name, NULL, NULL, 387 NULL); 388 err = mac_client_open(vnic->vn_lower_mh, &vnic->vn_mch, 389 vnic_name, MAC_OPEN_FLAGS_IS_VNIC | req_hwgrp_flag); 390 if (err != 0) 391 goto bail; 392 393 if (mrp != NULL) { 394 err = mac_client_set_resources(vnic->vn_mch, mrp); 395 if (err != 0) 396 goto bail; 397 } 398 /* assign a MAC address to the VNIC */ 399 400 err = vnic_unicast_add(vnic, *vnic_addr_type, mac_slot, 401 mac_prefix_len, mac_len, mac_addr, flags, diag, vid); 402 if (err != 0) { 403 vnic->vn_muh = NULL; 404 if (diag != NULL && req_hwgrp_flag != 0) 405 *diag = VNIC_IOC_DIAG_NO_HWRINGS; 406 goto bail; 407 } 408 409 /* register to receive notification from underlying MAC */ 410 vnic->vn_mnh = mac_notify_add(vnic->vn_lower_mh, vnic_notify_cb, 411 vnic); 412 413 *vnic_addr_type = vnic->vn_addr_type; 414 vnic->vn_addr_len = *mac_len; 415 vnic->vn_vid = vid; 416 417 bcopy(mac_addr, vnic->vn_addr, vnic->vn_addr_len); 418 419 if (vnic->vn_addr_type == VNIC_MAC_ADDR_TYPE_FACTORY) 420 vnic->vn_slot_id = *mac_slot; 421 422 /* set the initial VNIC capabilities */ 423 if (!mac_capab_get(vnic->vn_lower_mh, MAC_CAPAB_HCKSUM, 424 &vnic->vn_hcksum_txflags)) 425 vnic->vn_hcksum_txflags = 0; 426 } 427 428 /* register with the MAC module */ 429 if ((mac = mac_alloc(MAC_VERSION)) == NULL) 430 goto bail; 431 432 mac->m_type_ident = MAC_PLUGIN_IDENT_ETHER; 433 mac->m_driver = vnic; 434 mac->m_dip = vnic_get_dip(); 435 mac->m_instance = (uint_t)-1; 436 mac->m_src_addr = vnic->vn_addr; 437 mac->m_callbacks = &vnic_m_callbacks; 438 439 if (!is_anchor) { 440 /* 441 * If this is a VNIC based VLAN, then we check for the 442 * margin unless it has been created with the force 443 * flag. If we are configuring a VLAN over an etherstub, 444 * we don't check the margin even if force is not set. 445 */ 446 if (vid == 0 || (flags & VNIC_IOC_CREATE_FORCE) != 0) { 447 if (vid != VLAN_ID_NONE) 448 vnic->vn_force = B_TRUE; 449 /* 450 * As the current margin size of the underlying mac is 451 * used to determine the margin size of the VNIC 452 * itself, request the underlying mac not to change 453 * to a smaller margin size. 454 */ 455 err = mac_margin_add(vnic->vn_lower_mh, 456 &vnic->vn_margin, B_TRUE); 457 ASSERT(err == 0); 458 } else { 459 vnic->vn_margin = VLAN_TAGSZ; 460 err = mac_margin_add(vnic->vn_lower_mh, 461 &vnic->vn_margin, B_FALSE); 462 if (err != 0) { 463 mac_free(mac); 464 if (diag != NULL) 465 *diag = VNIC_IOC_DIAG_MACMARGIN_INVALID; 466 goto bail; 467 } 468 } 469 470 mac_sdu_get(vnic->vn_lower_mh, &mac->m_min_sdu, 471 &mac->m_max_sdu); 472 } else { 473 vnic->vn_margin = VLAN_TAGSZ; 474 mac->m_min_sdu = 0; 475 mac->m_max_sdu = 9000; 476 } 477 478 mac->m_margin = vnic->vn_margin; 479 480 err = mac_register(mac, &vnic->vn_mh); 481 mac_free(mac); 482 if (err != 0) { 483 VERIFY(is_anchor || mac_margin_remove(vnic->vn_lower_mh, 484 vnic->vn_margin) == 0); 485 goto bail; 486 } 487 488 /* Set the VNIC's MAC in the client */ 489 if (!is_anchor) 490 mac_set_upper_mac(vnic->vn_mch, vnic->vn_mh); 491 492 if ((err = dls_devnet_create(vnic->vn_mh, vnic->vn_id)) != 0) { 493 VERIFY(is_anchor || mac_margin_remove(vnic->vn_lower_mh, 494 vnic->vn_margin) == 0); 495 (void) mac_unregister(vnic->vn_mh); 496 goto bail; 497 } 498 499 /* add new VNIC to hash table */ 500 err = mod_hash_insert(vnic_hash, VNIC_HASH_KEY(vnic_id), 501 (mod_hash_val_t)vnic); 502 ASSERT(err == 0); 503 vnic_count++; 504 505 vnic->vn_enabled = B_TRUE; 506 rw_exit(&vnic_lock); 507 508 return (0); 509 510 bail: 511 rw_exit(&vnic_lock); 512 if (!is_anchor) { 513 if (vnic->vn_mnh != NULL) 514 (void) mac_notify_remove(vnic->vn_mnh, B_TRUE); 515 if (vnic->vn_muh != NULL) 516 (void) mac_unicast_remove(vnic->vn_mch, vnic->vn_muh); 517 if (vnic->vn_mch != NULL) 518 mac_client_close(vnic->vn_mch, MAC_CLOSE_FLAGS_IS_VNIC); 519 if (vnic->vn_lower_mh != NULL) 520 mac_close(vnic->vn_lower_mh); 521 } 522 523 kmem_cache_free(vnic_cache, vnic); 524 return (err); 525 } 526 527 /* 528 * Modify the properties of an existing VNIC. 529 */ 530 /* ARGSUSED */ 531 int 532 vnic_dev_modify(datalink_id_t vnic_id, uint_t modify_mask, 533 vnic_mac_addr_type_t mac_addr_type, uint_t mac_len, uchar_t *mac_addr, 534 uint_t mac_slot, mac_resource_props_t *mrp) 535 { 536 vnic_t *vnic = NULL; 537 538 rw_enter(&vnic_lock, RW_WRITER); 539 540 if (mod_hash_find(vnic_hash, VNIC_HASH_KEY(vnic_id), 541 (mod_hash_val_t *)&vnic) != 0) { 542 rw_exit(&vnic_lock); 543 return (ENOENT); 544 } 545 546 rw_exit(&vnic_lock); 547 548 return (0); 549 } 550 551 /* ARGSUSED */ 552 int 553 vnic_dev_delete(datalink_id_t vnic_id, uint32_t flags) 554 { 555 vnic_t *vnic = NULL; 556 mod_hash_val_t val; 557 datalink_id_t tmpid; 558 int rc; 559 560 rw_enter(&vnic_lock, RW_WRITER); 561 562 if (mod_hash_find(vnic_hash, VNIC_HASH_KEY(vnic_id), 563 (mod_hash_val_t *)&vnic) != 0) { 564 rw_exit(&vnic_lock); 565 return (ENOENT); 566 } 567 568 if ((rc = dls_devnet_destroy(vnic->vn_mh, &tmpid, B_TRUE)) != 0) { 569 rw_exit(&vnic_lock); 570 return (rc); 571 } 572 573 ASSERT(vnic_id == tmpid); 574 575 /* 576 * We cannot unregister the MAC yet. Unregistering would 577 * free up mac_impl_t which should not happen at this time. 578 * So disable mac_impl_t by calling mac_disable(). This will prevent 579 * any new claims on mac_impl_t. 580 */ 581 if ((rc = mac_disable(vnic->vn_mh)) != 0) { 582 (void) dls_devnet_create(vnic->vn_mh, vnic_id); 583 rw_exit(&vnic_lock); 584 return (rc); 585 } 586 587 vnic->vn_enabled = B_FALSE; 588 (void) mod_hash_remove(vnic_hash, VNIC_HASH_KEY(vnic_id), &val); 589 ASSERT(vnic == (vnic_t *)val); 590 vnic_count--; 591 rw_exit(&vnic_lock); 592 593 /* 594 * XXX-nicolas shouldn't have a void cast here, if it's 595 * expected that the function will never fail, then we should 596 * have an ASSERT(). 597 */ 598 (void) mac_unregister(vnic->vn_mh); 599 600 if (vnic->vn_lower_mh != NULL) { 601 /* 602 * Check if MAC address for the vnic was obtained from the 603 * factory MAC addresses. If yes, release it. 604 */ 605 if (vnic->vn_addr_type == VNIC_MAC_ADDR_TYPE_FACTORY) { 606 (void) mac_addr_factory_release(vnic->vn_mch, 607 vnic->vn_slot_id); 608 } 609 (void) mac_margin_remove(vnic->vn_lower_mh, vnic->vn_margin); 610 (void) mac_notify_remove(vnic->vn_mnh, B_TRUE); 611 (void) mac_unicast_remove(vnic->vn_mch, vnic->vn_muh); 612 mac_client_close(vnic->vn_mch, MAC_CLOSE_FLAGS_IS_VNIC); 613 mac_close(vnic->vn_lower_mh); 614 } 615 616 kmem_cache_free(vnic_cache, vnic); 617 return (0); 618 } 619 620 /* ARGSUSED */ 621 mblk_t * 622 vnic_m_tx(void *arg, mblk_t *mp_chain) 623 { 624 /* 625 * This function could be invoked for an anchor VNIC when sending 626 * broadcast and multicast packets, and unicast packets which did 627 * not match any local known destination. 628 */ 629 freemsgchain(mp_chain); 630 return (NULL); 631 } 632 633 /*ARGSUSED*/ 634 static void 635 vnic_m_ioctl(void *arg, queue_t *q, mblk_t *mp) 636 { 637 miocnak(q, mp, 0, ENOTSUP); 638 } 639 640 /* 641 * This entry point cannot be passed-through, since it is invoked 642 * for the per-VNIC kstats which must be exported independently 643 * of the existence of VNIC MAC clients. 644 */ 645 static int 646 vnic_m_stat(void *arg, uint_t stat, uint64_t *val) 647 { 648 vnic_t *vnic = arg; 649 int rval = 0; 650 651 if (vnic->vn_lower_mh == NULL) { 652 /* 653 * It's an anchor VNIC, which does not have any 654 * statistics in itself. 655 */ 656 return (ENOTSUP); 657 } 658 659 /* 660 * ENOTSUP must be reported for unsupported stats, the VNIC 661 * driver reports a subset of the stats that would 662 * be returned by a real piece of hardware. 663 */ 664 665 switch (stat) { 666 case MAC_STAT_LINK_STATE: 667 case MAC_STAT_LINK_UP: 668 case MAC_STAT_PROMISC: 669 case MAC_STAT_IFSPEED: 670 case MAC_STAT_MULTIRCV: 671 case MAC_STAT_MULTIXMT: 672 case MAC_STAT_BRDCSTRCV: 673 case MAC_STAT_BRDCSTXMT: 674 case MAC_STAT_OPACKETS: 675 case MAC_STAT_OBYTES: 676 case MAC_STAT_IERRORS: 677 case MAC_STAT_OERRORS: 678 case MAC_STAT_RBYTES: 679 case MAC_STAT_IPACKETS: 680 *val = mac_client_stat_get(vnic->vn_mch, stat); 681 break; 682 default: 683 rval = ENOTSUP; 684 } 685 686 return (rval); 687 } 688 689 /* 690 * Invoked by the upper MAC to retrieve the lower MAC client handle 691 * corresponding to a VNIC. A pointer to this function is obtained 692 * by the upper MAC via capability query. 693 * 694 * XXX-nicolas Note: this currently causes all VNIC MAC clients to 695 * receive the same MAC client handle for the same VNIC. This is ok 696 * as long as we have only one VNIC MAC client which sends and 697 * receives data, but we don't currently enforce this at the MAC layer. 698 */ 699 static void * 700 vnic_mac_client_handle(void *vnic_arg) 701 { 702 vnic_t *vnic = vnic_arg; 703 704 return (vnic->vn_mch); 705 } 706 707 708 /* 709 * Return information about the specified capability. 710 */ 711 /* ARGSUSED */ 712 static boolean_t 713 vnic_m_capab_get(void *arg, mac_capab_t cap, void *cap_data) 714 { 715 vnic_t *vnic = arg; 716 717 switch (cap) { 718 case MAC_CAPAB_HCKSUM: { 719 uint32_t *hcksum_txflags = cap_data; 720 721 *hcksum_txflags = vnic->vn_hcksum_txflags & 722 (HCKSUM_INET_FULL_V4 | HCKSUM_IPHDRCKSUM | 723 HCKSUM_INET_PARTIAL); 724 break; 725 } 726 case MAC_CAPAB_VNIC: { 727 mac_capab_vnic_t *vnic_capab = cap_data; 728 729 if (vnic->vn_lower_mh == NULL) { 730 /* 731 * It's an anchor VNIC, we don't have an underlying 732 * NIC and MAC client handle. 733 */ 734 return (B_FALSE); 735 } 736 737 if (vnic_capab != NULL) { 738 vnic_capab->mcv_arg = vnic; 739 vnic_capab->mcv_mac_client_handle = 740 vnic_mac_client_handle; 741 } 742 break; 743 } 744 case MAC_CAPAB_ANCHOR_VNIC: { 745 /* since it's an anchor VNIC we don't have lower mac handle */ 746 if (vnic->vn_lower_mh == NULL) { 747 ASSERT(vnic->vn_link_id == 0); 748 return (B_TRUE); 749 } 750 return (B_FALSE); 751 } 752 case MAC_CAPAB_NO_NATIVEVLAN: 753 case MAC_CAPAB_NO_ZCOPY: 754 return (B_TRUE); 755 default: 756 return (B_FALSE); 757 } 758 return (B_TRUE); 759 } 760 761 /* ARGSUSED */ 762 static int 763 vnic_m_start(void *arg) 764 { 765 return (0); 766 } 767 768 /* ARGSUSED */ 769 static void 770 vnic_m_stop(void *arg) 771 { 772 } 773 774 /* ARGSUSED */ 775 static int 776 vnic_m_promisc(void *arg, boolean_t on) 777 { 778 return (0); 779 } 780 781 /* ARGSUSED */ 782 static int 783 vnic_m_multicst(void *arg, boolean_t add, const uint8_t *addrp) 784 { 785 return (0); 786 } 787 788 static int 789 vnic_m_unicst(void *arg, const uint8_t *macaddr) 790 { 791 vnic_t *vnic = arg; 792 793 return (mac_vnic_unicast_set(vnic->vn_mch, macaddr)); 794 } 795 796 /* 797 * Callback functions for set/get of properties 798 */ 799 /*ARGSUSED*/ 800 static int 801 vnic_m_setprop(void *m_driver, const char *pr_name, mac_prop_id_t pr_num, 802 uint_t pr_valsize, const void *pr_val) 803 { 804 int err = ENOTSUP; 805 vnic_t *vn = m_driver; 806 807 /* allow setting MTU only on an etherstub */ 808 if (vn->vn_link_id != DATALINK_INVALID_LINKID) 809 return (err); 810 811 switch (pr_num) { 812 case MAC_PROP_MTU: { 813 uint32_t mtu; 814 815 if (pr_valsize < sizeof (mtu)) { 816 err = EINVAL; 817 break; 818 } 819 bcopy(pr_val, &mtu, sizeof (mtu)); 820 err = mac_maxsdu_update(vn->vn_mh, mtu); 821 break; 822 } 823 default: 824 break; 825 } 826 return (err); 827 } 828 829 /*ARGSUSED*/ 830 static int 831 vnic_m_getprop(void *m_driver, const char *pr_name, mac_prop_id_t pr_num, 832 uint_t pr_flags, uint_t pr_valsize, void *pr_val, uint_t *perm) 833 { 834 return (ENOTSUP); 835 } 836 837 838 int 839 vnic_info(vnic_info_t *info) 840 { 841 vnic_t *vnic; 842 int err; 843 844 rw_enter(&vnic_lock, RW_WRITER); 845 846 err = mod_hash_find(vnic_hash, VNIC_HASH_KEY(info->vn_vnic_id), 847 (mod_hash_val_t *)&vnic); 848 if (err != 0) { 849 rw_exit(&vnic_lock); 850 return (ENOENT); 851 } 852 853 info->vn_link_id = vnic->vn_link_id; 854 info->vn_mac_addr_type = vnic->vn_addr_type; 855 info->vn_mac_len = vnic->vn_addr_len; 856 bcopy(vnic->vn_addr, info->vn_mac_addr, MAXMACADDRLEN); 857 info->vn_mac_slot = vnic->vn_slot_id; 858 info->vn_mac_prefix_len = 0; 859 info->vn_vid = vnic->vn_vid; 860 info->vn_force = vnic->vn_force; 861 862 bzero(&info->vn_resource_props, sizeof (mac_resource_props_t)); 863 if (vnic->vn_mch != NULL) 864 mac_resource_ctl_get(vnic->vn_mch, &info->vn_resource_props); 865 866 rw_exit(&vnic_lock); 867 return (0); 868 } 869 870 static void 871 vnic_notify_cb(void *arg, mac_notify_type_t type) 872 { 873 vnic_t *vnic = arg; 874 875 /* 876 * Do not deliver notifications if the vnic is not fully initialized 877 * or is in process of being torn down. 878 */ 879 if (!vnic->vn_enabled) 880 return; 881 882 switch (type) { 883 case MAC_NOTE_UNICST: 884 /* 885 * Only the VLAN VNIC needs to be notified with primary MAC 886 * address change. 887 */ 888 if (vnic->vn_addr_type != VNIC_MAC_ADDR_TYPE_PRIMARY) 889 return; 890 891 /* the unicast MAC address value */ 892 mac_unicast_primary_get(vnic->vn_lower_mh, vnic->vn_addr); 893 894 /* notify its upper layer MAC about MAC address change */ 895 mac_unicst_update(vnic->vn_mh, (const uint8_t *)vnic->vn_addr); 896 break; 897 898 case MAC_NOTE_LINK: 899 mac_link_update(vnic->vn_mh, 900 mac_client_stat_get(vnic->vn_mch, MAC_STAT_LINK_STATE)); 901 break; 902 903 default: 904 break; 905 } 906 } 907