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