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