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