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