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