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 (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. 24 * Copyright (c) 2014, Joyent, Inc. All rights reserved. 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 done 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 * - Secondary MACs for VNICs: 96 * 97 * VNICs support multiple upper mac clients to enable support for 98 * multiple MAC addresses on the VNIC. When the VNIC is created the 99 * initial mac client is the primary upper mac. Any additional mac 100 * clients are secondary macs. These are kept in sync with the primary 101 * (for things such as the rx function and resource control settings) 102 * using the same private capability interface between the MAC layer 103 * and the VNIC layer. 104 * 105 */ 106 107 #include <sys/types.h> 108 #include <sys/conf.h> 109 #include <sys/id_space.h> 110 #include <sys/esunddi.h> 111 #include <sys/stat.h> 112 #include <sys/mkdev.h> 113 #include <sys/stream.h> 114 #include <sys/strsun.h> 115 #include <sys/strsubr.h> 116 #include <sys/dlpi.h> 117 #include <sys/modhash.h> 118 #include <sys/mac_impl.h> 119 #include <sys/mac_client_impl.h> 120 #include <sys/mac_soft_ring.h> 121 #include <sys/mac_stat.h> 122 #include <sys/dls.h> 123 #include <sys/dld.h> 124 #include <sys/modctl.h> 125 #include <sys/fs/dv_node.h> 126 #include <sys/thread.h> 127 #include <sys/proc.h> 128 #include <sys/callb.h> 129 #include <sys/cpuvar.h> 130 #include <sys/atomic.h> 131 #include <sys/sdt.h> 132 #include <sys/mac_flow.h> 133 #include <sys/ddi_intr_impl.h> 134 #include <sys/disp.h> 135 #include <sys/sdt.h> 136 #include <sys/vnic.h> 137 #include <sys/vnic_impl.h> 138 #include <sys/vlan.h> 139 #include <inet/ip.h> 140 #include <inet/ip6.h> 141 #include <sys/exacct.h> 142 #include <sys/exacct_impl.h> 143 #include <inet/nd.h> 144 #include <sys/ethernet.h> 145 146 kmem_cache_t *mac_client_impl_cache; 147 kmem_cache_t *mac_promisc_impl_cache; 148 149 static boolean_t mac_client_single_rcvr(mac_client_impl_t *); 150 static flow_entry_t *mac_client_swap_mciflent(mac_client_impl_t *); 151 static flow_entry_t *mac_client_get_flow(mac_client_impl_t *, 152 mac_unicast_impl_t *); 153 static void mac_client_remove_flow_from_list(mac_client_impl_t *, 154 flow_entry_t *); 155 static void mac_client_add_to_flow_list(mac_client_impl_t *, flow_entry_t *); 156 static void mac_rename_flow_names(mac_client_impl_t *, const char *); 157 static void mac_virtual_link_update(mac_impl_t *); 158 static int mac_client_datapath_setup(mac_client_impl_t *, uint16_t, 159 uint8_t *, mac_resource_props_t *, boolean_t, mac_unicast_impl_t *); 160 static void mac_client_datapath_teardown(mac_client_handle_t, 161 mac_unicast_impl_t *, flow_entry_t *); 162 static int mac_resource_ctl_set(mac_client_handle_t, mac_resource_props_t *); 163 164 /* ARGSUSED */ 165 static int 166 i_mac_client_impl_ctor(void *buf, void *arg, int kmflag) 167 { 168 int i; 169 mac_client_impl_t *mcip = buf; 170 171 bzero(buf, MAC_CLIENT_IMPL_SIZE); 172 mutex_init(&mcip->mci_tx_cb_lock, NULL, MUTEX_DRIVER, NULL); 173 mcip->mci_tx_notify_cb_info.mcbi_lockp = &mcip->mci_tx_cb_lock; 174 175 ASSERT(mac_tx_percpu_cnt >= 0); 176 for (i = 0; i <= mac_tx_percpu_cnt; i++) { 177 mutex_init(&mcip->mci_tx_pcpu[i].pcpu_tx_lock, NULL, 178 MUTEX_DRIVER, NULL); 179 } 180 cv_init(&mcip->mci_tx_cv, NULL, CV_DRIVER, NULL); 181 182 return (0); 183 } 184 185 /* ARGSUSED */ 186 static void 187 i_mac_client_impl_dtor(void *buf, void *arg) 188 { 189 int i; 190 mac_client_impl_t *mcip = buf; 191 192 ASSERT(mcip->mci_promisc_list == NULL); 193 ASSERT(mcip->mci_unicast_list == NULL); 194 ASSERT(mcip->mci_state_flags == 0); 195 ASSERT(mcip->mci_tx_flag == 0); 196 197 mutex_destroy(&mcip->mci_tx_cb_lock); 198 199 ASSERT(mac_tx_percpu_cnt >= 0); 200 for (i = 0; i <= mac_tx_percpu_cnt; i++) { 201 ASSERT(mcip->mci_tx_pcpu[i].pcpu_tx_refcnt == 0); 202 mutex_destroy(&mcip->mci_tx_pcpu[i].pcpu_tx_lock); 203 } 204 cv_destroy(&mcip->mci_tx_cv); 205 } 206 207 /* ARGSUSED */ 208 static int 209 i_mac_promisc_impl_ctor(void *buf, void *arg, int kmflag) 210 { 211 mac_promisc_impl_t *mpip = buf; 212 213 bzero(buf, sizeof (mac_promisc_impl_t)); 214 mpip->mpi_mci_link.mcb_objp = buf; 215 mpip->mpi_mci_link.mcb_objsize = sizeof (mac_promisc_impl_t); 216 mpip->mpi_mi_link.mcb_objp = buf; 217 mpip->mpi_mi_link.mcb_objsize = sizeof (mac_promisc_impl_t); 218 return (0); 219 } 220 221 /* ARGSUSED */ 222 static void 223 i_mac_promisc_impl_dtor(void *buf, void *arg) 224 { 225 mac_promisc_impl_t *mpip = buf; 226 227 ASSERT(mpip->mpi_mci_link.mcb_objp != NULL); 228 ASSERT(mpip->mpi_mci_link.mcb_objsize == sizeof (mac_promisc_impl_t)); 229 ASSERT(mpip->mpi_mi_link.mcb_objp == mpip->mpi_mci_link.mcb_objp); 230 ASSERT(mpip->mpi_mi_link.mcb_objsize == sizeof (mac_promisc_impl_t)); 231 232 mpip->mpi_mci_link.mcb_objp = NULL; 233 mpip->mpi_mci_link.mcb_objsize = 0; 234 mpip->mpi_mi_link.mcb_objp = NULL; 235 mpip->mpi_mi_link.mcb_objsize = 0; 236 237 ASSERT(mpip->mpi_mci_link.mcb_flags == 0); 238 mpip->mpi_mci_link.mcb_objsize = 0; 239 } 240 241 void 242 mac_client_init(void) 243 { 244 ASSERT(mac_tx_percpu_cnt >= 0); 245 246 mac_client_impl_cache = kmem_cache_create("mac_client_impl_cache", 247 MAC_CLIENT_IMPL_SIZE, 0, i_mac_client_impl_ctor, 248 i_mac_client_impl_dtor, NULL, NULL, NULL, 0); 249 ASSERT(mac_client_impl_cache != NULL); 250 251 mac_promisc_impl_cache = kmem_cache_create("mac_promisc_impl_cache", 252 sizeof (mac_promisc_impl_t), 0, i_mac_promisc_impl_ctor, 253 i_mac_promisc_impl_dtor, NULL, NULL, NULL, 0); 254 ASSERT(mac_promisc_impl_cache != NULL); 255 } 256 257 void 258 mac_client_fini(void) 259 { 260 kmem_cache_destroy(mac_client_impl_cache); 261 kmem_cache_destroy(mac_promisc_impl_cache); 262 } 263 264 /* 265 * Return the lower MAC client handle from the VNIC driver for the 266 * specified VNIC MAC instance. 267 */ 268 mac_client_impl_t * 269 mac_vnic_lower(mac_impl_t *mip) 270 { 271 mac_capab_vnic_t cap; 272 mac_client_impl_t *mcip; 273 274 VERIFY(i_mac_capab_get((mac_handle_t)mip, MAC_CAPAB_VNIC, &cap)); 275 mcip = cap.mcv_mac_client_handle(cap.mcv_arg); 276 277 return (mcip); 278 } 279 280 /* 281 * Update the secondary macs 282 */ 283 void 284 mac_vnic_secondary_update(mac_impl_t *mip) 285 { 286 mac_capab_vnic_t cap; 287 288 VERIFY(i_mac_capab_get((mac_handle_t)mip, MAC_CAPAB_VNIC, &cap)); 289 cap.mcv_mac_secondary_update(cap.mcv_arg); 290 } 291 292 /* 293 * Return the MAC client handle of the primary MAC client for the 294 * specified MAC instance, or NULL otherwise. 295 */ 296 mac_client_impl_t * 297 mac_primary_client_handle(mac_impl_t *mip) 298 { 299 mac_client_impl_t *mcip; 300 301 if (mip->mi_state_flags & MIS_IS_VNIC) 302 return (mac_vnic_lower(mip)); 303 304 ASSERT(MAC_PERIM_HELD((mac_handle_t)mip)); 305 306 for (mcip = mip->mi_clients_list; mcip != NULL; 307 mcip = mcip->mci_client_next) { 308 if (MCIP_DATAPATH_SETUP(mcip) && mac_is_primary_client(mcip)) 309 return (mcip); 310 } 311 return (NULL); 312 } 313 314 /* 315 * Open a MAC specified by its MAC name. 316 */ 317 int 318 mac_open(const char *macname, mac_handle_t *mhp) 319 { 320 mac_impl_t *mip; 321 int err; 322 323 /* 324 * Look up its entry in the global hash table. 325 */ 326 if ((err = mac_hold(macname, &mip)) != 0) 327 return (err); 328 329 /* 330 * Hold the dip associated to the MAC to prevent it from being 331 * detached. For a softmac, its underlying dip is held by the 332 * mi_open() callback. 333 * 334 * This is done to be more tolerant with some defective drivers, 335 * which incorrectly handle mac_unregister() failure in their 336 * xxx_detach() routine. For example, some drivers ignore the 337 * failure of mac_unregister() and free all resources that 338 * that are needed for data transmition. 339 */ 340 e_ddi_hold_devi(mip->mi_dip); 341 342 if (!(mip->mi_callbacks->mc_callbacks & MC_OPEN)) { 343 *mhp = (mac_handle_t)mip; 344 return (0); 345 } 346 347 /* 348 * The mac perimeter is used in both mac_open and mac_close by the 349 * framework to single thread the MC_OPEN/MC_CLOSE of drivers. 350 */ 351 i_mac_perim_enter(mip); 352 mip->mi_oref++; 353 if (mip->mi_oref != 1 || ((err = mip->mi_open(mip->mi_driver)) == 0)) { 354 *mhp = (mac_handle_t)mip; 355 i_mac_perim_exit(mip); 356 return (0); 357 } 358 mip->mi_oref--; 359 ddi_release_devi(mip->mi_dip); 360 mac_rele(mip); 361 i_mac_perim_exit(mip); 362 return (err); 363 } 364 365 /* 366 * Open a MAC specified by its linkid. 367 */ 368 int 369 mac_open_by_linkid(datalink_id_t linkid, mac_handle_t *mhp) 370 { 371 dls_dl_handle_t dlh; 372 int err; 373 374 if ((err = dls_devnet_hold_tmp(linkid, &dlh)) != 0) 375 return (err); 376 377 dls_devnet_prop_task_wait(dlh); 378 379 err = mac_open(dls_devnet_mac(dlh), mhp); 380 381 dls_devnet_rele_tmp(dlh); 382 return (err); 383 } 384 385 /* 386 * Open a MAC specified by its link name. 387 */ 388 int 389 mac_open_by_linkname(const char *link, mac_handle_t *mhp) 390 { 391 datalink_id_t linkid; 392 int err; 393 394 if ((err = dls_mgmt_get_linkid(link, &linkid)) != 0) 395 return (err); 396 return (mac_open_by_linkid(linkid, mhp)); 397 } 398 399 /* 400 * Close the specified MAC. 401 */ 402 void 403 mac_close(mac_handle_t mh) 404 { 405 mac_impl_t *mip = (mac_impl_t *)mh; 406 407 i_mac_perim_enter(mip); 408 /* 409 * The mac perimeter is used in both mac_open and mac_close by the 410 * framework to single thread the MC_OPEN/MC_CLOSE of drivers. 411 */ 412 if (mip->mi_callbacks->mc_callbacks & MC_OPEN) { 413 ASSERT(mip->mi_oref != 0); 414 if (--mip->mi_oref == 0) { 415 if ((mip->mi_callbacks->mc_callbacks & MC_CLOSE)) 416 mip->mi_close(mip->mi_driver); 417 } 418 } 419 i_mac_perim_exit(mip); 420 ddi_release_devi(mip->mi_dip); 421 mac_rele(mip); 422 } 423 424 /* 425 * Misc utility functions to retrieve various information about a MAC 426 * instance or a MAC client. 427 */ 428 429 const mac_info_t * 430 mac_info(mac_handle_t mh) 431 { 432 return (&((mac_impl_t *)mh)->mi_info); 433 } 434 435 dev_info_t * 436 mac_devinfo_get(mac_handle_t mh) 437 { 438 return (((mac_impl_t *)mh)->mi_dip); 439 } 440 441 void * 442 mac_driver(mac_handle_t mh) 443 { 444 return (((mac_impl_t *)mh)->mi_driver); 445 } 446 447 const char * 448 mac_name(mac_handle_t mh) 449 { 450 return (((mac_impl_t *)mh)->mi_name); 451 } 452 453 int 454 mac_type(mac_handle_t mh) 455 { 456 return (((mac_impl_t *)mh)->mi_type->mt_type); 457 } 458 459 int 460 mac_nativetype(mac_handle_t mh) 461 { 462 return (((mac_impl_t *)mh)->mi_type->mt_nativetype); 463 } 464 465 char * 466 mac_client_name(mac_client_handle_t mch) 467 { 468 return (((mac_client_impl_t *)mch)->mci_name); 469 } 470 471 minor_t 472 mac_minor(mac_handle_t mh) 473 { 474 return (((mac_impl_t *)mh)->mi_minor); 475 } 476 477 /* 478 * Return the VID associated with a MAC client. This function should 479 * be called for clients which are associated with only one VID. 480 */ 481 uint16_t 482 mac_client_vid(mac_client_handle_t mch) 483 { 484 uint16_t vid = VLAN_ID_NONE; 485 mac_client_impl_t *mcip = (mac_client_impl_t *)mch; 486 flow_desc_t flow_desc; 487 488 if (mcip->mci_nflents == 0) 489 return (vid); 490 491 ASSERT(MCIP_DATAPATH_SETUP(mcip) && mac_client_single_rcvr(mcip)); 492 493 mac_flow_get_desc(mcip->mci_flent, &flow_desc); 494 if ((flow_desc.fd_mask & FLOW_LINK_VID) != 0) 495 vid = flow_desc.fd_vid; 496 497 return (vid); 498 } 499 500 /* 501 * Return whether the specified MAC client corresponds to a VLAN VNIC. 502 */ 503 boolean_t 504 mac_client_is_vlan_vnic(mac_client_handle_t mch) 505 { 506 mac_client_impl_t *mcip = (mac_client_impl_t *)mch; 507 508 return (((mcip->mci_state_flags & MCIS_IS_VNIC) != 0) && 509 ((mcip->mci_flent->fe_type & FLOW_PRIMARY_MAC) != 0)); 510 } 511 512 /* 513 * Return the link speed associated with the specified MAC client. 514 * 515 * The link speed of a MAC client is equal to the smallest value of 516 * 1) the current link speed of the underlying NIC, or 517 * 2) the bandwidth limit set for the MAC client. 518 * 519 * Note that the bandwidth limit can be higher than the speed 520 * of the underlying NIC. This is allowed to avoid spurious 521 * administration action failures or artifically lowering the 522 * bandwidth limit of a link that may have temporarily lowered 523 * its link speed due to hardware problem or administrator action. 524 */ 525 static uint64_t 526 mac_client_ifspeed(mac_client_impl_t *mcip) 527 { 528 mac_impl_t *mip = mcip->mci_mip; 529 uint64_t nic_speed; 530 531 nic_speed = mac_stat_get((mac_handle_t)mip, MAC_STAT_IFSPEED); 532 533 if (nic_speed == 0) { 534 return (0); 535 } else { 536 uint64_t policy_limit = (uint64_t)-1; 537 538 if (MCIP_RESOURCE_PROPS_MASK(mcip) & MRP_MAXBW) 539 policy_limit = MCIP_RESOURCE_PROPS_MAXBW(mcip); 540 541 return (MIN(policy_limit, nic_speed)); 542 } 543 } 544 545 /* 546 * Return the link state of the specified client. If here are more 547 * than one clients of the underying mac_impl_t, the link state 548 * will always be UP regardless of the link state of the underlying 549 * mac_impl_t. This is needed to allow the MAC clients to continue 550 * to communicate with each other even when the physical link of 551 * their mac_impl_t is down. 552 */ 553 static uint64_t 554 mac_client_link_state(mac_client_impl_t *mcip) 555 { 556 mac_impl_t *mip = mcip->mci_mip; 557 uint16_t vid; 558 mac_client_impl_t *mci_list; 559 mac_unicast_impl_t *mui_list, *oth_mui_list; 560 561 /* 562 * Returns LINK_STATE_UP if there are other MAC clients defined on 563 * mac_impl_t which share same VLAN ID as that of mcip. Note that 564 * if 'mcip' has more than one VID's then we match ANY one of the 565 * VID's with other MAC client's VID's and return LINK_STATE_UP. 566 */ 567 rw_enter(&mcip->mci_rw_lock, RW_READER); 568 for (mui_list = mcip->mci_unicast_list; mui_list != NULL; 569 mui_list = mui_list->mui_next) { 570 vid = mui_list->mui_vid; 571 for (mci_list = mip->mi_clients_list; mci_list != NULL; 572 mci_list = mci_list->mci_client_next) { 573 if (mci_list == mcip) 574 continue; 575 for (oth_mui_list = mci_list->mci_unicast_list; 576 oth_mui_list != NULL; oth_mui_list = oth_mui_list-> 577 mui_next) { 578 if (vid == oth_mui_list->mui_vid) { 579 rw_exit(&mcip->mci_rw_lock); 580 return (LINK_STATE_UP); 581 } 582 } 583 } 584 } 585 rw_exit(&mcip->mci_rw_lock); 586 587 return (mac_stat_get((mac_handle_t)mip, MAC_STAT_LINK_STATE)); 588 } 589 590 /* 591 * These statistics are consumed by dladm show-link -s <vnic>, 592 * dladm show-vnic -s and netstat. With the introduction of dlstat, 593 * dladm show-link -s and dladm show-vnic -s witll be EOL'ed while 594 * netstat will consume from kstats introduced for dlstat. This code 595 * will be removed at that time. 596 */ 597 598 /* 599 * Return the statistics of a MAC client. These statistics are different 600 * then the statistics of the underlying MAC which are returned by 601 * mac_stat_get(). 602 */ 603 uint64_t 604 mac_client_stat_get(mac_client_handle_t mch, uint_t stat) 605 { 606 mac_client_impl_t *mcip = (mac_client_impl_t *)mch; 607 mac_impl_t *mip = mcip->mci_mip; 608 flow_entry_t *flent = mcip->mci_flent; 609 mac_soft_ring_set_t *mac_srs; 610 mac_rx_stats_t *mac_rx_stat; 611 mac_tx_stats_t *mac_tx_stat; 612 int i; 613 uint64_t val = 0; 614 615 mac_srs = (mac_soft_ring_set_t *)(flent->fe_tx_srs); 616 mac_tx_stat = &mac_srs->srs_tx.st_stat; 617 618 switch (stat) { 619 case MAC_STAT_LINK_STATE: 620 val = mac_client_link_state(mcip); 621 break; 622 case MAC_STAT_LINK_UP: 623 val = (mac_client_link_state(mcip) == LINK_STATE_UP); 624 break; 625 case MAC_STAT_PROMISC: 626 val = mac_stat_get((mac_handle_t)mip, MAC_STAT_PROMISC); 627 break; 628 case MAC_STAT_LOWLINK_STATE: 629 val = mac_stat_get((mac_handle_t)mip, MAC_STAT_LOWLINK_STATE); 630 break; 631 case MAC_STAT_IFSPEED: 632 val = mac_client_ifspeed(mcip); 633 break; 634 case MAC_STAT_MULTIRCV: 635 val = mcip->mci_misc_stat.mms_multircv; 636 break; 637 case MAC_STAT_BRDCSTRCV: 638 val = mcip->mci_misc_stat.mms_brdcstrcv; 639 break; 640 case MAC_STAT_MULTIXMT: 641 val = mcip->mci_misc_stat.mms_multixmt; 642 break; 643 case MAC_STAT_BRDCSTXMT: 644 val = mcip->mci_misc_stat.mms_brdcstxmt; 645 break; 646 case MAC_STAT_OBYTES: 647 val = mac_tx_stat->mts_obytes; 648 break; 649 case MAC_STAT_OPACKETS: 650 val = mac_tx_stat->mts_opackets; 651 break; 652 case MAC_STAT_OERRORS: 653 val = mac_tx_stat->mts_oerrors; 654 break; 655 case MAC_STAT_IPACKETS: 656 for (i = 0; i < flent->fe_rx_srs_cnt; i++) { 657 mac_srs = (mac_soft_ring_set_t *)flent->fe_rx_srs[i]; 658 mac_rx_stat = &mac_srs->srs_rx.sr_stat; 659 val += mac_rx_stat->mrs_intrcnt + 660 mac_rx_stat->mrs_pollcnt + mac_rx_stat->mrs_lclcnt; 661 } 662 break; 663 case MAC_STAT_RBYTES: 664 for (i = 0; i < flent->fe_rx_srs_cnt; i++) { 665 mac_srs = (mac_soft_ring_set_t *)flent->fe_rx_srs[i]; 666 mac_rx_stat = &mac_srs->srs_rx.sr_stat; 667 val += mac_rx_stat->mrs_intrbytes + 668 mac_rx_stat->mrs_pollbytes + 669 mac_rx_stat->mrs_lclbytes; 670 } 671 break; 672 case MAC_STAT_IERRORS: 673 for (i = 0; i < flent->fe_rx_srs_cnt; i++) { 674 mac_srs = (mac_soft_ring_set_t *)flent->fe_rx_srs[i]; 675 mac_rx_stat = &mac_srs->srs_rx.sr_stat; 676 val += mac_rx_stat->mrs_ierrors; 677 } 678 break; 679 default: 680 val = mac_driver_stat_default(mip, stat); 681 break; 682 } 683 684 return (val); 685 } 686 687 /* 688 * Return the statistics of the specified MAC instance. 689 */ 690 uint64_t 691 mac_stat_get(mac_handle_t mh, uint_t stat) 692 { 693 mac_impl_t *mip = (mac_impl_t *)mh; 694 uint64_t val; 695 int ret; 696 697 /* 698 * The range of stat determines where it is maintained. Stat 699 * values from 0 up to (but not including) MAC_STAT_MIN are 700 * mainteined by the mac module itself. Everything else is 701 * maintained by the driver. 702 * 703 * If the mac_impl_t being queried corresponds to a VNIC, 704 * the stats need to be queried from the lower MAC client 705 * corresponding to the VNIC. (The mac_link_update() 706 * invoked by the driver to the lower MAC causes the *lower 707 * MAC* to update its mi_linkstate, and send a notification 708 * to its MAC clients. Due to the VNIC passthrough, 709 * these notifications are sent to the upper MAC clients 710 * of the VNIC directly, and the upper mac_impl_t of the VNIC 711 * does not have a valid mi_linkstate. 712 */ 713 if (stat < MAC_STAT_MIN && !(mip->mi_state_flags & MIS_IS_VNIC)) { 714 /* these stats are maintained by the mac module itself */ 715 switch (stat) { 716 case MAC_STAT_LINK_STATE: 717 return (mip->mi_linkstate); 718 case MAC_STAT_LINK_UP: 719 return (mip->mi_linkstate == LINK_STATE_UP); 720 case MAC_STAT_PROMISC: 721 return (mip->mi_devpromisc != 0); 722 case MAC_STAT_LOWLINK_STATE: 723 return (mip->mi_lowlinkstate); 724 default: 725 ASSERT(B_FALSE); 726 } 727 } 728 729 /* 730 * Call the driver to get the given statistic. 731 */ 732 ret = mip->mi_getstat(mip->mi_driver, stat, &val); 733 if (ret != 0) { 734 /* 735 * The driver doesn't support this statistic. Get the 736 * statistic's default value. 737 */ 738 val = mac_driver_stat_default(mip, stat); 739 } 740 return (val); 741 } 742 743 /* 744 * Query hardware rx ring corresponding to the pseudo ring. 745 */ 746 uint64_t 747 mac_pseudo_rx_ring_stat_get(mac_ring_handle_t handle, uint_t stat) 748 { 749 return (mac_rx_ring_stat_get(handle, stat)); 750 } 751 752 /* 753 * Query hardware tx ring corresponding to the pseudo ring. 754 */ 755 uint64_t 756 mac_pseudo_tx_ring_stat_get(mac_ring_handle_t handle, uint_t stat) 757 { 758 return (mac_tx_ring_stat_get(handle, stat)); 759 } 760 761 /* 762 * Utility function which returns the VID associated with a flow entry. 763 */ 764 uint16_t 765 i_mac_flow_vid(flow_entry_t *flent) 766 { 767 flow_desc_t flow_desc; 768 769 mac_flow_get_desc(flent, &flow_desc); 770 771 if ((flow_desc.fd_mask & FLOW_LINK_VID) != 0) 772 return (flow_desc.fd_vid); 773 return (VLAN_ID_NONE); 774 } 775 776 /* 777 * Verify the validity of the specified unicast MAC address. Returns B_TRUE 778 * if the address is valid, B_FALSE otherwise (multicast address, or incorrect 779 * length. 780 */ 781 boolean_t 782 mac_unicst_verify(mac_handle_t mh, const uint8_t *addr, uint_t len) 783 { 784 mac_impl_t *mip = (mac_impl_t *)mh; 785 786 /* 787 * Verify the address. No lock is needed since mi_type and plugin 788 * details don't change after mac_register(). 789 */ 790 if ((len != mip->mi_type->mt_addr_length) || 791 (mip->mi_type->mt_ops.mtops_unicst_verify(addr, 792 mip->mi_pdata)) != 0) { 793 return (B_FALSE); 794 } else { 795 return (B_TRUE); 796 } 797 } 798 799 void 800 mac_sdu_get(mac_handle_t mh, uint_t *min_sdu, uint_t *max_sdu) 801 { 802 mac_impl_t *mip = (mac_impl_t *)mh; 803 804 if (min_sdu != NULL) 805 *min_sdu = mip->mi_sdu_min; 806 if (max_sdu != NULL) 807 *max_sdu = mip->mi_sdu_max; 808 } 809 810 void 811 mac_sdu_get2(mac_handle_t mh, uint_t *min_sdu, uint_t *max_sdu, 812 uint_t *multicast_sdu) 813 { 814 mac_impl_t *mip = (mac_impl_t *)mh; 815 816 if (min_sdu != NULL) 817 *min_sdu = mip->mi_sdu_min; 818 if (max_sdu != NULL) 819 *max_sdu = mip->mi_sdu_max; 820 if (multicast_sdu != NULL) 821 *multicast_sdu = mip->mi_sdu_multicast; 822 } 823 824 /* 825 * Update the MAC unicast address of the specified client's flows. Currently 826 * only one unicast MAC unicast address is allowed per client. 827 */ 828 static void 829 mac_unicast_update_client_flow(mac_client_impl_t *mcip) 830 { 831 mac_impl_t *mip = mcip->mci_mip; 832 flow_entry_t *flent = mcip->mci_flent; 833 mac_address_t *map = mcip->mci_unicast; 834 flow_desc_t flow_desc; 835 836 ASSERT(MAC_PERIM_HELD((mac_handle_t)mip)); 837 ASSERT(flent != NULL); 838 839 mac_flow_get_desc(flent, &flow_desc); 840 ASSERT(flow_desc.fd_mask & FLOW_LINK_DST); 841 842 bcopy(map->ma_addr, flow_desc.fd_dst_mac, map->ma_len); 843 mac_flow_set_desc(flent, &flow_desc); 844 845 /* 846 * The v6 local addr (used by mac protection) needs to be 847 * regenerated because our mac address has changed. 848 */ 849 mac_protect_update_v6_local_addr(mcip); 850 851 /* 852 * A MAC client could have one MAC address but multiple 853 * VLANs. In that case update the flow entries corresponding 854 * to all VLANs of the MAC client. 855 */ 856 for (flent = mcip->mci_flent_list; flent != NULL; 857 flent = flent->fe_client_next) { 858 mac_flow_get_desc(flent, &flow_desc); 859 if (!(flent->fe_type & FLOW_PRIMARY_MAC || 860 flent->fe_type & FLOW_VNIC_MAC)) 861 continue; 862 863 bcopy(map->ma_addr, flow_desc.fd_dst_mac, map->ma_len); 864 mac_flow_set_desc(flent, &flow_desc); 865 } 866 } 867 868 /* 869 * Update all clients that share the same unicast address. 870 */ 871 void 872 mac_unicast_update_clients(mac_impl_t *mip, mac_address_t *map) 873 { 874 mac_client_impl_t *mcip; 875 876 ASSERT(MAC_PERIM_HELD((mac_handle_t)mip)); 877 878 /* 879 * Find all clients that share the same unicast MAC address and update 880 * them appropriately. 881 */ 882 for (mcip = mip->mi_clients_list; mcip != NULL; 883 mcip = mcip->mci_client_next) { 884 /* 885 * Ignore clients that don't share this MAC address. 886 */ 887 if (map != mcip->mci_unicast) 888 continue; 889 890 /* 891 * Update those clients with same old unicast MAC address. 892 */ 893 mac_unicast_update_client_flow(mcip); 894 } 895 } 896 897 /* 898 * Update the unicast MAC address of the specified VNIC MAC client. 899 * 900 * Check whether the operation is valid. Any of following cases should fail: 901 * 902 * 1. It's a VLAN type of VNIC. 903 * 2. The new value is current "primary" MAC address. 904 * 3. The current MAC address is shared with other clients. 905 * 4. The new MAC address has been used. This case will be valid when 906 * client migration is fully supported. 907 */ 908 int 909 mac_vnic_unicast_set(mac_client_handle_t mch, const uint8_t *addr) 910 { 911 mac_client_impl_t *mcip = (mac_client_impl_t *)mch; 912 mac_impl_t *mip = mcip->mci_mip; 913 mac_address_t *map = mcip->mci_unicast; 914 int err; 915 916 ASSERT(!(mip->mi_state_flags & MIS_IS_VNIC)); 917 ASSERT(mcip->mci_state_flags & MCIS_IS_VNIC); 918 ASSERT(mcip->mci_flags != MAC_CLIENT_FLAGS_PRIMARY); 919 920 i_mac_perim_enter(mip); 921 922 /* 923 * If this is a VLAN type of VNIC, it's using "primary" MAC address 924 * of the underlying interface. Must fail here. Refer to case 1 above. 925 */ 926 if (bcmp(map->ma_addr, mip->mi_addr, map->ma_len) == 0) { 927 i_mac_perim_exit(mip); 928 return (ENOTSUP); 929 } 930 931 /* 932 * If the new address is the "primary" one, must fail. Refer to 933 * case 2 above. 934 */ 935 if (bcmp(addr, mip->mi_addr, map->ma_len) == 0) { 936 i_mac_perim_exit(mip); 937 return (EACCES); 938 } 939 940 /* 941 * If the address is shared by multiple clients, must fail. Refer 942 * to case 3 above. 943 */ 944 if (mac_check_macaddr_shared(map)) { 945 i_mac_perim_exit(mip); 946 return (EBUSY); 947 } 948 949 /* 950 * If the new address has been used, must fail for now. Refer to 951 * case 4 above. 952 */ 953 if (mac_find_macaddr(mip, (uint8_t *)addr) != NULL) { 954 i_mac_perim_exit(mip); 955 return (ENOTSUP); 956 } 957 958 /* 959 * Update the MAC address. 960 */ 961 err = mac_update_macaddr(map, (uint8_t *)addr); 962 963 if (err != 0) { 964 i_mac_perim_exit(mip); 965 return (err); 966 } 967 968 /* 969 * Update all flows of this MAC client. 970 */ 971 mac_unicast_update_client_flow(mcip); 972 973 i_mac_perim_exit(mip); 974 return (0); 975 } 976 977 /* 978 * Program the new primary unicast address of the specified MAC. 979 * 980 * Function mac_update_macaddr() takes care different types of underlying 981 * MAC. If the underlying MAC is VNIC, the VNIC driver must have registerd 982 * mi_unicst() entry point, that indirectly calls mac_vnic_unicast_set() 983 * which will take care of updating the MAC address of the corresponding 984 * MAC client. 985 * 986 * This is the only interface that allow the client to update the "primary" 987 * MAC address of the underlying MAC. The new value must have not been 988 * used by other clients. 989 */ 990 int 991 mac_unicast_primary_set(mac_handle_t mh, const uint8_t *addr) 992 { 993 mac_impl_t *mip = (mac_impl_t *)mh; 994 mac_address_t *map; 995 int err; 996 997 /* verify the address validity */ 998 if (!mac_unicst_verify(mh, addr, mip->mi_type->mt_addr_length)) 999 return (EINVAL); 1000 1001 i_mac_perim_enter(mip); 1002 1003 /* 1004 * If the new value is the same as the current primary address value, 1005 * there's nothing to do. 1006 */ 1007 if (bcmp(addr, mip->mi_addr, mip->mi_type->mt_addr_length) == 0) { 1008 i_mac_perim_exit(mip); 1009 return (0); 1010 } 1011 1012 if (mac_find_macaddr(mip, (uint8_t *)addr) != 0) { 1013 i_mac_perim_exit(mip); 1014 return (EBUSY); 1015 } 1016 1017 map = mac_find_macaddr(mip, mip->mi_addr); 1018 ASSERT(map != NULL); 1019 1020 /* 1021 * Update the MAC address. 1022 */ 1023 if (mip->mi_state_flags & MIS_IS_AGGR) { 1024 mac_capab_aggr_t aggr_cap; 1025 1026 /* 1027 * If the mac is an aggregation, other than the unicast 1028 * addresses programming, aggr must be informed about this 1029 * primary unicst address change to change its mac address 1030 * policy to be user-specified. 1031 */ 1032 ASSERT(map->ma_type == MAC_ADDRESS_TYPE_UNICAST_CLASSIFIED); 1033 VERIFY(i_mac_capab_get(mh, MAC_CAPAB_AGGR, &aggr_cap)); 1034 err = aggr_cap.mca_unicst(mip->mi_driver, addr); 1035 if (err == 0) 1036 bcopy(addr, map->ma_addr, map->ma_len); 1037 } else { 1038 err = mac_update_macaddr(map, (uint8_t *)addr); 1039 } 1040 1041 if (err != 0) { 1042 i_mac_perim_exit(mip); 1043 return (err); 1044 } 1045 1046 mac_unicast_update_clients(mip, map); 1047 1048 /* 1049 * Save the new primary MAC address in mac_impl_t. 1050 */ 1051 bcopy(addr, mip->mi_addr, mip->mi_type->mt_addr_length); 1052 1053 i_mac_perim_exit(mip); 1054 1055 if (err == 0) 1056 i_mac_notify(mip, MAC_NOTE_UNICST); 1057 1058 return (err); 1059 } 1060 1061 /* 1062 * Return the current primary MAC address of the specified MAC. 1063 */ 1064 void 1065 mac_unicast_primary_get(mac_handle_t mh, uint8_t *addr) 1066 { 1067 mac_impl_t *mip = (mac_impl_t *)mh; 1068 1069 rw_enter(&mip->mi_rw_lock, RW_READER); 1070 bcopy(mip->mi_addr, addr, mip->mi_type->mt_addr_length); 1071 rw_exit(&mip->mi_rw_lock); 1072 } 1073 1074 /* 1075 * Return the secondary MAC address for the specified handle 1076 */ 1077 void 1078 mac_unicast_secondary_get(mac_client_handle_t mh, uint8_t *addr) 1079 { 1080 mac_client_impl_t *mcip = (mac_client_impl_t *)mh; 1081 1082 ASSERT(mcip->mci_unicast != NULL); 1083 bcopy(mcip->mci_unicast->ma_addr, addr, mcip->mci_unicast->ma_len); 1084 } 1085 1086 /* 1087 * Return information about the use of the primary MAC address of the 1088 * specified MAC instance: 1089 * 1090 * - if client_name is non-NULL, it must point to a string of at 1091 * least MAXNAMELEN bytes, and will be set to the name of the MAC 1092 * client which uses the primary MAC address. 1093 * 1094 * - if in_use is non-NULL, used to return whether the primary MAC 1095 * address is currently in use. 1096 */ 1097 void 1098 mac_unicast_primary_info(mac_handle_t mh, char *client_name, boolean_t *in_use) 1099 { 1100 mac_impl_t *mip = (mac_impl_t *)mh; 1101 mac_client_impl_t *cur_client; 1102 1103 if (in_use != NULL) 1104 *in_use = B_FALSE; 1105 if (client_name != NULL) 1106 bzero(client_name, MAXNAMELEN); 1107 1108 /* 1109 * The mi_rw_lock is used to protect threads that don't hold the 1110 * mac perimeter to get a consistent view of the mi_clients_list. 1111 * Threads that modify the list must hold both the mac perimeter and 1112 * mi_rw_lock(RW_WRITER) 1113 */ 1114 rw_enter(&mip->mi_rw_lock, RW_READER); 1115 for (cur_client = mip->mi_clients_list; cur_client != NULL; 1116 cur_client = cur_client->mci_client_next) { 1117 if (mac_is_primary_client(cur_client) || 1118 (mip->mi_state_flags & MIS_IS_VNIC)) { 1119 rw_exit(&mip->mi_rw_lock); 1120 if (in_use != NULL) 1121 *in_use = B_TRUE; 1122 if (client_name != NULL) { 1123 bcopy(cur_client->mci_name, client_name, 1124 MAXNAMELEN); 1125 } 1126 return; 1127 } 1128 } 1129 rw_exit(&mip->mi_rw_lock); 1130 } 1131 1132 /* 1133 * Return the current destination MAC address of the specified MAC. 1134 */ 1135 boolean_t 1136 mac_dst_get(mac_handle_t mh, uint8_t *addr) 1137 { 1138 mac_impl_t *mip = (mac_impl_t *)mh; 1139 1140 rw_enter(&mip->mi_rw_lock, RW_READER); 1141 if (mip->mi_dstaddr_set) 1142 bcopy(mip->mi_dstaddr, addr, mip->mi_type->mt_addr_length); 1143 rw_exit(&mip->mi_rw_lock); 1144 return (mip->mi_dstaddr_set); 1145 } 1146 1147 /* 1148 * Add the specified MAC client to the list of clients which opened 1149 * the specified MAC. 1150 */ 1151 static void 1152 mac_client_add(mac_client_impl_t *mcip) 1153 { 1154 mac_impl_t *mip = mcip->mci_mip; 1155 1156 ASSERT(MAC_PERIM_HELD((mac_handle_t)mip)); 1157 1158 /* add VNIC to the front of the list */ 1159 rw_enter(&mip->mi_rw_lock, RW_WRITER); 1160 mcip->mci_client_next = mip->mi_clients_list; 1161 mip->mi_clients_list = mcip; 1162 mip->mi_nclients++; 1163 rw_exit(&mip->mi_rw_lock); 1164 } 1165 1166 /* 1167 * Remove the specified MAC client from the list of clients which opened 1168 * the specified MAC. 1169 */ 1170 static void 1171 mac_client_remove(mac_client_impl_t *mcip) 1172 { 1173 mac_impl_t *mip = mcip->mci_mip; 1174 mac_client_impl_t **prev, *cclient; 1175 1176 ASSERT(MAC_PERIM_HELD((mac_handle_t)mip)); 1177 1178 rw_enter(&mip->mi_rw_lock, RW_WRITER); 1179 prev = &mip->mi_clients_list; 1180 cclient = *prev; 1181 while (cclient != NULL && cclient != mcip) { 1182 prev = &cclient->mci_client_next; 1183 cclient = *prev; 1184 } 1185 ASSERT(cclient != NULL); 1186 *prev = cclient->mci_client_next; 1187 mip->mi_nclients--; 1188 rw_exit(&mip->mi_rw_lock); 1189 } 1190 1191 static mac_unicast_impl_t * 1192 mac_client_find_vid(mac_client_impl_t *mcip, uint16_t vid) 1193 { 1194 mac_unicast_impl_t *muip = mcip->mci_unicast_list; 1195 1196 while ((muip != NULL) && (muip->mui_vid != vid)) 1197 muip = muip->mui_next; 1198 1199 return (muip); 1200 } 1201 1202 /* 1203 * Return whether the specified (MAC address, VID) tuple is already used by 1204 * one of the MAC clients associated with the specified MAC. 1205 */ 1206 static boolean_t 1207 mac_addr_in_use(mac_impl_t *mip, uint8_t *mac_addr, uint16_t vid) 1208 { 1209 mac_client_impl_t *client; 1210 mac_address_t *map; 1211 1212 ASSERT(MAC_PERIM_HELD((mac_handle_t)mip)); 1213 1214 for (client = mip->mi_clients_list; client != NULL; 1215 client = client->mci_client_next) { 1216 1217 /* 1218 * Ignore clients that don't have unicast address. 1219 */ 1220 if (client->mci_unicast_list == NULL) 1221 continue; 1222 1223 map = client->mci_unicast; 1224 1225 if ((bcmp(mac_addr, map->ma_addr, map->ma_len) == 0) && 1226 (mac_client_find_vid(client, vid) != NULL)) { 1227 return (B_TRUE); 1228 } 1229 } 1230 1231 return (B_FALSE); 1232 } 1233 1234 /* 1235 * Generate a random MAC address. The MAC address prefix is 1236 * stored in the array pointed to by mac_addr, and its length, in bytes, 1237 * is specified by prefix_len. The least significant bits 1238 * after prefix_len bytes are generated, and stored after the prefix 1239 * in the mac_addr array. 1240 */ 1241 int 1242 mac_addr_random(mac_client_handle_t mch, uint_t prefix_len, 1243 uint8_t *mac_addr, mac_diag_t *diag) 1244 { 1245 mac_client_impl_t *mcip = (mac_client_impl_t *)mch; 1246 mac_impl_t *mip = mcip->mci_mip; 1247 size_t addr_len = mip->mi_type->mt_addr_length; 1248 1249 if (prefix_len >= addr_len) { 1250 *diag = MAC_DIAG_MACPREFIXLEN_INVALID; 1251 return (EINVAL); 1252 } 1253 1254 /* check the prefix value */ 1255 if (prefix_len > 0) { 1256 bzero(mac_addr + prefix_len, addr_len - prefix_len); 1257 if (!mac_unicst_verify((mac_handle_t)mip, mac_addr, 1258 addr_len)) { 1259 *diag = MAC_DIAG_MACPREFIX_INVALID; 1260 return (EINVAL); 1261 } 1262 } 1263 1264 /* generate the MAC address */ 1265 if (prefix_len < addr_len) { 1266 (void) random_get_pseudo_bytes(mac_addr + 1267 prefix_len, addr_len - prefix_len); 1268 } 1269 1270 *diag = 0; 1271 return (0); 1272 } 1273 1274 /* 1275 * Set the priority range for this MAC client. This will be used to 1276 * determine the absolute priority for the threads created for this 1277 * MAC client using the specified "low", "medium" and "high" level. 1278 * This will also be used for any subflows on this MAC client. 1279 */ 1280 #define MAC_CLIENT_SET_PRIORITY_RANGE(mcip, pri) { \ 1281 (mcip)->mci_min_pri = FLOW_MIN_PRIORITY(MINCLSYSPRI, \ 1282 MAXCLSYSPRI, (pri)); \ 1283 (mcip)->mci_max_pri = FLOW_MAX_PRIORITY(MINCLSYSPRI, \ 1284 MAXCLSYSPRI, (mcip)->mci_min_pri); \ 1285 } 1286 1287 /* 1288 * MAC client open entry point. Return a new MAC client handle. Each 1289 * MAC client is associated with a name, specified through the 'name' 1290 * argument. 1291 */ 1292 int 1293 mac_client_open(mac_handle_t mh, mac_client_handle_t *mchp, char *name, 1294 uint16_t flags) 1295 { 1296 mac_impl_t *mip = (mac_impl_t *)mh; 1297 mac_client_impl_t *mcip; 1298 int err = 0; 1299 boolean_t share_desired; 1300 flow_entry_t *flent = NULL; 1301 1302 share_desired = (flags & MAC_OPEN_FLAGS_SHARES_DESIRED) != 0; 1303 *mchp = NULL; 1304 1305 i_mac_perim_enter(mip); 1306 1307 if (mip->mi_state_flags & MIS_IS_VNIC) { 1308 /* 1309 * The underlying MAC is a VNIC. Return the MAC client 1310 * handle of the lower MAC which was obtained by 1311 * the VNIC driver when it did its mac_client_open(). 1312 */ 1313 1314 mcip = mac_vnic_lower(mip); 1315 1316 /* 1317 * Note that multiple mac clients share the same mcip in 1318 * this case. 1319 */ 1320 if (flags & MAC_OPEN_FLAGS_EXCLUSIVE) 1321 mcip->mci_state_flags |= MCIS_EXCLUSIVE; 1322 1323 if (flags & MAC_OPEN_FLAGS_MULTI_PRIMARY) 1324 mcip->mci_flags |= MAC_CLIENT_FLAGS_MULTI_PRIMARY; 1325 1326 mip->mi_clients_list = mcip; 1327 i_mac_perim_exit(mip); 1328 *mchp = (mac_client_handle_t)mcip; 1329 1330 DTRACE_PROBE2(mac__client__open__nonallocated, mac_impl_t *, 1331 mcip->mci_mip, mac_client_impl_t *, mcip); 1332 1333 return (err); 1334 } 1335 1336 mcip = kmem_cache_alloc(mac_client_impl_cache, KM_SLEEP); 1337 1338 mcip->mci_mip = mip; 1339 mcip->mci_upper_mip = NULL; 1340 mcip->mci_rx_fn = mac_pkt_drop; 1341 mcip->mci_rx_arg = NULL; 1342 mcip->mci_rx_p_fn = NULL; 1343 mcip->mci_rx_p_arg = NULL; 1344 mcip->mci_p_unicast_list = NULL; 1345 mcip->mci_direct_rx_fn = NULL; 1346 mcip->mci_direct_rx_arg = NULL; 1347 mcip->mci_vidcache = MCIP_VIDCACHE_INVALID; 1348 1349 mcip->mci_unicast_list = NULL; 1350 1351 if ((flags & MAC_OPEN_FLAGS_IS_VNIC) != 0) 1352 mcip->mci_state_flags |= MCIS_IS_VNIC; 1353 1354 if ((flags & MAC_OPEN_FLAGS_EXCLUSIVE) != 0) 1355 mcip->mci_state_flags |= MCIS_EXCLUSIVE; 1356 1357 if ((flags & MAC_OPEN_FLAGS_IS_AGGR_PORT) != 0) 1358 mcip->mci_state_flags |= MCIS_IS_AGGR_PORT; 1359 1360 if (mip->mi_state_flags & MIS_IS_AGGR) 1361 mcip->mci_state_flags |= MCIS_IS_AGGR; 1362 1363 if ((flags & MAC_OPEN_FLAGS_USE_DATALINK_NAME) != 0) { 1364 datalink_id_t linkid; 1365 1366 ASSERT(name == NULL); 1367 if ((err = dls_devnet_macname2linkid(mip->mi_name, 1368 &linkid)) != 0) { 1369 goto done; 1370 } 1371 if ((err = dls_mgmt_get_linkinfo(linkid, mcip->mci_name, NULL, 1372 NULL, NULL)) != 0) { 1373 /* 1374 * Use mac name if dlmgmtd is not available. 1375 */ 1376 if (err == EBADF) { 1377 (void) strlcpy(mcip->mci_name, mip->mi_name, 1378 sizeof (mcip->mci_name)); 1379 err = 0; 1380 } else { 1381 goto done; 1382 } 1383 } 1384 mcip->mci_state_flags |= MCIS_USE_DATALINK_NAME; 1385 } else { 1386 ASSERT(name != NULL); 1387 if (strlen(name) > MAXNAMELEN) { 1388 err = EINVAL; 1389 goto done; 1390 } 1391 (void) strlcpy(mcip->mci_name, name, sizeof (mcip->mci_name)); 1392 } 1393 1394 if (flags & MAC_OPEN_FLAGS_MULTI_PRIMARY) 1395 mcip->mci_flags |= MAC_CLIENT_FLAGS_MULTI_PRIMARY; 1396 1397 if (flags & MAC_OPEN_FLAGS_NO_UNICAST_ADDR) 1398 mcip->mci_state_flags |= MCIS_NO_UNICAST_ADDR; 1399 1400 mac_protect_init(mcip); 1401 1402 /* the subflow table will be created dynamically */ 1403 mcip->mci_subflow_tab = NULL; 1404 1405 mcip->mci_misc_stat.mms_multircv = 0; 1406 mcip->mci_misc_stat.mms_brdcstrcv = 0; 1407 mcip->mci_misc_stat.mms_multixmt = 0; 1408 mcip->mci_misc_stat.mms_brdcstxmt = 0; 1409 1410 /* Create an initial flow */ 1411 1412 err = mac_flow_create(NULL, NULL, mcip->mci_name, NULL, 1413 mcip->mci_state_flags & MCIS_IS_VNIC ? FLOW_VNIC_MAC : 1414 FLOW_PRIMARY_MAC, &flent); 1415 if (err != 0) 1416 goto done; 1417 mcip->mci_flent = flent; 1418 FLOW_MARK(flent, FE_MC_NO_DATAPATH); 1419 flent->fe_mcip = mcip; 1420 /* 1421 * Place initial creation reference on the flow. This reference 1422 * is released in the corresponding delete action viz. 1423 * mac_unicast_remove after waiting for all transient refs to 1424 * to go away. The wait happens in mac_flow_wait. 1425 */ 1426 FLOW_REFHOLD(flent); 1427 1428 /* 1429 * Do this ahead of the mac_bcast_add() below so that the mi_nclients 1430 * will have the right value for mac_rx_srs_setup(). 1431 */ 1432 mac_client_add(mcip); 1433 1434 mcip->mci_share = NULL; 1435 if (share_desired) 1436 i_mac_share_alloc(mcip); 1437 1438 /* 1439 * We will do mimimal datapath setup to allow a MAC client to 1440 * transmit or receive non-unicast packets without waiting 1441 * for mac_unicast_add. 1442 */ 1443 if (mcip->mci_state_flags & MCIS_NO_UNICAST_ADDR) { 1444 if ((err = mac_client_datapath_setup(mcip, VLAN_ID_NONE, 1445 NULL, NULL, B_TRUE, NULL)) != 0) { 1446 goto done; 1447 } 1448 } 1449 1450 DTRACE_PROBE2(mac__client__open__allocated, mac_impl_t *, 1451 mcip->mci_mip, mac_client_impl_t *, mcip); 1452 1453 *mchp = (mac_client_handle_t)mcip; 1454 i_mac_perim_exit(mip); 1455 return (0); 1456 1457 done: 1458 i_mac_perim_exit(mip); 1459 mcip->mci_state_flags = 0; 1460 mcip->mci_tx_flag = 0; 1461 kmem_cache_free(mac_client_impl_cache, mcip); 1462 return (err); 1463 } 1464 1465 /* 1466 * Close the specified MAC client handle. 1467 */ 1468 void 1469 mac_client_close(mac_client_handle_t mch, uint16_t flags) 1470 { 1471 mac_client_impl_t *mcip = (mac_client_impl_t *)mch; 1472 mac_impl_t *mip = mcip->mci_mip; 1473 flow_entry_t *flent; 1474 1475 i_mac_perim_enter(mip); 1476 1477 if (flags & MAC_CLOSE_FLAGS_EXCLUSIVE) 1478 mcip->mci_state_flags &= ~MCIS_EXCLUSIVE; 1479 1480 if ((mcip->mci_state_flags & MCIS_IS_VNIC) && 1481 !(flags & MAC_CLOSE_FLAGS_IS_VNIC)) { 1482 /* 1483 * This is an upper VNIC client initiated operation. 1484 * The lower MAC client will be closed by the VNIC driver 1485 * when the VNIC is deleted. 1486 */ 1487 1488 i_mac_perim_exit(mip); 1489 return; 1490 } 1491 1492 /* If we have only setup up minimal datapth setup, tear it down */ 1493 if (mcip->mci_state_flags & MCIS_NO_UNICAST_ADDR) { 1494 mac_client_datapath_teardown((mac_client_handle_t)mcip, NULL, 1495 mcip->mci_flent); 1496 mcip->mci_state_flags &= ~MCIS_NO_UNICAST_ADDR; 1497 } 1498 1499 /* 1500 * Remove the flent associated with the MAC client 1501 */ 1502 flent = mcip->mci_flent; 1503 mcip->mci_flent = NULL; 1504 FLOW_FINAL_REFRELE(flent); 1505 1506 /* 1507 * MAC clients must remove the unicast addresses and promisc callbacks 1508 * they added before issuing a mac_client_close(). 1509 */ 1510 ASSERT(mcip->mci_unicast_list == NULL); 1511 ASSERT(mcip->mci_promisc_list == NULL); 1512 ASSERT(mcip->mci_tx_notify_cb_list == NULL); 1513 1514 i_mac_share_free(mcip); 1515 mac_protect_fini(mcip); 1516 mac_client_remove(mcip); 1517 1518 i_mac_perim_exit(mip); 1519 mcip->mci_subflow_tab = NULL; 1520 mcip->mci_state_flags = 0; 1521 mcip->mci_tx_flag = 0; 1522 kmem_cache_free(mac_client_impl_cache, mch); 1523 } 1524 1525 /* 1526 * Set the rx bypass receive callback. 1527 */ 1528 boolean_t 1529 mac_rx_bypass_set(mac_client_handle_t mch, mac_direct_rx_t rx_fn, void *arg1) 1530 { 1531 mac_client_impl_t *mcip = (mac_client_impl_t *)mch; 1532 mac_impl_t *mip = mcip->mci_mip; 1533 1534 ASSERT(MAC_PERIM_HELD((mac_handle_t)mip)); 1535 1536 /* 1537 * If the mac_client is a VLAN, we should not do DLS bypass and 1538 * instead let the packets come up via mac_rx_deliver so the vlan 1539 * header can be stripped. 1540 */ 1541 if (mcip->mci_nvids > 0) 1542 return (B_FALSE); 1543 1544 /* 1545 * These are not accessed directly in the data path, and hence 1546 * don't need any protection 1547 */ 1548 mcip->mci_direct_rx_fn = rx_fn; 1549 mcip->mci_direct_rx_arg = arg1; 1550 return (B_TRUE); 1551 } 1552 1553 /* 1554 * Enable/Disable rx bypass. By default, bypass is assumed to be enabled. 1555 */ 1556 void 1557 mac_rx_bypass_enable(mac_client_handle_t mch) 1558 { 1559 ((mac_client_impl_t *)mch)->mci_state_flags &= ~MCIS_RX_BYPASS_DISABLE; 1560 } 1561 1562 void 1563 mac_rx_bypass_disable(mac_client_handle_t mch) 1564 { 1565 ((mac_client_impl_t *)mch)->mci_state_flags |= MCIS_RX_BYPASS_DISABLE; 1566 } 1567 1568 /* 1569 * Set the receive callback for the specified MAC client. There can be 1570 * at most one such callback per MAC client. 1571 */ 1572 void 1573 mac_rx_set(mac_client_handle_t mch, mac_rx_t rx_fn, void *arg) 1574 { 1575 mac_client_impl_t *mcip = (mac_client_impl_t *)mch; 1576 mac_impl_t *mip = mcip->mci_mip; 1577 mac_impl_t *umip = mcip->mci_upper_mip; 1578 1579 /* 1580 * Instead of adding an extra set of locks and refcnts in 1581 * the datapath at the mac client boundary, we temporarily quiesce 1582 * the SRS and related entities. We then change the receive function 1583 * without interference from any receive data thread and then reenable 1584 * the data flow subsequently. 1585 */ 1586 i_mac_perim_enter(mip); 1587 mac_rx_client_quiesce(mch); 1588 1589 mcip->mci_rx_fn = rx_fn; 1590 mcip->mci_rx_arg = arg; 1591 mac_rx_client_restart(mch); 1592 i_mac_perim_exit(mip); 1593 1594 /* 1595 * If we're changing the rx function on the primary mac of a vnic, 1596 * make sure any secondary macs on the vnic are updated as well. 1597 */ 1598 if (umip != NULL) { 1599 ASSERT((umip->mi_state_flags & MIS_IS_VNIC) != 0); 1600 mac_vnic_secondary_update(umip); 1601 } 1602 } 1603 1604 /* 1605 * Reset the receive callback for the specified MAC client. 1606 */ 1607 void 1608 mac_rx_clear(mac_client_handle_t mch) 1609 { 1610 mac_rx_set(mch, mac_pkt_drop, NULL); 1611 } 1612 1613 void 1614 mac_secondary_dup(mac_client_handle_t smch, mac_client_handle_t dmch) 1615 { 1616 mac_client_impl_t *smcip = (mac_client_impl_t *)smch; 1617 mac_client_impl_t *dmcip = (mac_client_impl_t *)dmch; 1618 flow_entry_t *flent = dmcip->mci_flent; 1619 1620 /* This should only be called to setup secondary macs */ 1621 ASSERT((flent->fe_type & FLOW_PRIMARY_MAC) == 0); 1622 1623 mac_rx_set(dmch, smcip->mci_rx_fn, smcip->mci_rx_arg); 1624 dmcip->mci_promisc_list = smcip->mci_promisc_list; 1625 1626 /* 1627 * Duplicate the primary mac resources to the secondary. 1628 * Since we already validated the resource controls when setting 1629 * them on the primary, we can ignore errors here. 1630 */ 1631 (void) mac_resource_ctl_set(dmch, MCIP_RESOURCE_PROPS(smcip)); 1632 } 1633 1634 /* 1635 * Called when removing a secondary MAC. Currently only clears the promisc_list 1636 * since we share the primary mac's promisc_list. 1637 */ 1638 void 1639 mac_secondary_cleanup(mac_client_handle_t mch) 1640 { 1641 mac_client_impl_t *mcip = (mac_client_impl_t *)mch; 1642 flow_entry_t *flent = mcip->mci_flent; 1643 1644 /* This should only be called for secondary macs */ 1645 ASSERT((flent->fe_type & FLOW_PRIMARY_MAC) == 0); 1646 mcip->mci_promisc_list = NULL; 1647 } 1648 1649 /* 1650 * Walk the MAC client subflow table and updates their priority values. 1651 */ 1652 static int 1653 mac_update_subflow_priority_cb(flow_entry_t *flent, void *arg) 1654 { 1655 mac_flow_update_priority(arg, flent); 1656 return (0); 1657 } 1658 1659 void 1660 mac_update_subflow_priority(mac_client_impl_t *mcip) 1661 { 1662 (void) mac_flow_walk(mcip->mci_subflow_tab, 1663 mac_update_subflow_priority_cb, mcip); 1664 } 1665 1666 /* 1667 * Modify the TX or RX ring properties. We could either just move around 1668 * rings, i.e add/remove rings given to a client. Or this might cause the 1669 * client to move from hardware based to software or the other way around. 1670 * If we want to reset this property, then we clear the mask, additionally 1671 * if the client was given a non-default group we remove all rings except 1672 * for 1 and give it back to the default group. 1673 */ 1674 int 1675 mac_client_set_rings_prop(mac_client_impl_t *mcip, mac_resource_props_t *mrp, 1676 mac_resource_props_t *tmrp) 1677 { 1678 mac_impl_t *mip = mcip->mci_mip; 1679 flow_entry_t *flent = mcip->mci_flent; 1680 uint8_t *mac_addr; 1681 int err = 0; 1682 mac_group_t *defgrp; 1683 mac_group_t *group; 1684 mac_group_t *ngrp; 1685 mac_resource_props_t *cmrp = MCIP_RESOURCE_PROPS(mcip); 1686 uint_t ringcnt; 1687 boolean_t unspec; 1688 1689 if (mcip->mci_share != NULL) 1690 return (EINVAL); 1691 1692 if (mrp->mrp_mask & MRP_RX_RINGS) { 1693 unspec = mrp->mrp_mask & MRP_RXRINGS_UNSPEC; 1694 group = flent->fe_rx_ring_group; 1695 defgrp = MAC_DEFAULT_RX_GROUP(mip); 1696 mac_addr = flent->fe_flow_desc.fd_dst_mac; 1697 1698 /* 1699 * No resulting change. If we are resetting on a client on 1700 * which there was no rx rings property. For dynamic group 1701 * if we are setting the same number of rings already set. 1702 * For static group if we are requesting a group again. 1703 */ 1704 if (mrp->mrp_mask & MRP_RINGS_RESET) { 1705 if (!(tmrp->mrp_mask & MRP_RX_RINGS)) 1706 return (0); 1707 } else { 1708 if (unspec) { 1709 if (tmrp->mrp_mask & MRP_RXRINGS_UNSPEC) 1710 return (0); 1711 } else if (mip->mi_rx_group_type == 1712 MAC_GROUP_TYPE_DYNAMIC) { 1713 if ((tmrp->mrp_mask & MRP_RX_RINGS) && 1714 !(tmrp->mrp_mask & MRP_RXRINGS_UNSPEC) && 1715 mrp->mrp_nrxrings == tmrp->mrp_nrxrings) { 1716 return (0); 1717 } 1718 } 1719 } 1720 /* Resetting the prop */ 1721 if (mrp->mrp_mask & MRP_RINGS_RESET) { 1722 /* 1723 * We will just keep one ring and give others back if 1724 * we are not the primary. For the primary we give 1725 * all the rings in the default group except the 1726 * default ring. If it is a static group, then 1727 * we don't do anything, but clear the MRP_RX_RINGS 1728 * flag. 1729 */ 1730 if (group != defgrp) { 1731 if (mip->mi_rx_group_type == 1732 MAC_GROUP_TYPE_DYNAMIC) { 1733 /* 1734 * This group has reserved rings 1735 * that need to be released now, 1736 * so does the group. 1737 */ 1738 MAC_RX_RING_RELEASED(mip, 1739 group->mrg_cur_count); 1740 MAC_RX_GRP_RELEASED(mip); 1741 if ((flent->fe_type & 1742 FLOW_PRIMARY_MAC) != 0) { 1743 if (mip->mi_nactiveclients == 1744 1) { 1745 (void) 1746 mac_rx_switch_group( 1747 mcip, group, 1748 defgrp); 1749 return (0); 1750 } else { 1751 cmrp->mrp_nrxrings = 1752 group-> 1753 mrg_cur_count + 1754 defgrp-> 1755 mrg_cur_count - 1; 1756 } 1757 } else { 1758 cmrp->mrp_nrxrings = 1; 1759 } 1760 (void) mac_group_ring_modify(mcip, 1761 group, defgrp); 1762 } else { 1763 /* 1764 * If this is a static group, we 1765 * need to release the group. The 1766 * client will remain in the same 1767 * group till some other client 1768 * needs this group. 1769 */ 1770 MAC_RX_GRP_RELEASED(mip); 1771 } 1772 /* Let check if we can give this an excl group */ 1773 } else if (group == defgrp) { 1774 ngrp = mac_reserve_rx_group(mcip, mac_addr, 1775 B_TRUE); 1776 /* Couldn't give it a group, that's fine */ 1777 if (ngrp == NULL) 1778 return (0); 1779 /* Switch to H/W */ 1780 if (mac_rx_switch_group(mcip, defgrp, ngrp) != 1781 0) { 1782 mac_stop_group(ngrp); 1783 return (0); 1784 } 1785 } 1786 /* 1787 * If the client is in the default group, we will 1788 * just clear the MRP_RX_RINGS and leave it as 1789 * it rather than look for an exclusive group 1790 * for it. 1791 */ 1792 return (0); 1793 } 1794 1795 if (group == defgrp && ((mrp->mrp_nrxrings > 0) || unspec)) { 1796 ngrp = mac_reserve_rx_group(mcip, mac_addr, B_TRUE); 1797 if (ngrp == NULL) 1798 return (ENOSPC); 1799 1800 /* Switch to H/W */ 1801 if (mac_rx_switch_group(mcip, defgrp, ngrp) != 0) { 1802 mac_release_rx_group(mcip, ngrp); 1803 return (ENOSPC); 1804 } 1805 MAC_RX_GRP_RESERVED(mip); 1806 if (mip->mi_rx_group_type == MAC_GROUP_TYPE_DYNAMIC) 1807 MAC_RX_RING_RESERVED(mip, ngrp->mrg_cur_count); 1808 } else if (group != defgrp && !unspec && 1809 mrp->mrp_nrxrings == 0) { 1810 /* Switch to S/W */ 1811 ringcnt = group->mrg_cur_count; 1812 if (mac_rx_switch_group(mcip, group, defgrp) != 0) 1813 return (ENOSPC); 1814 if (tmrp->mrp_mask & MRP_RX_RINGS) { 1815 MAC_RX_GRP_RELEASED(mip); 1816 if (mip->mi_rx_group_type == 1817 MAC_GROUP_TYPE_DYNAMIC) { 1818 MAC_RX_RING_RELEASED(mip, ringcnt); 1819 } 1820 } 1821 } else if (group != defgrp && mip->mi_rx_group_type == 1822 MAC_GROUP_TYPE_DYNAMIC) { 1823 ringcnt = group->mrg_cur_count; 1824 err = mac_group_ring_modify(mcip, group, defgrp); 1825 if (err != 0) 1826 return (err); 1827 /* 1828 * Update the accounting. If this group 1829 * already had explicitly reserved rings, 1830 * we need to update the rings based on 1831 * the new ring count. If this group 1832 * had not explicitly reserved rings, 1833 * then we just reserve the rings asked for 1834 * and reserve the group. 1835 */ 1836 if (tmrp->mrp_mask & MRP_RX_RINGS) { 1837 if (ringcnt > group->mrg_cur_count) { 1838 MAC_RX_RING_RELEASED(mip, 1839 ringcnt - group->mrg_cur_count); 1840 } else { 1841 MAC_RX_RING_RESERVED(mip, 1842 group->mrg_cur_count - ringcnt); 1843 } 1844 } else { 1845 MAC_RX_RING_RESERVED(mip, group->mrg_cur_count); 1846 MAC_RX_GRP_RESERVED(mip); 1847 } 1848 } 1849 } 1850 if (mrp->mrp_mask & MRP_TX_RINGS) { 1851 unspec = mrp->mrp_mask & MRP_TXRINGS_UNSPEC; 1852 group = flent->fe_tx_ring_group; 1853 defgrp = MAC_DEFAULT_TX_GROUP(mip); 1854 1855 /* 1856 * For static groups we only allow rings=0 or resetting the 1857 * rings property. 1858 */ 1859 if (mrp->mrp_ntxrings > 0 && 1860 mip->mi_tx_group_type != MAC_GROUP_TYPE_DYNAMIC) { 1861 return (ENOTSUP); 1862 } 1863 if (mrp->mrp_mask & MRP_RINGS_RESET) { 1864 if (!(tmrp->mrp_mask & MRP_TX_RINGS)) 1865 return (0); 1866 } else { 1867 if (unspec) { 1868 if (tmrp->mrp_mask & MRP_TXRINGS_UNSPEC) 1869 return (0); 1870 } else if (mip->mi_tx_group_type == 1871 MAC_GROUP_TYPE_DYNAMIC) { 1872 if ((tmrp->mrp_mask & MRP_TX_RINGS) && 1873 !(tmrp->mrp_mask & MRP_TXRINGS_UNSPEC) && 1874 mrp->mrp_ntxrings == tmrp->mrp_ntxrings) { 1875 return (0); 1876 } 1877 } 1878 } 1879 /* Resetting the prop */ 1880 if (mrp->mrp_mask & MRP_RINGS_RESET) { 1881 if (group != defgrp) { 1882 if (mip->mi_tx_group_type == 1883 MAC_GROUP_TYPE_DYNAMIC) { 1884 ringcnt = group->mrg_cur_count; 1885 if ((flent->fe_type & 1886 FLOW_PRIMARY_MAC) != 0) { 1887 mac_tx_client_quiesce( 1888 (mac_client_handle_t) 1889 mcip); 1890 mac_tx_switch_group(mcip, 1891 group, defgrp); 1892 mac_tx_client_restart( 1893 (mac_client_handle_t) 1894 mcip); 1895 MAC_TX_GRP_RELEASED(mip); 1896 MAC_TX_RING_RELEASED(mip, 1897 ringcnt); 1898 return (0); 1899 } 1900 cmrp->mrp_ntxrings = 1; 1901 (void) mac_group_ring_modify(mcip, 1902 group, defgrp); 1903 /* 1904 * This group has reserved rings 1905 * that need to be released now. 1906 */ 1907 MAC_TX_RING_RELEASED(mip, ringcnt); 1908 } 1909 /* 1910 * If this is a static group, we 1911 * need to release the group. The 1912 * client will remain in the same 1913 * group till some other client 1914 * needs this group. 1915 */ 1916 MAC_TX_GRP_RELEASED(mip); 1917 } else if (group == defgrp && 1918 (flent->fe_type & FLOW_PRIMARY_MAC) == 0) { 1919 ngrp = mac_reserve_tx_group(mcip, B_TRUE); 1920 if (ngrp == NULL) 1921 return (0); 1922 mac_tx_client_quiesce( 1923 (mac_client_handle_t)mcip); 1924 mac_tx_switch_group(mcip, defgrp, ngrp); 1925 mac_tx_client_restart( 1926 (mac_client_handle_t)mcip); 1927 } 1928 /* 1929 * If the client is in the default group, we will 1930 * just clear the MRP_TX_RINGS and leave it as 1931 * it rather than look for an exclusive group 1932 * for it. 1933 */ 1934 return (0); 1935 } 1936 1937 /* Switch to H/W */ 1938 if (group == defgrp && ((mrp->mrp_ntxrings > 0) || unspec)) { 1939 ngrp = mac_reserve_tx_group(mcip, B_TRUE); 1940 if (ngrp == NULL) 1941 return (ENOSPC); 1942 mac_tx_client_quiesce((mac_client_handle_t)mcip); 1943 mac_tx_switch_group(mcip, defgrp, ngrp); 1944 mac_tx_client_restart((mac_client_handle_t)mcip); 1945 MAC_TX_GRP_RESERVED(mip); 1946 if (mip->mi_tx_group_type == MAC_GROUP_TYPE_DYNAMIC) 1947 MAC_TX_RING_RESERVED(mip, ngrp->mrg_cur_count); 1948 /* Switch to S/W */ 1949 } else if (group != defgrp && !unspec && 1950 mrp->mrp_ntxrings == 0) { 1951 /* Switch to S/W */ 1952 ringcnt = group->mrg_cur_count; 1953 mac_tx_client_quiesce((mac_client_handle_t)mcip); 1954 mac_tx_switch_group(mcip, group, defgrp); 1955 mac_tx_client_restart((mac_client_handle_t)mcip); 1956 if (tmrp->mrp_mask & MRP_TX_RINGS) { 1957 MAC_TX_GRP_RELEASED(mip); 1958 if (mip->mi_tx_group_type == 1959 MAC_GROUP_TYPE_DYNAMIC) { 1960 MAC_TX_RING_RELEASED(mip, ringcnt); 1961 } 1962 } 1963 } else if (group != defgrp && mip->mi_tx_group_type == 1964 MAC_GROUP_TYPE_DYNAMIC) { 1965 ringcnt = group->mrg_cur_count; 1966 err = mac_group_ring_modify(mcip, group, defgrp); 1967 if (err != 0) 1968 return (err); 1969 /* 1970 * Update the accounting. If this group 1971 * already had explicitly reserved rings, 1972 * we need to update the rings based on 1973 * the new ring count. If this group 1974 * had not explicitly reserved rings, 1975 * then we just reserve the rings asked for 1976 * and reserve the group. 1977 */ 1978 if (tmrp->mrp_mask & MRP_TX_RINGS) { 1979 if (ringcnt > group->mrg_cur_count) { 1980 MAC_TX_RING_RELEASED(mip, 1981 ringcnt - group->mrg_cur_count); 1982 } else { 1983 MAC_TX_RING_RESERVED(mip, 1984 group->mrg_cur_count - ringcnt); 1985 } 1986 } else { 1987 MAC_TX_RING_RESERVED(mip, group->mrg_cur_count); 1988 MAC_TX_GRP_RESERVED(mip); 1989 } 1990 } 1991 } 1992 return (0); 1993 } 1994 1995 /* 1996 * When the MAC client is being brought up (i.e. we do a unicast_add) we need 1997 * to initialize the cpu and resource control structure in the 1998 * mac_client_impl_t from the mac_impl_t (i.e if there are any cached 1999 * properties before the flow entry for the unicast address was created). 2000 */ 2001 static int 2002 mac_resource_ctl_set(mac_client_handle_t mch, mac_resource_props_t *mrp) 2003 { 2004 mac_client_impl_t *mcip = (mac_client_impl_t *)mch; 2005 mac_impl_t *mip = (mac_impl_t *)mcip->mci_mip; 2006 mac_impl_t *umip = mcip->mci_upper_mip; 2007 int err = 0; 2008 flow_entry_t *flent = mcip->mci_flent; 2009 mac_resource_props_t *omrp, *nmrp = MCIP_RESOURCE_PROPS(mcip); 2010 2011 ASSERT(MAC_PERIM_HELD((mac_handle_t)mip)); 2012 2013 err = mac_validate_props(mcip->mci_state_flags & MCIS_IS_VNIC ? 2014 mcip->mci_upper_mip : mip, mrp); 2015 if (err != 0) 2016 return (err); 2017 2018 /* 2019 * Copy over the existing properties since mac_update_resources 2020 * will modify the client's mrp. Currently, the saved property 2021 * is used to determine the difference between existing and 2022 * modified rings property. 2023 */ 2024 omrp = kmem_zalloc(sizeof (*omrp), KM_SLEEP); 2025 bcopy(nmrp, omrp, sizeof (*omrp)); 2026 mac_update_resources(mrp, MCIP_RESOURCE_PROPS(mcip), B_FALSE); 2027 if (MCIP_DATAPATH_SETUP(mcip)) { 2028 /* 2029 * We support rings only for primary client when there are 2030 * multiple clients sharing the same MAC address (e.g. VLAN). 2031 */ 2032 if (mrp->mrp_mask & MRP_RX_RINGS || 2033 mrp->mrp_mask & MRP_TX_RINGS) { 2034 2035 if ((err = mac_client_set_rings_prop(mcip, mrp, 2036 omrp)) != 0) { 2037 if (omrp->mrp_mask & MRP_RX_RINGS) { 2038 nmrp->mrp_mask |= MRP_RX_RINGS; 2039 nmrp->mrp_nrxrings = omrp->mrp_nrxrings; 2040 } else { 2041 nmrp->mrp_mask &= ~MRP_RX_RINGS; 2042 nmrp->mrp_nrxrings = 0; 2043 } 2044 if (omrp->mrp_mask & MRP_TX_RINGS) { 2045 nmrp->mrp_mask |= MRP_TX_RINGS; 2046 nmrp->mrp_ntxrings = omrp->mrp_ntxrings; 2047 } else { 2048 nmrp->mrp_mask &= ~MRP_TX_RINGS; 2049 nmrp->mrp_ntxrings = 0; 2050 } 2051 if (omrp->mrp_mask & MRP_RXRINGS_UNSPEC) 2052 omrp->mrp_mask |= MRP_RXRINGS_UNSPEC; 2053 else 2054 omrp->mrp_mask &= ~MRP_RXRINGS_UNSPEC; 2055 2056 if (omrp->mrp_mask & MRP_TXRINGS_UNSPEC) 2057 omrp->mrp_mask |= MRP_TXRINGS_UNSPEC; 2058 else 2059 omrp->mrp_mask &= ~MRP_TXRINGS_UNSPEC; 2060 kmem_free(omrp, sizeof (*omrp)); 2061 return (err); 2062 } 2063 2064 /* 2065 * If we modified the rings property of the primary 2066 * we need to update the property fields of its 2067 * VLANs as they inherit the primary's properites. 2068 */ 2069 if (mac_is_primary_client(mcip)) { 2070 mac_set_prim_vlan_rings(mip, 2071 MCIP_RESOURCE_PROPS(mcip)); 2072 } 2073 } 2074 /* 2075 * We have to set this prior to calling mac_flow_modify. 2076 */ 2077 if (mrp->mrp_mask & MRP_PRIORITY) { 2078 if (mrp->mrp_priority == MPL_RESET) { 2079 MAC_CLIENT_SET_PRIORITY_RANGE(mcip, 2080 MPL_LINK_DEFAULT); 2081 } else { 2082 MAC_CLIENT_SET_PRIORITY_RANGE(mcip, 2083 mrp->mrp_priority); 2084 } 2085 } 2086 2087 mac_flow_modify(mip->mi_flow_tab, flent, mrp); 2088 if (mrp->mrp_mask & MRP_PRIORITY) 2089 mac_update_subflow_priority(mcip); 2090 2091 /* Apply these resource settings to any secondary macs */ 2092 if (umip != NULL) { 2093 ASSERT((umip->mi_state_flags & MIS_IS_VNIC) != 0); 2094 mac_vnic_secondary_update(umip); 2095 } 2096 } 2097 kmem_free(omrp, sizeof (*omrp)); 2098 return (0); 2099 } 2100 2101 static int 2102 mac_unicast_flow_create(mac_client_impl_t *mcip, uint8_t *mac_addr, 2103 uint16_t vid, boolean_t is_primary, boolean_t first_flow, 2104 flow_entry_t **flent, mac_resource_props_t *mrp) 2105 { 2106 mac_impl_t *mip = (mac_impl_t *)mcip->mci_mip; 2107 flow_desc_t flow_desc; 2108 char flowname[MAXFLOWNAMELEN]; 2109 int err; 2110 uint_t flent_flags; 2111 2112 /* 2113 * First unicast address being added, create a new flow 2114 * for that MAC client. 2115 */ 2116 bzero(&flow_desc, sizeof (flow_desc)); 2117 2118 ASSERT(mac_addr != NULL || 2119 (mcip->mci_state_flags & MCIS_NO_UNICAST_ADDR)); 2120 if (mac_addr != NULL) { 2121 flow_desc.fd_mac_len = mip->mi_type->mt_addr_length; 2122 bcopy(mac_addr, flow_desc.fd_dst_mac, flow_desc.fd_mac_len); 2123 } 2124 flow_desc.fd_mask = FLOW_LINK_DST; 2125 if (vid != 0) { 2126 flow_desc.fd_vid = vid; 2127 flow_desc.fd_mask |= FLOW_LINK_VID; 2128 } 2129 2130 /* 2131 * XXX-nicolas. For now I'm keeping the FLOW_PRIMARY_MAC 2132 * and FLOW_VNIC. Even though they're a hack inherited 2133 * from the SRS code, we'll keep them for now. They're currently 2134 * consumed by mac_datapath_setup() to create the SRS. 2135 * That code should be eventually moved out of 2136 * mac_datapath_setup() and moved to a mac_srs_create() 2137 * function of some sort to keep things clean. 2138 * 2139 * Also, there's no reason why the SRS for the primary MAC 2140 * client should be different than any other MAC client. Until 2141 * this is cleaned-up, we support only one MAC unicast address 2142 * per client. 2143 * 2144 * We set FLOW_PRIMARY_MAC for the primary MAC address, 2145 * FLOW_VNIC for everything else. 2146 */ 2147 if (is_primary) 2148 flent_flags = FLOW_PRIMARY_MAC; 2149 else 2150 flent_flags = FLOW_VNIC_MAC; 2151 2152 /* 2153 * For the first flow we use the mac client's name - mci_name, for 2154 * subsequent ones we just create a name with the vid. This is 2155 * so that we can add these flows to the same flow table. This is 2156 * fine as the flow name (except for the one with the mac client's 2157 * name) is not visible. When the first flow is removed, we just replace 2158 * its fdesc with another from the list, so we will still retain the 2159 * flent with the MAC client's flow name. 2160 */ 2161 if (first_flow) { 2162 bcopy(mcip->mci_name, flowname, MAXFLOWNAMELEN); 2163 } else { 2164 (void) sprintf(flowname, "%s%u", mcip->mci_name, vid); 2165 flent_flags = FLOW_NO_STATS; 2166 } 2167 2168 if ((err = mac_flow_create(&flow_desc, mrp, flowname, NULL, 2169 flent_flags, flent)) != 0) 2170 return (err); 2171 2172 mac_misc_stat_create(*flent); 2173 FLOW_MARK(*flent, FE_INCIPIENT); 2174 (*flent)->fe_mcip = mcip; 2175 2176 /* 2177 * Place initial creation reference on the flow. This reference 2178 * is released in the corresponding delete action viz. 2179 * mac_unicast_remove after waiting for all transient refs to 2180 * to go away. The wait happens in mac_flow_wait. 2181 * We have already held the reference in mac_client_open(). 2182 */ 2183 if (!first_flow) 2184 FLOW_REFHOLD(*flent); 2185 return (0); 2186 } 2187 2188 /* Refresh the multicast grouping for this VID. */ 2189 int 2190 mac_client_update_mcast(void *arg, boolean_t add, const uint8_t *addrp) 2191 { 2192 flow_entry_t *flent = arg; 2193 mac_client_impl_t *mcip = flent->fe_mcip; 2194 uint16_t vid; 2195 flow_desc_t flow_desc; 2196 2197 mac_flow_get_desc(flent, &flow_desc); 2198 vid = (flow_desc.fd_mask & FLOW_LINK_VID) != 0 ? 2199 flow_desc.fd_vid : VLAN_ID_NONE; 2200 2201 /* 2202 * We don't call mac_multicast_add()/mac_multicast_remove() as 2203 * we want to add/remove for this specific vid. 2204 */ 2205 if (add) { 2206 return (mac_bcast_add(mcip, addrp, vid, 2207 MAC_ADDRTYPE_MULTICAST)); 2208 } else { 2209 mac_bcast_delete(mcip, addrp, vid); 2210 return (0); 2211 } 2212 } 2213 2214 static void 2215 mac_update_single_active_client(mac_impl_t *mip) 2216 { 2217 mac_client_impl_t *client = NULL; 2218 2219 ASSERT(MAC_PERIM_HELD((mac_handle_t)mip)); 2220 2221 rw_enter(&mip->mi_rw_lock, RW_WRITER); 2222 if (mip->mi_nactiveclients == 1) { 2223 /* 2224 * Find the one active MAC client from the list of MAC 2225 * clients. The active MAC client has at least one 2226 * unicast address. 2227 */ 2228 for (client = mip->mi_clients_list; client != NULL; 2229 client = client->mci_client_next) { 2230 if (client->mci_unicast_list != NULL) 2231 break; 2232 } 2233 ASSERT(client != NULL); 2234 } 2235 2236 /* 2237 * mi_single_active_client is protected by the MAC impl's read/writer 2238 * lock, which allows mac_rx() to check the value of that pointer 2239 * as a reader. 2240 */ 2241 mip->mi_single_active_client = client; 2242 rw_exit(&mip->mi_rw_lock); 2243 } 2244 2245 /* 2246 * Set up the data path. Called from i_mac_unicast_add after having 2247 * done all the validations including making sure this is an active 2248 * client (i.e that is ready to process packets.) 2249 */ 2250 static int 2251 mac_client_datapath_setup(mac_client_impl_t *mcip, uint16_t vid, 2252 uint8_t *mac_addr, mac_resource_props_t *mrp, boolean_t isprimary, 2253 mac_unicast_impl_t *muip) 2254 { 2255 mac_impl_t *mip = mcip->mci_mip; 2256 boolean_t mac_started = B_FALSE; 2257 boolean_t bcast_added = B_FALSE; 2258 boolean_t nactiveclients_added = B_FALSE; 2259 flow_entry_t *flent; 2260 int err = 0; 2261 boolean_t no_unicast; 2262 2263 no_unicast = mcip->mci_state_flags & MCIS_NO_UNICAST_ADDR; 2264 2265 if ((err = mac_start((mac_handle_t)mip)) != 0) 2266 goto bail; 2267 2268 mac_started = B_TRUE; 2269 2270 /* add the MAC client to the broadcast address group by default */ 2271 if (mip->mi_type->mt_brdcst_addr != NULL) { 2272 err = mac_bcast_add(mcip, mip->mi_type->mt_brdcst_addr, vid, 2273 MAC_ADDRTYPE_BROADCAST); 2274 if (err != 0) 2275 goto bail; 2276 bcast_added = B_TRUE; 2277 } 2278 2279 /* 2280 * If this is the first unicast address addition for this 2281 * client, reuse the pre-allocated larval flow entry associated with 2282 * the MAC client. 2283 */ 2284 flent = (mcip->mci_nflents == 0) ? mcip->mci_flent : NULL; 2285 2286 /* We are configuring the unicast flow now */ 2287 if (!MCIP_DATAPATH_SETUP(mcip)) { 2288 2289 if (mrp != NULL) { 2290 MAC_CLIENT_SET_PRIORITY_RANGE(mcip, 2291 (mrp->mrp_mask & MRP_PRIORITY) ? mrp->mrp_priority : 2292 MPL_LINK_DEFAULT); 2293 } 2294 if ((err = mac_unicast_flow_create(mcip, mac_addr, vid, 2295 isprimary, B_TRUE, &flent, mrp)) != 0) 2296 goto bail; 2297 2298 mip->mi_nactiveclients++; 2299 nactiveclients_added = B_TRUE; 2300 2301 /* 2302 * This will allocate the RX ring group if possible for the 2303 * flow and program the software classifier as needed. 2304 */ 2305 if ((err = mac_datapath_setup(mcip, flent, SRST_LINK)) != 0) 2306 goto bail; 2307 2308 if (no_unicast) 2309 goto done_setup; 2310 /* 2311 * The unicast MAC address must have been added successfully. 2312 */ 2313 ASSERT(mcip->mci_unicast != NULL); 2314 /* 2315 * Push down the sub-flows that were defined on this link 2316 * hitherto. The flows are added to the active flow table 2317 * and SRS, softrings etc. are created as needed. 2318 */ 2319 mac_link_init_flows((mac_client_handle_t)mcip); 2320 } else { 2321 mac_address_t *map = mcip->mci_unicast; 2322 2323 ASSERT(!no_unicast); 2324 /* 2325 * A unicast flow already exists for that MAC client, 2326 * this flow must be the same mac address but with 2327 * different VID. It has been checked by mac_addr_in_use(). 2328 * 2329 * We will use the SRS etc. from the mci_flent. Note that 2330 * We don't need to create kstat for this as except for 2331 * the fdesc, everything will be used from in the 1st flent. 2332 */ 2333 2334 if (bcmp(mac_addr, map->ma_addr, map->ma_len) != 0) { 2335 err = EINVAL; 2336 goto bail; 2337 } 2338 2339 if ((err = mac_unicast_flow_create(mcip, mac_addr, vid, 2340 isprimary, B_FALSE, &flent, NULL)) != 0) { 2341 goto bail; 2342 } 2343 if ((err = mac_flow_add(mip->mi_flow_tab, flent)) != 0) { 2344 FLOW_FINAL_REFRELE(flent); 2345 goto bail; 2346 } 2347 2348 /* update the multicast group for this vid */ 2349 mac_client_bcast_refresh(mcip, mac_client_update_mcast, 2350 (void *)flent, B_TRUE); 2351 2352 } 2353 2354 /* populate the shared MAC address */ 2355 muip->mui_map = mcip->mci_unicast; 2356 2357 rw_enter(&mcip->mci_rw_lock, RW_WRITER); 2358 muip->mui_next = mcip->mci_unicast_list; 2359 mcip->mci_unicast_list = muip; 2360 rw_exit(&mcip->mci_rw_lock); 2361 2362 done_setup: 2363 /* 2364 * First add the flent to the flow list of this mcip. Then set 2365 * the mip's mi_single_active_client if needed. The Rx path assumes 2366 * that mip->mi_single_active_client will always have an associated 2367 * flent. 2368 */ 2369 mac_client_add_to_flow_list(mcip, flent); 2370 if (nactiveclients_added) 2371 mac_update_single_active_client(mip); 2372 /* 2373 * Trigger a renegotiation of the capabilities when the number of 2374 * active clients changes from 1 to 2, since some of the capabilities 2375 * might have to be disabled. Also send a MAC_NOTE_LINK notification 2376 * to all the MAC clients whenever physical link is DOWN. 2377 */ 2378 if (mip->mi_nactiveclients == 2) { 2379 mac_capab_update((mac_handle_t)mip); 2380 mac_virtual_link_update(mip); 2381 } 2382 /* 2383 * Now that the setup is complete, clear the INCIPIENT flag. 2384 * The flag was set to avoid incoming packets seeing inconsistent 2385 * structures while the setup was in progress. Clear the mci_tx_flag 2386 * by calling mac_tx_client_block. It is possible that 2387 * mac_unicast_remove was called prior to this mac_unicast_add which 2388 * could have set the MCI_TX_QUIESCE flag. 2389 */ 2390 if (flent->fe_rx_ring_group != NULL) 2391 mac_rx_group_unmark(flent->fe_rx_ring_group, MR_INCIPIENT); 2392 FLOW_UNMARK(flent, FE_INCIPIENT); 2393 FLOW_UNMARK(flent, FE_MC_NO_DATAPATH); 2394 mac_tx_client_unblock(mcip); 2395 return (0); 2396 bail: 2397 if (bcast_added) 2398 mac_bcast_delete(mcip, mip->mi_type->mt_brdcst_addr, vid); 2399 2400 if (nactiveclients_added) 2401 mip->mi_nactiveclients--; 2402 2403 if (mac_started) 2404 mac_stop((mac_handle_t)mip); 2405 2406 return (err); 2407 } 2408 2409 /* 2410 * Return the passive primary MAC client, if present. The passive client is 2411 * a stand-by client that has the same unicast address as another that is 2412 * currenly active. Once the active client goes away, the passive client 2413 * becomes active. 2414 */ 2415 static mac_client_impl_t * 2416 mac_get_passive_primary_client(mac_impl_t *mip) 2417 { 2418 mac_client_impl_t *mcip; 2419 2420 for (mcip = mip->mi_clients_list; mcip != NULL; 2421 mcip = mcip->mci_client_next) { 2422 if (mac_is_primary_client(mcip) && 2423 (mcip->mci_flags & MAC_CLIENT_FLAGS_PASSIVE_PRIMARY) != 0) { 2424 return (mcip); 2425 } 2426 } 2427 return (NULL); 2428 } 2429 2430 /* 2431 * Add a new unicast address to the MAC client. 2432 * 2433 * The MAC address can be specified either by value, or the MAC client 2434 * can specify that it wants to use the primary MAC address of the 2435 * underlying MAC. See the introductory comments at the beginning 2436 * of this file for more more information on primary MAC addresses. 2437 * 2438 * Note also the tuple (MAC address, VID) must be unique 2439 * for the MAC clients defined on top of the same underlying MAC 2440 * instance, unless the MAC_UNICAST_NODUPCHECK is specified. 2441 * 2442 * In no case can a client use the PVID for the MAC, if the MAC has one set. 2443 */ 2444 int 2445 i_mac_unicast_add(mac_client_handle_t mch, uint8_t *mac_addr, uint16_t flags, 2446 mac_unicast_handle_t *mah, uint16_t vid, mac_diag_t *diag) 2447 { 2448 mac_client_impl_t *mcip = (mac_client_impl_t *)mch; 2449 mac_impl_t *mip = mcip->mci_mip; 2450 int err; 2451 uint_t mac_len = mip->mi_type->mt_addr_length; 2452 boolean_t check_dups = !(flags & MAC_UNICAST_NODUPCHECK); 2453 boolean_t fastpath_disabled = B_FALSE; 2454 boolean_t is_primary = (flags & MAC_UNICAST_PRIMARY); 2455 boolean_t is_unicast_hw = (flags & MAC_UNICAST_HW); 2456 mac_resource_props_t *mrp; 2457 boolean_t passive_client = B_FALSE; 2458 mac_unicast_impl_t *muip; 2459 boolean_t is_vnic_primary = 2460 (flags & MAC_UNICAST_VNIC_PRIMARY); 2461 2462 /* when VID is non-zero, the underlying MAC can not be VNIC */ 2463 ASSERT(!((mip->mi_state_flags & MIS_IS_VNIC) && (vid != 0))); 2464 2465 /* 2466 * Can't unicast add if the client asked only for minimal datapath 2467 * setup. 2468 */ 2469 if (mcip->mci_state_flags & MCIS_NO_UNICAST_ADDR) 2470 return (ENOTSUP); 2471 2472 /* 2473 * Check for an attempted use of the current Port VLAN ID, if enabled. 2474 * No client may use it. 2475 */ 2476 if (mip->mi_pvid != 0 && vid == mip->mi_pvid) 2477 return (EBUSY); 2478 2479 /* 2480 * Check whether it's the primary client and flag it. 2481 */ 2482 if (!(mcip->mci_state_flags & MCIS_IS_VNIC) && is_primary && vid == 0) 2483 mcip->mci_flags |= MAC_CLIENT_FLAGS_PRIMARY; 2484 2485 /* 2486 * is_vnic_primary is true when we come here as a VLAN VNIC 2487 * which uses the primary mac client's address but with a non-zero 2488 * VID. In this case the MAC address is not specified by an upper 2489 * MAC client. 2490 */ 2491 if ((mcip->mci_state_flags & MCIS_IS_VNIC) && is_primary && 2492 !is_vnic_primary) { 2493 /* 2494 * The address is being set by the upper MAC client 2495 * of a VNIC. The MAC address was already set by the 2496 * VNIC driver during VNIC creation. 2497 * 2498 * Note: a VNIC has only one MAC address. We return 2499 * the MAC unicast address handle of the lower MAC client 2500 * corresponding to the VNIC. We allocate a new entry 2501 * which is flagged appropriately, so that mac_unicast_remove() 2502 * doesn't attempt to free the original entry that 2503 * was allocated by the VNIC driver. 2504 */ 2505 ASSERT(mcip->mci_unicast != NULL); 2506 2507 /* Check for VLAN flags, if present */ 2508 if ((flags & MAC_UNICAST_TAG_DISABLE) != 0) 2509 mcip->mci_state_flags |= MCIS_TAG_DISABLE; 2510 2511 if ((flags & MAC_UNICAST_STRIP_DISABLE) != 0) 2512 mcip->mci_state_flags |= MCIS_STRIP_DISABLE; 2513 2514 if ((flags & MAC_UNICAST_DISABLE_TX_VID_CHECK) != 0) 2515 mcip->mci_state_flags |= MCIS_DISABLE_TX_VID_CHECK; 2516 2517 /* 2518 * Ensure that the primary unicast address of the VNIC 2519 * is added only once unless we have the 2520 * MAC_CLIENT_FLAGS_MULTI_PRIMARY set (and this is not 2521 * a passive MAC client). 2522 */ 2523 if ((mcip->mci_flags & MAC_CLIENT_FLAGS_VNIC_PRIMARY) != 0) { 2524 if ((mcip->mci_flags & 2525 MAC_CLIENT_FLAGS_MULTI_PRIMARY) == 0 || 2526 (mcip->mci_flags & 2527 MAC_CLIENT_FLAGS_PASSIVE_PRIMARY) != 0) { 2528 return (EBUSY); 2529 } 2530 mcip->mci_flags |= MAC_CLIENT_FLAGS_PASSIVE_PRIMARY; 2531 passive_client = B_TRUE; 2532 } 2533 2534 mcip->mci_flags |= MAC_CLIENT_FLAGS_VNIC_PRIMARY; 2535 2536 /* 2537 * Create a handle for vid 0. 2538 */ 2539 ASSERT(vid == 0); 2540 muip = kmem_zalloc(sizeof (mac_unicast_impl_t), KM_SLEEP); 2541 muip->mui_vid = vid; 2542 *mah = (mac_unicast_handle_t)muip; 2543 /* 2544 * This will be used by the caller to defer setting the 2545 * rx functions. 2546 */ 2547 if (passive_client) 2548 return (EAGAIN); 2549 return (0); 2550 } 2551 2552 /* primary MAC clients cannot be opened on top of anchor VNICs */ 2553 if ((is_vnic_primary || is_primary) && 2554 i_mac_capab_get((mac_handle_t)mip, MAC_CAPAB_ANCHOR_VNIC, NULL)) { 2555 return (ENXIO); 2556 } 2557 2558 /* 2559 * If this is a VNIC/VLAN, disable softmac fast-path. 2560 */ 2561 if (mcip->mci_state_flags & MCIS_IS_VNIC) { 2562 err = mac_fastpath_disable((mac_handle_t)mip); 2563 if (err != 0) 2564 return (err); 2565 fastpath_disabled = B_TRUE; 2566 } 2567 2568 /* 2569 * Return EBUSY if: 2570 * - there is an exclusively active mac client exists. 2571 * - this is an exclusive active mac client but 2572 * a. there is already active mac clients exist, or 2573 * b. fastpath streams are already plumbed on this legacy device 2574 * - the mac creator has disallowed active mac clients. 2575 */ 2576 if (mip->mi_state_flags & (MIS_EXCLUSIVE|MIS_NO_ACTIVE)) { 2577 if (fastpath_disabled) 2578 mac_fastpath_enable((mac_handle_t)mip); 2579 return (EBUSY); 2580 } 2581 2582 if (mcip->mci_state_flags & MCIS_EXCLUSIVE) { 2583 ASSERT(!fastpath_disabled); 2584 if (mip->mi_nactiveclients != 0) 2585 return (EBUSY); 2586 2587 if ((mip->mi_state_flags & MIS_LEGACY) && 2588 !(mip->mi_capab_legacy.ml_active_set(mip->mi_driver))) { 2589 return (EBUSY); 2590 } 2591 mip->mi_state_flags |= MIS_EXCLUSIVE; 2592 } 2593 2594 mrp = kmem_zalloc(sizeof (*mrp), KM_SLEEP); 2595 if (is_primary && !(mcip->mci_state_flags & (MCIS_IS_VNIC | 2596 MCIS_IS_AGGR_PORT))) { 2597 /* 2598 * Apply the property cached in the mac_impl_t to the primary 2599 * mac client. If the mac client is a VNIC or an aggregation 2600 * port, its property should be set in the mcip when the 2601 * VNIC/aggr was created. 2602 */ 2603 mac_get_resources((mac_handle_t)mip, mrp); 2604 (void) mac_client_set_resources(mch, mrp); 2605 } else if (mcip->mci_state_flags & MCIS_IS_VNIC) { 2606 /* 2607 * This is a primary VLAN client, we don't support 2608 * specifying rings property for this as it inherits the 2609 * rings property from its MAC. 2610 */ 2611 if (is_vnic_primary) { 2612 mac_resource_props_t *vmrp; 2613 2614 vmrp = MCIP_RESOURCE_PROPS(mcip); 2615 if (vmrp->mrp_mask & MRP_RX_RINGS || 2616 vmrp->mrp_mask & MRP_TX_RINGS) { 2617 if (fastpath_disabled) 2618 mac_fastpath_enable((mac_handle_t)mip); 2619 kmem_free(mrp, sizeof (*mrp)); 2620 return (ENOTSUP); 2621 } 2622 /* 2623 * Additionally we also need to inherit any 2624 * rings property from the MAC. 2625 */ 2626 mac_get_resources((mac_handle_t)mip, mrp); 2627 if (mrp->mrp_mask & MRP_RX_RINGS) { 2628 vmrp->mrp_mask |= MRP_RX_RINGS; 2629 vmrp->mrp_nrxrings = mrp->mrp_nrxrings; 2630 } 2631 if (mrp->mrp_mask & MRP_TX_RINGS) { 2632 vmrp->mrp_mask |= MRP_TX_RINGS; 2633 vmrp->mrp_ntxrings = mrp->mrp_ntxrings; 2634 } 2635 } 2636 bcopy(MCIP_RESOURCE_PROPS(mcip), mrp, sizeof (*mrp)); 2637 } 2638 2639 muip = kmem_zalloc(sizeof (mac_unicast_impl_t), KM_SLEEP); 2640 muip->mui_vid = vid; 2641 2642 if (is_primary || is_vnic_primary) { 2643 mac_addr = mip->mi_addr; 2644 } else { 2645 2646 /* 2647 * Verify the validity of the specified MAC addresses value. 2648 */ 2649 if (!mac_unicst_verify((mac_handle_t)mip, mac_addr, mac_len)) { 2650 *diag = MAC_DIAG_MACADDR_INVALID; 2651 err = EINVAL; 2652 goto bail_out; 2653 } 2654 2655 /* 2656 * Make sure that the specified MAC address is different 2657 * than the unicast MAC address of the underlying NIC. 2658 */ 2659 if (check_dups && bcmp(mip->mi_addr, mac_addr, mac_len) == 0) { 2660 *diag = MAC_DIAG_MACADDR_NIC; 2661 err = EINVAL; 2662 goto bail_out; 2663 } 2664 } 2665 2666 /* 2667 * Set the flags here so that if this is a passive client, we 2668 * can return and set it when we call mac_client_datapath_setup 2669 * when this becomes the active client. If we defer to using these 2670 * flags to mac_client_datapath_setup, then for a passive client, 2671 * we'd have to store the flags somewhere (probably fe_flags) 2672 * and then use it. 2673 */ 2674 if (!MCIP_DATAPATH_SETUP(mcip)) { 2675 if (is_unicast_hw) { 2676 /* 2677 * The client requires a hardware MAC address slot 2678 * for that unicast address. Since we support only 2679 * one unicast MAC address per client, flag the 2680 * MAC client itself. 2681 */ 2682 mcip->mci_state_flags |= MCIS_UNICAST_HW; 2683 } 2684 2685 /* Check for VLAN flags, if present */ 2686 if ((flags & MAC_UNICAST_TAG_DISABLE) != 0) 2687 mcip->mci_state_flags |= MCIS_TAG_DISABLE; 2688 2689 if ((flags & MAC_UNICAST_STRIP_DISABLE) != 0) 2690 mcip->mci_state_flags |= MCIS_STRIP_DISABLE; 2691 2692 if ((flags & MAC_UNICAST_DISABLE_TX_VID_CHECK) != 0) 2693 mcip->mci_state_flags |= MCIS_DISABLE_TX_VID_CHECK; 2694 } else { 2695 /* 2696 * Assert that the specified flags are consistent with the 2697 * flags specified by previous calls to mac_unicast_add(). 2698 */ 2699 ASSERT(((flags & MAC_UNICAST_TAG_DISABLE) != 0 && 2700 (mcip->mci_state_flags & MCIS_TAG_DISABLE) != 0) || 2701 ((flags & MAC_UNICAST_TAG_DISABLE) == 0 && 2702 (mcip->mci_state_flags & MCIS_TAG_DISABLE) == 0)); 2703 2704 ASSERT(((flags & MAC_UNICAST_STRIP_DISABLE) != 0 && 2705 (mcip->mci_state_flags & MCIS_STRIP_DISABLE) != 0) || 2706 ((flags & MAC_UNICAST_STRIP_DISABLE) == 0 && 2707 (mcip->mci_state_flags & MCIS_STRIP_DISABLE) == 0)); 2708 2709 ASSERT(((flags & MAC_UNICAST_DISABLE_TX_VID_CHECK) != 0 && 2710 (mcip->mci_state_flags & MCIS_DISABLE_TX_VID_CHECK) != 0) || 2711 ((flags & MAC_UNICAST_DISABLE_TX_VID_CHECK) == 0 && 2712 (mcip->mci_state_flags & MCIS_DISABLE_TX_VID_CHECK) == 0)); 2713 2714 /* 2715 * Make sure the client is consistent about its requests 2716 * for MAC addresses. I.e. all requests from the clients 2717 * must have the MAC_UNICAST_HW flag set or clear. 2718 */ 2719 if ((mcip->mci_state_flags & MCIS_UNICAST_HW) != 0 && 2720 !is_unicast_hw || 2721 (mcip->mci_state_flags & MCIS_UNICAST_HW) == 0 && 2722 is_unicast_hw) { 2723 err = EINVAL; 2724 goto bail_out; 2725 } 2726 } 2727 /* 2728 * Make sure the MAC address is not already used by 2729 * another MAC client defined on top of the same 2730 * underlying NIC. Unless we have MAC_CLIENT_FLAGS_MULTI_PRIMARY 2731 * set when we allow a passive client to be present which will 2732 * be activated when the currently active client goes away - this 2733 * works only with primary addresses. 2734 */ 2735 if ((check_dups || is_primary || is_vnic_primary) && 2736 mac_addr_in_use(mip, mac_addr, vid)) { 2737 /* 2738 * Must have set the multiple primary address flag when 2739 * we did a mac_client_open AND this should be a primary 2740 * MAC client AND there should not already be a passive 2741 * primary. If all is true then we let this succeed 2742 * even if the address is a dup. 2743 */ 2744 if ((mcip->mci_flags & MAC_CLIENT_FLAGS_MULTI_PRIMARY) == 0 || 2745 (mcip->mci_flags & MAC_CLIENT_FLAGS_PRIMARY) == 0 || 2746 mac_get_passive_primary_client(mip) != NULL) { 2747 *diag = MAC_DIAG_MACADDR_INUSE; 2748 err = EEXIST; 2749 goto bail_out; 2750 } 2751 ASSERT((mcip->mci_flags & 2752 MAC_CLIENT_FLAGS_PASSIVE_PRIMARY) == 0); 2753 mcip->mci_flags |= MAC_CLIENT_FLAGS_PASSIVE_PRIMARY; 2754 kmem_free(mrp, sizeof (*mrp)); 2755 2756 /* 2757 * Stash the unicast address handle, we will use it when 2758 * we set up the passive client. 2759 */ 2760 mcip->mci_p_unicast_list = muip; 2761 *mah = (mac_unicast_handle_t)muip; 2762 return (0); 2763 } 2764 2765 err = mac_client_datapath_setup(mcip, vid, mac_addr, mrp, 2766 is_primary || is_vnic_primary, muip); 2767 if (err != 0) 2768 goto bail_out; 2769 2770 kmem_free(mrp, sizeof (*mrp)); 2771 *mah = (mac_unicast_handle_t)muip; 2772 return (0); 2773 2774 bail_out: 2775 if (fastpath_disabled) 2776 mac_fastpath_enable((mac_handle_t)mip); 2777 if (mcip->mci_state_flags & MCIS_EXCLUSIVE) { 2778 mip->mi_state_flags &= ~MIS_EXCLUSIVE; 2779 if (mip->mi_state_flags & MIS_LEGACY) { 2780 mip->mi_capab_legacy.ml_active_clear( 2781 mip->mi_driver); 2782 } 2783 } 2784 kmem_free(mrp, sizeof (*mrp)); 2785 kmem_free(muip, sizeof (mac_unicast_impl_t)); 2786 return (err); 2787 } 2788 2789 /* 2790 * Wrapper function to mac_unicast_add when we want to have the same mac 2791 * client open for two instances, one that is currently active and another 2792 * that will become active when the current one is removed. In this case 2793 * mac_unicast_add will return EGAIN and we will save the rx function and 2794 * arg which will be used when we activate the passive client in 2795 * mac_unicast_remove. 2796 */ 2797 int 2798 mac_unicast_add_set_rx(mac_client_handle_t mch, uint8_t *mac_addr, 2799 uint16_t flags, mac_unicast_handle_t *mah, uint16_t vid, mac_diag_t *diag, 2800 mac_rx_t rx_fn, void *arg) 2801 { 2802 mac_client_impl_t *mcip = (mac_client_impl_t *)mch; 2803 uint_t err; 2804 2805 err = mac_unicast_add(mch, mac_addr, flags, mah, vid, diag); 2806 if (err != 0 && err != EAGAIN) 2807 return (err); 2808 if (err == EAGAIN) { 2809 if (rx_fn != NULL) { 2810 mcip->mci_rx_p_fn = rx_fn; 2811 mcip->mci_rx_p_arg = arg; 2812 } 2813 return (0); 2814 } 2815 if (rx_fn != NULL) 2816 mac_rx_set(mch, rx_fn, arg); 2817 return (err); 2818 } 2819 2820 int 2821 mac_unicast_add(mac_client_handle_t mch, uint8_t *mac_addr, uint16_t flags, 2822 mac_unicast_handle_t *mah, uint16_t vid, mac_diag_t *diag) 2823 { 2824 mac_impl_t *mip = ((mac_client_impl_t *)mch)->mci_mip; 2825 uint_t err; 2826 2827 i_mac_perim_enter(mip); 2828 err = i_mac_unicast_add(mch, mac_addr, flags, mah, vid, diag); 2829 i_mac_perim_exit(mip); 2830 2831 return (err); 2832 } 2833 2834 static void 2835 mac_client_datapath_teardown(mac_client_handle_t mch, mac_unicast_impl_t *muip, 2836 flow_entry_t *flent) 2837 { 2838 mac_client_impl_t *mcip = (mac_client_impl_t *)mch; 2839 mac_impl_t *mip = mcip->mci_mip; 2840 boolean_t no_unicast; 2841 2842 /* 2843 * If we have not added a unicast address for this MAC client, just 2844 * teardown the datapath. 2845 */ 2846 no_unicast = mcip->mci_state_flags & MCIS_NO_UNICAST_ADDR; 2847 2848 if (!no_unicast) { 2849 /* 2850 * We would have initialized subflows etc. only if we brought 2851 * up the primary client and set the unicast unicast address 2852 * etc. Deactivate the flows. The flow entry will be removed 2853 * from the active flow tables, and the associated SRS, 2854 * softrings etc will be deleted. But the flow entry itself 2855 * won't be destroyed, instead it will continue to be archived 2856 * off the the global flow hash list, for a possible future 2857 * activation when say IP is plumbed again. 2858 */ 2859 mac_link_release_flows(mch); 2860 } 2861 mip->mi_nactiveclients--; 2862 mac_update_single_active_client(mip); 2863 2864 /* Tear down the data path */ 2865 mac_datapath_teardown(mcip, mcip->mci_flent, SRST_LINK); 2866 2867 /* 2868 * Prevent any future access to the flow entry through the mci_flent 2869 * pointer by setting the mci_flent to NULL. Access to mci_flent in 2870 * mac_bcast_send is also under mi_rw_lock. 2871 */ 2872 rw_enter(&mip->mi_rw_lock, RW_WRITER); 2873 flent = mcip->mci_flent; 2874 mac_client_remove_flow_from_list(mcip, flent); 2875 2876 if (mcip->mci_state_flags & MCIS_DESC_LOGGED) 2877 mcip->mci_state_flags &= ~MCIS_DESC_LOGGED; 2878 2879 /* 2880 * This is the last unicast address being removed and there shouldn't 2881 * be any outbound data threads at this point coming down from mac 2882 * clients. We have waited for the data threads to finish before 2883 * starting dld_str_detach. Non-data threads must access TX SRS 2884 * under mi_rw_lock. 2885 */ 2886 rw_exit(&mip->mi_rw_lock); 2887 2888 /* 2889 * Don't use FLOW_MARK with FE_MC_NO_DATAPATH, as the flow might 2890 * contain other flags, such as FE_CONDEMNED, which we need to 2891 * cleared. We don't call mac_flow_cleanup() for this unicast 2892 * flow as we have a already cleaned up SRSs etc. (via the teadown 2893 * path). We just clear the stats and reset the initial callback 2894 * function, the rest will be set when we call mac_flow_create, 2895 * if at all. 2896 */ 2897 mutex_enter(&flent->fe_lock); 2898 ASSERT(flent->fe_refcnt == 1 && flent->fe_mbg == NULL && 2899 flent->fe_tx_srs == NULL && flent->fe_rx_srs_cnt == 0); 2900 flent->fe_flags = FE_MC_NO_DATAPATH; 2901 flow_stat_destroy(flent); 2902 mac_misc_stat_delete(flent); 2903 2904 /* Initialize the receiver function to a safe routine */ 2905 flent->fe_cb_fn = (flow_fn_t)mac_pkt_drop; 2906 flent->fe_cb_arg1 = NULL; 2907 flent->fe_cb_arg2 = NULL; 2908 2909 flent->fe_index = -1; 2910 mutex_exit(&flent->fe_lock); 2911 2912 if (mip->mi_type->mt_brdcst_addr != NULL) { 2913 ASSERT(muip != NULL || no_unicast); 2914 mac_bcast_delete(mcip, mip->mi_type->mt_brdcst_addr, 2915 muip != NULL ? muip->mui_vid : VLAN_ID_NONE); 2916 } 2917 2918 if (mip->mi_nactiveclients == 1) { 2919 mac_capab_update((mac_handle_t)mip); 2920 mac_virtual_link_update(mip); 2921 } 2922 2923 if (mcip->mci_state_flags & MCIS_EXCLUSIVE) { 2924 mip->mi_state_flags &= ~MIS_EXCLUSIVE; 2925 2926 if (mip->mi_state_flags & MIS_LEGACY) 2927 mip->mi_capab_legacy.ml_active_clear(mip->mi_driver); 2928 } 2929 2930 mcip->mci_state_flags &= ~MCIS_UNICAST_HW; 2931 2932 if (mcip->mci_state_flags & MCIS_TAG_DISABLE) 2933 mcip->mci_state_flags &= ~MCIS_TAG_DISABLE; 2934 2935 if (mcip->mci_state_flags & MCIS_STRIP_DISABLE) 2936 mcip->mci_state_flags &= ~MCIS_STRIP_DISABLE; 2937 2938 if (mcip->mci_state_flags & MCIS_DISABLE_TX_VID_CHECK) 2939 mcip->mci_state_flags &= ~MCIS_DISABLE_TX_VID_CHECK; 2940 2941 if (muip != NULL) 2942 kmem_free(muip, sizeof (mac_unicast_impl_t)); 2943 mac_protect_cancel_timer(mcip); 2944 mac_protect_flush_dhcp(mcip); 2945 2946 bzero(&mcip->mci_misc_stat, sizeof (mcip->mci_misc_stat)); 2947 /* 2948 * Disable fastpath if this is a VNIC or a VLAN. 2949 */ 2950 if (mcip->mci_state_flags & MCIS_IS_VNIC) 2951 mac_fastpath_enable((mac_handle_t)mip); 2952 mac_stop((mac_handle_t)mip); 2953 } 2954 2955 /* 2956 * Remove a MAC address which was previously added by mac_unicast_add(). 2957 */ 2958 int 2959 mac_unicast_remove(mac_client_handle_t mch, mac_unicast_handle_t mah) 2960 { 2961 mac_client_impl_t *mcip = (mac_client_impl_t *)mch; 2962 mac_unicast_impl_t *muip = (mac_unicast_impl_t *)mah; 2963 mac_unicast_impl_t *pre; 2964 mac_impl_t *mip = mcip->mci_mip; 2965 flow_entry_t *flent; 2966 uint16_t mui_vid; 2967 2968 i_mac_perim_enter(mip); 2969 if (mcip->mci_flags & MAC_CLIENT_FLAGS_VNIC_PRIMARY) { 2970 /* 2971 * Called made by the upper MAC client of a VNIC. 2972 * There's nothing much to do, the unicast address will 2973 * be removed by the VNIC driver when the VNIC is deleted, 2974 * but let's ensure that all our transmit is done before 2975 * the client does a mac_client_stop lest it trigger an 2976 * assert in the driver. 2977 */ 2978 ASSERT(muip->mui_vid == 0); 2979 2980 mac_tx_client_flush(mcip); 2981 2982 if ((mcip->mci_flags & MAC_CLIENT_FLAGS_PASSIVE_PRIMARY) != 0) { 2983 mcip->mci_flags &= ~MAC_CLIENT_FLAGS_PASSIVE_PRIMARY; 2984 if (mcip->mci_rx_p_fn != NULL) { 2985 mac_rx_set(mch, mcip->mci_rx_p_fn, 2986 mcip->mci_rx_p_arg); 2987 mcip->mci_rx_p_fn = NULL; 2988 mcip->mci_rx_p_arg = NULL; 2989 } 2990 kmem_free(muip, sizeof (mac_unicast_impl_t)); 2991 i_mac_perim_exit(mip); 2992 return (0); 2993 } 2994 mcip->mci_flags &= ~MAC_CLIENT_FLAGS_VNIC_PRIMARY; 2995 2996 if (mcip->mci_state_flags & MCIS_TAG_DISABLE) 2997 mcip->mci_state_flags &= ~MCIS_TAG_DISABLE; 2998 2999 if (mcip->mci_state_flags & MCIS_STRIP_DISABLE) 3000 mcip->mci_state_flags &= ~MCIS_STRIP_DISABLE; 3001 3002 if (mcip->mci_state_flags & MCIS_DISABLE_TX_VID_CHECK) 3003 mcip->mci_state_flags &= ~MCIS_DISABLE_TX_VID_CHECK; 3004 3005 kmem_free(muip, sizeof (mac_unicast_impl_t)); 3006 i_mac_perim_exit(mip); 3007 return (0); 3008 } 3009 3010 ASSERT(muip != NULL); 3011 3012 /* 3013 * We are removing a passive client, we haven't setup the datapath 3014 * for this yet, so nothing much to do. 3015 */ 3016 if ((mcip->mci_flags & MAC_CLIENT_FLAGS_PASSIVE_PRIMARY) != 0) { 3017 3018 ASSERT((mcip->mci_flent->fe_flags & FE_MC_NO_DATAPATH) != 0); 3019 ASSERT(mcip->mci_p_unicast_list == muip); 3020 3021 mcip->mci_flags &= ~MAC_CLIENT_FLAGS_PASSIVE_PRIMARY; 3022 3023 mcip->mci_p_unicast_list = NULL; 3024 mcip->mci_rx_p_fn = NULL; 3025 mcip->mci_rx_p_arg = NULL; 3026 3027 mcip->mci_state_flags &= ~MCIS_UNICAST_HW; 3028 3029 if (mcip->mci_state_flags & MCIS_TAG_DISABLE) 3030 mcip->mci_state_flags &= ~MCIS_TAG_DISABLE; 3031 3032 if (mcip->mci_state_flags & MCIS_STRIP_DISABLE) 3033 mcip->mci_state_flags &= ~MCIS_STRIP_DISABLE; 3034 3035 if (mcip->mci_state_flags & MCIS_DISABLE_TX_VID_CHECK) 3036 mcip->mci_state_flags &= ~MCIS_DISABLE_TX_VID_CHECK; 3037 3038 kmem_free(muip, sizeof (mac_unicast_impl_t)); 3039 i_mac_perim_exit(mip); 3040 return (0); 3041 } 3042 /* 3043 * Remove the VID from the list of client's VIDs. 3044 */ 3045 pre = mcip->mci_unicast_list; 3046 if (muip == pre) { 3047 mcip->mci_unicast_list = muip->mui_next; 3048 } else { 3049 while ((pre->mui_next != NULL) && (pre->mui_next != muip)) 3050 pre = pre->mui_next; 3051 ASSERT(pre->mui_next == muip); 3052 rw_enter(&mcip->mci_rw_lock, RW_WRITER); 3053 pre->mui_next = muip->mui_next; 3054 rw_exit(&mcip->mci_rw_lock); 3055 } 3056 3057 if (!mac_client_single_rcvr(mcip)) { 3058 /* 3059 * This MAC client is shared by more than one unicast 3060 * addresses, so we will just remove the flent 3061 * corresponding to the address being removed. We don't invoke 3062 * mac_rx_classify_flow_rem() since the additional flow is 3063 * not associated with its own separate set of SRS and rings, 3064 * and these constructs are still needed for the remaining 3065 * flows. 3066 */ 3067 flent = mac_client_get_flow(mcip, muip); 3068 ASSERT(flent != NULL); 3069 3070 /* 3071 * The first one is disappearing, need to make sure 3072 * we replace it with another from the list of 3073 * shared clients. 3074 */ 3075 if (flent == mcip->mci_flent) 3076 flent = mac_client_swap_mciflent(mcip); 3077 mac_client_remove_flow_from_list(mcip, flent); 3078 mac_flow_remove(mip->mi_flow_tab, flent, B_FALSE); 3079 mac_flow_wait(flent, FLOW_DRIVER_UPCALL); 3080 3081 /* 3082 * The multicast groups that were added by the client so 3083 * far must be removed from the brodcast domain corresponding 3084 * to the VID being removed. 3085 */ 3086 mac_client_bcast_refresh(mcip, mac_client_update_mcast, 3087 (void *)flent, B_FALSE); 3088 3089 if (mip->mi_type->mt_brdcst_addr != NULL) { 3090 mac_bcast_delete(mcip, mip->mi_type->mt_brdcst_addr, 3091 muip->mui_vid); 3092 } 3093 3094 FLOW_FINAL_REFRELE(flent); 3095 ASSERT(!(mcip->mci_state_flags & MCIS_EXCLUSIVE)); 3096 /* 3097 * Enable fastpath if this is a VNIC or a VLAN. 3098 */ 3099 if (mcip->mci_state_flags & MCIS_IS_VNIC) 3100 mac_fastpath_enable((mac_handle_t)mip); 3101 mac_stop((mac_handle_t)mip); 3102 i_mac_perim_exit(mip); 3103 return (0); 3104 } 3105 3106 mui_vid = muip->mui_vid; 3107 mac_client_datapath_teardown(mch, muip, flent); 3108 3109 if ((mcip->mci_flags & MAC_CLIENT_FLAGS_PRIMARY) && mui_vid == 0) { 3110 mcip->mci_flags &= ~MAC_CLIENT_FLAGS_PRIMARY; 3111 } else { 3112 i_mac_perim_exit(mip); 3113 return (0); 3114 } 3115 3116 /* 3117 * If we are removing the primary, check if we have a passive primary 3118 * client that we need to activate now. 3119 */ 3120 mcip = mac_get_passive_primary_client(mip); 3121 if (mcip != NULL) { 3122 mac_resource_props_t *mrp; 3123 mac_unicast_impl_t *muip; 3124 3125 mcip->mci_flags &= ~MAC_CLIENT_FLAGS_PASSIVE_PRIMARY; 3126 mrp = kmem_zalloc(sizeof (*mrp), KM_SLEEP); 3127 3128 /* 3129 * Apply the property cached in the mac_impl_t to the 3130 * primary mac client. 3131 */ 3132 mac_get_resources((mac_handle_t)mip, mrp); 3133 (void) mac_client_set_resources(mch, mrp); 3134 ASSERT(mcip->mci_p_unicast_list != NULL); 3135 muip = mcip->mci_p_unicast_list; 3136 mcip->mci_p_unicast_list = NULL; 3137 if (mac_client_datapath_setup(mcip, VLAN_ID_NONE, 3138 mip->mi_addr, mrp, B_TRUE, muip) == 0) { 3139 if (mcip->mci_rx_p_fn != NULL) { 3140 mac_rx_set(mch, mcip->mci_rx_p_fn, 3141 mcip->mci_rx_p_arg); 3142 mcip->mci_rx_p_fn = NULL; 3143 mcip->mci_rx_p_arg = NULL; 3144 } 3145 } else { 3146 kmem_free(muip, sizeof (mac_unicast_impl_t)); 3147 } 3148 kmem_free(mrp, sizeof (*mrp)); 3149 } 3150 i_mac_perim_exit(mip); 3151 return (0); 3152 } 3153 3154 /* 3155 * Multicast add function invoked by MAC clients. 3156 */ 3157 int 3158 mac_multicast_add(mac_client_handle_t mch, const uint8_t *addr) 3159 { 3160 mac_client_impl_t *mcip = (mac_client_impl_t *)mch; 3161 mac_impl_t *mip = mcip->mci_mip; 3162 flow_entry_t *flent = mcip->mci_flent_list; 3163 flow_entry_t *prev_fe = NULL; 3164 uint16_t vid; 3165 int err = 0; 3166 3167 /* Verify the address is a valid multicast address */ 3168 if ((err = mip->mi_type->mt_ops.mtops_multicst_verify(addr, 3169 mip->mi_pdata)) != 0) 3170 return (err); 3171 3172 i_mac_perim_enter(mip); 3173 while (flent != NULL) { 3174 vid = i_mac_flow_vid(flent); 3175 3176 err = mac_bcast_add((mac_client_impl_t *)mch, addr, vid, 3177 MAC_ADDRTYPE_MULTICAST); 3178 if (err != 0) 3179 break; 3180 prev_fe = flent; 3181 flent = flent->fe_client_next; 3182 } 3183 3184 /* 3185 * If we failed adding, then undo all, rather than partial 3186 * success. 3187 */ 3188 if (flent != NULL && prev_fe != NULL) { 3189 flent = mcip->mci_flent_list; 3190 while (flent != prev_fe->fe_client_next) { 3191 vid = i_mac_flow_vid(flent); 3192 mac_bcast_delete((mac_client_impl_t *)mch, addr, vid); 3193 flent = flent->fe_client_next; 3194 } 3195 } 3196 i_mac_perim_exit(mip); 3197 return (err); 3198 } 3199 3200 /* 3201 * Multicast delete function invoked by MAC clients. 3202 */ 3203 void 3204 mac_multicast_remove(mac_client_handle_t mch, const uint8_t *addr) 3205 { 3206 mac_client_impl_t *mcip = (mac_client_impl_t *)mch; 3207 mac_impl_t *mip = mcip->mci_mip; 3208 flow_entry_t *flent; 3209 uint16_t vid; 3210 3211 i_mac_perim_enter(mip); 3212 for (flent = mcip->mci_flent_list; flent != NULL; 3213 flent = flent->fe_client_next) { 3214 vid = i_mac_flow_vid(flent); 3215 mac_bcast_delete((mac_client_impl_t *)mch, addr, vid); 3216 } 3217 i_mac_perim_exit(mip); 3218 } 3219 3220 /* 3221 * When a MAC client desires to capture packets on an interface, 3222 * it registers a promiscuous call back with mac_promisc_add(). 3223 * There are three types of promiscuous callbacks: 3224 * 3225 * * MAC_CLIENT_PROMISC_ALL 3226 * Captures all packets sent and received by the MAC client, 3227 * the physical interface, as well as all other MAC clients 3228 * defined on top of the same MAC. 3229 * 3230 * * MAC_CLIENT_PROMISC_FILTERED 3231 * Captures all packets sent and received by the MAC client, 3232 * plus all multicast traffic sent and received by the phyisical 3233 * interface and the other MAC clients. 3234 * 3235 * * MAC_CLIENT_PROMISC_MULTI 3236 * Captures all broadcast and multicast packets sent and 3237 * received by the MAC clients as well as the physical interface. 3238 * 3239 * In all cases, the underlying MAC is put in promiscuous mode. 3240 */ 3241 int 3242 mac_promisc_add(mac_client_handle_t mch, mac_client_promisc_type_t type, 3243 mac_rx_t fn, void *arg, mac_promisc_handle_t *mphp, uint16_t flags) 3244 { 3245 mac_client_impl_t *mcip = (mac_client_impl_t *)mch; 3246 mac_impl_t *mip = mcip->mci_mip; 3247 mac_promisc_impl_t *mpip; 3248 mac_cb_info_t *mcbi; 3249 int rc; 3250 3251 i_mac_perim_enter(mip); 3252 3253 if ((rc = mac_start((mac_handle_t)mip)) != 0) { 3254 i_mac_perim_exit(mip); 3255 return (rc); 3256 } 3257 3258 if ((mcip->mci_state_flags & MCIS_IS_VNIC) && 3259 type == MAC_CLIENT_PROMISC_ALL && 3260 (mcip->mci_protect_flags & MPT_FLAG_PROMISC_FILTERED)) { 3261 /* 3262 * The function is being invoked by the upper MAC client 3263 * of a VNIC. The VNIC should only see the traffic 3264 * it is entitled to. 3265 */ 3266 type = MAC_CLIENT_PROMISC_FILTERED; 3267 } 3268 3269 3270 /* 3271 * Turn on promiscuous mode for the underlying NIC. 3272 * This is needed even for filtered callbacks which 3273 * expect to receive all multicast traffic on the wire. 3274 * 3275 * Physical promiscuous mode should not be turned on if 3276 * MAC_PROMISC_FLAGS_NO_PHYS is set. 3277 */ 3278 if ((flags & MAC_PROMISC_FLAGS_NO_PHYS) == 0) { 3279 if ((rc = i_mac_promisc_set(mip, B_TRUE)) != 0) { 3280 mac_stop((mac_handle_t)mip); 3281 i_mac_perim_exit(mip); 3282 return (rc); 3283 } 3284 } 3285 3286 mpip = kmem_cache_alloc(mac_promisc_impl_cache, KM_SLEEP); 3287 3288 mpip->mpi_type = type; 3289 mpip->mpi_fn = fn; 3290 mpip->mpi_arg = arg; 3291 mpip->mpi_mcip = mcip; 3292 mpip->mpi_no_tx_loop = ((flags & MAC_PROMISC_FLAGS_NO_TX_LOOP) != 0); 3293 mpip->mpi_no_phys = ((flags & MAC_PROMISC_FLAGS_NO_PHYS) != 0); 3294 mpip->mpi_strip_vlan_tag = 3295 ((flags & MAC_PROMISC_FLAGS_VLAN_TAG_STRIP) != 0); 3296 mpip->mpi_no_copy = ((flags & MAC_PROMISC_FLAGS_NO_COPY) != 0); 3297 3298 mcbi = &mip->mi_promisc_cb_info; 3299 mutex_enter(mcbi->mcbi_lockp); 3300 3301 mac_callback_add(&mip->mi_promisc_cb_info, &mcip->mci_promisc_list, 3302 &mpip->mpi_mci_link); 3303 mac_callback_add(&mip->mi_promisc_cb_info, &mip->mi_promisc_list, 3304 &mpip->mpi_mi_link); 3305 3306 mutex_exit(mcbi->mcbi_lockp); 3307 3308 *mphp = (mac_promisc_handle_t)mpip; 3309 3310 if (mcip->mci_state_flags & MCIS_IS_VNIC) { 3311 mac_impl_t *umip = mcip->mci_upper_mip; 3312 3313 ASSERT(umip != NULL); 3314 mac_vnic_secondary_update(umip); 3315 } 3316 3317 i_mac_perim_exit(mip); 3318 3319 return (0); 3320 } 3321 3322 /* 3323 * Remove a multicast address previously aded through mac_promisc_add(). 3324 */ 3325 void 3326 mac_promisc_remove(mac_promisc_handle_t mph) 3327 { 3328 mac_promisc_impl_t *mpip = (mac_promisc_impl_t *)mph; 3329 mac_client_impl_t *mcip = mpip->mpi_mcip; 3330 mac_impl_t *mip = mcip->mci_mip; 3331 mac_cb_info_t *mcbi; 3332 int rv; 3333 3334 i_mac_perim_enter(mip); 3335 3336 /* 3337 * Even if the device can't be reset into normal mode, we still 3338 * need to clear the client promisc callbacks. The client may want 3339 * to close the mac end point and we can't have stale callbacks. 3340 */ 3341 if (!(mpip->mpi_no_phys)) { 3342 if ((rv = i_mac_promisc_set(mip, B_FALSE)) != 0) { 3343 cmn_err(CE_WARN, "%s: failed to switch OFF promiscuous" 3344 " mode because of error 0x%x", mip->mi_name, rv); 3345 } 3346 } 3347 mcbi = &mip->mi_promisc_cb_info; 3348 mutex_enter(mcbi->mcbi_lockp); 3349 if (mac_callback_remove(mcbi, &mip->mi_promisc_list, 3350 &mpip->mpi_mi_link)) { 3351 VERIFY(mac_callback_remove(&mip->mi_promisc_cb_info, 3352 &mcip->mci_promisc_list, &mpip->mpi_mci_link)); 3353 kmem_cache_free(mac_promisc_impl_cache, mpip); 3354 } else { 3355 mac_callback_remove_wait(&mip->mi_promisc_cb_info); 3356 } 3357 3358 if (mcip->mci_state_flags & MCIS_IS_VNIC) { 3359 mac_impl_t *umip = mcip->mci_upper_mip; 3360 3361 ASSERT(umip != NULL); 3362 mac_vnic_secondary_update(umip); 3363 } 3364 3365 mutex_exit(mcbi->mcbi_lockp); 3366 mac_stop((mac_handle_t)mip); 3367 3368 i_mac_perim_exit(mip); 3369 } 3370 3371 /* 3372 * Reference count the number of active Tx threads. MCI_TX_QUIESCE indicates 3373 * that a control operation wants to quiesce the Tx data flow in which case 3374 * we return an error. Holding any of the per cpu locks ensures that the 3375 * mci_tx_flag won't change. 3376 * 3377 * 'CPU' must be accessed just once and used to compute the index into the 3378 * percpu array, and that index must be used for the entire duration of the 3379 * packet send operation. Note that the thread may be preempted and run on 3380 * another cpu any time and so we can't use 'CPU' more than once for the 3381 * operation. 3382 */ 3383 #define MAC_TX_TRY_HOLD(mcip, mytx, error) \ 3384 { \ 3385 (error) = 0; \ 3386 (mytx) = &(mcip)->mci_tx_pcpu[CPU->cpu_seqid & mac_tx_percpu_cnt]; \ 3387 mutex_enter(&(mytx)->pcpu_tx_lock); \ 3388 if (!((mcip)->mci_tx_flag & MCI_TX_QUIESCE)) { \ 3389 (mytx)->pcpu_tx_refcnt++; \ 3390 } else { \ 3391 (error) = -1; \ 3392 } \ 3393 mutex_exit(&(mytx)->pcpu_tx_lock); \ 3394 } 3395 3396 /* 3397 * Release the reference. If needed, signal any control operation waiting 3398 * for Tx quiescence. The wait and signal are always done using the 3399 * mci_tx_pcpu[0]'s lock 3400 */ 3401 #define MAC_TX_RELE(mcip, mytx) { \ 3402 mutex_enter(&(mytx)->pcpu_tx_lock); \ 3403 if (--(mytx)->pcpu_tx_refcnt == 0 && \ 3404 (mcip)->mci_tx_flag & MCI_TX_QUIESCE) { \ 3405 mutex_exit(&(mytx)->pcpu_tx_lock); \ 3406 mutex_enter(&(mcip)->mci_tx_pcpu[0].pcpu_tx_lock); \ 3407 cv_signal(&(mcip)->mci_tx_cv); \ 3408 mutex_exit(&(mcip)->mci_tx_pcpu[0].pcpu_tx_lock); \ 3409 } else { \ 3410 mutex_exit(&(mytx)->pcpu_tx_lock); \ 3411 } \ 3412 } 3413 3414 /* 3415 * Send function invoked by MAC clients. 3416 */ 3417 mac_tx_cookie_t 3418 mac_tx(mac_client_handle_t mch, mblk_t *mp_chain, uintptr_t hint, 3419 uint16_t flag, mblk_t **ret_mp) 3420 { 3421 mac_tx_cookie_t cookie = NULL; 3422 int error; 3423 mac_tx_percpu_t *mytx; 3424 mac_soft_ring_set_t *srs; 3425 flow_entry_t *flent; 3426 boolean_t is_subflow = B_FALSE; 3427 mac_client_impl_t *mcip = (mac_client_impl_t *)mch; 3428 mac_impl_t *mip = mcip->mci_mip; 3429 mac_srs_tx_t *srs_tx; 3430 3431 /* 3432 * Check whether the active Tx threads count is bumped already. 3433 */ 3434 if (!(flag & MAC_TX_NO_HOLD)) { 3435 MAC_TX_TRY_HOLD(mcip, mytx, error); 3436 if (error != 0) { 3437 freemsgchain(mp_chain); 3438 return (NULL); 3439 } 3440 } 3441 3442 /* 3443 * If mac protection is enabled, only the permissible packets will be 3444 * returned by mac_protect_check(). 3445 */ 3446 if ((mcip->mci_flent-> 3447 fe_resource_props.mrp_mask & MRP_PROTECT) != 0 && 3448 (mp_chain = mac_protect_check(mch, mp_chain)) == NULL) 3449 goto done; 3450 3451 if (mcip->mci_subflow_tab != NULL && 3452 mcip->mci_subflow_tab->ft_flow_count > 0 && 3453 mac_flow_lookup(mcip->mci_subflow_tab, mp_chain, 3454 FLOW_OUTBOUND, &flent) == 0) { 3455 /* 3456 * The main assumption here is that if in the event 3457 * we get a chain, all the packets will be classified 3458 * to the same Flow/SRS. If this changes for any 3459 * reason, the following logic should change as well. 3460 * I suppose the fanout_hint also assumes this . 3461 */ 3462 ASSERT(flent != NULL); 3463 is_subflow = B_TRUE; 3464 } else { 3465 flent = mcip->mci_flent; 3466 } 3467 3468 srs = flent->fe_tx_srs; 3469 /* 3470 * This is to avoid panics with PF_PACKET that can call mac_tx() 3471 * against an interface that is not capable of sending. A rewrite 3472 * of the mac datapath is required to remove this limitation. 3473 */ 3474 if (srs == NULL) { 3475 freemsgchain(mp_chain); 3476 goto done; 3477 } 3478 3479 srs_tx = &srs->srs_tx; 3480 if (srs_tx->st_mode == SRS_TX_DEFAULT && 3481 (srs->srs_state & SRS_ENQUEUED) == 0 && 3482 mip->mi_nactiveclients == 1 && mp_chain->b_next == NULL) { 3483 uint64_t obytes; 3484 3485 /* 3486 * Since dls always opens the underlying MAC, nclients equals 3487 * to 1 means that the only active client is dls itself acting 3488 * as a primary client of the MAC instance. Since dls will not 3489 * send tagged packets in that case, and dls is trusted to send 3490 * packets for its allowed VLAN(s), the VLAN tag insertion and 3491 * check is required only if nclients is greater than 1. 3492 */ 3493 if (mip->mi_nclients > 1) { 3494 if (MAC_VID_CHECK_NEEDED(mcip)) { 3495 int err = 0; 3496 3497 MAC_VID_CHECK(mcip, mp_chain, err); 3498 if (err != 0) { 3499 freemsg(mp_chain); 3500 mcip->mci_misc_stat.mms_txerrors++; 3501 goto done; 3502 } 3503 } 3504 if (MAC_TAG_NEEDED(mcip)) { 3505 mp_chain = mac_add_vlan_tag(mp_chain, 0, 3506 mac_client_vid(mch)); 3507 if (mp_chain == NULL) { 3508 mcip->mci_misc_stat.mms_txerrors++; 3509 goto done; 3510 } 3511 } 3512 } 3513 3514 obytes = (mp_chain->b_cont == NULL ? MBLKL(mp_chain) : 3515 msgdsize(mp_chain)); 3516 3517 MAC_TX(mip, srs_tx->st_arg2, mp_chain, mcip); 3518 if (mp_chain == NULL) { 3519 cookie = NULL; 3520 SRS_TX_STAT_UPDATE(srs, opackets, 1); 3521 SRS_TX_STAT_UPDATE(srs, obytes, obytes); 3522 } else { 3523 mutex_enter(&srs->srs_lock); 3524 cookie = mac_tx_srs_no_desc(srs, mp_chain, 3525 flag, ret_mp); 3526 mutex_exit(&srs->srs_lock); 3527 } 3528 } else { 3529 cookie = srs_tx->st_func(srs, mp_chain, hint, flag, ret_mp); 3530 } 3531 3532 done: 3533 if (is_subflow) 3534 FLOW_REFRELE(flent); 3535 3536 if (!(flag & MAC_TX_NO_HOLD)) 3537 MAC_TX_RELE(mcip, mytx); 3538 3539 return (cookie); 3540 } 3541 3542 /* 3543 * mac_tx_is_blocked 3544 * 3545 * Given a cookie, it returns if the ring identified by the cookie is 3546 * flow-controlled or not. If NULL is passed in place of a cookie, 3547 * then it finds out if any of the underlying rings belonging to the 3548 * SRS is flow controlled or not and returns that status. 3549 */ 3550 /* ARGSUSED */ 3551 boolean_t 3552 mac_tx_is_flow_blocked(mac_client_handle_t mch, mac_tx_cookie_t cookie) 3553 { 3554 mac_client_impl_t *mcip = (mac_client_impl_t *)mch; 3555 mac_soft_ring_set_t *mac_srs; 3556 mac_soft_ring_t *sringp; 3557 boolean_t blocked = B_FALSE; 3558 mac_tx_percpu_t *mytx; 3559 int err; 3560 int i; 3561 3562 /* 3563 * Bump the reference count so that mac_srs won't be deleted. 3564 * If the client is currently quiesced and we failed to bump 3565 * the reference, return B_TRUE so that flow control stays 3566 * as enabled. 3567 * 3568 * Flow control will then be disabled once the client is no 3569 * longer quiesced. 3570 */ 3571 MAC_TX_TRY_HOLD(mcip, mytx, err); 3572 if (err != 0) 3573 return (B_TRUE); 3574 3575 if ((mac_srs = MCIP_TX_SRS(mcip)) == NULL) { 3576 MAC_TX_RELE(mcip, mytx); 3577 return (B_FALSE); 3578 } 3579 3580 mutex_enter(&mac_srs->srs_lock); 3581 /* 3582 * Only in the case of TX_FANOUT and TX_AGGR, the underlying 3583 * softring (s_ring_state) will have the HIWAT set. This is 3584 * the multiple Tx ring flow control case. For all other 3585 * case, SRS (srs_state) will store the condition. 3586 */ 3587 if (mac_srs->srs_tx.st_mode == SRS_TX_FANOUT || 3588 mac_srs->srs_tx.st_mode == SRS_TX_AGGR) { 3589 if (cookie != NULL) { 3590 sringp = (mac_soft_ring_t *)cookie; 3591 mutex_enter(&sringp->s_ring_lock); 3592 if (sringp->s_ring_state & S_RING_TX_HIWAT) 3593 blocked = B_TRUE; 3594 mutex_exit(&sringp->s_ring_lock); 3595 } else { 3596 for (i = 0; i < mac_srs->srs_tx_ring_count; i++) { 3597 sringp = mac_srs->srs_tx_soft_rings[i]; 3598 mutex_enter(&sringp->s_ring_lock); 3599 if (sringp->s_ring_state & S_RING_TX_HIWAT) { 3600 blocked = B_TRUE; 3601 mutex_exit(&sringp->s_ring_lock); 3602 break; 3603 } 3604 mutex_exit(&sringp->s_ring_lock); 3605 } 3606 } 3607 } else { 3608 blocked = (mac_srs->srs_state & SRS_TX_HIWAT); 3609 } 3610 mutex_exit(&mac_srs->srs_lock); 3611 MAC_TX_RELE(mcip, mytx); 3612 return (blocked); 3613 } 3614 3615 /* 3616 * Check if the MAC client is the primary MAC client. 3617 */ 3618 boolean_t 3619 mac_is_primary_client(mac_client_impl_t *mcip) 3620 { 3621 return (mcip->mci_flags & MAC_CLIENT_FLAGS_PRIMARY); 3622 } 3623 3624 void 3625 mac_ioctl(mac_handle_t mh, queue_t *wq, mblk_t *bp) 3626 { 3627 mac_impl_t *mip = (mac_impl_t *)mh; 3628 int cmd = ((struct iocblk *)bp->b_rptr)->ioc_cmd; 3629 3630 if ((cmd == ND_GET && (mip->mi_callbacks->mc_callbacks & MC_GETPROP)) || 3631 (cmd == ND_SET && (mip->mi_callbacks->mc_callbacks & MC_SETPROP))) { 3632 /* 3633 * If ndd props were registered, call them. 3634 * Note that ndd ioctls are Obsolete 3635 */ 3636 mac_ndd_ioctl(mip, wq, bp); 3637 return; 3638 } 3639 3640 /* 3641 * Call the driver to handle the ioctl. The driver may not support 3642 * any ioctls, in which case we reply with a NAK on its behalf. 3643 */ 3644 if (mip->mi_callbacks->mc_callbacks & MC_IOCTL) 3645 mip->mi_ioctl(mip->mi_driver, wq, bp); 3646 else 3647 miocnak(wq, bp, 0, EINVAL); 3648 } 3649 3650 /* 3651 * Return the link state of the specified MAC instance. 3652 */ 3653 link_state_t 3654 mac_link_get(mac_handle_t mh) 3655 { 3656 return (((mac_impl_t *)mh)->mi_linkstate); 3657 } 3658 3659 /* 3660 * Add a mac client specified notification callback. Please see the comments 3661 * above mac_callback_add() for general information about mac callback 3662 * addition/deletion in the presence of mac callback list walkers 3663 */ 3664 mac_notify_handle_t 3665 mac_notify_add(mac_handle_t mh, mac_notify_t notify_fn, void *arg) 3666 { 3667 mac_impl_t *mip = (mac_impl_t *)mh; 3668 mac_notify_cb_t *mncb; 3669 mac_cb_info_t *mcbi; 3670 3671 /* 3672 * Allocate a notify callback structure, fill in the details and 3673 * use the mac callback list manipulation functions to chain into 3674 * the list of callbacks. 3675 */ 3676 mncb = kmem_zalloc(sizeof (mac_notify_cb_t), KM_SLEEP); 3677 mncb->mncb_fn = notify_fn; 3678 mncb->mncb_arg = arg; 3679 mncb->mncb_mip = mip; 3680 mncb->mncb_link.mcb_objp = mncb; 3681 mncb->mncb_link.mcb_objsize = sizeof (mac_notify_cb_t); 3682 mncb->mncb_link.mcb_flags = MCB_NOTIFY_CB_T; 3683 3684 mcbi = &mip->mi_notify_cb_info; 3685 3686 i_mac_perim_enter(mip); 3687 mutex_enter(mcbi->mcbi_lockp); 3688 3689 mac_callback_add(&mip->mi_notify_cb_info, &mip->mi_notify_cb_list, 3690 &mncb->mncb_link); 3691 3692 mutex_exit(mcbi->mcbi_lockp); 3693 i_mac_perim_exit(mip); 3694 return ((mac_notify_handle_t)mncb); 3695 } 3696 3697 void 3698 mac_notify_remove_wait(mac_handle_t mh) 3699 { 3700 mac_impl_t *mip = (mac_impl_t *)mh; 3701 mac_cb_info_t *mcbi = &mip->mi_notify_cb_info; 3702 3703 mutex_enter(mcbi->mcbi_lockp); 3704 mac_callback_remove_wait(&mip->mi_notify_cb_info); 3705 mutex_exit(mcbi->mcbi_lockp); 3706 } 3707 3708 /* 3709 * Remove a mac client specified notification callback 3710 */ 3711 int 3712 mac_notify_remove(mac_notify_handle_t mnh, boolean_t wait) 3713 { 3714 mac_notify_cb_t *mncb = (mac_notify_cb_t *)mnh; 3715 mac_impl_t *mip = mncb->mncb_mip; 3716 mac_cb_info_t *mcbi; 3717 int err = 0; 3718 3719 mcbi = &mip->mi_notify_cb_info; 3720 3721 i_mac_perim_enter(mip); 3722 mutex_enter(mcbi->mcbi_lockp); 3723 3724 ASSERT(mncb->mncb_link.mcb_objp == mncb); 3725 /* 3726 * If there aren't any list walkers, the remove would succeed 3727 * inline, else we wait for the deferred remove to complete 3728 */ 3729 if (mac_callback_remove(&mip->mi_notify_cb_info, 3730 &mip->mi_notify_cb_list, &mncb->mncb_link)) { 3731 kmem_free(mncb, sizeof (mac_notify_cb_t)); 3732 } else { 3733 err = EBUSY; 3734 } 3735 3736 mutex_exit(mcbi->mcbi_lockp); 3737 i_mac_perim_exit(mip); 3738 3739 /* 3740 * If we failed to remove the notification callback and "wait" is set 3741 * to be B_TRUE, wait for the callback to finish after we exit the 3742 * mac perimeter. 3743 */ 3744 if (err != 0 && wait) { 3745 mac_notify_remove_wait((mac_handle_t)mip); 3746 return (0); 3747 } 3748 3749 return (err); 3750 } 3751 3752 /* 3753 * Associate resource management callbacks with the specified MAC 3754 * clients. 3755 */ 3756 3757 void 3758 mac_resource_set_common(mac_client_handle_t mch, mac_resource_add_t add, 3759 mac_resource_remove_t remove, mac_resource_quiesce_t quiesce, 3760 mac_resource_restart_t restart, mac_resource_bind_t bind, 3761 void *arg) 3762 { 3763 mac_client_impl_t *mcip = (mac_client_impl_t *)mch; 3764 3765 mcip->mci_resource_add = add; 3766 mcip->mci_resource_remove = remove; 3767 mcip->mci_resource_quiesce = quiesce; 3768 mcip->mci_resource_restart = restart; 3769 mcip->mci_resource_bind = bind; 3770 mcip->mci_resource_arg = arg; 3771 } 3772 3773 void 3774 mac_resource_set(mac_client_handle_t mch, mac_resource_add_t add, void *arg) 3775 { 3776 /* update the 'resource_add' callback */ 3777 mac_resource_set_common(mch, add, NULL, NULL, NULL, NULL, arg); 3778 } 3779 3780 /* 3781 * Sets up the client resources and enable the polling interface over all the 3782 * SRS's and the soft rings of the client 3783 */ 3784 void 3785 mac_client_poll_enable(mac_client_handle_t mch) 3786 { 3787 mac_client_impl_t *mcip = (mac_client_impl_t *)mch; 3788 mac_soft_ring_set_t *mac_srs; 3789 flow_entry_t *flent; 3790 int i; 3791 3792 flent = mcip->mci_flent; 3793 ASSERT(flent != NULL); 3794 3795 mcip->mci_state_flags |= MCIS_CLIENT_POLL_CAPABLE; 3796 for (i = 0; i < flent->fe_rx_srs_cnt; i++) { 3797 mac_srs = (mac_soft_ring_set_t *)flent->fe_rx_srs[i]; 3798 ASSERT(mac_srs->srs_mcip == mcip); 3799 mac_srs_client_poll_enable(mcip, mac_srs); 3800 } 3801 } 3802 3803 /* 3804 * Tears down the client resources and disable the polling interface over all 3805 * the SRS's and the soft rings of the client 3806 */ 3807 void 3808 mac_client_poll_disable(mac_client_handle_t mch) 3809 { 3810 mac_client_impl_t *mcip = (mac_client_impl_t *)mch; 3811 mac_soft_ring_set_t *mac_srs; 3812 flow_entry_t *flent; 3813 int i; 3814 3815 flent = mcip->mci_flent; 3816 ASSERT(flent != NULL); 3817 3818 mcip->mci_state_flags &= ~MCIS_CLIENT_POLL_CAPABLE; 3819 for (i = 0; i < flent->fe_rx_srs_cnt; i++) { 3820 mac_srs = (mac_soft_ring_set_t *)flent->fe_rx_srs[i]; 3821 ASSERT(mac_srs->srs_mcip == mcip); 3822 mac_srs_client_poll_disable(mcip, mac_srs); 3823 } 3824 } 3825 3826 /* 3827 * Associate the CPUs specified by the given property with a MAC client. 3828 */ 3829 int 3830 mac_cpu_set(mac_client_handle_t mch, mac_resource_props_t *mrp) 3831 { 3832 mac_client_impl_t *mcip = (mac_client_impl_t *)mch; 3833 mac_impl_t *mip = mcip->mci_mip; 3834 int err = 0; 3835 3836 ASSERT(MAC_PERIM_HELD((mac_handle_t)mip)); 3837 3838 if ((err = mac_validate_props(mcip->mci_state_flags & MCIS_IS_VNIC ? 3839 mcip->mci_upper_mip : mip, mrp)) != 0) { 3840 return (err); 3841 } 3842 if (MCIP_DATAPATH_SETUP(mcip)) 3843 mac_flow_modify(mip->mi_flow_tab, mcip->mci_flent, mrp); 3844 3845 mac_update_resources(mrp, MCIP_RESOURCE_PROPS(mcip), B_FALSE); 3846 return (0); 3847 } 3848 3849 /* 3850 * Apply the specified properties to the specified MAC client. 3851 */ 3852 int 3853 mac_client_set_resources(mac_client_handle_t mch, mac_resource_props_t *mrp) 3854 { 3855 mac_client_impl_t *mcip = (mac_client_impl_t *)mch; 3856 mac_impl_t *mip = mcip->mci_mip; 3857 int err = 0; 3858 3859 i_mac_perim_enter(mip); 3860 3861 if ((mrp->mrp_mask & MRP_MAXBW) || (mrp->mrp_mask & MRP_PRIORITY)) { 3862 err = mac_resource_ctl_set(mch, mrp); 3863 if (err != 0) 3864 goto done; 3865 } 3866 3867 if (mrp->mrp_mask & (MRP_CPUS|MRP_POOL)) { 3868 err = mac_cpu_set(mch, mrp); 3869 if (err != 0) 3870 goto done; 3871 } 3872 3873 if (mrp->mrp_mask & MRP_PROTECT) { 3874 err = mac_protect_set(mch, mrp); 3875 if (err != 0) 3876 goto done; 3877 } 3878 3879 if ((mrp->mrp_mask & MRP_RX_RINGS) || (mrp->mrp_mask & MRP_TX_RINGS)) 3880 err = mac_resource_ctl_set(mch, mrp); 3881 3882 done: 3883 i_mac_perim_exit(mip); 3884 return (err); 3885 } 3886 3887 /* 3888 * Return the properties currently associated with the specified MAC client. 3889 */ 3890 void 3891 mac_client_get_resources(mac_client_handle_t mch, mac_resource_props_t *mrp) 3892 { 3893 mac_client_impl_t *mcip = (mac_client_impl_t *)mch; 3894 mac_resource_props_t *mcip_mrp = MCIP_RESOURCE_PROPS(mcip); 3895 3896 bcopy(mcip_mrp, mrp, sizeof (mac_resource_props_t)); 3897 } 3898 3899 /* 3900 * Return the effective properties currently associated with the specified 3901 * MAC client. 3902 */ 3903 void 3904 mac_client_get_effective_resources(mac_client_handle_t mch, 3905 mac_resource_props_t *mrp) 3906 { 3907 mac_client_impl_t *mcip = (mac_client_impl_t *)mch; 3908 mac_resource_props_t *mcip_mrp = MCIP_EFFECTIVE_PROPS(mcip); 3909 3910 bcopy(mcip_mrp, mrp, sizeof (mac_resource_props_t)); 3911 } 3912 3913 /* 3914 * Pass a copy of the specified packet to the promiscuous callbacks 3915 * of the specified MAC. 3916 * 3917 * If sender is NULL, the function is being invoked for a packet chain 3918 * received from the wire. If sender is non-NULL, it points to 3919 * the MAC client from which the packet is being sent. 3920 * 3921 * The packets are distributed to the promiscuous callbacks as follows: 3922 * 3923 * - all packets are sent to the MAC_CLIENT_PROMISC_ALL callbacks 3924 * - all broadcast and multicast packets are sent to the 3925 * MAC_CLIENT_PROMISC_FILTER and MAC_CLIENT_PROMISC_MULTI. 3926 * 3927 * The unicast packets of MAC_CLIENT_PROMISC_FILTER callbacks are dispatched 3928 * after classification by mac_rx_deliver(). 3929 */ 3930 3931 static void 3932 mac_promisc_dispatch_one(mac_promisc_impl_t *mpip, mblk_t *mp, 3933 boolean_t loopback) 3934 { 3935 mblk_t *mp_copy, *mp_next; 3936 3937 if (!mpip->mpi_no_copy || mpip->mpi_strip_vlan_tag) { 3938 mp_copy = copymsg(mp); 3939 if (mp_copy == NULL) 3940 return; 3941 3942 if (mpip->mpi_strip_vlan_tag) { 3943 mp_copy = mac_strip_vlan_tag_chain(mp_copy); 3944 if (mp_copy == NULL) 3945 return; 3946 } 3947 mp_next = NULL; 3948 } else { 3949 mp_copy = mp; 3950 mp_next = mp->b_next; 3951 } 3952 mp_copy->b_next = NULL; 3953 3954 mpip->mpi_fn(mpip->mpi_arg, NULL, mp_copy, loopback); 3955 if (mp_copy == mp) 3956 mp->b_next = mp_next; 3957 } 3958 3959 /* 3960 * Return the VID of a packet. Zero if the packet is not tagged. 3961 */ 3962 static uint16_t 3963 mac_ether_vid(mblk_t *mp) 3964 { 3965 struct ether_header *eth = (struct ether_header *)mp->b_rptr; 3966 3967 if (ntohs(eth->ether_type) == ETHERTYPE_VLAN) { 3968 struct ether_vlan_header *t_evhp = 3969 (struct ether_vlan_header *)mp->b_rptr; 3970 return (VLAN_ID(ntohs(t_evhp->ether_tci))); 3971 } 3972 3973 return (0); 3974 } 3975 3976 /* 3977 * Return whether the specified packet contains a multicast or broadcast 3978 * destination MAC address. 3979 */ 3980 static boolean_t 3981 mac_is_mcast(mac_impl_t *mip, mblk_t *mp) 3982 { 3983 mac_header_info_t hdr_info; 3984 3985 if (mac_header_info((mac_handle_t)mip, mp, &hdr_info) != 0) 3986 return (B_FALSE); 3987 return ((hdr_info.mhi_dsttype == MAC_ADDRTYPE_BROADCAST) || 3988 (hdr_info.mhi_dsttype == MAC_ADDRTYPE_MULTICAST)); 3989 } 3990 3991 /* 3992 * Send a copy of an mblk chain to the MAC clients of the specified MAC. 3993 * "sender" points to the sender MAC client for outbound packets, and 3994 * is set to NULL for inbound packets. 3995 */ 3996 void 3997 mac_promisc_dispatch(mac_impl_t *mip, mblk_t *mp_chain, 3998 mac_client_impl_t *sender) 3999 { 4000 mac_promisc_impl_t *mpip; 4001 mac_cb_t *mcb; 4002 mblk_t *mp; 4003 boolean_t is_mcast, is_sender; 4004 4005 MAC_PROMISC_WALKER_INC(mip); 4006 for (mp = mp_chain; mp != NULL; mp = mp->b_next) { 4007 is_mcast = mac_is_mcast(mip, mp); 4008 /* send packet to interested callbacks */ 4009 for (mcb = mip->mi_promisc_list; mcb != NULL; 4010 mcb = mcb->mcb_nextp) { 4011 mpip = (mac_promisc_impl_t *)mcb->mcb_objp; 4012 is_sender = (mpip->mpi_mcip == sender); 4013 4014 if (is_sender && mpip->mpi_no_tx_loop) 4015 /* 4016 * The sender doesn't want to receive 4017 * copies of the packets it sends. 4018 */ 4019 continue; 4020 4021 /* this client doesn't need any packets (bridge) */ 4022 if (mpip->mpi_fn == NULL) 4023 continue; 4024 4025 /* 4026 * For an ethernet MAC, don't displatch a multicast 4027 * packet to a non-PROMISC_ALL callbacks unless the VID 4028 * of the packet matches the VID of the client. 4029 */ 4030 if (is_mcast && 4031 mpip->mpi_type != MAC_CLIENT_PROMISC_ALL && 4032 !mac_client_check_flow_vid(mpip->mpi_mcip, 4033 mac_ether_vid(mp))) 4034 continue; 4035 4036 if (is_sender || 4037 mpip->mpi_type == MAC_CLIENT_PROMISC_ALL || 4038 is_mcast) 4039 mac_promisc_dispatch_one(mpip, mp, is_sender); 4040 } 4041 } 4042 MAC_PROMISC_WALKER_DCR(mip); 4043 } 4044 4045 void 4046 mac_promisc_client_dispatch(mac_client_impl_t *mcip, mblk_t *mp_chain) 4047 { 4048 mac_impl_t *mip = mcip->mci_mip; 4049 mac_promisc_impl_t *mpip; 4050 boolean_t is_mcast; 4051 mblk_t *mp; 4052 mac_cb_t *mcb; 4053 4054 /* 4055 * The unicast packets for the MAC client still 4056 * need to be delivered to the MAC_CLIENT_PROMISC_FILTERED 4057 * promiscuous callbacks. The broadcast and multicast 4058 * packets were delivered from mac_rx(). 4059 */ 4060 MAC_PROMISC_WALKER_INC(mip); 4061 for (mp = mp_chain; mp != NULL; mp = mp->b_next) { 4062 is_mcast = mac_is_mcast(mip, mp); 4063 for (mcb = mcip->mci_promisc_list; mcb != NULL; 4064 mcb = mcb->mcb_nextp) { 4065 mpip = (mac_promisc_impl_t *)mcb->mcb_objp; 4066 if (mpip->mpi_type == MAC_CLIENT_PROMISC_FILTERED && 4067 !is_mcast) { 4068 mac_promisc_dispatch_one(mpip, mp, B_FALSE); 4069 } 4070 } 4071 } 4072 MAC_PROMISC_WALKER_DCR(mip); 4073 } 4074 4075 /* 4076 * Return the margin value currently assigned to the specified MAC instance. 4077 */ 4078 void 4079 mac_margin_get(mac_handle_t mh, uint32_t *marginp) 4080 { 4081 mac_impl_t *mip = (mac_impl_t *)mh; 4082 4083 rw_enter(&(mip->mi_rw_lock), RW_READER); 4084 *marginp = mip->mi_margin; 4085 rw_exit(&(mip->mi_rw_lock)); 4086 } 4087 4088 /* 4089 * mac_info_get() is used for retrieving the mac_info when a DL_INFO_REQ is 4090 * issued before a DL_ATTACH_REQ. we walk the i_mac_impl_hash table and find 4091 * the first mac_impl_t with a matching driver name; then we copy its mac_info_t 4092 * to the caller. we do all this with i_mac_impl_lock held so the mac_impl_t 4093 * cannot disappear while we are accessing it. 4094 */ 4095 typedef struct i_mac_info_state_s { 4096 const char *mi_name; 4097 mac_info_t *mi_infop; 4098 } i_mac_info_state_t; 4099 4100 /*ARGSUSED*/ 4101 static uint_t 4102 i_mac_info_walker(mod_hash_key_t key, mod_hash_val_t *val, void *arg) 4103 { 4104 i_mac_info_state_t *statep = arg; 4105 mac_impl_t *mip = (mac_impl_t *)val; 4106 4107 if (mip->mi_state_flags & MIS_DISABLED) 4108 return (MH_WALK_CONTINUE); 4109 4110 if (strcmp(statep->mi_name, 4111 ddi_driver_name(mip->mi_dip)) != 0) 4112 return (MH_WALK_CONTINUE); 4113 4114 statep->mi_infop = &mip->mi_info; 4115 return (MH_WALK_TERMINATE); 4116 } 4117 4118 boolean_t 4119 mac_info_get(const char *name, mac_info_t *minfop) 4120 { 4121 i_mac_info_state_t state; 4122 4123 rw_enter(&i_mac_impl_lock, RW_READER); 4124 state.mi_name = name; 4125 state.mi_infop = NULL; 4126 mod_hash_walk(i_mac_impl_hash, i_mac_info_walker, &state); 4127 if (state.mi_infop == NULL) { 4128 rw_exit(&i_mac_impl_lock); 4129 return (B_FALSE); 4130 } 4131 *minfop = *state.mi_infop; 4132 rw_exit(&i_mac_impl_lock); 4133 return (B_TRUE); 4134 } 4135 4136 /* 4137 * To get the capabilities that MAC layer cares about, such as rings, factory 4138 * mac address, vnic or not, it should directly invoke this function. If the 4139 * link is part of a bridge, then the only "capability" it has is the inability 4140 * to do zero copy. 4141 */ 4142 boolean_t 4143 i_mac_capab_get(mac_handle_t mh, mac_capab_t cap, void *cap_data) 4144 { 4145 mac_impl_t *mip = (mac_impl_t *)mh; 4146 4147 if (mip->mi_bridge_link != NULL) 4148 return (cap == MAC_CAPAB_NO_ZCOPY); 4149 else if (mip->mi_callbacks->mc_callbacks & MC_GETCAPAB) 4150 return (mip->mi_getcapab(mip->mi_driver, cap, cap_data)); 4151 else 4152 return (B_FALSE); 4153 } 4154 4155 /* 4156 * Capability query function. If number of active mac clients is greater than 4157 * 1, only limited capabilities can be advertised to the caller no matter the 4158 * driver has certain capability or not. Else, we query the driver to get the 4159 * capability. 4160 */ 4161 boolean_t 4162 mac_capab_get(mac_handle_t mh, mac_capab_t cap, void *cap_data) 4163 { 4164 mac_impl_t *mip = (mac_impl_t *)mh; 4165 4166 /* 4167 * if mi_nactiveclients > 1, only MAC_CAPAB_LEGACY, MAC_CAPAB_HCKSUM, 4168 * MAC_CAPAB_NO_NATIVEVLAN and MAC_CAPAB_NO_ZCOPY can be advertised. 4169 */ 4170 if (mip->mi_nactiveclients > 1) { 4171 switch (cap) { 4172 case MAC_CAPAB_NO_ZCOPY: 4173 return (B_TRUE); 4174 case MAC_CAPAB_LEGACY: 4175 case MAC_CAPAB_HCKSUM: 4176 case MAC_CAPAB_NO_NATIVEVLAN: 4177 break; 4178 default: 4179 return (B_FALSE); 4180 } 4181 } 4182 4183 /* else get capab from driver */ 4184 return (i_mac_capab_get(mh, cap, cap_data)); 4185 } 4186 4187 boolean_t 4188 mac_sap_verify(mac_handle_t mh, uint32_t sap, uint32_t *bind_sap) 4189 { 4190 mac_impl_t *mip = (mac_impl_t *)mh; 4191 4192 return (mip->mi_type->mt_ops.mtops_sap_verify(sap, bind_sap, 4193 mip->mi_pdata)); 4194 } 4195 4196 mblk_t * 4197 mac_header(mac_handle_t mh, const uint8_t *daddr, uint32_t sap, mblk_t *payload, 4198 size_t extra_len) 4199 { 4200 mac_impl_t *mip = (mac_impl_t *)mh; 4201 const uint8_t *hdr_daddr; 4202 4203 /* 4204 * If the MAC is point-to-point with a fixed destination address, then 4205 * we must always use that destination in the MAC header. 4206 */ 4207 hdr_daddr = (mip->mi_dstaddr_set ? mip->mi_dstaddr : daddr); 4208 return (mip->mi_type->mt_ops.mtops_header(mip->mi_addr, hdr_daddr, sap, 4209 mip->mi_pdata, payload, extra_len)); 4210 } 4211 4212 int 4213 mac_header_info(mac_handle_t mh, mblk_t *mp, mac_header_info_t *mhip) 4214 { 4215 mac_impl_t *mip = (mac_impl_t *)mh; 4216 4217 return (mip->mi_type->mt_ops.mtops_header_info(mp, mip->mi_pdata, 4218 mhip)); 4219 } 4220 4221 int 4222 mac_vlan_header_info(mac_handle_t mh, mblk_t *mp, mac_header_info_t *mhip) 4223 { 4224 mac_impl_t *mip = (mac_impl_t *)mh; 4225 boolean_t is_ethernet = (mip->mi_info.mi_media == DL_ETHER); 4226 int err = 0; 4227 4228 /* 4229 * Packets should always be at least 16 bit aligned. 4230 */ 4231 ASSERT(IS_P2ALIGNED(mp->b_rptr, sizeof (uint16_t))); 4232 4233 if ((err = mac_header_info(mh, mp, mhip)) != 0) 4234 return (err); 4235 4236 /* 4237 * If this is a VLAN-tagged Ethernet packet, then the SAP in the 4238 * mac_header_info_t as returned by mac_header_info() is 4239 * ETHERTYPE_VLAN. We need to grab the ethertype from the VLAN header. 4240 */ 4241 if (is_ethernet && (mhip->mhi_bindsap == ETHERTYPE_VLAN)) { 4242 struct ether_vlan_header *evhp; 4243 uint16_t sap; 4244 mblk_t *tmp = NULL; 4245 size_t size; 4246 4247 size = sizeof (struct ether_vlan_header); 4248 if (MBLKL(mp) < size) { 4249 /* 4250 * Pullup the message in order to get the MAC header 4251 * infomation. Note that this is a read-only function, 4252 * we keep the input packet intact. 4253 */ 4254 if ((tmp = msgpullup(mp, size)) == NULL) 4255 return (EINVAL); 4256 4257 mp = tmp; 4258 } 4259 evhp = (struct ether_vlan_header *)mp->b_rptr; 4260 sap = ntohs(evhp->ether_type); 4261 (void) mac_sap_verify(mh, sap, &mhip->mhi_bindsap); 4262 mhip->mhi_hdrsize = sizeof (struct ether_vlan_header); 4263 mhip->mhi_tci = ntohs(evhp->ether_tci); 4264 mhip->mhi_istagged = B_TRUE; 4265 freemsg(tmp); 4266 4267 if (VLAN_CFI(mhip->mhi_tci) != ETHER_CFI) 4268 return (EINVAL); 4269 } else { 4270 mhip->mhi_istagged = B_FALSE; 4271 mhip->mhi_tci = 0; 4272 } 4273 4274 return (0); 4275 } 4276 4277 mblk_t * 4278 mac_header_cook(mac_handle_t mh, mblk_t *mp) 4279 { 4280 mac_impl_t *mip = (mac_impl_t *)mh; 4281 4282 if (mip->mi_type->mt_ops.mtops_ops & MTOPS_HEADER_COOK) { 4283 if (DB_REF(mp) > 1) { 4284 mblk_t *newmp = copymsg(mp); 4285 if (newmp == NULL) 4286 return (NULL); 4287 freemsg(mp); 4288 mp = newmp; 4289 } 4290 return (mip->mi_type->mt_ops.mtops_header_cook(mp, 4291 mip->mi_pdata)); 4292 } 4293 return (mp); 4294 } 4295 4296 mblk_t * 4297 mac_header_uncook(mac_handle_t mh, mblk_t *mp) 4298 { 4299 mac_impl_t *mip = (mac_impl_t *)mh; 4300 4301 if (mip->mi_type->mt_ops.mtops_ops & MTOPS_HEADER_UNCOOK) { 4302 if (DB_REF(mp) > 1) { 4303 mblk_t *newmp = copymsg(mp); 4304 if (newmp == NULL) 4305 return (NULL); 4306 freemsg(mp); 4307 mp = newmp; 4308 } 4309 return (mip->mi_type->mt_ops.mtops_header_uncook(mp, 4310 mip->mi_pdata)); 4311 } 4312 return (mp); 4313 } 4314 4315 uint_t 4316 mac_addr_len(mac_handle_t mh) 4317 { 4318 mac_impl_t *mip = (mac_impl_t *)mh; 4319 4320 return (mip->mi_type->mt_addr_length); 4321 } 4322 4323 /* True if a MAC is a VNIC */ 4324 boolean_t 4325 mac_is_vnic(mac_handle_t mh) 4326 { 4327 return (((mac_impl_t *)mh)->mi_state_flags & MIS_IS_VNIC); 4328 } 4329 4330 mac_handle_t 4331 mac_get_lower_mac_handle(mac_handle_t mh) 4332 { 4333 mac_impl_t *mip = (mac_impl_t *)mh; 4334 4335 ASSERT(mac_is_vnic(mh)); 4336 return (((vnic_t *)mip->mi_driver)->vn_lower_mh); 4337 } 4338 4339 boolean_t 4340 mac_is_vnic_primary(mac_handle_t mh) 4341 { 4342 mac_impl_t *mip = (mac_impl_t *)mh; 4343 4344 ASSERT(mac_is_vnic(mh)); 4345 return (((vnic_t *)mip->mi_driver)->vn_addr_type == 4346 VNIC_MAC_ADDR_TYPE_PRIMARY); 4347 } 4348 4349 void 4350 mac_update_resources(mac_resource_props_t *nmrp, mac_resource_props_t *cmrp, 4351 boolean_t is_user_flow) 4352 { 4353 if (nmrp != NULL && cmrp != NULL) { 4354 if (nmrp->mrp_mask & MRP_PRIORITY) { 4355 if (nmrp->mrp_priority == MPL_RESET) { 4356 cmrp->mrp_mask &= ~MRP_PRIORITY; 4357 if (is_user_flow) { 4358 cmrp->mrp_priority = 4359 MPL_SUBFLOW_DEFAULT; 4360 } else { 4361 cmrp->mrp_priority = MPL_LINK_DEFAULT; 4362 } 4363 } else { 4364 cmrp->mrp_mask |= MRP_PRIORITY; 4365 cmrp->mrp_priority = nmrp->mrp_priority; 4366 } 4367 } 4368 if (nmrp->mrp_mask & MRP_MAXBW) { 4369 if (nmrp->mrp_maxbw == MRP_MAXBW_RESETVAL) { 4370 cmrp->mrp_mask &= ~MRP_MAXBW; 4371 cmrp->mrp_maxbw = 0; 4372 } else { 4373 cmrp->mrp_mask |= MRP_MAXBW; 4374 cmrp->mrp_maxbw = nmrp->mrp_maxbw; 4375 } 4376 } 4377 if (nmrp->mrp_mask & MRP_CPUS) 4378 MAC_COPY_CPUS(nmrp, cmrp); 4379 4380 if (nmrp->mrp_mask & MRP_POOL) { 4381 if (strlen(nmrp->mrp_pool) == 0) { 4382 cmrp->mrp_mask &= ~MRP_POOL; 4383 bzero(cmrp->mrp_pool, sizeof (cmrp->mrp_pool)); 4384 } else { 4385 cmrp->mrp_mask |= MRP_POOL; 4386 (void) strncpy(cmrp->mrp_pool, nmrp->mrp_pool, 4387 sizeof (cmrp->mrp_pool)); 4388 } 4389 4390 } 4391 4392 if (nmrp->mrp_mask & MRP_PROTECT) 4393 mac_protect_update(nmrp, cmrp); 4394 4395 /* 4396 * Update the rings specified. 4397 */ 4398 if (nmrp->mrp_mask & MRP_RX_RINGS) { 4399 if (nmrp->mrp_mask & MRP_RINGS_RESET) { 4400 cmrp->mrp_mask &= ~MRP_RX_RINGS; 4401 if (cmrp->mrp_mask & MRP_RXRINGS_UNSPEC) 4402 cmrp->mrp_mask &= ~MRP_RXRINGS_UNSPEC; 4403 cmrp->mrp_nrxrings = 0; 4404 } else { 4405 cmrp->mrp_mask |= MRP_RX_RINGS; 4406 cmrp->mrp_nrxrings = nmrp->mrp_nrxrings; 4407 } 4408 } 4409 if (nmrp->mrp_mask & MRP_TX_RINGS) { 4410 if (nmrp->mrp_mask & MRP_RINGS_RESET) { 4411 cmrp->mrp_mask &= ~MRP_TX_RINGS; 4412 if (cmrp->mrp_mask & MRP_TXRINGS_UNSPEC) 4413 cmrp->mrp_mask &= ~MRP_TXRINGS_UNSPEC; 4414 cmrp->mrp_ntxrings = 0; 4415 } else { 4416 cmrp->mrp_mask |= MRP_TX_RINGS; 4417 cmrp->mrp_ntxrings = nmrp->mrp_ntxrings; 4418 } 4419 } 4420 if (nmrp->mrp_mask & MRP_RXRINGS_UNSPEC) 4421 cmrp->mrp_mask |= MRP_RXRINGS_UNSPEC; 4422 else if (cmrp->mrp_mask & MRP_RXRINGS_UNSPEC) 4423 cmrp->mrp_mask &= ~MRP_RXRINGS_UNSPEC; 4424 4425 if (nmrp->mrp_mask & MRP_TXRINGS_UNSPEC) 4426 cmrp->mrp_mask |= MRP_TXRINGS_UNSPEC; 4427 else if (cmrp->mrp_mask & MRP_TXRINGS_UNSPEC) 4428 cmrp->mrp_mask &= ~MRP_TXRINGS_UNSPEC; 4429 } 4430 } 4431 4432 /* 4433 * i_mac_set_resources: 4434 * 4435 * This routine associates properties with the primary MAC client of 4436 * the specified MAC instance. 4437 * - Cache the properties in mac_impl_t 4438 * - Apply the properties to the primary MAC client if exists 4439 */ 4440 int 4441 i_mac_set_resources(mac_handle_t mh, mac_resource_props_t *mrp) 4442 { 4443 mac_impl_t *mip = (mac_impl_t *)mh; 4444 mac_client_impl_t *mcip; 4445 int err = 0; 4446 uint32_t resmask, newresmask; 4447 mac_resource_props_t *tmrp, *umrp; 4448 4449 ASSERT(MAC_PERIM_HELD((mac_handle_t)mip)); 4450 4451 err = mac_validate_props(mip, mrp); 4452 if (err != 0) 4453 return (err); 4454 4455 umrp = kmem_zalloc(sizeof (*umrp), KM_SLEEP); 4456 bcopy(&mip->mi_resource_props, umrp, sizeof (*umrp)); 4457 resmask = umrp->mrp_mask; 4458 mac_update_resources(mrp, umrp, B_FALSE); 4459 newresmask = umrp->mrp_mask; 4460 4461 if (resmask == 0 && newresmask != 0) { 4462 /* 4463 * Bandwidth, priority, cpu or pool link properties configured, 4464 * must disable fastpath. 4465 */ 4466 if ((err = mac_fastpath_disable((mac_handle_t)mip)) != 0) { 4467 kmem_free(umrp, sizeof (*umrp)); 4468 return (err); 4469 } 4470 } 4471 4472 /* 4473 * Since bind_cpu may be modified by mac_client_set_resources() 4474 * we use a copy of bind_cpu and finally cache bind_cpu in mip. 4475 * This allows us to cache only user edits in mip. 4476 */ 4477 tmrp = kmem_zalloc(sizeof (*tmrp), KM_SLEEP); 4478 bcopy(mrp, tmrp, sizeof (*tmrp)); 4479 mcip = mac_primary_client_handle(mip); 4480 if (mcip != NULL && (mcip->mci_state_flags & MCIS_IS_AGGR_PORT) == 0) { 4481 err = mac_client_set_resources((mac_client_handle_t)mcip, tmrp); 4482 } else if ((mrp->mrp_mask & MRP_RX_RINGS || 4483 mrp->mrp_mask & MRP_TX_RINGS)) { 4484 mac_client_impl_t *vmcip; 4485 4486 /* 4487 * If the primary is not up, we need to check if there 4488 * are any VLANs on this primary. If there are then 4489 * we need to set this property on the VLANs since 4490 * VLANs follow the primary they are based on. Just 4491 * look for the first VLAN and change its properties, 4492 * all the other VLANs should be in the same group. 4493 */ 4494 for (vmcip = mip->mi_clients_list; vmcip != NULL; 4495 vmcip = vmcip->mci_client_next) { 4496 if ((vmcip->mci_flent->fe_type & FLOW_PRIMARY_MAC) && 4497 mac_client_vid((mac_client_handle_t)vmcip) != 4498 VLAN_ID_NONE) { 4499 break; 4500 } 4501 } 4502 if (vmcip != NULL) { 4503 mac_resource_props_t *omrp; 4504 mac_resource_props_t *vmrp; 4505 4506 omrp = kmem_zalloc(sizeof (*omrp), KM_SLEEP); 4507 bcopy(MCIP_RESOURCE_PROPS(vmcip), omrp, sizeof (*omrp)); 4508 /* 4509 * We dont' call mac_update_resources since we 4510 * want to take only the ring properties and 4511 * not all the properties that may have changed. 4512 */ 4513 vmrp = MCIP_RESOURCE_PROPS(vmcip); 4514 if (mrp->mrp_mask & MRP_RX_RINGS) { 4515 if (mrp->mrp_mask & MRP_RINGS_RESET) { 4516 vmrp->mrp_mask &= ~MRP_RX_RINGS; 4517 if (vmrp->mrp_mask & 4518 MRP_RXRINGS_UNSPEC) { 4519 vmrp->mrp_mask &= 4520 ~MRP_RXRINGS_UNSPEC; 4521 } 4522 vmrp->mrp_nrxrings = 0; 4523 } else { 4524 vmrp->mrp_mask |= MRP_RX_RINGS; 4525 vmrp->mrp_nrxrings = mrp->mrp_nrxrings; 4526 } 4527 } 4528 if (mrp->mrp_mask & MRP_TX_RINGS) { 4529 if (mrp->mrp_mask & MRP_RINGS_RESET) { 4530 vmrp->mrp_mask &= ~MRP_TX_RINGS; 4531 if (vmrp->mrp_mask & 4532 MRP_TXRINGS_UNSPEC) { 4533 vmrp->mrp_mask &= 4534 ~MRP_TXRINGS_UNSPEC; 4535 } 4536 vmrp->mrp_ntxrings = 0; 4537 } else { 4538 vmrp->mrp_mask |= MRP_TX_RINGS; 4539 vmrp->mrp_ntxrings = mrp->mrp_ntxrings; 4540 } 4541 } 4542 if (mrp->mrp_mask & MRP_RXRINGS_UNSPEC) 4543 vmrp->mrp_mask |= MRP_RXRINGS_UNSPEC; 4544 4545 if (mrp->mrp_mask & MRP_TXRINGS_UNSPEC) 4546 vmrp->mrp_mask |= MRP_TXRINGS_UNSPEC; 4547 4548 if ((err = mac_client_set_rings_prop(vmcip, mrp, 4549 omrp)) != 0) { 4550 bcopy(omrp, MCIP_RESOURCE_PROPS(vmcip), 4551 sizeof (*omrp)); 4552 } else { 4553 mac_set_prim_vlan_rings(mip, vmrp); 4554 } 4555 kmem_free(omrp, sizeof (*omrp)); 4556 } 4557 } 4558 4559 /* Only update the values if mac_client_set_resources succeeded */ 4560 if (err == 0) { 4561 bcopy(umrp, &mip->mi_resource_props, sizeof (*umrp)); 4562 /* 4563 * If bandwidth, priority or cpu link properties cleared, 4564 * renable fastpath. 4565 */ 4566 if (resmask != 0 && newresmask == 0) 4567 mac_fastpath_enable((mac_handle_t)mip); 4568 } else if (resmask == 0 && newresmask != 0) { 4569 mac_fastpath_enable((mac_handle_t)mip); 4570 } 4571 kmem_free(tmrp, sizeof (*tmrp)); 4572 kmem_free(umrp, sizeof (*umrp)); 4573 return (err); 4574 } 4575 4576 int 4577 mac_set_resources(mac_handle_t mh, mac_resource_props_t *mrp) 4578 { 4579 int err; 4580 4581 i_mac_perim_enter((mac_impl_t *)mh); 4582 err = i_mac_set_resources(mh, mrp); 4583 i_mac_perim_exit((mac_impl_t *)mh); 4584 return (err); 4585 } 4586 4587 /* 4588 * Get the properties cached for the specified MAC instance. 4589 */ 4590 void 4591 mac_get_resources(mac_handle_t mh, mac_resource_props_t *mrp) 4592 { 4593 mac_impl_t *mip = (mac_impl_t *)mh; 4594 mac_client_impl_t *mcip; 4595 4596 mcip = mac_primary_client_handle(mip); 4597 if (mcip != NULL) { 4598 mac_client_get_resources((mac_client_handle_t)mcip, mrp); 4599 return; 4600 } 4601 bcopy(&mip->mi_resource_props, mrp, sizeof (mac_resource_props_t)); 4602 } 4603 4604 /* 4605 * Get the effective properties from the primary client of the 4606 * specified MAC instance. 4607 */ 4608 void 4609 mac_get_effective_resources(mac_handle_t mh, mac_resource_props_t *mrp) 4610 { 4611 mac_impl_t *mip = (mac_impl_t *)mh; 4612 mac_client_impl_t *mcip; 4613 4614 mcip = mac_primary_client_handle(mip); 4615 if (mcip != NULL) { 4616 mac_client_get_effective_resources((mac_client_handle_t)mcip, 4617 mrp); 4618 return; 4619 } 4620 bzero(mrp, sizeof (mac_resource_props_t)); 4621 } 4622 4623 int 4624 mac_set_pvid(mac_handle_t mh, uint16_t pvid) 4625 { 4626 mac_impl_t *mip = (mac_impl_t *)mh; 4627 mac_client_impl_t *mcip; 4628 mac_unicast_impl_t *muip; 4629 4630 i_mac_perim_enter(mip); 4631 if (pvid != 0) { 4632 for (mcip = mip->mi_clients_list; mcip != NULL; 4633 mcip = mcip->mci_client_next) { 4634 for (muip = mcip->mci_unicast_list; muip != NULL; 4635 muip = muip->mui_next) { 4636 if (muip->mui_vid == pvid) { 4637 i_mac_perim_exit(mip); 4638 return (EBUSY); 4639 } 4640 } 4641 } 4642 } 4643 mip->mi_pvid = pvid; 4644 i_mac_perim_exit(mip); 4645 return (0); 4646 } 4647 4648 uint16_t 4649 mac_get_pvid(mac_handle_t mh) 4650 { 4651 mac_impl_t *mip = (mac_impl_t *)mh; 4652 4653 return (mip->mi_pvid); 4654 } 4655 4656 uint32_t 4657 mac_get_llimit(mac_handle_t mh) 4658 { 4659 mac_impl_t *mip = (mac_impl_t *)mh; 4660 4661 return (mip->mi_llimit); 4662 } 4663 4664 uint32_t 4665 mac_get_ldecay(mac_handle_t mh) 4666 { 4667 mac_impl_t *mip = (mac_impl_t *)mh; 4668 4669 return (mip->mi_ldecay); 4670 } 4671 4672 /* 4673 * Rename a mac client, its flow, and the kstat. 4674 */ 4675 int 4676 mac_rename_primary(mac_handle_t mh, const char *new_name) 4677 { 4678 mac_impl_t *mip = (mac_impl_t *)mh; 4679 mac_client_impl_t *cur_clnt = NULL; 4680 flow_entry_t *fep; 4681 4682 i_mac_perim_enter(mip); 4683 4684 /* 4685 * VNICs: we need to change the sys flow name and 4686 * the associated flow kstat. 4687 */ 4688 if (mip->mi_state_flags & MIS_IS_VNIC) { 4689 mac_client_impl_t *mcip = mac_vnic_lower(mip); 4690 ASSERT(new_name != NULL); 4691 mac_rename_flow_names(mcip, new_name); 4692 mac_stat_rename(mcip); 4693 goto done; 4694 } 4695 /* 4696 * This mac may itself be an aggr link, or it may have some client 4697 * which is an aggr port. For both cases, we need to change the 4698 * aggr port's mac client name, its flow name and the associated flow 4699 * kstat. 4700 */ 4701 if (mip->mi_state_flags & MIS_IS_AGGR) { 4702 mac_capab_aggr_t aggr_cap; 4703 mac_rename_fn_t rename_fn; 4704 boolean_t ret; 4705 4706 ASSERT(new_name != NULL); 4707 ret = i_mac_capab_get((mac_handle_t)mip, MAC_CAPAB_AGGR, 4708 (void *)(&aggr_cap)); 4709 ASSERT(ret == B_TRUE); 4710 rename_fn = aggr_cap.mca_rename_fn; 4711 rename_fn(new_name, mip->mi_driver); 4712 /* 4713 * The aggr's client name and kstat flow name will be 4714 * updated below, i.e. via mac_rename_flow_names. 4715 */ 4716 } 4717 4718 for (cur_clnt = mip->mi_clients_list; cur_clnt != NULL; 4719 cur_clnt = cur_clnt->mci_client_next) { 4720 if (cur_clnt->mci_state_flags & MCIS_IS_AGGR_PORT) { 4721 if (new_name != NULL) { 4722 char *str_st = cur_clnt->mci_name; 4723 char *str_del = strchr(str_st, '-'); 4724 4725 ASSERT(str_del != NULL); 4726 bzero(str_del + 1, MAXNAMELEN - 4727 (str_del - str_st + 1)); 4728 bcopy(new_name, str_del + 1, 4729 strlen(new_name)); 4730 } 4731 fep = cur_clnt->mci_flent; 4732 mac_rename_flow(fep, cur_clnt->mci_name); 4733 break; 4734 } else if (new_name != NULL && 4735 cur_clnt->mci_state_flags & MCIS_USE_DATALINK_NAME) { 4736 mac_rename_flow_names(cur_clnt, new_name); 4737 break; 4738 } 4739 } 4740 4741 /* Recreate kstats associated with aggr pseudo rings */ 4742 if (mip->mi_state_flags & MIS_IS_AGGR) 4743 mac_pseudo_ring_stat_rename(mip); 4744 4745 done: 4746 i_mac_perim_exit(mip); 4747 return (0); 4748 } 4749 4750 /* 4751 * Rename the MAC client's flow names 4752 */ 4753 static void 4754 mac_rename_flow_names(mac_client_impl_t *mcip, const char *new_name) 4755 { 4756 flow_entry_t *flent; 4757 uint16_t vid; 4758 char flowname[MAXFLOWNAMELEN]; 4759 mac_impl_t *mip = mcip->mci_mip; 4760 4761 ASSERT(MAC_PERIM_HELD((mac_handle_t)mip)); 4762 4763 /* 4764 * Use mi_rw_lock to ensure that threads not in the mac perimeter 4765 * see a self-consistent value for mci_name 4766 */ 4767 rw_enter(&mip->mi_rw_lock, RW_WRITER); 4768 (void) strlcpy(mcip->mci_name, new_name, sizeof (mcip->mci_name)); 4769 rw_exit(&mip->mi_rw_lock); 4770 4771 mac_rename_flow(mcip->mci_flent, new_name); 4772 4773 if (mcip->mci_nflents == 1) 4774 return; 4775 4776 /* 4777 * We have to rename all the others too, no stats to destroy for 4778 * these. 4779 */ 4780 for (flent = mcip->mci_flent_list; flent != NULL; 4781 flent = flent->fe_client_next) { 4782 if (flent != mcip->mci_flent) { 4783 vid = i_mac_flow_vid(flent); 4784 (void) sprintf(flowname, "%s%u", new_name, vid); 4785 mac_flow_set_name(flent, flowname); 4786 } 4787 } 4788 } 4789 4790 4791 /* 4792 * Add a flow to the MAC client's flow list - i.e list of MAC/VID tuples 4793 * defined for the specified MAC client. 4794 */ 4795 static void 4796 mac_client_add_to_flow_list(mac_client_impl_t *mcip, flow_entry_t *flent) 4797 { 4798 ASSERT(MAC_PERIM_HELD((mac_handle_t)mcip->mci_mip)); 4799 /* 4800 * The promisc Rx data path walks the mci_flent_list. Protect by 4801 * using mi_rw_lock 4802 */ 4803 rw_enter(&mcip->mci_rw_lock, RW_WRITER); 4804 4805 mcip->mci_vidcache = MCIP_VIDCACHE_INVALID; 4806 4807 /* Add it to the head */ 4808 flent->fe_client_next = mcip->mci_flent_list; 4809 mcip->mci_flent_list = flent; 4810 mcip->mci_nflents++; 4811 4812 /* 4813 * Keep track of the number of non-zero VIDs addresses per MAC 4814 * client to avoid figuring it out in the data-path. 4815 */ 4816 if (i_mac_flow_vid(flent) != VLAN_ID_NONE) 4817 mcip->mci_nvids++; 4818 4819 rw_exit(&mcip->mci_rw_lock); 4820 } 4821 4822 /* 4823 * Remove a flow entry from the MAC client's list. 4824 */ 4825 static void 4826 mac_client_remove_flow_from_list(mac_client_impl_t *mcip, flow_entry_t *flent) 4827 { 4828 flow_entry_t *fe = mcip->mci_flent_list; 4829 flow_entry_t *prev_fe = NULL; 4830 4831 ASSERT(MAC_PERIM_HELD((mac_handle_t)mcip->mci_mip)); 4832 /* 4833 * The promisc Rx data path walks the mci_flent_list. Protect by 4834 * using mci_rw_lock 4835 */ 4836 rw_enter(&mcip->mci_rw_lock, RW_WRITER); 4837 mcip->mci_vidcache = MCIP_VIDCACHE_INVALID; 4838 4839 while ((fe != NULL) && (fe != flent)) { 4840 prev_fe = fe; 4841 fe = fe->fe_client_next; 4842 } 4843 4844 ASSERT(fe != NULL); 4845 if (prev_fe == NULL) { 4846 /* Deleting the first node */ 4847 mcip->mci_flent_list = fe->fe_client_next; 4848 } else { 4849 prev_fe->fe_client_next = fe->fe_client_next; 4850 } 4851 mcip->mci_nflents--; 4852 4853 if (i_mac_flow_vid(flent) != VLAN_ID_NONE) 4854 mcip->mci_nvids--; 4855 4856 rw_exit(&mcip->mci_rw_lock); 4857 } 4858 4859 /* 4860 * Check if the given VID belongs to this MAC client. 4861 */ 4862 boolean_t 4863 mac_client_check_flow_vid(mac_client_impl_t *mcip, uint16_t vid) 4864 { 4865 flow_entry_t *flent; 4866 uint16_t mci_vid; 4867 uint32_t cache = mcip->mci_vidcache; 4868 4869 /* 4870 * In hopes of not having to touch the mci_rw_lock, check to see if 4871 * this vid matches our cached result. 4872 */ 4873 if (MCIP_VIDCACHE_ISVALID(cache) && MCIP_VIDCACHE_VID(cache) == vid) 4874 return (MCIP_VIDCACHE_BOOL(cache) ? B_TRUE : B_FALSE); 4875 4876 /* The mci_flent_list is protected by mci_rw_lock */ 4877 rw_enter(&mcip->mci_rw_lock, RW_WRITER); 4878 for (flent = mcip->mci_flent_list; flent != NULL; 4879 flent = flent->fe_client_next) { 4880 mci_vid = i_mac_flow_vid(flent); 4881 if (vid == mci_vid) { 4882 mcip->mci_vidcache = MCIP_VIDCACHE_CACHE(vid, B_TRUE); 4883 rw_exit(&mcip->mci_rw_lock); 4884 return (B_TRUE); 4885 } 4886 } 4887 4888 mcip->mci_vidcache = MCIP_VIDCACHE_CACHE(vid, B_FALSE); 4889 rw_exit(&mcip->mci_rw_lock); 4890 return (B_FALSE); 4891 } 4892 4893 /* 4894 * Get the flow entry for the specified <MAC addr, VID> tuple. 4895 */ 4896 static flow_entry_t * 4897 mac_client_get_flow(mac_client_impl_t *mcip, mac_unicast_impl_t *muip) 4898 { 4899 mac_address_t *map = mcip->mci_unicast; 4900 flow_entry_t *flent; 4901 uint16_t vid; 4902 flow_desc_t flow_desc; 4903 4904 ASSERT(MAC_PERIM_HELD((mac_handle_t)mcip->mci_mip)); 4905 4906 mac_flow_get_desc(mcip->mci_flent, &flow_desc); 4907 if (bcmp(flow_desc.fd_dst_mac, map->ma_addr, map->ma_len) != 0) 4908 return (NULL); 4909 4910 for (flent = mcip->mci_flent_list; flent != NULL; 4911 flent = flent->fe_client_next) { 4912 vid = i_mac_flow_vid(flent); 4913 if (vid == muip->mui_vid) { 4914 return (flent); 4915 } 4916 } 4917 4918 return (NULL); 4919 } 4920 4921 /* 4922 * Since mci_flent has the SRSs, when we want to remove it, we replace 4923 * the flow_desc_t in mci_flent with that of an existing flent and then 4924 * remove that flent instead of mci_flent. 4925 */ 4926 static flow_entry_t * 4927 mac_client_swap_mciflent(mac_client_impl_t *mcip) 4928 { 4929 flow_entry_t *flent = mcip->mci_flent; 4930 flow_tab_t *ft = flent->fe_flow_tab; 4931 flow_entry_t *flent1; 4932 flow_desc_t fl_desc; 4933 char fl_name[MAXFLOWNAMELEN]; 4934 int err; 4935 4936 ASSERT(MAC_PERIM_HELD((mac_handle_t)mcip->mci_mip)); 4937 ASSERT(mcip->mci_nflents > 1); 4938 4939 /* get the next flent following the primary flent */ 4940 flent1 = mcip->mci_flent_list->fe_client_next; 4941 ASSERT(flent1 != NULL && flent1->fe_flow_tab == ft); 4942 4943 /* 4944 * Remove the flent from the flow table before updating the 4945 * flow descriptor as the hash depends on the flow descriptor. 4946 * This also helps incoming packet classification avoid having 4947 * to grab fe_lock. Access to fe_flow_desc of a flent not in the 4948 * flow table is done under the fe_lock so that log or stat functions 4949 * see a self-consistent fe_flow_desc. The name and desc are specific 4950 * to a flow, the rest are shared by all the clients, including 4951 * resource control etc. 4952 */ 4953 mac_flow_remove(ft, flent, B_TRUE); 4954 mac_flow_remove(ft, flent1, B_TRUE); 4955 4956 bcopy(&flent->fe_flow_desc, &fl_desc, sizeof (flow_desc_t)); 4957 bcopy(flent->fe_flow_name, fl_name, MAXFLOWNAMELEN); 4958 4959 /* update the primary flow entry */ 4960 mutex_enter(&flent->fe_lock); 4961 bcopy(&flent1->fe_flow_desc, &flent->fe_flow_desc, 4962 sizeof (flow_desc_t)); 4963 bcopy(&flent1->fe_flow_name, &flent->fe_flow_name, MAXFLOWNAMELEN); 4964 mutex_exit(&flent->fe_lock); 4965 4966 /* update the flow entry that is to be freed */ 4967 mutex_enter(&flent1->fe_lock); 4968 bcopy(&fl_desc, &flent1->fe_flow_desc, sizeof (flow_desc_t)); 4969 bcopy(fl_name, &flent1->fe_flow_name, MAXFLOWNAMELEN); 4970 mutex_exit(&flent1->fe_lock); 4971 4972 /* now reinsert the flow entries in the table */ 4973 err = mac_flow_add(ft, flent); 4974 ASSERT(err == 0); 4975 4976 err = mac_flow_add(ft, flent1); 4977 ASSERT(err == 0); 4978 4979 return (flent1); 4980 } 4981 4982 /* 4983 * Return whether there is only one flow entry associated with this 4984 * MAC client. 4985 */ 4986 static boolean_t 4987 mac_client_single_rcvr(mac_client_impl_t *mcip) 4988 { 4989 return (mcip->mci_nflents == 1); 4990 } 4991 4992 int 4993 mac_validate_props(mac_impl_t *mip, mac_resource_props_t *mrp) 4994 { 4995 boolean_t reset; 4996 uint32_t rings_needed; 4997 uint32_t rings_avail; 4998 mac_group_type_t gtype; 4999 mac_resource_props_t *mip_mrp; 5000 5001 if (mrp == NULL) 5002 return (0); 5003 5004 if (mrp->mrp_mask & MRP_PRIORITY) { 5005 mac_priority_level_t pri = mrp->mrp_priority; 5006 5007 if (pri < MPL_LOW || pri > MPL_RESET) 5008 return (EINVAL); 5009 } 5010 5011 if (mrp->mrp_mask & MRP_MAXBW) { 5012 uint64_t maxbw = mrp->mrp_maxbw; 5013 5014 if (maxbw < MRP_MAXBW_MINVAL && maxbw != 0) 5015 return (EINVAL); 5016 } 5017 if (mrp->mrp_mask & MRP_CPUS) { 5018 int i, j; 5019 mac_cpu_mode_t fanout; 5020 5021 if (mrp->mrp_ncpus > ncpus) 5022 return (EINVAL); 5023 5024 for (i = 0; i < mrp->mrp_ncpus; i++) { 5025 for (j = 0; j < mrp->mrp_ncpus; j++) { 5026 if (i != j && 5027 mrp->mrp_cpu[i] == mrp->mrp_cpu[j]) { 5028 return (EINVAL); 5029 } 5030 } 5031 } 5032 5033 for (i = 0; i < mrp->mrp_ncpus; i++) { 5034 cpu_t *cp; 5035 int rv; 5036 5037 mutex_enter(&cpu_lock); 5038 cp = cpu_get(mrp->mrp_cpu[i]); 5039 if (cp != NULL) 5040 rv = cpu_is_online(cp); 5041 else 5042 rv = 0; 5043 mutex_exit(&cpu_lock); 5044 if (rv == 0) 5045 return (EINVAL); 5046 } 5047 5048 fanout = mrp->mrp_fanout_mode; 5049 if (fanout < 0 || fanout > MCM_CPUS) 5050 return (EINVAL); 5051 } 5052 5053 if (mrp->mrp_mask & MRP_PROTECT) { 5054 int err = mac_protect_validate(mrp); 5055 if (err != 0) 5056 return (err); 5057 } 5058 5059 if (!(mrp->mrp_mask & MRP_RX_RINGS) && 5060 !(mrp->mrp_mask & MRP_TX_RINGS)) { 5061 return (0); 5062 } 5063 5064 /* 5065 * mip will be null when we come from mac_flow_create or 5066 * mac_link_flow_modify. In the latter case it is a user flow, 5067 * for which we don't support rings. In the former we would 5068 * have validated the props beforehand (i_mac_unicast_add -> 5069 * mac_client_set_resources -> validate for the primary and 5070 * vnic_dev_create -> mac_client_set_resources -> validate for 5071 * a vnic. 5072 */ 5073 if (mip == NULL) 5074 return (0); 5075 5076 /* 5077 * We don't support setting rings property for a VNIC that is using a 5078 * primary address (VLAN) 5079 */ 5080 if ((mip->mi_state_flags & MIS_IS_VNIC) && 5081 mac_is_vnic_primary((mac_handle_t)mip)) { 5082 return (ENOTSUP); 5083 } 5084 5085 mip_mrp = &mip->mi_resource_props; 5086 /* 5087 * The rings property should be validated against the NICs 5088 * resources 5089 */ 5090 if (mip->mi_state_flags & MIS_IS_VNIC) 5091 mip = (mac_impl_t *)mac_get_lower_mac_handle((mac_handle_t)mip); 5092 5093 reset = mrp->mrp_mask & MRP_RINGS_RESET; 5094 /* 5095 * If groups are not supported, return error. 5096 */ 5097 if (((mrp->mrp_mask & MRP_RX_RINGS) && mip->mi_rx_groups == NULL) || 5098 ((mrp->mrp_mask & MRP_TX_RINGS) && mip->mi_tx_groups == NULL)) { 5099 return (EINVAL); 5100 } 5101 /* 5102 * If we are just resetting, there is no validation needed. 5103 */ 5104 if (reset) 5105 return (0); 5106 5107 if (mrp->mrp_mask & MRP_RX_RINGS) { 5108 rings_needed = mrp->mrp_nrxrings; 5109 /* 5110 * We just want to check if the number of additional 5111 * rings requested is available. 5112 */ 5113 if (mip_mrp->mrp_mask & MRP_RX_RINGS) { 5114 if (mrp->mrp_nrxrings > mip_mrp->mrp_nrxrings) 5115 /* Just check for the additional rings */ 5116 rings_needed -= mip_mrp->mrp_nrxrings; 5117 else 5118 /* We are not asking for additional rings */ 5119 rings_needed = 0; 5120 } 5121 rings_avail = mip->mi_rxrings_avail; 5122 gtype = mip->mi_rx_group_type; 5123 } else { 5124 rings_needed = mrp->mrp_ntxrings; 5125 /* Similarly for the TX rings */ 5126 if (mip_mrp->mrp_mask & MRP_TX_RINGS) { 5127 if (mrp->mrp_ntxrings > mip_mrp->mrp_ntxrings) 5128 /* Just check for the additional rings */ 5129 rings_needed -= mip_mrp->mrp_ntxrings; 5130 else 5131 /* We are not asking for additional rings */ 5132 rings_needed = 0; 5133 } 5134 rings_avail = mip->mi_txrings_avail; 5135 gtype = mip->mi_tx_group_type; 5136 } 5137 5138 /* Error if the group is dynamic .. */ 5139 if (gtype == MAC_GROUP_TYPE_DYNAMIC) { 5140 /* 5141 * .. and rings specified are more than available. 5142 */ 5143 if (rings_needed > rings_avail) 5144 return (EINVAL); 5145 } else { 5146 /* 5147 * OR group is static and we have specified some rings. 5148 */ 5149 if (rings_needed > 0) 5150 return (EINVAL); 5151 } 5152 return (0); 5153 } 5154 5155 /* 5156 * Send a MAC_NOTE_LINK notification to all the MAC clients whenever the 5157 * underlying physical link is down. This is to allow MAC clients to 5158 * communicate with other clients. 5159 */ 5160 void 5161 mac_virtual_link_update(mac_impl_t *mip) 5162 { 5163 if (mip->mi_linkstate != LINK_STATE_UP) 5164 i_mac_notify(mip, MAC_NOTE_LINK); 5165 } 5166 5167 /* 5168 * For clients that have a pass-thru MAC, e.g. VNIC, we set the VNIC's 5169 * mac handle in the client. 5170 */ 5171 void 5172 mac_set_upper_mac(mac_client_handle_t mch, mac_handle_t mh, 5173 mac_resource_props_t *mrp) 5174 { 5175 mac_client_impl_t *mcip = (mac_client_impl_t *)mch; 5176 mac_impl_t *mip = (mac_impl_t *)mh; 5177 5178 mcip->mci_upper_mip = mip; 5179 /* If there are any properties, copy it over too */ 5180 if (mrp != NULL) { 5181 bcopy(mrp, &mip->mi_resource_props, 5182 sizeof (mac_resource_props_t)); 5183 } 5184 } 5185 5186 /* 5187 * Mark the mac as being used exclusively by the single mac client that is 5188 * doing some control operation on this mac. No further opens of this mac 5189 * will be allowed until this client calls mac_unmark_exclusive. The mac 5190 * client calling this function must already be in the mac perimeter 5191 */ 5192 int 5193 mac_mark_exclusive(mac_handle_t mh) 5194 { 5195 mac_impl_t *mip = (mac_impl_t *)mh; 5196 5197 ASSERT(MAC_PERIM_HELD(mh)); 5198 /* 5199 * Look up its entry in the global hash table. 5200 */ 5201 rw_enter(&i_mac_impl_lock, RW_WRITER); 5202 if (mip->mi_state_flags & MIS_DISABLED) { 5203 rw_exit(&i_mac_impl_lock); 5204 return (ENOENT); 5205 } 5206 5207 /* 5208 * A reference to mac is held even if the link is not plumbed. 5209 * In i_dls_link_create() we open the MAC interface and hold the 5210 * reference. There is an additional reference for the mac_open 5211 * done in acquiring the mac perimeter 5212 */ 5213 if (mip->mi_ref != 2) { 5214 rw_exit(&i_mac_impl_lock); 5215 return (EBUSY); 5216 } 5217 5218 ASSERT(!(mip->mi_state_flags & MIS_EXCLUSIVE_HELD)); 5219 mip->mi_state_flags |= MIS_EXCLUSIVE_HELD; 5220 rw_exit(&i_mac_impl_lock); 5221 return (0); 5222 } 5223 5224 void 5225 mac_unmark_exclusive(mac_handle_t mh) 5226 { 5227 mac_impl_t *mip = (mac_impl_t *)mh; 5228 5229 ASSERT(MAC_PERIM_HELD(mh)); 5230 5231 rw_enter(&i_mac_impl_lock, RW_WRITER); 5232 /* 1 for the creation and another for the perimeter */ 5233 ASSERT(mip->mi_ref == 2 && (mip->mi_state_flags & MIS_EXCLUSIVE_HELD)); 5234 mip->mi_state_flags &= ~MIS_EXCLUSIVE_HELD; 5235 rw_exit(&i_mac_impl_lock); 5236 } 5237 5238 /* 5239 * Set the MTU for the specified MAC. 5240 */ 5241 int 5242 mac_set_mtu(mac_handle_t mh, uint_t new_mtu, uint_t *old_mtu_arg) 5243 { 5244 mac_impl_t *mip = (mac_impl_t *)mh; 5245 uint_t old_mtu; 5246 int rv = 0; 5247 5248 i_mac_perim_enter(mip); 5249 5250 if (!(mip->mi_callbacks->mc_callbacks & (MC_SETPROP|MC_GETPROP))) { 5251 rv = ENOTSUP; 5252 goto bail; 5253 } 5254 5255 old_mtu = mip->mi_sdu_max; 5256 5257 if (new_mtu == 0 || new_mtu < mip->mi_sdu_min) { 5258 rv = EINVAL; 5259 goto bail; 5260 } 5261 5262 rw_enter(&mip->mi_rw_lock, RW_READER); 5263 if (mip->mi_mtrp != NULL && new_mtu < mip->mi_mtrp->mtr_mtu) { 5264 rv = EBUSY; 5265 rw_exit(&mip->mi_rw_lock); 5266 goto bail; 5267 } 5268 rw_exit(&mip->mi_rw_lock); 5269 5270 if (old_mtu != new_mtu) { 5271 rv = mip->mi_callbacks->mc_setprop(mip->mi_driver, 5272 "mtu", MAC_PROP_MTU, sizeof (uint_t), &new_mtu); 5273 if (rv != 0) 5274 goto bail; 5275 rv = mac_maxsdu_update(mh, new_mtu); 5276 ASSERT(rv == 0); 5277 } 5278 5279 bail: 5280 i_mac_perim_exit(mip); 5281 5282 if (rv == 0 && old_mtu_arg != NULL) 5283 *old_mtu_arg = old_mtu; 5284 return (rv); 5285 } 5286 5287 /* 5288 * Return the RX h/w information for the group indexed by grp_num. 5289 */ 5290 void 5291 mac_get_hwrxgrp_info(mac_handle_t mh, int grp_index, uint_t *grp_num, 5292 uint_t *n_rings, uint_t *rings, uint_t *type, uint_t *n_clnts, 5293 char *clnts_name) 5294 { 5295 mac_impl_t *mip = (mac_impl_t *)mh; 5296 mac_grp_client_t *mcip; 5297 uint_t i = 0, index = 0; 5298 mac_ring_t *ring; 5299 5300 /* Revisit when we implement fully dynamic group allocation */ 5301 ASSERT(grp_index >= 0 && grp_index < mip->mi_rx_group_count); 5302 5303 rw_enter(&mip->mi_rw_lock, RW_READER); 5304 *grp_num = mip->mi_rx_groups[grp_index].mrg_index; 5305 *type = mip->mi_rx_groups[grp_index].mrg_type; 5306 *n_rings = mip->mi_rx_groups[grp_index].mrg_cur_count; 5307 ring = mip->mi_rx_groups[grp_index].mrg_rings; 5308 for (index = 0; index < mip->mi_rx_groups[grp_index].mrg_cur_count; 5309 index++) { 5310 rings[index] = ring->mr_index; 5311 ring = ring->mr_next; 5312 } 5313 /* Assuming the 1st is the default group */ 5314 index = 0; 5315 if (grp_index == 0) { 5316 (void) strlcpy(clnts_name, "<default,mcast>,", 5317 MAXCLIENTNAMELEN); 5318 index += strlen("<default,mcast>,"); 5319 } 5320 for (mcip = mip->mi_rx_groups[grp_index].mrg_clients; mcip != NULL; 5321 mcip = mcip->mgc_next) { 5322 int name_len = strlen(mcip->mgc_client->mci_name); 5323 5324 /* 5325 * MAXCLIENTNAMELEN is the buffer size reserved for client 5326 * names. 5327 * XXXX Formating the client name string needs to be moved 5328 * to user land when fixing the size of dhi_clnts in 5329 * dld_hwgrpinfo_t. We should use n_clients * client_name for 5330 * dhi_clntsin instead of MAXCLIENTNAMELEN 5331 */ 5332 if (index + name_len >= MAXCLIENTNAMELEN) { 5333 index = MAXCLIENTNAMELEN; 5334 break; 5335 } 5336 bcopy(mcip->mgc_client->mci_name, &(clnts_name[index]), 5337 name_len); 5338 index += name_len; 5339 clnts_name[index++] = ','; 5340 i++; 5341 } 5342 5343 /* Get rid of the last , */ 5344 if (index > 0) 5345 clnts_name[index - 1] = '\0'; 5346 *n_clnts = i; 5347 rw_exit(&mip->mi_rw_lock); 5348 } 5349 5350 /* 5351 * Return the TX h/w information for the group indexed by grp_num. 5352 */ 5353 void 5354 mac_get_hwtxgrp_info(mac_handle_t mh, int grp_index, uint_t *grp_num, 5355 uint_t *n_rings, uint_t *rings, uint_t *type, uint_t *n_clnts, 5356 char *clnts_name) 5357 { 5358 mac_impl_t *mip = (mac_impl_t *)mh; 5359 mac_grp_client_t *mcip; 5360 uint_t i = 0, index = 0; 5361 mac_ring_t *ring; 5362 5363 /* Revisit when we implement fully dynamic group allocation */ 5364 ASSERT(grp_index >= 0 && grp_index <= mip->mi_tx_group_count); 5365 5366 rw_enter(&mip->mi_rw_lock, RW_READER); 5367 *grp_num = mip->mi_tx_groups[grp_index].mrg_index > 0 ? 5368 mip->mi_tx_groups[grp_index].mrg_index : grp_index; 5369 *type = mip->mi_tx_groups[grp_index].mrg_type; 5370 *n_rings = mip->mi_tx_groups[grp_index].mrg_cur_count; 5371 ring = mip->mi_tx_groups[grp_index].mrg_rings; 5372 for (index = 0; index < mip->mi_tx_groups[grp_index].mrg_cur_count; 5373 index++) { 5374 rings[index] = ring->mr_index; 5375 ring = ring->mr_next; 5376 } 5377 index = 0; 5378 /* Default group has an index of -1 */ 5379 if (mip->mi_tx_groups[grp_index].mrg_index < 0) { 5380 (void) strlcpy(clnts_name, "<default>,", 5381 MAXCLIENTNAMELEN); 5382 index += strlen("<default>,"); 5383 } 5384 for (mcip = mip->mi_tx_groups[grp_index].mrg_clients; mcip != NULL; 5385 mcip = mcip->mgc_next) { 5386 int name_len = strlen(mcip->mgc_client->mci_name); 5387 5388 /* 5389 * MAXCLIENTNAMELEN is the buffer size reserved for client 5390 * names. 5391 * XXXX Formating the client name string needs to be moved 5392 * to user land when fixing the size of dhi_clnts in 5393 * dld_hwgrpinfo_t. We should use n_clients * client_name for 5394 * dhi_clntsin instead of MAXCLIENTNAMELEN 5395 */ 5396 if (index + name_len >= MAXCLIENTNAMELEN) { 5397 index = MAXCLIENTNAMELEN; 5398 break; 5399 } 5400 bcopy(mcip->mgc_client->mci_name, &(clnts_name[index]), 5401 name_len); 5402 index += name_len; 5403 clnts_name[index++] = ','; 5404 i++; 5405 } 5406 5407 /* Get rid of the last , */ 5408 if (index > 0) 5409 clnts_name[index - 1] = '\0'; 5410 *n_clnts = i; 5411 rw_exit(&mip->mi_rw_lock); 5412 } 5413 5414 /* 5415 * Return the group count for RX or TX. 5416 */ 5417 uint_t 5418 mac_hwgrp_num(mac_handle_t mh, int type) 5419 { 5420 mac_impl_t *mip = (mac_impl_t *)mh; 5421 5422 /* 5423 * Return the Rx and Tx group count; for the Tx we need to 5424 * include the default too. 5425 */ 5426 return (type == MAC_RING_TYPE_RX ? mip->mi_rx_group_count : 5427 mip->mi_tx_groups != NULL ? mip->mi_tx_group_count + 1 : 0); 5428 } 5429 5430 /* 5431 * The total number of free TX rings for this MAC. 5432 */ 5433 uint_t 5434 mac_txavail_get(mac_handle_t mh) 5435 { 5436 mac_impl_t *mip = (mac_impl_t *)mh; 5437 5438 return (mip->mi_txrings_avail); 5439 } 5440 5441 /* 5442 * The total number of free RX rings for this MAC. 5443 */ 5444 uint_t 5445 mac_rxavail_get(mac_handle_t mh) 5446 { 5447 mac_impl_t *mip = (mac_impl_t *)mh; 5448 5449 return (mip->mi_rxrings_avail); 5450 } 5451 5452 /* 5453 * The total number of reserved RX rings on this MAC. 5454 */ 5455 uint_t 5456 mac_rxrsvd_get(mac_handle_t mh) 5457 { 5458 mac_impl_t *mip = (mac_impl_t *)mh; 5459 5460 return (mip->mi_rxrings_rsvd); 5461 } 5462 5463 /* 5464 * The total number of reserved TX rings on this MAC. 5465 */ 5466 uint_t 5467 mac_txrsvd_get(mac_handle_t mh) 5468 { 5469 mac_impl_t *mip = (mac_impl_t *)mh; 5470 5471 return (mip->mi_txrings_rsvd); 5472 } 5473 5474 /* 5475 * Total number of free RX groups on this MAC. 5476 */ 5477 uint_t 5478 mac_rxhwlnksavail_get(mac_handle_t mh) 5479 { 5480 mac_impl_t *mip = (mac_impl_t *)mh; 5481 5482 return (mip->mi_rxhwclnt_avail); 5483 } 5484 5485 /* 5486 * Total number of RX groups reserved on this MAC. 5487 */ 5488 uint_t 5489 mac_rxhwlnksrsvd_get(mac_handle_t mh) 5490 { 5491 mac_impl_t *mip = (mac_impl_t *)mh; 5492 5493 return (mip->mi_rxhwclnt_used); 5494 } 5495 5496 /* 5497 * Total number of free TX groups on this MAC. 5498 */ 5499 uint_t 5500 mac_txhwlnksavail_get(mac_handle_t mh) 5501 { 5502 mac_impl_t *mip = (mac_impl_t *)mh; 5503 5504 return (mip->mi_txhwclnt_avail); 5505 } 5506 5507 /* 5508 * Total number of TX groups reserved on this MAC. 5509 */ 5510 uint_t 5511 mac_txhwlnksrsvd_get(mac_handle_t mh) 5512 { 5513 mac_impl_t *mip = (mac_impl_t *)mh; 5514 5515 return (mip->mi_txhwclnt_used); 5516 } 5517 5518 /* 5519 * Initialize the rings property for a mac client. A non-0 value for 5520 * rxring or txring specifies the number of rings required, a value 5521 * of MAC_RXRINGS_NONE/MAC_TXRINGS_NONE specifies that it doesn't need 5522 * any RX/TX rings and a value of MAC_RXRINGS_DONTCARE/MAC_TXRINGS_DONTCARE 5523 * means the system can decide whether it can give any rings or not. 5524 */ 5525 void 5526 mac_client_set_rings(mac_client_handle_t mch, int rxrings, int txrings) 5527 { 5528 mac_client_impl_t *mcip = (mac_client_impl_t *)mch; 5529 mac_resource_props_t *mrp = MCIP_RESOURCE_PROPS(mcip); 5530 5531 if (rxrings != MAC_RXRINGS_DONTCARE) { 5532 mrp->mrp_mask |= MRP_RX_RINGS; 5533 mrp->mrp_nrxrings = rxrings; 5534 } 5535 5536 if (txrings != MAC_TXRINGS_DONTCARE) { 5537 mrp->mrp_mask |= MRP_TX_RINGS; 5538 mrp->mrp_ntxrings = txrings; 5539 } 5540 } 5541 5542 boolean_t 5543 mac_get_promisc_filtered(mac_client_handle_t mch) 5544 { 5545 mac_client_impl_t *mcip = (mac_client_impl_t *)mch; 5546 5547 return (mcip->mci_protect_flags & MPT_FLAG_PROMISC_FILTERED); 5548 } 5549 5550 void 5551 mac_set_promisc_filtered(mac_client_handle_t mch, boolean_t enable) 5552 { 5553 mac_client_impl_t *mcip = (mac_client_impl_t *)mch; 5554 5555 ASSERT(MAC_PERIM_HELD((mac_handle_t)mcip->mci_mip)); 5556 if (enable) 5557 mcip->mci_protect_flags |= MPT_FLAG_PROMISC_FILTERED; 5558 else 5559 mcip->mci_protect_flags &= ~MPT_FLAG_PROMISC_FILTERED; 5560 } 5561