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