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 2020 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 i_mac_perim_exit(mip); 1616 1617 /* 1618 * If we're changing the Rx function on the primary MAC of a VNIC, 1619 * make sure any secondary addresses on the VNIC are updated as well. 1620 */ 1621 if (umip != NULL) { 1622 ASSERT((umip->mi_state_flags & MIS_IS_VNIC) != 0); 1623 mac_vnic_secondary_update(umip); 1624 } 1625 } 1626 1627 /* 1628 * Reset the receive callback for the specified MAC client. 1629 */ 1630 void 1631 mac_rx_clear(mac_client_handle_t mch) 1632 { 1633 mac_rx_set(mch, mac_rx_def, NULL); 1634 } 1635 1636 void 1637 mac_rx_barrier(mac_client_handle_t mch) 1638 { 1639 mac_client_impl_t *mcip = (mac_client_impl_t *)mch; 1640 mac_impl_t *mip = mcip->mci_mip; 1641 1642 i_mac_perim_enter(mip); 1643 1644 /* If a RX callback is set, quiesce and restart that datapath */ 1645 if (mcip->mci_rx_fn != mac_rx_def) { 1646 mac_rx_client_quiesce(mch); 1647 mac_rx_client_restart(mch); 1648 } 1649 1650 /* If any promisc callbacks are registered, perform a barrier there */ 1651 if (mcip->mci_promisc_list != NULL || mip->mi_promisc_list != NULL) { 1652 mac_cb_info_t *mcbi = &mip->mi_promisc_cb_info; 1653 1654 mutex_enter(mcbi->mcbi_lockp); 1655 mac_callback_barrier(mcbi); 1656 mutex_exit(mcbi->mcbi_lockp); 1657 } 1658 1659 i_mac_perim_exit(mip); 1660 } 1661 1662 void 1663 mac_secondary_dup(mac_client_handle_t smch, mac_client_handle_t dmch) 1664 { 1665 mac_client_impl_t *smcip = (mac_client_impl_t *)smch; 1666 mac_client_impl_t *dmcip = (mac_client_impl_t *)dmch; 1667 flow_entry_t *flent = dmcip->mci_flent; 1668 1669 /* This should only be called to setup secondary macs */ 1670 ASSERT((flent->fe_type & FLOW_PRIMARY_MAC) == 0); 1671 1672 mac_rx_set(dmch, smcip->mci_rx_fn, smcip->mci_rx_arg); 1673 dmcip->mci_promisc_list = smcip->mci_promisc_list; 1674 1675 /* 1676 * Duplicate the primary mac resources to the secondary. 1677 * Since we already validated the resource controls when setting 1678 * them on the primary, we can ignore errors here. 1679 */ 1680 (void) mac_resource_ctl_set(dmch, MCIP_RESOURCE_PROPS(smcip)); 1681 } 1682 1683 /* 1684 * Called when removing a secondary MAC. Currently only clears the promisc_list 1685 * since we share the primary mac's promisc_list. 1686 */ 1687 void 1688 mac_secondary_cleanup(mac_client_handle_t mch) 1689 { 1690 mac_client_impl_t *mcip = (mac_client_impl_t *)mch; 1691 flow_entry_t *flent = mcip->mci_flent; 1692 1693 /* This should only be called for secondary macs */ 1694 ASSERT((flent->fe_type & FLOW_PRIMARY_MAC) == 0); 1695 mcip->mci_promisc_list = NULL; 1696 } 1697 1698 /* 1699 * Walk the MAC client subflow table and updates their priority values. 1700 */ 1701 static int 1702 mac_update_subflow_priority_cb(flow_entry_t *flent, void *arg) 1703 { 1704 mac_flow_update_priority(arg, flent); 1705 return (0); 1706 } 1707 1708 void 1709 mac_update_subflow_priority(mac_client_impl_t *mcip) 1710 { 1711 (void) mac_flow_walk(mcip->mci_subflow_tab, 1712 mac_update_subflow_priority_cb, mcip); 1713 } 1714 1715 /* 1716 * Modify the TX or RX ring properties. We could either just move around 1717 * rings, i.e add/remove rings given to a client. Or this might cause the 1718 * client to move from hardware based to software or the other way around. 1719 * If we want to reset this property, then we clear the mask, additionally 1720 * if the client was given a non-default group we remove all rings except 1721 * for 1 and give it back to the default group. 1722 */ 1723 int 1724 mac_client_set_rings_prop(mac_client_impl_t *mcip, mac_resource_props_t *mrp, 1725 mac_resource_props_t *tmrp) 1726 { 1727 mac_impl_t *mip = mcip->mci_mip; 1728 flow_entry_t *flent = mcip->mci_flent; 1729 uint8_t *mac_addr; 1730 int err = 0; 1731 mac_group_t *defgrp; 1732 mac_group_t *group; 1733 mac_group_t *ngrp; 1734 mac_resource_props_t *cmrp = MCIP_RESOURCE_PROPS(mcip); 1735 uint_t ringcnt; 1736 boolean_t unspec; 1737 1738 if (mcip->mci_share != 0) 1739 return (EINVAL); 1740 1741 if (mrp->mrp_mask & MRP_RX_RINGS) { 1742 unspec = mrp->mrp_mask & MRP_RXRINGS_UNSPEC; 1743 group = flent->fe_rx_ring_group; 1744 defgrp = MAC_DEFAULT_RX_GROUP(mip); 1745 mac_addr = flent->fe_flow_desc.fd_dst_mac; 1746 1747 /* 1748 * No resulting change. If we are resetting on a client on 1749 * which there was no rx rings property. For dynamic group 1750 * if we are setting the same number of rings already set. 1751 * For static group if we are requesting a group again. 1752 */ 1753 if (mrp->mrp_mask & MRP_RINGS_RESET) { 1754 if (!(tmrp->mrp_mask & MRP_RX_RINGS)) 1755 return (0); 1756 } else { 1757 if (unspec) { 1758 if (tmrp->mrp_mask & MRP_RXRINGS_UNSPEC) 1759 return (0); 1760 } else if (mip->mi_rx_group_type == 1761 MAC_GROUP_TYPE_DYNAMIC) { 1762 if ((tmrp->mrp_mask & MRP_RX_RINGS) && 1763 !(tmrp->mrp_mask & MRP_RXRINGS_UNSPEC) && 1764 mrp->mrp_nrxrings == tmrp->mrp_nrxrings) { 1765 return (0); 1766 } 1767 } 1768 } 1769 /* Resetting the prop */ 1770 if (mrp->mrp_mask & MRP_RINGS_RESET) { 1771 /* 1772 * We will just keep one ring and give others back if 1773 * we are not the primary. For the primary we give 1774 * all the rings in the default group except the 1775 * default ring. If it is a static group, then 1776 * we don't do anything, but clear the MRP_RX_RINGS 1777 * flag. 1778 */ 1779 if (group != defgrp) { 1780 if (mip->mi_rx_group_type == 1781 MAC_GROUP_TYPE_DYNAMIC) { 1782 /* 1783 * This group has reserved rings 1784 * that need to be released now, 1785 * so does the group. 1786 */ 1787 MAC_RX_RING_RELEASED(mip, 1788 group->mrg_cur_count); 1789 MAC_RX_GRP_RELEASED(mip); 1790 if ((flent->fe_type & 1791 FLOW_PRIMARY_MAC) != 0) { 1792 if (mip->mi_nactiveclients == 1793 1) { 1794 (void) 1795 mac_rx_switch_group( 1796 mcip, group, 1797 defgrp); 1798 return (0); 1799 } else { 1800 cmrp->mrp_nrxrings = 1801 group-> 1802 mrg_cur_count + 1803 defgrp-> 1804 mrg_cur_count - 1; 1805 } 1806 } else { 1807 cmrp->mrp_nrxrings = 1; 1808 } 1809 (void) mac_group_ring_modify(mcip, 1810 group, defgrp); 1811 } else { 1812 /* 1813 * If this is a static group, we 1814 * need to release the group. The 1815 * client will remain in the same 1816 * group till some other client 1817 * needs this group. 1818 */ 1819 MAC_RX_GRP_RELEASED(mip); 1820 } 1821 /* Let check if we can give this an excl group */ 1822 } else if (group == defgrp) { 1823 /* 1824 * If multiple clients share an 1825 * address then they must stay on the 1826 * default group. 1827 */ 1828 if (mac_check_macaddr_shared(mcip->mci_unicast)) 1829 return (0); 1830 1831 ngrp = mac_reserve_rx_group(mcip, mac_addr, 1832 B_TRUE); 1833 /* Couldn't give it a group, that's fine */ 1834 if (ngrp == NULL) 1835 return (0); 1836 /* Switch to H/W */ 1837 if (mac_rx_switch_group(mcip, defgrp, ngrp) != 1838 0) { 1839 mac_stop_group(ngrp); 1840 return (0); 1841 } 1842 } 1843 /* 1844 * If the client is in the default group, we will 1845 * just clear the MRP_RX_RINGS and leave it as 1846 * it rather than look for an exclusive group 1847 * for it. 1848 */ 1849 return (0); 1850 } 1851 1852 if (group == defgrp && ((mrp->mrp_nrxrings > 0) || unspec)) { 1853 /* 1854 * We are requesting Rx rings. Try to reserve 1855 * a non-default group. 1856 * 1857 * If multiple clients share an address then 1858 * they must stay on the default group. 1859 */ 1860 if (mac_check_macaddr_shared(mcip->mci_unicast)) 1861 return (EINVAL); 1862 1863 ngrp = mac_reserve_rx_group(mcip, mac_addr, B_TRUE); 1864 if (ngrp == NULL) 1865 return (ENOSPC); 1866 1867 /* Switch to H/W */ 1868 if (mac_rx_switch_group(mcip, defgrp, ngrp) != 0) { 1869 mac_release_rx_group(mcip, ngrp); 1870 return (ENOSPC); 1871 } 1872 MAC_RX_GRP_RESERVED(mip); 1873 if (mip->mi_rx_group_type == MAC_GROUP_TYPE_DYNAMIC) 1874 MAC_RX_RING_RESERVED(mip, ngrp->mrg_cur_count); 1875 } else if (group != defgrp && !unspec && 1876 mrp->mrp_nrxrings == 0) { 1877 /* Switch to S/W */ 1878 ringcnt = group->mrg_cur_count; 1879 if (mac_rx_switch_group(mcip, group, defgrp) != 0) 1880 return (ENOSPC); 1881 if (tmrp->mrp_mask & MRP_RX_RINGS) { 1882 MAC_RX_GRP_RELEASED(mip); 1883 if (mip->mi_rx_group_type == 1884 MAC_GROUP_TYPE_DYNAMIC) { 1885 MAC_RX_RING_RELEASED(mip, ringcnt); 1886 } 1887 } 1888 } else if (group != defgrp && mip->mi_rx_group_type == 1889 MAC_GROUP_TYPE_DYNAMIC) { 1890 ringcnt = group->mrg_cur_count; 1891 err = mac_group_ring_modify(mcip, group, defgrp); 1892 if (err != 0) 1893 return (err); 1894 /* 1895 * Update the accounting. If this group 1896 * already had explicitly reserved rings, 1897 * we need to update the rings based on 1898 * the new ring count. If this group 1899 * had not explicitly reserved rings, 1900 * then we just reserve the rings asked for 1901 * and reserve the group. 1902 */ 1903 if (tmrp->mrp_mask & MRP_RX_RINGS) { 1904 if (ringcnt > group->mrg_cur_count) { 1905 MAC_RX_RING_RELEASED(mip, 1906 ringcnt - group->mrg_cur_count); 1907 } else { 1908 MAC_RX_RING_RESERVED(mip, 1909 group->mrg_cur_count - ringcnt); 1910 } 1911 } else { 1912 MAC_RX_RING_RESERVED(mip, group->mrg_cur_count); 1913 MAC_RX_GRP_RESERVED(mip); 1914 } 1915 } 1916 } 1917 if (mrp->mrp_mask & MRP_TX_RINGS) { 1918 unspec = mrp->mrp_mask & MRP_TXRINGS_UNSPEC; 1919 group = flent->fe_tx_ring_group; 1920 defgrp = MAC_DEFAULT_TX_GROUP(mip); 1921 1922 /* 1923 * For static groups we only allow rings=0 or resetting the 1924 * rings property. 1925 */ 1926 if (mrp->mrp_ntxrings > 0 && 1927 mip->mi_tx_group_type != MAC_GROUP_TYPE_DYNAMIC) { 1928 return (ENOTSUP); 1929 } 1930 if (mrp->mrp_mask & MRP_RINGS_RESET) { 1931 if (!(tmrp->mrp_mask & MRP_TX_RINGS)) 1932 return (0); 1933 } else { 1934 if (unspec) { 1935 if (tmrp->mrp_mask & MRP_TXRINGS_UNSPEC) 1936 return (0); 1937 } else if (mip->mi_tx_group_type == 1938 MAC_GROUP_TYPE_DYNAMIC) { 1939 if ((tmrp->mrp_mask & MRP_TX_RINGS) && 1940 !(tmrp->mrp_mask & MRP_TXRINGS_UNSPEC) && 1941 mrp->mrp_ntxrings == tmrp->mrp_ntxrings) { 1942 return (0); 1943 } 1944 } 1945 } 1946 /* Resetting the prop */ 1947 if (mrp->mrp_mask & MRP_RINGS_RESET) { 1948 if (group != defgrp) { 1949 if (mip->mi_tx_group_type == 1950 MAC_GROUP_TYPE_DYNAMIC) { 1951 ringcnt = group->mrg_cur_count; 1952 if ((flent->fe_type & 1953 FLOW_PRIMARY_MAC) != 0) { 1954 mac_tx_client_quiesce( 1955 (mac_client_handle_t) 1956 mcip); 1957 mac_tx_switch_group(mcip, 1958 group, defgrp); 1959 mac_tx_client_restart( 1960 (mac_client_handle_t) 1961 mcip); 1962 MAC_TX_GRP_RELEASED(mip); 1963 MAC_TX_RING_RELEASED(mip, 1964 ringcnt); 1965 return (0); 1966 } 1967 cmrp->mrp_ntxrings = 1; 1968 (void) mac_group_ring_modify(mcip, 1969 group, defgrp); 1970 /* 1971 * This group has reserved rings 1972 * that need to be released now. 1973 */ 1974 MAC_TX_RING_RELEASED(mip, ringcnt); 1975 } 1976 /* 1977 * If this is a static group, we 1978 * need to release the group. The 1979 * client will remain in the same 1980 * group till some other client 1981 * needs this group. 1982 */ 1983 MAC_TX_GRP_RELEASED(mip); 1984 } else if (group == defgrp && 1985 (flent->fe_type & FLOW_PRIMARY_MAC) == 0) { 1986 ngrp = mac_reserve_tx_group(mcip, B_TRUE); 1987 if (ngrp == NULL) 1988 return (0); 1989 mac_tx_client_quiesce( 1990 (mac_client_handle_t)mcip); 1991 mac_tx_switch_group(mcip, defgrp, ngrp); 1992 mac_tx_client_restart( 1993 (mac_client_handle_t)mcip); 1994 } 1995 /* 1996 * If the client is in the default group, we will 1997 * just clear the MRP_TX_RINGS and leave it as 1998 * it rather than look for an exclusive group 1999 * for it. 2000 */ 2001 return (0); 2002 } 2003 2004 /* Switch to H/W */ 2005 if (group == defgrp && ((mrp->mrp_ntxrings > 0) || unspec)) { 2006 ngrp = mac_reserve_tx_group(mcip, B_TRUE); 2007 if (ngrp == NULL) 2008 return (ENOSPC); 2009 mac_tx_client_quiesce((mac_client_handle_t)mcip); 2010 mac_tx_switch_group(mcip, defgrp, ngrp); 2011 mac_tx_client_restart((mac_client_handle_t)mcip); 2012 MAC_TX_GRP_RESERVED(mip); 2013 if (mip->mi_tx_group_type == MAC_GROUP_TYPE_DYNAMIC) 2014 MAC_TX_RING_RESERVED(mip, ngrp->mrg_cur_count); 2015 /* Switch to S/W */ 2016 } else if (group != defgrp && !unspec && 2017 mrp->mrp_ntxrings == 0) { 2018 /* Switch to S/W */ 2019 ringcnt = group->mrg_cur_count; 2020 mac_tx_client_quiesce((mac_client_handle_t)mcip); 2021 mac_tx_switch_group(mcip, group, defgrp); 2022 mac_tx_client_restart((mac_client_handle_t)mcip); 2023 if (tmrp->mrp_mask & MRP_TX_RINGS) { 2024 MAC_TX_GRP_RELEASED(mip); 2025 if (mip->mi_tx_group_type == 2026 MAC_GROUP_TYPE_DYNAMIC) { 2027 MAC_TX_RING_RELEASED(mip, ringcnt); 2028 } 2029 } 2030 } else if (group != defgrp && mip->mi_tx_group_type == 2031 MAC_GROUP_TYPE_DYNAMIC) { 2032 ringcnt = group->mrg_cur_count; 2033 err = mac_group_ring_modify(mcip, group, defgrp); 2034 if (err != 0) 2035 return (err); 2036 /* 2037 * Update the accounting. If this group 2038 * already had explicitly reserved rings, 2039 * we need to update the rings based on 2040 * the new ring count. If this group 2041 * had not explicitly reserved rings, 2042 * then we just reserve the rings asked for 2043 * and reserve the group. 2044 */ 2045 if (tmrp->mrp_mask & MRP_TX_RINGS) { 2046 if (ringcnt > group->mrg_cur_count) { 2047 MAC_TX_RING_RELEASED(mip, 2048 ringcnt - group->mrg_cur_count); 2049 } else { 2050 MAC_TX_RING_RESERVED(mip, 2051 group->mrg_cur_count - ringcnt); 2052 } 2053 } else { 2054 MAC_TX_RING_RESERVED(mip, group->mrg_cur_count); 2055 MAC_TX_GRP_RESERVED(mip); 2056 } 2057 } 2058 } 2059 return (0); 2060 } 2061 2062 /* 2063 * When the MAC client is being brought up (i.e. we do a unicast_add) we need 2064 * to initialize the cpu and resource control structure in the 2065 * mac_client_impl_t from the mac_impl_t (i.e if there are any cached 2066 * properties before the flow entry for the unicast address was created). 2067 */ 2068 static int 2069 mac_resource_ctl_set(mac_client_handle_t mch, mac_resource_props_t *mrp) 2070 { 2071 mac_client_impl_t *mcip = (mac_client_impl_t *)mch; 2072 mac_impl_t *mip = (mac_impl_t *)mcip->mci_mip; 2073 mac_impl_t *umip = mcip->mci_upper_mip; 2074 int err = 0; 2075 flow_entry_t *flent = mcip->mci_flent; 2076 mac_resource_props_t *omrp, *nmrp = MCIP_RESOURCE_PROPS(mcip); 2077 2078 ASSERT(MAC_PERIM_HELD((mac_handle_t)mip)); 2079 2080 err = mac_validate_props(mcip->mci_state_flags & MCIS_IS_VNIC ? 2081 mcip->mci_upper_mip : mip, mrp); 2082 if (err != 0) 2083 return (err); 2084 2085 /* 2086 * Copy over the existing properties since mac_update_resources 2087 * will modify the client's mrp. Currently, the saved property 2088 * is used to determine the difference between existing and 2089 * modified rings property. 2090 */ 2091 omrp = kmem_zalloc(sizeof (*omrp), KM_SLEEP); 2092 bcopy(nmrp, omrp, sizeof (*omrp)); 2093 mac_update_resources(mrp, MCIP_RESOURCE_PROPS(mcip), B_FALSE); 2094 if (MCIP_DATAPATH_SETUP(mcip)) { 2095 /* 2096 * We support rings only for primary client when there are 2097 * multiple clients sharing the same MAC address (e.g. VLAN). 2098 */ 2099 if (mrp->mrp_mask & MRP_RX_RINGS || 2100 mrp->mrp_mask & MRP_TX_RINGS) { 2101 2102 if ((err = mac_client_set_rings_prop(mcip, mrp, 2103 omrp)) != 0) { 2104 if (omrp->mrp_mask & MRP_RX_RINGS) { 2105 nmrp->mrp_mask |= MRP_RX_RINGS; 2106 nmrp->mrp_nrxrings = omrp->mrp_nrxrings; 2107 } else { 2108 nmrp->mrp_mask &= ~MRP_RX_RINGS; 2109 nmrp->mrp_nrxrings = 0; 2110 } 2111 if (omrp->mrp_mask & MRP_TX_RINGS) { 2112 nmrp->mrp_mask |= MRP_TX_RINGS; 2113 nmrp->mrp_ntxrings = omrp->mrp_ntxrings; 2114 } else { 2115 nmrp->mrp_mask &= ~MRP_TX_RINGS; 2116 nmrp->mrp_ntxrings = 0; 2117 } 2118 if (omrp->mrp_mask & MRP_RXRINGS_UNSPEC) 2119 omrp->mrp_mask |= MRP_RXRINGS_UNSPEC; 2120 else 2121 omrp->mrp_mask &= ~MRP_RXRINGS_UNSPEC; 2122 2123 if (omrp->mrp_mask & MRP_TXRINGS_UNSPEC) 2124 omrp->mrp_mask |= MRP_TXRINGS_UNSPEC; 2125 else 2126 omrp->mrp_mask &= ~MRP_TXRINGS_UNSPEC; 2127 kmem_free(omrp, sizeof (*omrp)); 2128 return (err); 2129 } 2130 2131 /* 2132 * If we modified the rings property of the primary 2133 * we need to update the property fields of its 2134 * VLANs as they inherit the primary's properites. 2135 */ 2136 if (mac_is_primary_client(mcip)) { 2137 mac_set_prim_vlan_rings(mip, 2138 MCIP_RESOURCE_PROPS(mcip)); 2139 } 2140 } 2141 /* 2142 * We have to set this prior to calling mac_flow_modify. 2143 */ 2144 if (mrp->mrp_mask & MRP_PRIORITY) { 2145 if (mrp->mrp_priority == MPL_RESET) { 2146 MAC_CLIENT_SET_PRIORITY_RANGE(mcip, 2147 MPL_LINK_DEFAULT); 2148 } else { 2149 MAC_CLIENT_SET_PRIORITY_RANGE(mcip, 2150 mrp->mrp_priority); 2151 } 2152 } 2153 2154 mac_flow_modify(mip->mi_flow_tab, flent, mrp); 2155 if (mrp->mrp_mask & MRP_PRIORITY) 2156 mac_update_subflow_priority(mcip); 2157 2158 /* Apply these resource settings to any secondary macs */ 2159 if (umip != NULL) { 2160 ASSERT((umip->mi_state_flags & MIS_IS_VNIC) != 0); 2161 mac_vnic_secondary_update(umip); 2162 } 2163 } 2164 kmem_free(omrp, sizeof (*omrp)); 2165 return (0); 2166 } 2167 2168 static int 2169 mac_unicast_flow_create(mac_client_impl_t *mcip, uint8_t *mac_addr, 2170 uint16_t vid, boolean_t is_primary, boolean_t first_flow, 2171 flow_entry_t **flent, mac_resource_props_t *mrp) 2172 { 2173 mac_impl_t *mip = (mac_impl_t *)mcip->mci_mip; 2174 flow_desc_t flow_desc; 2175 char flowname[MAXFLOWNAMELEN]; 2176 int err; 2177 uint_t flent_flags; 2178 2179 /* 2180 * First unicast address being added, create a new flow 2181 * for that MAC client. 2182 */ 2183 bzero(&flow_desc, sizeof (flow_desc)); 2184 2185 ASSERT(mac_addr != NULL || 2186 (mcip->mci_state_flags & MCIS_NO_UNICAST_ADDR)); 2187 if (mac_addr != NULL) { 2188 flow_desc.fd_mac_len = mip->mi_type->mt_addr_length; 2189 bcopy(mac_addr, flow_desc.fd_dst_mac, flow_desc.fd_mac_len); 2190 } 2191 flow_desc.fd_mask = FLOW_LINK_DST; 2192 if (vid != 0) { 2193 flow_desc.fd_vid = vid; 2194 flow_desc.fd_mask |= FLOW_LINK_VID; 2195 } 2196 2197 /* 2198 * XXX-nicolas. For now I'm keeping the FLOW_PRIMARY_MAC 2199 * and FLOW_VNIC. Even though they're a hack inherited 2200 * from the SRS code, we'll keep them for now. They're currently 2201 * consumed by mac_datapath_setup() to create the SRS. 2202 * That code should be eventually moved out of 2203 * mac_datapath_setup() and moved to a mac_srs_create() 2204 * function of some sort to keep things clean. 2205 * 2206 * Also, there's no reason why the SRS for the primary MAC 2207 * client should be different than any other MAC client. Until 2208 * this is cleaned-up, we support only one MAC unicast address 2209 * per client. 2210 * 2211 * We set FLOW_PRIMARY_MAC for the primary MAC address, 2212 * FLOW_VNIC for everything else. 2213 */ 2214 if (is_primary) 2215 flent_flags = FLOW_PRIMARY_MAC; 2216 else 2217 flent_flags = FLOW_VNIC_MAC; 2218 2219 /* 2220 * For the first flow we use the MAC client's name - mci_name, for 2221 * subsequent ones we just create a name with the VID. This is 2222 * so that we can add these flows to the same flow table. This is 2223 * fine as the flow name (except for the one with the MAC client's 2224 * name) is not visible. When the first flow is removed, we just replace 2225 * its fdesc with another from the list, so we will still retain the 2226 * flent with the MAC client's flow name. 2227 */ 2228 if (first_flow) { 2229 bcopy(mcip->mci_name, flowname, MAXFLOWNAMELEN); 2230 } else { 2231 (void) sprintf(flowname, "%s%u", mcip->mci_name, vid); 2232 flent_flags = FLOW_NO_STATS; 2233 } 2234 2235 if ((err = mac_flow_create(&flow_desc, mrp, flowname, NULL, 2236 flent_flags, flent)) != 0) 2237 return (err); 2238 2239 mac_misc_stat_create(*flent); 2240 FLOW_MARK(*flent, FE_INCIPIENT); 2241 (*flent)->fe_mcip = mcip; 2242 2243 /* 2244 * Place initial creation reference on the flow. This reference 2245 * is released in the corresponding delete action viz. 2246 * mac_unicast_remove after waiting for all transient refs to 2247 * to go away. The wait happens in mac_flow_wait. 2248 * We have already held the reference in mac_client_open(). 2249 */ 2250 if (!first_flow) 2251 FLOW_REFHOLD(*flent); 2252 return (0); 2253 } 2254 2255 /* Refresh the multicast grouping for this VID. */ 2256 int 2257 mac_client_update_mcast(void *arg, boolean_t add, const uint8_t *addrp) 2258 { 2259 flow_entry_t *flent = arg; 2260 mac_client_impl_t *mcip = flent->fe_mcip; 2261 uint16_t vid; 2262 flow_desc_t flow_desc; 2263 2264 mac_flow_get_desc(flent, &flow_desc); 2265 vid = (flow_desc.fd_mask & FLOW_LINK_VID) != 0 ? 2266 flow_desc.fd_vid : VLAN_ID_NONE; 2267 2268 /* 2269 * We don't call mac_multicast_add()/mac_multicast_remove() as 2270 * we want to add/remove for this specific vid. 2271 */ 2272 if (add) { 2273 return (mac_bcast_add(mcip, addrp, vid, 2274 MAC_ADDRTYPE_MULTICAST)); 2275 } else { 2276 mac_bcast_delete(mcip, addrp, vid); 2277 return (0); 2278 } 2279 } 2280 2281 static void 2282 mac_update_single_active_client(mac_impl_t *mip) 2283 { 2284 mac_client_impl_t *client = NULL; 2285 2286 ASSERT(MAC_PERIM_HELD((mac_handle_t)mip)); 2287 2288 rw_enter(&mip->mi_rw_lock, RW_WRITER); 2289 if (mip->mi_nactiveclients == 1) { 2290 /* 2291 * Find the one active MAC client from the list of MAC 2292 * clients. The active MAC client has at least one 2293 * unicast address. 2294 */ 2295 for (client = mip->mi_clients_list; client != NULL; 2296 client = client->mci_client_next) { 2297 if (client->mci_unicast_list != NULL) 2298 break; 2299 } 2300 ASSERT(client != NULL); 2301 } 2302 2303 /* 2304 * mi_single_active_client is protected by the MAC impl's read/writer 2305 * lock, which allows mac_rx() to check the value of that pointer 2306 * as a reader. 2307 */ 2308 mip->mi_single_active_client = client; 2309 rw_exit(&mip->mi_rw_lock); 2310 } 2311 2312 /* 2313 * Set up the data path. Called from i_mac_unicast_add after having 2314 * done all the validations including making sure this is an active 2315 * client (i.e that is ready to process packets.) 2316 */ 2317 static int 2318 mac_client_datapath_setup(mac_client_impl_t *mcip, uint16_t vid, 2319 uint8_t *mac_addr, mac_resource_props_t *mrp, boolean_t isprimary, 2320 mac_unicast_impl_t *muip) 2321 { 2322 mac_impl_t *mip = mcip->mci_mip; 2323 boolean_t mac_started = B_FALSE; 2324 boolean_t bcast_added = B_FALSE; 2325 boolean_t nactiveclients_added = B_FALSE; 2326 flow_entry_t *flent; 2327 int err = 0; 2328 boolean_t no_unicast; 2329 2330 no_unicast = mcip->mci_state_flags & MCIS_NO_UNICAST_ADDR; 2331 2332 if ((err = mac_start((mac_handle_t)mip)) != 0) 2333 goto bail; 2334 2335 mac_started = B_TRUE; 2336 2337 /* add the MAC client to the broadcast address group by default */ 2338 if (mip->mi_type->mt_brdcst_addr != NULL) { 2339 err = mac_bcast_add(mcip, mip->mi_type->mt_brdcst_addr, vid, 2340 MAC_ADDRTYPE_BROADCAST); 2341 if (err != 0) 2342 goto bail; 2343 bcast_added = B_TRUE; 2344 } 2345 2346 /* 2347 * If this is the first unicast address addition for this 2348 * client, reuse the pre-allocated larval flow entry associated with 2349 * the MAC client. 2350 */ 2351 flent = (mcip->mci_nflents == 0) ? mcip->mci_flent : NULL; 2352 2353 /* We are configuring the unicast flow now */ 2354 if (!MCIP_DATAPATH_SETUP(mcip)) { 2355 2356 if (mrp != NULL) { 2357 MAC_CLIENT_SET_PRIORITY_RANGE(mcip, 2358 (mrp->mrp_mask & MRP_PRIORITY) ? mrp->mrp_priority : 2359 MPL_LINK_DEFAULT); 2360 } 2361 if ((err = mac_unicast_flow_create(mcip, mac_addr, vid, 2362 isprimary, B_TRUE, &flent, mrp)) != 0) 2363 goto bail; 2364 2365 mip->mi_nactiveclients++; 2366 nactiveclients_added = B_TRUE; 2367 2368 /* 2369 * This will allocate the RX ring group if possible for the 2370 * flow and program the software classifier as needed. 2371 */ 2372 if ((err = mac_datapath_setup(mcip, flent, SRST_LINK)) != 0) 2373 goto bail; 2374 2375 if (no_unicast) 2376 goto done_setup; 2377 /* 2378 * The unicast MAC address must have been added successfully. 2379 */ 2380 ASSERT(mcip->mci_unicast != NULL); 2381 2382 /* 2383 * Push down the sub-flows that were defined on this link 2384 * hitherto. The flows are added to the active flow table 2385 * and SRS, softrings etc. are created as needed. 2386 */ 2387 mac_link_init_flows((mac_client_handle_t)mcip); 2388 } else { 2389 mac_address_t *map = mcip->mci_unicast; 2390 2391 ASSERT(!no_unicast); 2392 /* 2393 * A unicast flow already exists for that MAC client 2394 * so this flow must be the same MAC address but with 2395 * a different VID. It has been checked by 2396 * mac_addr_in_use(). 2397 * 2398 * We will use the SRS etc. from the initial 2399 * mci_flent. We don't need to create a kstat for 2400 * this, as except for the fdesc, everything will be 2401 * used from the first flent. 2402 * 2403 * The only time we should see multiple flents on the 2404 * same MAC client is on the sun4v vsw. If we removed 2405 * that code we should be able to remove the entire 2406 * notion of multiple flents on a MAC client (this 2407 * doesn't affect sub/user flows because they have 2408 * their own list unrelated to mci_flent_list). 2409 */ 2410 if (bcmp(mac_addr, map->ma_addr, map->ma_len) != 0) { 2411 err = EINVAL; 2412 goto bail; 2413 } 2414 2415 if ((err = mac_unicast_flow_create(mcip, mac_addr, vid, 2416 isprimary, B_FALSE, &flent, NULL)) != 0) { 2417 goto bail; 2418 } 2419 if ((err = mac_flow_add(mip->mi_flow_tab, flent)) != 0) { 2420 FLOW_FINAL_REFRELE(flent); 2421 goto bail; 2422 } 2423 2424 /* update the multicast group for this vid */ 2425 mac_client_bcast_refresh(mcip, mac_client_update_mcast, 2426 (void *)flent, B_TRUE); 2427 2428 } 2429 2430 /* populate the shared MAC address */ 2431 muip->mui_map = mcip->mci_unicast; 2432 2433 rw_enter(&mcip->mci_rw_lock, RW_WRITER); 2434 muip->mui_next = mcip->mci_unicast_list; 2435 mcip->mci_unicast_list = muip; 2436 rw_exit(&mcip->mci_rw_lock); 2437 2438 done_setup: 2439 /* 2440 * First add the flent to the flow list of this mcip. Then set 2441 * the mip's mi_single_active_client if needed. The Rx path assumes 2442 * that mip->mi_single_active_client will always have an associated 2443 * flent. 2444 */ 2445 mac_client_add_to_flow_list(mcip, flent); 2446 if (nactiveclients_added) 2447 mac_update_single_active_client(mip); 2448 /* 2449 * Trigger a renegotiation of the capabilities when the number of 2450 * active clients changes from 1 to 2, since some of the capabilities 2451 * might have to be disabled. Also send a MAC_NOTE_LINK notification 2452 * to all the MAC clients whenever physical link is DOWN. 2453 */ 2454 if (mip->mi_nactiveclients == 2) { 2455 mac_capab_update((mac_handle_t)mip); 2456 mac_virtual_link_update(mip); 2457 } 2458 /* 2459 * Now that the setup is complete, clear the INCIPIENT flag. 2460 * The flag was set to avoid incoming packets seeing inconsistent 2461 * structures while the setup was in progress. Clear the mci_tx_flag 2462 * by calling mac_tx_client_block. It is possible that 2463 * mac_unicast_remove was called prior to this mac_unicast_add which 2464 * could have set the MCI_TX_QUIESCE flag. 2465 */ 2466 if (flent->fe_rx_ring_group != NULL) 2467 mac_rx_group_unmark(flent->fe_rx_ring_group, MR_INCIPIENT); 2468 FLOW_UNMARK(flent, FE_INCIPIENT); 2469 2470 /* 2471 * If this is an aggr port client, don't enable the flow's 2472 * datapath at this stage. Otherwise, bcast traffic could 2473 * arrive while the aggr port is in the process of 2474 * initializing. Instead, the flow's datapath is started later 2475 * when mac_client_set_flow_cb() is called. 2476 */ 2477 if ((mcip->mci_state_flags & MCIS_IS_AGGR_PORT) == 0) 2478 FLOW_UNMARK(flent, FE_MC_NO_DATAPATH); 2479 2480 mac_tx_client_unblock(mcip); 2481 return (0); 2482 bail: 2483 if (bcast_added) 2484 mac_bcast_delete(mcip, mip->mi_type->mt_brdcst_addr, vid); 2485 2486 if (nactiveclients_added) 2487 mip->mi_nactiveclients--; 2488 2489 if (mac_started) 2490 mac_stop((mac_handle_t)mip); 2491 2492 return (err); 2493 } 2494 2495 /* 2496 * Return the passive primary MAC client, if present. The passive client is 2497 * a stand-by client that has the same unicast address as another that is 2498 * currenly active. Once the active client goes away, the passive client 2499 * becomes active. 2500 */ 2501 static mac_client_impl_t * 2502 mac_get_passive_primary_client(mac_impl_t *mip) 2503 { 2504 mac_client_impl_t *mcip; 2505 2506 for (mcip = mip->mi_clients_list; mcip != NULL; 2507 mcip = mcip->mci_client_next) { 2508 if (mac_is_primary_client(mcip) && 2509 (mcip->mci_flags & MAC_CLIENT_FLAGS_PASSIVE_PRIMARY) != 0) { 2510 return (mcip); 2511 } 2512 } 2513 return (NULL); 2514 } 2515 2516 /* 2517 * Add a new unicast address to the MAC client. 2518 * 2519 * The MAC address can be specified either by value, or the MAC client 2520 * can specify that it wants to use the primary MAC address of the 2521 * underlying MAC. See the introductory comments at the beginning 2522 * of this file for more more information on primary MAC addresses. 2523 * 2524 * Note also the tuple (MAC address, VID) must be unique 2525 * for the MAC clients defined on top of the same underlying MAC 2526 * instance, unless the MAC_UNICAST_NODUPCHECK is specified. 2527 * 2528 * In no case can a client use the PVID for the MAC, if the MAC has one set. 2529 */ 2530 int 2531 i_mac_unicast_add(mac_client_handle_t mch, uint8_t *mac_addr, uint16_t flags, 2532 mac_unicast_handle_t *mah, uint16_t vid, mac_diag_t *diag) 2533 { 2534 mac_client_impl_t *mcip = (mac_client_impl_t *)mch; 2535 mac_impl_t *mip = mcip->mci_mip; 2536 int err; 2537 uint_t mac_len = mip->mi_type->mt_addr_length; 2538 boolean_t check_dups = !(flags & MAC_UNICAST_NODUPCHECK); 2539 boolean_t fastpath_disabled = B_FALSE; 2540 boolean_t is_primary = (flags & MAC_UNICAST_PRIMARY); 2541 boolean_t is_unicast_hw = (flags & MAC_UNICAST_HW); 2542 mac_resource_props_t *mrp; 2543 boolean_t passive_client = B_FALSE; 2544 mac_unicast_impl_t *muip; 2545 boolean_t is_vnic_primary = 2546 (flags & MAC_UNICAST_VNIC_PRIMARY); 2547 2548 /* 2549 * When the VID is non-zero the underlying MAC cannot be a 2550 * VNIC. I.e., dladm create-vlan cannot take a VNIC as 2551 * argument, only the primary MAC client. 2552 */ 2553 ASSERT(!((mip->mi_state_flags & MIS_IS_VNIC) && (vid != VLAN_ID_NONE))); 2554 2555 *diag = MAC_DIAG_NONE; 2556 2557 /* 2558 * Can't unicast add if the client asked only for minimal datapath 2559 * setup. 2560 */ 2561 if (mcip->mci_state_flags & MCIS_NO_UNICAST_ADDR) 2562 return (ENOTSUP); 2563 2564 /* 2565 * Check for an attempted use of the current Port VLAN ID, if enabled. 2566 * No client may use it. 2567 */ 2568 if (mip->mi_pvid != VLAN_ID_NONE && vid == mip->mi_pvid) 2569 return (EBUSY); 2570 2571 /* 2572 * Check whether it's the primary client and flag it. 2573 */ 2574 if (!(mcip->mci_state_flags & MCIS_IS_VNIC) && is_primary && 2575 vid == VLAN_ID_NONE) 2576 mcip->mci_flags |= MAC_CLIENT_FLAGS_PRIMARY; 2577 2578 /* 2579 * is_vnic_primary is true when we come here as a VLAN VNIC 2580 * which uses the primary MAC client's address but with a non-zero 2581 * VID. In this case the MAC address is not specified by an upper 2582 * MAC client. 2583 */ 2584 if ((mcip->mci_state_flags & MCIS_IS_VNIC) && is_primary && 2585 !is_vnic_primary) { 2586 /* 2587 * The address is being set by the upper MAC client 2588 * of a VNIC. The MAC address was already set by the 2589 * VNIC driver during VNIC creation. 2590 * 2591 * Note: a VNIC has only one MAC address. We return 2592 * the MAC unicast address handle of the lower MAC client 2593 * corresponding to the VNIC. We allocate a new entry 2594 * which is flagged appropriately, so that mac_unicast_remove() 2595 * doesn't attempt to free the original entry that 2596 * was allocated by the VNIC driver. 2597 */ 2598 ASSERT(mcip->mci_unicast != NULL); 2599 2600 /* Check for VLAN flags, if present */ 2601 if ((flags & MAC_UNICAST_TAG_DISABLE) != 0) 2602 mcip->mci_state_flags |= MCIS_TAG_DISABLE; 2603 2604 if ((flags & MAC_UNICAST_STRIP_DISABLE) != 0) 2605 mcip->mci_state_flags |= MCIS_STRIP_DISABLE; 2606 2607 if ((flags & MAC_UNICAST_DISABLE_TX_VID_CHECK) != 0) 2608 mcip->mci_state_flags |= MCIS_DISABLE_TX_VID_CHECK; 2609 2610 /* 2611 * Ensure that the primary unicast address of the VNIC 2612 * is added only once unless we have the 2613 * MAC_CLIENT_FLAGS_MULTI_PRIMARY set (and this is not 2614 * a passive MAC client). 2615 */ 2616 if ((mcip->mci_flags & MAC_CLIENT_FLAGS_VNIC_PRIMARY) != 0) { 2617 if ((mcip->mci_flags & 2618 MAC_CLIENT_FLAGS_MULTI_PRIMARY) == 0 || 2619 (mcip->mci_flags & 2620 MAC_CLIENT_FLAGS_PASSIVE_PRIMARY) != 0) { 2621 return (EBUSY); 2622 } 2623 mcip->mci_flags |= MAC_CLIENT_FLAGS_PASSIVE_PRIMARY; 2624 passive_client = B_TRUE; 2625 } 2626 2627 mcip->mci_flags |= MAC_CLIENT_FLAGS_VNIC_PRIMARY; 2628 2629 /* 2630 * Create a handle for vid 0. 2631 */ 2632 ASSERT(vid == VLAN_ID_NONE); 2633 muip = kmem_zalloc(sizeof (mac_unicast_impl_t), KM_SLEEP); 2634 muip->mui_vid = vid; 2635 *mah = (mac_unicast_handle_t)muip; 2636 /* 2637 * This will be used by the caller to defer setting the 2638 * rx functions. 2639 */ 2640 if (passive_client) 2641 return (EAGAIN); 2642 return (0); 2643 } 2644 2645 /* primary MAC clients cannot be opened on top of anchor VNICs */ 2646 if ((is_vnic_primary || is_primary) && 2647 i_mac_capab_get((mac_handle_t)mip, MAC_CAPAB_ANCHOR_VNIC, NULL)) { 2648 return (ENXIO); 2649 } 2650 2651 /* 2652 * If this is a VNIC/VLAN, disable softmac fast-path. This is 2653 * only relevant to legacy devices which use softmac to 2654 * interface with GLDv3. 2655 */ 2656 if (mcip->mci_state_flags & MCIS_IS_VNIC) { 2657 err = mac_fastpath_disable((mac_handle_t)mip); 2658 if (err != 0) 2659 return (err); 2660 fastpath_disabled = B_TRUE; 2661 } 2662 2663 /* 2664 * Return EBUSY if: 2665 * - there is an exclusively active mac client exists. 2666 * - this is an exclusive active mac client but 2667 * a. there is already active mac clients exist, or 2668 * b. fastpath streams are already plumbed on this legacy device 2669 * - the mac creator has disallowed active mac clients. 2670 */ 2671 if (mip->mi_state_flags & (MIS_EXCLUSIVE|MIS_NO_ACTIVE)) { 2672 if (fastpath_disabled) 2673 mac_fastpath_enable((mac_handle_t)mip); 2674 return (EBUSY); 2675 } 2676 2677 if (mcip->mci_state_flags & MCIS_EXCLUSIVE) { 2678 ASSERT(!fastpath_disabled); 2679 if (mip->mi_nactiveclients != 0) 2680 return (EBUSY); 2681 2682 if ((mip->mi_state_flags & MIS_LEGACY) && 2683 !(mip->mi_capab_legacy.ml_active_set(mip->mi_driver))) { 2684 return (EBUSY); 2685 } 2686 mip->mi_state_flags |= MIS_EXCLUSIVE; 2687 } 2688 2689 mrp = kmem_zalloc(sizeof (*mrp), KM_SLEEP); 2690 if (is_primary && !(mcip->mci_state_flags & (MCIS_IS_VNIC | 2691 MCIS_IS_AGGR_PORT))) { 2692 /* 2693 * Apply the property cached in the mac_impl_t to the primary 2694 * mac client. If the mac client is a VNIC or an aggregation 2695 * port, its property should be set in the mcip when the 2696 * VNIC/aggr was created. 2697 */ 2698 mac_get_resources((mac_handle_t)mip, mrp); 2699 (void) mac_client_set_resources(mch, mrp); 2700 } else if (mcip->mci_state_flags & MCIS_IS_VNIC) { 2701 /* 2702 * This is a VLAN client sharing the address of the 2703 * primary MAC client; i.e., one created via dladm 2704 * create-vlan. We don't support specifying ring 2705 * properties for this type of client as it inherits 2706 * these from the primary MAC client. 2707 */ 2708 if (is_vnic_primary) { 2709 mac_resource_props_t *vmrp; 2710 2711 vmrp = MCIP_RESOURCE_PROPS(mcip); 2712 if (vmrp->mrp_mask & MRP_RX_RINGS || 2713 vmrp->mrp_mask & MRP_TX_RINGS) { 2714 if (fastpath_disabled) 2715 mac_fastpath_enable((mac_handle_t)mip); 2716 kmem_free(mrp, sizeof (*mrp)); 2717 return (ENOTSUP); 2718 } 2719 /* 2720 * Additionally we also need to inherit any 2721 * rings property from the MAC. 2722 */ 2723 mac_get_resources((mac_handle_t)mip, mrp); 2724 if (mrp->mrp_mask & MRP_RX_RINGS) { 2725 vmrp->mrp_mask |= MRP_RX_RINGS; 2726 vmrp->mrp_nrxrings = mrp->mrp_nrxrings; 2727 } 2728 if (mrp->mrp_mask & MRP_TX_RINGS) { 2729 vmrp->mrp_mask |= MRP_TX_RINGS; 2730 vmrp->mrp_ntxrings = mrp->mrp_ntxrings; 2731 } 2732 } 2733 bcopy(MCIP_RESOURCE_PROPS(mcip), mrp, sizeof (*mrp)); 2734 } 2735 2736 muip = kmem_zalloc(sizeof (mac_unicast_impl_t), KM_SLEEP); 2737 muip->mui_vid = vid; 2738 2739 if (is_primary || is_vnic_primary) { 2740 mac_addr = mip->mi_addr; 2741 } else { 2742 2743 /* 2744 * Verify the validity of the specified MAC addresses value. 2745 */ 2746 if (!mac_unicst_verify((mac_handle_t)mip, mac_addr, mac_len)) { 2747 *diag = MAC_DIAG_MACADDR_INVALID; 2748 err = EINVAL; 2749 goto bail_out; 2750 } 2751 2752 /* 2753 * Make sure that the specified MAC address is different 2754 * than the unicast MAC address of the underlying NIC. 2755 */ 2756 if (check_dups && bcmp(mip->mi_addr, mac_addr, mac_len) == 0) { 2757 *diag = MAC_DIAG_MACADDR_NIC; 2758 err = EINVAL; 2759 goto bail_out; 2760 } 2761 } 2762 2763 /* 2764 * Set the flags here so that if this is a passive client, we 2765 * can return and set it when we call mac_client_datapath_setup 2766 * when this becomes the active client. If we defer to using these 2767 * flags to mac_client_datapath_setup, then for a passive client, 2768 * we'd have to store the flags somewhere (probably fe_flags) 2769 * and then use it. 2770 */ 2771 if (!MCIP_DATAPATH_SETUP(mcip)) { 2772 if (is_unicast_hw) { 2773 /* 2774 * The client requires a hardware MAC address slot 2775 * for that unicast address. Since we support only 2776 * one unicast MAC address per client, flag the 2777 * MAC client itself. 2778 */ 2779 mcip->mci_state_flags |= MCIS_UNICAST_HW; 2780 } 2781 2782 /* Check for VLAN flags, if present */ 2783 if ((flags & MAC_UNICAST_TAG_DISABLE) != 0) 2784 mcip->mci_state_flags |= MCIS_TAG_DISABLE; 2785 2786 if ((flags & MAC_UNICAST_STRIP_DISABLE) != 0) 2787 mcip->mci_state_flags |= MCIS_STRIP_DISABLE; 2788 2789 if ((flags & MAC_UNICAST_DISABLE_TX_VID_CHECK) != 0) 2790 mcip->mci_state_flags |= MCIS_DISABLE_TX_VID_CHECK; 2791 } else { 2792 /* 2793 * Assert that the specified flags are consistent with the 2794 * flags specified by previous calls to mac_unicast_add(). 2795 */ 2796 ASSERT(((flags & MAC_UNICAST_TAG_DISABLE) != 0 && 2797 (mcip->mci_state_flags & MCIS_TAG_DISABLE) != 0) || 2798 ((flags & MAC_UNICAST_TAG_DISABLE) == 0 && 2799 (mcip->mci_state_flags & MCIS_TAG_DISABLE) == 0)); 2800 2801 ASSERT(((flags & MAC_UNICAST_STRIP_DISABLE) != 0 && 2802 (mcip->mci_state_flags & MCIS_STRIP_DISABLE) != 0) || 2803 ((flags & MAC_UNICAST_STRIP_DISABLE) == 0 && 2804 (mcip->mci_state_flags & MCIS_STRIP_DISABLE) == 0)); 2805 2806 ASSERT(((flags & MAC_UNICAST_DISABLE_TX_VID_CHECK) != 0 && 2807 (mcip->mci_state_flags & MCIS_DISABLE_TX_VID_CHECK) != 0) || 2808 ((flags & MAC_UNICAST_DISABLE_TX_VID_CHECK) == 0 && 2809 (mcip->mci_state_flags & MCIS_DISABLE_TX_VID_CHECK) == 0)); 2810 2811 /* 2812 * Make sure the client is consistent about its requests 2813 * for MAC addresses. I.e. all requests from the clients 2814 * must have the MAC_UNICAST_HW flag set or clear. 2815 */ 2816 if (((mcip->mci_state_flags & MCIS_UNICAST_HW) != 0 && 2817 !is_unicast_hw) || 2818 ((mcip->mci_state_flags & MCIS_UNICAST_HW) == 0 && 2819 is_unicast_hw)) { 2820 err = EINVAL; 2821 goto bail_out; 2822 } 2823 } 2824 /* 2825 * Make sure the MAC address is not already used by 2826 * another MAC client defined on top of the same 2827 * underlying NIC. Unless we have MAC_CLIENT_FLAGS_MULTI_PRIMARY 2828 * set when we allow a passive client to be present which will 2829 * be activated when the currently active client goes away - this 2830 * works only with primary addresses. 2831 */ 2832 if ((check_dups || is_primary || is_vnic_primary) && 2833 mac_addr_in_use(mip, mac_addr, vid)) { 2834 /* 2835 * Must have set the multiple primary address flag when 2836 * we did a mac_client_open AND this should be a primary 2837 * MAC client AND there should not already be a passive 2838 * primary. If all is true then we let this succeed 2839 * even if the address is a dup. 2840 */ 2841 if ((mcip->mci_flags & MAC_CLIENT_FLAGS_MULTI_PRIMARY) == 0 || 2842 (mcip->mci_flags & MAC_CLIENT_FLAGS_PRIMARY) == 0 || 2843 mac_get_passive_primary_client(mip) != NULL) { 2844 *diag = MAC_DIAG_MACADDR_INUSE; 2845 err = EEXIST; 2846 goto bail_out; 2847 } 2848 ASSERT((mcip->mci_flags & 2849 MAC_CLIENT_FLAGS_PASSIVE_PRIMARY) == 0); 2850 mcip->mci_flags |= MAC_CLIENT_FLAGS_PASSIVE_PRIMARY; 2851 kmem_free(mrp, sizeof (*mrp)); 2852 2853 /* 2854 * Stash the unicast address handle, we will use it when 2855 * we set up the passive client. 2856 */ 2857 mcip->mci_p_unicast_list = muip; 2858 *mah = (mac_unicast_handle_t)muip; 2859 return (0); 2860 } 2861 2862 err = mac_client_datapath_setup(mcip, vid, mac_addr, mrp, 2863 is_primary || is_vnic_primary, muip); 2864 if (err != 0) 2865 goto bail_out; 2866 2867 kmem_free(mrp, sizeof (*mrp)); 2868 *mah = (mac_unicast_handle_t)muip; 2869 return (0); 2870 2871 bail_out: 2872 if (fastpath_disabled) 2873 mac_fastpath_enable((mac_handle_t)mip); 2874 if (mcip->mci_state_flags & MCIS_EXCLUSIVE) { 2875 mip->mi_state_flags &= ~MIS_EXCLUSIVE; 2876 if (mip->mi_state_flags & MIS_LEGACY) { 2877 mip->mi_capab_legacy.ml_active_clear( 2878 mip->mi_driver); 2879 } 2880 } 2881 kmem_free(mrp, sizeof (*mrp)); 2882 kmem_free(muip, sizeof (mac_unicast_impl_t)); 2883 return (err); 2884 } 2885 2886 /* 2887 * Wrapper function to mac_unicast_add when we want to have the same mac 2888 * client open for two instances, one that is currently active and another 2889 * that will become active when the current one is removed. In this case 2890 * mac_unicast_add will return EGAIN and we will save the rx function and 2891 * arg which will be used when we activate the passive client in 2892 * mac_unicast_remove. 2893 */ 2894 int 2895 mac_unicast_add_set_rx(mac_client_handle_t mch, uint8_t *mac_addr, 2896 uint16_t flags, mac_unicast_handle_t *mah, uint16_t vid, mac_diag_t *diag, 2897 mac_rx_t rx_fn, void *arg) 2898 { 2899 mac_client_impl_t *mcip = (mac_client_impl_t *)mch; 2900 uint_t err; 2901 2902 err = mac_unicast_add(mch, mac_addr, flags, mah, vid, diag); 2903 if (err != 0 && err != EAGAIN) 2904 return (err); 2905 if (err == EAGAIN) { 2906 if (rx_fn != NULL) { 2907 mcip->mci_rx_p_fn = rx_fn; 2908 mcip->mci_rx_p_arg = arg; 2909 } 2910 return (0); 2911 } 2912 if (rx_fn != NULL) 2913 mac_rx_set(mch, rx_fn, arg); 2914 return (err); 2915 } 2916 2917 int 2918 mac_unicast_add(mac_client_handle_t mch, uint8_t *mac_addr, uint16_t flags, 2919 mac_unicast_handle_t *mah, uint16_t vid, mac_diag_t *diag) 2920 { 2921 mac_impl_t *mip = ((mac_client_impl_t *)mch)->mci_mip; 2922 uint_t err; 2923 2924 i_mac_perim_enter(mip); 2925 err = i_mac_unicast_add(mch, mac_addr, flags, mah, vid, diag); 2926 i_mac_perim_exit(mip); 2927 2928 return (err); 2929 } 2930 2931 static void 2932 mac_client_datapath_teardown(mac_client_handle_t mch, mac_unicast_impl_t *muip, 2933 flow_entry_t *flent) 2934 { 2935 mac_client_impl_t *mcip = (mac_client_impl_t *)mch; 2936 mac_impl_t *mip = mcip->mci_mip; 2937 boolean_t no_unicast; 2938 2939 /* 2940 * If we have not added a unicast address for this MAC client, just 2941 * teardown the datapath. 2942 */ 2943 no_unicast = mcip->mci_state_flags & MCIS_NO_UNICAST_ADDR; 2944 2945 if (!no_unicast) { 2946 /* 2947 * We would have initialized subflows etc. only if we brought 2948 * up the primary client and set the unicast unicast address 2949 * etc. Deactivate the flows. The flow entry will be removed 2950 * from the active flow tables, and the associated SRS, 2951 * softrings etc will be deleted. But the flow entry itself 2952 * won't be destroyed, instead it will continue to be archived 2953 * off the the global flow hash list, for a possible future 2954 * activation when say IP is plumbed again. 2955 */ 2956 mac_link_release_flows(mch); 2957 } 2958 mip->mi_nactiveclients--; 2959 mac_update_single_active_client(mip); 2960 2961 /* Tear down the data path */ 2962 mac_datapath_teardown(mcip, mcip->mci_flent, SRST_LINK); 2963 2964 /* 2965 * Prevent any future access to the flow entry through the mci_flent 2966 * pointer by setting the mci_flent to NULL. Access to mci_flent in 2967 * mac_bcast_send is also under mi_rw_lock. 2968 */ 2969 rw_enter(&mip->mi_rw_lock, RW_WRITER); 2970 flent = mcip->mci_flent; 2971 mac_client_remove_flow_from_list(mcip, flent); 2972 2973 if (mcip->mci_state_flags & MCIS_DESC_LOGGED) 2974 mcip->mci_state_flags &= ~MCIS_DESC_LOGGED; 2975 2976 /* 2977 * This is the last unicast address being removed and there shouldn't 2978 * be any outbound data threads at this point coming down from mac 2979 * clients. We have waited for the data threads to finish before 2980 * starting dld_str_detach. Non-data threads must access TX SRS 2981 * under mi_rw_lock. 2982 */ 2983 rw_exit(&mip->mi_rw_lock); 2984 2985 /* 2986 * Don't use FLOW_MARK with FE_MC_NO_DATAPATH, as the flow might 2987 * contain other flags, such as FE_CONDEMNED, which we need to 2988 * cleared. We don't call mac_flow_cleanup() for this unicast 2989 * flow as we have a already cleaned up SRSs etc. (via the teadown 2990 * path). We just clear the stats and reset the initial callback 2991 * function, the rest will be set when we call mac_flow_create, 2992 * if at all. 2993 */ 2994 mutex_enter(&flent->fe_lock); 2995 ASSERT(flent->fe_refcnt == 1 && flent->fe_mbg == NULL && 2996 flent->fe_tx_srs == NULL && flent->fe_rx_srs_cnt == 0); 2997 flent->fe_flags = FE_MC_NO_DATAPATH; 2998 flow_stat_destroy(flent); 2999 mac_misc_stat_delete(flent); 3000 3001 /* Initialize the receiver function to a safe routine */ 3002 flent->fe_cb_fn = (flow_fn_t)mac_rx_def; 3003 flent->fe_cb_arg1 = NULL; 3004 flent->fe_cb_arg2 = NULL; 3005 3006 flent->fe_index = -1; 3007 mutex_exit(&flent->fe_lock); 3008 3009 if (mip->mi_type->mt_brdcst_addr != NULL) { 3010 ASSERT(muip != NULL || no_unicast); 3011 mac_bcast_delete(mcip, mip->mi_type->mt_brdcst_addr, 3012 muip != NULL ? muip->mui_vid : VLAN_ID_NONE); 3013 } 3014 3015 if (mip->mi_nactiveclients == 1) { 3016 mac_capab_update((mac_handle_t)mip); 3017 mac_virtual_link_update(mip); 3018 } 3019 3020 if (mcip->mci_state_flags & MCIS_EXCLUSIVE) { 3021 mip->mi_state_flags &= ~MIS_EXCLUSIVE; 3022 3023 if (mip->mi_state_flags & MIS_LEGACY) 3024 mip->mi_capab_legacy.ml_active_clear(mip->mi_driver); 3025 } 3026 3027 mcip->mci_state_flags &= ~MCIS_UNICAST_HW; 3028 3029 if (mcip->mci_state_flags & MCIS_TAG_DISABLE) 3030 mcip->mci_state_flags &= ~MCIS_TAG_DISABLE; 3031 3032 if (mcip->mci_state_flags & MCIS_STRIP_DISABLE) 3033 mcip->mci_state_flags &= ~MCIS_STRIP_DISABLE; 3034 3035 if (mcip->mci_state_flags & MCIS_DISABLE_TX_VID_CHECK) 3036 mcip->mci_state_flags &= ~MCIS_DISABLE_TX_VID_CHECK; 3037 3038 if (muip != NULL) 3039 kmem_free(muip, sizeof (mac_unicast_impl_t)); 3040 mac_protect_cancel_timer(mcip); 3041 mac_protect_flush_dynamic(mcip); 3042 3043 bzero(&mcip->mci_misc_stat, sizeof (mcip->mci_misc_stat)); 3044 /* 3045 * Disable fastpath if this is a VNIC or a VLAN. 3046 */ 3047 if (mcip->mci_state_flags & MCIS_IS_VNIC) 3048 mac_fastpath_enable((mac_handle_t)mip); 3049 mac_stop((mac_handle_t)mip); 3050 } 3051 3052 /* 3053 * Remove a MAC address which was previously added by mac_unicast_add(). 3054 */ 3055 int 3056 mac_unicast_remove(mac_client_handle_t mch, mac_unicast_handle_t mah) 3057 { 3058 mac_client_impl_t *mcip = (mac_client_impl_t *)mch; 3059 mac_unicast_impl_t *muip = (mac_unicast_impl_t *)mah; 3060 mac_unicast_impl_t *pre; 3061 mac_impl_t *mip = mcip->mci_mip; 3062 flow_entry_t *flent; 3063 uint16_t mui_vid; 3064 3065 i_mac_perim_enter(mip); 3066 if (mcip->mci_flags & MAC_CLIENT_FLAGS_VNIC_PRIMARY) { 3067 /* 3068 * Call made by the upper MAC client of a VNIC. 3069 * There's nothing much to do, the unicast address will 3070 * be removed by the VNIC driver when the VNIC is deleted, 3071 * but let's ensure that all our transmit is done before 3072 * the client does a mac_client_stop lest it trigger an 3073 * assert in the driver. 3074 */ 3075 ASSERT(muip->mui_vid == VLAN_ID_NONE); 3076 3077 mac_tx_client_flush(mcip); 3078 3079 if ((mcip->mci_flags & MAC_CLIENT_FLAGS_PASSIVE_PRIMARY) != 0) { 3080 mcip->mci_flags &= ~MAC_CLIENT_FLAGS_PASSIVE_PRIMARY; 3081 if (mcip->mci_rx_p_fn != NULL) { 3082 mac_rx_set(mch, mcip->mci_rx_p_fn, 3083 mcip->mci_rx_p_arg); 3084 mcip->mci_rx_p_fn = NULL; 3085 mcip->mci_rx_p_arg = NULL; 3086 } 3087 kmem_free(muip, sizeof (mac_unicast_impl_t)); 3088 i_mac_perim_exit(mip); 3089 return (0); 3090 } 3091 mcip->mci_flags &= ~MAC_CLIENT_FLAGS_VNIC_PRIMARY; 3092 3093 if (mcip->mci_state_flags & MCIS_TAG_DISABLE) 3094 mcip->mci_state_flags &= ~MCIS_TAG_DISABLE; 3095 3096 if (mcip->mci_state_flags & MCIS_STRIP_DISABLE) 3097 mcip->mci_state_flags &= ~MCIS_STRIP_DISABLE; 3098 3099 if (mcip->mci_state_flags & MCIS_DISABLE_TX_VID_CHECK) 3100 mcip->mci_state_flags &= ~MCIS_DISABLE_TX_VID_CHECK; 3101 3102 kmem_free(muip, sizeof (mac_unicast_impl_t)); 3103 i_mac_perim_exit(mip); 3104 return (0); 3105 } 3106 3107 ASSERT(muip != NULL); 3108 3109 /* 3110 * We are removing a passive client, we haven't setup the datapath 3111 * for this yet, so nothing much to do. 3112 */ 3113 if ((mcip->mci_flags & MAC_CLIENT_FLAGS_PASSIVE_PRIMARY) != 0) { 3114 3115 ASSERT((mcip->mci_flent->fe_flags & FE_MC_NO_DATAPATH) != 0); 3116 ASSERT(mcip->mci_p_unicast_list == muip); 3117 3118 mcip->mci_flags &= ~MAC_CLIENT_FLAGS_PASSIVE_PRIMARY; 3119 3120 mcip->mci_p_unicast_list = NULL; 3121 mcip->mci_rx_p_fn = NULL; 3122 mcip->mci_rx_p_arg = NULL; 3123 3124 mcip->mci_state_flags &= ~MCIS_UNICAST_HW; 3125 3126 if (mcip->mci_state_flags & MCIS_TAG_DISABLE) 3127 mcip->mci_state_flags &= ~MCIS_TAG_DISABLE; 3128 3129 if (mcip->mci_state_flags & MCIS_STRIP_DISABLE) 3130 mcip->mci_state_flags &= ~MCIS_STRIP_DISABLE; 3131 3132 if (mcip->mci_state_flags & MCIS_DISABLE_TX_VID_CHECK) 3133 mcip->mci_state_flags &= ~MCIS_DISABLE_TX_VID_CHECK; 3134 3135 kmem_free(muip, sizeof (mac_unicast_impl_t)); 3136 i_mac_perim_exit(mip); 3137 return (0); 3138 } 3139 3140 /* 3141 * Remove the VID from the list of client's VIDs. 3142 */ 3143 pre = mcip->mci_unicast_list; 3144 if (muip == pre) { 3145 mcip->mci_unicast_list = muip->mui_next; 3146 } else { 3147 while ((pre->mui_next != NULL) && (pre->mui_next != muip)) 3148 pre = pre->mui_next; 3149 ASSERT(pre->mui_next == muip); 3150 rw_enter(&mcip->mci_rw_lock, RW_WRITER); 3151 pre->mui_next = muip->mui_next; 3152 rw_exit(&mcip->mci_rw_lock); 3153 } 3154 3155 if (!mac_client_single_rcvr(mcip)) { 3156 /* 3157 * This MAC client is shared by more than one unicast 3158 * addresses, so we will just remove the flent 3159 * corresponding to the address being removed. We don't invoke 3160 * mac_rx_classify_flow_rem() since the additional flow is 3161 * not associated with its own separate set of SRS and rings, 3162 * and these constructs are still needed for the remaining 3163 * flows. 3164 */ 3165 flent = mac_client_get_flow(mcip, muip); 3166 VERIFY3P(flent, !=, NULL); 3167 3168 /* 3169 * The first one is disappearing, need to make sure 3170 * we replace it with another from the list of 3171 * shared clients. 3172 */ 3173 if (flent == mcip->mci_flent) 3174 flent = mac_client_swap_mciflent(mcip); 3175 mac_client_remove_flow_from_list(mcip, flent); 3176 mac_flow_remove(mip->mi_flow_tab, flent, B_FALSE); 3177 mac_flow_wait(flent, FLOW_DRIVER_UPCALL); 3178 3179 /* 3180 * The multicast groups that were added by the client so 3181 * far must be removed from the brodcast domain corresponding 3182 * to the VID being removed. 3183 */ 3184 mac_client_bcast_refresh(mcip, mac_client_update_mcast, 3185 (void *)flent, B_FALSE); 3186 3187 if (mip->mi_type->mt_brdcst_addr != NULL) { 3188 mac_bcast_delete(mcip, mip->mi_type->mt_brdcst_addr, 3189 muip->mui_vid); 3190 } 3191 3192 FLOW_FINAL_REFRELE(flent); 3193 ASSERT(!(mcip->mci_state_flags & MCIS_EXCLUSIVE)); 3194 3195 /* 3196 * Enable fastpath if this is a VNIC or a VLAN. 3197 */ 3198 if (mcip->mci_state_flags & MCIS_IS_VNIC) 3199 mac_fastpath_enable((mac_handle_t)mip); 3200 mac_stop((mac_handle_t)mip); 3201 i_mac_perim_exit(mip); 3202 return (0); 3203 } 3204 3205 mui_vid = muip->mui_vid; 3206 mac_client_datapath_teardown(mch, muip, flent); 3207 3208 if ((mcip->mci_flags & MAC_CLIENT_FLAGS_PRIMARY) && 3209 mui_vid == VLAN_ID_NONE) { 3210 mcip->mci_flags &= ~MAC_CLIENT_FLAGS_PRIMARY; 3211 } else { 3212 i_mac_perim_exit(mip); 3213 return (0); 3214 } 3215 3216 /* 3217 * If we are removing the primary, check if we have a passive primary 3218 * client that we need to activate now. 3219 */ 3220 mcip = mac_get_passive_primary_client(mip); 3221 if (mcip != NULL) { 3222 mac_resource_props_t *mrp; 3223 mac_unicast_impl_t *muip; 3224 3225 mcip->mci_flags &= ~MAC_CLIENT_FLAGS_PASSIVE_PRIMARY; 3226 mrp = kmem_zalloc(sizeof (*mrp), KM_SLEEP); 3227 3228 /* 3229 * Apply the property cached in the mac_impl_t to the 3230 * primary mac client. 3231 */ 3232 mac_get_resources((mac_handle_t)mip, mrp); 3233 (void) mac_client_set_resources(mch, mrp); 3234 ASSERT(mcip->mci_p_unicast_list != NULL); 3235 muip = mcip->mci_p_unicast_list; 3236 mcip->mci_p_unicast_list = NULL; 3237 if (mac_client_datapath_setup(mcip, VLAN_ID_NONE, 3238 mip->mi_addr, mrp, B_TRUE, muip) == 0) { 3239 if (mcip->mci_rx_p_fn != NULL) { 3240 mac_rx_set(mch, mcip->mci_rx_p_fn, 3241 mcip->mci_rx_p_arg); 3242 mcip->mci_rx_p_fn = NULL; 3243 mcip->mci_rx_p_arg = NULL; 3244 } 3245 } else { 3246 kmem_free(muip, sizeof (mac_unicast_impl_t)); 3247 } 3248 kmem_free(mrp, sizeof (*mrp)); 3249 } 3250 i_mac_perim_exit(mip); 3251 return (0); 3252 } 3253 3254 /* 3255 * Multicast add function invoked by MAC clients. 3256 */ 3257 int 3258 mac_multicast_add(mac_client_handle_t mch, const uint8_t *addr) 3259 { 3260 mac_client_impl_t *mcip = (mac_client_impl_t *)mch; 3261 mac_impl_t *mip = mcip->mci_mip; 3262 flow_entry_t *flent = mcip->mci_flent_list; 3263 flow_entry_t *prev_fe = NULL; 3264 uint16_t vid; 3265 int err = 0; 3266 3267 /* Verify the address is a valid multicast address */ 3268 if ((err = mip->mi_type->mt_ops.mtops_multicst_verify(addr, 3269 mip->mi_pdata)) != 0) 3270 return (err); 3271 3272 i_mac_perim_enter(mip); 3273 while (flent != NULL) { 3274 vid = i_mac_flow_vid(flent); 3275 3276 err = mac_bcast_add((mac_client_impl_t *)mch, addr, vid, 3277 MAC_ADDRTYPE_MULTICAST); 3278 if (err != 0) 3279 break; 3280 prev_fe = flent; 3281 flent = flent->fe_client_next; 3282 } 3283 3284 /* 3285 * If we failed adding, then undo all, rather than partial 3286 * success. 3287 */ 3288 if (flent != NULL && prev_fe != NULL) { 3289 flent = mcip->mci_flent_list; 3290 while (flent != prev_fe->fe_client_next) { 3291 vid = i_mac_flow_vid(flent); 3292 mac_bcast_delete((mac_client_impl_t *)mch, addr, vid); 3293 flent = flent->fe_client_next; 3294 } 3295 } 3296 i_mac_perim_exit(mip); 3297 return (err); 3298 } 3299 3300 /* 3301 * Multicast delete function invoked by MAC clients. 3302 */ 3303 void 3304 mac_multicast_remove(mac_client_handle_t mch, const uint8_t *addr) 3305 { 3306 mac_client_impl_t *mcip = (mac_client_impl_t *)mch; 3307 mac_impl_t *mip = mcip->mci_mip; 3308 flow_entry_t *flent; 3309 uint16_t vid; 3310 3311 i_mac_perim_enter(mip); 3312 for (flent = mcip->mci_flent_list; flent != NULL; 3313 flent = flent->fe_client_next) { 3314 vid = i_mac_flow_vid(flent); 3315 mac_bcast_delete((mac_client_impl_t *)mch, addr, vid); 3316 } 3317 i_mac_perim_exit(mip); 3318 } 3319 3320 /* 3321 * When a MAC client desires to capture packets on an interface, 3322 * it registers a promiscuous call back with mac_promisc_add(). 3323 * There are three types of promiscuous callbacks: 3324 * 3325 * * MAC_CLIENT_PROMISC_ALL 3326 * Captures all packets sent and received by the MAC client, 3327 * the physical interface, as well as all other MAC clients 3328 * defined on top of the same MAC. 3329 * 3330 * * MAC_CLIENT_PROMISC_FILTERED 3331 * Captures all packets sent and received by the MAC client, 3332 * plus all multicast traffic sent and received by the phyisical 3333 * interface and the other MAC clients. 3334 * 3335 * * MAC_CLIENT_PROMISC_MULTI 3336 * Captures all broadcast and multicast packets sent and 3337 * received by the MAC clients as well as the physical interface. 3338 * 3339 * In all cases, the underlying MAC is put in promiscuous mode. 3340 */ 3341 int 3342 mac_promisc_add(mac_client_handle_t mch, mac_client_promisc_type_t type, 3343 mac_rx_t fn, void *arg, mac_promisc_handle_t *mphp, uint16_t flags) 3344 { 3345 mac_client_impl_t *mcip = (mac_client_impl_t *)mch; 3346 mac_impl_t *mip = mcip->mci_mip; 3347 mac_promisc_impl_t *mpip; 3348 mac_cb_info_t *mcbi; 3349 int rc; 3350 3351 i_mac_perim_enter(mip); 3352 3353 if ((rc = mac_start((mac_handle_t)mip)) != 0) { 3354 i_mac_perim_exit(mip); 3355 return (rc); 3356 } 3357 3358 if ((mcip->mci_state_flags & MCIS_IS_VNIC) && 3359 type == MAC_CLIENT_PROMISC_ALL && 3360 (mcip->mci_protect_flags & MPT_FLAG_PROMISC_FILTERED)) { 3361 /* 3362 * The function is being invoked by the upper MAC client 3363 * of a VNIC. The VNIC should only see the traffic 3364 * it is entitled to. 3365 */ 3366 type = MAC_CLIENT_PROMISC_FILTERED; 3367 } 3368 3369 3370 /* 3371 * Turn on promiscuous mode for the underlying NIC. 3372 * This is needed even for filtered callbacks which 3373 * expect to receive all multicast traffic on the wire. 3374 * 3375 * Physical promiscuous mode should not be turned on if 3376 * MAC_PROMISC_FLAGS_NO_PHYS is set. 3377 */ 3378 if ((flags & MAC_PROMISC_FLAGS_NO_PHYS) == 0) { 3379 if ((rc = i_mac_promisc_set(mip, B_TRUE)) != 0) { 3380 mac_stop((mac_handle_t)mip); 3381 i_mac_perim_exit(mip); 3382 return (rc); 3383 } 3384 } 3385 3386 mpip = kmem_cache_alloc(mac_promisc_impl_cache, KM_SLEEP); 3387 3388 mpip->mpi_type = type; 3389 mpip->mpi_fn = fn; 3390 mpip->mpi_arg = arg; 3391 mpip->mpi_mcip = mcip; 3392 mpip->mpi_no_tx_loop = ((flags & MAC_PROMISC_FLAGS_NO_TX_LOOP) != 0); 3393 mpip->mpi_no_phys = ((flags & MAC_PROMISC_FLAGS_NO_PHYS) != 0); 3394 mpip->mpi_strip_vlan_tag = 3395 ((flags & MAC_PROMISC_FLAGS_VLAN_TAG_STRIP) != 0); 3396 mpip->mpi_no_copy = ((flags & MAC_PROMISC_FLAGS_NO_COPY) != 0); 3397 3398 mcbi = &mip->mi_promisc_cb_info; 3399 mutex_enter(mcbi->mcbi_lockp); 3400 3401 mac_callback_add(&mip->mi_promisc_cb_info, &mcip->mci_promisc_list, 3402 &mpip->mpi_mci_link); 3403 mac_callback_add(&mip->mi_promisc_cb_info, &mip->mi_promisc_list, 3404 &mpip->mpi_mi_link); 3405 3406 mutex_exit(mcbi->mcbi_lockp); 3407 3408 *mphp = (mac_promisc_handle_t)mpip; 3409 3410 if (mcip->mci_state_flags & MCIS_IS_VNIC) { 3411 mac_impl_t *umip = mcip->mci_upper_mip; 3412 3413 ASSERT(umip != NULL); 3414 mac_vnic_secondary_update(umip); 3415 } 3416 3417 i_mac_perim_exit(mip); 3418 3419 return (0); 3420 } 3421 3422 /* 3423 * Remove a multicast address previously aded through mac_promisc_add(). 3424 */ 3425 void 3426 mac_promisc_remove(mac_promisc_handle_t mph) 3427 { 3428 mac_promisc_impl_t *mpip = (mac_promisc_impl_t *)mph; 3429 mac_client_impl_t *mcip = mpip->mpi_mcip; 3430 mac_impl_t *mip = mcip->mci_mip; 3431 mac_cb_info_t *mcbi; 3432 int rv; 3433 3434 i_mac_perim_enter(mip); 3435 3436 /* 3437 * Even if the device can't be reset into normal mode, we still 3438 * need to clear the client promisc callbacks. The client may want 3439 * to close the mac end point and we can't have stale callbacks. 3440 */ 3441 if (!(mpip->mpi_no_phys)) { 3442 if ((rv = i_mac_promisc_set(mip, B_FALSE)) != 0) { 3443 cmn_err(CE_WARN, "%s: failed to switch OFF promiscuous" 3444 " mode because of error 0x%x", mip->mi_name, rv); 3445 } 3446 } 3447 mcbi = &mip->mi_promisc_cb_info; 3448 mutex_enter(mcbi->mcbi_lockp); 3449 if (mac_callback_remove(mcbi, &mip->mi_promisc_list, 3450 &mpip->mpi_mi_link)) { 3451 VERIFY(mac_callback_remove(&mip->mi_promisc_cb_info, 3452 &mcip->mci_promisc_list, &mpip->mpi_mci_link)); 3453 kmem_cache_free(mac_promisc_impl_cache, mpip); 3454 } else { 3455 mac_callback_remove_wait(&mip->mi_promisc_cb_info); 3456 } 3457 3458 if (mcip->mci_state_flags & MCIS_IS_VNIC) { 3459 mac_impl_t *umip = mcip->mci_upper_mip; 3460 3461 ASSERT(umip != NULL); 3462 mac_vnic_secondary_update(umip); 3463 } 3464 3465 mutex_exit(mcbi->mcbi_lockp); 3466 mac_stop((mac_handle_t)mip); 3467 3468 i_mac_perim_exit(mip); 3469 } 3470 3471 /* 3472 * Reference count the number of active Tx threads. MCI_TX_QUIESCE indicates 3473 * that a control operation wants to quiesce the Tx data flow in which case 3474 * we return an error. Holding any of the per cpu locks ensures that the 3475 * mci_tx_flag won't change. 3476 * 3477 * 'CPU' must be accessed just once and used to compute the index into the 3478 * percpu array, and that index must be used for the entire duration of the 3479 * packet send operation. Note that the thread may be preempted and run on 3480 * another cpu any time and so we can't use 'CPU' more than once for the 3481 * operation. 3482 */ 3483 #define MAC_TX_TRY_HOLD(mcip, mytx, error) \ 3484 { \ 3485 (error) = 0; \ 3486 (mytx) = &(mcip)->mci_tx_pcpu[CPU->cpu_seqid & mac_tx_percpu_cnt]; \ 3487 mutex_enter(&(mytx)->pcpu_tx_lock); \ 3488 if (!((mcip)->mci_tx_flag & MCI_TX_QUIESCE)) { \ 3489 (mytx)->pcpu_tx_refcnt++; \ 3490 } else { \ 3491 (error) = -1; \ 3492 } \ 3493 mutex_exit(&(mytx)->pcpu_tx_lock); \ 3494 } 3495 3496 /* 3497 * Release the reference. If needed, signal any control operation waiting 3498 * for Tx quiescence. The wait and signal are always done using the 3499 * mci_tx_pcpu[0]'s lock 3500 */ 3501 #define MAC_TX_RELE(mcip, mytx) { \ 3502 mutex_enter(&(mytx)->pcpu_tx_lock); \ 3503 if (--(mytx)->pcpu_tx_refcnt == 0 && \ 3504 (mcip)->mci_tx_flag & MCI_TX_QUIESCE) { \ 3505 mutex_exit(&(mytx)->pcpu_tx_lock); \ 3506 mutex_enter(&(mcip)->mci_tx_pcpu[0].pcpu_tx_lock); \ 3507 cv_signal(&(mcip)->mci_tx_cv); \ 3508 mutex_exit(&(mcip)->mci_tx_pcpu[0].pcpu_tx_lock); \ 3509 } else { \ 3510 mutex_exit(&(mytx)->pcpu_tx_lock); \ 3511 } \ 3512 } 3513 3514 /* 3515 * Send function invoked by MAC clients. 3516 */ 3517 mac_tx_cookie_t 3518 mac_tx(mac_client_handle_t mch, mblk_t *mp_chain, uintptr_t hint, 3519 uint16_t flag, mblk_t **ret_mp) 3520 { 3521 mac_tx_cookie_t cookie = 0; 3522 int error; 3523 mac_tx_percpu_t *mytx; 3524 mac_soft_ring_set_t *srs; 3525 flow_entry_t *flent; 3526 boolean_t is_subflow = B_FALSE; 3527 mac_client_impl_t *mcip = (mac_client_impl_t *)mch; 3528 mac_impl_t *mip = mcip->mci_mip; 3529 mac_srs_tx_t *srs_tx; 3530 3531 /* 3532 * Check whether the active Tx threads count is bumped already. 3533 */ 3534 if (!(flag & MAC_TX_NO_HOLD)) { 3535 MAC_TX_TRY_HOLD(mcip, mytx, error); 3536 if (error != 0) { 3537 freemsgchain(mp_chain); 3538 return (0); 3539 } 3540 } 3541 3542 /* 3543 * If mac protection is enabled, only the permissible packets will be 3544 * returned by mac_protect_check(). 3545 */ 3546 if ((mcip->mci_flent-> 3547 fe_resource_props.mrp_mask & MRP_PROTECT) != 0 && 3548 (mp_chain = mac_protect_check(mch, mp_chain)) == NULL) 3549 goto done; 3550 3551 if (mcip->mci_subflow_tab != NULL && 3552 mcip->mci_subflow_tab->ft_flow_count > 0 && 3553 mac_flow_lookup(mcip->mci_subflow_tab, mp_chain, 3554 FLOW_OUTBOUND, &flent) == 0) { 3555 /* 3556 * The main assumption here is that if in the event 3557 * we get a chain, all the packets will be classified 3558 * to the same Flow/SRS. If this changes for any 3559 * reason, the following logic should change as well. 3560 * I suppose the fanout_hint also assumes this . 3561 */ 3562 ASSERT(flent != NULL); 3563 is_subflow = B_TRUE; 3564 } else { 3565 flent = mcip->mci_flent; 3566 } 3567 3568 srs = flent->fe_tx_srs; 3569 /* 3570 * This is to avoid panics with PF_PACKET that can call mac_tx() 3571 * against an interface that is not capable of sending. A rewrite 3572 * of the mac datapath is required to remove this limitation. 3573 */ 3574 if (srs == NULL) { 3575 freemsgchain(mp_chain); 3576 goto done; 3577 } 3578 3579 srs_tx = &srs->srs_tx; 3580 if (srs_tx->st_mode == SRS_TX_DEFAULT && 3581 (srs->srs_state & SRS_ENQUEUED) == 0 && 3582 mip->mi_nactiveclients == 1 && 3583 mp_chain->b_next == NULL && 3584 (DB_CKSUMFLAGS(mp_chain) & HW_LSO) == 0) { 3585 uint64_t obytes; 3586 3587 /* 3588 * Since dls always opens the underlying MAC, nclients equals 3589 * to 1 means that the only active client is dls itself acting 3590 * as a primary client of the MAC instance. Since dls will not 3591 * send tagged packets in that case, and dls is trusted to send 3592 * packets for its allowed VLAN(s), the VLAN tag insertion and 3593 * check is required only if nclients is greater than 1. 3594 */ 3595 if (mip->mi_nclients > 1) { 3596 if (MAC_VID_CHECK_NEEDED(mcip)) { 3597 int err = 0; 3598 3599 MAC_VID_CHECK(mcip, mp_chain, err); 3600 if (err != 0) { 3601 freemsg(mp_chain); 3602 mcip->mci_misc_stat.mms_txerrors++; 3603 goto done; 3604 } 3605 } 3606 if (MAC_TAG_NEEDED(mcip)) { 3607 mp_chain = mac_add_vlan_tag(mp_chain, 0, 3608 mac_client_vid(mch)); 3609 if (mp_chain == NULL) { 3610 mcip->mci_misc_stat.mms_txerrors++; 3611 goto done; 3612 } 3613 } 3614 } 3615 3616 obytes = (mp_chain->b_cont == NULL ? MBLKL(mp_chain) : 3617 msgdsize(mp_chain)); 3618 3619 mp_chain = mac_provider_tx(mip, srs_tx->st_arg2, mp_chain, 3620 mcip); 3621 3622 if (mp_chain == NULL) { 3623 cookie = 0; 3624 SRS_TX_STAT_UPDATE(srs, opackets, 1); 3625 SRS_TX_STAT_UPDATE(srs, obytes, obytes); 3626 } else { 3627 mutex_enter(&srs->srs_lock); 3628 cookie = mac_tx_srs_no_desc(srs, mp_chain, 3629 flag, ret_mp); 3630 mutex_exit(&srs->srs_lock); 3631 } 3632 } else { 3633 mblk_t *mp = mp_chain; 3634 mblk_t *new_head = NULL; 3635 mblk_t *new_tail = NULL; 3636 3637 /* 3638 * There are occasions where the packets arriving here 3639 * may request hardware offloads that are not 3640 * available from the underlying MAC provider. This 3641 * currently only happens when a packet is sent across 3642 * the MAC-loopback path of one MAC and then forwarded 3643 * (via IP) to another MAC that lacks one or more of 3644 * the hardware offloads provided by the first one. 3645 * However, in the future, we may choose to pretend 3646 * all MAC providers support all offloads, performing 3647 * emulation on Tx as needed. 3648 * 3649 * We iterate each mblk in-turn, emulating hardware 3650 * offloads as required. From this process, we create 3651 * a new chain. The new chain may be the same as the 3652 * original chain (no hardware emulation needed), a 3653 * collection of new mblks (hardware emulation 3654 * needed), or a mix. At this point, the chain is safe 3655 * for consumption by the underlying MAC provider and 3656 * is passed down to the SRS. 3657 */ 3658 while (mp != NULL) { 3659 mblk_t *next = mp->b_next; 3660 mblk_t *tail = NULL; 3661 const uint16_t needed = 3662 (DB_CKSUMFLAGS(mp) ^ mip->mi_tx_cksum_flags) & 3663 DB_CKSUMFLAGS(mp); 3664 3665 mp->b_next = NULL; 3666 3667 if ((needed & (HCK_TX_FLAGS | HW_LSO_FLAGS)) != 0) { 3668 mac_emul_t emul = 0; 3669 3670 if (needed & HCK_IPV4_HDRCKSUM) 3671 emul |= MAC_IPCKSUM_EMUL; 3672 if (needed & (HCK_PARTIALCKSUM | HCK_FULLCKSUM)) 3673 emul |= MAC_HWCKSUM_EMUL; 3674 if (needed & HW_LSO) 3675 emul = MAC_LSO_EMUL; 3676 3677 mac_hw_emul(&mp, &tail, NULL, emul); 3678 3679 if (mp == NULL) { 3680 mp = next; 3681 continue; 3682 } 3683 } 3684 3685 if (new_head == NULL) { 3686 new_head = mp; 3687 } else { 3688 new_tail->b_next = mp; 3689 } 3690 3691 new_tail = (tail == NULL) ? mp : tail; 3692 mp = next; 3693 } 3694 3695 if (new_head == NULL) { 3696 cookie = 0; 3697 goto done; 3698 } 3699 3700 cookie = srs_tx->st_func(srs, new_head, hint, flag, ret_mp); 3701 } 3702 3703 done: 3704 if (is_subflow) 3705 FLOW_REFRELE(flent); 3706 3707 if (!(flag & MAC_TX_NO_HOLD)) 3708 MAC_TX_RELE(mcip, mytx); 3709 3710 return (cookie); 3711 } 3712 3713 /* 3714 * mac_tx_is_blocked 3715 * 3716 * Given a cookie, it returns if the ring identified by the cookie is 3717 * flow-controlled or not. If NULL is passed in place of a cookie, 3718 * then it finds out if any of the underlying rings belonging to the 3719 * SRS is flow controlled or not and returns that status. 3720 */ 3721 /* ARGSUSED */ 3722 boolean_t 3723 mac_tx_is_flow_blocked(mac_client_handle_t mch, mac_tx_cookie_t cookie) 3724 { 3725 mac_client_impl_t *mcip = (mac_client_impl_t *)mch; 3726 mac_soft_ring_set_t *mac_srs; 3727 mac_soft_ring_t *sringp; 3728 boolean_t blocked = B_FALSE; 3729 mac_tx_percpu_t *mytx; 3730 int err; 3731 int i; 3732 3733 /* 3734 * Bump the reference count so that mac_srs won't be deleted. 3735 * If the client is currently quiesced and we failed to bump 3736 * the reference, return B_TRUE so that flow control stays 3737 * as enabled. 3738 * 3739 * Flow control will then be disabled once the client is no 3740 * longer quiesced. 3741 */ 3742 MAC_TX_TRY_HOLD(mcip, mytx, err); 3743 if (err != 0) 3744 return (B_TRUE); 3745 3746 if ((mac_srs = MCIP_TX_SRS(mcip)) == NULL) { 3747 MAC_TX_RELE(mcip, mytx); 3748 return (B_FALSE); 3749 } 3750 3751 mutex_enter(&mac_srs->srs_lock); 3752 /* 3753 * Only in the case of TX_FANOUT and TX_AGGR, the underlying 3754 * softring (s_ring_state) will have the HIWAT set. This is 3755 * the multiple Tx ring flow control case. For all other 3756 * case, SRS (srs_state) will store the condition. 3757 */ 3758 if (mac_srs->srs_tx.st_mode == SRS_TX_FANOUT || 3759 mac_srs->srs_tx.st_mode == SRS_TX_AGGR) { 3760 if (cookie != 0) { 3761 sringp = (mac_soft_ring_t *)cookie; 3762 mutex_enter(&sringp->s_ring_lock); 3763 if (sringp->s_ring_state & S_RING_TX_HIWAT) 3764 blocked = B_TRUE; 3765 mutex_exit(&sringp->s_ring_lock); 3766 } else { 3767 for (i = 0; i < mac_srs->srs_tx_ring_count; i++) { 3768 sringp = mac_srs->srs_tx_soft_rings[i]; 3769 mutex_enter(&sringp->s_ring_lock); 3770 if (sringp->s_ring_state & S_RING_TX_HIWAT) { 3771 blocked = B_TRUE; 3772 mutex_exit(&sringp->s_ring_lock); 3773 break; 3774 } 3775 mutex_exit(&sringp->s_ring_lock); 3776 } 3777 } 3778 } else { 3779 blocked = (mac_srs->srs_state & SRS_TX_HIWAT); 3780 } 3781 mutex_exit(&mac_srs->srs_lock); 3782 MAC_TX_RELE(mcip, mytx); 3783 return (blocked); 3784 } 3785 3786 /* 3787 * Check if the MAC client is the primary MAC client. 3788 */ 3789 boolean_t 3790 mac_is_primary_client(mac_client_impl_t *mcip) 3791 { 3792 return (mcip->mci_flags & MAC_CLIENT_FLAGS_PRIMARY); 3793 } 3794 3795 void 3796 mac_ioctl(mac_handle_t mh, queue_t *wq, mblk_t *bp) 3797 { 3798 mac_impl_t *mip = (mac_impl_t *)mh; 3799 int cmd = ((struct iocblk *)bp->b_rptr)->ioc_cmd; 3800 3801 if ((cmd == ND_GET && (mip->mi_callbacks->mc_callbacks & MC_GETPROP)) || 3802 (cmd == ND_SET && (mip->mi_callbacks->mc_callbacks & MC_SETPROP))) { 3803 /* 3804 * If ndd props were registered, call them. 3805 * Note that ndd ioctls are Obsolete 3806 */ 3807 mac_ndd_ioctl(mip, wq, bp); 3808 return; 3809 } 3810 3811 /* 3812 * Call the driver to handle the ioctl. The driver may not support 3813 * any ioctls, in which case we reply with a NAK on its behalf. 3814 */ 3815 if (mip->mi_callbacks->mc_callbacks & MC_IOCTL) 3816 mip->mi_ioctl(mip->mi_driver, wq, bp); 3817 else 3818 miocnak(wq, bp, 0, EINVAL); 3819 } 3820 3821 /* 3822 * Return the link state of the specified MAC instance. 3823 */ 3824 link_state_t 3825 mac_link_get(mac_handle_t mh) 3826 { 3827 return (((mac_impl_t *)mh)->mi_linkstate); 3828 } 3829 3830 /* 3831 * Add a mac client specified notification callback. Please see the comments 3832 * above mac_callback_add() for general information about mac callback 3833 * addition/deletion in the presence of mac callback list walkers 3834 */ 3835 mac_notify_handle_t 3836 mac_notify_add(mac_handle_t mh, mac_notify_t notify_fn, void *arg) 3837 { 3838 mac_impl_t *mip = (mac_impl_t *)mh; 3839 mac_notify_cb_t *mncb; 3840 mac_cb_info_t *mcbi; 3841 3842 /* 3843 * Allocate a notify callback structure, fill in the details and 3844 * use the mac callback list manipulation functions to chain into 3845 * the list of callbacks. 3846 */ 3847 mncb = kmem_zalloc(sizeof (mac_notify_cb_t), KM_SLEEP); 3848 mncb->mncb_fn = notify_fn; 3849 mncb->mncb_arg = arg; 3850 mncb->mncb_mip = mip; 3851 mncb->mncb_link.mcb_objp = mncb; 3852 mncb->mncb_link.mcb_objsize = sizeof (mac_notify_cb_t); 3853 mncb->mncb_link.mcb_flags = MCB_NOTIFY_CB_T; 3854 3855 mcbi = &mip->mi_notify_cb_info; 3856 3857 i_mac_perim_enter(mip); 3858 mutex_enter(mcbi->mcbi_lockp); 3859 3860 mac_callback_add(&mip->mi_notify_cb_info, &mip->mi_notify_cb_list, 3861 &mncb->mncb_link); 3862 3863 mutex_exit(mcbi->mcbi_lockp); 3864 i_mac_perim_exit(mip); 3865 return ((mac_notify_handle_t)mncb); 3866 } 3867 3868 void 3869 mac_notify_remove_wait(mac_handle_t mh) 3870 { 3871 mac_impl_t *mip = (mac_impl_t *)mh; 3872 mac_cb_info_t *mcbi = &mip->mi_notify_cb_info; 3873 3874 mutex_enter(mcbi->mcbi_lockp); 3875 mac_callback_remove_wait(&mip->mi_notify_cb_info); 3876 mutex_exit(mcbi->mcbi_lockp); 3877 } 3878 3879 /* 3880 * Remove a mac client specified notification callback 3881 */ 3882 int 3883 mac_notify_remove(mac_notify_handle_t mnh, boolean_t wait) 3884 { 3885 mac_notify_cb_t *mncb = (mac_notify_cb_t *)mnh; 3886 mac_impl_t *mip = mncb->mncb_mip; 3887 mac_cb_info_t *mcbi; 3888 int err = 0; 3889 3890 mcbi = &mip->mi_notify_cb_info; 3891 3892 i_mac_perim_enter(mip); 3893 mutex_enter(mcbi->mcbi_lockp); 3894 3895 ASSERT(mncb->mncb_link.mcb_objp == mncb); 3896 /* 3897 * If there aren't any list walkers, the remove would succeed 3898 * inline, else we wait for the deferred remove to complete 3899 */ 3900 if (mac_callback_remove(&mip->mi_notify_cb_info, 3901 &mip->mi_notify_cb_list, &mncb->mncb_link)) { 3902 kmem_free(mncb, sizeof (mac_notify_cb_t)); 3903 } else { 3904 err = EBUSY; 3905 } 3906 3907 mutex_exit(mcbi->mcbi_lockp); 3908 i_mac_perim_exit(mip); 3909 3910 /* 3911 * If we failed to remove the notification callback and "wait" is set 3912 * to be B_TRUE, wait for the callback to finish after we exit the 3913 * mac perimeter. 3914 */ 3915 if (err != 0 && wait) { 3916 mac_notify_remove_wait((mac_handle_t)mip); 3917 return (0); 3918 } 3919 3920 return (err); 3921 } 3922 3923 /* 3924 * Associate resource management callbacks with the specified MAC 3925 * clients. 3926 */ 3927 3928 void 3929 mac_resource_set_common(mac_client_handle_t mch, mac_resource_add_t add, 3930 mac_resource_remove_t remove, mac_resource_quiesce_t quiesce, 3931 mac_resource_restart_t restart, mac_resource_bind_t bind, 3932 void *arg) 3933 { 3934 mac_client_impl_t *mcip = (mac_client_impl_t *)mch; 3935 3936 mcip->mci_resource_add = add; 3937 mcip->mci_resource_remove = remove; 3938 mcip->mci_resource_quiesce = quiesce; 3939 mcip->mci_resource_restart = restart; 3940 mcip->mci_resource_bind = bind; 3941 mcip->mci_resource_arg = arg; 3942 } 3943 3944 void 3945 mac_resource_set(mac_client_handle_t mch, mac_resource_add_t add, void *arg) 3946 { 3947 /* update the 'resource_add' callback */ 3948 mac_resource_set_common(mch, add, NULL, NULL, NULL, NULL, arg); 3949 } 3950 3951 /* 3952 * Sets up the client resources and enable the polling interface over all the 3953 * SRS's and the soft rings of the client 3954 */ 3955 void 3956 mac_client_poll_enable(mac_client_handle_t mch) 3957 { 3958 mac_client_impl_t *mcip = (mac_client_impl_t *)mch; 3959 mac_soft_ring_set_t *mac_srs; 3960 flow_entry_t *flent; 3961 int i; 3962 3963 flent = mcip->mci_flent; 3964 ASSERT(flent != NULL); 3965 3966 mcip->mci_state_flags |= MCIS_CLIENT_POLL_CAPABLE; 3967 for (i = 0; i < flent->fe_rx_srs_cnt; i++) { 3968 mac_srs = (mac_soft_ring_set_t *)flent->fe_rx_srs[i]; 3969 ASSERT(mac_srs->srs_mcip == mcip); 3970 mac_srs_client_poll_enable(mcip, mac_srs); 3971 } 3972 } 3973 3974 /* 3975 * Tears down the client resources and disable the polling interface over all 3976 * the SRS's and the soft rings of the client 3977 */ 3978 void 3979 mac_client_poll_disable(mac_client_handle_t mch) 3980 { 3981 mac_client_impl_t *mcip = (mac_client_impl_t *)mch; 3982 mac_soft_ring_set_t *mac_srs; 3983 flow_entry_t *flent; 3984 int i; 3985 3986 flent = mcip->mci_flent; 3987 ASSERT(flent != NULL); 3988 3989 mcip->mci_state_flags &= ~MCIS_CLIENT_POLL_CAPABLE; 3990 for (i = 0; i < flent->fe_rx_srs_cnt; i++) { 3991 mac_srs = (mac_soft_ring_set_t *)flent->fe_rx_srs[i]; 3992 ASSERT(mac_srs->srs_mcip == mcip); 3993 mac_srs_client_poll_disable(mcip, mac_srs); 3994 } 3995 } 3996 3997 /* 3998 * Associate the CPUs specified by the given property with a MAC client. 3999 */ 4000 int 4001 mac_cpu_set(mac_client_handle_t mch, mac_resource_props_t *mrp) 4002 { 4003 mac_client_impl_t *mcip = (mac_client_impl_t *)mch; 4004 mac_impl_t *mip = mcip->mci_mip; 4005 int err = 0; 4006 4007 ASSERT(MAC_PERIM_HELD((mac_handle_t)mip)); 4008 4009 if ((err = mac_validate_props(mcip->mci_state_flags & MCIS_IS_VNIC ? 4010 mcip->mci_upper_mip : mip, mrp)) != 0) { 4011 return (err); 4012 } 4013 if (MCIP_DATAPATH_SETUP(mcip)) 4014 mac_flow_modify(mip->mi_flow_tab, mcip->mci_flent, mrp); 4015 4016 mac_update_resources(mrp, MCIP_RESOURCE_PROPS(mcip), B_FALSE); 4017 return (0); 4018 } 4019 4020 /* 4021 * Apply the specified properties to the specified MAC client. 4022 */ 4023 int 4024 mac_client_set_resources(mac_client_handle_t mch, mac_resource_props_t *mrp) 4025 { 4026 mac_client_impl_t *mcip = (mac_client_impl_t *)mch; 4027 mac_impl_t *mip = mcip->mci_mip; 4028 int err = 0; 4029 4030 i_mac_perim_enter(mip); 4031 4032 if ((mrp->mrp_mask & MRP_MAXBW) || (mrp->mrp_mask & MRP_PRIORITY)) { 4033 err = mac_resource_ctl_set(mch, mrp); 4034 if (err != 0) 4035 goto done; 4036 } 4037 4038 if (mrp->mrp_mask & (MRP_CPUS|MRP_POOL)) { 4039 err = mac_cpu_set(mch, mrp); 4040 if (err != 0) 4041 goto done; 4042 } 4043 4044 if (mrp->mrp_mask & MRP_PROTECT) { 4045 err = mac_protect_set(mch, mrp); 4046 if (err != 0) 4047 goto done; 4048 } 4049 4050 if ((mrp->mrp_mask & MRP_RX_RINGS) || (mrp->mrp_mask & MRP_TX_RINGS)) 4051 err = mac_resource_ctl_set(mch, mrp); 4052 4053 done: 4054 i_mac_perim_exit(mip); 4055 return (err); 4056 } 4057 4058 /* 4059 * Return the properties currently associated with the specified MAC client. 4060 */ 4061 void 4062 mac_client_get_resources(mac_client_handle_t mch, mac_resource_props_t *mrp) 4063 { 4064 mac_client_impl_t *mcip = (mac_client_impl_t *)mch; 4065 mac_resource_props_t *mcip_mrp = MCIP_RESOURCE_PROPS(mcip); 4066 4067 bcopy(mcip_mrp, mrp, sizeof (mac_resource_props_t)); 4068 } 4069 4070 /* 4071 * Return the effective properties currently associated with the specified 4072 * MAC client. 4073 */ 4074 void 4075 mac_client_get_effective_resources(mac_client_handle_t mch, 4076 mac_resource_props_t *mrp) 4077 { 4078 mac_client_impl_t *mcip = (mac_client_impl_t *)mch; 4079 mac_resource_props_t *mcip_mrp = MCIP_EFFECTIVE_PROPS(mcip); 4080 4081 bcopy(mcip_mrp, mrp, sizeof (mac_resource_props_t)); 4082 } 4083 4084 /* 4085 * Pass a copy of the specified packet to the promiscuous callbacks 4086 * of the specified MAC. 4087 * 4088 * If sender is NULL, the function is being invoked for a packet chain 4089 * received from the wire. If sender is non-NULL, it points to 4090 * the MAC client from which the packet is being sent. 4091 * 4092 * The packets are distributed to the promiscuous callbacks as follows: 4093 * 4094 * - all packets are sent to the MAC_CLIENT_PROMISC_ALL callbacks 4095 * - all broadcast and multicast packets are sent to the 4096 * MAC_CLIENT_PROMISC_FILTER and MAC_CLIENT_PROMISC_MULTI. 4097 * 4098 * The unicast packets of MAC_CLIENT_PROMISC_FILTER callbacks are dispatched 4099 * after classification by mac_rx_deliver(). 4100 */ 4101 static void 4102 mac_promisc_dispatch_one(mac_promisc_impl_t *mpip, mblk_t *mp, 4103 boolean_t loopback, boolean_t local) 4104 { 4105 mblk_t *mp_next; 4106 4107 if (!mpip->mpi_no_copy || mpip->mpi_strip_vlan_tag) { 4108 mblk_t *mp_copy; 4109 4110 mp_copy = copymsg(mp); 4111 if (mp_copy == NULL) 4112 return; 4113 4114 if (mpip->mpi_strip_vlan_tag) { 4115 mp_copy = mac_strip_vlan_tag_chain(mp_copy); 4116 if (mp_copy == NULL) 4117 return; 4118 } 4119 4120 /* 4121 * There is code upstack that can't deal with message 4122 * chains. 4123 */ 4124 for (mblk_t *tmp = mp_copy; tmp != NULL; tmp = mp_next) { 4125 mp_next = tmp->b_next; 4126 tmp->b_next = NULL; 4127 mpip->mpi_fn(mpip->mpi_arg, NULL, tmp, loopback); 4128 } 4129 4130 return; 4131 } 4132 4133 mp_next = mp->b_next; 4134 mp->b_next = NULL; 4135 mpip->mpi_fn(mpip->mpi_arg, NULL, mp, loopback); 4136 mp->b_next = mp_next; 4137 } 4138 4139 /* 4140 * Return the VID of a packet. Zero if the packet is not tagged. 4141 */ 4142 static uint16_t 4143 mac_ether_vid(mblk_t *mp) 4144 { 4145 struct ether_header *eth = (struct ether_header *)mp->b_rptr; 4146 4147 if (ntohs(eth->ether_type) == ETHERTYPE_VLAN) { 4148 struct ether_vlan_header *t_evhp = 4149 (struct ether_vlan_header *)mp->b_rptr; 4150 return (VLAN_ID(ntohs(t_evhp->ether_tci))); 4151 } 4152 4153 return (0); 4154 } 4155 4156 /* 4157 * Return whether the specified packet contains a multicast or broadcast 4158 * destination MAC address. 4159 */ 4160 static boolean_t 4161 mac_is_mcast(mac_impl_t *mip, mblk_t *mp) 4162 { 4163 mac_header_info_t hdr_info; 4164 4165 if (mac_header_info((mac_handle_t)mip, mp, &hdr_info) != 0) 4166 return (B_FALSE); 4167 return ((hdr_info.mhi_dsttype == MAC_ADDRTYPE_BROADCAST) || 4168 (hdr_info.mhi_dsttype == MAC_ADDRTYPE_MULTICAST)); 4169 } 4170 4171 /* 4172 * Send a copy of an mblk chain to the MAC clients of the specified MAC. 4173 * "sender" points to the sender MAC client for outbound packets, and 4174 * is set to NULL for inbound packets. 4175 */ 4176 void 4177 mac_promisc_dispatch(mac_impl_t *mip, mblk_t *mp_chain, 4178 mac_client_impl_t *sender, boolean_t local) 4179 { 4180 mac_promisc_impl_t *mpip; 4181 mac_cb_t *mcb; 4182 mblk_t *mp; 4183 boolean_t is_mcast, is_sender; 4184 4185 MAC_PROMISC_WALKER_INC(mip); 4186 for (mp = mp_chain; mp != NULL; mp = mp->b_next) { 4187 is_mcast = mac_is_mcast(mip, mp); 4188 /* send packet to interested callbacks */ 4189 for (mcb = mip->mi_promisc_list; mcb != NULL; 4190 mcb = mcb->mcb_nextp) { 4191 mpip = (mac_promisc_impl_t *)mcb->mcb_objp; 4192 is_sender = (mpip->mpi_mcip == sender); 4193 4194 if (is_sender && mpip->mpi_no_tx_loop) 4195 /* 4196 * The sender doesn't want to receive 4197 * copies of the packets it sends. 4198 */ 4199 continue; 4200 4201 /* this client doesn't need any packets (bridge) */ 4202 if (mpip->mpi_fn == NULL) 4203 continue; 4204 4205 /* 4206 * For an ethernet MAC, don't displatch a multicast 4207 * packet to a non-PROMISC_ALL callbacks unless the VID 4208 * of the packet matches the VID of the client. 4209 */ 4210 if (is_mcast && 4211 mpip->mpi_type != MAC_CLIENT_PROMISC_ALL && 4212 !mac_client_check_flow_vid(mpip->mpi_mcip, 4213 mac_ether_vid(mp))) 4214 continue; 4215 4216 if (is_sender || 4217 mpip->mpi_type == MAC_CLIENT_PROMISC_ALL || 4218 is_mcast) { 4219 mac_promisc_dispatch_one(mpip, mp, is_sender, 4220 local); 4221 } 4222 } 4223 } 4224 MAC_PROMISC_WALKER_DCR(mip); 4225 } 4226 4227 void 4228 mac_promisc_client_dispatch(mac_client_impl_t *mcip, mblk_t *mp_chain) 4229 { 4230 mac_impl_t *mip = mcip->mci_mip; 4231 mac_promisc_impl_t *mpip; 4232 boolean_t is_mcast; 4233 mblk_t *mp; 4234 mac_cb_t *mcb; 4235 4236 /* 4237 * The unicast packets for the MAC client still 4238 * need to be delivered to the MAC_CLIENT_PROMISC_FILTERED 4239 * promiscuous callbacks. The broadcast and multicast 4240 * packets were delivered from mac_rx(). 4241 */ 4242 MAC_PROMISC_WALKER_INC(mip); 4243 for (mp = mp_chain; mp != NULL; mp = mp->b_next) { 4244 is_mcast = mac_is_mcast(mip, mp); 4245 for (mcb = mcip->mci_promisc_list; mcb != NULL; 4246 mcb = mcb->mcb_nextp) { 4247 mpip = (mac_promisc_impl_t *)mcb->mcb_objp; 4248 if (mpip->mpi_type == MAC_CLIENT_PROMISC_FILTERED && 4249 !is_mcast) { 4250 mac_promisc_dispatch_one(mpip, mp, B_FALSE, 4251 B_FALSE); 4252 } 4253 } 4254 } 4255 MAC_PROMISC_WALKER_DCR(mip); 4256 } 4257 4258 /* 4259 * Return the margin value currently assigned to the specified MAC instance. 4260 */ 4261 void 4262 mac_margin_get(mac_handle_t mh, uint32_t *marginp) 4263 { 4264 mac_impl_t *mip = (mac_impl_t *)mh; 4265 4266 rw_enter(&(mip->mi_rw_lock), RW_READER); 4267 *marginp = mip->mi_margin; 4268 rw_exit(&(mip->mi_rw_lock)); 4269 } 4270 4271 /* 4272 * mac_info_get() is used for retrieving the mac_info when a DL_INFO_REQ is 4273 * issued before a DL_ATTACH_REQ. we walk the i_mac_impl_hash table and find 4274 * the first mac_impl_t with a matching driver name; then we copy its mac_info_t 4275 * to the caller. we do all this with i_mac_impl_lock held so the mac_impl_t 4276 * cannot disappear while we are accessing it. 4277 */ 4278 typedef struct i_mac_info_state_s { 4279 const char *mi_name; 4280 mac_info_t *mi_infop; 4281 } i_mac_info_state_t; 4282 4283 /*ARGSUSED*/ 4284 static uint_t 4285 i_mac_info_walker(mod_hash_key_t key, mod_hash_val_t *val, void *arg) 4286 { 4287 i_mac_info_state_t *statep = arg; 4288 mac_impl_t *mip = (mac_impl_t *)val; 4289 4290 if (mip->mi_state_flags & MIS_DISABLED) 4291 return (MH_WALK_CONTINUE); 4292 4293 if (strcmp(statep->mi_name, 4294 ddi_driver_name(mip->mi_dip)) != 0) 4295 return (MH_WALK_CONTINUE); 4296 4297 statep->mi_infop = &mip->mi_info; 4298 return (MH_WALK_TERMINATE); 4299 } 4300 4301 boolean_t 4302 mac_info_get(const char *name, mac_info_t *minfop) 4303 { 4304 i_mac_info_state_t state; 4305 4306 rw_enter(&i_mac_impl_lock, RW_READER); 4307 state.mi_name = name; 4308 state.mi_infop = NULL; 4309 mod_hash_walk(i_mac_impl_hash, i_mac_info_walker, &state); 4310 if (state.mi_infop == NULL) { 4311 rw_exit(&i_mac_impl_lock); 4312 return (B_FALSE); 4313 } 4314 *minfop = *state.mi_infop; 4315 rw_exit(&i_mac_impl_lock); 4316 return (B_TRUE); 4317 } 4318 4319 /* 4320 * To get the capabilities that MAC layer cares about, such as rings, factory 4321 * mac address, vnic or not, it should directly invoke this function. If the 4322 * link is part of a bridge, then the only "capability" it has is the inability 4323 * to do zero copy. 4324 */ 4325 boolean_t 4326 i_mac_capab_get(mac_handle_t mh, mac_capab_t cap, void *cap_data) 4327 { 4328 mac_impl_t *mip = (mac_impl_t *)mh; 4329 4330 if (mip->mi_bridge_link != NULL) { 4331 return (cap == MAC_CAPAB_NO_ZCOPY); 4332 } else if (mip->mi_callbacks->mc_callbacks & MC_GETCAPAB) { 4333 boolean_t res; 4334 4335 res = mip->mi_getcapab(mip->mi_driver, cap, cap_data); 4336 /* 4337 * Until we have suppport for TSOv6 emulation in the MAC 4338 * loopback path, do not allow the TSOv6 capability to be 4339 * advertised to consumers. 4340 */ 4341 if (res && cap == MAC_CAPAB_LSO) { 4342 mac_capab_lso_t *cap_lso = cap_data; 4343 4344 cap_lso->lso_flags &= ~LSO_TX_BASIC_TCP_IPV6; 4345 cap_lso->lso_basic_tcp_ipv6.lso_max = 0; 4346 } 4347 return (res); 4348 } else { 4349 return (B_FALSE); 4350 } 4351 } 4352 4353 /* 4354 * Capability query function. If number of active mac clients is greater than 4355 * 1, only limited capabilities can be advertised to the caller no matter the 4356 * driver has certain capability or not. Else, we query the driver to get the 4357 * capability. 4358 */ 4359 boolean_t 4360 mac_capab_get(mac_handle_t mh, mac_capab_t cap, void *cap_data) 4361 { 4362 mac_impl_t *mip = (mac_impl_t *)mh; 4363 4364 /* 4365 * Some capabilities are restricted when there are more than one active 4366 * clients on the MAC resource. The ones noted below are safe, 4367 * independent of that count. 4368 */ 4369 if (mip->mi_nactiveclients > 1) { 4370 switch (cap) { 4371 case MAC_CAPAB_NO_ZCOPY: 4372 return (B_TRUE); 4373 case MAC_CAPAB_LEGACY: 4374 case MAC_CAPAB_HCKSUM: 4375 case MAC_CAPAB_LSO: 4376 case MAC_CAPAB_NO_NATIVEVLAN: 4377 break; 4378 default: 4379 return (B_FALSE); 4380 } 4381 } 4382 4383 /* else get capab from driver */ 4384 return (i_mac_capab_get(mh, cap, cap_data)); 4385 } 4386 4387 boolean_t 4388 mac_sap_verify(mac_handle_t mh, uint32_t sap, uint32_t *bind_sap) 4389 { 4390 mac_impl_t *mip = (mac_impl_t *)mh; 4391 4392 return (mip->mi_type->mt_ops.mtops_sap_verify(sap, bind_sap, 4393 mip->mi_pdata)); 4394 } 4395 4396 mblk_t * 4397 mac_header(mac_handle_t mh, const uint8_t *daddr, uint32_t sap, mblk_t *payload, 4398 size_t extra_len) 4399 { 4400 mac_impl_t *mip = (mac_impl_t *)mh; 4401 const uint8_t *hdr_daddr; 4402 4403 /* 4404 * If the MAC is point-to-point with a fixed destination address, then 4405 * we must always use that destination in the MAC header. 4406 */ 4407 hdr_daddr = (mip->mi_dstaddr_set ? mip->mi_dstaddr : daddr); 4408 return (mip->mi_type->mt_ops.mtops_header(mip->mi_addr, hdr_daddr, sap, 4409 mip->mi_pdata, payload, extra_len)); 4410 } 4411 4412 int 4413 mac_header_info(mac_handle_t mh, mblk_t *mp, mac_header_info_t *mhip) 4414 { 4415 mac_impl_t *mip = (mac_impl_t *)mh; 4416 4417 return (mip->mi_type->mt_ops.mtops_header_info(mp, mip->mi_pdata, 4418 mhip)); 4419 } 4420 4421 int 4422 mac_vlan_header_info(mac_handle_t mh, mblk_t *mp, mac_header_info_t *mhip) 4423 { 4424 mac_impl_t *mip = (mac_impl_t *)mh; 4425 boolean_t is_ethernet = (mip->mi_info.mi_media == DL_ETHER); 4426 int err = 0; 4427 4428 /* 4429 * Packets should always be at least 16 bit aligned. 4430 */ 4431 ASSERT(IS_P2ALIGNED(mp->b_rptr, sizeof (uint16_t))); 4432 4433 if ((err = mac_header_info(mh, mp, mhip)) != 0) 4434 return (err); 4435 4436 /* 4437 * If this is a VLAN-tagged Ethernet packet, then the SAP in the 4438 * mac_header_info_t as returned by mac_header_info() is 4439 * ETHERTYPE_VLAN. We need to grab the ethertype from the VLAN header. 4440 */ 4441 if (is_ethernet && (mhip->mhi_bindsap == ETHERTYPE_VLAN)) { 4442 struct ether_vlan_header *evhp; 4443 uint16_t sap; 4444 mblk_t *tmp = NULL; 4445 size_t size; 4446 4447 size = sizeof (struct ether_vlan_header); 4448 if (MBLKL(mp) < size) { 4449 /* 4450 * Pullup the message in order to get the MAC header 4451 * infomation. Note that this is a read-only function, 4452 * we keep the input packet intact. 4453 */ 4454 if ((tmp = msgpullup(mp, size)) == NULL) 4455 return (EINVAL); 4456 4457 mp = tmp; 4458 } 4459 evhp = (struct ether_vlan_header *)mp->b_rptr; 4460 sap = ntohs(evhp->ether_type); 4461 (void) mac_sap_verify(mh, sap, &mhip->mhi_bindsap); 4462 mhip->mhi_hdrsize = sizeof (struct ether_vlan_header); 4463 mhip->mhi_tci = ntohs(evhp->ether_tci); 4464 mhip->mhi_istagged = B_TRUE; 4465 freemsg(tmp); 4466 4467 if (VLAN_CFI(mhip->mhi_tci) != ETHER_CFI) 4468 return (EINVAL); 4469 } else { 4470 mhip->mhi_istagged = B_FALSE; 4471 mhip->mhi_tci = 0; 4472 } 4473 4474 return (0); 4475 } 4476 4477 mblk_t * 4478 mac_header_cook(mac_handle_t mh, mblk_t *mp) 4479 { 4480 mac_impl_t *mip = (mac_impl_t *)mh; 4481 4482 if (mip->mi_type->mt_ops.mtops_ops & MTOPS_HEADER_COOK) { 4483 if (DB_REF(mp) > 1) { 4484 mblk_t *newmp = copymsg(mp); 4485 if (newmp == NULL) 4486 return (NULL); 4487 freemsg(mp); 4488 mp = newmp; 4489 } 4490 return (mip->mi_type->mt_ops.mtops_header_cook(mp, 4491 mip->mi_pdata)); 4492 } 4493 return (mp); 4494 } 4495 4496 mblk_t * 4497 mac_header_uncook(mac_handle_t mh, mblk_t *mp) 4498 { 4499 mac_impl_t *mip = (mac_impl_t *)mh; 4500 4501 if (mip->mi_type->mt_ops.mtops_ops & MTOPS_HEADER_UNCOOK) { 4502 if (DB_REF(mp) > 1) { 4503 mblk_t *newmp = copymsg(mp); 4504 if (newmp == NULL) 4505 return (NULL); 4506 freemsg(mp); 4507 mp = newmp; 4508 } 4509 return (mip->mi_type->mt_ops.mtops_header_uncook(mp, 4510 mip->mi_pdata)); 4511 } 4512 return (mp); 4513 } 4514 4515 uint_t 4516 mac_addr_len(mac_handle_t mh) 4517 { 4518 mac_impl_t *mip = (mac_impl_t *)mh; 4519 4520 return (mip->mi_type->mt_addr_length); 4521 } 4522 4523 /* True if a MAC is a VNIC */ 4524 boolean_t 4525 mac_is_vnic(mac_handle_t mh) 4526 { 4527 return (((mac_impl_t *)mh)->mi_state_flags & MIS_IS_VNIC); 4528 } 4529 4530 mac_handle_t 4531 mac_get_lower_mac_handle(mac_handle_t mh) 4532 { 4533 mac_impl_t *mip = (mac_impl_t *)mh; 4534 4535 ASSERT(mac_is_vnic(mh)); 4536 return (((vnic_t *)mip->mi_driver)->vn_lower_mh); 4537 } 4538 4539 boolean_t 4540 mac_is_vnic_primary(mac_handle_t mh) 4541 { 4542 mac_impl_t *mip = (mac_impl_t *)mh; 4543 4544 ASSERT(mac_is_vnic(mh)); 4545 return (((vnic_t *)mip->mi_driver)->vn_addr_type == 4546 VNIC_MAC_ADDR_TYPE_PRIMARY); 4547 } 4548 4549 void 4550 mac_update_resources(mac_resource_props_t *nmrp, mac_resource_props_t *cmrp, 4551 boolean_t is_user_flow) 4552 { 4553 if (nmrp != NULL && cmrp != NULL) { 4554 if (nmrp->mrp_mask & MRP_PRIORITY) { 4555 if (nmrp->mrp_priority == MPL_RESET) { 4556 cmrp->mrp_mask &= ~MRP_PRIORITY; 4557 if (is_user_flow) { 4558 cmrp->mrp_priority = 4559 MPL_SUBFLOW_DEFAULT; 4560 } else { 4561 cmrp->mrp_priority = MPL_LINK_DEFAULT; 4562 } 4563 } else { 4564 cmrp->mrp_mask |= MRP_PRIORITY; 4565 cmrp->mrp_priority = nmrp->mrp_priority; 4566 } 4567 } 4568 if (nmrp->mrp_mask & MRP_MAXBW) { 4569 if (nmrp->mrp_maxbw == MRP_MAXBW_RESETVAL) { 4570 cmrp->mrp_mask &= ~MRP_MAXBW; 4571 cmrp->mrp_maxbw = 0; 4572 } else { 4573 cmrp->mrp_mask |= MRP_MAXBW; 4574 cmrp->mrp_maxbw = nmrp->mrp_maxbw; 4575 } 4576 } 4577 if (nmrp->mrp_mask & MRP_CPUS) 4578 MAC_COPY_CPUS(nmrp, cmrp); 4579 4580 if (nmrp->mrp_mask & MRP_POOL) { 4581 if (strlen(nmrp->mrp_pool) == 0) { 4582 cmrp->mrp_mask &= ~MRP_POOL; 4583 bzero(cmrp->mrp_pool, sizeof (cmrp->mrp_pool)); 4584 } else { 4585 cmrp->mrp_mask |= MRP_POOL; 4586 (void) strncpy(cmrp->mrp_pool, nmrp->mrp_pool, 4587 sizeof (cmrp->mrp_pool)); 4588 } 4589 4590 } 4591 4592 if (nmrp->mrp_mask & MRP_PROTECT) 4593 mac_protect_update(nmrp, cmrp); 4594 4595 /* 4596 * Update the rings specified. 4597 */ 4598 if (nmrp->mrp_mask & MRP_RX_RINGS) { 4599 if (nmrp->mrp_mask & MRP_RINGS_RESET) { 4600 cmrp->mrp_mask &= ~MRP_RX_RINGS; 4601 if (cmrp->mrp_mask & MRP_RXRINGS_UNSPEC) 4602 cmrp->mrp_mask &= ~MRP_RXRINGS_UNSPEC; 4603 cmrp->mrp_nrxrings = 0; 4604 } else { 4605 cmrp->mrp_mask |= MRP_RX_RINGS; 4606 cmrp->mrp_nrxrings = nmrp->mrp_nrxrings; 4607 } 4608 } 4609 if (nmrp->mrp_mask & MRP_TX_RINGS) { 4610 if (nmrp->mrp_mask & MRP_RINGS_RESET) { 4611 cmrp->mrp_mask &= ~MRP_TX_RINGS; 4612 if (cmrp->mrp_mask & MRP_TXRINGS_UNSPEC) 4613 cmrp->mrp_mask &= ~MRP_TXRINGS_UNSPEC; 4614 cmrp->mrp_ntxrings = 0; 4615 } else { 4616 cmrp->mrp_mask |= MRP_TX_RINGS; 4617 cmrp->mrp_ntxrings = nmrp->mrp_ntxrings; 4618 } 4619 } 4620 if (nmrp->mrp_mask & MRP_RXRINGS_UNSPEC) 4621 cmrp->mrp_mask |= MRP_RXRINGS_UNSPEC; 4622 else if (cmrp->mrp_mask & MRP_RXRINGS_UNSPEC) 4623 cmrp->mrp_mask &= ~MRP_RXRINGS_UNSPEC; 4624 4625 if (nmrp->mrp_mask & MRP_TXRINGS_UNSPEC) 4626 cmrp->mrp_mask |= MRP_TXRINGS_UNSPEC; 4627 else if (cmrp->mrp_mask & MRP_TXRINGS_UNSPEC) 4628 cmrp->mrp_mask &= ~MRP_TXRINGS_UNSPEC; 4629 } 4630 } 4631 4632 /* 4633 * i_mac_set_resources: 4634 * 4635 * This routine associates properties with the primary MAC client of 4636 * the specified MAC instance. 4637 * - Cache the properties in mac_impl_t 4638 * - Apply the properties to the primary MAC client if exists 4639 */ 4640 int 4641 i_mac_set_resources(mac_handle_t mh, mac_resource_props_t *mrp) 4642 { 4643 mac_impl_t *mip = (mac_impl_t *)mh; 4644 mac_client_impl_t *mcip; 4645 int err = 0; 4646 uint32_t resmask, newresmask; 4647 mac_resource_props_t *tmrp, *umrp; 4648 4649 ASSERT(MAC_PERIM_HELD((mac_handle_t)mip)); 4650 4651 err = mac_validate_props(mip, mrp); 4652 if (err != 0) 4653 return (err); 4654 4655 umrp = kmem_zalloc(sizeof (*umrp), KM_SLEEP); 4656 bcopy(&mip->mi_resource_props, umrp, sizeof (*umrp)); 4657 resmask = umrp->mrp_mask; 4658 mac_update_resources(mrp, umrp, B_FALSE); 4659 newresmask = umrp->mrp_mask; 4660 4661 if (resmask == 0 && newresmask != 0) { 4662 /* 4663 * Bandwidth, priority, cpu or pool link properties configured, 4664 * must disable fastpath. 4665 */ 4666 if ((err = mac_fastpath_disable((mac_handle_t)mip)) != 0) { 4667 kmem_free(umrp, sizeof (*umrp)); 4668 return (err); 4669 } 4670 } 4671 4672 /* 4673 * Since bind_cpu may be modified by mac_client_set_resources() 4674 * we use a copy of bind_cpu and finally cache bind_cpu in mip. 4675 * This allows us to cache only user edits in mip. 4676 */ 4677 tmrp = kmem_zalloc(sizeof (*tmrp), KM_SLEEP); 4678 bcopy(mrp, tmrp, sizeof (*tmrp)); 4679 mcip = mac_primary_client_handle(mip); 4680 if (mcip != NULL && (mcip->mci_state_flags & MCIS_IS_AGGR_PORT) == 0) { 4681 err = mac_client_set_resources((mac_client_handle_t)mcip, tmrp); 4682 } else if ((mrp->mrp_mask & MRP_RX_RINGS || 4683 mrp->mrp_mask & MRP_TX_RINGS)) { 4684 mac_client_impl_t *vmcip; 4685 4686 /* 4687 * If the primary is not up, we need to check if there 4688 * are any VLANs on this primary. If there are then 4689 * we need to set this property on the VLANs since 4690 * VLANs follow the primary they are based on. Just 4691 * look for the first VLAN and change its properties, 4692 * all the other VLANs should be in the same group. 4693 */ 4694 for (vmcip = mip->mi_clients_list; vmcip != NULL; 4695 vmcip = vmcip->mci_client_next) { 4696 if ((vmcip->mci_flent->fe_type & FLOW_PRIMARY_MAC) && 4697 mac_client_vid((mac_client_handle_t)vmcip) != 4698 VLAN_ID_NONE) { 4699 break; 4700 } 4701 } 4702 if (vmcip != NULL) { 4703 mac_resource_props_t *omrp; 4704 mac_resource_props_t *vmrp; 4705 4706 omrp = kmem_zalloc(sizeof (*omrp), KM_SLEEP); 4707 bcopy(MCIP_RESOURCE_PROPS(vmcip), omrp, sizeof (*omrp)); 4708 /* 4709 * We dont' call mac_update_resources since we 4710 * want to take only the ring properties and 4711 * not all the properties that may have changed. 4712 */ 4713 vmrp = MCIP_RESOURCE_PROPS(vmcip); 4714 if (mrp->mrp_mask & MRP_RX_RINGS) { 4715 if (mrp->mrp_mask & MRP_RINGS_RESET) { 4716 vmrp->mrp_mask &= ~MRP_RX_RINGS; 4717 if (vmrp->mrp_mask & 4718 MRP_RXRINGS_UNSPEC) { 4719 vmrp->mrp_mask &= 4720 ~MRP_RXRINGS_UNSPEC; 4721 } 4722 vmrp->mrp_nrxrings = 0; 4723 } else { 4724 vmrp->mrp_mask |= MRP_RX_RINGS; 4725 vmrp->mrp_nrxrings = mrp->mrp_nrxrings; 4726 } 4727 } 4728 if (mrp->mrp_mask & MRP_TX_RINGS) { 4729 if (mrp->mrp_mask & MRP_RINGS_RESET) { 4730 vmrp->mrp_mask &= ~MRP_TX_RINGS; 4731 if (vmrp->mrp_mask & 4732 MRP_TXRINGS_UNSPEC) { 4733 vmrp->mrp_mask &= 4734 ~MRP_TXRINGS_UNSPEC; 4735 } 4736 vmrp->mrp_ntxrings = 0; 4737 } else { 4738 vmrp->mrp_mask |= MRP_TX_RINGS; 4739 vmrp->mrp_ntxrings = mrp->mrp_ntxrings; 4740 } 4741 } 4742 if (mrp->mrp_mask & MRP_RXRINGS_UNSPEC) 4743 vmrp->mrp_mask |= MRP_RXRINGS_UNSPEC; 4744 4745 if (mrp->mrp_mask & MRP_TXRINGS_UNSPEC) 4746 vmrp->mrp_mask |= MRP_TXRINGS_UNSPEC; 4747 4748 if ((err = mac_client_set_rings_prop(vmcip, mrp, 4749 omrp)) != 0) { 4750 bcopy(omrp, MCIP_RESOURCE_PROPS(vmcip), 4751 sizeof (*omrp)); 4752 } else { 4753 mac_set_prim_vlan_rings(mip, vmrp); 4754 } 4755 kmem_free(omrp, sizeof (*omrp)); 4756 } 4757 } 4758 4759 /* Only update the values if mac_client_set_resources succeeded */ 4760 if (err == 0) { 4761 bcopy(umrp, &mip->mi_resource_props, sizeof (*umrp)); 4762 /* 4763 * If bandwidth, priority or cpu link properties cleared, 4764 * renable fastpath. 4765 */ 4766 if (resmask != 0 && newresmask == 0) 4767 mac_fastpath_enable((mac_handle_t)mip); 4768 } else if (resmask == 0 && newresmask != 0) { 4769 mac_fastpath_enable((mac_handle_t)mip); 4770 } 4771 kmem_free(tmrp, sizeof (*tmrp)); 4772 kmem_free(umrp, sizeof (*umrp)); 4773 return (err); 4774 } 4775 4776 int 4777 mac_set_resources(mac_handle_t mh, mac_resource_props_t *mrp) 4778 { 4779 int err; 4780 4781 i_mac_perim_enter((mac_impl_t *)mh); 4782 err = i_mac_set_resources(mh, mrp); 4783 i_mac_perim_exit((mac_impl_t *)mh); 4784 return (err); 4785 } 4786 4787 /* 4788 * Get the properties cached for the specified MAC instance. 4789 */ 4790 void 4791 mac_get_resources(mac_handle_t mh, mac_resource_props_t *mrp) 4792 { 4793 mac_impl_t *mip = (mac_impl_t *)mh; 4794 mac_client_impl_t *mcip; 4795 4796 mcip = mac_primary_client_handle(mip); 4797 if (mcip != NULL) { 4798 mac_client_get_resources((mac_client_handle_t)mcip, mrp); 4799 return; 4800 } 4801 bcopy(&mip->mi_resource_props, mrp, sizeof (mac_resource_props_t)); 4802 } 4803 4804 /* 4805 * Get the effective properties from the primary client of the 4806 * specified MAC instance. 4807 */ 4808 void 4809 mac_get_effective_resources(mac_handle_t mh, mac_resource_props_t *mrp) 4810 { 4811 mac_impl_t *mip = (mac_impl_t *)mh; 4812 mac_client_impl_t *mcip; 4813 4814 mcip = mac_primary_client_handle(mip); 4815 if (mcip != NULL) { 4816 mac_client_get_effective_resources((mac_client_handle_t)mcip, 4817 mrp); 4818 return; 4819 } 4820 bzero(mrp, sizeof (mac_resource_props_t)); 4821 } 4822 4823 int 4824 mac_set_pvid(mac_handle_t mh, uint16_t pvid) 4825 { 4826 mac_impl_t *mip = (mac_impl_t *)mh; 4827 mac_client_impl_t *mcip; 4828 mac_unicast_impl_t *muip; 4829 4830 i_mac_perim_enter(mip); 4831 if (pvid != 0) { 4832 for (mcip = mip->mi_clients_list; mcip != NULL; 4833 mcip = mcip->mci_client_next) { 4834 for (muip = mcip->mci_unicast_list; muip != NULL; 4835 muip = muip->mui_next) { 4836 if (muip->mui_vid == pvid) { 4837 i_mac_perim_exit(mip); 4838 return (EBUSY); 4839 } 4840 } 4841 } 4842 } 4843 mip->mi_pvid = pvid; 4844 i_mac_perim_exit(mip); 4845 return (0); 4846 } 4847 4848 uint16_t 4849 mac_get_pvid(mac_handle_t mh) 4850 { 4851 mac_impl_t *mip = (mac_impl_t *)mh; 4852 4853 return (mip->mi_pvid); 4854 } 4855 4856 uint32_t 4857 mac_get_llimit(mac_handle_t mh) 4858 { 4859 mac_impl_t *mip = (mac_impl_t *)mh; 4860 4861 return (mip->mi_llimit); 4862 } 4863 4864 uint32_t 4865 mac_get_ldecay(mac_handle_t mh) 4866 { 4867 mac_impl_t *mip = (mac_impl_t *)mh; 4868 4869 return (mip->mi_ldecay); 4870 } 4871 4872 /* 4873 * Rename a mac client, its flow, and the kstat. 4874 */ 4875 int 4876 mac_rename_primary(mac_handle_t mh, const char *new_name) 4877 { 4878 mac_impl_t *mip = (mac_impl_t *)mh; 4879 mac_client_impl_t *cur_clnt = NULL; 4880 flow_entry_t *fep; 4881 4882 i_mac_perim_enter(mip); 4883 4884 /* 4885 * VNICs: we need to change the sys flow name and 4886 * the associated flow kstat. 4887 */ 4888 if (mip->mi_state_flags & MIS_IS_VNIC) { 4889 mac_client_impl_t *mcip = mac_vnic_lower(mip); 4890 ASSERT(new_name != NULL); 4891 mac_rename_flow_names(mcip, new_name); 4892 mac_stat_rename(mcip); 4893 goto done; 4894 } 4895 /* 4896 * This mac may itself be an aggr link, or it may have some client 4897 * which is an aggr port. For both cases, we need to change the 4898 * aggr port's mac client name, its flow name and the associated flow 4899 * kstat. 4900 */ 4901 if (mip->mi_state_flags & MIS_IS_AGGR) { 4902 mac_capab_aggr_t aggr_cap; 4903 mac_rename_fn_t rename_fn; 4904 boolean_t ret; 4905 4906 ASSERT(new_name != NULL); 4907 ret = i_mac_capab_get((mac_handle_t)mip, MAC_CAPAB_AGGR, 4908 (void *)(&aggr_cap)); 4909 ASSERT(ret == B_TRUE); 4910 rename_fn = aggr_cap.mca_rename_fn; 4911 rename_fn(new_name, mip->mi_driver); 4912 /* 4913 * The aggr's client name and kstat flow name will be 4914 * updated below, i.e. via mac_rename_flow_names. 4915 */ 4916 } 4917 4918 for (cur_clnt = mip->mi_clients_list; cur_clnt != NULL; 4919 cur_clnt = cur_clnt->mci_client_next) { 4920 if (cur_clnt->mci_state_flags & MCIS_IS_AGGR_PORT) { 4921 if (new_name != NULL) { 4922 char *str_st = cur_clnt->mci_name; 4923 char *str_del = strchr(str_st, '-'); 4924 4925 ASSERT(str_del != NULL); 4926 bzero(str_del + 1, MAXNAMELEN - 4927 (str_del - str_st + 1)); 4928 bcopy(new_name, str_del + 1, 4929 strlen(new_name)); 4930 } 4931 fep = cur_clnt->mci_flent; 4932 mac_rename_flow(fep, cur_clnt->mci_name); 4933 break; 4934 } else if (new_name != NULL && 4935 cur_clnt->mci_state_flags & MCIS_USE_DATALINK_NAME) { 4936 mac_rename_flow_names(cur_clnt, new_name); 4937 break; 4938 } 4939 } 4940 4941 /* Recreate kstats associated with aggr pseudo rings */ 4942 if (mip->mi_state_flags & MIS_IS_AGGR) 4943 mac_pseudo_ring_stat_rename(mip); 4944 4945 done: 4946 i_mac_perim_exit(mip); 4947 return (0); 4948 } 4949 4950 /* 4951 * Rename the MAC client's flow names 4952 */ 4953 static void 4954 mac_rename_flow_names(mac_client_impl_t *mcip, const char *new_name) 4955 { 4956 flow_entry_t *flent; 4957 uint16_t vid; 4958 char flowname[MAXFLOWNAMELEN]; 4959 mac_impl_t *mip = mcip->mci_mip; 4960 4961 ASSERT(MAC_PERIM_HELD((mac_handle_t)mip)); 4962 4963 /* 4964 * Use mi_rw_lock to ensure that threads not in the mac perimeter 4965 * see a self-consistent value for mci_name 4966 */ 4967 rw_enter(&mip->mi_rw_lock, RW_WRITER); 4968 (void) strlcpy(mcip->mci_name, new_name, sizeof (mcip->mci_name)); 4969 rw_exit(&mip->mi_rw_lock); 4970 4971 mac_rename_flow(mcip->mci_flent, new_name); 4972 4973 if (mcip->mci_nflents == 1) 4974 return; 4975 4976 /* 4977 * We have to rename all the others too, no stats to destroy for 4978 * these. 4979 */ 4980 for (flent = mcip->mci_flent_list; flent != NULL; 4981 flent = flent->fe_client_next) { 4982 if (flent != mcip->mci_flent) { 4983 vid = i_mac_flow_vid(flent); 4984 (void) sprintf(flowname, "%s%u", new_name, vid); 4985 mac_flow_set_name(flent, flowname); 4986 } 4987 } 4988 } 4989 4990 4991 /* 4992 * Add a flow to the MAC client's flow list - i.e list of MAC/VID tuples 4993 * defined for the specified MAC client. 4994 */ 4995 static void 4996 mac_client_add_to_flow_list(mac_client_impl_t *mcip, flow_entry_t *flent) 4997 { 4998 ASSERT(MAC_PERIM_HELD((mac_handle_t)mcip->mci_mip)); 4999 /* 5000 * The promisc Rx data path walks the mci_flent_list. Protect by 5001 * using mi_rw_lock 5002 */ 5003 rw_enter(&mcip->mci_rw_lock, RW_WRITER); 5004 5005 mcip->mci_vidcache = MCIP_VIDCACHE_INVALID; 5006 5007 /* Add it to the head */ 5008 flent->fe_client_next = mcip->mci_flent_list; 5009 mcip->mci_flent_list = flent; 5010 mcip->mci_nflents++; 5011 5012 /* 5013 * Keep track of the number of non-zero VIDs addresses per MAC 5014 * client to avoid figuring it out in the data-path. 5015 */ 5016 if (i_mac_flow_vid(flent) != VLAN_ID_NONE) 5017 mcip->mci_nvids++; 5018 5019 rw_exit(&mcip->mci_rw_lock); 5020 } 5021 5022 /* 5023 * Remove a flow entry from the MAC client's list. 5024 */ 5025 static void 5026 mac_client_remove_flow_from_list(mac_client_impl_t *mcip, flow_entry_t *flent) 5027 { 5028 flow_entry_t *fe = mcip->mci_flent_list; 5029 flow_entry_t *prev_fe = NULL; 5030 5031 ASSERT(MAC_PERIM_HELD((mac_handle_t)mcip->mci_mip)); 5032 /* 5033 * The promisc Rx data path walks the mci_flent_list. Protect by 5034 * using mci_rw_lock 5035 */ 5036 rw_enter(&mcip->mci_rw_lock, RW_WRITER); 5037 mcip->mci_vidcache = MCIP_VIDCACHE_INVALID; 5038 5039 while ((fe != NULL) && (fe != flent)) { 5040 prev_fe = fe; 5041 fe = fe->fe_client_next; 5042 } 5043 5044 ASSERT(fe != NULL); 5045 if (prev_fe == NULL) { 5046 /* Deleting the first node */ 5047 mcip->mci_flent_list = fe->fe_client_next; 5048 } else { 5049 prev_fe->fe_client_next = fe->fe_client_next; 5050 } 5051 mcip->mci_nflents--; 5052 5053 if (i_mac_flow_vid(flent) != VLAN_ID_NONE) 5054 mcip->mci_nvids--; 5055 5056 rw_exit(&mcip->mci_rw_lock); 5057 } 5058 5059 /* 5060 * Check if the given VID belongs to this MAC client. 5061 */ 5062 boolean_t 5063 mac_client_check_flow_vid(mac_client_impl_t *mcip, uint16_t vid) 5064 { 5065 flow_entry_t *flent; 5066 uint16_t mci_vid; 5067 uint32_t cache = mcip->mci_vidcache; 5068 5069 /* 5070 * In hopes of not having to touch the mci_rw_lock, check to see if 5071 * this vid matches our cached result. 5072 */ 5073 if (MCIP_VIDCACHE_ISVALID(cache) && MCIP_VIDCACHE_VID(cache) == vid) 5074 return (MCIP_VIDCACHE_BOOL(cache) ? B_TRUE : B_FALSE); 5075 5076 /* The mci_flent_list is protected by mci_rw_lock */ 5077 rw_enter(&mcip->mci_rw_lock, RW_WRITER); 5078 for (flent = mcip->mci_flent_list; flent != NULL; 5079 flent = flent->fe_client_next) { 5080 mci_vid = i_mac_flow_vid(flent); 5081 if (vid == mci_vid) { 5082 mcip->mci_vidcache = MCIP_VIDCACHE_CACHE(vid, B_TRUE); 5083 rw_exit(&mcip->mci_rw_lock); 5084 return (B_TRUE); 5085 } 5086 } 5087 5088 mcip->mci_vidcache = MCIP_VIDCACHE_CACHE(vid, B_FALSE); 5089 rw_exit(&mcip->mci_rw_lock); 5090 return (B_FALSE); 5091 } 5092 5093 /* 5094 * Get the flow entry for the specified <MAC addr, VID> tuple. 5095 */ 5096 static flow_entry_t * 5097 mac_client_get_flow(mac_client_impl_t *mcip, mac_unicast_impl_t *muip) 5098 { 5099 mac_address_t *map = mcip->mci_unicast; 5100 flow_entry_t *flent; 5101 uint16_t vid; 5102 flow_desc_t flow_desc; 5103 5104 ASSERT(MAC_PERIM_HELD((mac_handle_t)mcip->mci_mip)); 5105 5106 mac_flow_get_desc(mcip->mci_flent, &flow_desc); 5107 if (bcmp(flow_desc.fd_dst_mac, map->ma_addr, map->ma_len) != 0) 5108 return (NULL); 5109 5110 for (flent = mcip->mci_flent_list; flent != NULL; 5111 flent = flent->fe_client_next) { 5112 vid = i_mac_flow_vid(flent); 5113 if (vid == muip->mui_vid) { 5114 return (flent); 5115 } 5116 } 5117 5118 return (NULL); 5119 } 5120 5121 /* 5122 * Since mci_flent has the SRSs, when we want to remove it, we replace 5123 * the flow_desc_t in mci_flent with that of an existing flent and then 5124 * remove that flent instead of mci_flent. 5125 */ 5126 static flow_entry_t * 5127 mac_client_swap_mciflent(mac_client_impl_t *mcip) 5128 { 5129 flow_entry_t *flent = mcip->mci_flent; 5130 flow_tab_t *ft = flent->fe_flow_tab; 5131 flow_entry_t *flent1; 5132 flow_desc_t fl_desc; 5133 char fl_name[MAXFLOWNAMELEN]; 5134 int err; 5135 5136 ASSERT(MAC_PERIM_HELD((mac_handle_t)mcip->mci_mip)); 5137 ASSERT(mcip->mci_nflents > 1); 5138 5139 /* get the next flent following the primary flent */ 5140 flent1 = mcip->mci_flent_list->fe_client_next; 5141 ASSERT(flent1 != NULL && flent1->fe_flow_tab == ft); 5142 5143 /* 5144 * Remove the flent from the flow table before updating the 5145 * flow descriptor as the hash depends on the flow descriptor. 5146 * This also helps incoming packet classification avoid having 5147 * to grab fe_lock. Access to fe_flow_desc of a flent not in the 5148 * flow table is done under the fe_lock so that log or stat functions 5149 * see a self-consistent fe_flow_desc. The name and desc are specific 5150 * to a flow, the rest are shared by all the clients, including 5151 * resource control etc. 5152 */ 5153 mac_flow_remove(ft, flent, B_TRUE); 5154 mac_flow_remove(ft, flent1, B_TRUE); 5155 5156 bcopy(&flent->fe_flow_desc, &fl_desc, sizeof (flow_desc_t)); 5157 bcopy(flent->fe_flow_name, fl_name, MAXFLOWNAMELEN); 5158 5159 /* update the primary flow entry */ 5160 mutex_enter(&flent->fe_lock); 5161 bcopy(&flent1->fe_flow_desc, &flent->fe_flow_desc, 5162 sizeof (flow_desc_t)); 5163 bcopy(&flent1->fe_flow_name, &flent->fe_flow_name, MAXFLOWNAMELEN); 5164 mutex_exit(&flent->fe_lock); 5165 5166 /* update the flow entry that is to be freed */ 5167 mutex_enter(&flent1->fe_lock); 5168 bcopy(&fl_desc, &flent1->fe_flow_desc, sizeof (flow_desc_t)); 5169 bcopy(fl_name, &flent1->fe_flow_name, MAXFLOWNAMELEN); 5170 mutex_exit(&flent1->fe_lock); 5171 5172 /* now reinsert the flow entries in the table */ 5173 err = mac_flow_add(ft, flent); 5174 ASSERT(err == 0); 5175 5176 err = mac_flow_add(ft, flent1); 5177 ASSERT(err == 0); 5178 5179 return (flent1); 5180 } 5181 5182 /* 5183 * Return whether there is only one flow entry associated with this 5184 * MAC client. 5185 */ 5186 static boolean_t 5187 mac_client_single_rcvr(mac_client_impl_t *mcip) 5188 { 5189 return (mcip->mci_nflents == 1); 5190 } 5191 5192 int 5193 mac_validate_props(mac_impl_t *mip, mac_resource_props_t *mrp) 5194 { 5195 boolean_t reset; 5196 uint32_t rings_needed; 5197 uint32_t rings_avail; 5198 mac_group_type_t gtype; 5199 mac_resource_props_t *mip_mrp; 5200 5201 if (mrp == NULL) 5202 return (0); 5203 5204 if (mrp->mrp_mask & MRP_PRIORITY) { 5205 mac_priority_level_t pri = mrp->mrp_priority; 5206 5207 if (pri < MPL_LOW || pri > MPL_RESET) 5208 return (EINVAL); 5209 } 5210 5211 if (mrp->mrp_mask & MRP_MAXBW) { 5212 uint64_t maxbw = mrp->mrp_maxbw; 5213 5214 if (maxbw < MRP_MAXBW_MINVAL && maxbw != 0) 5215 return (EINVAL); 5216 } 5217 if (mrp->mrp_mask & MRP_CPUS) { 5218 int i, j; 5219 mac_cpu_mode_t fanout; 5220 5221 if (mrp->mrp_ncpus > ncpus) 5222 return (EINVAL); 5223 5224 for (i = 0; i < mrp->mrp_ncpus; i++) { 5225 for (j = 0; j < mrp->mrp_ncpus; j++) { 5226 if (i != j && 5227 mrp->mrp_cpu[i] == mrp->mrp_cpu[j]) { 5228 return (EINVAL); 5229 } 5230 } 5231 } 5232 5233 for (i = 0; i < mrp->mrp_ncpus; i++) { 5234 cpu_t *cp; 5235 int rv; 5236 5237 mutex_enter(&cpu_lock); 5238 cp = cpu_get(mrp->mrp_cpu[i]); 5239 if (cp != NULL) 5240 rv = cpu_is_online(cp); 5241 else 5242 rv = 0; 5243 mutex_exit(&cpu_lock); 5244 if (rv == 0) 5245 return (EINVAL); 5246 } 5247 5248 fanout = mrp->mrp_fanout_mode; 5249 if (fanout < 0 || fanout > MCM_CPUS) 5250 return (EINVAL); 5251 } 5252 5253 if (mrp->mrp_mask & MRP_PROTECT) { 5254 int err = mac_protect_validate(mrp); 5255 if (err != 0) 5256 return (err); 5257 } 5258 5259 if (!(mrp->mrp_mask & MRP_RX_RINGS) && 5260 !(mrp->mrp_mask & MRP_TX_RINGS)) { 5261 return (0); 5262 } 5263 5264 /* 5265 * mip will be null when we come from mac_flow_create or 5266 * mac_link_flow_modify. In the latter case it is a user flow, 5267 * for which we don't support rings. In the former we would 5268 * have validated the props beforehand (i_mac_unicast_add -> 5269 * mac_client_set_resources -> validate for the primary and 5270 * vnic_dev_create -> mac_client_set_resources -> validate for 5271 * a vnic. 5272 */ 5273 if (mip == NULL) 5274 return (0); 5275 5276 /* 5277 * We don't support setting rings property for a VNIC that is using a 5278 * primary address (VLAN) 5279 */ 5280 if ((mip->mi_state_flags & MIS_IS_VNIC) && 5281 mac_is_vnic_primary((mac_handle_t)mip)) { 5282 return (ENOTSUP); 5283 } 5284 5285 mip_mrp = &mip->mi_resource_props; 5286 /* 5287 * The rings property should be validated against the NICs 5288 * resources 5289 */ 5290 if (mip->mi_state_flags & MIS_IS_VNIC) 5291 mip = (mac_impl_t *)mac_get_lower_mac_handle((mac_handle_t)mip); 5292 5293 reset = mrp->mrp_mask & MRP_RINGS_RESET; 5294 /* 5295 * If groups are not supported, return error. 5296 */ 5297 if (((mrp->mrp_mask & MRP_RX_RINGS) && mip->mi_rx_groups == NULL) || 5298 ((mrp->mrp_mask & MRP_TX_RINGS) && mip->mi_tx_groups == NULL)) { 5299 return (EINVAL); 5300 } 5301 /* 5302 * If we are just resetting, there is no validation needed. 5303 */ 5304 if (reset) 5305 return (0); 5306 5307 if (mrp->mrp_mask & MRP_RX_RINGS) { 5308 rings_needed = mrp->mrp_nrxrings; 5309 /* 5310 * We just want to check if the number of additional 5311 * rings requested is available. 5312 */ 5313 if (mip_mrp->mrp_mask & MRP_RX_RINGS) { 5314 if (mrp->mrp_nrxrings > mip_mrp->mrp_nrxrings) 5315 /* Just check for the additional rings */ 5316 rings_needed -= mip_mrp->mrp_nrxrings; 5317 else 5318 /* We are not asking for additional rings */ 5319 rings_needed = 0; 5320 } 5321 rings_avail = mip->mi_rxrings_avail; 5322 gtype = mip->mi_rx_group_type; 5323 } else { 5324 rings_needed = mrp->mrp_ntxrings; 5325 /* Similarly for the TX rings */ 5326 if (mip_mrp->mrp_mask & MRP_TX_RINGS) { 5327 if (mrp->mrp_ntxrings > mip_mrp->mrp_ntxrings) 5328 /* Just check for the additional rings */ 5329 rings_needed -= mip_mrp->mrp_ntxrings; 5330 else 5331 /* We are not asking for additional rings */ 5332 rings_needed = 0; 5333 } 5334 rings_avail = mip->mi_txrings_avail; 5335 gtype = mip->mi_tx_group_type; 5336 } 5337 5338 /* Error if the group is dynamic .. */ 5339 if (gtype == MAC_GROUP_TYPE_DYNAMIC) { 5340 /* 5341 * .. and rings specified are more than available. 5342 */ 5343 if (rings_needed > rings_avail) 5344 return (EINVAL); 5345 } else { 5346 /* 5347 * OR group is static and we have specified some rings. 5348 */ 5349 if (rings_needed > 0) 5350 return (EINVAL); 5351 } 5352 return (0); 5353 } 5354 5355 /* 5356 * Send a MAC_NOTE_LINK notification to all the MAC clients whenever the 5357 * underlying physical link is down. This is to allow MAC clients to 5358 * communicate with other clients. 5359 */ 5360 void 5361 mac_virtual_link_update(mac_impl_t *mip) 5362 { 5363 if (mip->mi_linkstate != LINK_STATE_UP) 5364 i_mac_notify(mip, MAC_NOTE_LINK); 5365 } 5366 5367 /* 5368 * For clients that have a pass-thru MAC, e.g. VNIC, we set the VNIC's 5369 * mac handle in the client. 5370 */ 5371 void 5372 mac_set_upper_mac(mac_client_handle_t mch, mac_handle_t mh, 5373 mac_resource_props_t *mrp) 5374 { 5375 mac_client_impl_t *mcip = (mac_client_impl_t *)mch; 5376 mac_impl_t *mip = (mac_impl_t *)mh; 5377 5378 mcip->mci_upper_mip = mip; 5379 /* If there are any properties, copy it over too */ 5380 if (mrp != NULL) { 5381 bcopy(mrp, &mip->mi_resource_props, 5382 sizeof (mac_resource_props_t)); 5383 } 5384 } 5385 5386 /* 5387 * Mark the mac as being used exclusively by the single mac client that is 5388 * doing some control operation on this mac. No further opens of this mac 5389 * will be allowed until this client calls mac_unmark_exclusive. The mac 5390 * client calling this function must already be in the mac perimeter 5391 */ 5392 int 5393 mac_mark_exclusive(mac_handle_t mh) 5394 { 5395 mac_impl_t *mip = (mac_impl_t *)mh; 5396 5397 ASSERT(MAC_PERIM_HELD(mh)); 5398 /* 5399 * Look up its entry in the global hash table. 5400 */ 5401 rw_enter(&i_mac_impl_lock, RW_WRITER); 5402 if (mip->mi_state_flags & MIS_DISABLED) { 5403 rw_exit(&i_mac_impl_lock); 5404 return (ENOENT); 5405 } 5406 5407 /* 5408 * A reference to mac is held even if the link is not plumbed. 5409 * In i_dls_link_create() we open the MAC interface and hold the 5410 * reference. There is an additional reference for the mac_open 5411 * done in acquiring the mac perimeter 5412 */ 5413 if (mip->mi_ref != 2) { 5414 rw_exit(&i_mac_impl_lock); 5415 return (EBUSY); 5416 } 5417 5418 ASSERT(!(mip->mi_state_flags & MIS_EXCLUSIVE_HELD)); 5419 mip->mi_state_flags |= MIS_EXCLUSIVE_HELD; 5420 rw_exit(&i_mac_impl_lock); 5421 return (0); 5422 } 5423 5424 void 5425 mac_unmark_exclusive(mac_handle_t mh) 5426 { 5427 mac_impl_t *mip = (mac_impl_t *)mh; 5428 5429 ASSERT(MAC_PERIM_HELD(mh)); 5430 5431 rw_enter(&i_mac_impl_lock, RW_WRITER); 5432 /* 1 for the creation and another for the perimeter */ 5433 ASSERT(mip->mi_ref == 2 && (mip->mi_state_flags & MIS_EXCLUSIVE_HELD)); 5434 mip->mi_state_flags &= ~MIS_EXCLUSIVE_HELD; 5435 rw_exit(&i_mac_impl_lock); 5436 } 5437 5438 /* 5439 * Set the MTU for the specified MAC. 5440 */ 5441 int 5442 mac_set_mtu(mac_handle_t mh, uint_t new_mtu, uint_t *old_mtu_arg) 5443 { 5444 mac_impl_t *mip = (mac_impl_t *)mh; 5445 uint_t old_mtu; 5446 int rv = 0; 5447 5448 i_mac_perim_enter(mip); 5449 5450 if (!(mip->mi_callbacks->mc_callbacks & (MC_SETPROP|MC_GETPROP))) { 5451 rv = ENOTSUP; 5452 goto bail; 5453 } 5454 5455 old_mtu = mip->mi_sdu_max; 5456 5457 if (new_mtu == 0 || new_mtu < mip->mi_sdu_min) { 5458 rv = EINVAL; 5459 goto bail; 5460 } 5461 5462 rw_enter(&mip->mi_rw_lock, RW_READER); 5463 if (mip->mi_mtrp != NULL && new_mtu < mip->mi_mtrp->mtr_mtu) { 5464 rv = EBUSY; 5465 rw_exit(&mip->mi_rw_lock); 5466 goto bail; 5467 } 5468 rw_exit(&mip->mi_rw_lock); 5469 5470 if (old_mtu != new_mtu) { 5471 rv = mip->mi_callbacks->mc_setprop(mip->mi_driver, 5472 "mtu", MAC_PROP_MTU, sizeof (uint_t), &new_mtu); 5473 if (rv != 0) 5474 goto bail; 5475 rv = mac_maxsdu_update(mh, new_mtu); 5476 ASSERT(rv == 0); 5477 } 5478 5479 bail: 5480 i_mac_perim_exit(mip); 5481 5482 if (rv == 0 && old_mtu_arg != NULL) 5483 *old_mtu_arg = old_mtu; 5484 return (rv); 5485 } 5486 5487 /* 5488 * Return the RX h/w information for the group indexed by grp_num. 5489 */ 5490 void 5491 mac_get_hwrxgrp_info(mac_handle_t mh, int grp_index, uint_t *grp_num, 5492 uint_t *n_rings, uint_t *rings, uint_t *type, uint_t *n_clnts, 5493 char *clnts_name) 5494 { 5495 mac_impl_t *mip = (mac_impl_t *)mh; 5496 mac_grp_client_t *mcip; 5497 uint_t i = 0, index = 0; 5498 mac_ring_t *ring; 5499 5500 /* Revisit when we implement fully dynamic group allocation */ 5501 ASSERT(grp_index >= 0 && grp_index < mip->mi_rx_group_count); 5502 5503 rw_enter(&mip->mi_rw_lock, RW_READER); 5504 *grp_num = mip->mi_rx_groups[grp_index].mrg_index; 5505 *type = mip->mi_rx_groups[grp_index].mrg_type; 5506 *n_rings = mip->mi_rx_groups[grp_index].mrg_cur_count; 5507 ring = mip->mi_rx_groups[grp_index].mrg_rings; 5508 for (index = 0; index < mip->mi_rx_groups[grp_index].mrg_cur_count; 5509 index++) { 5510 rings[index] = ring->mr_index; 5511 ring = ring->mr_next; 5512 } 5513 /* Assuming the 1st is the default group */ 5514 index = 0; 5515 if (grp_index == 0) { 5516 (void) strlcpy(clnts_name, "<default,mcast>,", 5517 MAXCLIENTNAMELEN); 5518 index += strlen("<default,mcast>,"); 5519 } 5520 for (mcip = mip->mi_rx_groups[grp_index].mrg_clients; mcip != NULL; 5521 mcip = mcip->mgc_next) { 5522 int name_len = strlen(mcip->mgc_client->mci_name); 5523 5524 /* 5525 * MAXCLIENTNAMELEN is the buffer size reserved for client 5526 * names. 5527 * XXXX Formating the client name string needs to be moved 5528 * to user land when fixing the size of dhi_clnts in 5529 * dld_hwgrpinfo_t. We should use n_clients * client_name for 5530 * dhi_clntsin instead of MAXCLIENTNAMELEN 5531 */ 5532 if (index + name_len >= MAXCLIENTNAMELEN) { 5533 index = MAXCLIENTNAMELEN; 5534 break; 5535 } 5536 bcopy(mcip->mgc_client->mci_name, &(clnts_name[index]), 5537 name_len); 5538 index += name_len; 5539 clnts_name[index++] = ','; 5540 i++; 5541 } 5542 5543 /* Get rid of the last , */ 5544 if (index > 0) 5545 clnts_name[index - 1] = '\0'; 5546 *n_clnts = i; 5547 rw_exit(&mip->mi_rw_lock); 5548 } 5549 5550 /* 5551 * Return the TX h/w information for the group indexed by grp_num. 5552 */ 5553 void 5554 mac_get_hwtxgrp_info(mac_handle_t mh, int grp_index, uint_t *grp_num, 5555 uint_t *n_rings, uint_t *rings, uint_t *type, uint_t *n_clnts, 5556 char *clnts_name) 5557 { 5558 mac_impl_t *mip = (mac_impl_t *)mh; 5559 mac_grp_client_t *mcip; 5560 uint_t i = 0, index = 0; 5561 mac_ring_t *ring; 5562 5563 /* Revisit when we implement fully dynamic group allocation */ 5564 ASSERT(grp_index >= 0 && grp_index <= mip->mi_tx_group_count); 5565 5566 rw_enter(&mip->mi_rw_lock, RW_READER); 5567 *grp_num = mip->mi_tx_groups[grp_index].mrg_index > 0 ? 5568 mip->mi_tx_groups[grp_index].mrg_index : grp_index; 5569 *type = mip->mi_tx_groups[grp_index].mrg_type; 5570 *n_rings = mip->mi_tx_groups[grp_index].mrg_cur_count; 5571 ring = mip->mi_tx_groups[grp_index].mrg_rings; 5572 for (index = 0; index < mip->mi_tx_groups[grp_index].mrg_cur_count; 5573 index++) { 5574 rings[index] = ring->mr_index; 5575 ring = ring->mr_next; 5576 } 5577 index = 0; 5578 /* Default group has an index of -1 */ 5579 if (mip->mi_tx_groups[grp_index].mrg_index < 0) { 5580 (void) strlcpy(clnts_name, "<default>,", 5581 MAXCLIENTNAMELEN); 5582 index += strlen("<default>,"); 5583 } 5584 for (mcip = mip->mi_tx_groups[grp_index].mrg_clients; mcip != NULL; 5585 mcip = mcip->mgc_next) { 5586 int name_len = strlen(mcip->mgc_client->mci_name); 5587 5588 /* 5589 * MAXCLIENTNAMELEN is the buffer size reserved for client 5590 * names. 5591 * XXXX Formating the client name string needs to be moved 5592 * to user land when fixing the size of dhi_clnts in 5593 * dld_hwgrpinfo_t. We should use n_clients * client_name for 5594 * dhi_clntsin instead of MAXCLIENTNAMELEN 5595 */ 5596 if (index + name_len >= MAXCLIENTNAMELEN) { 5597 index = MAXCLIENTNAMELEN; 5598 break; 5599 } 5600 bcopy(mcip->mgc_client->mci_name, &(clnts_name[index]), 5601 name_len); 5602 index += name_len; 5603 clnts_name[index++] = ','; 5604 i++; 5605 } 5606 5607 /* Get rid of the last , */ 5608 if (index > 0) 5609 clnts_name[index - 1] = '\0'; 5610 *n_clnts = i; 5611 rw_exit(&mip->mi_rw_lock); 5612 } 5613 5614 /* 5615 * Return the group count for RX or TX. 5616 */ 5617 uint_t 5618 mac_hwgrp_num(mac_handle_t mh, int type) 5619 { 5620 mac_impl_t *mip = (mac_impl_t *)mh; 5621 5622 /* 5623 * Return the Rx and Tx group count; for the Tx we need to 5624 * include the default too. 5625 */ 5626 return (type == MAC_RING_TYPE_RX ? mip->mi_rx_group_count : 5627 mip->mi_tx_groups != NULL ? mip->mi_tx_group_count + 1 : 0); 5628 } 5629 5630 /* 5631 * The total number of free TX rings for this MAC. 5632 */ 5633 uint_t 5634 mac_txavail_get(mac_handle_t mh) 5635 { 5636 mac_impl_t *mip = (mac_impl_t *)mh; 5637 5638 return (mip->mi_txrings_avail); 5639 } 5640 5641 /* 5642 * The total number of free RX rings for this MAC. 5643 */ 5644 uint_t 5645 mac_rxavail_get(mac_handle_t mh) 5646 { 5647 mac_impl_t *mip = (mac_impl_t *)mh; 5648 5649 return (mip->mi_rxrings_avail); 5650 } 5651 5652 /* 5653 * The total number of reserved RX rings on this MAC. 5654 */ 5655 uint_t 5656 mac_rxrsvd_get(mac_handle_t mh) 5657 { 5658 mac_impl_t *mip = (mac_impl_t *)mh; 5659 5660 return (mip->mi_rxrings_rsvd); 5661 } 5662 5663 /* 5664 * The total number of reserved TX rings on this MAC. 5665 */ 5666 uint_t 5667 mac_txrsvd_get(mac_handle_t mh) 5668 { 5669 mac_impl_t *mip = (mac_impl_t *)mh; 5670 5671 return (mip->mi_txrings_rsvd); 5672 } 5673 5674 /* 5675 * Total number of free RX groups on this MAC. 5676 */ 5677 uint_t 5678 mac_rxhwlnksavail_get(mac_handle_t mh) 5679 { 5680 mac_impl_t *mip = (mac_impl_t *)mh; 5681 5682 return (mip->mi_rxhwclnt_avail); 5683 } 5684 5685 /* 5686 * Total number of RX groups reserved on this MAC. 5687 */ 5688 uint_t 5689 mac_rxhwlnksrsvd_get(mac_handle_t mh) 5690 { 5691 mac_impl_t *mip = (mac_impl_t *)mh; 5692 5693 return (mip->mi_rxhwclnt_used); 5694 } 5695 5696 /* 5697 * Total number of free TX groups on this MAC. 5698 */ 5699 uint_t 5700 mac_txhwlnksavail_get(mac_handle_t mh) 5701 { 5702 mac_impl_t *mip = (mac_impl_t *)mh; 5703 5704 return (mip->mi_txhwclnt_avail); 5705 } 5706 5707 /* 5708 * Total number of TX groups reserved on this MAC. 5709 */ 5710 uint_t 5711 mac_txhwlnksrsvd_get(mac_handle_t mh) 5712 { 5713 mac_impl_t *mip = (mac_impl_t *)mh; 5714 5715 return (mip->mi_txhwclnt_used); 5716 } 5717 5718 /* 5719 * Initialize the rings property for a mac client. A non-0 value for 5720 * rxring or txring specifies the number of rings required, a value 5721 * of MAC_RXRINGS_NONE/MAC_TXRINGS_NONE specifies that it doesn't need 5722 * any RX/TX rings and a value of MAC_RXRINGS_DONTCARE/MAC_TXRINGS_DONTCARE 5723 * means the system can decide whether it can give any rings or not. 5724 */ 5725 void 5726 mac_client_set_rings(mac_client_handle_t mch, int rxrings, int txrings) 5727 { 5728 mac_client_impl_t *mcip = (mac_client_impl_t *)mch; 5729 mac_resource_props_t *mrp = MCIP_RESOURCE_PROPS(mcip); 5730 5731 if (rxrings != MAC_RXRINGS_DONTCARE) { 5732 mrp->mrp_mask |= MRP_RX_RINGS; 5733 mrp->mrp_nrxrings = rxrings; 5734 } 5735 5736 if (txrings != MAC_TXRINGS_DONTCARE) { 5737 mrp->mrp_mask |= MRP_TX_RINGS; 5738 mrp->mrp_ntxrings = txrings; 5739 } 5740 } 5741 5742 boolean_t 5743 mac_get_promisc_filtered(mac_client_handle_t mch) 5744 { 5745 mac_client_impl_t *mcip = (mac_client_impl_t *)mch; 5746 5747 return (mcip->mci_protect_flags & MPT_FLAG_PROMISC_FILTERED); 5748 } 5749 5750 void 5751 mac_set_promisc_filtered(mac_client_handle_t mch, boolean_t enable) 5752 { 5753 mac_client_impl_t *mcip = (mac_client_impl_t *)mch; 5754 5755 ASSERT(MAC_PERIM_HELD((mac_handle_t)mcip->mci_mip)); 5756 if (enable) 5757 mcip->mci_protect_flags |= MPT_FLAG_PROMISC_FILTERED; 5758 else 5759 mcip->mci_protect_flags &= ~MPT_FLAG_PROMISC_FILTERED; 5760 } 5761