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