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