5013 add support for multiple mac addresses per client
[unleashed.git] / usr / src / uts / common / io / mac / mac_client.c
blobae2a39ff499d2b1adeccd791b4a41410f49f4e6e
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
23 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright (c) 2013, Joyent, Inc. All rights reserved.
28 * - General Introduction:
30 * This file contains the implementation of the MAC client kernel
31 * API and related code. The MAC client API allows a kernel module
32 * to gain access to a MAC instance (physical NIC, link aggregation, etc).
33 * It allows a MAC client to associate itself with a MAC address,
34 * VLANs, callback functions for data traffic and for promiscuous mode.
35 * The MAC client API is also used to specify the properties associated
36 * with a MAC client, such as bandwidth limits, priority, CPUS, etc.
37 * These properties are further used to determine the hardware resources
38 * to allocate to the various MAC clients.
40 * - Primary MAC clients:
42 * The MAC client API refers to "primary MAC clients". A primary MAC
43 * client is a client which "owns" the primary MAC address of
44 * the underlying MAC instance. The primary MAC address is called out
45 * since it is associated with specific semantics: the primary MAC
46 * address is the MAC address which is assigned to the IP interface
47 * when it is plumbed, and the primary MAC address is assigned
48 * to VLAN data-links. The primary address of a MAC instance can
49 * also change dynamically from under the MAC client, for example
50 * as a result of a change of state of a link aggregation. In that
51 * case the MAC layer automatically updates all data-structures which
52 * refer to the current value of the primary MAC address. Typical
53 * primary MAC clients are dls, aggr, and xnb. A typical non-primary
54 * MAC client is the vnic driver.
56 * - Virtual Switching:
58 * The MAC layer implements a virtual switch between the MAC clients
59 * (primary and non-primary) defined on top of the same underlying
60 * NIC (physical, link aggregation, etc). The virtual switch is
61 * VLAN-aware, i.e. it allows multiple MAC clients to be member
62 * of one or more VLANs, and the virtual switch will distribute
63 * multicast tagged packets only to the member of the corresponding
64 * VLANs.
66 * - Upper vs Lower MAC:
68 * Creating a VNIC on top of a MAC instance effectively causes
69 * two MAC instances to be layered on top of each other, one for
70 * the VNIC(s), one for the underlying MAC instance (physical NIC,
71 * link aggregation, etc). In the code below we refer to the
72 * underlying NIC as the "lower MAC", and we refer to VNICs as
73 * the "upper MAC".
75 * - Pass-through for VNICs:
77 * When VNICs are created on top of an underlying MAC, this causes
78 * a layering of two MAC instances. Since the lower MAC already
79 * does the switching and demultiplexing to its MAC clients, the
80 * upper MAC would simply have to pass packets to the layer below
81 * or above it, which would introduce overhead. In order to avoid
82 * this overhead, the MAC layer implements a pass-through mechanism
83 * for VNICs. When a VNIC opens the lower MAC instance, it saves
84 * the MAC client handle it optains from the MAC layer. When a MAC
85 * client opens a VNIC (upper MAC), the MAC layer detects that
86 * the MAC being opened is a VNIC, and gets the MAC client handle
87 * that the VNIC driver obtained from the lower MAC. This exchange
88 * is done through a private capability between the MAC layer
89 * and the VNIC driver. The upper MAC then returns that handle
90 * directly to its MAC client. Any operation done by the upper
91 * MAC client is now done on the lower MAC client handle, which
92 * allows the VNIC driver to be completely bypassed for the
93 * performance sensitive data-path.
95 * - Secondary MACs for VNICs:
97 * VNICs support multiple upper mac clients to enable support for
98 * multiple MAC addresses on the VNIC. When the VNIC is created the
99 * initial mac client is the primary upper mac. Any additional mac
100 * clients are secondary macs. These are kept in sync with the primary
101 * (for things such as the rx function and resource control settings)
102 * using the same private capability interface between the MAC layer
103 * and the VNIC layer.
107 #include <sys/types.h>
108 #include <sys/conf.h>
109 #include <sys/id_space.h>
110 #include <sys/esunddi.h>
111 #include <sys/stat.h>
112 #include <sys/mkdev.h>
113 #include <sys/stream.h>
114 #include <sys/strsun.h>
115 #include <sys/strsubr.h>
116 #include <sys/dlpi.h>
117 #include <sys/modhash.h>
118 #include <sys/mac_impl.h>
119 #include <sys/mac_client_impl.h>
120 #include <sys/mac_soft_ring.h>
121 #include <sys/mac_stat.h>
122 #include <sys/dls.h>
123 #include <sys/dld.h>
124 #include <sys/modctl.h>
125 #include <sys/fs/dv_node.h>
126 #include <sys/thread.h>
127 #include <sys/proc.h>
128 #include <sys/callb.h>
129 #include <sys/cpuvar.h>
130 #include <sys/atomic.h>
131 #include <sys/sdt.h>
132 #include <sys/mac_flow.h>
133 #include <sys/ddi_intr_impl.h>
134 #include <sys/disp.h>
135 #include <sys/sdt.h>
136 #include <sys/vnic.h>
137 #include <sys/vnic_impl.h>
138 #include <sys/vlan.h>
139 #include <inet/ip.h>
140 #include <inet/ip6.h>
141 #include <sys/exacct.h>
142 #include <sys/exacct_impl.h>
143 #include <inet/nd.h>
144 #include <sys/ethernet.h>
146 kmem_cache_t *mac_client_impl_cache;
147 kmem_cache_t *mac_promisc_impl_cache;
149 static boolean_t mac_client_single_rcvr(mac_client_impl_t *);
150 static flow_entry_t *mac_client_swap_mciflent(mac_client_impl_t *);
151 static flow_entry_t *mac_client_get_flow(mac_client_impl_t *,
152 mac_unicast_impl_t *);
153 static void mac_client_remove_flow_from_list(mac_client_impl_t *,
154 flow_entry_t *);
155 static void mac_client_add_to_flow_list(mac_client_impl_t *, flow_entry_t *);
156 static void mac_rename_flow_names(mac_client_impl_t *, const char *);
157 static void mac_virtual_link_update(mac_impl_t *);
158 static int mac_client_datapath_setup(mac_client_impl_t *, uint16_t,
159 uint8_t *, mac_resource_props_t *, boolean_t, mac_unicast_impl_t *);
160 static void mac_client_datapath_teardown(mac_client_handle_t,
161 mac_unicast_impl_t *, flow_entry_t *);
162 static int mac_resource_ctl_set(mac_client_handle_t, mac_resource_props_t *);
164 /* ARGSUSED */
165 static int
166 i_mac_client_impl_ctor(void *buf, void *arg, int kmflag)
168 int i;
169 mac_client_impl_t *mcip = buf;
171 bzero(buf, MAC_CLIENT_IMPL_SIZE);
172 mutex_init(&mcip->mci_tx_cb_lock, NULL, MUTEX_DRIVER, NULL);
173 mcip->mci_tx_notify_cb_info.mcbi_lockp = &mcip->mci_tx_cb_lock;
175 ASSERT(mac_tx_percpu_cnt >= 0);
176 for (i = 0; i <= mac_tx_percpu_cnt; i++) {
177 mutex_init(&mcip->mci_tx_pcpu[i].pcpu_tx_lock, NULL,
178 MUTEX_DRIVER, NULL);
180 cv_init(&mcip->mci_tx_cv, NULL, CV_DRIVER, NULL);
182 return (0);
185 /* ARGSUSED */
186 static void
187 i_mac_client_impl_dtor(void *buf, void *arg)
189 int i;
190 mac_client_impl_t *mcip = buf;
192 ASSERT(mcip->mci_promisc_list == NULL);
193 ASSERT(mcip->mci_unicast_list == NULL);
194 ASSERT(mcip->mci_state_flags == 0);
195 ASSERT(mcip->mci_tx_flag == 0);
197 mutex_destroy(&mcip->mci_tx_cb_lock);
199 ASSERT(mac_tx_percpu_cnt >= 0);
200 for (i = 0; i <= mac_tx_percpu_cnt; i++) {
201 ASSERT(mcip->mci_tx_pcpu[i].pcpu_tx_refcnt == 0);
202 mutex_destroy(&mcip->mci_tx_pcpu[i].pcpu_tx_lock);
204 cv_destroy(&mcip->mci_tx_cv);
207 /* ARGSUSED */
208 static int
209 i_mac_promisc_impl_ctor(void *buf, void *arg, int kmflag)
211 mac_promisc_impl_t *mpip = buf;
213 bzero(buf, sizeof (mac_promisc_impl_t));
214 mpip->mpi_mci_link.mcb_objp = buf;
215 mpip->mpi_mci_link.mcb_objsize = sizeof (mac_promisc_impl_t);
216 mpip->mpi_mi_link.mcb_objp = buf;
217 mpip->mpi_mi_link.mcb_objsize = sizeof (mac_promisc_impl_t);
218 return (0);
221 /* ARGSUSED */
222 static void
223 i_mac_promisc_impl_dtor(void *buf, void *arg)
225 mac_promisc_impl_t *mpip = buf;
227 ASSERT(mpip->mpi_mci_link.mcb_objp != NULL);
228 ASSERT(mpip->mpi_mci_link.mcb_objsize == sizeof (mac_promisc_impl_t));
229 ASSERT(mpip->mpi_mi_link.mcb_objp == mpip->mpi_mci_link.mcb_objp);
230 ASSERT(mpip->mpi_mi_link.mcb_objsize == sizeof (mac_promisc_impl_t));
232 mpip->mpi_mci_link.mcb_objp = NULL;
233 mpip->mpi_mci_link.mcb_objsize = 0;
234 mpip->mpi_mi_link.mcb_objp = NULL;
235 mpip->mpi_mi_link.mcb_objsize = 0;
237 ASSERT(mpip->mpi_mci_link.mcb_flags == 0);
238 mpip->mpi_mci_link.mcb_objsize = 0;
241 void
242 mac_client_init(void)
244 ASSERT(mac_tx_percpu_cnt >= 0);
246 mac_client_impl_cache = kmem_cache_create("mac_client_impl_cache",
247 MAC_CLIENT_IMPL_SIZE, 0, i_mac_client_impl_ctor,
248 i_mac_client_impl_dtor, NULL, NULL, NULL, 0);
249 ASSERT(mac_client_impl_cache != NULL);
251 mac_promisc_impl_cache = kmem_cache_create("mac_promisc_impl_cache",
252 sizeof (mac_promisc_impl_t), 0, i_mac_promisc_impl_ctor,
253 i_mac_promisc_impl_dtor, NULL, NULL, NULL, 0);
254 ASSERT(mac_promisc_impl_cache != NULL);
257 void
258 mac_client_fini(void)
260 kmem_cache_destroy(mac_client_impl_cache);
261 kmem_cache_destroy(mac_promisc_impl_cache);
265 * Return the lower MAC client handle from the VNIC driver for the
266 * specified VNIC MAC instance.
268 mac_client_impl_t *
269 mac_vnic_lower(mac_impl_t *mip)
271 mac_capab_vnic_t cap;
272 mac_client_impl_t *mcip;
274 VERIFY(i_mac_capab_get((mac_handle_t)mip, MAC_CAPAB_VNIC, &cap));
275 mcip = cap.mcv_mac_client_handle(cap.mcv_arg);
277 return (mcip);
281 * Update the secondary macs
283 void
284 mac_vnic_secondary_update(mac_impl_t *mip)
286 mac_capab_vnic_t cap;
288 VERIFY(i_mac_capab_get((mac_handle_t)mip, MAC_CAPAB_VNIC, &cap));
289 cap.mcv_mac_secondary_update(cap.mcv_arg);
293 * Return the MAC client handle of the primary MAC client for the
294 * specified MAC instance, or NULL otherwise.
296 mac_client_impl_t *
297 mac_primary_client_handle(mac_impl_t *mip)
299 mac_client_impl_t *mcip;
301 if (mip->mi_state_flags & MIS_IS_VNIC)
302 return (mac_vnic_lower(mip));
304 ASSERT(MAC_PERIM_HELD((mac_handle_t)mip));
306 for (mcip = mip->mi_clients_list; mcip != NULL;
307 mcip = mcip->mci_client_next) {
308 if (MCIP_DATAPATH_SETUP(mcip) && mac_is_primary_client(mcip))
309 return (mcip);
311 return (NULL);
315 * Open a MAC specified by its MAC name.
318 mac_open(const char *macname, mac_handle_t *mhp)
320 mac_impl_t *mip;
321 int err;
324 * Look up its entry in the global hash table.
326 if ((err = mac_hold(macname, &mip)) != 0)
327 return (err);
330 * Hold the dip associated to the MAC to prevent it from being
331 * detached. For a softmac, its underlying dip is held by the
332 * mi_open() callback.
334 * This is done to be more tolerant with some defective drivers,
335 * which incorrectly handle mac_unregister() failure in their
336 * xxx_detach() routine. For example, some drivers ignore the
337 * failure of mac_unregister() and free all resources that
338 * that are needed for data transmition.
340 e_ddi_hold_devi(mip->mi_dip);
342 if (!(mip->mi_callbacks->mc_callbacks & MC_OPEN)) {
343 *mhp = (mac_handle_t)mip;
344 return (0);
348 * The mac perimeter is used in both mac_open and mac_close by the
349 * framework to single thread the MC_OPEN/MC_CLOSE of drivers.
351 i_mac_perim_enter(mip);
352 mip->mi_oref++;
353 if (mip->mi_oref != 1 || ((err = mip->mi_open(mip->mi_driver)) == 0)) {
354 *mhp = (mac_handle_t)mip;
355 i_mac_perim_exit(mip);
356 return (0);
358 mip->mi_oref--;
359 ddi_release_devi(mip->mi_dip);
360 mac_rele(mip);
361 i_mac_perim_exit(mip);
362 return (err);
366 * Open a MAC specified by its linkid.
369 mac_open_by_linkid(datalink_id_t linkid, mac_handle_t *mhp)
371 dls_dl_handle_t dlh;
372 int err;
374 if ((err = dls_devnet_hold_tmp(linkid, &dlh)) != 0)
375 return (err);
377 dls_devnet_prop_task_wait(dlh);
379 err = mac_open(dls_devnet_mac(dlh), mhp);
381 dls_devnet_rele_tmp(dlh);
382 return (err);
386 * Open a MAC specified by its link name.
389 mac_open_by_linkname(const char *link, mac_handle_t *mhp)
391 datalink_id_t linkid;
392 int err;
394 if ((err = dls_mgmt_get_linkid(link, &linkid)) != 0)
395 return (err);
396 return (mac_open_by_linkid(linkid, mhp));
400 * Close the specified MAC.
402 void
403 mac_close(mac_handle_t mh)
405 mac_impl_t *mip = (mac_impl_t *)mh;
407 i_mac_perim_enter(mip);
409 * The mac perimeter is used in both mac_open and mac_close by the
410 * framework to single thread the MC_OPEN/MC_CLOSE of drivers.
412 if (mip->mi_callbacks->mc_callbacks & MC_OPEN) {
413 ASSERT(mip->mi_oref != 0);
414 if (--mip->mi_oref == 0) {
415 if ((mip->mi_callbacks->mc_callbacks & MC_CLOSE))
416 mip->mi_close(mip->mi_driver);
419 i_mac_perim_exit(mip);
420 ddi_release_devi(mip->mi_dip);
421 mac_rele(mip);
425 * Misc utility functions to retrieve various information about a MAC
426 * instance or a MAC client.
429 const mac_info_t *
430 mac_info(mac_handle_t mh)
432 return (&((mac_impl_t *)mh)->mi_info);
435 dev_info_t *
436 mac_devinfo_get(mac_handle_t mh)
438 return (((mac_impl_t *)mh)->mi_dip);
441 void *
442 mac_driver(mac_handle_t mh)
444 return (((mac_impl_t *)mh)->mi_driver);
447 const char *
448 mac_name(mac_handle_t mh)
450 return (((mac_impl_t *)mh)->mi_name);
454 mac_type(mac_handle_t mh)
456 return (((mac_impl_t *)mh)->mi_type->mt_type);
460 mac_nativetype(mac_handle_t mh)
462 return (((mac_impl_t *)mh)->mi_type->mt_nativetype);
465 char *
466 mac_client_name(mac_client_handle_t mch)
468 return (((mac_client_impl_t *)mch)->mci_name);
471 minor_t
472 mac_minor(mac_handle_t mh)
474 return (((mac_impl_t *)mh)->mi_minor);
478 * Return the VID associated with a MAC client. This function should
479 * be called for clients which are associated with only one VID.
481 uint16_t
482 mac_client_vid(mac_client_handle_t mch)
484 uint16_t vid = VLAN_ID_NONE;
485 mac_client_impl_t *mcip = (mac_client_impl_t *)mch;
486 flow_desc_t flow_desc;
488 if (mcip->mci_nflents == 0)
489 return (vid);
491 ASSERT(MCIP_DATAPATH_SETUP(mcip) && mac_client_single_rcvr(mcip));
493 mac_flow_get_desc(mcip->mci_flent, &flow_desc);
494 if ((flow_desc.fd_mask & FLOW_LINK_VID) != 0)
495 vid = flow_desc.fd_vid;
497 return (vid);
501 * Return whether the specified MAC client corresponds to a VLAN VNIC.
503 boolean_t
504 mac_client_is_vlan_vnic(mac_client_handle_t mch)
506 mac_client_impl_t *mcip = (mac_client_impl_t *)mch;
508 return (((mcip->mci_state_flags & MCIS_IS_VNIC) != 0) &&
509 ((mcip->mci_flent->fe_type & FLOW_PRIMARY_MAC) != 0));
513 * Return the link speed associated with the specified MAC client.
515 * The link speed of a MAC client is equal to the smallest value of
516 * 1) the current link speed of the underlying NIC, or
517 * 2) the bandwidth limit set for the MAC client.
519 * Note that the bandwidth limit can be higher than the speed
520 * of the underlying NIC. This is allowed to avoid spurious
521 * administration action failures or artifically lowering the
522 * bandwidth limit of a link that may have temporarily lowered
523 * its link speed due to hardware problem or administrator action.
525 static uint64_t
526 mac_client_ifspeed(mac_client_impl_t *mcip)
528 mac_impl_t *mip = mcip->mci_mip;
529 uint64_t nic_speed;
531 nic_speed = mac_stat_get((mac_handle_t)mip, MAC_STAT_IFSPEED);
533 if (nic_speed == 0) {
534 return (0);
535 } else {
536 uint64_t policy_limit = (uint64_t)-1;
538 if (MCIP_RESOURCE_PROPS_MASK(mcip) & MRP_MAXBW)
539 policy_limit = MCIP_RESOURCE_PROPS_MAXBW(mcip);
541 return (MIN(policy_limit, nic_speed));
546 * Return the link state of the specified client. If here are more
547 * than one clients of the underying mac_impl_t, the link state
548 * will always be UP regardless of the link state of the underlying
549 * mac_impl_t. This is needed to allow the MAC clients to continue
550 * to communicate with each other even when the physical link of
551 * their mac_impl_t is down.
553 static uint64_t
554 mac_client_link_state(mac_client_impl_t *mcip)
556 mac_impl_t *mip = mcip->mci_mip;
557 uint16_t vid;
558 mac_client_impl_t *mci_list;
559 mac_unicast_impl_t *mui_list, *oth_mui_list;
562 * Returns LINK_STATE_UP if there are other MAC clients defined on
563 * mac_impl_t which share same VLAN ID as that of mcip. Note that
564 * if 'mcip' has more than one VID's then we match ANY one of the
565 * VID's with other MAC client's VID's and return LINK_STATE_UP.
567 rw_enter(&mcip->mci_rw_lock, RW_READER);
568 for (mui_list = mcip->mci_unicast_list; mui_list != NULL;
569 mui_list = mui_list->mui_next) {
570 vid = mui_list->mui_vid;
571 for (mci_list = mip->mi_clients_list; mci_list != NULL;
572 mci_list = mci_list->mci_client_next) {
573 if (mci_list == mcip)
574 continue;
575 for (oth_mui_list = mci_list->mci_unicast_list;
576 oth_mui_list != NULL; oth_mui_list = oth_mui_list->
577 mui_next) {
578 if (vid == oth_mui_list->mui_vid) {
579 rw_exit(&mcip->mci_rw_lock);
580 return (LINK_STATE_UP);
585 rw_exit(&mcip->mci_rw_lock);
587 return (mac_stat_get((mac_handle_t)mip, MAC_STAT_LINK_STATE));
591 * These statistics are consumed by dladm show-link -s <vnic>,
592 * dladm show-vnic -s and netstat. With the introduction of dlstat,
593 * dladm show-link -s and dladm show-vnic -s witll be EOL'ed while
594 * netstat will consume from kstats introduced for dlstat. This code
595 * will be removed at that time.
599 * Return the statistics of a MAC client. These statistics are different
600 * then the statistics of the underlying MAC which are returned by
601 * mac_stat_get().
603 uint64_t
604 mac_client_stat_get(mac_client_handle_t mch, uint_t stat)
606 mac_client_impl_t *mcip = (mac_client_impl_t *)mch;
607 mac_impl_t *mip = mcip->mci_mip;
608 flow_entry_t *flent = mcip->mci_flent;
609 mac_soft_ring_set_t *mac_srs;
610 mac_rx_stats_t *mac_rx_stat;
611 mac_tx_stats_t *mac_tx_stat;
612 int i;
613 uint64_t val = 0;
615 mac_srs = (mac_soft_ring_set_t *)(flent->fe_tx_srs);
616 mac_tx_stat = &mac_srs->srs_tx.st_stat;
618 switch (stat) {
619 case MAC_STAT_LINK_STATE:
620 val = mac_client_link_state(mcip);
621 break;
622 case MAC_STAT_LINK_UP:
623 val = (mac_client_link_state(mcip) == LINK_STATE_UP);
624 break;
625 case MAC_STAT_PROMISC:
626 val = mac_stat_get((mac_handle_t)mip, MAC_STAT_PROMISC);
627 break;
628 case MAC_STAT_LOWLINK_STATE:
629 val = mac_stat_get((mac_handle_t)mip, MAC_STAT_LOWLINK_STATE);
630 break;
631 case MAC_STAT_IFSPEED:
632 val = mac_client_ifspeed(mcip);
633 break;
634 case MAC_STAT_MULTIRCV:
635 val = mcip->mci_misc_stat.mms_multircv;
636 break;
637 case MAC_STAT_BRDCSTRCV:
638 val = mcip->mci_misc_stat.mms_brdcstrcv;
639 break;
640 case MAC_STAT_MULTIXMT:
641 val = mcip->mci_misc_stat.mms_multixmt;
642 break;
643 case MAC_STAT_BRDCSTXMT:
644 val = mcip->mci_misc_stat.mms_brdcstxmt;
645 break;
646 case MAC_STAT_OBYTES:
647 val = mac_tx_stat->mts_obytes;
648 break;
649 case MAC_STAT_OPACKETS:
650 val = mac_tx_stat->mts_opackets;
651 break;
652 case MAC_STAT_OERRORS:
653 val = mac_tx_stat->mts_oerrors;
654 break;
655 case MAC_STAT_IPACKETS:
656 for (i = 0; i < flent->fe_rx_srs_cnt; i++) {
657 mac_srs = (mac_soft_ring_set_t *)flent->fe_rx_srs[i];
658 mac_rx_stat = &mac_srs->srs_rx.sr_stat;
659 val += mac_rx_stat->mrs_intrcnt +
660 mac_rx_stat->mrs_pollcnt + mac_rx_stat->mrs_lclcnt;
662 break;
663 case MAC_STAT_RBYTES:
664 for (i = 0; i < flent->fe_rx_srs_cnt; i++) {
665 mac_srs = (mac_soft_ring_set_t *)flent->fe_rx_srs[i];
666 mac_rx_stat = &mac_srs->srs_rx.sr_stat;
667 val += mac_rx_stat->mrs_intrbytes +
668 mac_rx_stat->mrs_pollbytes +
669 mac_rx_stat->mrs_lclbytes;
671 break;
672 case MAC_STAT_IERRORS:
673 for (i = 0; i < flent->fe_rx_srs_cnt; i++) {
674 mac_srs = (mac_soft_ring_set_t *)flent->fe_rx_srs[i];
675 mac_rx_stat = &mac_srs->srs_rx.sr_stat;
676 val += mac_rx_stat->mrs_ierrors;
678 break;
679 default:
680 val = mac_driver_stat_default(mip, stat);
681 break;
684 return (val);
688 * Return the statistics of the specified MAC instance.
690 uint64_t
691 mac_stat_get(mac_handle_t mh, uint_t stat)
693 mac_impl_t *mip = (mac_impl_t *)mh;
694 uint64_t val;
695 int ret;
698 * The range of stat determines where it is maintained. Stat
699 * values from 0 up to (but not including) MAC_STAT_MIN are
700 * mainteined by the mac module itself. Everything else is
701 * maintained by the driver.
703 * If the mac_impl_t being queried corresponds to a VNIC,
704 * the stats need to be queried from the lower MAC client
705 * corresponding to the VNIC. (The mac_link_update()
706 * invoked by the driver to the lower MAC causes the *lower
707 * MAC* to update its mi_linkstate, and send a notification
708 * to its MAC clients. Due to the VNIC passthrough,
709 * these notifications are sent to the upper MAC clients
710 * of the VNIC directly, and the upper mac_impl_t of the VNIC
711 * does not have a valid mi_linkstate.
713 if (stat < MAC_STAT_MIN && !(mip->mi_state_flags & MIS_IS_VNIC)) {
714 /* these stats are maintained by the mac module itself */
715 switch (stat) {
716 case MAC_STAT_LINK_STATE:
717 return (mip->mi_linkstate);
718 case MAC_STAT_LINK_UP:
719 return (mip->mi_linkstate == LINK_STATE_UP);
720 case MAC_STAT_PROMISC:
721 return (mip->mi_devpromisc != 0);
722 case MAC_STAT_LOWLINK_STATE:
723 return (mip->mi_lowlinkstate);
724 default:
725 ASSERT(B_FALSE);
730 * Call the driver to get the given statistic.
732 ret = mip->mi_getstat(mip->mi_driver, stat, &val);
733 if (ret != 0) {
735 * The driver doesn't support this statistic. Get the
736 * statistic's default value.
738 val = mac_driver_stat_default(mip, stat);
740 return (val);
744 * Query hardware rx ring corresponding to the pseudo ring.
746 uint64_t
747 mac_pseudo_rx_ring_stat_get(mac_ring_handle_t handle, uint_t stat)
749 return (mac_rx_ring_stat_get(handle, stat));
753 * Query hardware tx ring corresponding to the pseudo ring.
755 uint64_t
756 mac_pseudo_tx_ring_stat_get(mac_ring_handle_t handle, uint_t stat)
758 return (mac_tx_ring_stat_get(handle, stat));
762 * Utility function which returns the VID associated with a flow entry.
764 uint16_t
765 i_mac_flow_vid(flow_entry_t *flent)
767 flow_desc_t flow_desc;
769 mac_flow_get_desc(flent, &flow_desc);
771 if ((flow_desc.fd_mask & FLOW_LINK_VID) != 0)
772 return (flow_desc.fd_vid);
773 return (VLAN_ID_NONE);
777 * Verify the validity of the specified unicast MAC address. Returns B_TRUE
778 * if the address is valid, B_FALSE otherwise (multicast address, or incorrect
779 * length.
781 boolean_t
782 mac_unicst_verify(mac_handle_t mh, const uint8_t *addr, uint_t len)
784 mac_impl_t *mip = (mac_impl_t *)mh;
787 * Verify the address. No lock is needed since mi_type and plugin
788 * details don't change after mac_register().
790 if ((len != mip->mi_type->mt_addr_length) ||
791 (mip->mi_type->mt_ops.mtops_unicst_verify(addr,
792 mip->mi_pdata)) != 0) {
793 return (B_FALSE);
794 } else {
795 return (B_TRUE);
799 void
800 mac_sdu_get(mac_handle_t mh, uint_t *min_sdu, uint_t *max_sdu)
802 mac_impl_t *mip = (mac_impl_t *)mh;
804 if (min_sdu != NULL)
805 *min_sdu = mip->mi_sdu_min;
806 if (max_sdu != NULL)
807 *max_sdu = mip->mi_sdu_max;
810 void
811 mac_sdu_get2(mac_handle_t mh, uint_t *min_sdu, uint_t *max_sdu,
812 uint_t *multicast_sdu)
814 mac_impl_t *mip = (mac_impl_t *)mh;
816 if (min_sdu != NULL)
817 *min_sdu = mip->mi_sdu_min;
818 if (max_sdu != NULL)
819 *max_sdu = mip->mi_sdu_max;
820 if (multicast_sdu != NULL)
821 *multicast_sdu = mip->mi_sdu_multicast;
825 * Update the MAC unicast address of the specified client's flows. Currently
826 * only one unicast MAC unicast address is allowed per client.
828 static void
829 mac_unicast_update_client_flow(mac_client_impl_t *mcip)
831 mac_impl_t *mip = mcip->mci_mip;
832 flow_entry_t *flent = mcip->mci_flent;
833 mac_address_t *map = mcip->mci_unicast;
834 flow_desc_t flow_desc;
836 ASSERT(MAC_PERIM_HELD((mac_handle_t)mip));
837 ASSERT(flent != NULL);
839 mac_flow_get_desc(flent, &flow_desc);
840 ASSERT(flow_desc.fd_mask & FLOW_LINK_DST);
842 bcopy(map->ma_addr, flow_desc.fd_dst_mac, map->ma_len);
843 mac_flow_set_desc(flent, &flow_desc);
846 * The v6 local addr (used by mac protection) needs to be
847 * regenerated because our mac address has changed.
849 mac_protect_update_v6_local_addr(mcip);
852 * A MAC client could have one MAC address but multiple
853 * VLANs. In that case update the flow entries corresponding
854 * to all VLANs of the MAC client.
856 for (flent = mcip->mci_flent_list; flent != NULL;
857 flent = flent->fe_client_next) {
858 mac_flow_get_desc(flent, &flow_desc);
859 if (!(flent->fe_type & FLOW_PRIMARY_MAC ||
860 flent->fe_type & FLOW_VNIC_MAC))
861 continue;
863 bcopy(map->ma_addr, flow_desc.fd_dst_mac, map->ma_len);
864 mac_flow_set_desc(flent, &flow_desc);
869 * Update all clients that share the same unicast address.
871 void
872 mac_unicast_update_clients(mac_impl_t *mip, mac_address_t *map)
874 mac_client_impl_t *mcip;
876 ASSERT(MAC_PERIM_HELD((mac_handle_t)mip));
879 * Find all clients that share the same unicast MAC address and update
880 * them appropriately.
882 for (mcip = mip->mi_clients_list; mcip != NULL;
883 mcip = mcip->mci_client_next) {
885 * Ignore clients that don't share this MAC address.
887 if (map != mcip->mci_unicast)
888 continue;
891 * Update those clients with same old unicast MAC address.
893 mac_unicast_update_client_flow(mcip);
898 * Update the unicast MAC address of the specified VNIC MAC client.
900 * Check whether the operation is valid. Any of following cases should fail:
902 * 1. It's a VLAN type of VNIC.
903 * 2. The new value is current "primary" MAC address.
904 * 3. The current MAC address is shared with other clients.
905 * 4. The new MAC address has been used. This case will be valid when
906 * client migration is fully supported.
909 mac_vnic_unicast_set(mac_client_handle_t mch, const uint8_t *addr)
911 mac_client_impl_t *mcip = (mac_client_impl_t *)mch;
912 mac_impl_t *mip = mcip->mci_mip;
913 mac_address_t *map = mcip->mci_unicast;
914 int err;
916 ASSERT(!(mip->mi_state_flags & MIS_IS_VNIC));
917 ASSERT(mcip->mci_state_flags & MCIS_IS_VNIC);
918 ASSERT(mcip->mci_flags != MAC_CLIENT_FLAGS_PRIMARY);
920 i_mac_perim_enter(mip);
923 * If this is a VLAN type of VNIC, it's using "primary" MAC address
924 * of the underlying interface. Must fail here. Refer to case 1 above.
926 if (bcmp(map->ma_addr, mip->mi_addr, map->ma_len) == 0) {
927 i_mac_perim_exit(mip);
928 return (ENOTSUP);
932 * If the new address is the "primary" one, must fail. Refer to
933 * case 2 above.
935 if (bcmp(addr, mip->mi_addr, map->ma_len) == 0) {
936 i_mac_perim_exit(mip);
937 return (EACCES);
941 * If the address is shared by multiple clients, must fail. Refer
942 * to case 3 above.
944 if (mac_check_macaddr_shared(map)) {
945 i_mac_perim_exit(mip);
946 return (EBUSY);
950 * If the new address has been used, must fail for now. Refer to
951 * case 4 above.
953 if (mac_find_macaddr(mip, (uint8_t *)addr) != NULL) {
954 i_mac_perim_exit(mip);
955 return (ENOTSUP);
959 * Update the MAC address.
961 err = mac_update_macaddr(map, (uint8_t *)addr);
963 if (err != 0) {
964 i_mac_perim_exit(mip);
965 return (err);
969 * Update all flows of this MAC client.
971 mac_unicast_update_client_flow(mcip);
973 i_mac_perim_exit(mip);
974 return (0);
978 * Program the new primary unicast address of the specified MAC.
980 * Function mac_update_macaddr() takes care different types of underlying
981 * MAC. If the underlying MAC is VNIC, the VNIC driver must have registerd
982 * mi_unicst() entry point, that indirectly calls mac_vnic_unicast_set()
983 * which will take care of updating the MAC address of the corresponding
984 * MAC client.
986 * This is the only interface that allow the client to update the "primary"
987 * MAC address of the underlying MAC. The new value must have not been
988 * used by other clients.
991 mac_unicast_primary_set(mac_handle_t mh, const uint8_t *addr)
993 mac_impl_t *mip = (mac_impl_t *)mh;
994 mac_address_t *map;
995 int err;
997 /* verify the address validity */
998 if (!mac_unicst_verify(mh, addr, mip->mi_type->mt_addr_length))
999 return (EINVAL);
1001 i_mac_perim_enter(mip);
1004 * If the new value is the same as the current primary address value,
1005 * there's nothing to do.
1007 if (bcmp(addr, mip->mi_addr, mip->mi_type->mt_addr_length) == 0) {
1008 i_mac_perim_exit(mip);
1009 return (0);
1012 if (mac_find_macaddr(mip, (uint8_t *)addr) != 0) {
1013 i_mac_perim_exit(mip);
1014 return (EBUSY);
1017 map = mac_find_macaddr(mip, mip->mi_addr);
1018 ASSERT(map != NULL);
1021 * Update the MAC address.
1023 if (mip->mi_state_flags & MIS_IS_AGGR) {
1024 mac_capab_aggr_t aggr_cap;
1027 * If the mac is an aggregation, other than the unicast
1028 * addresses programming, aggr must be informed about this
1029 * primary unicst address change to change its mac address
1030 * policy to be user-specified.
1032 ASSERT(map->ma_type == MAC_ADDRESS_TYPE_UNICAST_CLASSIFIED);
1033 VERIFY(i_mac_capab_get(mh, MAC_CAPAB_AGGR, &aggr_cap));
1034 err = aggr_cap.mca_unicst(mip->mi_driver, addr);
1035 if (err == 0)
1036 bcopy(addr, map->ma_addr, map->ma_len);
1037 } else {
1038 err = mac_update_macaddr(map, (uint8_t *)addr);
1041 if (err != 0) {
1042 i_mac_perim_exit(mip);
1043 return (err);
1046 mac_unicast_update_clients(mip, map);
1049 * Save the new primary MAC address in mac_impl_t.
1051 bcopy(addr, mip->mi_addr, mip->mi_type->mt_addr_length);
1053 i_mac_perim_exit(mip);
1055 if (err == 0)
1056 i_mac_notify(mip, MAC_NOTE_UNICST);
1058 return (err);
1062 * Return the current primary MAC address of the specified MAC.
1064 void
1065 mac_unicast_primary_get(mac_handle_t mh, uint8_t *addr)
1067 mac_impl_t *mip = (mac_impl_t *)mh;
1069 rw_enter(&mip->mi_rw_lock, RW_READER);
1070 bcopy(mip->mi_addr, addr, mip->mi_type->mt_addr_length);
1071 rw_exit(&mip->mi_rw_lock);
1075 * Return the secondary MAC address for the specified handle
1077 void
1078 mac_unicast_secondary_get(mac_client_handle_t mh, uint8_t *addr)
1080 mac_client_impl_t *mcip = (mac_client_impl_t *)mh;
1082 ASSERT(mcip->mci_unicast != NULL);
1083 bcopy(mcip->mci_unicast->ma_addr, addr, mcip->mci_unicast->ma_len);
1087 * Return information about the use of the primary MAC address of the
1088 * specified MAC instance:
1090 * - if client_name is non-NULL, it must point to a string of at
1091 * least MAXNAMELEN bytes, and will be set to the name of the MAC
1092 * client which uses the primary MAC address.
1094 * - if in_use is non-NULL, used to return whether the primary MAC
1095 * address is currently in use.
1097 void
1098 mac_unicast_primary_info(mac_handle_t mh, char *client_name, boolean_t *in_use)
1100 mac_impl_t *mip = (mac_impl_t *)mh;
1101 mac_client_impl_t *cur_client;
1103 if (in_use != NULL)
1104 *in_use = B_FALSE;
1105 if (client_name != NULL)
1106 bzero(client_name, MAXNAMELEN);
1109 * The mi_rw_lock is used to protect threads that don't hold the
1110 * mac perimeter to get a consistent view of the mi_clients_list.
1111 * Threads that modify the list must hold both the mac perimeter and
1112 * mi_rw_lock(RW_WRITER)
1114 rw_enter(&mip->mi_rw_lock, RW_READER);
1115 for (cur_client = mip->mi_clients_list; cur_client != NULL;
1116 cur_client = cur_client->mci_client_next) {
1117 if (mac_is_primary_client(cur_client) ||
1118 (mip->mi_state_flags & MIS_IS_VNIC)) {
1119 rw_exit(&mip->mi_rw_lock);
1120 if (in_use != NULL)
1121 *in_use = B_TRUE;
1122 if (client_name != NULL) {
1123 bcopy(cur_client->mci_name, client_name,
1124 MAXNAMELEN);
1126 return;
1129 rw_exit(&mip->mi_rw_lock);
1133 * Return the current destination MAC address of the specified MAC.
1135 boolean_t
1136 mac_dst_get(mac_handle_t mh, uint8_t *addr)
1138 mac_impl_t *mip = (mac_impl_t *)mh;
1140 rw_enter(&mip->mi_rw_lock, RW_READER);
1141 if (mip->mi_dstaddr_set)
1142 bcopy(mip->mi_dstaddr, addr, mip->mi_type->mt_addr_length);
1143 rw_exit(&mip->mi_rw_lock);
1144 return (mip->mi_dstaddr_set);
1148 * Add the specified MAC client to the list of clients which opened
1149 * the specified MAC.
1151 static void
1152 mac_client_add(mac_client_impl_t *mcip)
1154 mac_impl_t *mip = mcip->mci_mip;
1156 ASSERT(MAC_PERIM_HELD((mac_handle_t)mip));
1158 /* add VNIC to the front of the list */
1159 rw_enter(&mip->mi_rw_lock, RW_WRITER);
1160 mcip->mci_client_next = mip->mi_clients_list;
1161 mip->mi_clients_list = mcip;
1162 mip->mi_nclients++;
1163 rw_exit(&mip->mi_rw_lock);
1167 * Remove the specified MAC client from the list of clients which opened
1168 * the specified MAC.
1170 static void
1171 mac_client_remove(mac_client_impl_t *mcip)
1173 mac_impl_t *mip = mcip->mci_mip;
1174 mac_client_impl_t **prev, *cclient;
1176 ASSERT(MAC_PERIM_HELD((mac_handle_t)mip));
1178 rw_enter(&mip->mi_rw_lock, RW_WRITER);
1179 prev = &mip->mi_clients_list;
1180 cclient = *prev;
1181 while (cclient != NULL && cclient != mcip) {
1182 prev = &cclient->mci_client_next;
1183 cclient = *prev;
1185 ASSERT(cclient != NULL);
1186 *prev = cclient->mci_client_next;
1187 mip->mi_nclients--;
1188 rw_exit(&mip->mi_rw_lock);
1191 static mac_unicast_impl_t *
1192 mac_client_find_vid(mac_client_impl_t *mcip, uint16_t vid)
1194 mac_unicast_impl_t *muip = mcip->mci_unicast_list;
1196 while ((muip != NULL) && (muip->mui_vid != vid))
1197 muip = muip->mui_next;
1199 return (muip);
1203 * Return whether the specified (MAC address, VID) tuple is already used by
1204 * one of the MAC clients associated with the specified MAC.
1206 static boolean_t
1207 mac_addr_in_use(mac_impl_t *mip, uint8_t *mac_addr, uint16_t vid)
1209 mac_client_impl_t *client;
1210 mac_address_t *map;
1212 ASSERT(MAC_PERIM_HELD((mac_handle_t)mip));
1214 for (client = mip->mi_clients_list; client != NULL;
1215 client = client->mci_client_next) {
1218 * Ignore clients that don't have unicast address.
1220 if (client->mci_unicast_list == NULL)
1221 continue;
1223 map = client->mci_unicast;
1225 if ((bcmp(mac_addr, map->ma_addr, map->ma_len) == 0) &&
1226 (mac_client_find_vid(client, vid) != NULL)) {
1227 return (B_TRUE);
1231 return (B_FALSE);
1235 * Generate a random MAC address. The MAC address prefix is
1236 * stored in the array pointed to by mac_addr, and its length, in bytes,
1237 * is specified by prefix_len. The least significant bits
1238 * after prefix_len bytes are generated, and stored after the prefix
1239 * in the mac_addr array.
1242 mac_addr_random(mac_client_handle_t mch, uint_t prefix_len,
1243 uint8_t *mac_addr, mac_diag_t *diag)
1245 mac_client_impl_t *mcip = (mac_client_impl_t *)mch;
1246 mac_impl_t *mip = mcip->mci_mip;
1247 size_t addr_len = mip->mi_type->mt_addr_length;
1249 if (prefix_len >= addr_len) {
1250 *diag = MAC_DIAG_MACPREFIXLEN_INVALID;
1251 return (EINVAL);
1254 /* check the prefix value */
1255 if (prefix_len > 0) {
1256 bzero(mac_addr + prefix_len, addr_len - prefix_len);
1257 if (!mac_unicst_verify((mac_handle_t)mip, mac_addr,
1258 addr_len)) {
1259 *diag = MAC_DIAG_MACPREFIX_INVALID;
1260 return (EINVAL);
1264 /* generate the MAC address */
1265 if (prefix_len < addr_len) {
1266 (void) random_get_pseudo_bytes(mac_addr +
1267 prefix_len, addr_len - prefix_len);
1270 *diag = 0;
1271 return (0);
1275 * Set the priority range for this MAC client. This will be used to
1276 * determine the absolute priority for the threads created for this
1277 * MAC client using the specified "low", "medium" and "high" level.
1278 * This will also be used for any subflows on this MAC client.
1280 #define MAC_CLIENT_SET_PRIORITY_RANGE(mcip, pri) { \
1281 (mcip)->mci_min_pri = FLOW_MIN_PRIORITY(MINCLSYSPRI, \
1282 MAXCLSYSPRI, (pri)); \
1283 (mcip)->mci_max_pri = FLOW_MAX_PRIORITY(MINCLSYSPRI, \
1284 MAXCLSYSPRI, (mcip)->mci_min_pri); \
1288 * MAC client open entry point. Return a new MAC client handle. Each
1289 * MAC client is associated with a name, specified through the 'name'
1290 * argument.
1293 mac_client_open(mac_handle_t mh, mac_client_handle_t *mchp, char *name,
1294 uint16_t flags)
1296 mac_impl_t *mip = (mac_impl_t *)mh;
1297 mac_client_impl_t *mcip;
1298 int err = 0;
1299 boolean_t share_desired;
1300 flow_entry_t *flent = NULL;
1302 share_desired = (flags & MAC_OPEN_FLAGS_SHARES_DESIRED) != 0;
1303 *mchp = NULL;
1305 i_mac_perim_enter(mip);
1307 if (mip->mi_state_flags & MIS_IS_VNIC) {
1309 * The underlying MAC is a VNIC. Return the MAC client
1310 * handle of the lower MAC which was obtained by
1311 * the VNIC driver when it did its mac_client_open().
1314 mcip = mac_vnic_lower(mip);
1317 * Note that multiple mac clients share the same mcip in
1318 * this case.
1320 if (flags & MAC_OPEN_FLAGS_EXCLUSIVE)
1321 mcip->mci_state_flags |= MCIS_EXCLUSIVE;
1323 if (flags & MAC_OPEN_FLAGS_MULTI_PRIMARY)
1324 mcip->mci_flags |= MAC_CLIENT_FLAGS_MULTI_PRIMARY;
1326 mip->mi_clients_list = mcip;
1327 i_mac_perim_exit(mip);
1328 *mchp = (mac_client_handle_t)mcip;
1330 DTRACE_PROBE2(mac__client__open__nonallocated, mac_impl_t *,
1331 mcip->mci_mip, mac_client_impl_t *, mcip);
1333 return (err);
1336 mcip = kmem_cache_alloc(mac_client_impl_cache, KM_SLEEP);
1338 mcip->mci_mip = mip;
1339 mcip->mci_upper_mip = NULL;
1340 mcip->mci_rx_fn = mac_pkt_drop;
1341 mcip->mci_rx_arg = NULL;
1342 mcip->mci_rx_p_fn = NULL;
1343 mcip->mci_rx_p_arg = NULL;
1344 mcip->mci_p_unicast_list = NULL;
1345 mcip->mci_direct_rx_fn = NULL;
1346 mcip->mci_direct_rx_arg = NULL;
1348 mcip->mci_unicast_list = NULL;
1350 if ((flags & MAC_OPEN_FLAGS_IS_VNIC) != 0)
1351 mcip->mci_state_flags |= MCIS_IS_VNIC;
1353 if ((flags & MAC_OPEN_FLAGS_EXCLUSIVE) != 0)
1354 mcip->mci_state_flags |= MCIS_EXCLUSIVE;
1356 if ((flags & MAC_OPEN_FLAGS_IS_AGGR_PORT) != 0)
1357 mcip->mci_state_flags |= MCIS_IS_AGGR_PORT;
1359 if (mip->mi_state_flags & MIS_IS_AGGR)
1360 mcip->mci_state_flags |= MCIS_IS_AGGR;
1362 if ((flags & MAC_OPEN_FLAGS_USE_DATALINK_NAME) != 0) {
1363 datalink_id_t linkid;
1365 ASSERT(name == NULL);
1366 if ((err = dls_devnet_macname2linkid(mip->mi_name,
1367 &linkid)) != 0) {
1368 goto done;
1370 if ((err = dls_mgmt_get_linkinfo(linkid, mcip->mci_name, NULL,
1371 NULL, NULL)) != 0) {
1373 * Use mac name if dlmgmtd is not available.
1375 if (err == EBADF) {
1376 (void) strlcpy(mcip->mci_name, mip->mi_name,
1377 sizeof (mcip->mci_name));
1378 err = 0;
1379 } else {
1380 goto done;
1383 mcip->mci_state_flags |= MCIS_USE_DATALINK_NAME;
1384 } else {
1385 ASSERT(name != NULL);
1386 if (strlen(name) > MAXNAMELEN) {
1387 err = EINVAL;
1388 goto done;
1390 (void) strlcpy(mcip->mci_name, name, sizeof (mcip->mci_name));
1393 if (flags & MAC_OPEN_FLAGS_MULTI_PRIMARY)
1394 mcip->mci_flags |= MAC_CLIENT_FLAGS_MULTI_PRIMARY;
1396 if (flags & MAC_OPEN_FLAGS_NO_UNICAST_ADDR)
1397 mcip->mci_state_flags |= MCIS_NO_UNICAST_ADDR;
1399 mac_protect_init(mcip);
1401 /* the subflow table will be created dynamically */
1402 mcip->mci_subflow_tab = NULL;
1404 mcip->mci_misc_stat.mms_multircv = 0;
1405 mcip->mci_misc_stat.mms_brdcstrcv = 0;
1406 mcip->mci_misc_stat.mms_multixmt = 0;
1407 mcip->mci_misc_stat.mms_brdcstxmt = 0;
1409 /* Create an initial flow */
1411 err = mac_flow_create(NULL, NULL, mcip->mci_name, NULL,
1412 mcip->mci_state_flags & MCIS_IS_VNIC ? FLOW_VNIC_MAC :
1413 FLOW_PRIMARY_MAC, &flent);
1414 if (err != 0)
1415 goto done;
1416 mcip->mci_flent = flent;
1417 FLOW_MARK(flent, FE_MC_NO_DATAPATH);
1418 flent->fe_mcip = mcip;
1420 * Place initial creation reference on the flow. This reference
1421 * is released in the corresponding delete action viz.
1422 * mac_unicast_remove after waiting for all transient refs to
1423 * to go away. The wait happens in mac_flow_wait.
1425 FLOW_REFHOLD(flent);
1428 * Do this ahead of the mac_bcast_add() below so that the mi_nclients
1429 * will have the right value for mac_rx_srs_setup().
1431 mac_client_add(mcip);
1433 mcip->mci_share = NULL;
1434 if (share_desired)
1435 i_mac_share_alloc(mcip);
1438 * We will do mimimal datapath setup to allow a MAC client to
1439 * transmit or receive non-unicast packets without waiting
1440 * for mac_unicast_add.
1442 if (mcip->mci_state_flags & MCIS_NO_UNICAST_ADDR) {
1443 if ((err = mac_client_datapath_setup(mcip, VLAN_ID_NONE,
1444 NULL, NULL, B_TRUE, NULL)) != 0) {
1445 goto done;
1449 DTRACE_PROBE2(mac__client__open__allocated, mac_impl_t *,
1450 mcip->mci_mip, mac_client_impl_t *, mcip);
1452 *mchp = (mac_client_handle_t)mcip;
1453 i_mac_perim_exit(mip);
1454 return (0);
1456 done:
1457 i_mac_perim_exit(mip);
1458 mcip->mci_state_flags = 0;
1459 mcip->mci_tx_flag = 0;
1460 kmem_cache_free(mac_client_impl_cache, mcip);
1461 return (err);
1465 * Close the specified MAC client handle.
1467 void
1468 mac_client_close(mac_client_handle_t mch, uint16_t flags)
1470 mac_client_impl_t *mcip = (mac_client_impl_t *)mch;
1471 mac_impl_t *mip = mcip->mci_mip;
1472 flow_entry_t *flent;
1474 i_mac_perim_enter(mip);
1476 if (flags & MAC_CLOSE_FLAGS_EXCLUSIVE)
1477 mcip->mci_state_flags &= ~MCIS_EXCLUSIVE;
1479 if ((mcip->mci_state_flags & MCIS_IS_VNIC) &&
1480 !(flags & MAC_CLOSE_FLAGS_IS_VNIC)) {
1482 * This is an upper VNIC client initiated operation.
1483 * The lower MAC client will be closed by the VNIC driver
1484 * when the VNIC is deleted.
1487 i_mac_perim_exit(mip);
1488 return;
1491 /* If we have only setup up minimal datapth setup, tear it down */
1492 if (mcip->mci_state_flags & MCIS_NO_UNICAST_ADDR) {
1493 mac_client_datapath_teardown((mac_client_handle_t)mcip, NULL,
1494 mcip->mci_flent);
1495 mcip->mci_state_flags &= ~MCIS_NO_UNICAST_ADDR;
1499 * Remove the flent associated with the MAC client
1501 flent = mcip->mci_flent;
1502 mcip->mci_flent = NULL;
1503 FLOW_FINAL_REFRELE(flent);
1506 * MAC clients must remove the unicast addresses and promisc callbacks
1507 * they added before issuing a mac_client_close().
1509 ASSERT(mcip->mci_unicast_list == NULL);
1510 ASSERT(mcip->mci_promisc_list == NULL);
1511 ASSERT(mcip->mci_tx_notify_cb_list == NULL);
1513 i_mac_share_free(mcip);
1514 mac_protect_fini(mcip);
1515 mac_client_remove(mcip);
1517 i_mac_perim_exit(mip);
1518 mcip->mci_subflow_tab = NULL;
1519 mcip->mci_state_flags = 0;
1520 mcip->mci_tx_flag = 0;
1521 kmem_cache_free(mac_client_impl_cache, mch);
1525 * Set the rx bypass receive callback.
1527 boolean_t
1528 mac_rx_bypass_set(mac_client_handle_t mch, mac_direct_rx_t rx_fn, void *arg1)
1530 mac_client_impl_t *mcip = (mac_client_impl_t *)mch;
1531 mac_impl_t *mip = mcip->mci_mip;
1533 ASSERT(MAC_PERIM_HELD((mac_handle_t)mip));
1536 * If the mac_client is a VLAN, we should not do DLS bypass and
1537 * instead let the packets come up via mac_rx_deliver so the vlan
1538 * header can be stripped.
1540 if (mcip->mci_nvids > 0)
1541 return (B_FALSE);
1544 * These are not accessed directly in the data path, and hence
1545 * don't need any protection
1547 mcip->mci_direct_rx_fn = rx_fn;
1548 mcip->mci_direct_rx_arg = arg1;
1549 return (B_TRUE);
1553 * Enable/Disable rx bypass. By default, bypass is assumed to be enabled.
1555 void
1556 mac_rx_bypass_enable(mac_client_handle_t mch)
1558 ((mac_client_impl_t *)mch)->mci_state_flags &= ~MCIS_RX_BYPASS_DISABLE;
1561 void
1562 mac_rx_bypass_disable(mac_client_handle_t mch)
1564 ((mac_client_impl_t *)mch)->mci_state_flags |= MCIS_RX_BYPASS_DISABLE;
1568 * Set the receive callback for the specified MAC client. There can be
1569 * at most one such callback per MAC client.
1571 void
1572 mac_rx_set(mac_client_handle_t mch, mac_rx_t rx_fn, void *arg)
1574 mac_client_impl_t *mcip = (mac_client_impl_t *)mch;
1575 mac_impl_t *mip = mcip->mci_mip;
1576 mac_impl_t *umip = mcip->mci_upper_mip;
1579 * Instead of adding an extra set of locks and refcnts in
1580 * the datapath at the mac client boundary, we temporarily quiesce
1581 * the SRS and related entities. We then change the receive function
1582 * without interference from any receive data thread and then reenable
1583 * the data flow subsequently.
1585 i_mac_perim_enter(mip);
1586 mac_rx_client_quiesce(mch);
1588 mcip->mci_rx_fn = rx_fn;
1589 mcip->mci_rx_arg = arg;
1590 mac_rx_client_restart(mch);
1591 i_mac_perim_exit(mip);
1594 * If we're changing the rx function on the primary mac of a vnic,
1595 * make sure any secondary macs on the vnic are updated as well.
1597 if (umip != NULL) {
1598 ASSERT((umip->mi_state_flags & MIS_IS_VNIC) != 0);
1599 mac_vnic_secondary_update(umip);
1604 * Reset the receive callback for the specified MAC client.
1606 void
1607 mac_rx_clear(mac_client_handle_t mch)
1609 mac_rx_set(mch, mac_pkt_drop, NULL);
1612 void
1613 mac_secondary_dup(mac_client_handle_t smch, mac_client_handle_t dmch)
1615 mac_client_impl_t *smcip = (mac_client_impl_t *)smch;
1616 mac_client_impl_t *dmcip = (mac_client_impl_t *)dmch;
1617 flow_entry_t *flent = dmcip->mci_flent;
1619 /* This should only be called to setup secondary macs */
1620 ASSERT((flent->fe_type & FLOW_PRIMARY_MAC) == 0);
1622 mac_rx_set(dmch, smcip->mci_rx_fn, smcip->mci_rx_arg);
1623 dmcip->mci_promisc_list = smcip->mci_promisc_list;
1626 * Duplicate the primary mac resources to the secondary.
1627 * Since we already validated the resource controls when setting
1628 * them on the primary, we can ignore errors here.
1630 (void) mac_resource_ctl_set(dmch, MCIP_RESOURCE_PROPS(smcip));
1634 * Called when removing a secondary MAC. Currently only clears the promisc_list
1635 * since we share the primary mac's promisc_list.
1637 void
1638 mac_secondary_cleanup(mac_client_handle_t mch)
1640 mac_client_impl_t *mcip = (mac_client_impl_t *)mch;
1641 flow_entry_t *flent = mcip->mci_flent;
1643 /* This should only be called for secondary macs */
1644 ASSERT((flent->fe_type & FLOW_PRIMARY_MAC) == 0);
1645 mcip->mci_promisc_list = NULL;
1649 * Walk the MAC client subflow table and updates their priority values.
1651 static int
1652 mac_update_subflow_priority_cb(flow_entry_t *flent, void *arg)
1654 mac_flow_update_priority(arg, flent);
1655 return (0);
1658 void
1659 mac_update_subflow_priority(mac_client_impl_t *mcip)
1661 (void) mac_flow_walk(mcip->mci_subflow_tab,
1662 mac_update_subflow_priority_cb, mcip);
1666 * Modify the TX or RX ring properties. We could either just move around
1667 * rings, i.e add/remove rings given to a client. Or this might cause the
1668 * client to move from hardware based to software or the other way around.
1669 * If we want to reset this property, then we clear the mask, additionally
1670 * if the client was given a non-default group we remove all rings except
1671 * for 1 and give it back to the default group.
1674 mac_client_set_rings_prop(mac_client_impl_t *mcip, mac_resource_props_t *mrp,
1675 mac_resource_props_t *tmrp)
1677 mac_impl_t *mip = mcip->mci_mip;
1678 flow_entry_t *flent = mcip->mci_flent;
1679 uint8_t *mac_addr;
1680 int err = 0;
1681 mac_group_t *defgrp;
1682 mac_group_t *group;
1683 mac_group_t *ngrp;
1684 mac_resource_props_t *cmrp = MCIP_RESOURCE_PROPS(mcip);
1685 uint_t ringcnt;
1686 boolean_t unspec;
1688 if (mcip->mci_share != NULL)
1689 return (EINVAL);
1691 if (mrp->mrp_mask & MRP_RX_RINGS) {
1692 unspec = mrp->mrp_mask & MRP_RXRINGS_UNSPEC;
1693 group = flent->fe_rx_ring_group;
1694 defgrp = MAC_DEFAULT_RX_GROUP(mip);
1695 mac_addr = flent->fe_flow_desc.fd_dst_mac;
1698 * No resulting change. If we are resetting on a client on
1699 * which there was no rx rings property. For dynamic group
1700 * if we are setting the same number of rings already set.
1701 * For static group if we are requesting a group again.
1703 if (mrp->mrp_mask & MRP_RINGS_RESET) {
1704 if (!(tmrp->mrp_mask & MRP_RX_RINGS))
1705 return (0);
1706 } else {
1707 if (unspec) {
1708 if (tmrp->mrp_mask & MRP_RXRINGS_UNSPEC)
1709 return (0);
1710 } else if (mip->mi_rx_group_type ==
1711 MAC_GROUP_TYPE_DYNAMIC) {
1712 if ((tmrp->mrp_mask & MRP_RX_RINGS) &&
1713 !(tmrp->mrp_mask & MRP_RXRINGS_UNSPEC) &&
1714 mrp->mrp_nrxrings == tmrp->mrp_nrxrings) {
1715 return (0);
1719 /* Resetting the prop */
1720 if (mrp->mrp_mask & MRP_RINGS_RESET) {
1722 * We will just keep one ring and give others back if
1723 * we are not the primary. For the primary we give
1724 * all the rings in the default group except the
1725 * default ring. If it is a static group, then
1726 * we don't do anything, but clear the MRP_RX_RINGS
1727 * flag.
1729 if (group != defgrp) {
1730 if (mip->mi_rx_group_type ==
1731 MAC_GROUP_TYPE_DYNAMIC) {
1733 * This group has reserved rings
1734 * that need to be released now,
1735 * so does the group.
1737 MAC_RX_RING_RELEASED(mip,
1738 group->mrg_cur_count);
1739 MAC_RX_GRP_RELEASED(mip);
1740 if ((flent->fe_type &
1741 FLOW_PRIMARY_MAC) != 0) {
1742 if (mip->mi_nactiveclients ==
1743 1) {
1744 (void)
1745 mac_rx_switch_group(
1746 mcip, group,
1747 defgrp);
1748 return (0);
1749 } else {
1750 cmrp->mrp_nrxrings =
1751 group->
1752 mrg_cur_count +
1753 defgrp->
1754 mrg_cur_count - 1;
1756 } else {
1757 cmrp->mrp_nrxrings = 1;
1759 (void) mac_group_ring_modify(mcip,
1760 group, defgrp);
1761 } else {
1763 * If this is a static group, we
1764 * need to release the group. The
1765 * client will remain in the same
1766 * group till some other client
1767 * needs this group.
1769 MAC_RX_GRP_RELEASED(mip);
1771 /* Let check if we can give this an excl group */
1772 } else if (group == defgrp) {
1773 ngrp = mac_reserve_rx_group(mcip, mac_addr,
1774 B_TRUE);
1775 /* Couldn't give it a group, that's fine */
1776 if (ngrp == NULL)
1777 return (0);
1778 /* Switch to H/W */
1779 if (mac_rx_switch_group(mcip, defgrp, ngrp) !=
1780 0) {
1781 mac_stop_group(ngrp);
1782 return (0);
1786 * If the client is in the default group, we will
1787 * just clear the MRP_RX_RINGS and leave it as
1788 * it rather than look for an exclusive group
1789 * for it.
1791 return (0);
1794 if (group == defgrp && ((mrp->mrp_nrxrings > 0) || unspec)) {
1795 ngrp = mac_reserve_rx_group(mcip, mac_addr, B_TRUE);
1796 if (ngrp == NULL)
1797 return (ENOSPC);
1799 /* Switch to H/W */
1800 if (mac_rx_switch_group(mcip, defgrp, ngrp) != 0) {
1801 mac_release_rx_group(mcip, ngrp);
1802 return (ENOSPC);
1804 MAC_RX_GRP_RESERVED(mip);
1805 if (mip->mi_rx_group_type == MAC_GROUP_TYPE_DYNAMIC)
1806 MAC_RX_RING_RESERVED(mip, ngrp->mrg_cur_count);
1807 } else if (group != defgrp && !unspec &&
1808 mrp->mrp_nrxrings == 0) {
1809 /* Switch to S/W */
1810 ringcnt = group->mrg_cur_count;
1811 if (mac_rx_switch_group(mcip, group, defgrp) != 0)
1812 return (ENOSPC);
1813 if (tmrp->mrp_mask & MRP_RX_RINGS) {
1814 MAC_RX_GRP_RELEASED(mip);
1815 if (mip->mi_rx_group_type ==
1816 MAC_GROUP_TYPE_DYNAMIC) {
1817 MAC_RX_RING_RELEASED(mip, ringcnt);
1820 } else if (group != defgrp && mip->mi_rx_group_type ==
1821 MAC_GROUP_TYPE_DYNAMIC) {
1822 ringcnt = group->mrg_cur_count;
1823 err = mac_group_ring_modify(mcip, group, defgrp);
1824 if (err != 0)
1825 return (err);
1827 * Update the accounting. If this group
1828 * already had explicitly reserved rings,
1829 * we need to update the rings based on
1830 * the new ring count. If this group
1831 * had not explicitly reserved rings,
1832 * then we just reserve the rings asked for
1833 * and reserve the group.
1835 if (tmrp->mrp_mask & MRP_RX_RINGS) {
1836 if (ringcnt > group->mrg_cur_count) {
1837 MAC_RX_RING_RELEASED(mip,
1838 ringcnt - group->mrg_cur_count);
1839 } else {
1840 MAC_RX_RING_RESERVED(mip,
1841 group->mrg_cur_count - ringcnt);
1843 } else {
1844 MAC_RX_RING_RESERVED(mip, group->mrg_cur_count);
1845 MAC_RX_GRP_RESERVED(mip);
1849 if (mrp->mrp_mask & MRP_TX_RINGS) {
1850 unspec = mrp->mrp_mask & MRP_TXRINGS_UNSPEC;
1851 group = flent->fe_tx_ring_group;
1852 defgrp = MAC_DEFAULT_TX_GROUP(mip);
1855 * For static groups we only allow rings=0 or resetting the
1856 * rings property.
1858 if (mrp->mrp_ntxrings > 0 &&
1859 mip->mi_tx_group_type != MAC_GROUP_TYPE_DYNAMIC) {
1860 return (ENOTSUP);
1862 if (mrp->mrp_mask & MRP_RINGS_RESET) {
1863 if (!(tmrp->mrp_mask & MRP_TX_RINGS))
1864 return (0);
1865 } else {
1866 if (unspec) {
1867 if (tmrp->mrp_mask & MRP_TXRINGS_UNSPEC)
1868 return (0);
1869 } else if (mip->mi_tx_group_type ==
1870 MAC_GROUP_TYPE_DYNAMIC) {
1871 if ((tmrp->mrp_mask & MRP_TX_RINGS) &&
1872 !(tmrp->mrp_mask & MRP_TXRINGS_UNSPEC) &&
1873 mrp->mrp_ntxrings == tmrp->mrp_ntxrings) {
1874 return (0);
1878 /* Resetting the prop */
1879 if (mrp->mrp_mask & MRP_RINGS_RESET) {
1880 if (group != defgrp) {
1881 if (mip->mi_tx_group_type ==
1882 MAC_GROUP_TYPE_DYNAMIC) {
1883 ringcnt = group->mrg_cur_count;
1884 if ((flent->fe_type &
1885 FLOW_PRIMARY_MAC) != 0) {
1886 mac_tx_client_quiesce(
1887 (mac_client_handle_t)
1888 mcip);
1889 mac_tx_switch_group(mcip,
1890 group, defgrp);
1891 mac_tx_client_restart(
1892 (mac_client_handle_t)
1893 mcip);
1894 MAC_TX_GRP_RELEASED(mip);
1895 MAC_TX_RING_RELEASED(mip,
1896 ringcnt);
1897 return (0);
1899 cmrp->mrp_ntxrings = 1;
1900 (void) mac_group_ring_modify(mcip,
1901 group, defgrp);
1903 * This group has reserved rings
1904 * that need to be released now.
1906 MAC_TX_RING_RELEASED(mip, ringcnt);
1909 * If this is a static group, we
1910 * need to release the group. The
1911 * client will remain in the same
1912 * group till some other client
1913 * needs this group.
1915 MAC_TX_GRP_RELEASED(mip);
1916 } else if (group == defgrp &&
1917 (flent->fe_type & FLOW_PRIMARY_MAC) == 0) {
1918 ngrp = mac_reserve_tx_group(mcip, B_TRUE);
1919 if (ngrp == NULL)
1920 return (0);
1921 mac_tx_client_quiesce(
1922 (mac_client_handle_t)mcip);
1923 mac_tx_switch_group(mcip, defgrp, ngrp);
1924 mac_tx_client_restart(
1925 (mac_client_handle_t)mcip);
1928 * If the client is in the default group, we will
1929 * just clear the MRP_TX_RINGS and leave it as
1930 * it rather than look for an exclusive group
1931 * for it.
1933 return (0);
1936 /* Switch to H/W */
1937 if (group == defgrp && ((mrp->mrp_ntxrings > 0) || unspec)) {
1938 ngrp = mac_reserve_tx_group(mcip, B_TRUE);
1939 if (ngrp == NULL)
1940 return (ENOSPC);
1941 mac_tx_client_quiesce((mac_client_handle_t)mcip);
1942 mac_tx_switch_group(mcip, defgrp, ngrp);
1943 mac_tx_client_restart((mac_client_handle_t)mcip);
1944 MAC_TX_GRP_RESERVED(mip);
1945 if (mip->mi_tx_group_type == MAC_GROUP_TYPE_DYNAMIC)
1946 MAC_TX_RING_RESERVED(mip, ngrp->mrg_cur_count);
1947 /* Switch to S/W */
1948 } else if (group != defgrp && !unspec &&
1949 mrp->mrp_ntxrings == 0) {
1950 /* Switch to S/W */
1951 ringcnt = group->mrg_cur_count;
1952 mac_tx_client_quiesce((mac_client_handle_t)mcip);
1953 mac_tx_switch_group(mcip, group, defgrp);
1954 mac_tx_client_restart((mac_client_handle_t)mcip);
1955 if (tmrp->mrp_mask & MRP_TX_RINGS) {
1956 MAC_TX_GRP_RELEASED(mip);
1957 if (mip->mi_tx_group_type ==
1958 MAC_GROUP_TYPE_DYNAMIC) {
1959 MAC_TX_RING_RELEASED(mip, ringcnt);
1962 } else if (group != defgrp && mip->mi_tx_group_type ==
1963 MAC_GROUP_TYPE_DYNAMIC) {
1964 ringcnt = group->mrg_cur_count;
1965 err = mac_group_ring_modify(mcip, group, defgrp);
1966 if (err != 0)
1967 return (err);
1969 * Update the accounting. If this group
1970 * already had explicitly reserved rings,
1971 * we need to update the rings based on
1972 * the new ring count. If this group
1973 * had not explicitly reserved rings,
1974 * then we just reserve the rings asked for
1975 * and reserve the group.
1977 if (tmrp->mrp_mask & MRP_TX_RINGS) {
1978 if (ringcnt > group->mrg_cur_count) {
1979 MAC_TX_RING_RELEASED(mip,
1980 ringcnt - group->mrg_cur_count);
1981 } else {
1982 MAC_TX_RING_RESERVED(mip,
1983 group->mrg_cur_count - ringcnt);
1985 } else {
1986 MAC_TX_RING_RESERVED(mip, group->mrg_cur_count);
1987 MAC_TX_GRP_RESERVED(mip);
1991 return (0);
1995 * When the MAC client is being brought up (i.e. we do a unicast_add) we need
1996 * to initialize the cpu and resource control structure in the
1997 * mac_client_impl_t from the mac_impl_t (i.e if there are any cached
1998 * properties before the flow entry for the unicast address was created).
2000 static int
2001 mac_resource_ctl_set(mac_client_handle_t mch, mac_resource_props_t *mrp)
2003 mac_client_impl_t *mcip = (mac_client_impl_t *)mch;
2004 mac_impl_t *mip = (mac_impl_t *)mcip->mci_mip;
2005 mac_impl_t *umip = mcip->mci_upper_mip;
2006 int err = 0;
2007 flow_entry_t *flent = mcip->mci_flent;
2008 mac_resource_props_t *omrp, *nmrp = MCIP_RESOURCE_PROPS(mcip);
2010 ASSERT(MAC_PERIM_HELD((mac_handle_t)mip));
2012 err = mac_validate_props(mcip->mci_state_flags & MCIS_IS_VNIC ?
2013 mcip->mci_upper_mip : mip, mrp);
2014 if (err != 0)
2015 return (err);
2018 * Copy over the existing properties since mac_update_resources
2019 * will modify the client's mrp. Currently, the saved property
2020 * is used to determine the difference between existing and
2021 * modified rings property.
2023 omrp = kmem_zalloc(sizeof (*omrp), KM_SLEEP);
2024 bcopy(nmrp, omrp, sizeof (*omrp));
2025 mac_update_resources(mrp, MCIP_RESOURCE_PROPS(mcip), B_FALSE);
2026 if (MCIP_DATAPATH_SETUP(mcip)) {
2028 * We support rings only for primary client when there are
2029 * multiple clients sharing the same MAC address (e.g. VLAN).
2031 if (mrp->mrp_mask & MRP_RX_RINGS ||
2032 mrp->mrp_mask & MRP_TX_RINGS) {
2034 if ((err = mac_client_set_rings_prop(mcip, mrp,
2035 omrp)) != 0) {
2036 if (omrp->mrp_mask & MRP_RX_RINGS) {
2037 nmrp->mrp_mask |= MRP_RX_RINGS;
2038 nmrp->mrp_nrxrings = omrp->mrp_nrxrings;
2039 } else {
2040 nmrp->mrp_mask &= ~MRP_RX_RINGS;
2041 nmrp->mrp_nrxrings = 0;
2043 if (omrp->mrp_mask & MRP_TX_RINGS) {
2044 nmrp->mrp_mask |= MRP_TX_RINGS;
2045 nmrp->mrp_ntxrings = omrp->mrp_ntxrings;
2046 } else {
2047 nmrp->mrp_mask &= ~MRP_TX_RINGS;
2048 nmrp->mrp_ntxrings = 0;
2050 if (omrp->mrp_mask & MRP_RXRINGS_UNSPEC)
2051 omrp->mrp_mask |= MRP_RXRINGS_UNSPEC;
2052 else
2053 omrp->mrp_mask &= ~MRP_RXRINGS_UNSPEC;
2055 if (omrp->mrp_mask & MRP_TXRINGS_UNSPEC)
2056 omrp->mrp_mask |= MRP_TXRINGS_UNSPEC;
2057 else
2058 omrp->mrp_mask &= ~MRP_TXRINGS_UNSPEC;
2059 kmem_free(omrp, sizeof (*omrp));
2060 return (err);
2064 * If we modified the rings property of the primary
2065 * we need to update the property fields of its
2066 * VLANs as they inherit the primary's properites.
2068 if (mac_is_primary_client(mcip)) {
2069 mac_set_prim_vlan_rings(mip,
2070 MCIP_RESOURCE_PROPS(mcip));
2074 * We have to set this prior to calling mac_flow_modify.
2076 if (mrp->mrp_mask & MRP_PRIORITY) {
2077 if (mrp->mrp_priority == MPL_RESET) {
2078 MAC_CLIENT_SET_PRIORITY_RANGE(mcip,
2079 MPL_LINK_DEFAULT);
2080 } else {
2081 MAC_CLIENT_SET_PRIORITY_RANGE(mcip,
2082 mrp->mrp_priority);
2086 mac_flow_modify(mip->mi_flow_tab, flent, mrp);
2087 if (mrp->mrp_mask & MRP_PRIORITY)
2088 mac_update_subflow_priority(mcip);
2090 /* Apply these resource settings to any secondary macs */
2091 if (umip != NULL) {
2092 ASSERT((umip->mi_state_flags & MIS_IS_VNIC) != 0);
2093 mac_vnic_secondary_update(umip);
2096 kmem_free(omrp, sizeof (*omrp));
2097 return (0);
2100 static int
2101 mac_unicast_flow_create(mac_client_impl_t *mcip, uint8_t *mac_addr,
2102 uint16_t vid, boolean_t is_primary, boolean_t first_flow,
2103 flow_entry_t **flent, mac_resource_props_t *mrp)
2105 mac_impl_t *mip = (mac_impl_t *)mcip->mci_mip;
2106 flow_desc_t flow_desc;
2107 char flowname[MAXFLOWNAMELEN];
2108 int err;
2109 uint_t flent_flags;
2112 * First unicast address being added, create a new flow
2113 * for that MAC client.
2115 bzero(&flow_desc, sizeof (flow_desc));
2117 ASSERT(mac_addr != NULL ||
2118 (mcip->mci_state_flags & MCIS_NO_UNICAST_ADDR));
2119 if (mac_addr != NULL) {
2120 flow_desc.fd_mac_len = mip->mi_type->mt_addr_length;
2121 bcopy(mac_addr, flow_desc.fd_dst_mac, flow_desc.fd_mac_len);
2123 flow_desc.fd_mask = FLOW_LINK_DST;
2124 if (vid != 0) {
2125 flow_desc.fd_vid = vid;
2126 flow_desc.fd_mask |= FLOW_LINK_VID;
2130 * XXX-nicolas. For now I'm keeping the FLOW_PRIMARY_MAC
2131 * and FLOW_VNIC. Even though they're a hack inherited
2132 * from the SRS code, we'll keep them for now. They're currently
2133 * consumed by mac_datapath_setup() to create the SRS.
2134 * That code should be eventually moved out of
2135 * mac_datapath_setup() and moved to a mac_srs_create()
2136 * function of some sort to keep things clean.
2138 * Also, there's no reason why the SRS for the primary MAC
2139 * client should be different than any other MAC client. Until
2140 * this is cleaned-up, we support only one MAC unicast address
2141 * per client.
2143 * We set FLOW_PRIMARY_MAC for the primary MAC address,
2144 * FLOW_VNIC for everything else.
2146 if (is_primary)
2147 flent_flags = FLOW_PRIMARY_MAC;
2148 else
2149 flent_flags = FLOW_VNIC_MAC;
2152 * For the first flow we use the mac client's name - mci_name, for
2153 * subsequent ones we just create a name with the vid. This is
2154 * so that we can add these flows to the same flow table. This is
2155 * fine as the flow name (except for the one with the mac client's
2156 * name) is not visible. When the first flow is removed, we just replace
2157 * its fdesc with another from the list, so we will still retain the
2158 * flent with the MAC client's flow name.
2160 if (first_flow) {
2161 bcopy(mcip->mci_name, flowname, MAXFLOWNAMELEN);
2162 } else {
2163 (void) sprintf(flowname, "%s%u", mcip->mci_name, vid);
2164 flent_flags = FLOW_NO_STATS;
2167 if ((err = mac_flow_create(&flow_desc, mrp, flowname, NULL,
2168 flent_flags, flent)) != 0)
2169 return (err);
2171 mac_misc_stat_create(*flent);
2172 FLOW_MARK(*flent, FE_INCIPIENT);
2173 (*flent)->fe_mcip = mcip;
2176 * Place initial creation reference on the flow. This reference
2177 * is released in the corresponding delete action viz.
2178 * mac_unicast_remove after waiting for all transient refs to
2179 * to go away. The wait happens in mac_flow_wait.
2180 * We have already held the reference in mac_client_open().
2182 if (!first_flow)
2183 FLOW_REFHOLD(*flent);
2184 return (0);
2187 /* Refresh the multicast grouping for this VID. */
2189 mac_client_update_mcast(void *arg, boolean_t add, const uint8_t *addrp)
2191 flow_entry_t *flent = arg;
2192 mac_client_impl_t *mcip = flent->fe_mcip;
2193 uint16_t vid;
2194 flow_desc_t flow_desc;
2196 mac_flow_get_desc(flent, &flow_desc);
2197 vid = (flow_desc.fd_mask & FLOW_LINK_VID) != 0 ?
2198 flow_desc.fd_vid : VLAN_ID_NONE;
2201 * We don't call mac_multicast_add()/mac_multicast_remove() as
2202 * we want to add/remove for this specific vid.
2204 if (add) {
2205 return (mac_bcast_add(mcip, addrp, vid,
2206 MAC_ADDRTYPE_MULTICAST));
2207 } else {
2208 mac_bcast_delete(mcip, addrp, vid);
2209 return (0);
2213 static void
2214 mac_update_single_active_client(mac_impl_t *mip)
2216 mac_client_impl_t *client = NULL;
2218 ASSERT(MAC_PERIM_HELD((mac_handle_t)mip));
2220 rw_enter(&mip->mi_rw_lock, RW_WRITER);
2221 if (mip->mi_nactiveclients == 1) {
2223 * Find the one active MAC client from the list of MAC
2224 * clients. The active MAC client has at least one
2225 * unicast address.
2227 for (client = mip->mi_clients_list; client != NULL;
2228 client = client->mci_client_next) {
2229 if (client->mci_unicast_list != NULL)
2230 break;
2232 ASSERT(client != NULL);
2236 * mi_single_active_client is protected by the MAC impl's read/writer
2237 * lock, which allows mac_rx() to check the value of that pointer
2238 * as a reader.
2240 mip->mi_single_active_client = client;
2241 rw_exit(&mip->mi_rw_lock);
2245 * Set up the data path. Called from i_mac_unicast_add after having
2246 * done all the validations including making sure this is an active
2247 * client (i.e that is ready to process packets.)
2249 static int
2250 mac_client_datapath_setup(mac_client_impl_t *mcip, uint16_t vid,
2251 uint8_t *mac_addr, mac_resource_props_t *mrp, boolean_t isprimary,
2252 mac_unicast_impl_t *muip)
2254 mac_impl_t *mip = mcip->mci_mip;
2255 boolean_t mac_started = B_FALSE;
2256 boolean_t bcast_added = B_FALSE;
2257 boolean_t nactiveclients_added = B_FALSE;
2258 flow_entry_t *flent;
2259 int err = 0;
2260 boolean_t no_unicast;
2262 no_unicast = mcip->mci_state_flags & MCIS_NO_UNICAST_ADDR;
2264 if ((err = mac_start((mac_handle_t)mip)) != 0)
2265 goto bail;
2267 mac_started = B_TRUE;
2269 /* add the MAC client to the broadcast address group by default */
2270 if (mip->mi_type->mt_brdcst_addr != NULL) {
2271 err = mac_bcast_add(mcip, mip->mi_type->mt_brdcst_addr, vid,
2272 MAC_ADDRTYPE_BROADCAST);
2273 if (err != 0)
2274 goto bail;
2275 bcast_added = B_TRUE;
2279 * If this is the first unicast address addition for this
2280 * client, reuse the pre-allocated larval flow entry associated with
2281 * the MAC client.
2283 flent = (mcip->mci_nflents == 0) ? mcip->mci_flent : NULL;
2285 /* We are configuring the unicast flow now */
2286 if (!MCIP_DATAPATH_SETUP(mcip)) {
2288 if (mrp != NULL) {
2289 MAC_CLIENT_SET_PRIORITY_RANGE(mcip,
2290 (mrp->mrp_mask & MRP_PRIORITY) ? mrp->mrp_priority :
2291 MPL_LINK_DEFAULT);
2293 if ((err = mac_unicast_flow_create(mcip, mac_addr, vid,
2294 isprimary, B_TRUE, &flent, mrp)) != 0)
2295 goto bail;
2297 mip->mi_nactiveclients++;
2298 nactiveclients_added = B_TRUE;
2301 * This will allocate the RX ring group if possible for the
2302 * flow and program the software classifier as needed.
2304 if ((err = mac_datapath_setup(mcip, flent, SRST_LINK)) != 0)
2305 goto bail;
2307 if (no_unicast)
2308 goto done_setup;
2310 * The unicast MAC address must have been added successfully.
2312 ASSERT(mcip->mci_unicast != NULL);
2314 * Push down the sub-flows that were defined on this link
2315 * hitherto. The flows are added to the active flow table
2316 * and SRS, softrings etc. are created as needed.
2318 mac_link_init_flows((mac_client_handle_t)mcip);
2319 } else {
2320 mac_address_t *map = mcip->mci_unicast;
2322 ASSERT(!no_unicast);
2324 * A unicast flow already exists for that MAC client,
2325 * this flow must be the same mac address but with
2326 * different VID. It has been checked by mac_addr_in_use().
2328 * We will use the SRS etc. from the mci_flent. Note that
2329 * We don't need to create kstat for this as except for
2330 * the fdesc, everything will be used from in the 1st flent.
2333 if (bcmp(mac_addr, map->ma_addr, map->ma_len) != 0) {
2334 err = EINVAL;
2335 goto bail;
2338 if ((err = mac_unicast_flow_create(mcip, mac_addr, vid,
2339 isprimary, B_FALSE, &flent, NULL)) != 0) {
2340 goto bail;
2342 if ((err = mac_flow_add(mip->mi_flow_tab, flent)) != 0) {
2343 FLOW_FINAL_REFRELE(flent);
2344 goto bail;
2347 /* update the multicast group for this vid */
2348 mac_client_bcast_refresh(mcip, mac_client_update_mcast,
2349 (void *)flent, B_TRUE);
2353 /* populate the shared MAC address */
2354 muip->mui_map = mcip->mci_unicast;
2356 rw_enter(&mcip->mci_rw_lock, RW_WRITER);
2357 muip->mui_next = mcip->mci_unicast_list;
2358 mcip->mci_unicast_list = muip;
2359 rw_exit(&mcip->mci_rw_lock);
2361 done_setup:
2363 * First add the flent to the flow list of this mcip. Then set
2364 * the mip's mi_single_active_client if needed. The Rx path assumes
2365 * that mip->mi_single_active_client will always have an associated
2366 * flent.
2368 mac_client_add_to_flow_list(mcip, flent);
2369 if (nactiveclients_added)
2370 mac_update_single_active_client(mip);
2372 * Trigger a renegotiation of the capabilities when the number of
2373 * active clients changes from 1 to 2, since some of the capabilities
2374 * might have to be disabled. Also send a MAC_NOTE_LINK notification
2375 * to all the MAC clients whenever physical link is DOWN.
2377 if (mip->mi_nactiveclients == 2) {
2378 mac_capab_update((mac_handle_t)mip);
2379 mac_virtual_link_update(mip);
2382 * Now that the setup is complete, clear the INCIPIENT flag.
2383 * The flag was set to avoid incoming packets seeing inconsistent
2384 * structures while the setup was in progress. Clear the mci_tx_flag
2385 * by calling mac_tx_client_block. It is possible that
2386 * mac_unicast_remove was called prior to this mac_unicast_add which
2387 * could have set the MCI_TX_QUIESCE flag.
2389 if (flent->fe_rx_ring_group != NULL)
2390 mac_rx_group_unmark(flent->fe_rx_ring_group, MR_INCIPIENT);
2391 FLOW_UNMARK(flent, FE_INCIPIENT);
2392 FLOW_UNMARK(flent, FE_MC_NO_DATAPATH);
2393 mac_tx_client_unblock(mcip);
2394 return (0);
2395 bail:
2396 if (bcast_added)
2397 mac_bcast_delete(mcip, mip->mi_type->mt_brdcst_addr, vid);
2399 if (nactiveclients_added)
2400 mip->mi_nactiveclients--;
2402 if (mac_started)
2403 mac_stop((mac_handle_t)mip);
2405 return (err);
2409 * Return the passive primary MAC client, if present. The passive client is
2410 * a stand-by client that has the same unicast address as another that is
2411 * currenly active. Once the active client goes away, the passive client
2412 * becomes active.
2414 static mac_client_impl_t *
2415 mac_get_passive_primary_client(mac_impl_t *mip)
2417 mac_client_impl_t *mcip;
2419 for (mcip = mip->mi_clients_list; mcip != NULL;
2420 mcip = mcip->mci_client_next) {
2421 if (mac_is_primary_client(mcip) &&
2422 (mcip->mci_flags & MAC_CLIENT_FLAGS_PASSIVE_PRIMARY) != 0) {
2423 return (mcip);
2426 return (NULL);
2430 * Add a new unicast address to the MAC client.
2432 * The MAC address can be specified either by value, or the MAC client
2433 * can specify that it wants to use the primary MAC address of the
2434 * underlying MAC. See the introductory comments at the beginning
2435 * of this file for more more information on primary MAC addresses.
2437 * Note also the tuple (MAC address, VID) must be unique
2438 * for the MAC clients defined on top of the same underlying MAC
2439 * instance, unless the MAC_UNICAST_NODUPCHECK is specified.
2441 * In no case can a client use the PVID for the MAC, if the MAC has one set.
2444 i_mac_unicast_add(mac_client_handle_t mch, uint8_t *mac_addr, uint16_t flags,
2445 mac_unicast_handle_t *mah, uint16_t vid, mac_diag_t *diag)
2447 mac_client_impl_t *mcip = (mac_client_impl_t *)mch;
2448 mac_impl_t *mip = mcip->mci_mip;
2449 int err;
2450 uint_t mac_len = mip->mi_type->mt_addr_length;
2451 boolean_t check_dups = !(flags & MAC_UNICAST_NODUPCHECK);
2452 boolean_t fastpath_disabled = B_FALSE;
2453 boolean_t is_primary = (flags & MAC_UNICAST_PRIMARY);
2454 boolean_t is_unicast_hw = (flags & MAC_UNICAST_HW);
2455 mac_resource_props_t *mrp;
2456 boolean_t passive_client = B_FALSE;
2457 mac_unicast_impl_t *muip;
2458 boolean_t is_vnic_primary =
2459 (flags & MAC_UNICAST_VNIC_PRIMARY);
2461 /* when VID is non-zero, the underlying MAC can not be VNIC */
2462 ASSERT(!((mip->mi_state_flags & MIS_IS_VNIC) && (vid != 0)));
2465 * Can't unicast add if the client asked only for minimal datapath
2466 * setup.
2468 if (mcip->mci_state_flags & MCIS_NO_UNICAST_ADDR)
2469 return (ENOTSUP);
2472 * Check for an attempted use of the current Port VLAN ID, if enabled.
2473 * No client may use it.
2475 if (mip->mi_pvid != 0 && vid == mip->mi_pvid)
2476 return (EBUSY);
2479 * Check whether it's the primary client and flag it.
2481 if (!(mcip->mci_state_flags & MCIS_IS_VNIC) && is_primary && vid == 0)
2482 mcip->mci_flags |= MAC_CLIENT_FLAGS_PRIMARY;
2485 * is_vnic_primary is true when we come here as a VLAN VNIC
2486 * which uses the primary mac client's address but with a non-zero
2487 * VID. In this case the MAC address is not specified by an upper
2488 * MAC client.
2490 if ((mcip->mci_state_flags & MCIS_IS_VNIC) && is_primary &&
2491 !is_vnic_primary) {
2493 * The address is being set by the upper MAC client
2494 * of a VNIC. The MAC address was already set by the
2495 * VNIC driver during VNIC creation.
2497 * Note: a VNIC has only one MAC address. We return
2498 * the MAC unicast address handle of the lower MAC client
2499 * corresponding to the VNIC. We allocate a new entry
2500 * which is flagged appropriately, so that mac_unicast_remove()
2501 * doesn't attempt to free the original entry that
2502 * was allocated by the VNIC driver.
2504 ASSERT(mcip->mci_unicast != NULL);
2506 /* Check for VLAN flags, if present */
2507 if ((flags & MAC_UNICAST_TAG_DISABLE) != 0)
2508 mcip->mci_state_flags |= MCIS_TAG_DISABLE;
2510 if ((flags & MAC_UNICAST_STRIP_DISABLE) != 0)
2511 mcip->mci_state_flags |= MCIS_STRIP_DISABLE;
2513 if ((flags & MAC_UNICAST_DISABLE_TX_VID_CHECK) != 0)
2514 mcip->mci_state_flags |= MCIS_DISABLE_TX_VID_CHECK;
2517 * Ensure that the primary unicast address of the VNIC
2518 * is added only once unless we have the
2519 * MAC_CLIENT_FLAGS_MULTI_PRIMARY set (and this is not
2520 * a passive MAC client).
2522 if ((mcip->mci_flags & MAC_CLIENT_FLAGS_VNIC_PRIMARY) != 0) {
2523 if ((mcip->mci_flags &
2524 MAC_CLIENT_FLAGS_MULTI_PRIMARY) == 0 ||
2525 (mcip->mci_flags &
2526 MAC_CLIENT_FLAGS_PASSIVE_PRIMARY) != 0) {
2527 return (EBUSY);
2529 mcip->mci_flags |= MAC_CLIENT_FLAGS_PASSIVE_PRIMARY;
2530 passive_client = B_TRUE;
2533 mcip->mci_flags |= MAC_CLIENT_FLAGS_VNIC_PRIMARY;
2536 * Create a handle for vid 0.
2538 ASSERT(vid == 0);
2539 muip = kmem_zalloc(sizeof (mac_unicast_impl_t), KM_SLEEP);
2540 muip->mui_vid = vid;
2541 *mah = (mac_unicast_handle_t)muip;
2543 * This will be used by the caller to defer setting the
2544 * rx functions.
2546 if (passive_client)
2547 return (EAGAIN);
2548 return (0);
2551 /* primary MAC clients cannot be opened on top of anchor VNICs */
2552 if ((is_vnic_primary || is_primary) &&
2553 i_mac_capab_get((mac_handle_t)mip, MAC_CAPAB_ANCHOR_VNIC, NULL)) {
2554 return (ENXIO);
2558 * If this is a VNIC/VLAN, disable softmac fast-path.
2560 if (mcip->mci_state_flags & MCIS_IS_VNIC) {
2561 err = mac_fastpath_disable((mac_handle_t)mip);
2562 if (err != 0)
2563 return (err);
2564 fastpath_disabled = B_TRUE;
2568 * Return EBUSY if:
2569 * - there is an exclusively active mac client exists.
2570 * - this is an exclusive active mac client but
2571 * a. there is already active mac clients exist, or
2572 * b. fastpath streams are already plumbed on this legacy device
2573 * - the mac creator has disallowed active mac clients.
2575 if (mip->mi_state_flags & (MIS_EXCLUSIVE|MIS_NO_ACTIVE)) {
2576 if (fastpath_disabled)
2577 mac_fastpath_enable((mac_handle_t)mip);
2578 return (EBUSY);
2581 if (mcip->mci_state_flags & MCIS_EXCLUSIVE) {
2582 ASSERT(!fastpath_disabled);
2583 if (mip->mi_nactiveclients != 0)
2584 return (EBUSY);
2586 if ((mip->mi_state_flags & MIS_LEGACY) &&
2587 !(mip->mi_capab_legacy.ml_active_set(mip->mi_driver))) {
2588 return (EBUSY);
2590 mip->mi_state_flags |= MIS_EXCLUSIVE;
2593 mrp = kmem_zalloc(sizeof (*mrp), KM_SLEEP);
2594 if (is_primary && !(mcip->mci_state_flags & (MCIS_IS_VNIC |
2595 MCIS_IS_AGGR_PORT))) {
2597 * Apply the property cached in the mac_impl_t to the primary
2598 * mac client. If the mac client is a VNIC or an aggregation
2599 * port, its property should be set in the mcip when the
2600 * VNIC/aggr was created.
2602 mac_get_resources((mac_handle_t)mip, mrp);
2603 (void) mac_client_set_resources(mch, mrp);
2604 } else if (mcip->mci_state_flags & MCIS_IS_VNIC) {
2606 * This is a primary VLAN client, we don't support
2607 * specifying rings property for this as it inherits the
2608 * rings property from its MAC.
2610 if (is_vnic_primary) {
2611 mac_resource_props_t *vmrp;
2613 vmrp = MCIP_RESOURCE_PROPS(mcip);
2614 if (vmrp->mrp_mask & MRP_RX_RINGS ||
2615 vmrp->mrp_mask & MRP_TX_RINGS) {
2616 if (fastpath_disabled)
2617 mac_fastpath_enable((mac_handle_t)mip);
2618 kmem_free(mrp, sizeof (*mrp));
2619 return (ENOTSUP);
2622 * Additionally we also need to inherit any
2623 * rings property from the MAC.
2625 mac_get_resources((mac_handle_t)mip, mrp);
2626 if (mrp->mrp_mask & MRP_RX_RINGS) {
2627 vmrp->mrp_mask |= MRP_RX_RINGS;
2628 vmrp->mrp_nrxrings = mrp->mrp_nrxrings;
2630 if (mrp->mrp_mask & MRP_TX_RINGS) {
2631 vmrp->mrp_mask |= MRP_TX_RINGS;
2632 vmrp->mrp_ntxrings = mrp->mrp_ntxrings;
2635 bcopy(MCIP_RESOURCE_PROPS(mcip), mrp, sizeof (*mrp));
2638 muip = kmem_zalloc(sizeof (mac_unicast_impl_t), KM_SLEEP);
2639 muip->mui_vid = vid;
2641 if (is_primary || is_vnic_primary) {
2642 mac_addr = mip->mi_addr;
2643 } else {
2646 * Verify the validity of the specified MAC addresses value.
2648 if (!mac_unicst_verify((mac_handle_t)mip, mac_addr, mac_len)) {
2649 *diag = MAC_DIAG_MACADDR_INVALID;
2650 err = EINVAL;
2651 goto bail_out;
2655 * Make sure that the specified MAC address is different
2656 * than the unicast MAC address of the underlying NIC.
2658 if (check_dups && bcmp(mip->mi_addr, mac_addr, mac_len) == 0) {
2659 *diag = MAC_DIAG_MACADDR_NIC;
2660 err = EINVAL;
2661 goto bail_out;
2666 * Set the flags here so that if this is a passive client, we
2667 * can return and set it when we call mac_client_datapath_setup
2668 * when this becomes the active client. If we defer to using these
2669 * flags to mac_client_datapath_setup, then for a passive client,
2670 * we'd have to store the flags somewhere (probably fe_flags)
2671 * and then use it.
2673 if (!MCIP_DATAPATH_SETUP(mcip)) {
2674 if (is_unicast_hw) {
2676 * The client requires a hardware MAC address slot
2677 * for that unicast address. Since we support only
2678 * one unicast MAC address per client, flag the
2679 * MAC client itself.
2681 mcip->mci_state_flags |= MCIS_UNICAST_HW;
2684 /* Check for VLAN flags, if present */
2685 if ((flags & MAC_UNICAST_TAG_DISABLE) != 0)
2686 mcip->mci_state_flags |= MCIS_TAG_DISABLE;
2688 if ((flags & MAC_UNICAST_STRIP_DISABLE) != 0)
2689 mcip->mci_state_flags |= MCIS_STRIP_DISABLE;
2691 if ((flags & MAC_UNICAST_DISABLE_TX_VID_CHECK) != 0)
2692 mcip->mci_state_flags |= MCIS_DISABLE_TX_VID_CHECK;
2693 } else {
2695 * Assert that the specified flags are consistent with the
2696 * flags specified by previous calls to mac_unicast_add().
2698 ASSERT(((flags & MAC_UNICAST_TAG_DISABLE) != 0 &&
2699 (mcip->mci_state_flags & MCIS_TAG_DISABLE) != 0) ||
2700 ((flags & MAC_UNICAST_TAG_DISABLE) == 0 &&
2701 (mcip->mci_state_flags & MCIS_TAG_DISABLE) == 0));
2703 ASSERT(((flags & MAC_UNICAST_STRIP_DISABLE) != 0 &&
2704 (mcip->mci_state_flags & MCIS_STRIP_DISABLE) != 0) ||
2705 ((flags & MAC_UNICAST_STRIP_DISABLE) == 0 &&
2706 (mcip->mci_state_flags & MCIS_STRIP_DISABLE) == 0));
2708 ASSERT(((flags & MAC_UNICAST_DISABLE_TX_VID_CHECK) != 0 &&
2709 (mcip->mci_state_flags & MCIS_DISABLE_TX_VID_CHECK) != 0) ||
2710 ((flags & MAC_UNICAST_DISABLE_TX_VID_CHECK) == 0 &&
2711 (mcip->mci_state_flags & MCIS_DISABLE_TX_VID_CHECK) == 0));
2714 * Make sure the client is consistent about its requests
2715 * for MAC addresses. I.e. all requests from the clients
2716 * must have the MAC_UNICAST_HW flag set or clear.
2718 if ((mcip->mci_state_flags & MCIS_UNICAST_HW) != 0 &&
2719 !is_unicast_hw ||
2720 (mcip->mci_state_flags & MCIS_UNICAST_HW) == 0 &&
2721 is_unicast_hw) {
2722 err = EINVAL;
2723 goto bail_out;
2727 * Make sure the MAC address is not already used by
2728 * another MAC client defined on top of the same
2729 * underlying NIC. Unless we have MAC_CLIENT_FLAGS_MULTI_PRIMARY
2730 * set when we allow a passive client to be present which will
2731 * be activated when the currently active client goes away - this
2732 * works only with primary addresses.
2734 if ((check_dups || is_primary || is_vnic_primary) &&
2735 mac_addr_in_use(mip, mac_addr, vid)) {
2737 * Must have set the multiple primary address flag when
2738 * we did a mac_client_open AND this should be a primary
2739 * MAC client AND there should not already be a passive
2740 * primary. If all is true then we let this succeed
2741 * even if the address is a dup.
2743 if ((mcip->mci_flags & MAC_CLIENT_FLAGS_MULTI_PRIMARY) == 0 ||
2744 (mcip->mci_flags & MAC_CLIENT_FLAGS_PRIMARY) == 0 ||
2745 mac_get_passive_primary_client(mip) != NULL) {
2746 *diag = MAC_DIAG_MACADDR_INUSE;
2747 err = EEXIST;
2748 goto bail_out;
2750 ASSERT((mcip->mci_flags &
2751 MAC_CLIENT_FLAGS_PASSIVE_PRIMARY) == 0);
2752 mcip->mci_flags |= MAC_CLIENT_FLAGS_PASSIVE_PRIMARY;
2753 kmem_free(mrp, sizeof (*mrp));
2756 * Stash the unicast address handle, we will use it when
2757 * we set up the passive client.
2759 mcip->mci_p_unicast_list = muip;
2760 *mah = (mac_unicast_handle_t)muip;
2761 return (0);
2764 err = mac_client_datapath_setup(mcip, vid, mac_addr, mrp,
2765 is_primary || is_vnic_primary, muip);
2766 if (err != 0)
2767 goto bail_out;
2769 kmem_free(mrp, sizeof (*mrp));
2770 *mah = (mac_unicast_handle_t)muip;
2771 return (0);
2773 bail_out:
2774 if (fastpath_disabled)
2775 mac_fastpath_enable((mac_handle_t)mip);
2776 if (mcip->mci_state_flags & MCIS_EXCLUSIVE) {
2777 mip->mi_state_flags &= ~MIS_EXCLUSIVE;
2778 if (mip->mi_state_flags & MIS_LEGACY) {
2779 mip->mi_capab_legacy.ml_active_clear(
2780 mip->mi_driver);
2783 kmem_free(mrp, sizeof (*mrp));
2784 kmem_free(muip, sizeof (mac_unicast_impl_t));
2785 return (err);
2789 * Wrapper function to mac_unicast_add when we want to have the same mac
2790 * client open for two instances, one that is currently active and another
2791 * that will become active when the current one is removed. In this case
2792 * mac_unicast_add will return EGAIN and we will save the rx function and
2793 * arg which will be used when we activate the passive client in
2794 * mac_unicast_remove.
2797 mac_unicast_add_set_rx(mac_client_handle_t mch, uint8_t *mac_addr,
2798 uint16_t flags, mac_unicast_handle_t *mah, uint16_t vid, mac_diag_t *diag,
2799 mac_rx_t rx_fn, void *arg)
2801 mac_client_impl_t *mcip = (mac_client_impl_t *)mch;
2802 uint_t err;
2804 err = mac_unicast_add(mch, mac_addr, flags, mah, vid, diag);
2805 if (err != 0 && err != EAGAIN)
2806 return (err);
2807 if (err == EAGAIN) {
2808 if (rx_fn != NULL) {
2809 mcip->mci_rx_p_fn = rx_fn;
2810 mcip->mci_rx_p_arg = arg;
2812 return (0);
2814 if (rx_fn != NULL)
2815 mac_rx_set(mch, rx_fn, arg);
2816 return (err);
2820 mac_unicast_add(mac_client_handle_t mch, uint8_t *mac_addr, uint16_t flags,
2821 mac_unicast_handle_t *mah, uint16_t vid, mac_diag_t *diag)
2823 mac_impl_t *mip = ((mac_client_impl_t *)mch)->mci_mip;
2824 uint_t err;
2826 i_mac_perim_enter(mip);
2827 err = i_mac_unicast_add(mch, mac_addr, flags, mah, vid, diag);
2828 i_mac_perim_exit(mip);
2830 return (err);
2833 static void
2834 mac_client_datapath_teardown(mac_client_handle_t mch, mac_unicast_impl_t *muip,
2835 flow_entry_t *flent)
2837 mac_client_impl_t *mcip = (mac_client_impl_t *)mch;
2838 mac_impl_t *mip = mcip->mci_mip;
2839 boolean_t no_unicast;
2842 * If we have not added a unicast address for this MAC client, just
2843 * teardown the datapath.
2845 no_unicast = mcip->mci_state_flags & MCIS_NO_UNICAST_ADDR;
2847 if (!no_unicast) {
2849 * We would have initialized subflows etc. only if we brought
2850 * up the primary client and set the unicast unicast address
2851 * etc. Deactivate the flows. The flow entry will be removed
2852 * from the active flow tables, and the associated SRS,
2853 * softrings etc will be deleted. But the flow entry itself
2854 * won't be destroyed, instead it will continue to be archived
2855 * off the the global flow hash list, for a possible future
2856 * activation when say IP is plumbed again.
2858 mac_link_release_flows(mch);
2860 mip->mi_nactiveclients--;
2861 mac_update_single_active_client(mip);
2863 /* Tear down the data path */
2864 mac_datapath_teardown(mcip, mcip->mci_flent, SRST_LINK);
2867 * Prevent any future access to the flow entry through the mci_flent
2868 * pointer by setting the mci_flent to NULL. Access to mci_flent in
2869 * mac_bcast_send is also under mi_rw_lock.
2871 rw_enter(&mip->mi_rw_lock, RW_WRITER);
2872 flent = mcip->mci_flent;
2873 mac_client_remove_flow_from_list(mcip, flent);
2875 if (mcip->mci_state_flags & MCIS_DESC_LOGGED)
2876 mcip->mci_state_flags &= ~MCIS_DESC_LOGGED;
2879 * This is the last unicast address being removed and there shouldn't
2880 * be any outbound data threads at this point coming down from mac
2881 * clients. We have waited for the data threads to finish before
2882 * starting dld_str_detach. Non-data threads must access TX SRS
2883 * under mi_rw_lock.
2885 rw_exit(&mip->mi_rw_lock);
2888 * Don't use FLOW_MARK with FE_MC_NO_DATAPATH, as the flow might
2889 * contain other flags, such as FE_CONDEMNED, which we need to
2890 * cleared. We don't call mac_flow_cleanup() for this unicast
2891 * flow as we have a already cleaned up SRSs etc. (via the teadown
2892 * path). We just clear the stats and reset the initial callback
2893 * function, the rest will be set when we call mac_flow_create,
2894 * if at all.
2896 mutex_enter(&flent->fe_lock);
2897 ASSERT(flent->fe_refcnt == 1 && flent->fe_mbg == NULL &&
2898 flent->fe_tx_srs == NULL && flent->fe_rx_srs_cnt == 0);
2899 flent->fe_flags = FE_MC_NO_DATAPATH;
2900 flow_stat_destroy(flent);
2901 mac_misc_stat_delete(flent);
2903 /* Initialize the receiver function to a safe routine */
2904 flent->fe_cb_fn = (flow_fn_t)mac_pkt_drop;
2905 flent->fe_cb_arg1 = NULL;
2906 flent->fe_cb_arg2 = NULL;
2908 flent->fe_index = -1;
2909 mutex_exit(&flent->fe_lock);
2911 if (mip->mi_type->mt_brdcst_addr != NULL) {
2912 ASSERT(muip != NULL || no_unicast);
2913 mac_bcast_delete(mcip, mip->mi_type->mt_brdcst_addr,
2914 muip != NULL ? muip->mui_vid : VLAN_ID_NONE);
2917 if (mip->mi_nactiveclients == 1) {
2918 mac_capab_update((mac_handle_t)mip);
2919 mac_virtual_link_update(mip);
2922 if (mcip->mci_state_flags & MCIS_EXCLUSIVE) {
2923 mip->mi_state_flags &= ~MIS_EXCLUSIVE;
2925 if (mip->mi_state_flags & MIS_LEGACY)
2926 mip->mi_capab_legacy.ml_active_clear(mip->mi_driver);
2929 mcip->mci_state_flags &= ~MCIS_UNICAST_HW;
2931 if (mcip->mci_state_flags & MCIS_TAG_DISABLE)
2932 mcip->mci_state_flags &= ~MCIS_TAG_DISABLE;
2934 if (mcip->mci_state_flags & MCIS_STRIP_DISABLE)
2935 mcip->mci_state_flags &= ~MCIS_STRIP_DISABLE;
2937 if (mcip->mci_state_flags & MCIS_DISABLE_TX_VID_CHECK)
2938 mcip->mci_state_flags &= ~MCIS_DISABLE_TX_VID_CHECK;
2940 if (muip != NULL)
2941 kmem_free(muip, sizeof (mac_unicast_impl_t));
2942 mac_protect_cancel_timer(mcip);
2943 mac_protect_flush_dhcp(mcip);
2945 bzero(&mcip->mci_misc_stat, sizeof (mcip->mci_misc_stat));
2947 * Disable fastpath if this is a VNIC or a VLAN.
2949 if (mcip->mci_state_flags & MCIS_IS_VNIC)
2950 mac_fastpath_enable((mac_handle_t)mip);
2951 mac_stop((mac_handle_t)mip);
2955 * Remove a MAC address which was previously added by mac_unicast_add().
2958 mac_unicast_remove(mac_client_handle_t mch, mac_unicast_handle_t mah)
2960 mac_client_impl_t *mcip = (mac_client_impl_t *)mch;
2961 mac_unicast_impl_t *muip = (mac_unicast_impl_t *)mah;
2962 mac_unicast_impl_t *pre;
2963 mac_impl_t *mip = mcip->mci_mip;
2964 flow_entry_t *flent;
2965 uint16_t mui_vid;
2967 i_mac_perim_enter(mip);
2968 if (mcip->mci_flags & MAC_CLIENT_FLAGS_VNIC_PRIMARY) {
2970 * Called made by the upper MAC client of a VNIC.
2971 * There's nothing much to do, the unicast address will
2972 * be removed by the VNIC driver when the VNIC is deleted,
2973 * but let's ensure that all our transmit is done before
2974 * the client does a mac_client_stop lest it trigger an
2975 * assert in the driver.
2977 ASSERT(muip->mui_vid == 0);
2979 mac_tx_client_flush(mcip);
2981 if ((mcip->mci_flags & MAC_CLIENT_FLAGS_PASSIVE_PRIMARY) != 0) {
2982 mcip->mci_flags &= ~MAC_CLIENT_FLAGS_PASSIVE_PRIMARY;
2983 if (mcip->mci_rx_p_fn != NULL) {
2984 mac_rx_set(mch, mcip->mci_rx_p_fn,
2985 mcip->mci_rx_p_arg);
2986 mcip->mci_rx_p_fn = NULL;
2987 mcip->mci_rx_p_arg = NULL;
2989 kmem_free(muip, sizeof (mac_unicast_impl_t));
2990 i_mac_perim_exit(mip);
2991 return (0);
2993 mcip->mci_flags &= ~MAC_CLIENT_FLAGS_VNIC_PRIMARY;
2995 if (mcip->mci_state_flags & MCIS_TAG_DISABLE)
2996 mcip->mci_state_flags &= ~MCIS_TAG_DISABLE;
2998 if (mcip->mci_state_flags & MCIS_STRIP_DISABLE)
2999 mcip->mci_state_flags &= ~MCIS_STRIP_DISABLE;
3001 if (mcip->mci_state_flags & MCIS_DISABLE_TX_VID_CHECK)
3002 mcip->mci_state_flags &= ~MCIS_DISABLE_TX_VID_CHECK;
3004 kmem_free(muip, sizeof (mac_unicast_impl_t));
3005 i_mac_perim_exit(mip);
3006 return (0);
3009 ASSERT(muip != NULL);
3012 * We are removing a passive client, we haven't setup the datapath
3013 * for this yet, so nothing much to do.
3015 if ((mcip->mci_flags & MAC_CLIENT_FLAGS_PASSIVE_PRIMARY) != 0) {
3017 ASSERT((mcip->mci_flent->fe_flags & FE_MC_NO_DATAPATH) != 0);
3018 ASSERT(mcip->mci_p_unicast_list == muip);
3020 mcip->mci_flags &= ~MAC_CLIENT_FLAGS_PASSIVE_PRIMARY;
3022 mcip->mci_p_unicast_list = NULL;
3023 mcip->mci_rx_p_fn = NULL;
3024 mcip->mci_rx_p_arg = NULL;
3026 mcip->mci_state_flags &= ~MCIS_UNICAST_HW;
3028 if (mcip->mci_state_flags & MCIS_TAG_DISABLE)
3029 mcip->mci_state_flags &= ~MCIS_TAG_DISABLE;
3031 if (mcip->mci_state_flags & MCIS_STRIP_DISABLE)
3032 mcip->mci_state_flags &= ~MCIS_STRIP_DISABLE;
3034 if (mcip->mci_state_flags & MCIS_DISABLE_TX_VID_CHECK)
3035 mcip->mci_state_flags &= ~MCIS_DISABLE_TX_VID_CHECK;
3037 kmem_free(muip, sizeof (mac_unicast_impl_t));
3038 i_mac_perim_exit(mip);
3039 return (0);
3042 * Remove the VID from the list of client's VIDs.
3044 pre = mcip->mci_unicast_list;
3045 if (muip == pre) {
3046 mcip->mci_unicast_list = muip->mui_next;
3047 } else {
3048 while ((pre->mui_next != NULL) && (pre->mui_next != muip))
3049 pre = pre->mui_next;
3050 ASSERT(pre->mui_next == muip);
3051 rw_enter(&mcip->mci_rw_lock, RW_WRITER);
3052 pre->mui_next = muip->mui_next;
3053 rw_exit(&mcip->mci_rw_lock);
3056 if (!mac_client_single_rcvr(mcip)) {
3058 * This MAC client is shared by more than one unicast
3059 * addresses, so we will just remove the flent
3060 * corresponding to the address being removed. We don't invoke
3061 * mac_rx_classify_flow_rem() since the additional flow is
3062 * not associated with its own separate set of SRS and rings,
3063 * and these constructs are still needed for the remaining
3064 * flows.
3066 flent = mac_client_get_flow(mcip, muip);
3067 ASSERT(flent != NULL);
3070 * The first one is disappearing, need to make sure
3071 * we replace it with another from the list of
3072 * shared clients.
3074 if (flent == mcip->mci_flent)
3075 flent = mac_client_swap_mciflent(mcip);
3076 mac_client_remove_flow_from_list(mcip, flent);
3077 mac_flow_remove(mip->mi_flow_tab, flent, B_FALSE);
3078 mac_flow_wait(flent, FLOW_DRIVER_UPCALL);
3081 * The multicast groups that were added by the client so
3082 * far must be removed from the brodcast domain corresponding
3083 * to the VID being removed.
3085 mac_client_bcast_refresh(mcip, mac_client_update_mcast,
3086 (void *)flent, B_FALSE);
3088 if (mip->mi_type->mt_brdcst_addr != NULL) {
3089 mac_bcast_delete(mcip, mip->mi_type->mt_brdcst_addr,
3090 muip->mui_vid);
3093 FLOW_FINAL_REFRELE(flent);
3094 ASSERT(!(mcip->mci_state_flags & MCIS_EXCLUSIVE));
3096 * Enable fastpath if this is a VNIC or a VLAN.
3098 if (mcip->mci_state_flags & MCIS_IS_VNIC)
3099 mac_fastpath_enable((mac_handle_t)mip);
3100 mac_stop((mac_handle_t)mip);
3101 i_mac_perim_exit(mip);
3102 return (0);
3105 mui_vid = muip->mui_vid;
3106 mac_client_datapath_teardown(mch, muip, flent);
3108 if ((mcip->mci_flags & MAC_CLIENT_FLAGS_PRIMARY) && mui_vid == 0) {
3109 mcip->mci_flags &= ~MAC_CLIENT_FLAGS_PRIMARY;
3110 } else {
3111 i_mac_perim_exit(mip);
3112 return (0);
3116 * If we are removing the primary, check if we have a passive primary
3117 * client that we need to activate now.
3119 mcip = mac_get_passive_primary_client(mip);
3120 if (mcip != NULL) {
3121 mac_resource_props_t *mrp;
3122 mac_unicast_impl_t *muip;
3124 mcip->mci_flags &= ~MAC_CLIENT_FLAGS_PASSIVE_PRIMARY;
3125 mrp = kmem_zalloc(sizeof (*mrp), KM_SLEEP);
3128 * Apply the property cached in the mac_impl_t to the
3129 * primary mac client.
3131 mac_get_resources((mac_handle_t)mip, mrp);
3132 (void) mac_client_set_resources(mch, mrp);
3133 ASSERT(mcip->mci_p_unicast_list != NULL);
3134 muip = mcip->mci_p_unicast_list;
3135 mcip->mci_p_unicast_list = NULL;
3136 if (mac_client_datapath_setup(mcip, VLAN_ID_NONE,
3137 mip->mi_addr, mrp, B_TRUE, muip) == 0) {
3138 if (mcip->mci_rx_p_fn != NULL) {
3139 mac_rx_set(mch, mcip->mci_rx_p_fn,
3140 mcip->mci_rx_p_arg);
3141 mcip->mci_rx_p_fn = NULL;
3142 mcip->mci_rx_p_arg = NULL;
3144 } else {
3145 kmem_free(muip, sizeof (mac_unicast_impl_t));
3147 kmem_free(mrp, sizeof (*mrp));
3149 i_mac_perim_exit(mip);
3150 return (0);
3154 * Multicast add function invoked by MAC clients.
3157 mac_multicast_add(mac_client_handle_t mch, const uint8_t *addr)
3159 mac_client_impl_t *mcip = (mac_client_impl_t *)mch;
3160 mac_impl_t *mip = mcip->mci_mip;
3161 flow_entry_t *flent = mcip->mci_flent_list;
3162 flow_entry_t *prev_fe = NULL;
3163 uint16_t vid;
3164 int err = 0;
3166 /* Verify the address is a valid multicast address */
3167 if ((err = mip->mi_type->mt_ops.mtops_multicst_verify(addr,
3168 mip->mi_pdata)) != 0)
3169 return (err);
3171 i_mac_perim_enter(mip);
3172 while (flent != NULL) {
3173 vid = i_mac_flow_vid(flent);
3175 err = mac_bcast_add((mac_client_impl_t *)mch, addr, vid,
3176 MAC_ADDRTYPE_MULTICAST);
3177 if (err != 0)
3178 break;
3179 prev_fe = flent;
3180 flent = flent->fe_client_next;
3184 * If we failed adding, then undo all, rather than partial
3185 * success.
3187 if (flent != NULL && prev_fe != NULL) {
3188 flent = mcip->mci_flent_list;
3189 while (flent != prev_fe->fe_client_next) {
3190 vid = i_mac_flow_vid(flent);
3191 mac_bcast_delete((mac_client_impl_t *)mch, addr, vid);
3192 flent = flent->fe_client_next;
3195 i_mac_perim_exit(mip);
3196 return (err);
3200 * Multicast delete function invoked by MAC clients.
3202 void
3203 mac_multicast_remove(mac_client_handle_t mch, const uint8_t *addr)
3205 mac_client_impl_t *mcip = (mac_client_impl_t *)mch;
3206 mac_impl_t *mip = mcip->mci_mip;
3207 flow_entry_t *flent;
3208 uint16_t vid;
3210 i_mac_perim_enter(mip);
3211 for (flent = mcip->mci_flent_list; flent != NULL;
3212 flent = flent->fe_client_next) {
3213 vid = i_mac_flow_vid(flent);
3214 mac_bcast_delete((mac_client_impl_t *)mch, addr, vid);
3216 i_mac_perim_exit(mip);
3220 * When a MAC client desires to capture packets on an interface,
3221 * it registers a promiscuous call back with mac_promisc_add().
3222 * There are three types of promiscuous callbacks:
3224 * * MAC_CLIENT_PROMISC_ALL
3225 * Captures all packets sent and received by the MAC client,
3226 * the physical interface, as well as all other MAC clients
3227 * defined on top of the same MAC.
3229 * * MAC_CLIENT_PROMISC_FILTERED
3230 * Captures all packets sent and received by the MAC client,
3231 * plus all multicast traffic sent and received by the phyisical
3232 * interface and the other MAC clients.
3234 * * MAC_CLIENT_PROMISC_MULTI
3235 * Captures all broadcast and multicast packets sent and
3236 * received by the MAC clients as well as the physical interface.
3238 * In all cases, the underlying MAC is put in promiscuous mode.
3241 mac_promisc_add(mac_client_handle_t mch, mac_client_promisc_type_t type,
3242 mac_rx_t fn, void *arg, mac_promisc_handle_t *mphp, uint16_t flags)
3244 mac_client_impl_t *mcip = (mac_client_impl_t *)mch;
3245 mac_impl_t *mip = mcip->mci_mip;
3246 mac_promisc_impl_t *mpip;
3247 mac_cb_info_t *mcbi;
3248 int rc;
3250 i_mac_perim_enter(mip);
3252 if ((rc = mac_start((mac_handle_t)mip)) != 0) {
3253 i_mac_perim_exit(mip);
3254 return (rc);
3257 if ((mcip->mci_state_flags & MCIS_IS_VNIC) &&
3258 type == MAC_CLIENT_PROMISC_ALL) {
3260 * The function is being invoked by the upper MAC client
3261 * of a VNIC. The VNIC should only see the traffic
3262 * it is entitled to.
3264 type = MAC_CLIENT_PROMISC_FILTERED;
3269 * Turn on promiscuous mode for the underlying NIC.
3270 * This is needed even for filtered callbacks which
3271 * expect to receive all multicast traffic on the wire.
3273 * Physical promiscuous mode should not be turned on if
3274 * MAC_PROMISC_FLAGS_NO_PHYS is set.
3276 if ((flags & MAC_PROMISC_FLAGS_NO_PHYS) == 0) {
3277 if ((rc = i_mac_promisc_set(mip, B_TRUE)) != 0) {
3278 mac_stop((mac_handle_t)mip);
3279 i_mac_perim_exit(mip);
3280 return (rc);
3284 mpip = kmem_cache_alloc(mac_promisc_impl_cache, KM_SLEEP);
3286 mpip->mpi_type = type;
3287 mpip->mpi_fn = fn;
3288 mpip->mpi_arg = arg;
3289 mpip->mpi_mcip = mcip;
3290 mpip->mpi_no_tx_loop = ((flags & MAC_PROMISC_FLAGS_NO_TX_LOOP) != 0);
3291 mpip->mpi_no_phys = ((flags & MAC_PROMISC_FLAGS_NO_PHYS) != 0);
3292 mpip->mpi_strip_vlan_tag =
3293 ((flags & MAC_PROMISC_FLAGS_VLAN_TAG_STRIP) != 0);
3294 mpip->mpi_no_copy = ((flags & MAC_PROMISC_FLAGS_NO_COPY) != 0);
3296 mcbi = &mip->mi_promisc_cb_info;
3297 mutex_enter(mcbi->mcbi_lockp);
3299 mac_callback_add(&mip->mi_promisc_cb_info, &mcip->mci_promisc_list,
3300 &mpip->mpi_mci_link);
3301 mac_callback_add(&mip->mi_promisc_cb_info, &mip->mi_promisc_list,
3302 &mpip->mpi_mi_link);
3304 mutex_exit(mcbi->mcbi_lockp);
3306 *mphp = (mac_promisc_handle_t)mpip;
3308 if (mcip->mci_state_flags & MCIS_IS_VNIC) {
3309 mac_impl_t *umip = mcip->mci_upper_mip;
3311 ASSERT(umip != NULL);
3312 mac_vnic_secondary_update(umip);
3315 i_mac_perim_exit(mip);
3317 return (0);
3321 * Remove a multicast address previously aded through mac_promisc_add().
3323 void
3324 mac_promisc_remove(mac_promisc_handle_t mph)
3326 mac_promisc_impl_t *mpip = (mac_promisc_impl_t *)mph;
3327 mac_client_impl_t *mcip = mpip->mpi_mcip;
3328 mac_impl_t *mip = mcip->mci_mip;
3329 mac_cb_info_t *mcbi;
3330 int rv;
3332 i_mac_perim_enter(mip);
3335 * Even if the device can't be reset into normal mode, we still
3336 * need to clear the client promisc callbacks. The client may want
3337 * to close the mac end point and we can't have stale callbacks.
3339 if (!(mpip->mpi_no_phys)) {
3340 if ((rv = i_mac_promisc_set(mip, B_FALSE)) != 0) {
3341 cmn_err(CE_WARN, "%s: failed to switch OFF promiscuous"
3342 " mode because of error 0x%x", mip->mi_name, rv);
3345 mcbi = &mip->mi_promisc_cb_info;
3346 mutex_enter(mcbi->mcbi_lockp);
3347 if (mac_callback_remove(mcbi, &mip->mi_promisc_list,
3348 &mpip->mpi_mi_link)) {
3349 VERIFY(mac_callback_remove(&mip->mi_promisc_cb_info,
3350 &mcip->mci_promisc_list, &mpip->mpi_mci_link));
3351 kmem_cache_free(mac_promisc_impl_cache, mpip);
3352 } else {
3353 mac_callback_remove_wait(&mip->mi_promisc_cb_info);
3356 if (mcip->mci_state_flags & MCIS_IS_VNIC) {
3357 mac_impl_t *umip = mcip->mci_upper_mip;
3359 ASSERT(umip != NULL);
3360 mac_vnic_secondary_update(umip);
3363 mutex_exit(mcbi->mcbi_lockp);
3364 mac_stop((mac_handle_t)mip);
3366 i_mac_perim_exit(mip);
3370 * Reference count the number of active Tx threads. MCI_TX_QUIESCE indicates
3371 * that a control operation wants to quiesce the Tx data flow in which case
3372 * we return an error. Holding any of the per cpu locks ensures that the
3373 * mci_tx_flag won't change.
3375 * 'CPU' must be accessed just once and used to compute the index into the
3376 * percpu array, and that index must be used for the entire duration of the
3377 * packet send operation. Note that the thread may be preempted and run on
3378 * another cpu any time and so we can't use 'CPU' more than once for the
3379 * operation.
3381 #define MAC_TX_TRY_HOLD(mcip, mytx, error) \
3383 (error) = 0; \
3384 (mytx) = &(mcip)->mci_tx_pcpu[CPU->cpu_seqid & mac_tx_percpu_cnt]; \
3385 mutex_enter(&(mytx)->pcpu_tx_lock); \
3386 if (!((mcip)->mci_tx_flag & MCI_TX_QUIESCE)) { \
3387 (mytx)->pcpu_tx_refcnt++; \
3388 } else { \
3389 (error) = -1; \
3391 mutex_exit(&(mytx)->pcpu_tx_lock); \
3395 * Release the reference. If needed, signal any control operation waiting
3396 * for Tx quiescence. The wait and signal are always done using the
3397 * mci_tx_pcpu[0]'s lock
3399 #define MAC_TX_RELE(mcip, mytx) { \
3400 mutex_enter(&(mytx)->pcpu_tx_lock); \
3401 if (--(mytx)->pcpu_tx_refcnt == 0 && \
3402 (mcip)->mci_tx_flag & MCI_TX_QUIESCE) { \
3403 mutex_exit(&(mytx)->pcpu_tx_lock); \
3404 mutex_enter(&(mcip)->mci_tx_pcpu[0].pcpu_tx_lock); \
3405 cv_signal(&(mcip)->mci_tx_cv); \
3406 mutex_exit(&(mcip)->mci_tx_pcpu[0].pcpu_tx_lock); \
3407 } else { \
3408 mutex_exit(&(mytx)->pcpu_tx_lock); \
3413 * Send function invoked by MAC clients.
3415 mac_tx_cookie_t
3416 mac_tx(mac_client_handle_t mch, mblk_t *mp_chain, uintptr_t hint,
3417 uint16_t flag, mblk_t **ret_mp)
3419 mac_tx_cookie_t cookie = NULL;
3420 int error;
3421 mac_tx_percpu_t *mytx;
3422 mac_soft_ring_set_t *srs;
3423 flow_entry_t *flent;
3424 boolean_t is_subflow = B_FALSE;
3425 mac_client_impl_t *mcip = (mac_client_impl_t *)mch;
3426 mac_impl_t *mip = mcip->mci_mip;
3427 mac_srs_tx_t *srs_tx;
3430 * Check whether the active Tx threads count is bumped already.
3432 if (!(flag & MAC_TX_NO_HOLD)) {
3433 MAC_TX_TRY_HOLD(mcip, mytx, error);
3434 if (error != 0) {
3435 freemsgchain(mp_chain);
3436 return (NULL);
3441 * If mac protection is enabled, only the permissible packets will be
3442 * returned by mac_protect_check().
3444 if ((mcip->mci_flent->
3445 fe_resource_props.mrp_mask & MRP_PROTECT) != 0 &&
3446 (mp_chain = mac_protect_check(mch, mp_chain)) == NULL)
3447 goto done;
3449 if (mcip->mci_subflow_tab != NULL &&
3450 mcip->mci_subflow_tab->ft_flow_count > 0 &&
3451 mac_flow_lookup(mcip->mci_subflow_tab, mp_chain,
3452 FLOW_OUTBOUND, &flent) == 0) {
3454 * The main assumption here is that if in the event
3455 * we get a chain, all the packets will be classified
3456 * to the same Flow/SRS. If this changes for any
3457 * reason, the following logic should change as well.
3458 * I suppose the fanout_hint also assumes this .
3460 ASSERT(flent != NULL);
3461 is_subflow = B_TRUE;
3462 } else {
3463 flent = mcip->mci_flent;
3466 srs = flent->fe_tx_srs;
3468 * This is to avoid panics with PF_PACKET that can call mac_tx()
3469 * against an interface that is not capable of sending. A rewrite
3470 * of the mac datapath is required to remove this limitation.
3472 if (srs == NULL) {
3473 freemsgchain(mp_chain);
3474 goto done;
3477 srs_tx = &srs->srs_tx;
3478 if (srs_tx->st_mode == SRS_TX_DEFAULT &&
3479 (srs->srs_state & SRS_ENQUEUED) == 0 &&
3480 mip->mi_nactiveclients == 1 && mp_chain->b_next == NULL) {
3481 uint64_t obytes;
3484 * Since dls always opens the underlying MAC, nclients equals
3485 * to 1 means that the only active client is dls itself acting
3486 * as a primary client of the MAC instance. Since dls will not
3487 * send tagged packets in that case, and dls is trusted to send
3488 * packets for its allowed VLAN(s), the VLAN tag insertion and
3489 * check is required only if nclients is greater than 1.
3491 if (mip->mi_nclients > 1) {
3492 if (MAC_VID_CHECK_NEEDED(mcip)) {
3493 int err = 0;
3495 MAC_VID_CHECK(mcip, mp_chain, err);
3496 if (err != 0) {
3497 freemsg(mp_chain);
3498 mcip->mci_misc_stat.mms_txerrors++;
3499 goto done;
3502 if (MAC_TAG_NEEDED(mcip)) {
3503 mp_chain = mac_add_vlan_tag(mp_chain, 0,
3504 mac_client_vid(mch));
3505 if (mp_chain == NULL) {
3506 mcip->mci_misc_stat.mms_txerrors++;
3507 goto done;
3512 obytes = (mp_chain->b_cont == NULL ? MBLKL(mp_chain) :
3513 msgdsize(mp_chain));
3515 MAC_TX(mip, srs_tx->st_arg2, mp_chain, mcip);
3516 if (mp_chain == NULL) {
3517 cookie = NULL;
3518 SRS_TX_STAT_UPDATE(srs, opackets, 1);
3519 SRS_TX_STAT_UPDATE(srs, obytes, obytes);
3520 } else {
3521 mutex_enter(&srs->srs_lock);
3522 cookie = mac_tx_srs_no_desc(srs, mp_chain,
3523 flag, ret_mp);
3524 mutex_exit(&srs->srs_lock);
3526 } else {
3527 cookie = srs_tx->st_func(srs, mp_chain, hint, flag, ret_mp);
3530 done:
3531 if (is_subflow)
3532 FLOW_REFRELE(flent);
3534 if (!(flag & MAC_TX_NO_HOLD))
3535 MAC_TX_RELE(mcip, mytx);
3537 return (cookie);
3541 * mac_tx_is_blocked
3543 * Given a cookie, it returns if the ring identified by the cookie is
3544 * flow-controlled or not. If NULL is passed in place of a cookie,
3545 * then it finds out if any of the underlying rings belonging to the
3546 * SRS is flow controlled or not and returns that status.
3548 /* ARGSUSED */
3549 boolean_t
3550 mac_tx_is_flow_blocked(mac_client_handle_t mch, mac_tx_cookie_t cookie)
3552 mac_client_impl_t *mcip = (mac_client_impl_t *)mch;
3553 mac_soft_ring_set_t *mac_srs;
3554 mac_soft_ring_t *sringp;
3555 boolean_t blocked = B_FALSE;
3556 mac_tx_percpu_t *mytx;
3557 int err;
3558 int i;
3561 * Bump the reference count so that mac_srs won't be deleted.
3562 * If the client is currently quiesced and we failed to bump
3563 * the reference, return B_TRUE so that flow control stays
3564 * as enabled.
3566 * Flow control will then be disabled once the client is no
3567 * longer quiesced.
3569 MAC_TX_TRY_HOLD(mcip, mytx, err);
3570 if (err != 0)
3571 return (B_TRUE);
3573 if ((mac_srs = MCIP_TX_SRS(mcip)) == NULL) {
3574 MAC_TX_RELE(mcip, mytx);
3575 return (B_FALSE);
3578 mutex_enter(&mac_srs->srs_lock);
3580 * Only in the case of TX_FANOUT and TX_AGGR, the underlying
3581 * softring (s_ring_state) will have the HIWAT set. This is
3582 * the multiple Tx ring flow control case. For all other
3583 * case, SRS (srs_state) will store the condition.
3585 if (mac_srs->srs_tx.st_mode == SRS_TX_FANOUT ||
3586 mac_srs->srs_tx.st_mode == SRS_TX_AGGR) {
3587 if (cookie != NULL) {
3588 sringp = (mac_soft_ring_t *)cookie;
3589 mutex_enter(&sringp->s_ring_lock);
3590 if (sringp->s_ring_state & S_RING_TX_HIWAT)
3591 blocked = B_TRUE;
3592 mutex_exit(&sringp->s_ring_lock);
3593 } else {
3594 for (i = 0; i < mac_srs->srs_tx_ring_count; i++) {
3595 sringp = mac_srs->srs_tx_soft_rings[i];
3596 mutex_enter(&sringp->s_ring_lock);
3597 if (sringp->s_ring_state & S_RING_TX_HIWAT) {
3598 blocked = B_TRUE;
3599 mutex_exit(&sringp->s_ring_lock);
3600 break;
3602 mutex_exit(&sringp->s_ring_lock);
3605 } else {
3606 blocked = (mac_srs->srs_state & SRS_TX_HIWAT);
3608 mutex_exit(&mac_srs->srs_lock);
3609 MAC_TX_RELE(mcip, mytx);
3610 return (blocked);
3614 * Check if the MAC client is the primary MAC client.
3616 boolean_t
3617 mac_is_primary_client(mac_client_impl_t *mcip)
3619 return (mcip->mci_flags & MAC_CLIENT_FLAGS_PRIMARY);
3622 void
3623 mac_ioctl(mac_handle_t mh, queue_t *wq, mblk_t *bp)
3625 mac_impl_t *mip = (mac_impl_t *)mh;
3626 int cmd = ((struct iocblk *)bp->b_rptr)->ioc_cmd;
3628 if ((cmd == ND_GET && (mip->mi_callbacks->mc_callbacks & MC_GETPROP)) ||
3629 (cmd == ND_SET && (mip->mi_callbacks->mc_callbacks & MC_SETPROP))) {
3631 * If ndd props were registered, call them.
3632 * Note that ndd ioctls are Obsolete
3634 mac_ndd_ioctl(mip, wq, bp);
3635 return;
3639 * Call the driver to handle the ioctl. The driver may not support
3640 * any ioctls, in which case we reply with a NAK on its behalf.
3642 if (mip->mi_callbacks->mc_callbacks & MC_IOCTL)
3643 mip->mi_ioctl(mip->mi_driver, wq, bp);
3644 else
3645 miocnak(wq, bp, 0, EINVAL);
3649 * Return the link state of the specified MAC instance.
3651 link_state_t
3652 mac_link_get(mac_handle_t mh)
3654 return (((mac_impl_t *)mh)->mi_linkstate);
3658 * Add a mac client specified notification callback. Please see the comments
3659 * above mac_callback_add() for general information about mac callback
3660 * addition/deletion in the presence of mac callback list walkers
3662 mac_notify_handle_t
3663 mac_notify_add(mac_handle_t mh, mac_notify_t notify_fn, void *arg)
3665 mac_impl_t *mip = (mac_impl_t *)mh;
3666 mac_notify_cb_t *mncb;
3667 mac_cb_info_t *mcbi;
3670 * Allocate a notify callback structure, fill in the details and
3671 * use the mac callback list manipulation functions to chain into
3672 * the list of callbacks.
3674 mncb = kmem_zalloc(sizeof (mac_notify_cb_t), KM_SLEEP);
3675 mncb->mncb_fn = notify_fn;
3676 mncb->mncb_arg = arg;
3677 mncb->mncb_mip = mip;
3678 mncb->mncb_link.mcb_objp = mncb;
3679 mncb->mncb_link.mcb_objsize = sizeof (mac_notify_cb_t);
3680 mncb->mncb_link.mcb_flags = MCB_NOTIFY_CB_T;
3682 mcbi = &mip->mi_notify_cb_info;
3684 i_mac_perim_enter(mip);
3685 mutex_enter(mcbi->mcbi_lockp);
3687 mac_callback_add(&mip->mi_notify_cb_info, &mip->mi_notify_cb_list,
3688 &mncb->mncb_link);
3690 mutex_exit(mcbi->mcbi_lockp);
3691 i_mac_perim_exit(mip);
3692 return ((mac_notify_handle_t)mncb);
3695 void
3696 mac_notify_remove_wait(mac_handle_t mh)
3698 mac_impl_t *mip = (mac_impl_t *)mh;
3699 mac_cb_info_t *mcbi = &mip->mi_notify_cb_info;
3701 mutex_enter(mcbi->mcbi_lockp);
3702 mac_callback_remove_wait(&mip->mi_notify_cb_info);
3703 mutex_exit(mcbi->mcbi_lockp);
3707 * Remove a mac client specified notification callback
3710 mac_notify_remove(mac_notify_handle_t mnh, boolean_t wait)
3712 mac_notify_cb_t *mncb = (mac_notify_cb_t *)mnh;
3713 mac_impl_t *mip = mncb->mncb_mip;
3714 mac_cb_info_t *mcbi;
3715 int err = 0;
3717 mcbi = &mip->mi_notify_cb_info;
3719 i_mac_perim_enter(mip);
3720 mutex_enter(mcbi->mcbi_lockp);
3722 ASSERT(mncb->mncb_link.mcb_objp == mncb);
3724 * If there aren't any list walkers, the remove would succeed
3725 * inline, else we wait for the deferred remove to complete
3727 if (mac_callback_remove(&mip->mi_notify_cb_info,
3728 &mip->mi_notify_cb_list, &mncb->mncb_link)) {
3729 kmem_free(mncb, sizeof (mac_notify_cb_t));
3730 } else {
3731 err = EBUSY;
3734 mutex_exit(mcbi->mcbi_lockp);
3735 i_mac_perim_exit(mip);
3738 * If we failed to remove the notification callback and "wait" is set
3739 * to be B_TRUE, wait for the callback to finish after we exit the
3740 * mac perimeter.
3742 if (err != 0 && wait) {
3743 mac_notify_remove_wait((mac_handle_t)mip);
3744 return (0);
3747 return (err);
3751 * Associate resource management callbacks with the specified MAC
3752 * clients.
3755 void
3756 mac_resource_set_common(mac_client_handle_t mch, mac_resource_add_t add,
3757 mac_resource_remove_t remove, mac_resource_quiesce_t quiesce,
3758 mac_resource_restart_t restart, mac_resource_bind_t bind,
3759 void *arg)
3761 mac_client_impl_t *mcip = (mac_client_impl_t *)mch;
3763 mcip->mci_resource_add = add;
3764 mcip->mci_resource_remove = remove;
3765 mcip->mci_resource_quiesce = quiesce;
3766 mcip->mci_resource_restart = restart;
3767 mcip->mci_resource_bind = bind;
3768 mcip->mci_resource_arg = arg;
3771 void
3772 mac_resource_set(mac_client_handle_t mch, mac_resource_add_t add, void *arg)
3774 /* update the 'resource_add' callback */
3775 mac_resource_set_common(mch, add, NULL, NULL, NULL, NULL, arg);
3779 * Sets up the client resources and enable the polling interface over all the
3780 * SRS's and the soft rings of the client
3782 void
3783 mac_client_poll_enable(mac_client_handle_t mch)
3785 mac_client_impl_t *mcip = (mac_client_impl_t *)mch;
3786 mac_soft_ring_set_t *mac_srs;
3787 flow_entry_t *flent;
3788 int i;
3790 flent = mcip->mci_flent;
3791 ASSERT(flent != NULL);
3793 mcip->mci_state_flags |= MCIS_CLIENT_POLL_CAPABLE;
3794 for (i = 0; i < flent->fe_rx_srs_cnt; i++) {
3795 mac_srs = (mac_soft_ring_set_t *)flent->fe_rx_srs[i];
3796 ASSERT(mac_srs->srs_mcip == mcip);
3797 mac_srs_client_poll_enable(mcip, mac_srs);
3802 * Tears down the client resources and disable the polling interface over all
3803 * the SRS's and the soft rings of the client
3805 void
3806 mac_client_poll_disable(mac_client_handle_t mch)
3808 mac_client_impl_t *mcip = (mac_client_impl_t *)mch;
3809 mac_soft_ring_set_t *mac_srs;
3810 flow_entry_t *flent;
3811 int i;
3813 flent = mcip->mci_flent;
3814 ASSERT(flent != NULL);
3816 mcip->mci_state_flags &= ~MCIS_CLIENT_POLL_CAPABLE;
3817 for (i = 0; i < flent->fe_rx_srs_cnt; i++) {
3818 mac_srs = (mac_soft_ring_set_t *)flent->fe_rx_srs[i];
3819 ASSERT(mac_srs->srs_mcip == mcip);
3820 mac_srs_client_poll_disable(mcip, mac_srs);
3825 * Associate the CPUs specified by the given property with a MAC client.
3828 mac_cpu_set(mac_client_handle_t mch, mac_resource_props_t *mrp)
3830 mac_client_impl_t *mcip = (mac_client_impl_t *)mch;
3831 mac_impl_t *mip = mcip->mci_mip;
3832 int err = 0;
3834 ASSERT(MAC_PERIM_HELD((mac_handle_t)mip));
3836 if ((err = mac_validate_props(mcip->mci_state_flags & MCIS_IS_VNIC ?
3837 mcip->mci_upper_mip : mip, mrp)) != 0) {
3838 return (err);
3840 if (MCIP_DATAPATH_SETUP(mcip))
3841 mac_flow_modify(mip->mi_flow_tab, mcip->mci_flent, mrp);
3843 mac_update_resources(mrp, MCIP_RESOURCE_PROPS(mcip), B_FALSE);
3844 return (0);
3848 * Apply the specified properties to the specified MAC client.
3851 mac_client_set_resources(mac_client_handle_t mch, mac_resource_props_t *mrp)
3853 mac_client_impl_t *mcip = (mac_client_impl_t *)mch;
3854 mac_impl_t *mip = mcip->mci_mip;
3855 int err = 0;
3857 i_mac_perim_enter(mip);
3859 if ((mrp->mrp_mask & MRP_MAXBW) || (mrp->mrp_mask & MRP_PRIORITY)) {
3860 err = mac_resource_ctl_set(mch, mrp);
3861 if (err != 0)
3862 goto done;
3865 if (mrp->mrp_mask & (MRP_CPUS|MRP_POOL)) {
3866 err = mac_cpu_set(mch, mrp);
3867 if (err != 0)
3868 goto done;
3871 if (mrp->mrp_mask & MRP_PROTECT) {
3872 err = mac_protect_set(mch, mrp);
3873 if (err != 0)
3874 goto done;
3877 if ((mrp->mrp_mask & MRP_RX_RINGS) || (mrp->mrp_mask & MRP_TX_RINGS))
3878 err = mac_resource_ctl_set(mch, mrp);
3880 done:
3881 i_mac_perim_exit(mip);
3882 return (err);
3886 * Return the properties currently associated with the specified MAC client.
3888 void
3889 mac_client_get_resources(mac_client_handle_t mch, mac_resource_props_t *mrp)
3891 mac_client_impl_t *mcip = (mac_client_impl_t *)mch;
3892 mac_resource_props_t *mcip_mrp = MCIP_RESOURCE_PROPS(mcip);
3894 bcopy(mcip_mrp, mrp, sizeof (mac_resource_props_t));
3898 * Return the effective properties currently associated with the specified
3899 * MAC client.
3901 void
3902 mac_client_get_effective_resources(mac_client_handle_t mch,
3903 mac_resource_props_t *mrp)
3905 mac_client_impl_t *mcip = (mac_client_impl_t *)mch;
3906 mac_resource_props_t *mcip_mrp = MCIP_EFFECTIVE_PROPS(mcip);
3908 bcopy(mcip_mrp, mrp, sizeof (mac_resource_props_t));
3912 * Pass a copy of the specified packet to the promiscuous callbacks
3913 * of the specified MAC.
3915 * If sender is NULL, the function is being invoked for a packet chain
3916 * received from the wire. If sender is non-NULL, it points to
3917 * the MAC client from which the packet is being sent.
3919 * The packets are distributed to the promiscuous callbacks as follows:
3921 * - all packets are sent to the MAC_CLIENT_PROMISC_ALL callbacks
3922 * - all broadcast and multicast packets are sent to the
3923 * MAC_CLIENT_PROMISC_FILTER and MAC_CLIENT_PROMISC_MULTI.
3925 * The unicast packets of MAC_CLIENT_PROMISC_FILTER callbacks are dispatched
3926 * after classification by mac_rx_deliver().
3929 static void
3930 mac_promisc_dispatch_one(mac_promisc_impl_t *mpip, mblk_t *mp,
3931 boolean_t loopback)
3933 mblk_t *mp_copy, *mp_next;
3935 if (!mpip->mpi_no_copy || mpip->mpi_strip_vlan_tag) {
3936 mp_copy = copymsg(mp);
3937 if (mp_copy == NULL)
3938 return;
3940 if (mpip->mpi_strip_vlan_tag) {
3941 mp_copy = mac_strip_vlan_tag_chain(mp_copy);
3942 if (mp_copy == NULL)
3943 return;
3945 mp_next = NULL;
3946 } else {
3947 mp_copy = mp;
3948 mp_next = mp->b_next;
3950 mp_copy->b_next = NULL;
3952 mpip->mpi_fn(mpip->mpi_arg, NULL, mp_copy, loopback);
3953 if (mp_copy == mp)
3954 mp->b_next = mp_next;
3958 * Return the VID of a packet. Zero if the packet is not tagged.
3960 static uint16_t
3961 mac_ether_vid(mblk_t *mp)
3963 struct ether_header *eth = (struct ether_header *)mp->b_rptr;
3965 if (ntohs(eth->ether_type) == ETHERTYPE_VLAN) {
3966 struct ether_vlan_header *t_evhp =
3967 (struct ether_vlan_header *)mp->b_rptr;
3968 return (VLAN_ID(ntohs(t_evhp->ether_tci)));
3971 return (0);
3975 * Return whether the specified packet contains a multicast or broadcast
3976 * destination MAC address.
3978 static boolean_t
3979 mac_is_mcast(mac_impl_t *mip, mblk_t *mp)
3981 mac_header_info_t hdr_info;
3983 if (mac_header_info((mac_handle_t)mip, mp, &hdr_info) != 0)
3984 return (B_FALSE);
3985 return ((hdr_info.mhi_dsttype == MAC_ADDRTYPE_BROADCAST) ||
3986 (hdr_info.mhi_dsttype == MAC_ADDRTYPE_MULTICAST));
3990 * Send a copy of an mblk chain to the MAC clients of the specified MAC.
3991 * "sender" points to the sender MAC client for outbound packets, and
3992 * is set to NULL for inbound packets.
3994 void
3995 mac_promisc_dispatch(mac_impl_t *mip, mblk_t *mp_chain,
3996 mac_client_impl_t *sender)
3998 mac_promisc_impl_t *mpip;
3999 mac_cb_t *mcb;
4000 mblk_t *mp;
4001 boolean_t is_mcast, is_sender;
4003 MAC_PROMISC_WALKER_INC(mip);
4004 for (mp = mp_chain; mp != NULL; mp = mp->b_next) {
4005 is_mcast = mac_is_mcast(mip, mp);
4006 /* send packet to interested callbacks */
4007 for (mcb = mip->mi_promisc_list; mcb != NULL;
4008 mcb = mcb->mcb_nextp) {
4009 mpip = (mac_promisc_impl_t *)mcb->mcb_objp;
4010 is_sender = (mpip->mpi_mcip == sender);
4012 if (is_sender && mpip->mpi_no_tx_loop)
4014 * The sender doesn't want to receive
4015 * copies of the packets it sends.
4017 continue;
4019 /* this client doesn't need any packets (bridge) */
4020 if (mpip->mpi_fn == NULL)
4021 continue;
4024 * For an ethernet MAC, don't displatch a multicast
4025 * packet to a non-PROMISC_ALL callbacks unless the VID
4026 * of the packet matches the VID of the client.
4028 if (is_mcast &&
4029 mpip->mpi_type != MAC_CLIENT_PROMISC_ALL &&
4030 !mac_client_check_flow_vid(mpip->mpi_mcip,
4031 mac_ether_vid(mp)))
4032 continue;
4034 if (is_sender ||
4035 mpip->mpi_type == MAC_CLIENT_PROMISC_ALL ||
4036 is_mcast)
4037 mac_promisc_dispatch_one(mpip, mp, is_sender);
4040 MAC_PROMISC_WALKER_DCR(mip);
4043 void
4044 mac_promisc_client_dispatch(mac_client_impl_t *mcip, mblk_t *mp_chain)
4046 mac_impl_t *mip = mcip->mci_mip;
4047 mac_promisc_impl_t *mpip;
4048 boolean_t is_mcast;
4049 mblk_t *mp;
4050 mac_cb_t *mcb;
4053 * The unicast packets for the MAC client still
4054 * need to be delivered to the MAC_CLIENT_PROMISC_FILTERED
4055 * promiscuous callbacks. The broadcast and multicast
4056 * packets were delivered from mac_rx().
4058 MAC_PROMISC_WALKER_INC(mip);
4059 for (mp = mp_chain; mp != NULL; mp = mp->b_next) {
4060 is_mcast = mac_is_mcast(mip, mp);
4061 for (mcb = mcip->mci_promisc_list; mcb != NULL;
4062 mcb = mcb->mcb_nextp) {
4063 mpip = (mac_promisc_impl_t *)mcb->mcb_objp;
4064 if (mpip->mpi_type == MAC_CLIENT_PROMISC_FILTERED &&
4065 !is_mcast) {
4066 mac_promisc_dispatch_one(mpip, mp, B_FALSE);
4070 MAC_PROMISC_WALKER_DCR(mip);
4074 * Return the margin value currently assigned to the specified MAC instance.
4076 void
4077 mac_margin_get(mac_handle_t mh, uint32_t *marginp)
4079 mac_impl_t *mip = (mac_impl_t *)mh;
4081 rw_enter(&(mip->mi_rw_lock), RW_READER);
4082 *marginp = mip->mi_margin;
4083 rw_exit(&(mip->mi_rw_lock));
4087 * mac_info_get() is used for retrieving the mac_info when a DL_INFO_REQ is
4088 * issued before a DL_ATTACH_REQ. we walk the i_mac_impl_hash table and find
4089 * the first mac_impl_t with a matching driver name; then we copy its mac_info_t
4090 * to the caller. we do all this with i_mac_impl_lock held so the mac_impl_t
4091 * cannot disappear while we are accessing it.
4093 typedef struct i_mac_info_state_s {
4094 const char *mi_name;
4095 mac_info_t *mi_infop;
4096 } i_mac_info_state_t;
4098 /*ARGSUSED*/
4099 static uint_t
4100 i_mac_info_walker(mod_hash_key_t key, mod_hash_val_t *val, void *arg)
4102 i_mac_info_state_t *statep = arg;
4103 mac_impl_t *mip = (mac_impl_t *)val;
4105 if (mip->mi_state_flags & MIS_DISABLED)
4106 return (MH_WALK_CONTINUE);
4108 if (strcmp(statep->mi_name,
4109 ddi_driver_name(mip->mi_dip)) != 0)
4110 return (MH_WALK_CONTINUE);
4112 statep->mi_infop = &mip->mi_info;
4113 return (MH_WALK_TERMINATE);
4116 boolean_t
4117 mac_info_get(const char *name, mac_info_t *minfop)
4119 i_mac_info_state_t state;
4121 rw_enter(&i_mac_impl_lock, RW_READER);
4122 state.mi_name = name;
4123 state.mi_infop = NULL;
4124 mod_hash_walk(i_mac_impl_hash, i_mac_info_walker, &state);
4125 if (state.mi_infop == NULL) {
4126 rw_exit(&i_mac_impl_lock);
4127 return (B_FALSE);
4129 *minfop = *state.mi_infop;
4130 rw_exit(&i_mac_impl_lock);
4131 return (B_TRUE);
4135 * To get the capabilities that MAC layer cares about, such as rings, factory
4136 * mac address, vnic or not, it should directly invoke this function. If the
4137 * link is part of a bridge, then the only "capability" it has is the inability
4138 * to do zero copy.
4140 boolean_t
4141 i_mac_capab_get(mac_handle_t mh, mac_capab_t cap, void *cap_data)
4143 mac_impl_t *mip = (mac_impl_t *)mh;
4145 if (mip->mi_bridge_link != NULL)
4146 return (cap == MAC_CAPAB_NO_ZCOPY);
4147 else if (mip->mi_callbacks->mc_callbacks & MC_GETCAPAB)
4148 return (mip->mi_getcapab(mip->mi_driver, cap, cap_data));
4149 else
4150 return (B_FALSE);
4154 * Capability query function. If number of active mac clients is greater than
4155 * 1, only limited capabilities can be advertised to the caller no matter the
4156 * driver has certain capability or not. Else, we query the driver to get the
4157 * capability.
4159 boolean_t
4160 mac_capab_get(mac_handle_t mh, mac_capab_t cap, void *cap_data)
4162 mac_impl_t *mip = (mac_impl_t *)mh;
4165 * if mi_nactiveclients > 1, only MAC_CAPAB_LEGACY, MAC_CAPAB_HCKSUM,
4166 * MAC_CAPAB_NO_NATIVEVLAN and MAC_CAPAB_NO_ZCOPY can be advertised.
4168 if (mip->mi_nactiveclients > 1) {
4169 switch (cap) {
4170 case MAC_CAPAB_NO_ZCOPY:
4171 return (B_TRUE);
4172 case MAC_CAPAB_LEGACY:
4173 case MAC_CAPAB_HCKSUM:
4174 case MAC_CAPAB_NO_NATIVEVLAN:
4175 break;
4176 default:
4177 return (B_FALSE);
4181 /* else get capab from driver */
4182 return (i_mac_capab_get(mh, cap, cap_data));
4185 boolean_t
4186 mac_sap_verify(mac_handle_t mh, uint32_t sap, uint32_t *bind_sap)
4188 mac_impl_t *mip = (mac_impl_t *)mh;
4190 return (mip->mi_type->mt_ops.mtops_sap_verify(sap, bind_sap,
4191 mip->mi_pdata));
4194 mblk_t *
4195 mac_header(mac_handle_t mh, const uint8_t *daddr, uint32_t sap, mblk_t *payload,
4196 size_t extra_len)
4198 mac_impl_t *mip = (mac_impl_t *)mh;
4199 const uint8_t *hdr_daddr;
4202 * If the MAC is point-to-point with a fixed destination address, then
4203 * we must always use that destination in the MAC header.
4205 hdr_daddr = (mip->mi_dstaddr_set ? mip->mi_dstaddr : daddr);
4206 return (mip->mi_type->mt_ops.mtops_header(mip->mi_addr, hdr_daddr, sap,
4207 mip->mi_pdata, payload, extra_len));
4211 mac_header_info(mac_handle_t mh, mblk_t *mp, mac_header_info_t *mhip)
4213 mac_impl_t *mip = (mac_impl_t *)mh;
4215 return (mip->mi_type->mt_ops.mtops_header_info(mp, mip->mi_pdata,
4216 mhip));
4220 mac_vlan_header_info(mac_handle_t mh, mblk_t *mp, mac_header_info_t *mhip)
4222 mac_impl_t *mip = (mac_impl_t *)mh;
4223 boolean_t is_ethernet = (mip->mi_info.mi_media == DL_ETHER);
4224 int err = 0;
4227 * Packets should always be at least 16 bit aligned.
4229 ASSERT(IS_P2ALIGNED(mp->b_rptr, sizeof (uint16_t)));
4231 if ((err = mac_header_info(mh, mp, mhip)) != 0)
4232 return (err);
4235 * If this is a VLAN-tagged Ethernet packet, then the SAP in the
4236 * mac_header_info_t as returned by mac_header_info() is
4237 * ETHERTYPE_VLAN. We need to grab the ethertype from the VLAN header.
4239 if (is_ethernet && (mhip->mhi_bindsap == ETHERTYPE_VLAN)) {
4240 struct ether_vlan_header *evhp;
4241 uint16_t sap;
4242 mblk_t *tmp = NULL;
4243 size_t size;
4245 size = sizeof (struct ether_vlan_header);
4246 if (MBLKL(mp) < size) {
4248 * Pullup the message in order to get the MAC header
4249 * infomation. Note that this is a read-only function,
4250 * we keep the input packet intact.
4252 if ((tmp = msgpullup(mp, size)) == NULL)
4253 return (EINVAL);
4255 mp = tmp;
4257 evhp = (struct ether_vlan_header *)mp->b_rptr;
4258 sap = ntohs(evhp->ether_type);
4259 (void) mac_sap_verify(mh, sap, &mhip->mhi_bindsap);
4260 mhip->mhi_hdrsize = sizeof (struct ether_vlan_header);
4261 mhip->mhi_tci = ntohs(evhp->ether_tci);
4262 mhip->mhi_istagged = B_TRUE;
4263 freemsg(tmp);
4265 if (VLAN_CFI(mhip->mhi_tci) != ETHER_CFI)
4266 return (EINVAL);
4267 } else {
4268 mhip->mhi_istagged = B_FALSE;
4269 mhip->mhi_tci = 0;
4272 return (0);
4275 mblk_t *
4276 mac_header_cook(mac_handle_t mh, mblk_t *mp)
4278 mac_impl_t *mip = (mac_impl_t *)mh;
4280 if (mip->mi_type->mt_ops.mtops_ops & MTOPS_HEADER_COOK) {
4281 if (DB_REF(mp) > 1) {
4282 mblk_t *newmp = copymsg(mp);
4283 if (newmp == NULL)
4284 return (NULL);
4285 freemsg(mp);
4286 mp = newmp;
4288 return (mip->mi_type->mt_ops.mtops_header_cook(mp,
4289 mip->mi_pdata));
4291 return (mp);
4294 mblk_t *
4295 mac_header_uncook(mac_handle_t mh, mblk_t *mp)
4297 mac_impl_t *mip = (mac_impl_t *)mh;
4299 if (mip->mi_type->mt_ops.mtops_ops & MTOPS_HEADER_UNCOOK) {
4300 if (DB_REF(mp) > 1) {
4301 mblk_t *newmp = copymsg(mp);
4302 if (newmp == NULL)
4303 return (NULL);
4304 freemsg(mp);
4305 mp = newmp;
4307 return (mip->mi_type->mt_ops.mtops_header_uncook(mp,
4308 mip->mi_pdata));
4310 return (mp);
4313 uint_t
4314 mac_addr_len(mac_handle_t mh)
4316 mac_impl_t *mip = (mac_impl_t *)mh;
4318 return (mip->mi_type->mt_addr_length);
4321 /* True if a MAC is a VNIC */
4322 boolean_t
4323 mac_is_vnic(mac_handle_t mh)
4325 return (((mac_impl_t *)mh)->mi_state_flags & MIS_IS_VNIC);
4328 mac_handle_t
4329 mac_get_lower_mac_handle(mac_handle_t mh)
4331 mac_impl_t *mip = (mac_impl_t *)mh;
4333 ASSERT(mac_is_vnic(mh));
4334 return (((vnic_t *)mip->mi_driver)->vn_lower_mh);
4337 boolean_t
4338 mac_is_vnic_primary(mac_handle_t mh)
4340 mac_impl_t *mip = (mac_impl_t *)mh;
4342 ASSERT(mac_is_vnic(mh));
4343 return (((vnic_t *)mip->mi_driver)->vn_addr_type ==
4344 VNIC_MAC_ADDR_TYPE_PRIMARY);
4347 void
4348 mac_update_resources(mac_resource_props_t *nmrp, mac_resource_props_t *cmrp,
4349 boolean_t is_user_flow)
4351 if (nmrp != NULL && cmrp != NULL) {
4352 if (nmrp->mrp_mask & MRP_PRIORITY) {
4353 if (nmrp->mrp_priority == MPL_RESET) {
4354 cmrp->mrp_mask &= ~MRP_PRIORITY;
4355 if (is_user_flow) {
4356 cmrp->mrp_priority =
4357 MPL_SUBFLOW_DEFAULT;
4358 } else {
4359 cmrp->mrp_priority = MPL_LINK_DEFAULT;
4361 } else {
4362 cmrp->mrp_mask |= MRP_PRIORITY;
4363 cmrp->mrp_priority = nmrp->mrp_priority;
4366 if (nmrp->mrp_mask & MRP_MAXBW) {
4367 if (nmrp->mrp_maxbw == MRP_MAXBW_RESETVAL) {
4368 cmrp->mrp_mask &= ~MRP_MAXBW;
4369 cmrp->mrp_maxbw = 0;
4370 } else {
4371 cmrp->mrp_mask |= MRP_MAXBW;
4372 cmrp->mrp_maxbw = nmrp->mrp_maxbw;
4375 if (nmrp->mrp_mask & MRP_CPUS)
4376 MAC_COPY_CPUS(nmrp, cmrp);
4378 if (nmrp->mrp_mask & MRP_POOL) {
4379 if (strlen(nmrp->mrp_pool) == 0) {
4380 cmrp->mrp_mask &= ~MRP_POOL;
4381 bzero(cmrp->mrp_pool, sizeof (cmrp->mrp_pool));
4382 } else {
4383 cmrp->mrp_mask |= MRP_POOL;
4384 (void) strncpy(cmrp->mrp_pool, nmrp->mrp_pool,
4385 sizeof (cmrp->mrp_pool));
4390 if (nmrp->mrp_mask & MRP_PROTECT)
4391 mac_protect_update(nmrp, cmrp);
4394 * Update the rings specified.
4396 if (nmrp->mrp_mask & MRP_RX_RINGS) {
4397 if (nmrp->mrp_mask & MRP_RINGS_RESET) {
4398 cmrp->mrp_mask &= ~MRP_RX_RINGS;
4399 if (cmrp->mrp_mask & MRP_RXRINGS_UNSPEC)
4400 cmrp->mrp_mask &= ~MRP_RXRINGS_UNSPEC;
4401 cmrp->mrp_nrxrings = 0;
4402 } else {
4403 cmrp->mrp_mask |= MRP_RX_RINGS;
4404 cmrp->mrp_nrxrings = nmrp->mrp_nrxrings;
4407 if (nmrp->mrp_mask & MRP_TX_RINGS) {
4408 if (nmrp->mrp_mask & MRP_RINGS_RESET) {
4409 cmrp->mrp_mask &= ~MRP_TX_RINGS;
4410 if (cmrp->mrp_mask & MRP_TXRINGS_UNSPEC)
4411 cmrp->mrp_mask &= ~MRP_TXRINGS_UNSPEC;
4412 cmrp->mrp_ntxrings = 0;
4413 } else {
4414 cmrp->mrp_mask |= MRP_TX_RINGS;
4415 cmrp->mrp_ntxrings = nmrp->mrp_ntxrings;
4418 if (nmrp->mrp_mask & MRP_RXRINGS_UNSPEC)
4419 cmrp->mrp_mask |= MRP_RXRINGS_UNSPEC;
4420 else if (cmrp->mrp_mask & MRP_RXRINGS_UNSPEC)
4421 cmrp->mrp_mask &= ~MRP_RXRINGS_UNSPEC;
4423 if (nmrp->mrp_mask & MRP_TXRINGS_UNSPEC)
4424 cmrp->mrp_mask |= MRP_TXRINGS_UNSPEC;
4425 else if (cmrp->mrp_mask & MRP_TXRINGS_UNSPEC)
4426 cmrp->mrp_mask &= ~MRP_TXRINGS_UNSPEC;
4431 * i_mac_set_resources:
4433 * This routine associates properties with the primary MAC client of
4434 * the specified MAC instance.
4435 * - Cache the properties in mac_impl_t
4436 * - Apply the properties to the primary MAC client if exists
4439 i_mac_set_resources(mac_handle_t mh, mac_resource_props_t *mrp)
4441 mac_impl_t *mip = (mac_impl_t *)mh;
4442 mac_client_impl_t *mcip;
4443 int err = 0;
4444 uint32_t resmask, newresmask;
4445 mac_resource_props_t *tmrp, *umrp;
4447 ASSERT(MAC_PERIM_HELD((mac_handle_t)mip));
4449 err = mac_validate_props(mip, mrp);
4450 if (err != 0)
4451 return (err);
4453 umrp = kmem_zalloc(sizeof (*umrp), KM_SLEEP);
4454 bcopy(&mip->mi_resource_props, umrp, sizeof (*umrp));
4455 resmask = umrp->mrp_mask;
4456 mac_update_resources(mrp, umrp, B_FALSE);
4457 newresmask = umrp->mrp_mask;
4459 if (resmask == 0 && newresmask != 0) {
4461 * Bandwidth, priority, cpu or pool link properties configured,
4462 * must disable fastpath.
4464 if ((err = mac_fastpath_disable((mac_handle_t)mip)) != 0) {
4465 kmem_free(umrp, sizeof (*umrp));
4466 return (err);
4471 * Since bind_cpu may be modified by mac_client_set_resources()
4472 * we use a copy of bind_cpu and finally cache bind_cpu in mip.
4473 * This allows us to cache only user edits in mip.
4475 tmrp = kmem_zalloc(sizeof (*tmrp), KM_SLEEP);
4476 bcopy(mrp, tmrp, sizeof (*tmrp));
4477 mcip = mac_primary_client_handle(mip);
4478 if (mcip != NULL && (mcip->mci_state_flags & MCIS_IS_AGGR_PORT) == 0) {
4479 err = mac_client_set_resources((mac_client_handle_t)mcip, tmrp);
4480 } else if ((mrp->mrp_mask & MRP_RX_RINGS ||
4481 mrp->mrp_mask & MRP_TX_RINGS)) {
4482 mac_client_impl_t *vmcip;
4485 * If the primary is not up, we need to check if there
4486 * are any VLANs on this primary. If there are then
4487 * we need to set this property on the VLANs since
4488 * VLANs follow the primary they are based on. Just
4489 * look for the first VLAN and change its properties,
4490 * all the other VLANs should be in the same group.
4492 for (vmcip = mip->mi_clients_list; vmcip != NULL;
4493 vmcip = vmcip->mci_client_next) {
4494 if ((vmcip->mci_flent->fe_type & FLOW_PRIMARY_MAC) &&
4495 mac_client_vid((mac_client_handle_t)vmcip) !=
4496 VLAN_ID_NONE) {
4497 break;
4500 if (vmcip != NULL) {
4501 mac_resource_props_t *omrp;
4502 mac_resource_props_t *vmrp;
4504 omrp = kmem_zalloc(sizeof (*omrp), KM_SLEEP);
4505 bcopy(MCIP_RESOURCE_PROPS(vmcip), omrp, sizeof (*omrp));
4507 * We dont' call mac_update_resources since we
4508 * want to take only the ring properties and
4509 * not all the properties that may have changed.
4511 vmrp = MCIP_RESOURCE_PROPS(vmcip);
4512 if (mrp->mrp_mask & MRP_RX_RINGS) {
4513 if (mrp->mrp_mask & MRP_RINGS_RESET) {
4514 vmrp->mrp_mask &= ~MRP_RX_RINGS;
4515 if (vmrp->mrp_mask &
4516 MRP_RXRINGS_UNSPEC) {
4517 vmrp->mrp_mask &=
4518 ~MRP_RXRINGS_UNSPEC;
4520 vmrp->mrp_nrxrings = 0;
4521 } else {
4522 vmrp->mrp_mask |= MRP_RX_RINGS;
4523 vmrp->mrp_nrxrings = mrp->mrp_nrxrings;
4526 if (mrp->mrp_mask & MRP_TX_RINGS) {
4527 if (mrp->mrp_mask & MRP_RINGS_RESET) {
4528 vmrp->mrp_mask &= ~MRP_TX_RINGS;
4529 if (vmrp->mrp_mask &
4530 MRP_TXRINGS_UNSPEC) {
4531 vmrp->mrp_mask &=
4532 ~MRP_TXRINGS_UNSPEC;
4534 vmrp->mrp_ntxrings = 0;
4535 } else {
4536 vmrp->mrp_mask |= MRP_TX_RINGS;
4537 vmrp->mrp_ntxrings = mrp->mrp_ntxrings;
4540 if (mrp->mrp_mask & MRP_RXRINGS_UNSPEC)
4541 vmrp->mrp_mask |= MRP_RXRINGS_UNSPEC;
4543 if (mrp->mrp_mask & MRP_TXRINGS_UNSPEC)
4544 vmrp->mrp_mask |= MRP_TXRINGS_UNSPEC;
4546 if ((err = mac_client_set_rings_prop(vmcip, mrp,
4547 omrp)) != 0) {
4548 bcopy(omrp, MCIP_RESOURCE_PROPS(vmcip),
4549 sizeof (*omrp));
4550 } else {
4551 mac_set_prim_vlan_rings(mip, vmrp);
4553 kmem_free(omrp, sizeof (*omrp));
4557 /* Only update the values if mac_client_set_resources succeeded */
4558 if (err == 0) {
4559 bcopy(umrp, &mip->mi_resource_props, sizeof (*umrp));
4561 * If bandwidth, priority or cpu link properties cleared,
4562 * renable fastpath.
4564 if (resmask != 0 && newresmask == 0)
4565 mac_fastpath_enable((mac_handle_t)mip);
4566 } else if (resmask == 0 && newresmask != 0) {
4567 mac_fastpath_enable((mac_handle_t)mip);
4569 kmem_free(tmrp, sizeof (*tmrp));
4570 kmem_free(umrp, sizeof (*umrp));
4571 return (err);
4575 mac_set_resources(mac_handle_t mh, mac_resource_props_t *mrp)
4577 int err;
4579 i_mac_perim_enter((mac_impl_t *)mh);
4580 err = i_mac_set_resources(mh, mrp);
4581 i_mac_perim_exit((mac_impl_t *)mh);
4582 return (err);
4586 * Get the properties cached for the specified MAC instance.
4588 void
4589 mac_get_resources(mac_handle_t mh, mac_resource_props_t *mrp)
4591 mac_impl_t *mip = (mac_impl_t *)mh;
4592 mac_client_impl_t *mcip;
4594 mcip = mac_primary_client_handle(mip);
4595 if (mcip != NULL) {
4596 mac_client_get_resources((mac_client_handle_t)mcip, mrp);
4597 return;
4599 bcopy(&mip->mi_resource_props, mrp, sizeof (mac_resource_props_t));
4603 * Get the effective properties from the primary client of the
4604 * specified MAC instance.
4606 void
4607 mac_get_effective_resources(mac_handle_t mh, mac_resource_props_t *mrp)
4609 mac_impl_t *mip = (mac_impl_t *)mh;
4610 mac_client_impl_t *mcip;
4612 mcip = mac_primary_client_handle(mip);
4613 if (mcip != NULL) {
4614 mac_client_get_effective_resources((mac_client_handle_t)mcip,
4615 mrp);
4616 return;
4618 bzero(mrp, sizeof (mac_resource_props_t));
4622 mac_set_pvid(mac_handle_t mh, uint16_t pvid)
4624 mac_impl_t *mip = (mac_impl_t *)mh;
4625 mac_client_impl_t *mcip;
4626 mac_unicast_impl_t *muip;
4628 i_mac_perim_enter(mip);
4629 if (pvid != 0) {
4630 for (mcip = mip->mi_clients_list; mcip != NULL;
4631 mcip = mcip->mci_client_next) {
4632 for (muip = mcip->mci_unicast_list; muip != NULL;
4633 muip = muip->mui_next) {
4634 if (muip->mui_vid == pvid) {
4635 i_mac_perim_exit(mip);
4636 return (EBUSY);
4641 mip->mi_pvid = pvid;
4642 i_mac_perim_exit(mip);
4643 return (0);
4646 uint16_t
4647 mac_get_pvid(mac_handle_t mh)
4649 mac_impl_t *mip = (mac_impl_t *)mh;
4651 return (mip->mi_pvid);
4654 uint32_t
4655 mac_get_llimit(mac_handle_t mh)
4657 mac_impl_t *mip = (mac_impl_t *)mh;
4659 return (mip->mi_llimit);
4662 uint32_t
4663 mac_get_ldecay(mac_handle_t mh)
4665 mac_impl_t *mip = (mac_impl_t *)mh;
4667 return (mip->mi_ldecay);
4671 * Rename a mac client, its flow, and the kstat.
4674 mac_rename_primary(mac_handle_t mh, const char *new_name)
4676 mac_impl_t *mip = (mac_impl_t *)mh;
4677 mac_client_impl_t *cur_clnt = NULL;
4678 flow_entry_t *fep;
4680 i_mac_perim_enter(mip);
4683 * VNICs: we need to change the sys flow name and
4684 * the associated flow kstat.
4686 if (mip->mi_state_flags & MIS_IS_VNIC) {
4687 mac_client_impl_t *mcip = mac_vnic_lower(mip);
4688 ASSERT(new_name != NULL);
4689 mac_rename_flow_names(mcip, new_name);
4690 mac_stat_rename(mcip);
4691 goto done;
4694 * This mac may itself be an aggr link, or it may have some client
4695 * which is an aggr port. For both cases, we need to change the
4696 * aggr port's mac client name, its flow name and the associated flow
4697 * kstat.
4699 if (mip->mi_state_flags & MIS_IS_AGGR) {
4700 mac_capab_aggr_t aggr_cap;
4701 mac_rename_fn_t rename_fn;
4702 boolean_t ret;
4704 ASSERT(new_name != NULL);
4705 ret = i_mac_capab_get((mac_handle_t)mip, MAC_CAPAB_AGGR,
4706 (void *)(&aggr_cap));
4707 ASSERT(ret == B_TRUE);
4708 rename_fn = aggr_cap.mca_rename_fn;
4709 rename_fn(new_name, mip->mi_driver);
4711 * The aggr's client name and kstat flow name will be
4712 * updated below, i.e. via mac_rename_flow_names.
4716 for (cur_clnt = mip->mi_clients_list; cur_clnt != NULL;
4717 cur_clnt = cur_clnt->mci_client_next) {
4718 if (cur_clnt->mci_state_flags & MCIS_IS_AGGR_PORT) {
4719 if (new_name != NULL) {
4720 char *str_st = cur_clnt->mci_name;
4721 char *str_del = strchr(str_st, '-');
4723 ASSERT(str_del != NULL);
4724 bzero(str_del + 1, MAXNAMELEN -
4725 (str_del - str_st + 1));
4726 bcopy(new_name, str_del + 1,
4727 strlen(new_name));
4729 fep = cur_clnt->mci_flent;
4730 mac_rename_flow(fep, cur_clnt->mci_name);
4731 break;
4732 } else if (new_name != NULL &&
4733 cur_clnt->mci_state_flags & MCIS_USE_DATALINK_NAME) {
4734 mac_rename_flow_names(cur_clnt, new_name);
4735 break;
4739 /* Recreate kstats associated with aggr pseudo rings */
4740 if (mip->mi_state_flags & MIS_IS_AGGR)
4741 mac_pseudo_ring_stat_rename(mip);
4743 done:
4744 i_mac_perim_exit(mip);
4745 return (0);
4749 * Rename the MAC client's flow names
4751 static void
4752 mac_rename_flow_names(mac_client_impl_t *mcip, const char *new_name)
4754 flow_entry_t *flent;
4755 uint16_t vid;
4756 char flowname[MAXFLOWNAMELEN];
4757 mac_impl_t *mip = mcip->mci_mip;
4759 ASSERT(MAC_PERIM_HELD((mac_handle_t)mip));
4762 * Use mi_rw_lock to ensure that threads not in the mac perimeter
4763 * see a self-consistent value for mci_name
4765 rw_enter(&mip->mi_rw_lock, RW_WRITER);
4766 (void) strlcpy(mcip->mci_name, new_name, sizeof (mcip->mci_name));
4767 rw_exit(&mip->mi_rw_lock);
4769 mac_rename_flow(mcip->mci_flent, new_name);
4771 if (mcip->mci_nflents == 1)
4772 return;
4775 * We have to rename all the others too, no stats to destroy for
4776 * these.
4778 for (flent = mcip->mci_flent_list; flent != NULL;
4779 flent = flent->fe_client_next) {
4780 if (flent != mcip->mci_flent) {
4781 vid = i_mac_flow_vid(flent);
4782 (void) sprintf(flowname, "%s%u", new_name, vid);
4783 mac_flow_set_name(flent, flowname);
4790 * Add a flow to the MAC client's flow list - i.e list of MAC/VID tuples
4791 * defined for the specified MAC client.
4793 static void
4794 mac_client_add_to_flow_list(mac_client_impl_t *mcip, flow_entry_t *flent)
4796 ASSERT(MAC_PERIM_HELD((mac_handle_t)mcip->mci_mip));
4798 * The promisc Rx data path walks the mci_flent_list. Protect by
4799 * using mi_rw_lock
4801 rw_enter(&mcip->mci_rw_lock, RW_WRITER);
4803 /* Add it to the head */
4804 flent->fe_client_next = mcip->mci_flent_list;
4805 mcip->mci_flent_list = flent;
4806 mcip->mci_nflents++;
4809 * Keep track of the number of non-zero VIDs addresses per MAC
4810 * client to avoid figuring it out in the data-path.
4812 if (i_mac_flow_vid(flent) != VLAN_ID_NONE)
4813 mcip->mci_nvids++;
4815 rw_exit(&mcip->mci_rw_lock);
4819 * Remove a flow entry from the MAC client's list.
4821 static void
4822 mac_client_remove_flow_from_list(mac_client_impl_t *mcip, flow_entry_t *flent)
4824 flow_entry_t *fe = mcip->mci_flent_list;
4825 flow_entry_t *prev_fe = NULL;
4827 ASSERT(MAC_PERIM_HELD((mac_handle_t)mcip->mci_mip));
4829 * The promisc Rx data path walks the mci_flent_list. Protect by
4830 * using mci_rw_lock
4832 rw_enter(&mcip->mci_rw_lock, RW_WRITER);
4833 while ((fe != NULL) && (fe != flent)) {
4834 prev_fe = fe;
4835 fe = fe->fe_client_next;
4838 ASSERT(fe != NULL);
4839 if (prev_fe == NULL) {
4840 /* Deleting the first node */
4841 mcip->mci_flent_list = fe->fe_client_next;
4842 } else {
4843 prev_fe->fe_client_next = fe->fe_client_next;
4845 mcip->mci_nflents--;
4847 if (i_mac_flow_vid(flent) != VLAN_ID_NONE)
4848 mcip->mci_nvids--;
4850 rw_exit(&mcip->mci_rw_lock);
4854 * Check if the given VID belongs to this MAC client.
4856 boolean_t
4857 mac_client_check_flow_vid(mac_client_impl_t *mcip, uint16_t vid)
4859 flow_entry_t *flent;
4860 uint16_t mci_vid;
4862 /* The mci_flent_list is protected by mci_rw_lock */
4863 rw_enter(&mcip->mci_rw_lock, RW_WRITER);
4864 for (flent = mcip->mci_flent_list; flent != NULL;
4865 flent = flent->fe_client_next) {
4866 mci_vid = i_mac_flow_vid(flent);
4867 if (vid == mci_vid) {
4868 rw_exit(&mcip->mci_rw_lock);
4869 return (B_TRUE);
4872 rw_exit(&mcip->mci_rw_lock);
4873 return (B_FALSE);
4877 * Get the flow entry for the specified <MAC addr, VID> tuple.
4879 static flow_entry_t *
4880 mac_client_get_flow(mac_client_impl_t *mcip, mac_unicast_impl_t *muip)
4882 mac_address_t *map = mcip->mci_unicast;
4883 flow_entry_t *flent;
4884 uint16_t vid;
4885 flow_desc_t flow_desc;
4887 ASSERT(MAC_PERIM_HELD((mac_handle_t)mcip->mci_mip));
4889 mac_flow_get_desc(mcip->mci_flent, &flow_desc);
4890 if (bcmp(flow_desc.fd_dst_mac, map->ma_addr, map->ma_len) != 0)
4891 return (NULL);
4893 for (flent = mcip->mci_flent_list; flent != NULL;
4894 flent = flent->fe_client_next) {
4895 vid = i_mac_flow_vid(flent);
4896 if (vid == muip->mui_vid) {
4897 return (flent);
4901 return (NULL);
4905 * Since mci_flent has the SRSs, when we want to remove it, we replace
4906 * the flow_desc_t in mci_flent with that of an existing flent and then
4907 * remove that flent instead of mci_flent.
4909 static flow_entry_t *
4910 mac_client_swap_mciflent(mac_client_impl_t *mcip)
4912 flow_entry_t *flent = mcip->mci_flent;
4913 flow_tab_t *ft = flent->fe_flow_tab;
4914 flow_entry_t *flent1;
4915 flow_desc_t fl_desc;
4916 char fl_name[MAXFLOWNAMELEN];
4917 int err;
4919 ASSERT(MAC_PERIM_HELD((mac_handle_t)mcip->mci_mip));
4920 ASSERT(mcip->mci_nflents > 1);
4922 /* get the next flent following the primary flent */
4923 flent1 = mcip->mci_flent_list->fe_client_next;
4924 ASSERT(flent1 != NULL && flent1->fe_flow_tab == ft);
4927 * Remove the flent from the flow table before updating the
4928 * flow descriptor as the hash depends on the flow descriptor.
4929 * This also helps incoming packet classification avoid having
4930 * to grab fe_lock. Access to fe_flow_desc of a flent not in the
4931 * flow table is done under the fe_lock so that log or stat functions
4932 * see a self-consistent fe_flow_desc. The name and desc are specific
4933 * to a flow, the rest are shared by all the clients, including
4934 * resource control etc.
4936 mac_flow_remove(ft, flent, B_TRUE);
4937 mac_flow_remove(ft, flent1, B_TRUE);
4939 bcopy(&flent->fe_flow_desc, &fl_desc, sizeof (flow_desc_t));
4940 bcopy(flent->fe_flow_name, fl_name, MAXFLOWNAMELEN);
4942 /* update the primary flow entry */
4943 mutex_enter(&flent->fe_lock);
4944 bcopy(&flent1->fe_flow_desc, &flent->fe_flow_desc,
4945 sizeof (flow_desc_t));
4946 bcopy(&flent1->fe_flow_name, &flent->fe_flow_name, MAXFLOWNAMELEN);
4947 mutex_exit(&flent->fe_lock);
4949 /* update the flow entry that is to be freed */
4950 mutex_enter(&flent1->fe_lock);
4951 bcopy(&fl_desc, &flent1->fe_flow_desc, sizeof (flow_desc_t));
4952 bcopy(fl_name, &flent1->fe_flow_name, MAXFLOWNAMELEN);
4953 mutex_exit(&flent1->fe_lock);
4955 /* now reinsert the flow entries in the table */
4956 err = mac_flow_add(ft, flent);
4957 ASSERT(err == 0);
4959 err = mac_flow_add(ft, flent1);
4960 ASSERT(err == 0);
4962 return (flent1);
4966 * Return whether there is only one flow entry associated with this
4967 * MAC client.
4969 static boolean_t
4970 mac_client_single_rcvr(mac_client_impl_t *mcip)
4972 return (mcip->mci_nflents == 1);
4976 mac_validate_props(mac_impl_t *mip, mac_resource_props_t *mrp)
4978 boolean_t reset;
4979 uint32_t rings_needed;
4980 uint32_t rings_avail;
4981 mac_group_type_t gtype;
4982 mac_resource_props_t *mip_mrp;
4984 if (mrp == NULL)
4985 return (0);
4987 if (mrp->mrp_mask & MRP_PRIORITY) {
4988 mac_priority_level_t pri = mrp->mrp_priority;
4990 if (pri < MPL_LOW || pri > MPL_RESET)
4991 return (EINVAL);
4994 if (mrp->mrp_mask & MRP_MAXBW) {
4995 uint64_t maxbw = mrp->mrp_maxbw;
4997 if (maxbw < MRP_MAXBW_MINVAL && maxbw != 0)
4998 return (EINVAL);
5000 if (mrp->mrp_mask & MRP_CPUS) {
5001 int i, j;
5002 mac_cpu_mode_t fanout;
5004 if (mrp->mrp_ncpus > ncpus)
5005 return (EINVAL);
5007 for (i = 0; i < mrp->mrp_ncpus; i++) {
5008 for (j = 0; j < mrp->mrp_ncpus; j++) {
5009 if (i != j &&
5010 mrp->mrp_cpu[i] == mrp->mrp_cpu[j]) {
5011 return (EINVAL);
5016 for (i = 0; i < mrp->mrp_ncpus; i++) {
5017 cpu_t *cp;
5018 int rv;
5020 mutex_enter(&cpu_lock);
5021 cp = cpu_get(mrp->mrp_cpu[i]);
5022 if (cp != NULL)
5023 rv = cpu_is_online(cp);
5024 else
5025 rv = 0;
5026 mutex_exit(&cpu_lock);
5027 if (rv == 0)
5028 return (EINVAL);
5031 fanout = mrp->mrp_fanout_mode;
5032 if (fanout < 0 || fanout > MCM_CPUS)
5033 return (EINVAL);
5036 if (mrp->mrp_mask & MRP_PROTECT) {
5037 int err = mac_protect_validate(mrp);
5038 if (err != 0)
5039 return (err);
5042 if (!(mrp->mrp_mask & MRP_RX_RINGS) &&
5043 !(mrp->mrp_mask & MRP_TX_RINGS)) {
5044 return (0);
5048 * mip will be null when we come from mac_flow_create or
5049 * mac_link_flow_modify. In the latter case it is a user flow,
5050 * for which we don't support rings. In the former we would
5051 * have validated the props beforehand (i_mac_unicast_add ->
5052 * mac_client_set_resources -> validate for the primary and
5053 * vnic_dev_create -> mac_client_set_resources -> validate for
5054 * a vnic.
5056 if (mip == NULL)
5057 return (0);
5060 * We don't support setting rings property for a VNIC that is using a
5061 * primary address (VLAN)
5063 if ((mip->mi_state_flags & MIS_IS_VNIC) &&
5064 mac_is_vnic_primary((mac_handle_t)mip)) {
5065 return (ENOTSUP);
5068 mip_mrp = &mip->mi_resource_props;
5070 * The rings property should be validated against the NICs
5071 * resources
5073 if (mip->mi_state_flags & MIS_IS_VNIC)
5074 mip = (mac_impl_t *)mac_get_lower_mac_handle((mac_handle_t)mip);
5076 reset = mrp->mrp_mask & MRP_RINGS_RESET;
5078 * If groups are not supported, return error.
5080 if (((mrp->mrp_mask & MRP_RX_RINGS) && mip->mi_rx_groups == NULL) ||
5081 ((mrp->mrp_mask & MRP_TX_RINGS) && mip->mi_tx_groups == NULL)) {
5082 return (EINVAL);
5085 * If we are just resetting, there is no validation needed.
5087 if (reset)
5088 return (0);
5090 if (mrp->mrp_mask & MRP_RX_RINGS) {
5091 rings_needed = mrp->mrp_nrxrings;
5093 * We just want to check if the number of additional
5094 * rings requested is available.
5096 if (mip_mrp->mrp_mask & MRP_RX_RINGS) {
5097 if (mrp->mrp_nrxrings > mip_mrp->mrp_nrxrings)
5098 /* Just check for the additional rings */
5099 rings_needed -= mip_mrp->mrp_nrxrings;
5100 else
5101 /* We are not asking for additional rings */
5102 rings_needed = 0;
5104 rings_avail = mip->mi_rxrings_avail;
5105 gtype = mip->mi_rx_group_type;
5106 } else {
5107 rings_needed = mrp->mrp_ntxrings;
5108 /* Similarly for the TX rings */
5109 if (mip_mrp->mrp_mask & MRP_TX_RINGS) {
5110 if (mrp->mrp_ntxrings > mip_mrp->mrp_ntxrings)
5111 /* Just check for the additional rings */
5112 rings_needed -= mip_mrp->mrp_ntxrings;
5113 else
5114 /* We are not asking for additional rings */
5115 rings_needed = 0;
5117 rings_avail = mip->mi_txrings_avail;
5118 gtype = mip->mi_tx_group_type;
5121 /* Error if the group is dynamic .. */
5122 if (gtype == MAC_GROUP_TYPE_DYNAMIC) {
5124 * .. and rings specified are more than available.
5126 if (rings_needed > rings_avail)
5127 return (EINVAL);
5128 } else {
5130 * OR group is static and we have specified some rings.
5132 if (rings_needed > 0)
5133 return (EINVAL);
5135 return (0);
5139 * Send a MAC_NOTE_LINK notification to all the MAC clients whenever the
5140 * underlying physical link is down. This is to allow MAC clients to
5141 * communicate with other clients.
5143 void
5144 mac_virtual_link_update(mac_impl_t *mip)
5146 if (mip->mi_linkstate != LINK_STATE_UP)
5147 i_mac_notify(mip, MAC_NOTE_LINK);
5151 * For clients that have a pass-thru MAC, e.g. VNIC, we set the VNIC's
5152 * mac handle in the client.
5154 void
5155 mac_set_upper_mac(mac_client_handle_t mch, mac_handle_t mh,
5156 mac_resource_props_t *mrp)
5158 mac_client_impl_t *mcip = (mac_client_impl_t *)mch;
5159 mac_impl_t *mip = (mac_impl_t *)mh;
5161 mcip->mci_upper_mip = mip;
5162 /* If there are any properties, copy it over too */
5163 if (mrp != NULL) {
5164 bcopy(mrp, &mip->mi_resource_props,
5165 sizeof (mac_resource_props_t));
5170 * Mark the mac as being used exclusively by the single mac client that is
5171 * doing some control operation on this mac. No further opens of this mac
5172 * will be allowed until this client calls mac_unmark_exclusive. The mac
5173 * client calling this function must already be in the mac perimeter
5176 mac_mark_exclusive(mac_handle_t mh)
5178 mac_impl_t *mip = (mac_impl_t *)mh;
5180 ASSERT(MAC_PERIM_HELD(mh));
5182 * Look up its entry in the global hash table.
5184 rw_enter(&i_mac_impl_lock, RW_WRITER);
5185 if (mip->mi_state_flags & MIS_DISABLED) {
5186 rw_exit(&i_mac_impl_lock);
5187 return (ENOENT);
5191 * A reference to mac is held even if the link is not plumbed.
5192 * In i_dls_link_create() we open the MAC interface and hold the
5193 * reference. There is an additional reference for the mac_open
5194 * done in acquiring the mac perimeter
5196 if (mip->mi_ref != 2) {
5197 rw_exit(&i_mac_impl_lock);
5198 return (EBUSY);
5201 ASSERT(!(mip->mi_state_flags & MIS_EXCLUSIVE_HELD));
5202 mip->mi_state_flags |= MIS_EXCLUSIVE_HELD;
5203 rw_exit(&i_mac_impl_lock);
5204 return (0);
5207 void
5208 mac_unmark_exclusive(mac_handle_t mh)
5210 mac_impl_t *mip = (mac_impl_t *)mh;
5212 ASSERT(MAC_PERIM_HELD(mh));
5214 rw_enter(&i_mac_impl_lock, RW_WRITER);
5215 /* 1 for the creation and another for the perimeter */
5216 ASSERT(mip->mi_ref == 2 && (mip->mi_state_flags & MIS_EXCLUSIVE_HELD));
5217 mip->mi_state_flags &= ~MIS_EXCLUSIVE_HELD;
5218 rw_exit(&i_mac_impl_lock);
5222 * Set the MTU for the specified MAC.
5225 mac_set_mtu(mac_handle_t mh, uint_t new_mtu, uint_t *old_mtu_arg)
5227 mac_impl_t *mip = (mac_impl_t *)mh;
5228 uint_t old_mtu;
5229 int rv = 0;
5231 i_mac_perim_enter(mip);
5233 if (!(mip->mi_callbacks->mc_callbacks & (MC_SETPROP|MC_GETPROP))) {
5234 rv = ENOTSUP;
5235 goto bail;
5238 old_mtu = mip->mi_sdu_max;
5240 if (new_mtu == 0 || new_mtu < mip->mi_sdu_min) {
5241 rv = EINVAL;
5242 goto bail;
5245 if (old_mtu != new_mtu) {
5246 rv = mip->mi_callbacks->mc_setprop(mip->mi_driver,
5247 "mtu", MAC_PROP_MTU, sizeof (uint_t), &new_mtu);
5248 if (rv != 0)
5249 goto bail;
5250 rv = mac_maxsdu_update(mh, new_mtu);
5251 ASSERT(rv == 0);
5254 bail:
5255 i_mac_perim_exit(mip);
5257 if (rv == 0 && old_mtu_arg != NULL)
5258 *old_mtu_arg = old_mtu;
5259 return (rv);
5263 * Return the RX h/w information for the group indexed by grp_num.
5265 void
5266 mac_get_hwrxgrp_info(mac_handle_t mh, int grp_index, uint_t *grp_num,
5267 uint_t *n_rings, uint_t *rings, uint_t *type, uint_t *n_clnts,
5268 char *clnts_name)
5270 mac_impl_t *mip = (mac_impl_t *)mh;
5271 mac_grp_client_t *mcip;
5272 uint_t i = 0, index = 0;
5273 mac_ring_t *ring;
5275 /* Revisit when we implement fully dynamic group allocation */
5276 ASSERT(grp_index >= 0 && grp_index < mip->mi_rx_group_count);
5278 rw_enter(&mip->mi_rw_lock, RW_READER);
5279 *grp_num = mip->mi_rx_groups[grp_index].mrg_index;
5280 *type = mip->mi_rx_groups[grp_index].mrg_type;
5281 *n_rings = mip->mi_rx_groups[grp_index].mrg_cur_count;
5282 ring = mip->mi_rx_groups[grp_index].mrg_rings;
5283 for (index = 0; index < mip->mi_rx_groups[grp_index].mrg_cur_count;
5284 index++) {
5285 rings[index] = ring->mr_index;
5286 ring = ring->mr_next;
5288 /* Assuming the 1st is the default group */
5289 index = 0;
5290 if (grp_index == 0) {
5291 (void) strlcpy(clnts_name, "<default,mcast>,",
5292 MAXCLIENTNAMELEN);
5293 index += strlen("<default,mcast>,");
5295 for (mcip = mip->mi_rx_groups[grp_index].mrg_clients; mcip != NULL;
5296 mcip = mcip->mgc_next) {
5297 int name_len = strlen(mcip->mgc_client->mci_name);
5300 * MAXCLIENTNAMELEN is the buffer size reserved for client
5301 * names.
5302 * XXXX Formating the client name string needs to be moved
5303 * to user land when fixing the size of dhi_clnts in
5304 * dld_hwgrpinfo_t. We should use n_clients * client_name for
5305 * dhi_clntsin instead of MAXCLIENTNAMELEN
5307 if (index + name_len >= MAXCLIENTNAMELEN) {
5308 index = MAXCLIENTNAMELEN;
5309 break;
5311 bcopy(mcip->mgc_client->mci_name, &(clnts_name[index]),
5312 name_len);
5313 index += name_len;
5314 clnts_name[index++] = ',';
5315 i++;
5318 /* Get rid of the last , */
5319 if (index > 0)
5320 clnts_name[index - 1] = '\0';
5321 *n_clnts = i;
5322 rw_exit(&mip->mi_rw_lock);
5326 * Return the TX h/w information for the group indexed by grp_num.
5328 void
5329 mac_get_hwtxgrp_info(mac_handle_t mh, int grp_index, uint_t *grp_num,
5330 uint_t *n_rings, uint_t *rings, uint_t *type, uint_t *n_clnts,
5331 char *clnts_name)
5333 mac_impl_t *mip = (mac_impl_t *)mh;
5334 mac_grp_client_t *mcip;
5335 uint_t i = 0, index = 0;
5336 mac_ring_t *ring;
5338 /* Revisit when we implement fully dynamic group allocation */
5339 ASSERT(grp_index >= 0 && grp_index <= mip->mi_tx_group_count);
5341 rw_enter(&mip->mi_rw_lock, RW_READER);
5342 *grp_num = mip->mi_tx_groups[grp_index].mrg_index > 0 ?
5343 mip->mi_tx_groups[grp_index].mrg_index : grp_index;
5344 *type = mip->mi_tx_groups[grp_index].mrg_type;
5345 *n_rings = mip->mi_tx_groups[grp_index].mrg_cur_count;
5346 ring = mip->mi_tx_groups[grp_index].mrg_rings;
5347 for (index = 0; index < mip->mi_tx_groups[grp_index].mrg_cur_count;
5348 index++) {
5349 rings[index] = ring->mr_index;
5350 ring = ring->mr_next;
5352 index = 0;
5353 /* Default group has an index of -1 */
5354 if (mip->mi_tx_groups[grp_index].mrg_index < 0) {
5355 (void) strlcpy(clnts_name, "<default>,",
5356 MAXCLIENTNAMELEN);
5357 index += strlen("<default>,");
5359 for (mcip = mip->mi_tx_groups[grp_index].mrg_clients; mcip != NULL;
5360 mcip = mcip->mgc_next) {
5361 int name_len = strlen(mcip->mgc_client->mci_name);
5364 * MAXCLIENTNAMELEN is the buffer size reserved for client
5365 * names.
5366 * XXXX Formating the client name string needs to be moved
5367 * to user land when fixing the size of dhi_clnts in
5368 * dld_hwgrpinfo_t. We should use n_clients * client_name for
5369 * dhi_clntsin instead of MAXCLIENTNAMELEN
5371 if (index + name_len >= MAXCLIENTNAMELEN) {
5372 index = MAXCLIENTNAMELEN;
5373 break;
5375 bcopy(mcip->mgc_client->mci_name, &(clnts_name[index]),
5376 name_len);
5377 index += name_len;
5378 clnts_name[index++] = ',';
5379 i++;
5382 /* Get rid of the last , */
5383 if (index > 0)
5384 clnts_name[index - 1] = '\0';
5385 *n_clnts = i;
5386 rw_exit(&mip->mi_rw_lock);
5390 * Return the group count for RX or TX.
5392 uint_t
5393 mac_hwgrp_num(mac_handle_t mh, int type)
5395 mac_impl_t *mip = (mac_impl_t *)mh;
5398 * Return the Rx and Tx group count; for the Tx we need to
5399 * include the default too.
5401 return (type == MAC_RING_TYPE_RX ? mip->mi_rx_group_count :
5402 mip->mi_tx_groups != NULL ? mip->mi_tx_group_count + 1 : 0);
5406 * The total number of free TX rings for this MAC.
5408 uint_t
5409 mac_txavail_get(mac_handle_t mh)
5411 mac_impl_t *mip = (mac_impl_t *)mh;
5413 return (mip->mi_txrings_avail);
5417 * The total number of free RX rings for this MAC.
5419 uint_t
5420 mac_rxavail_get(mac_handle_t mh)
5422 mac_impl_t *mip = (mac_impl_t *)mh;
5424 return (mip->mi_rxrings_avail);
5428 * The total number of reserved RX rings on this MAC.
5430 uint_t
5431 mac_rxrsvd_get(mac_handle_t mh)
5433 mac_impl_t *mip = (mac_impl_t *)mh;
5435 return (mip->mi_rxrings_rsvd);
5439 * The total number of reserved TX rings on this MAC.
5441 uint_t
5442 mac_txrsvd_get(mac_handle_t mh)
5444 mac_impl_t *mip = (mac_impl_t *)mh;
5446 return (mip->mi_txrings_rsvd);
5450 * Total number of free RX groups on this MAC.
5452 uint_t
5453 mac_rxhwlnksavail_get(mac_handle_t mh)
5455 mac_impl_t *mip = (mac_impl_t *)mh;
5457 return (mip->mi_rxhwclnt_avail);
5461 * Total number of RX groups reserved on this MAC.
5463 uint_t
5464 mac_rxhwlnksrsvd_get(mac_handle_t mh)
5466 mac_impl_t *mip = (mac_impl_t *)mh;
5468 return (mip->mi_rxhwclnt_used);
5472 * Total number of free TX groups on this MAC.
5474 uint_t
5475 mac_txhwlnksavail_get(mac_handle_t mh)
5477 mac_impl_t *mip = (mac_impl_t *)mh;
5479 return (mip->mi_txhwclnt_avail);
5483 * Total number of TX groups reserved on this MAC.
5485 uint_t
5486 mac_txhwlnksrsvd_get(mac_handle_t mh)
5488 mac_impl_t *mip = (mac_impl_t *)mh;
5490 return (mip->mi_txhwclnt_used);
5494 * Initialize the rings property for a mac client. A non-0 value for
5495 * rxring or txring specifies the number of rings required, a value
5496 * of MAC_RXRINGS_NONE/MAC_TXRINGS_NONE specifies that it doesn't need
5497 * any RX/TX rings and a value of MAC_RXRINGS_DONTCARE/MAC_TXRINGS_DONTCARE
5498 * means the system can decide whether it can give any rings or not.
5500 void
5501 mac_client_set_rings(mac_client_handle_t mch, int rxrings, int txrings)
5503 mac_client_impl_t *mcip = (mac_client_impl_t *)mch;
5504 mac_resource_props_t *mrp = MCIP_RESOURCE_PROPS(mcip);
5506 if (rxrings != MAC_RXRINGS_DONTCARE) {
5507 mrp->mrp_mask |= MRP_RX_RINGS;
5508 mrp->mrp_nrxrings = rxrings;
5511 if (txrings != MAC_TXRINGS_DONTCARE) {
5512 mrp->mrp_mask |= MRP_TX_RINGS;
5513 mrp->mrp_ntxrings = txrings;