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