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