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