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 /* 23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* 28 * - General Introduction: 29 * 30 * This file contains the implementation of the MAC client kernel 31 * API and related code. The MAC client API allows a kernel module 32 * to gain access to a MAC instance (physical NIC, link aggregation, etc). 33 * It allows a MAC client to associate itself with a MAC address, 34 * VLANs, callback functions for data traffic and for promiscuous mode. 35 * The MAC client API is also used to specify the properties associated 36 * with a MAC client, such as bandwidth limits, priority, CPUS, etc. 37 * These properties are further used to determine the hardware resources 38 * to allocate to the various MAC clients. 39 * 40 * - Primary MAC clients: 41 * 42 * The MAC client API refers to "primary MAC clients". A primary MAC 43 * client is a client which "owns" the primary MAC address of 44 * the underlying MAC instance. The primary MAC address is called out 45 * since it is associated with specific semantics: the primary MAC 46 * address is the MAC address which is assigned to the IP interface 47 * when it is plumbed, and the primary MAC address is assigned 48 * to VLAN data-links. The primary address of a MAC instance can 49 * also change dynamically from under the MAC client, for example 50 * as a result of a change of state of a link aggregation. In that 51 * case the MAC layer automatically updates all data-structures which 52 * refer to the current value of the primary MAC address. Typical 53 * primary MAC clients are dls, aggr, and xnb. A typical non-primary 54 * MAC client is the vnic driver. 55 * 56 * - Virtual Switching: 57 * 58 * The MAC layer implements a virtual switch between the MAC clients 59 * (primary and non-primary) defined on top of the same underlying 60 * NIC (physical, link aggregation, etc). The virtual switch is 61 * VLAN-aware, i.e. it allows multiple MAC clients to be member 62 * of one or more VLANs, and the virtual switch will distribute 63 * multicast tagged packets only to the member of the corresponding 64 * VLANs. 65 * 66 * - Upper vs Lower MAC: 67 * 68 * Creating a VNIC on top of a MAC instance effectively causes 69 * two MAC instances to be layered on top of each other, one for 70 * the VNIC(s), one for the underlying MAC instance (physical NIC, 71 * link aggregation, etc). In the code below we refer to the 72 * underlying NIC as the "lower MAC", and we refer to VNICs as 73 * the "upper MAC". 74 * 75 * - Pass-through for VNICs: 76 * 77 * When VNICs are created on top of an underlying MAC, this causes 78 * a layering of two MAC instances. Since the lower MAC already 79 * does the switching and demultiplexing to its MAC clients, the 80 * upper MAC would simply have to pass packets to the layer below 81 * or above it, which would introduce overhead. In order to avoid 82 * this overhead, the MAC layer implements a pass-through mechanism 83 * for VNICs. When a VNIC opens the lower MAC instance, it saves 84 * the MAC client handle it optains from the MAC layer. When a MAC 85 * client opens a VNIC (upper MAC), the MAC layer detects that 86 * the MAC being opened is a VNIC, and gets the MAC client handle 87 * that the VNIC driver obtained from the lower MAC. This exchange 88 * is doing through a private capability between the MAC layer 89 * and the VNIC driver. The upper MAC then returns that handle 90 * directly to its MAC client. Any operation done by the upper 91 * MAC client is now done on the lower MAC client handle, which 92 * allows the VNIC driver to be completely bypassed for the 93 * performance sensitive data-path. 94 * 95 */ 96 97 #include <sys/types.h> 98 #include <sys/conf.h> 99 #include <sys/id_space.h> 100 #include <sys/esunddi.h> 101 #include <sys/stat.h> 102 #include <sys/mkdev.h> 103 #include <sys/stream.h> 104 #include <sys/strsun.h> 105 #include <sys/strsubr.h> 106 #include <sys/dlpi.h> 107 #include <sys/modhash.h> 108 #include <sys/mac_impl.h> 109 #include <sys/mac_client_impl.h> 110 #include <sys/mac_soft_ring.h> 111 #include <sys/dls.h> 112 #include <sys/dld.h> 113 #include <sys/modctl.h> 114 #include <sys/fs/dv_node.h> 115 #include <sys/thread.h> 116 #include <sys/proc.h> 117 #include <sys/callb.h> 118 #include <sys/cpuvar.h> 119 #include <sys/atomic.h> 120 #include <sys/sdt.h> 121 #include <sys/mac_flow.h> 122 #include <sys/ddi_intr_impl.h> 123 #include <sys/disp.h> 124 #include <sys/sdt.h> 125 #include <sys/vnic.h> 126 #include <sys/vnic_impl.h> 127 #include <sys/vlan.h> 128 #include <inet/ip.h> 129 #include <inet/ip6.h> 130 #include <sys/exacct.h> 131 #include <sys/exacct_impl.h> 132 #include <inet/nd.h> 133 #include <sys/ethernet.h> 134 135 kmem_cache_t *mac_client_impl_cache; 136 kmem_cache_t *mac_promisc_impl_cache; 137 138 static boolean_t mac_client_single_rcvr(mac_client_impl_t *); 139 static flow_entry_t *mac_client_swap_mciflent(mac_client_impl_t *); 140 static flow_entry_t *mac_client_get_flow(mac_client_impl_t *, 141 mac_unicast_impl_t *); 142 static void mac_client_remove_flow_from_list(mac_client_impl_t *, 143 flow_entry_t *); 144 static void mac_client_add_to_flow_list(mac_client_impl_t *, flow_entry_t *); 145 static void mac_rename_flow_names(mac_client_impl_t *, const char *); 146 static void mac_virtual_link_update(mac_impl_t *); 147 148 /* ARGSUSED */ 149 static int 150 i_mac_client_impl_ctor(void *buf, void *arg, int kmflag) 151 { 152 int i; 153 mac_client_impl_t *mcip = buf; 154 155 bzero(buf, MAC_CLIENT_IMPL_SIZE); 156 mutex_init(&mcip->mci_tx_cb_lock, NULL, MUTEX_DRIVER, NULL); 157 mcip->mci_tx_notify_cb_info.mcbi_lockp = &mcip->mci_tx_cb_lock; 158 159 ASSERT(mac_tx_percpu_cnt >= 0); 160 for (i = 0; i <= mac_tx_percpu_cnt; i++) { 161 mutex_init(&mcip->mci_tx_pcpu[i].pcpu_tx_lock, NULL, 162 MUTEX_DRIVER, NULL); 163 } 164 cv_init(&mcip->mci_tx_cv, NULL, CV_DRIVER, NULL); 165 166 return (0); 167 } 168 169 /* ARGSUSED */ 170 static void 171 i_mac_client_impl_dtor(void *buf, void *arg) 172 { 173 int i; 174 mac_client_impl_t *mcip = buf; 175 176 ASSERT(mcip->mci_promisc_list == NULL); 177 ASSERT(mcip->mci_unicast_list == NULL); 178 ASSERT(mcip->mci_state_flags == 0); 179 ASSERT(mcip->mci_tx_flag == 0); 180 181 mutex_destroy(&mcip->mci_tx_cb_lock); 182 183 ASSERT(mac_tx_percpu_cnt >= 0); 184 for (i = 0; i <= mac_tx_percpu_cnt; i++) { 185 ASSERT(mcip->mci_tx_pcpu[i].pcpu_tx_refcnt == 0); 186 mutex_destroy(&mcip->mci_tx_pcpu[i].pcpu_tx_lock); 187 } 188 cv_destroy(&mcip->mci_tx_cv); 189 } 190 191 /* ARGSUSED */ 192 static int 193 i_mac_promisc_impl_ctor(void *buf, void *arg, int kmflag) 194 { 195 mac_promisc_impl_t *mpip = buf; 196 197 bzero(buf, sizeof (mac_promisc_impl_t)); 198 mpip->mpi_mci_link.mcb_objp = buf; 199 mpip->mpi_mci_link.mcb_objsize = sizeof (mac_promisc_impl_t); 200 mpip->mpi_mi_link.mcb_objp = buf; 201 mpip->mpi_mi_link.mcb_objsize = sizeof (mac_promisc_impl_t); 202 return (0); 203 } 204 205 /* ARGSUSED */ 206 static void 207 i_mac_promisc_impl_dtor(void *buf, void *arg) 208 { 209 mac_promisc_impl_t *mpip = buf; 210 211 ASSERT(mpip->mpi_mci_link.mcb_objp != NULL); 212 ASSERT(mpip->mpi_mci_link.mcb_objsize == sizeof (mac_promisc_impl_t)); 213 ASSERT(mpip->mpi_mi_link.mcb_objp == mpip->mpi_mci_link.mcb_objp); 214 ASSERT(mpip->mpi_mi_link.mcb_objsize == sizeof (mac_promisc_impl_t)); 215 216 mpip->mpi_mci_link.mcb_objp = NULL; 217 mpip->mpi_mci_link.mcb_objsize = 0; 218 mpip->mpi_mi_link.mcb_objp = NULL; 219 mpip->mpi_mi_link.mcb_objsize = 0; 220 221 ASSERT(mpip->mpi_mci_link.mcb_flags == 0); 222 mpip->mpi_mci_link.mcb_objsize = 0; 223 } 224 225 void 226 mac_client_init(void) 227 { 228 ASSERT(mac_tx_percpu_cnt >= 0); 229 230 mac_client_impl_cache = kmem_cache_create("mac_client_impl_cache", 231 MAC_CLIENT_IMPL_SIZE, 0, i_mac_client_impl_ctor, 232 i_mac_client_impl_dtor, NULL, NULL, NULL, 0); 233 ASSERT(mac_client_impl_cache != NULL); 234 235 mac_promisc_impl_cache = kmem_cache_create("mac_promisc_impl_cache", 236 sizeof (mac_promisc_impl_t), 0, i_mac_promisc_impl_ctor, 237 i_mac_promisc_impl_dtor, NULL, NULL, NULL, 0); 238 ASSERT(mac_promisc_impl_cache != NULL); 239 } 240 241 void 242 mac_client_fini(void) 243 { 244 kmem_cache_destroy(mac_client_impl_cache); 245 kmem_cache_destroy(mac_promisc_impl_cache); 246 } 247 248 /* 249 * Return the lower MAC client handle from the VNIC driver for the 250 * specified VNIC MAC instance. 251 */ 252 mac_client_impl_t * 253 mac_vnic_lower(mac_impl_t *mip) 254 { 255 mac_capab_vnic_t cap; 256 mac_client_impl_t *mcip; 257 258 VERIFY(i_mac_capab_get((mac_handle_t)mip, MAC_CAPAB_VNIC, &cap)); 259 mcip = cap.mcv_mac_client_handle(cap.mcv_arg); 260 261 return (mcip); 262 } 263 264 /* 265 * Return the MAC client handle of the primary MAC client for the 266 * specified MAC instance, or NULL otherwise. 267 */ 268 mac_client_impl_t * 269 mac_primary_client_handle(mac_impl_t *mip) 270 { 271 mac_client_impl_t *mcip; 272 273 if (mip->mi_state_flags & MIS_IS_VNIC) 274 return (mac_vnic_lower(mip)); 275 276 ASSERT(MAC_PERIM_HELD((mac_handle_t)mip)); 277 278 for (mcip = mip->mi_clients_list; mcip != NULL; 279 mcip = mcip->mci_client_next) { 280 if (MCIP_DATAPATH_SETUP(mcip) && mac_is_primary_client(mcip)) 281 return (mcip); 282 } 283 return (NULL); 284 } 285 286 /* 287 * Open a MAC specified by its MAC name. 288 */ 289 int 290 mac_open(const char *macname, mac_handle_t *mhp) 291 { 292 mac_impl_t *mip; 293 int err; 294 295 /* 296 * Look up its entry in the global hash table. 297 */ 298 if ((err = mac_hold(macname, &mip)) != 0) 299 return (err); 300 301 /* 302 * Hold the dip associated to the MAC to prevent it from being 303 * detached. For a softmac, its underlying dip is held by the 304 * mi_open() callback. 305 * 306 * This is done to be more tolerant with some defective drivers, 307 * which incorrectly handle mac_unregister() failure in their 308 * xxx_detach() routine. For example, some drivers ignore the 309 * failure of mac_unregister() and free all resources that 310 * that are needed for data transmition. 311 */ 312 e_ddi_hold_devi(mip->mi_dip); 313 314 if (!(mip->mi_callbacks->mc_callbacks & MC_OPEN)) { 315 *mhp = (mac_handle_t)mip; 316 return (0); 317 } 318 319 /* 320 * The mac perimeter is used in both mac_open and mac_close by the 321 * framework to single thread the MC_OPEN/MC_CLOSE of drivers. 322 */ 323 i_mac_perim_enter(mip); 324 mip->mi_oref++; 325 if (mip->mi_oref != 1 || ((err = mip->mi_open(mip->mi_driver)) == 0)) { 326 *mhp = (mac_handle_t)mip; 327 i_mac_perim_exit(mip); 328 return (0); 329 } 330 mip->mi_oref--; 331 ddi_release_devi(mip->mi_dip); 332 mac_rele(mip); 333 i_mac_perim_exit(mip); 334 return (err); 335 } 336 337 /* 338 * Open a MAC specified by its linkid. 339 */ 340 int 341 mac_open_by_linkid(datalink_id_t linkid, mac_handle_t *mhp) 342 { 343 dls_dl_handle_t dlh; 344 int err; 345 346 if ((err = dls_devnet_hold_tmp(linkid, &dlh)) != 0) 347 return (err); 348 349 dls_devnet_prop_task_wait(dlh); 350 351 err = mac_open(dls_devnet_mac(dlh), mhp); 352 353 dls_devnet_rele_tmp(dlh); 354 return (err); 355 } 356 357 /* 358 * Open a MAC specified by its link name. 359 */ 360 int 361 mac_open_by_linkname(const char *link, mac_handle_t *mhp) 362 { 363 datalink_id_t linkid; 364 int err; 365 366 if ((err = dls_mgmt_get_linkid(link, &linkid)) != 0) 367 return (err); 368 return (mac_open_by_linkid(linkid, mhp)); 369 } 370 371 /* 372 * Close the specified MAC. 373 */ 374 void 375 mac_close(mac_handle_t mh) 376 { 377 mac_impl_t *mip = (mac_impl_t *)mh; 378 379 i_mac_perim_enter(mip); 380 /* 381 * The mac perimeter is used in both mac_open and mac_close by the 382 * framework to single thread the MC_OPEN/MC_CLOSE of drivers. 383 */ 384 if (mip->mi_callbacks->mc_callbacks & MC_OPEN) { 385 ASSERT(mip->mi_oref != 0); 386 if (--mip->mi_oref == 0) { 387 if ((mip->mi_callbacks->mc_callbacks & MC_CLOSE)) 388 mip->mi_close(mip->mi_driver); 389 } 390 } 391 i_mac_perim_exit(mip); 392 ddi_release_devi(mip->mi_dip); 393 mac_rele(mip); 394 } 395 396 /* 397 * Misc utility functions to retrieve various information about a MAC 398 * instance or a MAC client. 399 */ 400 401 const mac_info_t * 402 mac_info(mac_handle_t mh) 403 { 404 return (&((mac_impl_t *)mh)->mi_info); 405 } 406 407 dev_info_t * 408 mac_devinfo_get(mac_handle_t mh) 409 { 410 return (((mac_impl_t *)mh)->mi_dip); 411 } 412 413 const char * 414 mac_name(mac_handle_t mh) 415 { 416 return (((mac_impl_t *)mh)->mi_name); 417 } 418 419 char * 420 mac_client_name(mac_client_handle_t mch) 421 { 422 return (((mac_client_impl_t *)mch)->mci_name); 423 } 424 425 minor_t 426 mac_minor(mac_handle_t mh) 427 { 428 return (((mac_impl_t *)mh)->mi_minor); 429 } 430 431 /* 432 * Return the VID associated with a MAC client. This function should 433 * be called for clients which are associated with only one VID. 434 */ 435 uint16_t 436 mac_client_vid(mac_client_handle_t mch) 437 { 438 uint16_t vid = VLAN_ID_NONE; 439 mac_client_impl_t *mcip = (mac_client_impl_t *)mch; 440 flow_desc_t flow_desc; 441 442 if (mcip->mci_nflents == 0) 443 return (vid); 444 445 ASSERT(MCIP_DATAPATH_SETUP(mcip) && mac_client_single_rcvr(mcip)); 446 447 mac_flow_get_desc(mcip->mci_flent, &flow_desc); 448 if ((flow_desc.fd_mask & FLOW_LINK_VID) != 0) 449 vid = flow_desc.fd_vid; 450 451 return (vid); 452 } 453 454 /* 455 * Return the link speed associated with the specified MAC client. 456 * 457 * The link speed of a MAC client is equal to the smallest value of 458 * 1) the current link speed of the underlying NIC, or 459 * 2) the bandwidth limit set for the MAC client. 460 * 461 * Note that the bandwidth limit can be higher than the speed 462 * of the underlying NIC. This is allowed to avoid spurious 463 * administration action failures or artifically lowering the 464 * bandwidth limit of a link that may have temporarily lowered 465 * its link speed due to hardware problem or administrator action. 466 */ 467 static uint64_t 468 mac_client_ifspeed(mac_client_impl_t *mcip) 469 { 470 mac_impl_t *mip = mcip->mci_mip; 471 uint64_t nic_speed; 472 473 nic_speed = mac_stat_get((mac_handle_t)mip, MAC_STAT_IFSPEED); 474 475 if (nic_speed == 0) { 476 return (0); 477 } else { 478 uint64_t policy_limit = (uint64_t)-1; 479 480 if (MCIP_RESOURCE_PROPS_MASK(mcip) & MRP_MAXBW) 481 policy_limit = MCIP_RESOURCE_PROPS_MAXBW(mcip); 482 483 return (MIN(policy_limit, nic_speed)); 484 } 485 } 486 487 /* 488 * Return the link state of the specified client. If here are more 489 * than one clients of the underying mac_impl_t, the link state 490 * will always be UP regardless of the link state of the underlying 491 * mac_impl_t. This is needed to allow the MAC clients to continue 492 * to communicate with each other even when the physical link of 493 * their mac_impl_t is down. 494 */ 495 static uint64_t 496 mac_client_link_state(mac_client_impl_t *mcip) 497 { 498 mac_impl_t *mip = mcip->mci_mip; 499 uint16_t vid; 500 mac_client_impl_t *mci_list; 501 mac_unicast_impl_t *mui_list, *oth_mui_list; 502 503 /* 504 * Returns LINK_STATE_UP if there are other MAC clients defined on 505 * mac_impl_t which share same VLAN ID as that of mcip. Note that 506 * if 'mcip' has more than one VID's then we match ANY one of the 507 * VID's with other MAC client's VID's and return LINK_STATE_UP. 508 */ 509 rw_enter(&mcip->mci_rw_lock, RW_READER); 510 for (mui_list = mcip->mci_unicast_list; mui_list != NULL; 511 mui_list = mui_list->mui_next) { 512 vid = mui_list->mui_vid; 513 for (mci_list = mip->mi_clients_list; mci_list != NULL; 514 mci_list = mci_list->mci_client_next) { 515 if (mci_list == mcip) 516 continue; 517 for (oth_mui_list = mci_list->mci_unicast_list; 518 oth_mui_list != NULL; oth_mui_list = oth_mui_list-> 519 mui_next) { 520 if (vid == oth_mui_list->mui_vid) { 521 rw_exit(&mcip->mci_rw_lock); 522 return (LINK_STATE_UP); 523 } 524 } 525 } 526 } 527 rw_exit(&mcip->mci_rw_lock); 528 529 return (mac_stat_get((mac_handle_t)mip, MAC_STAT_LINK_STATE)); 530 } 531 532 /* 533 * Return the statistics of a MAC client. These statistics are different 534 * then the statistics of the underlying MAC which are returned by 535 * mac_stat_get(). 536 */ 537 uint64_t 538 mac_client_stat_get(mac_client_handle_t mch, uint_t stat) 539 { 540 mac_client_impl_t *mcip = (mac_client_impl_t *)mch; 541 mac_impl_t *mip = mcip->mci_mip; 542 uint64_t val; 543 544 switch (stat) { 545 case MAC_STAT_LINK_STATE: 546 val = mac_client_link_state(mcip); 547 break; 548 case MAC_STAT_LINK_UP: 549 val = (mac_client_link_state(mcip) == LINK_STATE_UP); 550 break; 551 case MAC_STAT_PROMISC: 552 val = mac_stat_get((mac_handle_t)mip, MAC_STAT_PROMISC); 553 break; 554 case MAC_STAT_IFSPEED: 555 val = mac_client_ifspeed(mcip); 556 break; 557 case MAC_STAT_MULTIRCV: 558 val = mcip->mci_stat_multircv; 559 break; 560 case MAC_STAT_BRDCSTRCV: 561 val = mcip->mci_stat_brdcstrcv; 562 break; 563 case MAC_STAT_MULTIXMT: 564 val = mcip->mci_stat_multixmt; 565 break; 566 case MAC_STAT_BRDCSTXMT: 567 val = mcip->mci_stat_brdcstxmt; 568 break; 569 case MAC_STAT_OBYTES: 570 val = mcip->mci_stat_obytes; 571 break; 572 case MAC_STAT_OPACKETS: 573 val = mcip->mci_stat_opackets; 574 break; 575 case MAC_STAT_OERRORS: 576 val = mcip->mci_stat_oerrors; 577 break; 578 case MAC_STAT_IPACKETS: 579 val = mcip->mci_stat_ipackets; 580 break; 581 case MAC_STAT_RBYTES: 582 val = mcip->mci_stat_ibytes; 583 break; 584 case MAC_STAT_IERRORS: 585 val = mcip->mci_stat_ierrors; 586 break; 587 default: 588 val = mac_stat_default(mip, stat); 589 break; 590 } 591 592 return (val); 593 } 594 595 /* 596 * Return the statistics of the specified MAC instance. 597 */ 598 uint64_t 599 mac_stat_get(mac_handle_t mh, uint_t stat) 600 { 601 mac_impl_t *mip = (mac_impl_t *)mh; 602 uint64_t val; 603 int ret; 604 605 /* 606 * The range of stat determines where it is maintained. Stat 607 * values from 0 up to (but not including) MAC_STAT_MIN are 608 * mainteined by the mac module itself. Everything else is 609 * maintained by the driver. 610 * 611 * If the mac_impl_t being queried corresponds to a VNIC, 612 * the stats need to be queried from the lower MAC client 613 * corresponding to the VNIC. (The mac_link_update() 614 * invoked by the driver to the lower MAC causes the *lower 615 * MAC* to update its mi_linkstate, and send a notification 616 * to its MAC clients. Due to the VNIC passthrough, 617 * these notifications are sent to the upper MAC clients 618 * of the VNIC directly, and the upper mac_impl_t of the VNIC 619 * does not have a valid mi_linkstate. 620 */ 621 if (stat < MAC_STAT_MIN && !(mip->mi_state_flags & MIS_IS_VNIC)) { 622 /* these stats are maintained by the mac module itself */ 623 switch (stat) { 624 case MAC_STAT_LINK_STATE: 625 return (mip->mi_linkstate); 626 case MAC_STAT_LINK_UP: 627 return (mip->mi_linkstate == LINK_STATE_UP); 628 case MAC_STAT_PROMISC: 629 return (mip->mi_devpromisc != 0); 630 default: 631 ASSERT(B_FALSE); 632 } 633 } 634 635 /* 636 * Call the driver to get the given statistic. 637 */ 638 ret = mip->mi_getstat(mip->mi_driver, stat, &val); 639 if (ret != 0) { 640 /* 641 * The driver doesn't support this statistic. Get the 642 * statistic's default value. 643 */ 644 val = mac_stat_default(mip, stat); 645 } 646 return (val); 647 } 648 649 /* 650 * Utility function which returns the VID associated with a flow entry. 651 */ 652 uint16_t 653 i_mac_flow_vid(flow_entry_t *flent) 654 { 655 flow_desc_t flow_desc; 656 657 mac_flow_get_desc(flent, &flow_desc); 658 659 if ((flow_desc.fd_mask & FLOW_LINK_VID) != 0) 660 return (flow_desc.fd_vid); 661 return (VLAN_ID_NONE); 662 } 663 664 /* 665 * Verify the validity of the specified unicast MAC address. Returns B_TRUE 666 * if the address is valid, B_FALSE otherwise (multicast address, or incorrect 667 * length. 668 */ 669 boolean_t 670 mac_unicst_verify(mac_handle_t mh, const uint8_t *addr, uint_t len) 671 { 672 mac_impl_t *mip = (mac_impl_t *)mh; 673 674 /* 675 * Verify the address. No lock is needed since mi_type and plugin 676 * details don't change after mac_register(). 677 */ 678 if ((len != mip->mi_type->mt_addr_length) || 679 (mip->mi_type->mt_ops.mtops_unicst_verify(addr, 680 mip->mi_pdata)) != 0) { 681 return (B_FALSE); 682 } else { 683 return (B_TRUE); 684 } 685 } 686 687 void 688 mac_sdu_get(mac_handle_t mh, uint_t *min_sdu, uint_t *max_sdu) 689 { 690 mac_impl_t *mip = (mac_impl_t *)mh; 691 692 if (min_sdu != NULL) 693 *min_sdu = mip->mi_sdu_min; 694 if (max_sdu != NULL) 695 *max_sdu = mip->mi_sdu_max; 696 } 697 698 /* 699 * Update the MAC unicast address of the specified client's flows. Currently 700 * only one unicast MAC unicast address is allowed per client. 701 */ 702 static void 703 mac_unicast_update_client_flow(mac_client_impl_t *mcip) 704 { 705 mac_impl_t *mip = mcip->mci_mip; 706 flow_entry_t *flent = mcip->mci_flent; 707 mac_address_t *map = mcip->mci_unicast; 708 flow_desc_t flow_desc; 709 710 ASSERT(MAC_PERIM_HELD((mac_handle_t)mip)); 711 ASSERT(flent != NULL); 712 713 mac_flow_get_desc(flent, &flow_desc); 714 ASSERT(flow_desc.fd_mask & FLOW_LINK_DST); 715 716 bcopy(map->ma_addr, flow_desc.fd_dst_mac, map->ma_len); 717 mac_flow_set_desc(flent, &flow_desc); 718 719 /* 720 * A MAC client could have one MAC address but multiple 721 * VLANs. In that case update the flow entries corresponding 722 * to all VLANs of the MAC client. 723 */ 724 for (flent = mcip->mci_flent_list; flent != NULL; 725 flent = flent->fe_client_next) { 726 mac_flow_get_desc(flent, &flow_desc); 727 if (!(flent->fe_type & FLOW_PRIMARY_MAC || 728 flent->fe_type & FLOW_VNIC_MAC)) 729 continue; 730 731 bcopy(map->ma_addr, flow_desc.fd_dst_mac, map->ma_len); 732 mac_flow_set_desc(flent, &flow_desc); 733 } 734 } 735 736 /* 737 * Update all clients that share the same unicast address. 738 */ 739 void 740 mac_unicast_update_clients(mac_impl_t *mip, mac_address_t *map) 741 { 742 mac_client_impl_t *mcip; 743 744 ASSERT(MAC_PERIM_HELD((mac_handle_t)mip)); 745 746 /* 747 * Find all clients that share the same unicast MAC address and update 748 * them appropriately. 749 */ 750 for (mcip = mip->mi_clients_list; mcip != NULL; 751 mcip = mcip->mci_client_next) { 752 /* 753 * Ignore clients that don't share this MAC address. 754 */ 755 if (map != mcip->mci_unicast) 756 continue; 757 758 /* 759 * Update those clients with same old unicast MAC address. 760 */ 761 mac_unicast_update_client_flow(mcip); 762 } 763 } 764 765 /* 766 * Update the unicast MAC address of the specified VNIC MAC client. 767 * 768 * Check whether the operation is valid. Any of following cases should fail: 769 * 770 * 1. It's a VLAN type of VNIC. 771 * 2. The new value is current "primary" MAC address. 772 * 3. The current MAC address is shared with other clients. 773 * 4. The new MAC address has been used. This case will be valid when 774 * client migration is fully supported. 775 */ 776 int 777 mac_vnic_unicast_set(mac_client_handle_t mch, const uint8_t *addr) 778 { 779 mac_client_impl_t *mcip = (mac_client_impl_t *)mch; 780 mac_impl_t *mip = mcip->mci_mip; 781 mac_address_t *map = mcip->mci_unicast; 782 int err; 783 784 ASSERT(!(mip->mi_state_flags & MIS_IS_VNIC)); 785 ASSERT(mcip->mci_state_flags & MCIS_IS_VNIC); 786 ASSERT(mcip->mci_flags != MAC_CLIENT_FLAGS_PRIMARY); 787 788 i_mac_perim_enter(mip); 789 790 /* 791 * If this is a VLAN type of VNIC, it's using "primary" MAC address 792 * of the underlying interface. Must fail here. Refer to case 1 above. 793 */ 794 if (bcmp(map->ma_addr, mip->mi_addr, map->ma_len) == 0) { 795 i_mac_perim_exit(mip); 796 return (ENOTSUP); 797 } 798 799 /* 800 * If the new address is the "primary" one, must fail. Refer to 801 * case 2 above. 802 */ 803 if (bcmp(addr, mip->mi_addr, map->ma_len) == 0) { 804 i_mac_perim_exit(mip); 805 return (EACCES); 806 } 807 808 /* 809 * If the address is shared by multiple clients, must fail. Refer 810 * to case 3 above. 811 */ 812 if (mac_check_macaddr_shared(map)) { 813 i_mac_perim_exit(mip); 814 return (EBUSY); 815 } 816 817 /* 818 * If the new address has been used, must fail for now. Refer to 819 * case 4 above. 820 */ 821 if (mac_find_macaddr(mip, (uint8_t *)addr) != NULL) { 822 i_mac_perim_exit(mip); 823 return (ENOTSUP); 824 } 825 826 /* 827 * Update the MAC address. 828 */ 829 err = mac_update_macaddr(map, (uint8_t *)addr); 830 831 if (err != 0) { 832 i_mac_perim_exit(mip); 833 return (err); 834 } 835 836 /* 837 * Update all flows of this MAC client. 838 */ 839 mac_unicast_update_client_flow(mcip); 840 841 i_mac_perim_exit(mip); 842 return (0); 843 } 844 845 /* 846 * Program the new primary unicast address of the specified MAC. 847 * 848 * Function mac_update_macaddr() takes care different types of underlying 849 * MAC. If the underlying MAC is VNIC, the VNIC driver must have registerd 850 * mi_unicst() entry point, that indirectly calls mac_vnic_unicast_set() 851 * which will take care of updating the MAC address of the corresponding 852 * MAC client. 853 * 854 * This is the only interface that allow the client to update the "primary" 855 * MAC address of the underlying MAC. The new value must have not been 856 * used by other clients. 857 */ 858 int 859 mac_unicast_primary_set(mac_handle_t mh, const uint8_t *addr) 860 { 861 mac_impl_t *mip = (mac_impl_t *)mh; 862 mac_address_t *map; 863 int err; 864 865 /* verify the address validity */ 866 if (!mac_unicst_verify(mh, addr, mip->mi_type->mt_addr_length)) 867 return (EINVAL); 868 869 i_mac_perim_enter(mip); 870 871 /* 872 * If the new value is the same as the current primary address value, 873 * there's nothing to do. 874 */ 875 if (bcmp(addr, mip->mi_addr, mip->mi_type->mt_addr_length) == 0) { 876 i_mac_perim_exit(mip); 877 return (0); 878 } 879 880 if (mac_find_macaddr(mip, (uint8_t *)addr) != 0) { 881 i_mac_perim_exit(mip); 882 return (EBUSY); 883 } 884 885 map = mac_find_macaddr(mip, mip->mi_addr); 886 ASSERT(map != NULL); 887 888 /* 889 * Update the MAC address. 890 */ 891 if (mip->mi_state_flags & MIS_IS_AGGR) { 892 mac_capab_aggr_t aggr_cap; 893 894 /* 895 * If the mac is an aggregation, other than the unicast 896 * addresses programming, aggr must be informed about this 897 * primary unicst address change to change its mac address 898 * policy to be user-specified. 899 */ 900 ASSERT(map->ma_type == MAC_ADDRESS_TYPE_UNICAST_CLASSIFIED); 901 VERIFY(i_mac_capab_get(mh, MAC_CAPAB_AGGR, &aggr_cap)); 902 err = aggr_cap.mca_unicst(mip->mi_driver, addr); 903 if (err == 0) 904 bcopy(addr, map->ma_addr, map->ma_len); 905 } else { 906 err = mac_update_macaddr(map, (uint8_t *)addr); 907 } 908 909 if (err != 0) { 910 i_mac_perim_exit(mip); 911 return (err); 912 } 913 914 mac_unicast_update_clients(mip, map); 915 916 /* 917 * Save the new primary MAC address in mac_impl_t. 918 */ 919 bcopy(addr, mip->mi_addr, mip->mi_type->mt_addr_length); 920 921 i_mac_perim_exit(mip); 922 923 if (err == 0) 924 i_mac_notify(mip, MAC_NOTE_UNICST); 925 926 return (err); 927 } 928 929 /* 930 * Return the current primary MAC address of the specified MAC. 931 */ 932 void 933 mac_unicast_primary_get(mac_handle_t mh, uint8_t *addr) 934 { 935 mac_impl_t *mip = (mac_impl_t *)mh; 936 937 rw_enter(&mip->mi_rw_lock, RW_READER); 938 bcopy(mip->mi_addr, addr, mip->mi_type->mt_addr_length); 939 rw_exit(&mip->mi_rw_lock); 940 } 941 942 /* 943 * Return information about the use of the primary MAC address of the 944 * specified MAC instance: 945 * 946 * - if client_name is non-NULL, it must point to a string of at 947 * least MAXNAMELEN bytes, and will be set to the name of the MAC 948 * client which uses the primary MAC address. 949 * 950 * - if in_use is non-NULL, used to return whether the primary MAC 951 * address is currently in use. 952 */ 953 void 954 mac_unicast_primary_info(mac_handle_t mh, char *client_name, boolean_t *in_use) 955 { 956 mac_impl_t *mip = (mac_impl_t *)mh; 957 mac_client_impl_t *cur_client; 958 959 if (in_use != NULL) 960 *in_use = B_FALSE; 961 if (client_name != NULL) 962 bzero(client_name, MAXNAMELEN); 963 964 /* 965 * The mi_rw_lock is used to protect threads that don't hold the 966 * mac perimeter to get a consistent view of the mi_clients_list. 967 * Threads that modify the list must hold both the mac perimeter and 968 * mi_rw_lock(RW_WRITER) 969 */ 970 rw_enter(&mip->mi_rw_lock, RW_READER); 971 for (cur_client = mip->mi_clients_list; cur_client != NULL; 972 cur_client = cur_client->mci_client_next) { 973 if (mac_is_primary_client(cur_client) || 974 (mip->mi_state_flags & MIS_IS_VNIC)) { 975 rw_exit(&mip->mi_rw_lock); 976 if (in_use != NULL) 977 *in_use = B_TRUE; 978 if (client_name != NULL) { 979 bcopy(cur_client->mci_name, client_name, 980 MAXNAMELEN); 981 } 982 return; 983 } 984 } 985 rw_exit(&mip->mi_rw_lock); 986 } 987 988 /* 989 * Add the specified MAC client to the list of clients which opened 990 * the specified MAC. 991 */ 992 static void 993 mac_client_add(mac_client_impl_t *mcip) 994 { 995 mac_impl_t *mip = mcip->mci_mip; 996 997 ASSERT(MAC_PERIM_HELD((mac_handle_t)mip)); 998 999 /* add VNIC to the front of the list */ 1000 rw_enter(&mip->mi_rw_lock, RW_WRITER); 1001 mcip->mci_client_next = mip->mi_clients_list; 1002 mip->mi_clients_list = mcip; 1003 mip->mi_nclients++; 1004 rw_exit(&mip->mi_rw_lock); 1005 } 1006 1007 /* 1008 * Remove the specified MAC client from the list of clients which opened 1009 * the specified MAC. 1010 */ 1011 static void 1012 mac_client_remove(mac_client_impl_t *mcip) 1013 { 1014 mac_impl_t *mip = mcip->mci_mip; 1015 mac_client_impl_t **prev, *cclient; 1016 1017 ASSERT(MAC_PERIM_HELD((mac_handle_t)mip)); 1018 1019 rw_enter(&mip->mi_rw_lock, RW_WRITER); 1020 prev = &mip->mi_clients_list; 1021 cclient = *prev; 1022 while (cclient != NULL && cclient != mcip) { 1023 prev = &cclient->mci_client_next; 1024 cclient = *prev; 1025 } 1026 ASSERT(cclient != NULL); 1027 *prev = cclient->mci_client_next; 1028 mip->mi_nclients--; 1029 rw_exit(&mip->mi_rw_lock); 1030 } 1031 1032 static mac_unicast_impl_t * 1033 mac_client_find_vid(mac_client_impl_t *mcip, uint16_t vid) 1034 { 1035 mac_unicast_impl_t *muip = mcip->mci_unicast_list; 1036 1037 while ((muip != NULL) && (muip->mui_vid != vid)) 1038 muip = muip->mui_next; 1039 1040 return (muip); 1041 } 1042 1043 /* 1044 * Return whether the specified (MAC address, VID) tuple is already used by 1045 * one of the MAC clients associated with the specified MAC. 1046 */ 1047 static boolean_t 1048 mac_addr_in_use(mac_impl_t *mip, uint8_t *mac_addr, uint16_t vid) 1049 { 1050 mac_client_impl_t *client; 1051 mac_address_t *map; 1052 1053 ASSERT(MAC_PERIM_HELD((mac_handle_t)mip)); 1054 1055 for (client = mip->mi_clients_list; client != NULL; 1056 client = client->mci_client_next) { 1057 1058 /* 1059 * Ignore clients that don't have unicast address. 1060 */ 1061 if (client->mci_unicast_list == NULL) 1062 continue; 1063 1064 map = client->mci_unicast; 1065 1066 if ((bcmp(mac_addr, map->ma_addr, map->ma_len) == 0) && 1067 (mac_client_find_vid(client, vid) != NULL)) { 1068 return (B_TRUE); 1069 } 1070 } 1071 1072 return (B_FALSE); 1073 } 1074 1075 /* 1076 * Generate a random MAC address. The MAC address prefix is 1077 * stored in the array pointed to by mac_addr, and its length, in bytes, 1078 * is specified by prefix_len. The least significant bits 1079 * after prefix_len bytes are generated, and stored after the prefix 1080 * in the mac_addr array. 1081 */ 1082 int 1083 mac_addr_random(mac_client_handle_t mch, uint_t prefix_len, 1084 uint8_t *mac_addr, mac_diag_t *diag) 1085 { 1086 mac_client_impl_t *mcip = (mac_client_impl_t *)mch; 1087 mac_impl_t *mip = mcip->mci_mip; 1088 size_t addr_len = mip->mi_type->mt_addr_length; 1089 1090 if (prefix_len >= addr_len) { 1091 *diag = MAC_DIAG_MACPREFIXLEN_INVALID; 1092 return (EINVAL); 1093 } 1094 1095 /* check the prefix value */ 1096 if (prefix_len > 0) { 1097 bzero(mac_addr + prefix_len, addr_len - prefix_len); 1098 if (!mac_unicst_verify((mac_handle_t)mip, mac_addr, 1099 addr_len)) { 1100 *diag = MAC_DIAG_MACPREFIX_INVALID; 1101 return (EINVAL); 1102 } 1103 } 1104 1105 /* generate the MAC address */ 1106 if (prefix_len < addr_len) { 1107 (void) random_get_pseudo_bytes(mac_addr + 1108 prefix_len, addr_len - prefix_len); 1109 } 1110 1111 *diag = 0; 1112 return (0); 1113 } 1114 1115 /* 1116 * Set the priority range for this MAC client. This will be used to 1117 * determine the absolute priority for the threads created for this 1118 * MAC client using the specified "low", "medium" and "high" level. 1119 * This will also be used for any subflows on this MAC client. 1120 */ 1121 #define MAC_CLIENT_SET_PRIORITY_RANGE(mcip, pri) { \ 1122 (mcip)->mci_min_pri = FLOW_MIN_PRIORITY(MINCLSYSPRI, \ 1123 MAXCLSYSPRI, (pri)); \ 1124 (mcip)->mci_max_pri = FLOW_MAX_PRIORITY(MINCLSYSPRI, \ 1125 MAXCLSYSPRI, (mcip)->mci_min_pri); \ 1126 } 1127 1128 /* 1129 * MAC client open entry point. Return a new MAC client handle. Each 1130 * MAC client is associated with a name, specified through the 'name' 1131 * argument. 1132 */ 1133 int 1134 mac_client_open(mac_handle_t mh, mac_client_handle_t *mchp, char *name, 1135 uint16_t flags) 1136 { 1137 mac_impl_t *mip = (mac_impl_t *)mh; 1138 mac_client_impl_t *mcip; 1139 int err = 0; 1140 boolean_t share_desired = 1141 ((flags & MAC_OPEN_FLAGS_SHARES_DESIRED) != 0); 1142 boolean_t no_hwrings = ((flags & MAC_OPEN_FLAGS_NO_HWRINGS) != 0); 1143 boolean_t req_hwrings = ((flags & MAC_OPEN_FLAGS_REQ_HWRINGS) != 0); 1144 flow_entry_t *flent = NULL; 1145 1146 *mchp = NULL; 1147 if (share_desired && no_hwrings) { 1148 /* can't have shares but no hardware rings */ 1149 return (EINVAL); 1150 } 1151 1152 i_mac_perim_enter(mip); 1153 1154 if (mip->mi_state_flags & MIS_IS_VNIC) { 1155 /* 1156 * The underlying MAC is a VNIC. Return the MAC client 1157 * handle of the lower MAC which was obtained by 1158 * the VNIC driver when it did its mac_client_open(). 1159 */ 1160 1161 mcip = mac_vnic_lower(mip); 1162 1163 /* 1164 * Note that multiple mac clients share the same mcip in 1165 * this case. 1166 */ 1167 if (flags & MAC_OPEN_FLAGS_EXCLUSIVE) 1168 mcip->mci_state_flags |= MCIS_EXCLUSIVE; 1169 1170 mip->mi_clients_list = mcip; 1171 i_mac_perim_exit(mip); 1172 *mchp = (mac_client_handle_t)mcip; 1173 return (err); 1174 } 1175 1176 mcip = kmem_cache_alloc(mac_client_impl_cache, KM_SLEEP); 1177 1178 mcip->mci_mip = mip; 1179 mcip->mci_upper_mip = NULL; 1180 mcip->mci_rx_fn = mac_pkt_drop; 1181 mcip->mci_rx_arg = NULL; 1182 mcip->mci_direct_rx_fn = NULL; 1183 mcip->mci_direct_rx_arg = NULL; 1184 1185 if ((flags & MAC_OPEN_FLAGS_IS_VNIC) != 0) 1186 mcip->mci_state_flags |= MCIS_IS_VNIC; 1187 1188 if ((flags & MAC_OPEN_FLAGS_EXCLUSIVE) != 0) 1189 mcip->mci_state_flags |= MCIS_EXCLUSIVE; 1190 1191 if ((flags & MAC_OPEN_FLAGS_IS_AGGR_PORT) != 0) 1192 mcip->mci_state_flags |= MCIS_IS_AGGR_PORT; 1193 1194 if ((flags & MAC_OPEN_FLAGS_USE_DATALINK_NAME) != 0) { 1195 datalink_id_t linkid; 1196 1197 ASSERT(name == NULL); 1198 if ((err = dls_devnet_macname2linkid(mip->mi_name, 1199 &linkid)) != 0) { 1200 goto done; 1201 } 1202 if ((err = dls_mgmt_get_linkinfo(linkid, mcip->mci_name, NULL, 1203 NULL, NULL)) != 0) { 1204 /* 1205 * Use mac name if dlmgmtd is not available. 1206 */ 1207 if (err == EBADF) { 1208 (void) strlcpy(mcip->mci_name, mip->mi_name, 1209 sizeof (mcip->mci_name)); 1210 err = 0; 1211 } else { 1212 goto done; 1213 } 1214 } 1215 mcip->mci_state_flags |= MCIS_USE_DATALINK_NAME; 1216 } else { 1217 ASSERT(name != NULL); 1218 if (strlen(name) > MAXNAMELEN) { 1219 err = EINVAL; 1220 goto done; 1221 } 1222 (void) strlcpy(mcip->mci_name, name, sizeof (mcip->mci_name)); 1223 } 1224 /* the subflow table will be created dynamically */ 1225 mcip->mci_subflow_tab = NULL; 1226 mcip->mci_stat_multircv = 0; 1227 mcip->mci_stat_brdcstrcv = 0; 1228 mcip->mci_stat_multixmt = 0; 1229 mcip->mci_stat_brdcstxmt = 0; 1230 1231 mcip->mci_stat_obytes = 0; 1232 mcip->mci_stat_opackets = 0; 1233 mcip->mci_stat_oerrors = 0; 1234 mcip->mci_stat_ibytes = 0; 1235 mcip->mci_stat_ipackets = 0; 1236 mcip->mci_stat_ierrors = 0; 1237 1238 /* Create an initial flow */ 1239 1240 err = mac_flow_create(NULL, NULL, mcip->mci_name, NULL, 1241 mcip->mci_state_flags & MCIS_IS_VNIC ? FLOW_VNIC_MAC : 1242 FLOW_PRIMARY_MAC, &flent); 1243 if (err != 0) 1244 goto done; 1245 mcip->mci_flent = flent; 1246 FLOW_MARK(flent, FE_MC_NO_DATAPATH); 1247 flent->fe_mcip = mcip; 1248 /* 1249 * Place initial creation reference on the flow. This reference 1250 * is released in the corresponding delete action viz. 1251 * mac_unicast_remove after waiting for all transient refs to 1252 * to go away. The wait happens in mac_flow_wait. 1253 */ 1254 FLOW_REFHOLD(flent); 1255 1256 /* 1257 * Do this ahead of the mac_bcast_add() below so that the mi_nclients 1258 * will have the right value for mac_rx_srs_setup(). 1259 */ 1260 mac_client_add(mcip); 1261 1262 if (no_hwrings) 1263 mcip->mci_state_flags |= MCIS_NO_HWRINGS; 1264 if (req_hwrings) 1265 mcip->mci_state_flags |= MCIS_REQ_HWRINGS; 1266 mcip->mci_share = NULL; 1267 if (share_desired) { 1268 ASSERT(!no_hwrings); 1269 i_mac_share_alloc(mcip); 1270 } 1271 1272 DTRACE_PROBE2(mac__client__open__allocated, mac_impl_t *, 1273 mcip->mci_mip, mac_client_impl_t *, mcip); 1274 *mchp = (mac_client_handle_t)mcip; 1275 1276 i_mac_perim_exit(mip); 1277 return (0); 1278 1279 done: 1280 i_mac_perim_exit(mip); 1281 mcip->mci_state_flags = 0; 1282 mcip->mci_tx_flag = 0; 1283 kmem_cache_free(mac_client_impl_cache, mcip); 1284 return (err); 1285 } 1286 1287 /* 1288 * Close the specified MAC client handle. 1289 */ 1290 void 1291 mac_client_close(mac_client_handle_t mch, uint16_t flags) 1292 { 1293 mac_client_impl_t *mcip = (mac_client_impl_t *)mch; 1294 mac_impl_t *mip = mcip->mci_mip; 1295 flow_entry_t *flent; 1296 1297 i_mac_perim_enter(mip); 1298 1299 if (flags & MAC_CLOSE_FLAGS_EXCLUSIVE) 1300 mcip->mci_state_flags &= ~MCIS_EXCLUSIVE; 1301 1302 if ((mcip->mci_state_flags & MCIS_IS_VNIC) && 1303 !(flags & MAC_CLOSE_FLAGS_IS_VNIC)) { 1304 /* 1305 * This is an upper VNIC client initiated operation. 1306 * The lower MAC client will be closed by the VNIC driver 1307 * when the VNIC is deleted. 1308 */ 1309 1310 i_mac_perim_exit(mip); 1311 return; 1312 } 1313 1314 /* 1315 * Remove the flent associated with the MAC client 1316 */ 1317 flent = mcip->mci_flent; 1318 mcip->mci_flent = NULL; 1319 FLOW_FINAL_REFRELE(flent); 1320 1321 /* 1322 * MAC clients must remove the unicast addresses and promisc callbacks 1323 * they added before issuing a mac_client_close(). 1324 */ 1325 ASSERT(mcip->mci_unicast_list == NULL); 1326 ASSERT(mcip->mci_promisc_list == NULL); 1327 ASSERT(mcip->mci_tx_notify_cb_list == NULL); 1328 1329 i_mac_share_free(mcip); 1330 1331 mac_client_remove(mcip); 1332 1333 i_mac_perim_exit(mip); 1334 mcip->mci_subflow_tab = NULL; 1335 mcip->mci_state_flags = 0; 1336 mcip->mci_tx_flag = 0; 1337 kmem_cache_free(mac_client_impl_cache, mch); 1338 } 1339 1340 /* 1341 * Enable bypass for the specified MAC client. 1342 */ 1343 boolean_t 1344 mac_rx_bypass_set(mac_client_handle_t mch, mac_direct_rx_t rx_fn, void *arg1) 1345 { 1346 mac_client_impl_t *mcip = (mac_client_impl_t *)mch; 1347 mac_impl_t *mip = mcip->mci_mip; 1348 1349 ASSERT(MAC_PERIM_HELD((mac_handle_t)mip)); 1350 1351 /* 1352 * If the mac_client is a VLAN, we should not do DLS bypass and 1353 * instead let the packets come up via mac_rx_deliver so the vlan 1354 * header can be stripped. 1355 */ 1356 if (mcip->mci_nvids > 0) 1357 return (B_FALSE); 1358 1359 /* 1360 * These are not accessed directly in the data path, and hence 1361 * don't need any protection 1362 */ 1363 mcip->mci_direct_rx_fn = rx_fn; 1364 mcip->mci_direct_rx_arg = arg1; 1365 mcip->mci_state_flags |= MCIS_CLIENT_POLL_CAPABLE; 1366 return (B_TRUE); 1367 } 1368 1369 /* 1370 * Set the receive callback for the specified MAC client. There can be 1371 * at most one such callback per MAC client. 1372 */ 1373 void 1374 mac_rx_set(mac_client_handle_t mch, mac_rx_t rx_fn, void *arg) 1375 { 1376 mac_client_impl_t *mcip = (mac_client_impl_t *)mch; 1377 mac_impl_t *mip = mcip->mci_mip; 1378 1379 /* 1380 * Instead of adding an extra set of locks and refcnts in 1381 * the datapath at the mac client boundary, we temporarily quiesce 1382 * the SRS and related entities. We then change the receive function 1383 * without interference from any receive data thread and then reenable 1384 * the data flow subsequently. 1385 */ 1386 i_mac_perim_enter(mip); 1387 mac_rx_client_quiesce(mch); 1388 1389 mcip->mci_rx_fn = rx_fn; 1390 mcip->mci_rx_arg = arg; 1391 mac_rx_client_restart(mch); 1392 i_mac_perim_exit(mip); 1393 } 1394 1395 /* 1396 * Reset the receive callback for the specified MAC client. 1397 */ 1398 void 1399 mac_rx_clear(mac_client_handle_t mch) 1400 { 1401 mac_rx_set(mch, mac_pkt_drop, NULL); 1402 } 1403 1404 /* 1405 * Walk the MAC client subflow table and updates their priority values. 1406 */ 1407 static int 1408 mac_update_subflow_priority_cb(flow_entry_t *flent, void *arg) 1409 { 1410 mac_flow_update_priority(arg, flent); 1411 return (0); 1412 } 1413 1414 void 1415 mac_update_subflow_priority(mac_client_impl_t *mcip) 1416 { 1417 (void) mac_flow_walk(mcip->mci_subflow_tab, 1418 mac_update_subflow_priority_cb, mcip); 1419 } 1420 1421 /* 1422 * When the MAC client is being brought up (i.e. we do a unicast_add) we need 1423 * to initialize the cpu and resource control structure in the 1424 * mac_client_impl_t from the mac_impl_t (i.e if there are any cached 1425 * properties before the flow entry for the unicast address was created). 1426 */ 1427 int 1428 mac_resource_ctl_set(mac_client_handle_t mch, mac_resource_props_t *mrp) 1429 { 1430 mac_client_impl_t *mcip = (mac_client_impl_t *)mch; 1431 mac_impl_t *mip = (mac_impl_t *)mcip->mci_mip; 1432 int err = 0; 1433 1434 ASSERT(MAC_PERIM_HELD((mac_handle_t)mip)); 1435 1436 err = mac_validate_props(mrp); 1437 if (err != 0) 1438 return (err); 1439 1440 mac_update_resources(mrp, MCIP_RESOURCE_PROPS(mcip), B_FALSE); 1441 if (MCIP_DATAPATH_SETUP(mcip)) { 1442 /* 1443 * We have to set this prior to calling mac_flow_modify. 1444 */ 1445 if (mrp->mrp_mask & MRP_PRIORITY) { 1446 if (mrp->mrp_priority == MPL_RESET) { 1447 MAC_CLIENT_SET_PRIORITY_RANGE(mcip, 1448 MPL_LINK_DEFAULT); 1449 } else { 1450 MAC_CLIENT_SET_PRIORITY_RANGE(mcip, 1451 mrp->mrp_priority); 1452 } 1453 } 1454 1455 mac_flow_modify(mip->mi_flow_tab, mcip->mci_flent, mrp); 1456 if (mrp->mrp_mask & MRP_PRIORITY) 1457 mac_update_subflow_priority(mcip); 1458 return (0); 1459 } 1460 return (0); 1461 } 1462 1463 void 1464 mac_resource_ctl_get(mac_client_handle_t mch, mac_resource_props_t *mrp) 1465 { 1466 mac_client_impl_t *mcip = (mac_client_impl_t *)mch; 1467 mac_resource_props_t *mcip_mrp = MCIP_RESOURCE_PROPS(mcip); 1468 1469 bcopy(mcip_mrp, mrp, sizeof (mac_resource_props_t)); 1470 } 1471 1472 static int 1473 mac_unicast_flow_create(mac_client_impl_t *mcip, uint8_t *mac_addr, 1474 uint16_t vid, boolean_t is_primary, boolean_t first_flow, 1475 flow_entry_t **flent, mac_resource_props_t *mrp) 1476 { 1477 mac_impl_t *mip = (mac_impl_t *)mcip->mci_mip; 1478 flow_desc_t flow_desc; 1479 char flowname[MAXFLOWNAMELEN]; 1480 int err; 1481 uint_t flent_flags; 1482 1483 /* 1484 * First unicast address being added, create a new flow 1485 * for that MAC client. 1486 */ 1487 bzero(&flow_desc, sizeof (flow_desc)); 1488 1489 flow_desc.fd_mac_len = mip->mi_type->mt_addr_length; 1490 bcopy(mac_addr, flow_desc.fd_dst_mac, flow_desc.fd_mac_len); 1491 flow_desc.fd_mask = FLOW_LINK_DST; 1492 if (vid != 0) { 1493 flow_desc.fd_vid = vid; 1494 flow_desc.fd_mask |= FLOW_LINK_VID; 1495 } 1496 1497 /* 1498 * XXX-nicolas. For now I'm keeping the FLOW_PRIMARY_MAC 1499 * and FLOW_VNIC. Even though they're a hack inherited 1500 * from the SRS code, we'll keep them for now. They're currently 1501 * consumed by mac_datapath_setup() to create the SRS. 1502 * That code should be eventually moved out of 1503 * mac_datapath_setup() and moved to a mac_srs_create() 1504 * function of some sort to keep things clean. 1505 * 1506 * Also, there's no reason why the SRS for the primary MAC 1507 * client should be different than any other MAC client. Until 1508 * this is cleaned-up, we support only one MAC unicast address 1509 * per client. 1510 * 1511 * We set FLOW_PRIMARY_MAC for the primary MAC address, 1512 * FLOW_VNIC for everything else. 1513 */ 1514 if (is_primary) 1515 flent_flags = FLOW_PRIMARY_MAC; 1516 else 1517 flent_flags = FLOW_VNIC_MAC; 1518 1519 /* 1520 * For the first flow we use the mac client's name - mci_name, for 1521 * subsequent ones we just create a name with the vid. This is 1522 * so that we can add these flows to the same flow table. This is 1523 * fine as the flow name (except for the one with the mac client's 1524 * name) is not visible. When the first flow is removed, we just replace 1525 * its fdesc with another from the list, so we will still retain the 1526 * flent with the MAC client's flow name. 1527 */ 1528 if (first_flow) { 1529 bcopy(mcip->mci_name, flowname, MAXFLOWNAMELEN); 1530 } else { 1531 (void) sprintf(flowname, "%s%u", mcip->mci_name, vid); 1532 flent_flags = FLOW_NO_STATS; 1533 } 1534 1535 if ((err = mac_flow_create(&flow_desc, mrp, flowname, NULL, 1536 flent_flags, flent)) != 0) 1537 return (err); 1538 1539 FLOW_MARK(*flent, FE_INCIPIENT); 1540 (*flent)->fe_mcip = mcip; 1541 1542 /* 1543 * Place initial creation reference on the flow. This reference 1544 * is released in the corresponding delete action viz. 1545 * mac_unicast_remove after waiting for all transient refs to 1546 * to go away. The wait happens in mac_flow_wait. 1547 * We have already held the reference in mac_client_open(). 1548 */ 1549 if (!first_flow) 1550 FLOW_REFHOLD(*flent); 1551 return (0); 1552 } 1553 1554 /* Refresh the multicast grouping for this VID. */ 1555 int 1556 mac_client_update_mcast(void *arg, boolean_t add, const uint8_t *addrp) 1557 { 1558 flow_entry_t *flent = arg; 1559 mac_client_impl_t *mcip = flent->fe_mcip; 1560 uint16_t vid; 1561 flow_desc_t flow_desc; 1562 1563 mac_flow_get_desc(flent, &flow_desc); 1564 vid = (flow_desc.fd_mask & FLOW_LINK_VID) != 0 ? 1565 flow_desc.fd_vid : VLAN_ID_NONE; 1566 1567 /* 1568 * We don't call mac_multicast_add()/mac_multicast_remove() as 1569 * we want to add/remove for this specific vid. 1570 */ 1571 if (add) { 1572 return (mac_bcast_add(mcip, addrp, vid, 1573 MAC_ADDRTYPE_MULTICAST)); 1574 } else { 1575 mac_bcast_delete(mcip, addrp, vid); 1576 return (0); 1577 } 1578 } 1579 1580 static void 1581 mac_update_single_active_client(mac_impl_t *mip) 1582 { 1583 mac_client_impl_t *client = NULL; 1584 1585 ASSERT(MAC_PERIM_HELD((mac_handle_t)mip)); 1586 1587 rw_enter(&mip->mi_rw_lock, RW_WRITER); 1588 if (mip->mi_nactiveclients == 1) { 1589 /* 1590 * Find the one active MAC client from the list of MAC 1591 * clients. The active MAC client has at least one 1592 * unicast address. 1593 */ 1594 for (client = mip->mi_clients_list; client != NULL; 1595 client = client->mci_client_next) { 1596 if (client->mci_unicast_list != NULL) 1597 break; 1598 } 1599 ASSERT(client != NULL); 1600 } 1601 1602 /* 1603 * mi_single_active_client is protected by the MAC impl's read/writer 1604 * lock, which allows mac_rx() to check the value of that pointer 1605 * as a reader. 1606 */ 1607 mip->mi_single_active_client = client; 1608 rw_exit(&mip->mi_rw_lock); 1609 } 1610 1611 /* 1612 * Add a new unicast address to the MAC client. 1613 * 1614 * The MAC address can be specified either by value, or the MAC client 1615 * can specify that it wants to use the primary MAC address of the 1616 * underlying MAC. See the introductory comments at the beginning 1617 * of this file for more more information on primary MAC addresses. 1618 * 1619 * Note also the tuple (MAC address, VID) must be unique 1620 * for the MAC clients defined on top of the same underlying MAC 1621 * instance, unless the MAC_UNICAST_NODUPCHECK is specified. 1622 */ 1623 int 1624 i_mac_unicast_add(mac_client_handle_t mch, uint8_t *mac_addr, uint16_t flags, 1625 mac_unicast_handle_t *mah, uint16_t vid, mac_diag_t *diag) 1626 { 1627 mac_client_impl_t *mcip = (mac_client_impl_t *)mch; 1628 mac_impl_t *mip = mcip->mci_mip; 1629 mac_unicast_impl_t *muip; 1630 flow_entry_t *flent; 1631 int err; 1632 uint_t mac_len = mip->mi_type->mt_addr_length; 1633 boolean_t check_dups = !(flags & MAC_UNICAST_NODUPCHECK); 1634 boolean_t is_primary = (flags & MAC_UNICAST_PRIMARY); 1635 boolean_t is_vnic_primary = (flags & MAC_UNICAST_VNIC_PRIMARY); 1636 boolean_t is_unicast_hw = (flags & MAC_UNICAST_HW); 1637 boolean_t bcast_added = B_FALSE; 1638 boolean_t nactiveclients_added = B_FALSE; 1639 boolean_t mac_started = B_FALSE; 1640 mac_resource_props_t mrp; 1641 1642 ASSERT(MAC_PERIM_HELD((mac_handle_t)mip)); 1643 1644 /* when VID is non-zero, the underlying MAC can not be VNIC */ 1645 ASSERT(!((mip->mi_state_flags & MIS_IS_VNIC) && (vid != 0))); 1646 1647 /* 1648 * Check whether it's the primary client and flag it. 1649 */ 1650 if (!(mcip->mci_state_flags & MCIS_IS_VNIC) && is_primary && vid == 0) 1651 mcip->mci_flags |= MAC_CLIENT_FLAGS_PRIMARY; 1652 1653 /* 1654 * is_vnic_primary is true when we come here as a VLAN VNIC 1655 * which uses the primary mac client's address but with a non-zero 1656 * VID. In this case the MAC address is not specified by an upper 1657 * MAC client. 1658 */ 1659 if ((mcip->mci_state_flags & MCIS_IS_VNIC) && is_primary && 1660 !is_vnic_primary) { 1661 /* 1662 * The address is being set by the upper MAC client 1663 * of a VNIC. The MAC address was already set by the 1664 * VNIC driver during VNIC creation. 1665 * 1666 * Note: a VNIC has only one MAC address. We return 1667 * the MAC unicast address handle of the lower MAC client 1668 * corresponding to the VNIC. We allocate a new entry 1669 * which is flagged appropriately, so that mac_unicast_remove() 1670 * doesn't attempt to free the original entry that 1671 * was allocated by the VNIC driver. 1672 */ 1673 ASSERT(mcip->mci_unicast != NULL); 1674 1675 /* Check for VLAN flags, if present */ 1676 if ((flags & MAC_UNICAST_TAG_DISABLE) != 0) 1677 mcip->mci_state_flags |= MCIS_TAG_DISABLE; 1678 1679 if ((flags & MAC_UNICAST_STRIP_DISABLE) != 0) 1680 mcip->mci_state_flags |= MCIS_STRIP_DISABLE; 1681 1682 if ((flags & MAC_UNICAST_DISABLE_TX_VID_CHECK) != 0) 1683 mcip->mci_state_flags |= MCIS_DISABLE_TX_VID_CHECK; 1684 1685 /* 1686 * Ensure that the primary unicast address of the VNIC 1687 * is added only once. 1688 */ 1689 if (mcip->mci_flags & MAC_CLIENT_FLAGS_VNIC_PRIMARY) 1690 return (EBUSY); 1691 1692 mcip->mci_flags |= MAC_CLIENT_FLAGS_VNIC_PRIMARY; 1693 1694 /* 1695 * Create a handle for vid 0. 1696 */ 1697 ASSERT(vid == 0); 1698 muip = kmem_zalloc(sizeof (mac_unicast_impl_t), KM_SLEEP); 1699 muip->mui_vid = vid; 1700 *mah = (mac_unicast_handle_t)muip; 1701 return (0); 1702 } 1703 1704 /* primary MAC clients cannot be opened on top of anchor VNICs */ 1705 if ((is_vnic_primary || is_primary) && 1706 i_mac_capab_get((mac_handle_t)mip, MAC_CAPAB_ANCHOR_VNIC, NULL)) { 1707 return (ENXIO); 1708 } 1709 1710 /* 1711 * Return EBUSY if: 1712 * - this is an exclusive active mac client and there already exist 1713 * active mac clients, or 1714 * - there already exist an exclusively active mac client. 1715 */ 1716 if ((mcip->mci_state_flags & MCIS_EXCLUSIVE) && 1717 (mip->mi_nactiveclients != 0) || (mip->mi_state_flags & 1718 MIS_EXCLUSIVE)) { 1719 return (EBUSY); 1720 } 1721 1722 if (mcip->mci_state_flags & MCIS_EXCLUSIVE) 1723 mip->mi_state_flags |= MIS_EXCLUSIVE; 1724 1725 bzero(&mrp, sizeof (mac_resource_props_t)); 1726 if (is_primary && !(mcip->mci_state_flags & (MCIS_IS_VNIC | 1727 MCIS_IS_AGGR_PORT))) { 1728 /* 1729 * Apply the property cached in the mac_impl_t to the primary 1730 * mac client. If the mac client is a VNIC or an aggregation 1731 * port, its property should be set in the mcip when the 1732 * VNIC/aggr was created. 1733 */ 1734 mac_get_resources((mac_handle_t)mip, &mrp); 1735 (void) mac_client_set_resources(mch, &mrp); 1736 } else if (mcip->mci_state_flags & MCIS_IS_VNIC) { 1737 bcopy(MCIP_RESOURCE_PROPS(mcip), &mrp, 1738 sizeof (mac_resource_props_t)); 1739 } 1740 1741 muip = kmem_zalloc(sizeof (mac_unicast_impl_t), KM_SLEEP); 1742 muip->mui_vid = vid; 1743 1744 if (is_primary || is_vnic_primary) { 1745 mac_addr = mip->mi_addr; 1746 check_dups = B_TRUE; 1747 } else { 1748 1749 /* 1750 * Verify the validity of the specified MAC addresses value. 1751 */ 1752 if (!mac_unicst_verify((mac_handle_t)mip, mac_addr, mac_len)) { 1753 *diag = MAC_DIAG_MACADDR_INVALID; 1754 err = EINVAL; 1755 goto bail; 1756 } 1757 1758 /* 1759 * Make sure that the specified MAC address is different 1760 * than the unicast MAC address of the underlying NIC. 1761 */ 1762 if (check_dups && bcmp(mip->mi_addr, mac_addr, mac_len) == 0) { 1763 *diag = MAC_DIAG_MACADDR_NIC; 1764 err = EINVAL; 1765 goto bail; 1766 } 1767 } 1768 1769 /* 1770 * Make sure the MAC address is not already used by 1771 * another MAC client defined on top of the same 1772 * underlying NIC. 1773 * xxx-venu mac_unicast_add doesnt' seem to be called 1774 * with MAC_UNICAST_NODUPCHECK currently, if it does 1775 * get called we need to do mac_addr_in_use() just 1776 * to check for addr_in_use till 6697876 is fixed. 1777 */ 1778 if (check_dups && mac_addr_in_use(mip, mac_addr, vid)) { 1779 *diag = MAC_DIAG_MACADDR_INUSE; 1780 err = EEXIST; 1781 goto bail; 1782 } 1783 1784 if ((err = mac_start((mac_handle_t)mip)) != 0) 1785 goto bail; 1786 1787 mac_started = B_TRUE; 1788 1789 /* add the MAC client to the broadcast address group by default */ 1790 if (mip->mi_type->mt_brdcst_addr != NULL) { 1791 err = mac_bcast_add(mcip, mip->mi_type->mt_brdcst_addr, vid, 1792 MAC_ADDRTYPE_BROADCAST); 1793 if (err != 0) 1794 goto bail; 1795 bcast_added = B_TRUE; 1796 } 1797 1798 /* 1799 * If this is the first unicast address addition for this 1800 * client, reuse the pre-allocated larval flow entry associated with 1801 * the MAC client. 1802 */ 1803 flent = (mcip->mci_nflents == 0) ? mcip->mci_flent : NULL; 1804 1805 /* We are configuring the unicast flow now */ 1806 if (!MCIP_DATAPATH_SETUP(mcip)) { 1807 if (is_unicast_hw) { 1808 /* 1809 * The client requires a hardware MAC address slot 1810 * for that unicast address. Since we support only 1811 * one unicast MAC address per client, flag the 1812 * MAC client itself. 1813 */ 1814 mcip->mci_state_flags |= MCIS_UNICAST_HW; 1815 } 1816 1817 /* Check for VLAN flags, if present */ 1818 if ((flags & MAC_UNICAST_TAG_DISABLE) != 0) 1819 mcip->mci_state_flags |= MCIS_TAG_DISABLE; 1820 1821 if ((flags & MAC_UNICAST_STRIP_DISABLE) != 0) 1822 mcip->mci_state_flags |= MCIS_STRIP_DISABLE; 1823 1824 if ((flags & MAC_UNICAST_DISABLE_TX_VID_CHECK) != 0) 1825 mcip->mci_state_flags |= MCIS_DISABLE_TX_VID_CHECK; 1826 1827 MAC_CLIENT_SET_PRIORITY_RANGE(mcip, 1828 (mrp.mrp_mask & MRP_PRIORITY) ? mrp.mrp_priority : 1829 MPL_LINK_DEFAULT); 1830 1831 if ((err = mac_unicast_flow_create(mcip, mac_addr, vid, 1832 is_primary || is_vnic_primary, B_TRUE, &flent, &mrp)) != 0) 1833 goto bail; 1834 1835 mip->mi_nactiveclients++; 1836 nactiveclients_added = B_TRUE; 1837 1838 /* 1839 * This will allocate the RX ring group if possible for the 1840 * flow and program the software classifier as needed. 1841 */ 1842 if ((err = mac_datapath_setup(mcip, flent, SRST_LINK)) != 0) 1843 goto bail; 1844 1845 /* 1846 * The unicast MAC address must have been added successfully. 1847 */ 1848 ASSERT(mcip->mci_unicast != NULL); 1849 /* 1850 * Push down the sub-flows that were defined on this link 1851 * hitherto. The flows are added to the active flow table 1852 * and SRS, softrings etc. are created as needed. 1853 */ 1854 mac_link_init_flows(mch); 1855 } else { 1856 mac_address_t *map = mcip->mci_unicast; 1857 1858 /* 1859 * A unicast flow already exists for that MAC client, 1860 * this flow must be the same mac address but with 1861 * different VID. It has been checked by mac_addr_in_use(). 1862 * 1863 * We will use the SRS etc. from the mci_flent. Note that 1864 * We don't need to create kstat for this as except for 1865 * the fdesc, everything will be used from in the 1st flent. 1866 */ 1867 1868 /* 1869 * Assert that the specified flags are consistent with the 1870 * flags specified by previous calls to mac_unicast_add(). 1871 */ 1872 ASSERT(((flags & MAC_UNICAST_TAG_DISABLE) != 0 && 1873 (mcip->mci_state_flags & MCIS_TAG_DISABLE) != 0) || 1874 ((flags & MAC_UNICAST_TAG_DISABLE) == 0 && 1875 (mcip->mci_state_flags & MCIS_TAG_DISABLE) == 0)); 1876 1877 ASSERT(((flags & MAC_UNICAST_STRIP_DISABLE) != 0 && 1878 (mcip->mci_state_flags & MCIS_STRIP_DISABLE) != 0) || 1879 ((flags & MAC_UNICAST_STRIP_DISABLE) == 0 && 1880 (mcip->mci_state_flags & MCIS_STRIP_DISABLE) == 0)); 1881 1882 ASSERT(((flags & MAC_UNICAST_DISABLE_TX_VID_CHECK) != 0 && 1883 (mcip->mci_state_flags & MCIS_DISABLE_TX_VID_CHECK) != 0) || 1884 ((flags & MAC_UNICAST_DISABLE_TX_VID_CHECK) == 0 && 1885 (mcip->mci_state_flags & MCIS_DISABLE_TX_VID_CHECK) == 0)); 1886 1887 if (bcmp(mac_addr, map->ma_addr, map->ma_len) != 0) { 1888 err = EINVAL; 1889 goto bail; 1890 } 1891 1892 /* 1893 * Make sure the client is consistent about its requests 1894 * for MAC addresses. I.e. all requests from the clients 1895 * must have the MAC_UNICAST_HW flag set or clear. 1896 */ 1897 if ((mcip->mci_state_flags & MCIS_UNICAST_HW) != 0 && 1898 !is_unicast_hw || 1899 (mcip->mci_state_flags & MCIS_UNICAST_HW) == 0 && 1900 is_unicast_hw) { 1901 err = EINVAL; 1902 goto bail; 1903 } 1904 1905 if ((err = mac_unicast_flow_create(mcip, mac_addr, vid, 1906 is_primary || is_vnic_primary, B_FALSE, &flent, NULL)) != 0) 1907 goto bail; 1908 1909 if ((err = mac_flow_add(mip->mi_flow_tab, flent)) != 0) { 1910 FLOW_FINAL_REFRELE(flent); 1911 goto bail; 1912 } 1913 1914 /* update the multicast group for this vid */ 1915 mac_client_bcast_refresh(mcip, mac_client_update_mcast, 1916 (void *)flent, B_TRUE); 1917 1918 } 1919 1920 /* populate the shared MAC address */ 1921 muip->mui_map = mcip->mci_unicast; 1922 1923 rw_enter(&mcip->mci_rw_lock, RW_WRITER); 1924 muip->mui_next = mcip->mci_unicast_list; 1925 mcip->mci_unicast_list = muip; 1926 rw_exit(&mcip->mci_rw_lock); 1927 1928 *mah = (mac_unicast_handle_t)muip; 1929 1930 /* 1931 * First add the flent to the flow list of this mcip. Then set 1932 * the mip's mi_single_active_client if needed. The Rx path assumes 1933 * that mip->mi_single_active_client will always have an associated 1934 * flent. 1935 */ 1936 mac_client_add_to_flow_list(mcip, flent); 1937 1938 if (nactiveclients_added) 1939 mac_update_single_active_client(mip); 1940 /* 1941 * Trigger a renegotiation of the capabilities when the number of 1942 * active clients changes from 1 to 2, since some of the capabilities 1943 * might have to be disabled. Also send a MAC_NOTE_LINK notification 1944 * to all the MAC clients whenever physical link is DOWN. 1945 */ 1946 if (mip->mi_nactiveclients == 2) { 1947 mac_capab_update((mac_handle_t)mip); 1948 mac_virtual_link_update(mip); 1949 } 1950 /* 1951 * Now that the setup is complete, clear the INCIPIENT flag. 1952 * The flag was set to avoid incoming packets seeing inconsistent 1953 * structures while the setup was in progress. Clear the mci_tx_flag 1954 * by calling mac_tx_client_block. It is possible that 1955 * mac_unicast_remove was called prior to this mac_unicast_add which 1956 * could have set the MCI_TX_QUIESCE flag. 1957 */ 1958 if (flent->fe_rx_ring_group != NULL) 1959 mac_rx_group_unmark(flent->fe_rx_ring_group, MR_INCIPIENT); 1960 FLOW_UNMARK(flent, FE_INCIPIENT); 1961 FLOW_UNMARK(flent, FE_MC_NO_DATAPATH); 1962 mac_tx_client_unblock(mcip); 1963 return (0); 1964 bail: 1965 if (bcast_added) 1966 mac_bcast_delete(mcip, mip->mi_type->mt_brdcst_addr, vid); 1967 if (mac_started) 1968 mac_stop((mac_handle_t)mip); 1969 1970 if (nactiveclients_added) 1971 mip->mi_nactiveclients--; 1972 1973 if (mcip->mci_state_flags & MCIS_EXCLUSIVE) 1974 mip->mi_state_flags &= ~MIS_EXCLUSIVE; 1975 kmem_free(muip, sizeof (mac_unicast_impl_t)); 1976 return (err); 1977 } 1978 1979 int 1980 mac_unicast_add(mac_client_handle_t mch, uint8_t *mac_addr, uint16_t flags, 1981 mac_unicast_handle_t *mah, uint16_t vid, mac_diag_t *diag) 1982 { 1983 mac_impl_t *mip = ((mac_client_impl_t *)mch)->mci_mip; 1984 uint_t err; 1985 1986 i_mac_perim_enter(mip); 1987 err = i_mac_unicast_add(mch, mac_addr, flags, mah, vid, diag); 1988 i_mac_perim_exit(mip); 1989 1990 return (err); 1991 } 1992 1993 /* 1994 * Remove a MAC address which was previously added by mac_unicast_add(). 1995 */ 1996 int 1997 mac_unicast_remove(mac_client_handle_t mch, mac_unicast_handle_t mah) 1998 { 1999 mac_client_impl_t *mcip = (mac_client_impl_t *)mch; 2000 mac_unicast_impl_t *muip = (mac_unicast_impl_t *)mah; 2001 mac_unicast_impl_t *pre; 2002 mac_impl_t *mip = mcip->mci_mip; 2003 flow_entry_t *flent; 2004 2005 i_mac_perim_enter(mip); 2006 if (mcip->mci_flags & MAC_CLIENT_FLAGS_VNIC_PRIMARY) { 2007 /* 2008 * Called made by the upper MAC client of a VNIC. 2009 * There's nothing much to do, the unicast address will 2010 * be removed by the VNIC driver when the VNIC is deleted, 2011 * but let's ensure that all our transmit is done before 2012 * the client does a mac_client_stop lest it trigger an 2013 * assert in the driver. 2014 */ 2015 ASSERT(muip->mui_vid == 0); 2016 2017 mac_tx_client_flush(mcip); 2018 mcip->mci_flags &= ~MAC_CLIENT_FLAGS_VNIC_PRIMARY; 2019 2020 if (mcip->mci_state_flags & MCIS_TAG_DISABLE) 2021 mcip->mci_state_flags &= ~MCIS_TAG_DISABLE; 2022 2023 if (mcip->mci_state_flags & MCIS_STRIP_DISABLE) 2024 mcip->mci_state_flags &= ~MCIS_STRIP_DISABLE; 2025 2026 if (mcip->mci_state_flags & MCIS_DISABLE_TX_VID_CHECK) 2027 mcip->mci_state_flags &= ~MCIS_DISABLE_TX_VID_CHECK; 2028 2029 kmem_free(muip, sizeof (mac_unicast_impl_t)); 2030 i_mac_perim_exit(mip); 2031 return (0); 2032 } 2033 2034 ASSERT(muip != NULL); 2035 2036 /* 2037 * Remove the VID from the list of client's VIDs. 2038 */ 2039 pre = mcip->mci_unicast_list; 2040 if (muip == pre) { 2041 mcip->mci_unicast_list = muip->mui_next; 2042 } else { 2043 while ((pre->mui_next != NULL) && (pre->mui_next != muip)) 2044 pre = pre->mui_next; 2045 ASSERT(pre->mui_next == muip); 2046 rw_enter(&mcip->mci_rw_lock, RW_WRITER); 2047 pre->mui_next = muip->mui_next; 2048 rw_exit(&mcip->mci_rw_lock); 2049 } 2050 2051 if ((mcip->mci_flags & MAC_CLIENT_FLAGS_PRIMARY) && muip->mui_vid == 0) 2052 mcip->mci_flags &= ~MAC_CLIENT_FLAGS_PRIMARY; 2053 2054 if (!mac_client_single_rcvr(mcip)) { 2055 /* 2056 * This MAC client is shared by more than one unicast 2057 * addresses, so we will just remove the flent 2058 * corresponding to the address being removed. We don't invoke 2059 * mac_rx_classify_flow_rem() since the additional flow is 2060 * not associated with its own separate set of SRS and rings, 2061 * and these constructs are still needed for the remaining 2062 * flows. 2063 */ 2064 flent = mac_client_get_flow(mcip, muip); 2065 ASSERT(flent != NULL); 2066 2067 /* 2068 * The first one is disappearing, need to make sure 2069 * we replace it with another from the list of 2070 * shared clients. 2071 */ 2072 if (flent == mcip->mci_flent) 2073 flent = mac_client_swap_mciflent(mcip); 2074 mac_client_remove_flow_from_list(mcip, flent); 2075 mac_flow_remove(mip->mi_flow_tab, flent, B_FALSE); 2076 mac_flow_wait(flent, FLOW_DRIVER_UPCALL); 2077 2078 /* 2079 * The multicast groups that were added by the client so 2080 * far must be removed from the brodcast domain corresponding 2081 * to the VID being removed. 2082 */ 2083 mac_client_bcast_refresh(mcip, mac_client_update_mcast, 2084 (void *)flent, B_FALSE); 2085 2086 if (mip->mi_type->mt_brdcst_addr != NULL) { 2087 mac_bcast_delete(mcip, mip->mi_type->mt_brdcst_addr, 2088 muip->mui_vid); 2089 } 2090 mac_stop((mac_handle_t)mip); 2091 FLOW_FINAL_REFRELE(flent); 2092 i_mac_perim_exit(mip); 2093 return (0); 2094 } 2095 2096 /* 2097 * We would have initialized subflows etc. only if we brought up 2098 * the primary client and set the unicast unicast address etc. 2099 * Deactivate the flows. The flow entry will be removed from the 2100 * active flow tables, and the associated SRS, softrings etc will 2101 * be deleted. But the flow entry itself won't be destroyed, instead 2102 * it will continue to be archived off the the global flow hash 2103 * list, for a possible future activation when say IP is plumbed 2104 * again. 2105 */ 2106 mac_link_release_flows(mch); 2107 2108 mip->mi_nactiveclients--; 2109 mac_update_single_active_client(mip); 2110 2111 /* Tear down the Data path */ 2112 mac_datapath_teardown(mcip, mcip->mci_flent, SRST_LINK); 2113 2114 /* 2115 * Prevent any future access to the flow entry through the mci_flent 2116 * pointer by setting the mci_flent to NULL. Access to mci_flent in 2117 * mac_bcast_send is also under mi_rw_lock. 2118 */ 2119 rw_enter(&mip->mi_rw_lock, RW_WRITER); 2120 flent = mcip->mci_flent; 2121 mac_client_remove_flow_from_list(mcip, flent); 2122 2123 if (mcip->mci_state_flags & MCIS_DESC_LOGGED) 2124 mcip->mci_state_flags &= ~MCIS_DESC_LOGGED; 2125 2126 /* 2127 * This is the last unicast address being removed and there shouldn't 2128 * be any outbound data threads at this point coming down from mac 2129 * clients. We have waited for the data threads to finish before 2130 * starting dld_str_detach. Non-data threads must access TX SRS 2131 * under mi_rw_lock. 2132 */ 2133 rw_exit(&mip->mi_rw_lock); 2134 2135 /* 2136 * Update the multicast group for this vid. 2137 */ 2138 mac_client_bcast_refresh(mcip, mac_client_update_mcast, (void *)flent, 2139 B_FALSE); 2140 2141 /* 2142 * Don't use FLOW_MARK with FE_MC_NO_DATAPATH, as the flow might 2143 * contain other flags, such as FE_CONDEMNED, which we need to 2144 * cleared. We don't call mac_flow_cleanup() for this unicast 2145 * flow as we have a already cleaned up SRSs etc. (via the teadown 2146 * path). We just clear the stats and reset the initial callback 2147 * function, the rest will be set when we call mac_flow_create, 2148 * if at all. 2149 */ 2150 mutex_enter(&flent->fe_lock); 2151 ASSERT(flent->fe_refcnt == 1 && flent->fe_mbg == NULL && 2152 flent->fe_tx_srs == NULL && flent->fe_rx_srs_cnt == 0); 2153 flent->fe_flags = FE_MC_NO_DATAPATH; 2154 flow_stat_destroy(flent); 2155 2156 /* Initialize the receiver function to a safe routine */ 2157 flent->fe_cb_fn = (flow_fn_t)mac_pkt_drop; 2158 flent->fe_cb_arg1 = NULL; 2159 flent->fe_cb_arg2 = NULL; 2160 2161 flent->fe_index = -1; 2162 mutex_exit(&flent->fe_lock); 2163 2164 if (mip->mi_type->mt_brdcst_addr != NULL) { 2165 mac_bcast_delete(mcip, mip->mi_type->mt_brdcst_addr, 2166 muip->mui_vid); 2167 } 2168 2169 if (mip->mi_nactiveclients == 1) { 2170 mac_capab_update((mac_handle_t)mip); 2171 mac_virtual_link_update(mip); 2172 } 2173 if (mcip->mci_state_flags & MCIS_EXCLUSIVE) 2174 mip->mi_state_flags &= ~MIS_EXCLUSIVE; 2175 mcip->mci_state_flags &= ~MCIS_UNICAST_HW; 2176 2177 if (mcip->mci_state_flags & MCIS_TAG_DISABLE) 2178 mcip->mci_state_flags &= ~MCIS_TAG_DISABLE; 2179 2180 if (mcip->mci_state_flags & MCIS_STRIP_DISABLE) 2181 mcip->mci_state_flags &= ~MCIS_STRIP_DISABLE; 2182 2183 if (mcip->mci_state_flags & MCIS_DISABLE_TX_VID_CHECK) 2184 mcip->mci_state_flags &= ~MCIS_DISABLE_TX_VID_CHECK; 2185 2186 mac_stop((mac_handle_t)mip); 2187 2188 i_mac_perim_exit(mip); 2189 kmem_free(muip, sizeof (mac_unicast_impl_t)); 2190 return (0); 2191 } 2192 2193 /* 2194 * Multicast add function invoked by MAC clients. 2195 */ 2196 int 2197 mac_multicast_add(mac_client_handle_t mch, const uint8_t *addr) 2198 { 2199 mac_client_impl_t *mcip = (mac_client_impl_t *)mch; 2200 mac_impl_t *mip = mcip->mci_mip; 2201 flow_entry_t *flent = mcip->mci_flent_list; 2202 flow_entry_t *prev_fe = NULL; 2203 uint16_t vid; 2204 int err = 0; 2205 2206 /* Verify the address is a valid multicast address */ 2207 if ((err = mip->mi_type->mt_ops.mtops_multicst_verify(addr, 2208 mip->mi_pdata)) != 0) 2209 return (err); 2210 2211 i_mac_perim_enter(mip); 2212 while (flent != NULL) { 2213 vid = i_mac_flow_vid(flent); 2214 2215 err = mac_bcast_add((mac_client_impl_t *)mch, addr, vid, 2216 MAC_ADDRTYPE_MULTICAST); 2217 if (err != 0) 2218 break; 2219 prev_fe = flent; 2220 flent = flent->fe_client_next; 2221 } 2222 2223 /* 2224 * If we failed adding, then undo all, rather than partial 2225 * success. 2226 */ 2227 if (flent != NULL && prev_fe != NULL) { 2228 flent = mcip->mci_flent_list; 2229 while (flent != prev_fe->fe_client_next) { 2230 vid = i_mac_flow_vid(flent); 2231 mac_bcast_delete((mac_client_impl_t *)mch, addr, vid); 2232 flent = flent->fe_client_next; 2233 } 2234 } 2235 i_mac_perim_exit(mip); 2236 return (err); 2237 } 2238 2239 /* 2240 * Multicast delete function invoked by MAC clients. 2241 */ 2242 void 2243 mac_multicast_remove(mac_client_handle_t mch, const uint8_t *addr) 2244 { 2245 mac_client_impl_t *mcip = (mac_client_impl_t *)mch; 2246 mac_impl_t *mip = mcip->mci_mip; 2247 flow_entry_t *flent; 2248 uint16_t vid; 2249 2250 i_mac_perim_enter(mip); 2251 for (flent = mcip->mci_flent_list; flent != NULL; 2252 flent = flent->fe_client_next) { 2253 vid = i_mac_flow_vid(flent); 2254 mac_bcast_delete((mac_client_impl_t *)mch, addr, vid); 2255 } 2256 i_mac_perim_exit(mip); 2257 } 2258 2259 /* 2260 * When a MAC client desires to capture packets on an interface, 2261 * it registers a promiscuous call back with mac_promisc_add(). 2262 * There are three types of promiscuous callbacks: 2263 * 2264 * * MAC_CLIENT_PROMISC_ALL 2265 * Captures all packets sent and received by the MAC client, 2266 * the physical interface, as well as all other MAC clients 2267 * defined on top of the same MAC. 2268 * 2269 * * MAC_CLIENT_PROMISC_FILTERED 2270 * Captures all packets sent and received by the MAC client, 2271 * plus all multicast traffic sent and received by the phyisical 2272 * interface and the other MAC clients. 2273 * 2274 * * MAC_CLIENT_PROMISC_MULTI 2275 * Captures all broadcast and multicast packets sent and 2276 * received by the MAC clients as well as the physical interface. 2277 * 2278 * In all cases, the underlying MAC is put in promiscuous mode. 2279 */ 2280 int 2281 mac_promisc_add(mac_client_handle_t mch, mac_client_promisc_type_t type, 2282 mac_rx_t fn, void *arg, mac_promisc_handle_t *mphp, uint16_t flags) 2283 { 2284 mac_client_impl_t *mcip = (mac_client_impl_t *)mch; 2285 mac_impl_t *mip = mcip->mci_mip; 2286 mac_promisc_impl_t *mpip; 2287 mac_cb_info_t *mcbi; 2288 int rc; 2289 2290 i_mac_perim_enter(mip); 2291 2292 if ((rc = mac_start((mac_handle_t)mip)) != 0) { 2293 i_mac_perim_exit(mip); 2294 return (rc); 2295 } 2296 2297 if ((mcip->mci_state_flags & MCIS_IS_VNIC) && 2298 type == MAC_CLIENT_PROMISC_ALL) { 2299 /* 2300 * The function is being invoked by the upper MAC client 2301 * of a VNIC. The VNIC should only see the traffic 2302 * it is entitled to. 2303 */ 2304 type = MAC_CLIENT_PROMISC_FILTERED; 2305 } 2306 2307 2308 /* 2309 * Turn on promiscuous mode for the underlying NIC. 2310 * This is needed even for filtered callbacks which 2311 * expect to receive all multicast traffic on the wire. 2312 * 2313 * Physical promiscuous mode should not be turned on if 2314 * MAC_PROMISC_FLAGS_NO_PHYS is set. 2315 */ 2316 if ((flags & MAC_PROMISC_FLAGS_NO_PHYS) == 0) { 2317 if ((rc = i_mac_promisc_set(mip, B_TRUE, MAC_DEVPROMISC)) 2318 != 0) { 2319 mac_stop((mac_handle_t)mip); 2320 i_mac_perim_exit(mip); 2321 return (rc); 2322 } 2323 } 2324 2325 mpip = kmem_cache_alloc(mac_promisc_impl_cache, KM_SLEEP); 2326 2327 mpip->mpi_type = type; 2328 mpip->mpi_fn = fn; 2329 mpip->mpi_arg = arg; 2330 mpip->mpi_mcip = mcip; 2331 mpip->mpi_no_tx_loop = ((flags & MAC_PROMISC_FLAGS_NO_TX_LOOP) != 0); 2332 mpip->mpi_no_phys = ((flags & MAC_PROMISC_FLAGS_NO_PHYS) != 0); 2333 mpip->mpi_strip_vlan_tag = 2334 ((flags & MAC_PROMISC_FLAGS_VLAN_TAG_STRIP) != 0); 2335 2336 mcbi = &mip->mi_promisc_cb_info; 2337 mutex_enter(mcbi->mcbi_lockp); 2338 2339 mac_callback_add(&mip->mi_promisc_cb_info, &mcip->mci_promisc_list, 2340 &mpip->mpi_mci_link); 2341 mac_callback_add(&mip->mi_promisc_cb_info, &mip->mi_promisc_list, 2342 &mpip->mpi_mi_link); 2343 2344 mutex_exit(mcbi->mcbi_lockp); 2345 2346 *mphp = (mac_promisc_handle_t)mpip; 2347 i_mac_perim_exit(mip); 2348 return (0); 2349 } 2350 2351 /* 2352 * Remove a multicast address previously aded through mac_promisc_add(). 2353 */ 2354 int 2355 mac_promisc_remove(mac_promisc_handle_t mph) 2356 { 2357 mac_promisc_impl_t *mpip = (mac_promisc_impl_t *)mph; 2358 mac_client_impl_t *mcip = mpip->mpi_mcip; 2359 mac_impl_t *mip = mcip->mci_mip; 2360 mac_cb_info_t *mcbi; 2361 int rc = 0; 2362 2363 i_mac_perim_enter(mip); 2364 2365 /* 2366 * Even if the device can't be reset into normal mode, we still 2367 * need to clear the client promisc callbacks. The client may want 2368 * to close the mac end point and we can't have stale callbacks. 2369 */ 2370 if (!(mpip->mpi_no_phys)) { 2371 rc = mac_promisc_set((mac_handle_t)mip, B_FALSE, 2372 MAC_DEVPROMISC); 2373 if (rc != 0) 2374 goto done; 2375 } 2376 mcbi = &mip->mi_promisc_cb_info; 2377 mutex_enter(mcbi->mcbi_lockp); 2378 if (mac_callback_remove(mcbi, &mip->mi_promisc_list, 2379 &mpip->mpi_mi_link)) { 2380 VERIFY(mac_callback_remove(&mip->mi_promisc_cb_info, 2381 &mcip->mci_promisc_list, &mpip->mpi_mci_link)); 2382 kmem_cache_free(mac_promisc_impl_cache, mpip); 2383 } else { 2384 mac_callback_remove_wait(&mip->mi_promisc_cb_info); 2385 } 2386 mutex_exit(mcbi->mcbi_lockp); 2387 mac_stop((mac_handle_t)mip); 2388 2389 done: 2390 i_mac_perim_exit(mip); 2391 return (rc); 2392 } 2393 2394 /* 2395 * Reference count the number of active Tx threads. MCI_TX_QUIESCE indicates 2396 * that a control operation wants to quiesce the Tx data flow in which case 2397 * we return an error. Holding any of the per cpu locks ensures that the 2398 * mci_tx_flag won't change. 2399 * 2400 * 'CPU' must be accessed just once and used to compute the index into the 2401 * percpu array, and that index must be used for the entire duration of the 2402 * packet send operation. Note that the thread may be preempted and run on 2403 * another cpu any time and so we can't use 'CPU' more than once for the 2404 * operation. 2405 */ 2406 #define MAC_TX_TRY_HOLD(mcip, mytx, error) \ 2407 { \ 2408 (error) = 0; \ 2409 (mytx) = &(mcip)->mci_tx_pcpu[CPU->cpu_seqid & mac_tx_percpu_cnt]; \ 2410 mutex_enter(&(mytx)->pcpu_tx_lock); \ 2411 if (!((mcip)->mci_tx_flag & MCI_TX_QUIESCE)) { \ 2412 (mytx)->pcpu_tx_refcnt++; \ 2413 } else { \ 2414 (error) = -1; \ 2415 } \ 2416 mutex_exit(&(mytx)->pcpu_tx_lock); \ 2417 } 2418 2419 /* 2420 * Release the reference. If needed, signal any control operation waiting 2421 * for Tx quiescence. The wait and signal are always done using the 2422 * mci_tx_pcpu[0]'s lock 2423 */ 2424 #define MAC_TX_RELE(mcip, mytx) { \ 2425 mutex_enter(&(mytx)->pcpu_tx_lock); \ 2426 if (--(mytx)->pcpu_tx_refcnt == 0 && \ 2427 (mcip)->mci_tx_flag & MCI_TX_QUIESCE) { \ 2428 mutex_exit(&(mytx)->pcpu_tx_lock); \ 2429 mutex_enter(&(mcip)->mci_tx_pcpu[0].pcpu_tx_lock); \ 2430 cv_signal(&(mcip)->mci_tx_cv); \ 2431 mutex_exit(&(mcip)->mci_tx_pcpu[0].pcpu_tx_lock); \ 2432 } else { \ 2433 mutex_exit(&(mytx)->pcpu_tx_lock); \ 2434 } \ 2435 } 2436 2437 /* 2438 * Bump the count of the number of active Tx threads. This is maintained as 2439 * a per CPU counter. On (CMT kind of) machines with large number of CPUs, 2440 * a single mci_tx_lock may become contended. However a count of the total 2441 * number of Tx threads per client is needed in order to quiesce the Tx side 2442 * prior to reassigning a Tx ring dynamically to another client. The thread 2443 * that needs to quiesce the Tx traffic grabs all the percpu locks and checks 2444 * the sum of the individual percpu refcnts. Each Tx data thread only grabs 2445 * its own percpu lock and increments its own refcnt. 2446 */ 2447 void * 2448 mac_tx_hold(mac_client_handle_t mch) 2449 { 2450 mac_client_impl_t *mcip = (mac_client_impl_t *)mch; 2451 mac_tx_percpu_t *mytx; 2452 int error; 2453 2454 MAC_TX_TRY_HOLD(mcip, mytx, error); 2455 return (error == 0 ? (void *)mytx : NULL); 2456 } 2457 2458 void 2459 mac_tx_rele(mac_client_handle_t mch, void *mytx_handle) 2460 { 2461 mac_client_impl_t *mcip = (mac_client_impl_t *)mch; 2462 mac_tx_percpu_t *mytx = mytx_handle; 2463 2464 MAC_TX_RELE(mcip, mytx) 2465 } 2466 2467 /* 2468 * Send function invoked by MAC clients. 2469 */ 2470 mac_tx_cookie_t 2471 mac_tx(mac_client_handle_t mch, mblk_t *mp_chain, uintptr_t hint, 2472 uint16_t flag, mblk_t **ret_mp) 2473 { 2474 mac_tx_cookie_t cookie; 2475 int error; 2476 mac_tx_percpu_t *mytx; 2477 mac_soft_ring_set_t *srs; 2478 flow_entry_t *flent; 2479 boolean_t is_subflow = B_FALSE; 2480 mac_client_impl_t *mcip = (mac_client_impl_t *)mch; 2481 mac_impl_t *mip = mcip->mci_mip; 2482 mac_srs_tx_t *srs_tx; 2483 2484 /* 2485 * Check whether the active Tx threads count is bumped already. 2486 */ 2487 if (!(flag & MAC_TX_NO_HOLD)) { 2488 MAC_TX_TRY_HOLD(mcip, mytx, error); 2489 if (error != 0) { 2490 freemsgchain(mp_chain); 2491 return (NULL); 2492 } 2493 } 2494 2495 if (mcip->mci_subflow_tab != NULL && 2496 mcip->mci_subflow_tab->ft_flow_count > 0 && 2497 mac_flow_lookup(mcip->mci_subflow_tab, mp_chain, 2498 FLOW_OUTBOUND, &flent) == 0) { 2499 /* 2500 * The main assumption here is that if in the event 2501 * we get a chain, all the packets will be classified 2502 * to the same Flow/SRS. If this changes for any 2503 * reason, the following logic should change as well. 2504 * I suppose the fanout_hint also assumes this . 2505 */ 2506 ASSERT(flent != NULL); 2507 is_subflow = B_TRUE; 2508 } else { 2509 flent = mcip->mci_flent; 2510 } 2511 2512 srs = flent->fe_tx_srs; 2513 srs_tx = &srs->srs_tx; 2514 if (srs_tx->st_mode == SRS_TX_DEFAULT && 2515 (srs->srs_state & SRS_ENQUEUED) == 0 && 2516 mip->mi_nactiveclients == 1 && mip->mi_promisc_list == NULL && 2517 mp_chain->b_next == NULL) { 2518 uint64_t obytes; 2519 2520 /* 2521 * Since dls always opens the underlying MAC, nclients equals 2522 * to 1 means that the only active client is dls itself acting 2523 * as a primary client of the MAC instance. Since dls will not 2524 * send tagged packets in that case, and dls is trusted to send 2525 * packets for its allowed VLAN(s), the VLAN tag insertion and 2526 * check is required only if nclients is greater than 1. 2527 */ 2528 if (mip->mi_nclients > 1) { 2529 if (MAC_VID_CHECK_NEEDED(mcip)) { 2530 int err = 0; 2531 2532 MAC_VID_CHECK(mcip, mp_chain, err); 2533 if (err != 0) { 2534 freemsg(mp_chain); 2535 mcip->mci_stat_oerrors++; 2536 goto done; 2537 } 2538 } 2539 if (MAC_TAG_NEEDED(mcip)) { 2540 mp_chain = mac_add_vlan_tag(mp_chain, 0, 2541 mac_client_vid(mch)); 2542 if (mp_chain == NULL) { 2543 mcip->mci_stat_oerrors++; 2544 goto done; 2545 } 2546 } 2547 } 2548 2549 obytes = (mp_chain->b_cont == NULL ? MBLKL(mp_chain) : 2550 msgdsize(mp_chain)); 2551 2552 MAC_TX(mip, srs_tx->st_arg2, mp_chain, mcip); 2553 2554 if (mp_chain == NULL) { 2555 cookie = NULL; 2556 mcip->mci_stat_obytes += obytes; 2557 mcip->mci_stat_opackets += 1; 2558 if ((srs->srs_type & SRST_FLOW) != 0) { 2559 FLOW_STAT_UPDATE(flent, obytes, obytes); 2560 FLOW_STAT_UPDATE(flent, opackets, 1); 2561 } 2562 } else { 2563 mutex_enter(&srs->srs_lock); 2564 cookie = mac_tx_srs_no_desc(srs, mp_chain, 2565 flag, ret_mp); 2566 mutex_exit(&srs->srs_lock); 2567 } 2568 } else { 2569 cookie = srs_tx->st_func(srs, mp_chain, hint, flag, ret_mp); 2570 } 2571 2572 done: 2573 if (is_subflow) 2574 FLOW_REFRELE(flent); 2575 2576 if (!(flag & MAC_TX_NO_HOLD)) 2577 MAC_TX_RELE(mcip, mytx); 2578 2579 return (cookie); 2580 } 2581 2582 /* 2583 * mac_tx_is_blocked 2584 * 2585 * Given a cookie, it returns if the ring identified by the cookie is 2586 * flow-controlled or not. If NULL is passed in place of a cookie, 2587 * then it finds out if any of the underlying rings belonging to the 2588 * SRS is flow controlled or not and returns that status. 2589 */ 2590 /* ARGSUSED */ 2591 boolean_t 2592 mac_tx_is_flow_blocked(mac_client_handle_t mch, mac_tx_cookie_t cookie) 2593 { 2594 mac_client_impl_t *mcip = (mac_client_impl_t *)mch; 2595 mac_soft_ring_set_t *mac_srs; 2596 mac_soft_ring_t *sringp; 2597 boolean_t blocked = B_FALSE; 2598 mac_tx_percpu_t *mytx; 2599 int err; 2600 int i; 2601 2602 /* 2603 * Bump the reference count so that mac_srs won't be deleted. 2604 * If the client is currently quiesced and we failed to bump 2605 * the reference, return B_TRUE so that flow control stays 2606 * as enabled. 2607 * 2608 * Flow control will then be disabled once the client is no 2609 * longer quiesced. 2610 */ 2611 MAC_TX_TRY_HOLD(mcip, mytx, err); 2612 if (err != 0) 2613 return (B_TRUE); 2614 2615 if ((mac_srs = MCIP_TX_SRS(mcip)) == NULL) { 2616 MAC_TX_RELE(mcip, mytx); 2617 return (B_FALSE); 2618 } 2619 2620 mutex_enter(&mac_srs->srs_lock); 2621 if (mac_srs->srs_tx.st_mode == SRS_TX_FANOUT) { 2622 if (cookie != NULL) { 2623 sringp = (mac_soft_ring_t *)cookie; 2624 mutex_enter(&sringp->s_ring_lock); 2625 if (sringp->s_ring_state & S_RING_TX_HIWAT) 2626 blocked = B_TRUE; 2627 mutex_exit(&sringp->s_ring_lock); 2628 } else { 2629 for (i = 0; i < mac_srs->srs_oth_ring_count; i++) { 2630 sringp = mac_srs->srs_oth_soft_rings[i]; 2631 mutex_enter(&sringp->s_ring_lock); 2632 if (sringp->s_ring_state & S_RING_TX_HIWAT) { 2633 blocked = B_TRUE; 2634 mutex_exit(&sringp->s_ring_lock); 2635 break; 2636 } 2637 mutex_exit(&sringp->s_ring_lock); 2638 } 2639 } 2640 } else { 2641 blocked = (mac_srs->srs_state & SRS_TX_HIWAT); 2642 } 2643 mutex_exit(&mac_srs->srs_lock); 2644 MAC_TX_RELE(mcip, mytx); 2645 return (blocked); 2646 } 2647 2648 /* 2649 * Check if the MAC client is the primary MAC client. 2650 */ 2651 boolean_t 2652 mac_is_primary_client(mac_client_impl_t *mcip) 2653 { 2654 return (mcip->mci_flags & MAC_CLIENT_FLAGS_PRIMARY); 2655 } 2656 2657 void 2658 mac_ioctl(mac_handle_t mh, queue_t *wq, mblk_t *bp) 2659 { 2660 mac_impl_t *mip = (mac_impl_t *)mh; 2661 int cmd = ((struct iocblk *)bp->b_rptr)->ioc_cmd; 2662 2663 if ((cmd == ND_GET && (mip->mi_callbacks->mc_callbacks & MC_GETPROP)) || 2664 (cmd == ND_SET && (mip->mi_callbacks->mc_callbacks & MC_SETPROP))) { 2665 /* 2666 * If ndd props were registered, call them. 2667 * Note that ndd ioctls are Obsolete 2668 */ 2669 mac_ndd_ioctl(mip, wq, bp); 2670 return; 2671 } 2672 2673 /* 2674 * Call the driver to handle the ioctl. The driver may not support 2675 * any ioctls, in which case we reply with a NAK on its behalf. 2676 */ 2677 if (mip->mi_callbacks->mc_callbacks & MC_IOCTL) 2678 mip->mi_ioctl(mip->mi_driver, wq, bp); 2679 else 2680 miocnak(wq, bp, 0, EINVAL); 2681 } 2682 2683 /* 2684 * Return the link state of the specified MAC instance. 2685 */ 2686 link_state_t 2687 mac_link_get(mac_handle_t mh) 2688 { 2689 return (((mac_impl_t *)mh)->mi_linkstate); 2690 } 2691 2692 /* 2693 * Add a mac client specified notification callback. Please see the comments 2694 * above mac_callback_add() for general information about mac callback 2695 * addition/deletion in the presence of mac callback list walkers 2696 */ 2697 mac_notify_handle_t 2698 mac_notify_add(mac_handle_t mh, mac_notify_t notify_fn, void *arg) 2699 { 2700 mac_impl_t *mip = (mac_impl_t *)mh; 2701 mac_notify_cb_t *mncb; 2702 mac_cb_info_t *mcbi; 2703 2704 /* 2705 * Allocate a notify callback structure, fill in the details and 2706 * use the mac callback list manipulation functions to chain into 2707 * the list of callbacks. 2708 */ 2709 mncb = kmem_zalloc(sizeof (mac_notify_cb_t), KM_SLEEP); 2710 mncb->mncb_fn = notify_fn; 2711 mncb->mncb_arg = arg; 2712 mncb->mncb_mip = mip; 2713 mncb->mncb_link.mcb_objp = mncb; 2714 mncb->mncb_link.mcb_objsize = sizeof (mac_notify_cb_t); 2715 mncb->mncb_link.mcb_flags = MCB_NOTIFY_CB_T; 2716 2717 mcbi = &mip->mi_notify_cb_info; 2718 2719 i_mac_perim_enter(mip); 2720 mutex_enter(mcbi->mcbi_lockp); 2721 2722 mac_callback_add(&mip->mi_notify_cb_info, &mip->mi_notify_cb_list, 2723 &mncb->mncb_link); 2724 2725 mutex_exit(mcbi->mcbi_lockp); 2726 i_mac_perim_exit(mip); 2727 return ((mac_notify_handle_t)mncb); 2728 } 2729 2730 void 2731 mac_notify_remove_wait(mac_handle_t mh) 2732 { 2733 mac_impl_t *mip = (mac_impl_t *)mh; 2734 mac_cb_info_t *mcbi = &mip->mi_notify_cb_info; 2735 2736 mutex_enter(mcbi->mcbi_lockp); 2737 mac_callback_remove_wait(&mip->mi_notify_cb_info); 2738 mutex_exit(mcbi->mcbi_lockp); 2739 } 2740 2741 /* 2742 * Remove a mac client specified notification callback 2743 */ 2744 int 2745 mac_notify_remove(mac_notify_handle_t mnh, boolean_t wait) 2746 { 2747 mac_notify_cb_t *mncb = (mac_notify_cb_t *)mnh; 2748 mac_impl_t *mip = mncb->mncb_mip; 2749 mac_cb_info_t *mcbi; 2750 int err = 0; 2751 2752 mcbi = &mip->mi_notify_cb_info; 2753 2754 i_mac_perim_enter(mip); 2755 mutex_enter(mcbi->mcbi_lockp); 2756 2757 ASSERT(mncb->mncb_link.mcb_objp == mncb); 2758 /* 2759 * If there aren't any list walkers, the remove would succeed 2760 * inline, else we wait for the deferred remove to complete 2761 */ 2762 if (mac_callback_remove(&mip->mi_notify_cb_info, 2763 &mip->mi_notify_cb_list, &mncb->mncb_link)) { 2764 kmem_free(mncb, sizeof (mac_notify_cb_t)); 2765 } else { 2766 err = EBUSY; 2767 } 2768 2769 mutex_exit(mcbi->mcbi_lockp); 2770 i_mac_perim_exit(mip); 2771 2772 /* 2773 * If we failed to remove the notification callback and "wait" is set 2774 * to be B_TRUE, wait for the callback to finish after we exit the 2775 * mac perimeter. 2776 */ 2777 if (err != 0 && wait) { 2778 mac_notify_remove_wait((mac_handle_t)mip); 2779 return (0); 2780 } 2781 2782 return (err); 2783 } 2784 2785 /* 2786 * Associate resource management callbacks with the specified MAC 2787 * clients. 2788 */ 2789 2790 void 2791 mac_resource_set_common(mac_client_handle_t mch, mac_resource_add_t add, 2792 mac_resource_remove_t remove, mac_resource_quiesce_t quiesce, 2793 mac_resource_restart_t restart, mac_resource_bind_t bind, 2794 void *arg) 2795 { 2796 mac_client_impl_t *mcip = (mac_client_impl_t *)mch; 2797 2798 mcip->mci_resource_add = add; 2799 mcip->mci_resource_remove = remove; 2800 mcip->mci_resource_quiesce = quiesce; 2801 mcip->mci_resource_restart = restart; 2802 mcip->mci_resource_bind = bind; 2803 mcip->mci_resource_arg = arg; 2804 2805 if (arg == NULL) 2806 mcip->mci_state_flags &= ~MCIS_CLIENT_POLL_CAPABLE; 2807 } 2808 2809 void 2810 mac_resource_set(mac_client_handle_t mch, mac_resource_add_t add, void *arg) 2811 { 2812 /* update the 'resource_add' callback */ 2813 mac_resource_set_common(mch, add, NULL, NULL, NULL, NULL, arg); 2814 } 2815 2816 /* 2817 * Sets up the client resources and enable the polling interface over all the 2818 * SRS's and the soft rings of the client 2819 */ 2820 void 2821 mac_client_poll_enable(mac_client_handle_t mch) 2822 { 2823 mac_client_impl_t *mcip = (mac_client_impl_t *)mch; 2824 mac_soft_ring_set_t *mac_srs; 2825 flow_entry_t *flent; 2826 int i; 2827 2828 flent = mcip->mci_flent; 2829 ASSERT(flent != NULL); 2830 2831 for (i = 0; i < flent->fe_rx_srs_cnt; i++) { 2832 mac_srs = (mac_soft_ring_set_t *)flent->fe_rx_srs[i]; 2833 ASSERT(mac_srs->srs_mcip == mcip); 2834 mac_srs_client_poll_enable(mcip, mac_srs); 2835 } 2836 } 2837 2838 /* 2839 * Tears down the client resources and disable the polling interface over all 2840 * the SRS's and the soft rings of the client 2841 */ 2842 void 2843 mac_client_poll_disable(mac_client_handle_t mch) 2844 { 2845 mac_client_impl_t *mcip = (mac_client_impl_t *)mch; 2846 mac_soft_ring_set_t *mac_srs; 2847 flow_entry_t *flent; 2848 int i; 2849 2850 flent = mcip->mci_flent; 2851 ASSERT(flent != NULL); 2852 2853 for (i = 0; i < flent->fe_rx_srs_cnt; i++) { 2854 mac_srs = (mac_soft_ring_set_t *)flent->fe_rx_srs[i]; 2855 ASSERT(mac_srs->srs_mcip == mcip); 2856 mac_srs_client_poll_disable(mcip, mac_srs); 2857 } 2858 } 2859 2860 /* 2861 * Associate the CPUs specified by the given property with a MAC client. 2862 */ 2863 int 2864 mac_cpu_set(mac_client_handle_t mch, mac_resource_props_t *mrp) 2865 { 2866 mac_client_impl_t *mcip = (mac_client_impl_t *)mch; 2867 mac_impl_t *mip = mcip->mci_mip; 2868 int err = 0; 2869 2870 ASSERT(MAC_PERIM_HELD((mac_handle_t)mip)); 2871 2872 if ((err = mac_validate_props(mrp)) != 0) 2873 return (err); 2874 2875 if (MCIP_DATAPATH_SETUP(mcip)) 2876 mac_flow_modify(mip->mi_flow_tab, mcip->mci_flent, mrp); 2877 2878 mac_update_resources(mrp, MCIP_RESOURCE_PROPS(mcip), B_FALSE); 2879 return (0); 2880 } 2881 2882 /* 2883 * Apply the specified properties to the specified MAC client. 2884 */ 2885 int 2886 mac_client_set_resources(mac_client_handle_t mch, mac_resource_props_t *mrp) 2887 { 2888 mac_client_impl_t *mcip = (mac_client_impl_t *)mch; 2889 mac_impl_t *mip = mcip->mci_mip; 2890 int err = 0; 2891 2892 i_mac_perim_enter(mip); 2893 2894 if ((mrp->mrp_mask & MRP_MAXBW) || (mrp->mrp_mask & MRP_PRIORITY)) { 2895 err = mac_resource_ctl_set(mch, mrp); 2896 if (err != 0) { 2897 i_mac_perim_exit(mip); 2898 return (err); 2899 } 2900 } 2901 2902 if (mrp->mrp_mask & MRP_CPUS) 2903 err = mac_cpu_set(mch, mrp); 2904 2905 i_mac_perim_exit(mip); 2906 return (err); 2907 } 2908 2909 /* 2910 * Return the properties currently associated with the specified MAC client. 2911 */ 2912 void 2913 mac_client_get_resources(mac_client_handle_t mch, mac_resource_props_t *mrp) 2914 { 2915 mac_client_impl_t *mcip = (mac_client_impl_t *)mch; 2916 mac_resource_props_t *mcip_mrp = MCIP_RESOURCE_PROPS(mcip); 2917 2918 bcopy(mcip_mrp, mrp, sizeof (mac_resource_props_t)); 2919 } 2920 2921 /* 2922 * Pass a copy of the specified packet to the promiscuous callbacks 2923 * of the specified MAC. 2924 * 2925 * If sender is NULL, the function is being invoked for a packet chain 2926 * received from the wire. If sender is non-NULL, it points to 2927 * the MAC client from which the packet is being sent. 2928 * 2929 * The packets are distributed to the promiscuous callbacks as follows: 2930 * 2931 * - all packets are sent to the MAC_CLIENT_PROMISC_ALL callbacks 2932 * - all broadcast and multicast packets are sent to the 2933 * MAC_CLIENT_PROMISC_FILTER and MAC_CLIENT_PROMISC_MULTI. 2934 * 2935 * The unicast packets of MAC_CLIENT_PROMISC_FILTER callbacks are dispatched 2936 * after classification by mac_rx_deliver(). 2937 */ 2938 2939 static void 2940 mac_promisc_dispatch_one(mac_promisc_impl_t *mpip, mblk_t *mp, 2941 boolean_t loopback) 2942 { 2943 mblk_t *mp_copy; 2944 2945 mp_copy = copymsg(mp); 2946 if (mp_copy == NULL) 2947 return; 2948 mp_copy->b_next = NULL; 2949 2950 if (mpip->mpi_strip_vlan_tag) { 2951 if ((mp_copy = mac_strip_vlan_tag_chain(mp_copy)) == NULL) 2952 return; 2953 } 2954 mpip->mpi_fn(mpip->mpi_arg, NULL, mp_copy, loopback); 2955 } 2956 2957 /* 2958 * Return the VID of a packet. Zero if the packet is not tagged. 2959 */ 2960 static uint16_t 2961 mac_ether_vid(mblk_t *mp) 2962 { 2963 struct ether_header *eth = (struct ether_header *)mp->b_rptr; 2964 2965 if (ntohs(eth->ether_type) == ETHERTYPE_VLAN) { 2966 struct ether_vlan_header *t_evhp = 2967 (struct ether_vlan_header *)mp->b_rptr; 2968 return (VLAN_ID(ntohs(t_evhp->ether_tci))); 2969 } 2970 2971 return (0); 2972 } 2973 2974 /* 2975 * Return whether the specified packet contains a multicast or broadcast 2976 * destination MAC address. 2977 */ 2978 static boolean_t 2979 mac_is_mcast(mac_impl_t *mip, mblk_t *mp) 2980 { 2981 mac_header_info_t hdr_info; 2982 2983 if (mac_header_info((mac_handle_t)mip, mp, &hdr_info) != 0) 2984 return (B_FALSE); 2985 return ((hdr_info.mhi_dsttype == MAC_ADDRTYPE_BROADCAST) || 2986 (hdr_info.mhi_dsttype == MAC_ADDRTYPE_MULTICAST)); 2987 } 2988 2989 /* 2990 * Send a copy of an mblk chain to the MAC clients of the specified MAC. 2991 * "sender" points to the sender MAC client for outbound packets, and 2992 * is set to NULL for inbound packets. 2993 */ 2994 void 2995 mac_promisc_dispatch(mac_impl_t *mip, mblk_t *mp_chain, 2996 mac_client_impl_t *sender) 2997 { 2998 mac_promisc_impl_t *mpip; 2999 mac_cb_t *mcb; 3000 mblk_t *mp; 3001 boolean_t is_mcast, is_sender; 3002 3003 MAC_PROMISC_WALKER_INC(mip); 3004 for (mp = mp_chain; mp != NULL; mp = mp->b_next) { 3005 is_mcast = mac_is_mcast(mip, mp); 3006 /* send packet to interested callbacks */ 3007 for (mcb = mip->mi_promisc_list; mcb != NULL; 3008 mcb = mcb->mcb_nextp) { 3009 mpip = (mac_promisc_impl_t *)mcb->mcb_objp; 3010 is_sender = (mpip->mpi_mcip == sender); 3011 3012 if (is_sender && mpip->mpi_no_tx_loop) 3013 /* 3014 * The sender doesn't want to receive 3015 * copies of the packets it sends. 3016 */ 3017 continue; 3018 3019 /* 3020 * For an ethernet MAC, don't displatch a multicast 3021 * packet to a non-PROMISC_ALL callbacks unless the VID 3022 * of the packet matches the VID of the client. 3023 */ 3024 if (is_mcast && 3025 mpip->mpi_type != MAC_CLIENT_PROMISC_ALL && 3026 !mac_client_check_flow_vid(mpip->mpi_mcip, 3027 mac_ether_vid(mp))) 3028 continue; 3029 3030 if (is_sender || 3031 mpip->mpi_type == MAC_CLIENT_PROMISC_ALL || 3032 is_mcast) 3033 mac_promisc_dispatch_one(mpip, mp, is_sender); 3034 } 3035 } 3036 MAC_PROMISC_WALKER_DCR(mip); 3037 } 3038 3039 void 3040 mac_promisc_client_dispatch(mac_client_impl_t *mcip, mblk_t *mp_chain) 3041 { 3042 mac_impl_t *mip = mcip->mci_mip; 3043 mac_promisc_impl_t *mpip; 3044 boolean_t is_mcast; 3045 mblk_t *mp; 3046 mac_cb_t *mcb; 3047 3048 /* 3049 * The unicast packets for the MAC client still 3050 * need to be delivered to the MAC_CLIENT_PROMISC_FILTERED 3051 * promiscuous callbacks. The broadcast and multicast 3052 * packets were delivered from mac_rx(). 3053 */ 3054 MAC_PROMISC_WALKER_INC(mip); 3055 for (mp = mp_chain; mp != NULL; mp = mp->b_next) { 3056 is_mcast = mac_is_mcast(mip, mp); 3057 for (mcb = mcip->mci_promisc_list; mcb != NULL; 3058 mcb = mcb->mcb_nextp) { 3059 mpip = (mac_promisc_impl_t *)mcb->mcb_objp; 3060 if (mpip->mpi_type == MAC_CLIENT_PROMISC_FILTERED && 3061 !is_mcast) { 3062 mac_promisc_dispatch_one(mpip, mp, B_FALSE); 3063 } 3064 } 3065 } 3066 MAC_PROMISC_WALKER_DCR(mip); 3067 } 3068 3069 /* 3070 * Return the margin value currently assigned to the specified MAC instance. 3071 */ 3072 void 3073 mac_margin_get(mac_handle_t mh, uint32_t *marginp) 3074 { 3075 mac_impl_t *mip = (mac_impl_t *)mh; 3076 3077 rw_enter(&(mip->mi_rw_lock), RW_READER); 3078 *marginp = mip->mi_margin; 3079 rw_exit(&(mip->mi_rw_lock)); 3080 } 3081 3082 /* 3083 * mac_info_get() is used for retrieving the mac_info when a DL_INFO_REQ is 3084 * issued before a DL_ATTACH_REQ. we walk the i_mac_impl_hash table and find 3085 * the first mac_impl_t with a matching driver name; then we copy its mac_info_t 3086 * to the caller. we do all this with i_mac_impl_lock held so the mac_impl_t 3087 * cannot disappear while we are accessing it. 3088 */ 3089 typedef struct i_mac_info_state_s { 3090 const char *mi_name; 3091 mac_info_t *mi_infop; 3092 } i_mac_info_state_t; 3093 3094 /*ARGSUSED*/ 3095 static uint_t 3096 i_mac_info_walker(mod_hash_key_t key, mod_hash_val_t *val, void *arg) 3097 { 3098 i_mac_info_state_t *statep = arg; 3099 mac_impl_t *mip = (mac_impl_t *)val; 3100 3101 if (mip->mi_state_flags & MIS_DISABLED) 3102 return (MH_WALK_CONTINUE); 3103 3104 if (strcmp(statep->mi_name, 3105 ddi_driver_name(mip->mi_dip)) != 0) 3106 return (MH_WALK_CONTINUE); 3107 3108 statep->mi_infop = &mip->mi_info; 3109 return (MH_WALK_TERMINATE); 3110 } 3111 3112 boolean_t 3113 mac_info_get(const char *name, mac_info_t *minfop) 3114 { 3115 i_mac_info_state_t state; 3116 3117 rw_enter(&i_mac_impl_lock, RW_READER); 3118 state.mi_name = name; 3119 state.mi_infop = NULL; 3120 mod_hash_walk(i_mac_impl_hash, i_mac_info_walker, &state); 3121 if (state.mi_infop == NULL) { 3122 rw_exit(&i_mac_impl_lock); 3123 return (B_FALSE); 3124 } 3125 *minfop = *state.mi_infop; 3126 rw_exit(&i_mac_impl_lock); 3127 return (B_TRUE); 3128 } 3129 3130 /* 3131 * To get the capabilities that MAC layer cares about, such as rings, factory 3132 * mac address, vnic or not, it should directly invoke this function 3133 */ 3134 boolean_t 3135 i_mac_capab_get(mac_handle_t mh, mac_capab_t cap, void *cap_data) 3136 { 3137 mac_impl_t *mip = (mac_impl_t *)mh; 3138 3139 if (mip->mi_callbacks->mc_callbacks & MC_GETCAPAB) 3140 return (mip->mi_getcapab(mip->mi_driver, cap, cap_data)); 3141 else 3142 return (B_FALSE); 3143 } 3144 3145 /* 3146 * Capability query function. If number of active mac clients is greater than 3147 * 1, only limited capabilities can be advertised to the caller no matter the 3148 * driver has certain capability or not. Else, we query the driver to get the 3149 * capability. 3150 */ 3151 boolean_t 3152 mac_capab_get(mac_handle_t mh, mac_capab_t cap, void *cap_data) 3153 { 3154 mac_impl_t *mip = (mac_impl_t *)mh; 3155 3156 /* 3157 * if mi_nactiveclients > 1, only MAC_CAPAB_HCKSUM, 3158 * MAC_CAPAB_NO_NATIVEVLAN, MAC_CAPAB_NO_ZCOPY can be advertised. 3159 */ 3160 if (mip->mi_nactiveclients > 1) { 3161 switch (cap) { 3162 case MAC_CAPAB_HCKSUM: 3163 return (i_mac_capab_get(mh, cap, cap_data)); 3164 case MAC_CAPAB_NO_NATIVEVLAN: 3165 case MAC_CAPAB_NO_ZCOPY: 3166 return (B_TRUE); 3167 default: 3168 return (B_FALSE); 3169 } 3170 } 3171 3172 /* else get capab from driver */ 3173 return (i_mac_capab_get(mh, cap, cap_data)); 3174 } 3175 3176 boolean_t 3177 mac_sap_verify(mac_handle_t mh, uint32_t sap, uint32_t *bind_sap) 3178 { 3179 mac_impl_t *mip = (mac_impl_t *)mh; 3180 3181 return (mip->mi_type->mt_ops.mtops_sap_verify(sap, bind_sap, 3182 mip->mi_pdata)); 3183 } 3184 3185 mblk_t * 3186 mac_header(mac_handle_t mh, const uint8_t *daddr, uint32_t sap, mblk_t *payload, 3187 size_t extra_len) 3188 { 3189 mac_impl_t *mip = (mac_impl_t *)mh; 3190 3191 return (mip->mi_type->mt_ops.mtops_header(mip->mi_addr, daddr, sap, 3192 mip->mi_pdata, payload, extra_len)); 3193 } 3194 3195 int 3196 mac_header_info(mac_handle_t mh, mblk_t *mp, mac_header_info_t *mhip) 3197 { 3198 mac_impl_t *mip = (mac_impl_t *)mh; 3199 3200 return (mip->mi_type->mt_ops.mtops_header_info(mp, mip->mi_pdata, 3201 mhip)); 3202 } 3203 3204 mblk_t * 3205 mac_header_cook(mac_handle_t mh, mblk_t *mp) 3206 { 3207 mac_impl_t *mip = (mac_impl_t *)mh; 3208 3209 if (mip->mi_type->mt_ops.mtops_ops & MTOPS_HEADER_COOK) { 3210 if (DB_REF(mp) > 1) { 3211 mblk_t *newmp = copymsg(mp); 3212 if (newmp == NULL) 3213 return (NULL); 3214 freemsg(mp); 3215 mp = newmp; 3216 } 3217 return (mip->mi_type->mt_ops.mtops_header_cook(mp, 3218 mip->mi_pdata)); 3219 } 3220 return (mp); 3221 } 3222 3223 mblk_t * 3224 mac_header_uncook(mac_handle_t mh, mblk_t *mp) 3225 { 3226 mac_impl_t *mip = (mac_impl_t *)mh; 3227 3228 if (mip->mi_type->mt_ops.mtops_ops & MTOPS_HEADER_UNCOOK) { 3229 if (DB_REF(mp) > 1) { 3230 mblk_t *newmp = copymsg(mp); 3231 if (newmp == NULL) 3232 return (NULL); 3233 freemsg(mp); 3234 mp = newmp; 3235 } 3236 return (mip->mi_type->mt_ops.mtops_header_uncook(mp, 3237 mip->mi_pdata)); 3238 } 3239 return (mp); 3240 } 3241 3242 uint_t 3243 mac_addr_len(mac_handle_t mh) 3244 { 3245 mac_impl_t *mip = (mac_impl_t *)mh; 3246 3247 return (mip->mi_type->mt_addr_length); 3248 } 3249 3250 /* True if a MAC is a VNIC */ 3251 boolean_t 3252 mac_is_vnic(mac_handle_t mh) 3253 { 3254 return (((mac_impl_t *)mh)->mi_state_flags & MIS_IS_VNIC); 3255 } 3256 3257 mac_handle_t 3258 mac_get_lower_mac_handle(mac_handle_t mh) 3259 { 3260 mac_impl_t *mip = (mac_impl_t *)mh; 3261 3262 ASSERT(mac_is_vnic(mh)); 3263 return (((vnic_t *)mip->mi_driver)->vn_lower_mh); 3264 } 3265 3266 void 3267 mac_update_resources(mac_resource_props_t *nmrp, mac_resource_props_t *cmrp, 3268 boolean_t is_user_flow) 3269 { 3270 if (nmrp != NULL && cmrp != NULL) { 3271 if (nmrp->mrp_mask & MRP_PRIORITY) { 3272 if (nmrp->mrp_priority == MPL_RESET) { 3273 cmrp->mrp_mask &= ~MRP_PRIORITY; 3274 if (is_user_flow) { 3275 cmrp->mrp_priority = 3276 MPL_SUBFLOW_DEFAULT; 3277 } else { 3278 cmrp->mrp_priority = MPL_LINK_DEFAULT; 3279 } 3280 } else { 3281 cmrp->mrp_mask |= MRP_PRIORITY; 3282 cmrp->mrp_priority = nmrp->mrp_priority; 3283 } 3284 } 3285 if (nmrp->mrp_mask & MRP_MAXBW) { 3286 cmrp->mrp_maxbw = nmrp->mrp_maxbw; 3287 if (nmrp->mrp_maxbw == MRP_MAXBW_RESETVAL) 3288 cmrp->mrp_mask &= ~MRP_MAXBW; 3289 else 3290 cmrp->mrp_mask |= MRP_MAXBW; 3291 } 3292 if (nmrp->mrp_mask & MRP_CPUS) 3293 MAC_COPY_CPUS(nmrp, cmrp); 3294 } 3295 } 3296 3297 /* 3298 * i_mac_set_resources: 3299 * 3300 * This routine associates properties with the primary MAC client of 3301 * the specified MAC instance. 3302 * - Cache the properties in mac_impl_t 3303 * - Apply the properties to the primary MAC client if exists 3304 */ 3305 int 3306 i_mac_set_resources(mac_handle_t mh, mac_resource_props_t *mrp) 3307 { 3308 mac_impl_t *mip = (mac_impl_t *)mh; 3309 mac_client_impl_t *mcip; 3310 int err = 0; 3311 mac_resource_props_t tmrp; 3312 3313 ASSERT(MAC_PERIM_HELD((mac_handle_t)mip)); 3314 3315 err = mac_validate_props(mrp); 3316 if (err != 0) 3317 return (err); 3318 3319 /* 3320 * Since bind_cpu may be modified by mac_client_set_resources() 3321 * we use a copy of bind_cpu and finally cache bind_cpu in mip. 3322 * This allows us to cache only user edits in mip. 3323 */ 3324 bcopy(mrp, &tmrp, sizeof (mac_resource_props_t)); 3325 mcip = mac_primary_client_handle(mip); 3326 if (mcip != NULL && (mcip->mci_state_flags & MCIS_IS_AGGR_PORT) == 0) { 3327 err = 3328 mac_client_set_resources((mac_client_handle_t)mcip, &tmrp); 3329 } 3330 /* if mac_client_set_resources failed, do not update the values */ 3331 if (err == 0) 3332 mac_update_resources(mrp, &mip->mi_resource_props, B_FALSE); 3333 return (err); 3334 } 3335 3336 int 3337 mac_set_resources(mac_handle_t mh, mac_resource_props_t *mrp) 3338 { 3339 int err; 3340 3341 i_mac_perim_enter((mac_impl_t *)mh); 3342 err = i_mac_set_resources(mh, mrp); 3343 i_mac_perim_exit((mac_impl_t *)mh); 3344 return (err); 3345 } 3346 3347 /* 3348 * Get the properties cached for the specified MAC instance. 3349 */ 3350 void 3351 mac_get_resources(mac_handle_t mh, mac_resource_props_t *mrp) 3352 { 3353 mac_impl_t *mip = (mac_impl_t *)mh; 3354 mac_client_impl_t *mcip; 3355 3356 if (mip->mi_state_flags & MIS_IS_VNIC) { 3357 mcip = mac_primary_client_handle(mip); 3358 if (mcip != NULL) { 3359 mac_client_get_resources((mac_client_handle_t)mcip, 3360 mrp); 3361 return; 3362 } 3363 } 3364 bcopy(&mip->mi_resource_props, mrp, sizeof (mac_resource_props_t)); 3365 } 3366 3367 /* 3368 * Rename a mac client, its flow, and the kstat. 3369 */ 3370 int 3371 mac_rename_primary(mac_handle_t mh, const char *new_name) 3372 { 3373 mac_impl_t *mip = (mac_impl_t *)mh; 3374 mac_client_impl_t *cur_clnt = NULL; 3375 flow_entry_t *fep; 3376 3377 i_mac_perim_enter(mip); 3378 3379 /* 3380 * VNICs: we need to change the sys flow name and 3381 * the associated flow kstat. 3382 */ 3383 if (mip->mi_state_flags & MIS_IS_VNIC) { 3384 ASSERT(new_name != NULL); 3385 mac_rename_flow_names(mac_vnic_lower(mip), new_name); 3386 goto done; 3387 } 3388 /* 3389 * This mac may itself be an aggr link, or it may have some client 3390 * which is an aggr port. For both cases, we need to change the 3391 * aggr port's mac client name, its flow name and the associated flow 3392 * kstat. 3393 */ 3394 if (mip->mi_state_flags & MIS_IS_AGGR) { 3395 mac_capab_aggr_t aggr_cap; 3396 mac_rename_fn_t rename_fn; 3397 boolean_t ret; 3398 3399 ASSERT(new_name != NULL); 3400 ret = i_mac_capab_get((mac_handle_t)mip, MAC_CAPAB_AGGR, 3401 (void *)(&aggr_cap)); 3402 ASSERT(ret == B_TRUE); 3403 rename_fn = aggr_cap.mca_rename_fn; 3404 rename_fn(new_name, mip->mi_driver); 3405 /* 3406 * The aggr's client name and kstat flow name will be 3407 * updated below, i.e. via mac_rename_flow_names. 3408 */ 3409 } 3410 3411 for (cur_clnt = mip->mi_clients_list; cur_clnt != NULL; 3412 cur_clnt = cur_clnt->mci_client_next) { 3413 if (cur_clnt->mci_state_flags & MCIS_IS_AGGR_PORT) { 3414 if (new_name != NULL) { 3415 char *str_st = cur_clnt->mci_name; 3416 char *str_del = strchr(str_st, '-'); 3417 3418 ASSERT(str_del != NULL); 3419 bzero(str_del + 1, MAXNAMELEN - 3420 (str_del - str_st + 1)); 3421 bcopy(new_name, str_del + 1, 3422 strlen(new_name)); 3423 } 3424 fep = cur_clnt->mci_flent; 3425 mac_rename_flow(fep, cur_clnt->mci_name); 3426 break; 3427 } else if (new_name != NULL && 3428 cur_clnt->mci_state_flags & MCIS_USE_DATALINK_NAME) { 3429 mac_rename_flow_names(cur_clnt, new_name); 3430 break; 3431 } 3432 } 3433 3434 done: 3435 i_mac_perim_exit(mip); 3436 return (0); 3437 } 3438 3439 /* 3440 * Rename the MAC client's flow names 3441 */ 3442 static void 3443 mac_rename_flow_names(mac_client_impl_t *mcip, const char *new_name) 3444 { 3445 flow_entry_t *flent; 3446 uint16_t vid; 3447 char flowname[MAXFLOWNAMELEN]; 3448 mac_impl_t *mip = mcip->mci_mip; 3449 3450 ASSERT(MAC_PERIM_HELD((mac_handle_t)mip)); 3451 3452 /* 3453 * Use mi_rw_lock to ensure that threads not in the mac perimeter 3454 * see a self-consistent value for mci_name 3455 */ 3456 rw_enter(&mip->mi_rw_lock, RW_WRITER); 3457 (void) strlcpy(mcip->mci_name, new_name, sizeof (mcip->mci_name)); 3458 rw_exit(&mip->mi_rw_lock); 3459 3460 mac_rename_flow(mcip->mci_flent, new_name); 3461 3462 if (mcip->mci_nflents == 1) 3463 return; 3464 3465 /* 3466 * We have to rename all the others too, no stats to destroy for 3467 * these. 3468 */ 3469 for (flent = mcip->mci_flent_list; flent != NULL; 3470 flent = flent->fe_client_next) { 3471 if (flent != mcip->mci_flent) { 3472 vid = i_mac_flow_vid(flent); 3473 (void) sprintf(flowname, "%s%u", new_name, vid); 3474 mac_flow_set_name(flent, flowname); 3475 } 3476 } 3477 } 3478 3479 3480 /* 3481 * Add a flow to the MAC client's flow list - i.e list of MAC/VID tuples 3482 * defined for the specified MAC client. 3483 */ 3484 static void 3485 mac_client_add_to_flow_list(mac_client_impl_t *mcip, flow_entry_t *flent) 3486 { 3487 ASSERT(MAC_PERIM_HELD((mac_handle_t)mcip->mci_mip)); 3488 /* 3489 * The promisc Rx data path walks the mci_flent_list. Protect by 3490 * using mi_rw_lock 3491 */ 3492 rw_enter(&mcip->mci_rw_lock, RW_WRITER); 3493 3494 /* Add it to the head */ 3495 flent->fe_client_next = mcip->mci_flent_list; 3496 mcip->mci_flent_list = flent; 3497 mcip->mci_nflents++; 3498 3499 /* 3500 * Keep track of the number of non-zero VIDs addresses per MAC 3501 * client to avoid figuring it out in the data-path. 3502 */ 3503 if (i_mac_flow_vid(flent) != VLAN_ID_NONE) 3504 mcip->mci_nvids++; 3505 3506 rw_exit(&mcip->mci_rw_lock); 3507 } 3508 3509 /* 3510 * Remove a flow entry from the MAC client's list. 3511 */ 3512 static void 3513 mac_client_remove_flow_from_list(mac_client_impl_t *mcip, flow_entry_t *flent) 3514 { 3515 flow_entry_t *fe = mcip->mci_flent_list; 3516 flow_entry_t *prev_fe = NULL; 3517 3518 ASSERT(MAC_PERIM_HELD((mac_handle_t)mcip->mci_mip)); 3519 /* 3520 * The promisc Rx data path walks the mci_flent_list. Protect by 3521 * using mci_rw_lock 3522 */ 3523 rw_enter(&mcip->mci_rw_lock, RW_WRITER); 3524 while ((fe != NULL) && (fe != flent)) { 3525 prev_fe = fe; 3526 fe = fe->fe_client_next; 3527 } 3528 3529 ASSERT(fe != NULL); 3530 if (prev_fe == NULL) { 3531 /* Deleting the first node */ 3532 mcip->mci_flent_list = fe->fe_client_next; 3533 } else { 3534 prev_fe->fe_client_next = fe->fe_client_next; 3535 } 3536 mcip->mci_nflents--; 3537 3538 if (i_mac_flow_vid(flent) != VLAN_ID_NONE) 3539 mcip->mci_nvids--; 3540 3541 rw_exit(&mcip->mci_rw_lock); 3542 } 3543 3544 /* 3545 * Check if the given VID belongs to this MAC client. 3546 */ 3547 boolean_t 3548 mac_client_check_flow_vid(mac_client_impl_t *mcip, uint16_t vid) 3549 { 3550 flow_entry_t *flent; 3551 uint16_t mci_vid; 3552 3553 /* The mci_flent_list is protected by mci_rw_lock */ 3554 rw_enter(&mcip->mci_rw_lock, RW_WRITER); 3555 for (flent = mcip->mci_flent_list; flent != NULL; 3556 flent = flent->fe_client_next) { 3557 mci_vid = i_mac_flow_vid(flent); 3558 if (vid == mci_vid) { 3559 rw_exit(&mcip->mci_rw_lock); 3560 return (B_TRUE); 3561 } 3562 } 3563 rw_exit(&mcip->mci_rw_lock); 3564 return (B_FALSE); 3565 } 3566 3567 /* 3568 * Get the flow entry for the specified <MAC addr, VID> tuple. 3569 */ 3570 static flow_entry_t * 3571 mac_client_get_flow(mac_client_impl_t *mcip, mac_unicast_impl_t *muip) 3572 { 3573 mac_address_t *map = mcip->mci_unicast; 3574 flow_entry_t *flent; 3575 uint16_t vid; 3576 flow_desc_t flow_desc; 3577 3578 ASSERT(MAC_PERIM_HELD((mac_handle_t)mcip->mci_mip)); 3579 3580 mac_flow_get_desc(mcip->mci_flent, &flow_desc); 3581 if (bcmp(flow_desc.fd_dst_mac, map->ma_addr, map->ma_len) != 0) 3582 return (NULL); 3583 3584 for (flent = mcip->mci_flent_list; flent != NULL; 3585 flent = flent->fe_client_next) { 3586 vid = i_mac_flow_vid(flent); 3587 if (vid == muip->mui_vid) { 3588 return (flent); 3589 } 3590 } 3591 3592 return (NULL); 3593 } 3594 3595 /* 3596 * Since mci_flent has the SRSs, when we want to remove it, we replace 3597 * the flow_desc_t in mci_flent with that of an existing flent and then 3598 * remove that flent instead of mci_flent. 3599 */ 3600 static flow_entry_t * 3601 mac_client_swap_mciflent(mac_client_impl_t *mcip) 3602 { 3603 flow_entry_t *flent = mcip->mci_flent; 3604 flow_tab_t *ft = flent->fe_flow_tab; 3605 flow_entry_t *flent1; 3606 flow_desc_t fl_desc; 3607 char fl_name[MAXFLOWNAMELEN]; 3608 int err; 3609 3610 ASSERT(MAC_PERIM_HELD((mac_handle_t)mcip->mci_mip)); 3611 ASSERT(mcip->mci_nflents > 1); 3612 3613 /* get the next flent following the primary flent */ 3614 flent1 = mcip->mci_flent_list->fe_client_next; 3615 ASSERT(flent1 != NULL && flent1->fe_flow_tab == ft); 3616 3617 /* 3618 * Remove the flent from the flow table before updating the 3619 * flow descriptor as the hash depends on the flow descriptor. 3620 * This also helps incoming packet classification avoid having 3621 * to grab fe_lock. Access to fe_flow_desc of a flent not in the 3622 * flow table is done under the fe_lock so that log or stat functions 3623 * see a self-consistent fe_flow_desc. The name and desc are specific 3624 * to a flow, the rest are shared by all the clients, including 3625 * resource control etc. 3626 */ 3627 mac_flow_remove(ft, flent, B_TRUE); 3628 mac_flow_remove(ft, flent1, B_TRUE); 3629 3630 bcopy(&flent->fe_flow_desc, &fl_desc, sizeof (flow_desc_t)); 3631 bcopy(flent->fe_flow_name, fl_name, MAXFLOWNAMELEN); 3632 3633 /* update the primary flow entry */ 3634 mutex_enter(&flent->fe_lock); 3635 bcopy(&flent1->fe_flow_desc, &flent->fe_flow_desc, 3636 sizeof (flow_desc_t)); 3637 bcopy(&flent1->fe_flow_name, &flent->fe_flow_name, MAXFLOWNAMELEN); 3638 mutex_exit(&flent->fe_lock); 3639 3640 /* update the flow entry that is to be freed */ 3641 mutex_enter(&flent1->fe_lock); 3642 bcopy(&fl_desc, &flent1->fe_flow_desc, sizeof (flow_desc_t)); 3643 bcopy(fl_name, &flent1->fe_flow_name, MAXFLOWNAMELEN); 3644 mutex_exit(&flent1->fe_lock); 3645 3646 /* now reinsert the flow entries in the table */ 3647 err = mac_flow_add(ft, flent); 3648 ASSERT(err == 0); 3649 3650 err = mac_flow_add(ft, flent1); 3651 ASSERT(err == 0); 3652 3653 return (flent1); 3654 } 3655 3656 /* 3657 * Return whether there is only one flow entry associated with this 3658 * MAC client. 3659 */ 3660 static boolean_t 3661 mac_client_single_rcvr(mac_client_impl_t *mcip) 3662 { 3663 return (mcip->mci_nflents == 1); 3664 } 3665 3666 int 3667 mac_validate_props(mac_resource_props_t *mrp) 3668 { 3669 if (mrp == NULL) 3670 return (0); 3671 3672 if (mrp->mrp_mask & MRP_PRIORITY) { 3673 mac_priority_level_t pri = mrp->mrp_priority; 3674 3675 if (pri < MPL_LOW || pri > MPL_RESET) 3676 return (EINVAL); 3677 } 3678 3679 if (mrp->mrp_mask & MRP_MAXBW) { 3680 uint64_t maxbw = mrp->mrp_maxbw; 3681 3682 if (maxbw < MRP_MAXBW_MINVAL && maxbw != 0) 3683 return (EINVAL); 3684 } 3685 if (mrp->mrp_mask & MRP_CPUS) { 3686 int i; 3687 mac_cpu_mode_t fanout; 3688 3689 if (mrp->mrp_ncpus > ncpus || mrp->mrp_ncpus > MAX_SR_FANOUT) 3690 return (EINVAL); 3691 3692 for (i = 0; i < mrp->mrp_ncpus; i++) { 3693 cpu_t *cp; 3694 int rv; 3695 3696 mutex_enter(&cpu_lock); 3697 cp = cpu_get(mrp->mrp_cpu[i]); 3698 if (cp != NULL) 3699 rv = cpu_is_online(cp); 3700 else 3701 rv = 0; 3702 mutex_exit(&cpu_lock); 3703 if (rv == 0) 3704 return (EINVAL); 3705 } 3706 3707 fanout = mrp->mrp_fanout_mode; 3708 if (fanout < 0 || fanout > MCM_CPUS) 3709 return (EINVAL); 3710 } 3711 return (0); 3712 } 3713 3714 /* 3715 * Send a MAC_NOTE_LINK notification to all the MAC clients whenever the 3716 * underlying physical link is down. This is to allow MAC clients to 3717 * communicate with other clients. 3718 */ 3719 void 3720 mac_virtual_link_update(mac_impl_t *mip) 3721 { 3722 if (mip->mi_linkstate != LINK_STATE_UP) 3723 i_mac_notify(mip, MAC_NOTE_LINK); 3724 } 3725 3726 /* 3727 * For clients that have a pass-thru MAC, e.g. VNIC, we set the VNIC's 3728 * mac handle in the client. 3729 */ 3730 void 3731 mac_set_upper_mac(mac_client_handle_t mch, mac_handle_t mh) 3732 { 3733 mac_client_impl_t *mcip = (mac_client_impl_t *)mch; 3734 3735 mcip->mci_upper_mip = (mac_impl_t *)mh; 3736 } 3737 3738 /* 3739 * Mark the mac as being used exclusively by the single mac client that is 3740 * doing some control operation on this mac. No further opens of this mac 3741 * will be allowed until this client calls mac_unmark_exclusive. The mac 3742 * client calling this function must already be in the mac perimeter 3743 */ 3744 int 3745 mac_mark_exclusive(mac_handle_t mh) 3746 { 3747 mac_impl_t *mip = (mac_impl_t *)mh; 3748 3749 ASSERT(MAC_PERIM_HELD(mh)); 3750 /* 3751 * Look up its entry in the global hash table. 3752 */ 3753 rw_enter(&i_mac_impl_lock, RW_WRITER); 3754 if (mip->mi_state_flags & MIS_DISABLED) { 3755 rw_exit(&i_mac_impl_lock); 3756 return (ENOENT); 3757 } 3758 3759 /* 3760 * A reference to mac is held even if the link is not plumbed. 3761 * In i_dls_link_create() we open the MAC interface and hold the 3762 * reference. There is an additional reference for the mac_open 3763 * done in acquiring the mac perimeter 3764 */ 3765 if (mip->mi_ref != 2) { 3766 rw_exit(&i_mac_impl_lock); 3767 return (EBUSY); 3768 } 3769 3770 ASSERT(!(mip->mi_state_flags & MIS_EXCLUSIVE_HELD)); 3771 mip->mi_state_flags |= MIS_EXCLUSIVE_HELD; 3772 rw_exit(&i_mac_impl_lock); 3773 return (0); 3774 } 3775 3776 void 3777 mac_unmark_exclusive(mac_handle_t mh) 3778 { 3779 mac_impl_t *mip = (mac_impl_t *)mh; 3780 3781 ASSERT(MAC_PERIM_HELD(mh)); 3782 3783 rw_enter(&i_mac_impl_lock, RW_WRITER); 3784 /* 1 for the creation and another for the perimeter */ 3785 ASSERT(mip->mi_ref == 2 && (mip->mi_state_flags & MIS_EXCLUSIVE_HELD)); 3786 mip->mi_state_flags &= ~MIS_EXCLUSIVE_HELD; 3787 rw_exit(&i_mac_impl_lock); 3788 } 3789 3790 /* 3791 * Set the MTU for the specified device. The function returns EBUSY if 3792 * another MAC client prevents the caller to become the exclusive client. 3793 * Returns EAGAIN if the client is started. 3794 */ 3795 int 3796 mac_set_mtu(mac_handle_t mh, uint_t new_mtu, uint_t *old_mtu_arg) 3797 { 3798 mac_impl_t *mip = (mac_impl_t *)mh; 3799 uint_t old_mtu; 3800 int rv; 3801 boolean_t exclusive = B_FALSE; 3802 3803 i_mac_perim_enter(mip); 3804 3805 if ((mip->mi_callbacks->mc_callbacks & MC_SETPROP) == 0 || 3806 (mip->mi_callbacks->mc_callbacks & MC_GETPROP) == 0) { 3807 rv = ENOTSUP; 3808 goto bail; 3809 } 3810 3811 if ((rv = mac_mark_exclusive(mh)) != 0) 3812 goto bail; 3813 exclusive = B_TRUE; 3814 3815 if (mip->mi_active > 0) { 3816 /* 3817 * The MAC instance is started, for example due to the 3818 * presence of a promiscuous clients. Fail the operation 3819 * since the MAC's MTU cannot be changed while the NIC 3820 * is started. 3821 */ 3822 rv = EAGAIN; 3823 goto bail; 3824 } 3825 3826 mac_sdu_get(mh, NULL, &old_mtu); 3827 3828 if (old_mtu != new_mtu) { 3829 rv = mip->mi_callbacks->mc_setprop(mip->mi_driver, 3830 "mtu", MAC_PROP_MTU, sizeof (uint_t), &new_mtu); 3831 } 3832 3833 bail: 3834 if (exclusive) 3835 mac_unmark_exclusive(mh); 3836 i_mac_perim_exit(mip); 3837 3838 if (rv == 0 && old_mtu_arg != NULL) 3839 *old_mtu_arg = old_mtu; 3840 return (rv); 3841 } 3842 3843 void 3844 mac_get_hwgrp_info(mac_handle_t mh, int grp_index, uint_t *grp_num, 3845 uint_t *n_rings, uint_t *type, uint_t *n_clnts, char *clnts_name) 3846 { 3847 mac_impl_t *mip = (mac_impl_t *)mh; 3848 mac_grp_client_t *mcip; 3849 uint_t i = 0, index = 0; 3850 3851 /* Revisit when we implement fully dynamic group allocation */ 3852 ASSERT(grp_index >= 0 && grp_index < mip->mi_rx_group_count); 3853 3854 rw_enter(&mip->mi_rw_lock, RW_READER); 3855 *grp_num = mip->mi_rx_groups[grp_index].mrg_index; 3856 *type = mip->mi_rx_groups[grp_index].mrg_type; 3857 *n_rings = mip->mi_rx_groups[grp_index].mrg_cur_count; 3858 for (mcip = mip->mi_rx_groups[grp_index].mrg_clients; mcip != NULL; 3859 mcip = mcip->mgc_next) { 3860 int name_len = strlen(mcip->mgc_client->mci_name); 3861 3862 /* 3863 * MAXCLIENTNAMELEN is the buffer size reserved for client 3864 * names. 3865 * XXXX Formating the client name string needs to be moved 3866 * to user land when fixing the size of dhi_clnts in 3867 * dld_hwgrpinfo_t. We should use n_clients * client_name for 3868 * dhi_clntsin instead of MAXCLIENTNAMELEN 3869 */ 3870 if (index + name_len >= MAXCLIENTNAMELEN) { 3871 index = MAXCLIENTNAMELEN; 3872 break; 3873 } 3874 bcopy(mcip->mgc_client->mci_name, &(clnts_name[index]), 3875 name_len); 3876 index += name_len; 3877 clnts_name[index++] = ','; 3878 i++; 3879 } 3880 3881 /* Get rid of the last , */ 3882 if (index > 0) 3883 clnts_name[index - 1] = '\0'; 3884 *n_clnts = i; 3885 rw_exit(&mip->mi_rw_lock); 3886 } 3887 3888 uint_t 3889 mac_hwgrp_num(mac_handle_t mh) 3890 { 3891 mac_impl_t *mip = (mac_impl_t *)mh; 3892 3893 return (mip->mi_rx_group_count); 3894 } 3895