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]
23 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright (c) 2014, Joyent, Inc. All rights reserved.
25 * Copyright 2017 RackTop Systems.
29 * - General Introduction:
31 * This file contains the implementation of the MAC client kernel
32 * API and related code. The MAC client API allows a kernel module
33 * to gain access to a MAC instance (physical NIC, link aggregation, etc).
34 * It allows a MAC client to associate itself with a MAC address,
35 * VLANs, callback functions for data traffic and for promiscuous mode.
36 * The MAC client API is also used to specify the properties associated
37 * with a MAC client, such as bandwidth limits, priority, CPUS, etc.
38 * These properties are further used to determine the hardware resources
39 * to allocate to the various MAC clients.
41 * - Primary MAC clients:
43 * The MAC client API refers to "primary MAC clients". A primary MAC
44 * client is a client which "owns" the primary MAC address of
45 * the underlying MAC instance. The primary MAC address is called out
46 * since it is associated with specific semantics: the primary MAC
47 * address is the MAC address which is assigned to the IP interface
48 * when it is plumbed, and the primary MAC address is assigned
49 * to VLAN data-links. The primary address of a MAC instance can
50 * also change dynamically from under the MAC client, for example
51 * as a result of a change of state of a link aggregation. In that
52 * case the MAC layer automatically updates all data-structures which
53 * refer to the current value of the primary MAC address. Typical
54 * primary MAC clients are dls, aggr, and xnb. A typical non-primary
55 * MAC client is the vnic driver.
57 * - Virtual Switching:
59 * The MAC layer implements a virtual switch between the MAC clients
60 * (primary and non-primary) defined on top of the same underlying
61 * NIC (physical, link aggregation, etc). The virtual switch is
62 * VLAN-aware, i.e. it allows multiple MAC clients to be member
63 * of one or more VLANs, and the virtual switch will distribute
64 * multicast tagged packets only to the member of the corresponding
67 * - Upper vs Lower MAC:
69 * Creating a VNIC on top of a MAC instance effectively causes
70 * two MAC instances to be layered on top of each other, one for
71 * the VNIC(s), one for the underlying MAC instance (physical NIC,
72 * link aggregation, etc). In the code below we refer to the
73 * underlying NIC as the "lower MAC", and we refer to VNICs as
76 * - Pass-through for VNICs:
78 * When VNICs are created on top of an underlying MAC, this causes
79 * a layering of two MAC instances. Since the lower MAC already
80 * does the switching and demultiplexing to its MAC clients, the
81 * upper MAC would simply have to pass packets to the layer below
82 * or above it, which would introduce overhead. In order to avoid
83 * this overhead, the MAC layer implements a pass-through mechanism
84 * for VNICs. When a VNIC opens the lower MAC instance, it saves
85 * the MAC client handle it optains from the MAC layer. When a MAC
86 * client opens a VNIC (upper MAC), the MAC layer detects that
87 * the MAC being opened is a VNIC, and gets the MAC client handle
88 * that the VNIC driver obtained from the lower MAC. This exchange
89 * is done through a private capability between the MAC layer
90 * and the VNIC driver. The upper MAC then returns that handle
91 * directly to its MAC client. Any operation done by the upper
92 * MAC client is now done on the lower MAC client handle, which
93 * allows the VNIC driver to be completely bypassed for the
94 * performance sensitive data-path.
96 * - Secondary MACs for VNICs:
98 * VNICs support multiple upper mac clients to enable support for
99 * multiple MAC addresses on the VNIC. When the VNIC is created the
100 * initial mac client is the primary upper mac. Any additional mac
101 * clients are secondary macs. These are kept in sync with the primary
102 * (for things such as the rx function and resource control settings)
103 * using the same private capability interface between the MAC layer
104 * and the VNIC layer.
108 #include <sys/types.h>
109 #include <sys/conf.h>
110 #include <sys/id_space.h>
111 #include <sys/esunddi.h>
112 #include <sys/stat.h>
113 #include <sys/mkdev.h>
114 #include <sys/stream.h>
115 #include <sys/strsun.h>
116 #include <sys/strsubr.h>
117 #include <sys/dlpi.h>
118 #include <sys/modhash.h>
119 #include <sys/mac_impl.h>
120 #include <sys/mac_client_impl.h>
121 #include <sys/mac_soft_ring.h>
122 #include <sys/mac_stat.h>
125 #include <sys/modctl.h>
126 #include <sys/fs/dv_node.h>
127 #include <sys/thread.h>
128 #include <sys/proc.h>
129 #include <sys/callb.h>
130 #include <sys/cpuvar.h>
131 #include <sys/atomic.h>
133 #include <sys/mac_flow.h>
134 #include <sys/ddi_intr_impl.h>
135 #include <sys/disp.h>
137 #include <sys/vnic.h>
138 #include <sys/vnic_impl.h>
139 #include <sys/vlan.h>
141 #include <inet/ip6.h>
142 #include <sys/exacct.h>
143 #include <sys/exacct_impl.h>
145 #include <sys/ethernet.h>
147 kmem_cache_t
*mac_client_impl_cache
;
148 kmem_cache_t
*mac_promisc_impl_cache
;
150 static boolean_t
mac_client_single_rcvr(mac_client_impl_t
*);
151 static flow_entry_t
*mac_client_swap_mciflent(mac_client_impl_t
*);
152 static flow_entry_t
*mac_client_get_flow(mac_client_impl_t
*,
153 mac_unicast_impl_t
*);
154 static void mac_client_remove_flow_from_list(mac_client_impl_t
*,
156 static void mac_client_add_to_flow_list(mac_client_impl_t
*, flow_entry_t
*);
157 static void mac_rename_flow_names(mac_client_impl_t
*, const char *);
158 static void mac_virtual_link_update(mac_impl_t
*);
159 static int mac_client_datapath_setup(mac_client_impl_t
*, uint16_t,
160 uint8_t *, mac_resource_props_t
*, boolean_t
, mac_unicast_impl_t
*);
161 static void mac_client_datapath_teardown(mac_client_handle_t
,
162 mac_unicast_impl_t
*, flow_entry_t
*);
163 static int mac_resource_ctl_set(mac_client_handle_t
, mac_resource_props_t
*);
167 i_mac_client_impl_ctor(void *buf
, void *arg
, int kmflag
)
170 mac_client_impl_t
*mcip
= buf
;
172 bzero(buf
, MAC_CLIENT_IMPL_SIZE
);
173 mutex_init(&mcip
->mci_tx_cb_lock
, NULL
, MUTEX_DRIVER
, NULL
);
174 mcip
->mci_tx_notify_cb_info
.mcbi_lockp
= &mcip
->mci_tx_cb_lock
;
176 ASSERT(mac_tx_percpu_cnt
>= 0);
177 for (i
= 0; i
<= mac_tx_percpu_cnt
; i
++) {
178 mutex_init(&mcip
->mci_tx_pcpu
[i
].pcpu_tx_lock
, NULL
,
181 cv_init(&mcip
->mci_tx_cv
, NULL
, CV_DRIVER
, NULL
);
188 i_mac_client_impl_dtor(void *buf
, void *arg
)
191 mac_client_impl_t
*mcip
= buf
;
193 ASSERT(mcip
->mci_promisc_list
== NULL
);
194 ASSERT(mcip
->mci_unicast_list
== NULL
);
195 ASSERT(mcip
->mci_state_flags
== 0);
196 ASSERT(mcip
->mci_tx_flag
== 0);
198 mutex_destroy(&mcip
->mci_tx_cb_lock
);
200 ASSERT(mac_tx_percpu_cnt
>= 0);
201 for (i
= 0; i
<= mac_tx_percpu_cnt
; i
++) {
202 ASSERT(mcip
->mci_tx_pcpu
[i
].pcpu_tx_refcnt
== 0);
203 mutex_destroy(&mcip
->mci_tx_pcpu
[i
].pcpu_tx_lock
);
205 cv_destroy(&mcip
->mci_tx_cv
);
210 i_mac_promisc_impl_ctor(void *buf
, void *arg
, int kmflag
)
212 mac_promisc_impl_t
*mpip
= buf
;
214 bzero(buf
, sizeof (mac_promisc_impl_t
));
215 mpip
->mpi_mci_link
.mcb_objp
= buf
;
216 mpip
->mpi_mci_link
.mcb_objsize
= sizeof (mac_promisc_impl_t
);
217 mpip
->mpi_mi_link
.mcb_objp
= buf
;
218 mpip
->mpi_mi_link
.mcb_objsize
= sizeof (mac_promisc_impl_t
);
224 i_mac_promisc_impl_dtor(void *buf
, void *arg
)
226 mac_promisc_impl_t
*mpip
= buf
;
228 ASSERT(mpip
->mpi_mci_link
.mcb_objp
!= NULL
);
229 ASSERT(mpip
->mpi_mci_link
.mcb_objsize
== sizeof (mac_promisc_impl_t
));
230 ASSERT(mpip
->mpi_mi_link
.mcb_objp
== mpip
->mpi_mci_link
.mcb_objp
);
231 ASSERT(mpip
->mpi_mi_link
.mcb_objsize
== sizeof (mac_promisc_impl_t
));
233 mpip
->mpi_mci_link
.mcb_objp
= NULL
;
234 mpip
->mpi_mci_link
.mcb_objsize
= 0;
235 mpip
->mpi_mi_link
.mcb_objp
= NULL
;
236 mpip
->mpi_mi_link
.mcb_objsize
= 0;
238 ASSERT(mpip
->mpi_mci_link
.mcb_flags
== 0);
239 mpip
->mpi_mci_link
.mcb_objsize
= 0;
243 mac_client_init(void)
245 ASSERT(mac_tx_percpu_cnt
>= 0);
247 mac_client_impl_cache
= kmem_cache_create("mac_client_impl_cache",
248 MAC_CLIENT_IMPL_SIZE
, 0, i_mac_client_impl_ctor
,
249 i_mac_client_impl_dtor
, NULL
, NULL
, NULL
, 0);
250 ASSERT(mac_client_impl_cache
!= NULL
);
252 mac_promisc_impl_cache
= kmem_cache_create("mac_promisc_impl_cache",
253 sizeof (mac_promisc_impl_t
), 0, i_mac_promisc_impl_ctor
,
254 i_mac_promisc_impl_dtor
, NULL
, NULL
, NULL
, 0);
255 ASSERT(mac_promisc_impl_cache
!= NULL
);
259 mac_client_fini(void)
261 kmem_cache_destroy(mac_client_impl_cache
);
262 kmem_cache_destroy(mac_promisc_impl_cache
);
266 * Return the lower MAC client handle from the VNIC driver for the
267 * specified VNIC MAC instance.
270 mac_vnic_lower(mac_impl_t
*mip
)
272 mac_capab_vnic_t cap
;
273 mac_client_impl_t
*mcip
;
275 VERIFY(i_mac_capab_get((mac_handle_t
)mip
, MAC_CAPAB_VNIC
, &cap
));
276 mcip
= cap
.mcv_mac_client_handle(cap
.mcv_arg
);
282 * Update the secondary macs
285 mac_vnic_secondary_update(mac_impl_t
*mip
)
287 mac_capab_vnic_t cap
;
289 VERIFY(i_mac_capab_get((mac_handle_t
)mip
, MAC_CAPAB_VNIC
, &cap
));
290 cap
.mcv_mac_secondary_update(cap
.mcv_arg
);
294 * Return the MAC client handle of the primary MAC client for the
295 * specified MAC instance, or NULL otherwise.
298 mac_primary_client_handle(mac_impl_t
*mip
)
300 mac_client_impl_t
*mcip
;
302 if (mip
->mi_state_flags
& MIS_IS_VNIC
)
303 return (mac_vnic_lower(mip
));
305 ASSERT(MAC_PERIM_HELD((mac_handle_t
)mip
));
307 for (mcip
= mip
->mi_clients_list
; mcip
!= NULL
;
308 mcip
= mcip
->mci_client_next
) {
309 if (MCIP_DATAPATH_SETUP(mcip
) && mac_is_primary_client(mcip
))
316 * Open a MAC specified by its MAC name.
319 mac_open(const char *macname
, mac_handle_t
*mhp
)
325 * Look up its entry in the global hash table.
327 if ((err
= mac_hold(macname
, &mip
)) != 0)
331 * Hold the dip associated to the MAC to prevent it from being
332 * detached. For a softmac, its underlying dip is held by the
333 * mi_open() callback.
335 * This is done to be more tolerant with some defective drivers,
336 * which incorrectly handle mac_unregister() failure in their
337 * xxx_detach() routine. For example, some drivers ignore the
338 * failure of mac_unregister() and free all resources that
339 * that are needed for data transmition.
341 e_ddi_hold_devi(mip
->mi_dip
);
343 if (!(mip
->mi_callbacks
->mc_callbacks
& MC_OPEN
)) {
344 *mhp
= (mac_handle_t
)mip
;
349 * The mac perimeter is used in both mac_open and mac_close by the
350 * framework to single thread the MC_OPEN/MC_CLOSE of drivers.
352 i_mac_perim_enter(mip
);
354 if (mip
->mi_oref
!= 1 || ((err
= mip
->mi_open(mip
->mi_driver
)) == 0)) {
355 *mhp
= (mac_handle_t
)mip
;
356 i_mac_perim_exit(mip
);
360 ddi_release_devi(mip
->mi_dip
);
362 i_mac_perim_exit(mip
);
367 * Open a MAC specified by its linkid.
370 mac_open_by_linkid(datalink_id_t linkid
, mac_handle_t
*mhp
)
375 if ((err
= dls_devnet_hold_tmp(linkid
, &dlh
)) != 0)
378 dls_devnet_prop_task_wait(dlh
);
380 err
= mac_open(dls_devnet_mac(dlh
), mhp
);
382 dls_devnet_rele_tmp(dlh
);
387 * Open a MAC specified by its link name.
390 mac_open_by_linkname(const char *link
, mac_handle_t
*mhp
)
392 datalink_id_t linkid
;
395 if ((err
= dls_mgmt_get_linkid(link
, &linkid
)) != 0)
397 return (mac_open_by_linkid(linkid
, mhp
));
401 * Close the specified MAC.
404 mac_close(mac_handle_t mh
)
406 mac_impl_t
*mip
= (mac_impl_t
*)mh
;
408 i_mac_perim_enter(mip
);
410 * The mac perimeter is used in both mac_open and mac_close by the
411 * framework to single thread the MC_OPEN/MC_CLOSE of drivers.
413 if (mip
->mi_callbacks
->mc_callbacks
& MC_OPEN
) {
414 ASSERT(mip
->mi_oref
!= 0);
415 if (--mip
->mi_oref
== 0) {
416 if ((mip
->mi_callbacks
->mc_callbacks
& MC_CLOSE
))
417 mip
->mi_close(mip
->mi_driver
);
420 i_mac_perim_exit(mip
);
421 ddi_release_devi(mip
->mi_dip
);
426 * Misc utility functions to retrieve various information about a MAC
427 * instance or a MAC client.
431 mac_info(mac_handle_t mh
)
433 return (&((mac_impl_t
*)mh
)->mi_info
);
437 mac_devinfo_get(mac_handle_t mh
)
439 return (((mac_impl_t
*)mh
)->mi_dip
);
443 mac_driver(mac_handle_t mh
)
445 return (((mac_impl_t
*)mh
)->mi_driver
);
449 mac_name(mac_handle_t mh
)
451 return (((mac_impl_t
*)mh
)->mi_name
);
455 mac_type(mac_handle_t mh
)
457 return (((mac_impl_t
*)mh
)->mi_type
->mt_type
);
461 mac_nativetype(mac_handle_t mh
)
463 return (((mac_impl_t
*)mh
)->mi_type
->mt_nativetype
);
467 mac_client_name(mac_client_handle_t mch
)
469 return (((mac_client_impl_t
*)mch
)->mci_name
);
473 mac_minor(mac_handle_t mh
)
475 return (((mac_impl_t
*)mh
)->mi_minor
);
479 * Return the VID associated with a MAC client. This function should
480 * be called for clients which are associated with only one VID.
483 mac_client_vid(mac_client_handle_t mch
)
485 uint16_t vid
= VLAN_ID_NONE
;
486 mac_client_impl_t
*mcip
= (mac_client_impl_t
*)mch
;
487 flow_desc_t flow_desc
;
489 if (mcip
->mci_nflents
== 0)
492 ASSERT(MCIP_DATAPATH_SETUP(mcip
) && mac_client_single_rcvr(mcip
));
494 mac_flow_get_desc(mcip
->mci_flent
, &flow_desc
);
495 if ((flow_desc
.fd_mask
& FLOW_LINK_VID
) != 0)
496 vid
= flow_desc
.fd_vid
;
502 * Return whether the specified MAC client corresponds to a VLAN VNIC.
505 mac_client_is_vlan_vnic(mac_client_handle_t mch
)
507 mac_client_impl_t
*mcip
= (mac_client_impl_t
*)mch
;
509 return (((mcip
->mci_state_flags
& MCIS_IS_VNIC
) != 0) &&
510 ((mcip
->mci_flent
->fe_type
& FLOW_PRIMARY_MAC
) != 0));
514 * Return the link speed associated with the specified MAC client.
516 * The link speed of a MAC client is equal to the smallest value of
517 * 1) the current link speed of the underlying NIC, or
518 * 2) the bandwidth limit set for the MAC client.
520 * Note that the bandwidth limit can be higher than the speed
521 * of the underlying NIC. This is allowed to avoid spurious
522 * administration action failures or artifically lowering the
523 * bandwidth limit of a link that may have temporarily lowered
524 * its link speed due to hardware problem or administrator action.
527 mac_client_ifspeed(mac_client_impl_t
*mcip
)
529 mac_impl_t
*mip
= mcip
->mci_mip
;
532 nic_speed
= mac_stat_get((mac_handle_t
)mip
, MAC_STAT_IFSPEED
);
534 if (nic_speed
== 0) {
537 uint64_t policy_limit
= (uint64_t)-1;
539 if (MCIP_RESOURCE_PROPS_MASK(mcip
) & MRP_MAXBW
)
540 policy_limit
= MCIP_RESOURCE_PROPS_MAXBW(mcip
);
542 return (MIN(policy_limit
, nic_speed
));
547 * Return the link state of the specified client. If here are more
548 * than one clients of the underying mac_impl_t, the link state
549 * will always be UP regardless of the link state of the underlying
550 * mac_impl_t. This is needed to allow the MAC clients to continue
551 * to communicate with each other even when the physical link of
552 * their mac_impl_t is down.
555 mac_client_link_state(mac_client_impl_t
*mcip
)
557 mac_impl_t
*mip
= mcip
->mci_mip
;
559 mac_client_impl_t
*mci_list
;
560 mac_unicast_impl_t
*mui_list
, *oth_mui_list
;
563 * Returns LINK_STATE_UP if there are other MAC clients defined on
564 * mac_impl_t which share same VLAN ID as that of mcip. Note that
565 * if 'mcip' has more than one VID's then we match ANY one of the
566 * VID's with other MAC client's VID's and return LINK_STATE_UP.
568 rw_enter(&mcip
->mci_rw_lock
, RW_READER
);
569 for (mui_list
= mcip
->mci_unicast_list
; mui_list
!= NULL
;
570 mui_list
= mui_list
->mui_next
) {
571 vid
= mui_list
->mui_vid
;
572 for (mci_list
= mip
->mi_clients_list
; mci_list
!= NULL
;
573 mci_list
= mci_list
->mci_client_next
) {
574 if (mci_list
== mcip
)
576 for (oth_mui_list
= mci_list
->mci_unicast_list
;
577 oth_mui_list
!= NULL
; oth_mui_list
= oth_mui_list
->
579 if (vid
== oth_mui_list
->mui_vid
) {
580 rw_exit(&mcip
->mci_rw_lock
);
581 return (LINK_STATE_UP
);
586 rw_exit(&mcip
->mci_rw_lock
);
588 return (mac_stat_get((mac_handle_t
)mip
, MAC_STAT_LINK_STATE
));
592 * These statistics are consumed by dladm show-link -s <vnic>,
593 * dladm show-vnic -s and netstat. With the introduction of dlstat,
594 * dladm show-link -s and dladm show-vnic -s witll be EOL'ed while
595 * netstat will consume from kstats introduced for dlstat. This code
596 * will be removed at that time.
600 * Return the statistics of a MAC client. These statistics are different
601 * then the statistics of the underlying MAC which are returned by
604 * Note that for things based on the tx and rx stats, mac will end up clobbering
605 * those stats when the underlying set of rings in the srs changes. As such, we
606 * need to source not only the current set, but also the historical set when
607 * returning to the client, lest our counters appear to go backwards.
610 mac_client_stat_get(mac_client_handle_t mch
, uint_t stat
)
612 mac_client_impl_t
*mcip
= (mac_client_impl_t
*)mch
;
613 mac_impl_t
*mip
= mcip
->mci_mip
;
614 flow_entry_t
*flent
= mcip
->mci_flent
;
615 mac_soft_ring_set_t
*mac_srs
;
616 mac_rx_stats_t
*mac_rx_stat
, *old_rx_stat
;
617 mac_tx_stats_t
*mac_tx_stat
, *old_tx_stat
;
621 mac_srs
= (mac_soft_ring_set_t
*)(flent
->fe_tx_srs
);
622 mac_tx_stat
= &mac_srs
->srs_tx
.st_stat
;
623 old_rx_stat
= &mcip
->mci_misc_stat
.mms_defunctrxlanestats
;
624 old_tx_stat
= &mcip
->mci_misc_stat
.mms_defuncttxlanestats
;
627 case MAC_STAT_LINK_STATE
:
628 val
= mac_client_link_state(mcip
);
630 case MAC_STAT_LINK_UP
:
631 val
= (mac_client_link_state(mcip
) == LINK_STATE_UP
);
633 case MAC_STAT_PROMISC
:
634 val
= mac_stat_get((mac_handle_t
)mip
, MAC_STAT_PROMISC
);
636 case MAC_STAT_LOWLINK_STATE
:
637 val
= mac_stat_get((mac_handle_t
)mip
, MAC_STAT_LOWLINK_STATE
);
639 case MAC_STAT_IFSPEED
:
640 val
= mac_client_ifspeed(mcip
);
642 case MAC_STAT_MULTIRCV
:
643 val
= mcip
->mci_misc_stat
.mms_multircv
;
645 case MAC_STAT_BRDCSTRCV
:
646 val
= mcip
->mci_misc_stat
.mms_brdcstrcv
;
648 case MAC_STAT_MULTIXMT
:
649 val
= mcip
->mci_misc_stat
.mms_multixmt
;
651 case MAC_STAT_BRDCSTXMT
:
652 val
= mcip
->mci_misc_stat
.mms_brdcstxmt
;
654 case MAC_STAT_OBYTES
:
655 val
= mac_tx_stat
->mts_obytes
;
656 val
+= old_tx_stat
->mts_obytes
;
658 case MAC_STAT_OPACKETS
:
659 val
= mac_tx_stat
->mts_opackets
;
660 val
+= old_tx_stat
->mts_opackets
;
662 case MAC_STAT_OERRORS
:
663 val
= mac_tx_stat
->mts_oerrors
;
664 val
+= old_tx_stat
->mts_oerrors
;
666 case MAC_STAT_IPACKETS
:
667 for (i
= 0; i
< flent
->fe_rx_srs_cnt
; i
++) {
668 mac_srs
= (mac_soft_ring_set_t
*)flent
->fe_rx_srs
[i
];
669 mac_rx_stat
= &mac_srs
->srs_rx
.sr_stat
;
670 val
+= mac_rx_stat
->mrs_intrcnt
+
671 mac_rx_stat
->mrs_pollcnt
+ mac_rx_stat
->mrs_lclcnt
;
673 val
+= old_rx_stat
->mrs_intrcnt
+ old_rx_stat
->mrs_pollcnt
+
674 old_rx_stat
->mrs_lclcnt
;
676 case MAC_STAT_RBYTES
:
677 for (i
= 0; i
< flent
->fe_rx_srs_cnt
; i
++) {
678 mac_srs
= (mac_soft_ring_set_t
*)flent
->fe_rx_srs
[i
];
679 mac_rx_stat
= &mac_srs
->srs_rx
.sr_stat
;
680 val
+= mac_rx_stat
->mrs_intrbytes
+
681 mac_rx_stat
->mrs_pollbytes
+
682 mac_rx_stat
->mrs_lclbytes
;
684 val
+= old_rx_stat
->mrs_intrbytes
+ old_rx_stat
->mrs_pollbytes
+
685 old_rx_stat
->mrs_lclbytes
;
687 case MAC_STAT_IERRORS
:
688 for (i
= 0; i
< flent
->fe_rx_srs_cnt
; i
++) {
689 mac_srs
= (mac_soft_ring_set_t
*)flent
->fe_rx_srs
[i
];
690 mac_rx_stat
= &mac_srs
->srs_rx
.sr_stat
;
691 val
+= mac_rx_stat
->mrs_ierrors
;
693 val
+= old_rx_stat
->mrs_ierrors
;
696 val
= mac_driver_stat_default(mip
, stat
);
704 * Return the statistics of the specified MAC instance.
707 mac_stat_get(mac_handle_t mh
, uint_t stat
)
709 mac_impl_t
*mip
= (mac_impl_t
*)mh
;
714 * The range of stat determines where it is maintained. Stat
715 * values from 0 up to (but not including) MAC_STAT_MIN are
716 * mainteined by the mac module itself. Everything else is
717 * maintained by the driver.
719 * If the mac_impl_t being queried corresponds to a VNIC,
720 * the stats need to be queried from the lower MAC client
721 * corresponding to the VNIC. (The mac_link_update()
722 * invoked by the driver to the lower MAC causes the *lower
723 * MAC* to update its mi_linkstate, and send a notification
724 * to its MAC clients. Due to the VNIC passthrough,
725 * these notifications are sent to the upper MAC clients
726 * of the VNIC directly, and the upper mac_impl_t of the VNIC
727 * does not have a valid mi_linkstate.
729 if (stat
< MAC_STAT_MIN
&& !(mip
->mi_state_flags
& MIS_IS_VNIC
)) {
730 /* these stats are maintained by the mac module itself */
732 case MAC_STAT_LINK_STATE
:
733 return (mip
->mi_linkstate
);
734 case MAC_STAT_LINK_UP
:
735 return (mip
->mi_linkstate
== LINK_STATE_UP
);
736 case MAC_STAT_PROMISC
:
737 return (mip
->mi_devpromisc
!= 0);
738 case MAC_STAT_LOWLINK_STATE
:
739 return (mip
->mi_lowlinkstate
);
746 * Call the driver to get the given statistic.
748 ret
= mip
->mi_getstat(mip
->mi_driver
, stat
, &val
);
751 * The driver doesn't support this statistic. Get the
752 * statistic's default value.
754 val
= mac_driver_stat_default(mip
, stat
);
760 * Query hardware rx ring corresponding to the pseudo ring.
763 mac_pseudo_rx_ring_stat_get(mac_ring_handle_t handle
, uint_t stat
)
765 return (mac_rx_ring_stat_get(handle
, stat
));
769 * Query hardware tx ring corresponding to the pseudo ring.
772 mac_pseudo_tx_ring_stat_get(mac_ring_handle_t handle
, uint_t stat
)
774 return (mac_tx_ring_stat_get(handle
, stat
));
778 * Utility function which returns the VID associated with a flow entry.
781 i_mac_flow_vid(flow_entry_t
*flent
)
783 flow_desc_t flow_desc
;
785 mac_flow_get_desc(flent
, &flow_desc
);
787 if ((flow_desc
.fd_mask
& FLOW_LINK_VID
) != 0)
788 return (flow_desc
.fd_vid
);
789 return (VLAN_ID_NONE
);
793 * Verify the validity of the specified unicast MAC address. Returns B_TRUE
794 * if the address is valid, B_FALSE otherwise (multicast address, or incorrect
798 mac_unicst_verify(mac_handle_t mh
, const uint8_t *addr
, uint_t len
)
800 mac_impl_t
*mip
= (mac_impl_t
*)mh
;
803 * Verify the address. No lock is needed since mi_type and plugin
804 * details don't change after mac_register().
806 if ((len
!= mip
->mi_type
->mt_addr_length
) ||
807 (mip
->mi_type
->mt_ops
.mtops_unicst_verify(addr
,
808 mip
->mi_pdata
)) != 0) {
816 mac_sdu_get(mac_handle_t mh
, uint_t
*min_sdu
, uint_t
*max_sdu
)
818 mac_impl_t
*mip
= (mac_impl_t
*)mh
;
821 *min_sdu
= mip
->mi_sdu_min
;
823 *max_sdu
= mip
->mi_sdu_max
;
827 mac_sdu_get2(mac_handle_t mh
, uint_t
*min_sdu
, uint_t
*max_sdu
,
828 uint_t
*multicast_sdu
)
830 mac_impl_t
*mip
= (mac_impl_t
*)mh
;
833 *min_sdu
= mip
->mi_sdu_min
;
835 *max_sdu
= mip
->mi_sdu_max
;
836 if (multicast_sdu
!= NULL
)
837 *multicast_sdu
= mip
->mi_sdu_multicast
;
841 * Update the MAC unicast address of the specified client's flows. Currently
842 * only one unicast MAC unicast address is allowed per client.
845 mac_unicast_update_client_flow(mac_client_impl_t
*mcip
)
847 mac_impl_t
*mip
= mcip
->mci_mip
;
848 flow_entry_t
*flent
= mcip
->mci_flent
;
849 mac_address_t
*map
= mcip
->mci_unicast
;
850 flow_desc_t flow_desc
;
852 ASSERT(MAC_PERIM_HELD((mac_handle_t
)mip
));
853 ASSERT(flent
!= NULL
);
855 mac_flow_get_desc(flent
, &flow_desc
);
856 ASSERT(flow_desc
.fd_mask
& FLOW_LINK_DST
);
858 bcopy(map
->ma_addr
, flow_desc
.fd_dst_mac
, map
->ma_len
);
859 mac_flow_set_desc(flent
, &flow_desc
);
862 * The v6 local and SLAAC addrs (used by mac protection) need to be
863 * regenerated because our mac address has changed.
865 mac_protect_update_mac_token(mcip
);
868 * A MAC client could have one MAC address but multiple
869 * VLANs. In that case update the flow entries corresponding
870 * to all VLANs of the MAC client.
872 for (flent
= mcip
->mci_flent_list
; flent
!= NULL
;
873 flent
= flent
->fe_client_next
) {
874 mac_flow_get_desc(flent
, &flow_desc
);
875 if (!(flent
->fe_type
& FLOW_PRIMARY_MAC
||
876 flent
->fe_type
& FLOW_VNIC_MAC
))
879 bcopy(map
->ma_addr
, flow_desc
.fd_dst_mac
, map
->ma_len
);
880 mac_flow_set_desc(flent
, &flow_desc
);
885 * Update all clients that share the same unicast address.
888 mac_unicast_update_clients(mac_impl_t
*mip
, mac_address_t
*map
)
890 mac_client_impl_t
*mcip
;
892 ASSERT(MAC_PERIM_HELD((mac_handle_t
)mip
));
895 * Find all clients that share the same unicast MAC address and update
896 * them appropriately.
898 for (mcip
= mip
->mi_clients_list
; mcip
!= NULL
;
899 mcip
= mcip
->mci_client_next
) {
901 * Ignore clients that don't share this MAC address.
903 if (map
!= mcip
->mci_unicast
)
907 * Update those clients with same old unicast MAC address.
909 mac_unicast_update_client_flow(mcip
);
914 * Update the unicast MAC address of the specified VNIC MAC client.
916 * Check whether the operation is valid. Any of following cases should fail:
918 * 1. It's a VLAN type of VNIC.
919 * 2. The new value is current "primary" MAC address.
920 * 3. The current MAC address is shared with other clients.
921 * 4. The new MAC address has been used. This case will be valid when
922 * client migration is fully supported.
925 mac_vnic_unicast_set(mac_client_handle_t mch
, const uint8_t *addr
)
927 mac_client_impl_t
*mcip
= (mac_client_impl_t
*)mch
;
928 mac_impl_t
*mip
= mcip
->mci_mip
;
929 mac_address_t
*map
= mcip
->mci_unicast
;
932 ASSERT(!(mip
->mi_state_flags
& MIS_IS_VNIC
));
933 ASSERT(mcip
->mci_state_flags
& MCIS_IS_VNIC
);
934 ASSERT(mcip
->mci_flags
!= MAC_CLIENT_FLAGS_PRIMARY
);
936 i_mac_perim_enter(mip
);
939 * If this is a VLAN type of VNIC, it's using "primary" MAC address
940 * of the underlying interface. Must fail here. Refer to case 1 above.
942 if (bcmp(map
->ma_addr
, mip
->mi_addr
, map
->ma_len
) == 0) {
943 i_mac_perim_exit(mip
);
948 * If the new address is the "primary" one, must fail. Refer to
951 if (bcmp(addr
, mip
->mi_addr
, map
->ma_len
) == 0) {
952 i_mac_perim_exit(mip
);
957 * If the address is shared by multiple clients, must fail. Refer
960 if (mac_check_macaddr_shared(map
)) {
961 i_mac_perim_exit(mip
);
966 * If the new address has been used, must fail for now. Refer to
969 if (mac_find_macaddr(mip
, (uint8_t *)addr
) != NULL
) {
970 i_mac_perim_exit(mip
);
975 * Update the MAC address.
977 err
= mac_update_macaddr(map
, (uint8_t *)addr
);
980 i_mac_perim_exit(mip
);
985 * Update all flows of this MAC client.
987 mac_unicast_update_client_flow(mcip
);
989 i_mac_perim_exit(mip
);
994 * Program the new primary unicast address of the specified MAC.
996 * Function mac_update_macaddr() takes care different types of underlying
997 * MAC. If the underlying MAC is VNIC, the VNIC driver must have registerd
998 * mi_unicst() entry point, that indirectly calls mac_vnic_unicast_set()
999 * which will take care of updating the MAC address of the corresponding
1002 * This is the only interface that allow the client to update the "primary"
1003 * MAC address of the underlying MAC. The new value must have not been
1004 * used by other clients.
1007 mac_unicast_primary_set(mac_handle_t mh
, const uint8_t *addr
)
1009 mac_impl_t
*mip
= (mac_impl_t
*)mh
;
1013 /* verify the address validity */
1014 if (!mac_unicst_verify(mh
, addr
, mip
->mi_type
->mt_addr_length
))
1017 i_mac_perim_enter(mip
);
1020 * If the new value is the same as the current primary address value,
1021 * there's nothing to do.
1023 if (bcmp(addr
, mip
->mi_addr
, mip
->mi_type
->mt_addr_length
) == 0) {
1024 i_mac_perim_exit(mip
);
1028 if (mac_find_macaddr(mip
, (uint8_t *)addr
) != 0) {
1029 i_mac_perim_exit(mip
);
1033 map
= mac_find_macaddr(mip
, mip
->mi_addr
);
1034 ASSERT(map
!= NULL
);
1037 * Update the MAC address.
1039 if (mip
->mi_state_flags
& MIS_IS_AGGR
) {
1040 mac_capab_aggr_t aggr_cap
;
1043 * If the mac is an aggregation, other than the unicast
1044 * addresses programming, aggr must be informed about this
1045 * primary unicst address change to change its mac address
1046 * policy to be user-specified.
1048 ASSERT(map
->ma_type
== MAC_ADDRESS_TYPE_UNICAST_CLASSIFIED
);
1049 VERIFY(i_mac_capab_get(mh
, MAC_CAPAB_AGGR
, &aggr_cap
));
1050 err
= aggr_cap
.mca_unicst(mip
->mi_driver
, addr
);
1052 bcopy(addr
, map
->ma_addr
, map
->ma_len
);
1054 err
= mac_update_macaddr(map
, (uint8_t *)addr
);
1058 i_mac_perim_exit(mip
);
1062 mac_unicast_update_clients(mip
, map
);
1065 * Save the new primary MAC address in mac_impl_t.
1067 bcopy(addr
, mip
->mi_addr
, mip
->mi_type
->mt_addr_length
);
1069 i_mac_perim_exit(mip
);
1072 i_mac_notify(mip
, MAC_NOTE_UNICST
);
1078 * Return the current primary MAC address of the specified MAC.
1081 mac_unicast_primary_get(mac_handle_t mh
, uint8_t *addr
)
1083 mac_impl_t
*mip
= (mac_impl_t
*)mh
;
1085 rw_enter(&mip
->mi_rw_lock
, RW_READER
);
1086 bcopy(mip
->mi_addr
, addr
, mip
->mi_type
->mt_addr_length
);
1087 rw_exit(&mip
->mi_rw_lock
);
1091 * Return the secondary MAC address for the specified handle
1094 mac_unicast_secondary_get(mac_client_handle_t mh
, uint8_t *addr
)
1096 mac_client_impl_t
*mcip
= (mac_client_impl_t
*)mh
;
1098 ASSERT(mcip
->mci_unicast
!= NULL
);
1099 bcopy(mcip
->mci_unicast
->ma_addr
, addr
, mcip
->mci_unicast
->ma_len
);
1103 * Return information about the use of the primary MAC address of the
1104 * specified MAC instance:
1106 * - if client_name is non-NULL, it must point to a string of at
1107 * least MAXNAMELEN bytes, and will be set to the name of the MAC
1108 * client which uses the primary MAC address.
1110 * - if in_use is non-NULL, used to return whether the primary MAC
1111 * address is currently in use.
1114 mac_unicast_primary_info(mac_handle_t mh
, char *client_name
, boolean_t
*in_use
)
1116 mac_impl_t
*mip
= (mac_impl_t
*)mh
;
1117 mac_client_impl_t
*cur_client
;
1121 if (client_name
!= NULL
)
1122 bzero(client_name
, MAXNAMELEN
);
1125 * The mi_rw_lock is used to protect threads that don't hold the
1126 * mac perimeter to get a consistent view of the mi_clients_list.
1127 * Threads that modify the list must hold both the mac perimeter and
1128 * mi_rw_lock(RW_WRITER)
1130 rw_enter(&mip
->mi_rw_lock
, RW_READER
);
1131 for (cur_client
= mip
->mi_clients_list
; cur_client
!= NULL
;
1132 cur_client
= cur_client
->mci_client_next
) {
1133 if (mac_is_primary_client(cur_client
) ||
1134 (mip
->mi_state_flags
& MIS_IS_VNIC
)) {
1135 rw_exit(&mip
->mi_rw_lock
);
1138 if (client_name
!= NULL
) {
1139 bcopy(cur_client
->mci_name
, client_name
,
1145 rw_exit(&mip
->mi_rw_lock
);
1149 * Return the current destination MAC address of the specified MAC.
1152 mac_dst_get(mac_handle_t mh
, uint8_t *addr
)
1154 mac_impl_t
*mip
= (mac_impl_t
*)mh
;
1156 rw_enter(&mip
->mi_rw_lock
, RW_READER
);
1157 if (mip
->mi_dstaddr_set
)
1158 bcopy(mip
->mi_dstaddr
, addr
, mip
->mi_type
->mt_addr_length
);
1159 rw_exit(&mip
->mi_rw_lock
);
1160 return (mip
->mi_dstaddr_set
);
1164 * Add the specified MAC client to the list of clients which opened
1165 * the specified MAC.
1168 mac_client_add(mac_client_impl_t
*mcip
)
1170 mac_impl_t
*mip
= mcip
->mci_mip
;
1172 ASSERT(MAC_PERIM_HELD((mac_handle_t
)mip
));
1174 /* add VNIC to the front of the list */
1175 rw_enter(&mip
->mi_rw_lock
, RW_WRITER
);
1176 mcip
->mci_client_next
= mip
->mi_clients_list
;
1177 mip
->mi_clients_list
= mcip
;
1179 rw_exit(&mip
->mi_rw_lock
);
1183 * Remove the specified MAC client from the list of clients which opened
1184 * the specified MAC.
1187 mac_client_remove(mac_client_impl_t
*mcip
)
1189 mac_impl_t
*mip
= mcip
->mci_mip
;
1190 mac_client_impl_t
**prev
, *cclient
;
1192 ASSERT(MAC_PERIM_HELD((mac_handle_t
)mip
));
1194 rw_enter(&mip
->mi_rw_lock
, RW_WRITER
);
1195 prev
= &mip
->mi_clients_list
;
1197 while (cclient
!= NULL
&& cclient
!= mcip
) {
1198 prev
= &cclient
->mci_client_next
;
1201 ASSERT(cclient
!= NULL
);
1202 *prev
= cclient
->mci_client_next
;
1204 rw_exit(&mip
->mi_rw_lock
);
1207 static mac_unicast_impl_t
*
1208 mac_client_find_vid(mac_client_impl_t
*mcip
, uint16_t vid
)
1210 mac_unicast_impl_t
*muip
= mcip
->mci_unicast_list
;
1212 while ((muip
!= NULL
) && (muip
->mui_vid
!= vid
))
1213 muip
= muip
->mui_next
;
1219 * Return whether the specified (MAC address, VID) tuple is already used by
1220 * one of the MAC clients associated with the specified MAC.
1223 mac_addr_in_use(mac_impl_t
*mip
, uint8_t *mac_addr
, uint16_t vid
)
1225 mac_client_impl_t
*client
;
1228 ASSERT(MAC_PERIM_HELD((mac_handle_t
)mip
));
1230 for (client
= mip
->mi_clients_list
; client
!= NULL
;
1231 client
= client
->mci_client_next
) {
1234 * Ignore clients that don't have unicast address.
1236 if (client
->mci_unicast_list
== NULL
)
1239 map
= client
->mci_unicast
;
1241 if ((bcmp(mac_addr
, map
->ma_addr
, map
->ma_len
) == 0) &&
1242 (mac_client_find_vid(client
, vid
) != NULL
)) {
1251 * Generate a random MAC address. The MAC address prefix is
1252 * stored in the array pointed to by mac_addr, and its length, in bytes,
1253 * is specified by prefix_len. The least significant bits
1254 * after prefix_len bytes are generated, and stored after the prefix
1255 * in the mac_addr array.
1258 mac_addr_random(mac_client_handle_t mch
, uint_t prefix_len
,
1259 uint8_t *mac_addr
, mac_diag_t
*diag
)
1261 mac_client_impl_t
*mcip
= (mac_client_impl_t
*)mch
;
1262 mac_impl_t
*mip
= mcip
->mci_mip
;
1263 size_t addr_len
= mip
->mi_type
->mt_addr_length
;
1265 if (prefix_len
>= addr_len
) {
1266 *diag
= MAC_DIAG_MACPREFIXLEN_INVALID
;
1270 /* check the prefix value */
1271 if (prefix_len
> 0) {
1272 bzero(mac_addr
+ prefix_len
, addr_len
- prefix_len
);
1273 if (!mac_unicst_verify((mac_handle_t
)mip
, mac_addr
,
1275 *diag
= MAC_DIAG_MACPREFIX_INVALID
;
1280 /* generate the MAC address */
1281 if (prefix_len
< addr_len
) {
1282 (void) random_get_pseudo_bytes(mac_addr
+
1283 prefix_len
, addr_len
- prefix_len
);
1291 * Set the priority range for this MAC client. This will be used to
1292 * determine the absolute priority for the threads created for this
1293 * MAC client using the specified "low", "medium" and "high" level.
1294 * This will also be used for any subflows on this MAC client.
1296 #define MAC_CLIENT_SET_PRIORITY_RANGE(mcip, pri) { \
1297 (mcip)->mci_min_pri = FLOW_MIN_PRIORITY(MINCLSYSPRI, \
1298 MAXCLSYSPRI, (pri)); \
1299 (mcip)->mci_max_pri = FLOW_MAX_PRIORITY(MINCLSYSPRI, \
1300 MAXCLSYSPRI, (mcip)->mci_min_pri); \
1304 * MAC client open entry point. Return a new MAC client handle. Each
1305 * MAC client is associated with a name, specified through the 'name'
1309 mac_client_open(mac_handle_t mh
, mac_client_handle_t
*mchp
, char *name
,
1312 mac_impl_t
*mip
= (mac_impl_t
*)mh
;
1313 mac_client_impl_t
*mcip
;
1315 boolean_t share_desired
;
1316 flow_entry_t
*flent
= NULL
;
1318 share_desired
= (flags
& MAC_OPEN_FLAGS_SHARES_DESIRED
) != 0;
1321 i_mac_perim_enter(mip
);
1323 if (mip
->mi_state_flags
& MIS_IS_VNIC
) {
1325 * The underlying MAC is a VNIC. Return the MAC client
1326 * handle of the lower MAC which was obtained by
1327 * the VNIC driver when it did its mac_client_open().
1330 mcip
= mac_vnic_lower(mip
);
1333 * Note that multiple mac clients share the same mcip in
1336 if (flags
& MAC_OPEN_FLAGS_EXCLUSIVE
)
1337 mcip
->mci_state_flags
|= MCIS_EXCLUSIVE
;
1339 if (flags
& MAC_OPEN_FLAGS_MULTI_PRIMARY
)
1340 mcip
->mci_flags
|= MAC_CLIENT_FLAGS_MULTI_PRIMARY
;
1342 mip
->mi_clients_list
= mcip
;
1343 i_mac_perim_exit(mip
);
1344 *mchp
= (mac_client_handle_t
)mcip
;
1346 DTRACE_PROBE2(mac__client__open__nonallocated
, mac_impl_t
*,
1347 mcip
->mci_mip
, mac_client_impl_t
*, mcip
);
1352 mcip
= kmem_cache_alloc(mac_client_impl_cache
, KM_SLEEP
);
1354 mcip
->mci_mip
= mip
;
1355 mcip
->mci_upper_mip
= NULL
;
1356 mcip
->mci_rx_fn
= mac_pkt_drop
;
1357 mcip
->mci_rx_arg
= NULL
;
1358 mcip
->mci_rx_p_fn
= NULL
;
1359 mcip
->mci_rx_p_arg
= NULL
;
1360 mcip
->mci_p_unicast_list
= NULL
;
1361 mcip
->mci_direct_rx_fn
= NULL
;
1362 mcip
->mci_direct_rx_arg
= NULL
;
1363 mcip
->mci_vidcache
= MCIP_VIDCACHE_INVALID
;
1365 mcip
->mci_unicast_list
= NULL
;
1367 if ((flags
& MAC_OPEN_FLAGS_IS_VNIC
) != 0)
1368 mcip
->mci_state_flags
|= MCIS_IS_VNIC
;
1370 if ((flags
& MAC_OPEN_FLAGS_EXCLUSIVE
) != 0)
1371 mcip
->mci_state_flags
|= MCIS_EXCLUSIVE
;
1373 if ((flags
& MAC_OPEN_FLAGS_IS_AGGR_PORT
) != 0)
1374 mcip
->mci_state_flags
|= MCIS_IS_AGGR_PORT
;
1376 if (mip
->mi_state_flags
& MIS_IS_AGGR
)
1377 mcip
->mci_state_flags
|= MCIS_IS_AGGR
;
1379 if ((flags
& MAC_OPEN_FLAGS_USE_DATALINK_NAME
) != 0) {
1380 datalink_id_t linkid
;
1382 ASSERT(name
== NULL
);
1383 if ((err
= dls_devnet_macname2linkid(mip
->mi_name
,
1387 if ((err
= dls_mgmt_get_linkinfo(linkid
, mcip
->mci_name
, NULL
,
1388 NULL
, NULL
)) != 0) {
1390 * Use mac name if dlmgmtd is not available.
1393 (void) strlcpy(mcip
->mci_name
, mip
->mi_name
,
1394 sizeof (mcip
->mci_name
));
1400 mcip
->mci_state_flags
|= MCIS_USE_DATALINK_NAME
;
1402 ASSERT(name
!= NULL
);
1403 if (strlen(name
) > MAXNAMELEN
) {
1407 (void) strlcpy(mcip
->mci_name
, name
, sizeof (mcip
->mci_name
));
1410 if (flags
& MAC_OPEN_FLAGS_MULTI_PRIMARY
)
1411 mcip
->mci_flags
|= MAC_CLIENT_FLAGS_MULTI_PRIMARY
;
1413 if (flags
& MAC_OPEN_FLAGS_NO_UNICAST_ADDR
)
1414 mcip
->mci_state_flags
|= MCIS_NO_UNICAST_ADDR
;
1416 mac_protect_init(mcip
);
1418 /* the subflow table will be created dynamically */
1419 mcip
->mci_subflow_tab
= NULL
;
1421 mcip
->mci_misc_stat
.mms_multircv
= 0;
1422 mcip
->mci_misc_stat
.mms_brdcstrcv
= 0;
1423 mcip
->mci_misc_stat
.mms_multixmt
= 0;
1424 mcip
->mci_misc_stat
.mms_brdcstxmt
= 0;
1426 /* Create an initial flow */
1428 err
= mac_flow_create(NULL
, NULL
, mcip
->mci_name
, NULL
,
1429 mcip
->mci_state_flags
& MCIS_IS_VNIC
? FLOW_VNIC_MAC
:
1430 FLOW_PRIMARY_MAC
, &flent
);
1433 mcip
->mci_flent
= flent
;
1434 FLOW_MARK(flent
, FE_MC_NO_DATAPATH
);
1435 flent
->fe_mcip
= mcip
;
1437 * Place initial creation reference on the flow. This reference
1438 * is released in the corresponding delete action viz.
1439 * mac_unicast_remove after waiting for all transient refs to
1440 * to go away. The wait happens in mac_flow_wait.
1442 FLOW_REFHOLD(flent
);
1445 * Do this ahead of the mac_bcast_add() below so that the mi_nclients
1446 * will have the right value for mac_rx_srs_setup().
1448 mac_client_add(mcip
);
1450 mcip
->mci_share
= (uintptr_t)NULL
;
1452 i_mac_share_alloc(mcip
);
1455 * We will do mimimal datapath setup to allow a MAC client to
1456 * transmit or receive non-unicast packets without waiting
1457 * for mac_unicast_add.
1459 if (mcip
->mci_state_flags
& MCIS_NO_UNICAST_ADDR
) {
1460 if ((err
= mac_client_datapath_setup(mcip
, VLAN_ID_NONE
,
1461 NULL
, NULL
, B_TRUE
, NULL
)) != 0) {
1466 DTRACE_PROBE2(mac__client__open__allocated
, mac_impl_t
*,
1467 mcip
->mci_mip
, mac_client_impl_t
*, mcip
);
1469 *mchp
= (mac_client_handle_t
)mcip
;
1470 i_mac_perim_exit(mip
);
1474 i_mac_perim_exit(mip
);
1475 mcip
->mci_state_flags
= 0;
1476 mcip
->mci_tx_flag
= 0;
1477 kmem_cache_free(mac_client_impl_cache
, mcip
);
1482 * Close the specified MAC client handle.
1485 mac_client_close(mac_client_handle_t mch
, uint16_t flags
)
1487 mac_client_impl_t
*mcip
= (mac_client_impl_t
*)mch
;
1488 mac_impl_t
*mip
= mcip
->mci_mip
;
1489 flow_entry_t
*flent
;
1491 i_mac_perim_enter(mip
);
1493 if (flags
& MAC_CLOSE_FLAGS_EXCLUSIVE
)
1494 mcip
->mci_state_flags
&= ~MCIS_EXCLUSIVE
;
1496 if ((mcip
->mci_state_flags
& MCIS_IS_VNIC
) &&
1497 !(flags
& MAC_CLOSE_FLAGS_IS_VNIC
)) {
1499 * This is an upper VNIC client initiated operation.
1500 * The lower MAC client will be closed by the VNIC driver
1501 * when the VNIC is deleted.
1504 i_mac_perim_exit(mip
);
1508 /* If we have only setup up minimal datapth setup, tear it down */
1509 if (mcip
->mci_state_flags
& MCIS_NO_UNICAST_ADDR
) {
1510 mac_client_datapath_teardown((mac_client_handle_t
)mcip
, NULL
,
1512 mcip
->mci_state_flags
&= ~MCIS_NO_UNICAST_ADDR
;
1516 * Remove the flent associated with the MAC client
1518 flent
= mcip
->mci_flent
;
1519 mcip
->mci_flent
= NULL
;
1520 FLOW_FINAL_REFRELE(flent
);
1523 * MAC clients must remove the unicast addresses and promisc callbacks
1524 * they added before issuing a mac_client_close().
1526 ASSERT(mcip
->mci_unicast_list
== NULL
);
1527 ASSERT(mcip
->mci_promisc_list
== NULL
);
1528 ASSERT(mcip
->mci_tx_notify_cb_list
== NULL
);
1530 i_mac_share_free(mcip
);
1531 mac_protect_fini(mcip
);
1532 mac_client_remove(mcip
);
1534 i_mac_perim_exit(mip
);
1535 mcip
->mci_subflow_tab
= NULL
;
1536 mcip
->mci_state_flags
= 0;
1537 mcip
->mci_tx_flag
= 0;
1538 kmem_cache_free(mac_client_impl_cache
, mch
);
1542 * Set the rx bypass receive callback.
1545 mac_rx_bypass_set(mac_client_handle_t mch
, mac_direct_rx_t rx_fn
, void *arg1
)
1547 mac_client_impl_t
*mcip
= (mac_client_impl_t
*)mch
;
1548 mac_impl_t
*mip
= mcip
->mci_mip
;
1550 ASSERT(MAC_PERIM_HELD((mac_handle_t
)mip
));
1553 * If the mac_client is a VLAN, we should not do DLS bypass and
1554 * instead let the packets come up via mac_rx_deliver so the vlan
1555 * header can be stripped.
1557 if (mcip
->mci_nvids
> 0)
1561 * These are not accessed directly in the data path, and hence
1562 * don't need any protection
1564 mcip
->mci_direct_rx_fn
= rx_fn
;
1565 mcip
->mci_direct_rx_arg
= arg1
;
1570 * Enable/Disable rx bypass. By default, bypass is assumed to be enabled.
1573 mac_rx_bypass_enable(mac_client_handle_t mch
)
1575 ((mac_client_impl_t
*)mch
)->mci_state_flags
&= ~MCIS_RX_BYPASS_DISABLE
;
1579 mac_rx_bypass_disable(mac_client_handle_t mch
)
1581 ((mac_client_impl_t
*)mch
)->mci_state_flags
|= MCIS_RX_BYPASS_DISABLE
;
1585 * Set the receive callback for the specified MAC client. There can be
1586 * at most one such callback per MAC client.
1589 mac_rx_set(mac_client_handle_t mch
, mac_rx_t rx_fn
, void *arg
)
1591 mac_client_impl_t
*mcip
= (mac_client_impl_t
*)mch
;
1592 mac_impl_t
*mip
= mcip
->mci_mip
;
1593 mac_impl_t
*umip
= mcip
->mci_upper_mip
;
1596 * Instead of adding an extra set of locks and refcnts in
1597 * the datapath at the mac client boundary, we temporarily quiesce
1598 * the SRS and related entities. We then change the receive function
1599 * without interference from any receive data thread and then reenable
1600 * the data flow subsequently.
1602 i_mac_perim_enter(mip
);
1603 mac_rx_client_quiesce(mch
);
1605 mcip
->mci_rx_fn
= rx_fn
;
1606 mcip
->mci_rx_arg
= arg
;
1607 mac_rx_client_restart(mch
);
1608 i_mac_perim_exit(mip
);
1611 * If we're changing the rx function on the primary mac of a vnic,
1612 * make sure any secondary macs on the vnic are updated as well.
1615 ASSERT((umip
->mi_state_flags
& MIS_IS_VNIC
) != 0);
1616 mac_vnic_secondary_update(umip
);
1621 * Reset the receive callback for the specified MAC client.
1624 mac_rx_clear(mac_client_handle_t mch
)
1626 mac_rx_set(mch
, mac_pkt_drop
, NULL
);
1630 mac_secondary_dup(mac_client_handle_t smch
, mac_client_handle_t dmch
)
1632 mac_client_impl_t
*smcip
= (mac_client_impl_t
*)smch
;
1633 mac_client_impl_t
*dmcip
= (mac_client_impl_t
*)dmch
;
1634 flow_entry_t
*flent
= dmcip
->mci_flent
;
1636 /* This should only be called to setup secondary macs */
1637 ASSERT((flent
->fe_type
& FLOW_PRIMARY_MAC
) == 0);
1639 mac_rx_set(dmch
, smcip
->mci_rx_fn
, smcip
->mci_rx_arg
);
1640 dmcip
->mci_promisc_list
= smcip
->mci_promisc_list
;
1643 * Duplicate the primary mac resources to the secondary.
1644 * Since we already validated the resource controls when setting
1645 * them on the primary, we can ignore errors here.
1647 (void) mac_resource_ctl_set(dmch
, MCIP_RESOURCE_PROPS(smcip
));
1651 * Called when removing a secondary MAC. Currently only clears the promisc_list
1652 * since we share the primary mac's promisc_list.
1655 mac_secondary_cleanup(mac_client_handle_t mch
)
1657 mac_client_impl_t
*mcip
= (mac_client_impl_t
*)mch
;
1658 flow_entry_t
*flent
= mcip
->mci_flent
;
1660 /* This should only be called for secondary macs */
1661 ASSERT((flent
->fe_type
& FLOW_PRIMARY_MAC
) == 0);
1662 mcip
->mci_promisc_list
= NULL
;
1666 * Walk the MAC client subflow table and updates their priority values.
1669 mac_update_subflow_priority_cb(flow_entry_t
*flent
, void *arg
)
1671 mac_flow_update_priority(arg
, flent
);
1676 mac_update_subflow_priority(mac_client_impl_t
*mcip
)
1678 (void) mac_flow_walk(mcip
->mci_subflow_tab
,
1679 mac_update_subflow_priority_cb
, mcip
);
1683 * Modify the TX or RX ring properties. We could either just move around
1684 * rings, i.e add/remove rings given to a client. Or this might cause the
1685 * client to move from hardware based to software or the other way around.
1686 * If we want to reset this property, then we clear the mask, additionally
1687 * if the client was given a non-default group we remove all rings except
1688 * for 1 and give it back to the default group.
1691 mac_client_set_rings_prop(mac_client_impl_t
*mcip
, mac_resource_props_t
*mrp
,
1692 mac_resource_props_t
*tmrp
)
1694 mac_impl_t
*mip
= mcip
->mci_mip
;
1695 flow_entry_t
*flent
= mcip
->mci_flent
;
1698 mac_group_t
*defgrp
;
1701 mac_resource_props_t
*cmrp
= MCIP_RESOURCE_PROPS(mcip
);
1705 if (mcip
->mci_share
!= (uintptr_t)NULL
)
1708 if (mrp
->mrp_mask
& MRP_RX_RINGS
) {
1709 unspec
= mrp
->mrp_mask
& MRP_RXRINGS_UNSPEC
;
1710 group
= flent
->fe_rx_ring_group
;
1711 defgrp
= MAC_DEFAULT_RX_GROUP(mip
);
1712 mac_addr
= flent
->fe_flow_desc
.fd_dst_mac
;
1715 * No resulting change. If we are resetting on a client on
1716 * which there was no rx rings property. For dynamic group
1717 * if we are setting the same number of rings already set.
1718 * For static group if we are requesting a group again.
1720 if (mrp
->mrp_mask
& MRP_RINGS_RESET
) {
1721 if (!(tmrp
->mrp_mask
& MRP_RX_RINGS
))
1725 if (tmrp
->mrp_mask
& MRP_RXRINGS_UNSPEC
)
1727 } else if (mip
->mi_rx_group_type
==
1728 MAC_GROUP_TYPE_DYNAMIC
) {
1729 if ((tmrp
->mrp_mask
& MRP_RX_RINGS
) &&
1730 !(tmrp
->mrp_mask
& MRP_RXRINGS_UNSPEC
) &&
1731 mrp
->mrp_nrxrings
== tmrp
->mrp_nrxrings
) {
1736 /* Resetting the prop */
1737 if (mrp
->mrp_mask
& MRP_RINGS_RESET
) {
1739 * We will just keep one ring and give others back if
1740 * we are not the primary. For the primary we give
1741 * all the rings in the default group except the
1742 * default ring. If it is a static group, then
1743 * we don't do anything, but clear the MRP_RX_RINGS
1746 if (group
!= defgrp
) {
1747 if (mip
->mi_rx_group_type
==
1748 MAC_GROUP_TYPE_DYNAMIC
) {
1750 * This group has reserved rings
1751 * that need to be released now,
1752 * so does the group.
1754 MAC_RX_RING_RELEASED(mip
,
1755 group
->mrg_cur_count
);
1756 MAC_RX_GRP_RELEASED(mip
);
1757 if ((flent
->fe_type
&
1758 FLOW_PRIMARY_MAC
) != 0) {
1759 if (mip
->mi_nactiveclients
==
1762 mac_rx_switch_group(
1767 cmrp
->mrp_nrxrings
=
1774 cmrp
->mrp_nrxrings
= 1;
1776 (void) mac_group_ring_modify(mcip
,
1780 * If this is a static group, we
1781 * need to release the group. The
1782 * client will remain in the same
1783 * group till some other client
1786 MAC_RX_GRP_RELEASED(mip
);
1788 /* Let check if we can give this an excl group */
1789 } else if (group
== defgrp
) {
1790 ngrp
= mac_reserve_rx_group(mcip
, mac_addr
,
1792 /* Couldn't give it a group, that's fine */
1796 if (mac_rx_switch_group(mcip
, defgrp
, ngrp
) !=
1798 mac_stop_group(ngrp
);
1803 * If the client is in the default group, we will
1804 * just clear the MRP_RX_RINGS and leave it as
1805 * it rather than look for an exclusive group
1811 if (group
== defgrp
&& ((mrp
->mrp_nrxrings
> 0) || unspec
)) {
1812 ngrp
= mac_reserve_rx_group(mcip
, mac_addr
, B_TRUE
);
1817 if (mac_rx_switch_group(mcip
, defgrp
, ngrp
) != 0) {
1818 mac_release_rx_group(mcip
, ngrp
);
1821 MAC_RX_GRP_RESERVED(mip
);
1822 if (mip
->mi_rx_group_type
== MAC_GROUP_TYPE_DYNAMIC
)
1823 MAC_RX_RING_RESERVED(mip
, ngrp
->mrg_cur_count
);
1824 } else if (group
!= defgrp
&& !unspec
&&
1825 mrp
->mrp_nrxrings
== 0) {
1827 ringcnt
= group
->mrg_cur_count
;
1828 if (mac_rx_switch_group(mcip
, group
, defgrp
) != 0)
1830 if (tmrp
->mrp_mask
& MRP_RX_RINGS
) {
1831 MAC_RX_GRP_RELEASED(mip
);
1832 if (mip
->mi_rx_group_type
==
1833 MAC_GROUP_TYPE_DYNAMIC
) {
1834 MAC_RX_RING_RELEASED(mip
, ringcnt
);
1837 } else if (group
!= defgrp
&& mip
->mi_rx_group_type
==
1838 MAC_GROUP_TYPE_DYNAMIC
) {
1839 ringcnt
= group
->mrg_cur_count
;
1840 err
= mac_group_ring_modify(mcip
, group
, defgrp
);
1844 * Update the accounting. If this group
1845 * already had explicitly reserved rings,
1846 * we need to update the rings based on
1847 * the new ring count. If this group
1848 * had not explicitly reserved rings,
1849 * then we just reserve the rings asked for
1850 * and reserve the group.
1852 if (tmrp
->mrp_mask
& MRP_RX_RINGS
) {
1853 if (ringcnt
> group
->mrg_cur_count
) {
1854 MAC_RX_RING_RELEASED(mip
,
1855 ringcnt
- group
->mrg_cur_count
);
1857 MAC_RX_RING_RESERVED(mip
,
1858 group
->mrg_cur_count
- ringcnt
);
1861 MAC_RX_RING_RESERVED(mip
, group
->mrg_cur_count
);
1862 MAC_RX_GRP_RESERVED(mip
);
1866 if (mrp
->mrp_mask
& MRP_TX_RINGS
) {
1867 unspec
= mrp
->mrp_mask
& MRP_TXRINGS_UNSPEC
;
1868 group
= flent
->fe_tx_ring_group
;
1869 defgrp
= MAC_DEFAULT_TX_GROUP(mip
);
1872 * For static groups we only allow rings=0 or resetting the
1875 if (mrp
->mrp_ntxrings
> 0 &&
1876 mip
->mi_tx_group_type
!= MAC_GROUP_TYPE_DYNAMIC
) {
1879 if (mrp
->mrp_mask
& MRP_RINGS_RESET
) {
1880 if (!(tmrp
->mrp_mask
& MRP_TX_RINGS
))
1884 if (tmrp
->mrp_mask
& MRP_TXRINGS_UNSPEC
)
1886 } else if (mip
->mi_tx_group_type
==
1887 MAC_GROUP_TYPE_DYNAMIC
) {
1888 if ((tmrp
->mrp_mask
& MRP_TX_RINGS
) &&
1889 !(tmrp
->mrp_mask
& MRP_TXRINGS_UNSPEC
) &&
1890 mrp
->mrp_ntxrings
== tmrp
->mrp_ntxrings
) {
1895 /* Resetting the prop */
1896 if (mrp
->mrp_mask
& MRP_RINGS_RESET
) {
1897 if (group
!= defgrp
) {
1898 if (mip
->mi_tx_group_type
==
1899 MAC_GROUP_TYPE_DYNAMIC
) {
1900 ringcnt
= group
->mrg_cur_count
;
1901 if ((flent
->fe_type
&
1902 FLOW_PRIMARY_MAC
) != 0) {
1903 mac_tx_client_quiesce(
1904 (mac_client_handle_t
)
1906 mac_tx_switch_group(mcip
,
1908 mac_tx_client_restart(
1909 (mac_client_handle_t
)
1911 MAC_TX_GRP_RELEASED(mip
);
1912 MAC_TX_RING_RELEASED(mip
,
1916 cmrp
->mrp_ntxrings
= 1;
1917 (void) mac_group_ring_modify(mcip
,
1920 * This group has reserved rings
1921 * that need to be released now.
1923 MAC_TX_RING_RELEASED(mip
, ringcnt
);
1926 * If this is a static group, we
1927 * need to release the group. The
1928 * client will remain in the same
1929 * group till some other client
1932 MAC_TX_GRP_RELEASED(mip
);
1933 } else if (group
== defgrp
&&
1934 (flent
->fe_type
& FLOW_PRIMARY_MAC
) == 0) {
1935 ngrp
= mac_reserve_tx_group(mcip
, B_TRUE
);
1938 mac_tx_client_quiesce(
1939 (mac_client_handle_t
)mcip
);
1940 mac_tx_switch_group(mcip
, defgrp
, ngrp
);
1941 mac_tx_client_restart(
1942 (mac_client_handle_t
)mcip
);
1945 * If the client is in the default group, we will
1946 * just clear the MRP_TX_RINGS and leave it as
1947 * it rather than look for an exclusive group
1954 if (group
== defgrp
&& ((mrp
->mrp_ntxrings
> 0) || unspec
)) {
1955 ngrp
= mac_reserve_tx_group(mcip
, B_TRUE
);
1958 mac_tx_client_quiesce((mac_client_handle_t
)mcip
);
1959 mac_tx_switch_group(mcip
, defgrp
, ngrp
);
1960 mac_tx_client_restart((mac_client_handle_t
)mcip
);
1961 MAC_TX_GRP_RESERVED(mip
);
1962 if (mip
->mi_tx_group_type
== MAC_GROUP_TYPE_DYNAMIC
)
1963 MAC_TX_RING_RESERVED(mip
, ngrp
->mrg_cur_count
);
1965 } else if (group
!= defgrp
&& !unspec
&&
1966 mrp
->mrp_ntxrings
== 0) {
1968 ringcnt
= group
->mrg_cur_count
;
1969 mac_tx_client_quiesce((mac_client_handle_t
)mcip
);
1970 mac_tx_switch_group(mcip
, group
, defgrp
);
1971 mac_tx_client_restart((mac_client_handle_t
)mcip
);
1972 if (tmrp
->mrp_mask
& MRP_TX_RINGS
) {
1973 MAC_TX_GRP_RELEASED(mip
);
1974 if (mip
->mi_tx_group_type
==
1975 MAC_GROUP_TYPE_DYNAMIC
) {
1976 MAC_TX_RING_RELEASED(mip
, ringcnt
);
1979 } else if (group
!= defgrp
&& mip
->mi_tx_group_type
==
1980 MAC_GROUP_TYPE_DYNAMIC
) {
1981 ringcnt
= group
->mrg_cur_count
;
1982 err
= mac_group_ring_modify(mcip
, group
, defgrp
);
1986 * Update the accounting. If this group
1987 * already had explicitly reserved rings,
1988 * we need to update the rings based on
1989 * the new ring count. If this group
1990 * had not explicitly reserved rings,
1991 * then we just reserve the rings asked for
1992 * and reserve the group.
1994 if (tmrp
->mrp_mask
& MRP_TX_RINGS
) {
1995 if (ringcnt
> group
->mrg_cur_count
) {
1996 MAC_TX_RING_RELEASED(mip
,
1997 ringcnt
- group
->mrg_cur_count
);
1999 MAC_TX_RING_RESERVED(mip
,
2000 group
->mrg_cur_count
- ringcnt
);
2003 MAC_TX_RING_RESERVED(mip
, group
->mrg_cur_count
);
2004 MAC_TX_GRP_RESERVED(mip
);
2012 * When the MAC client is being brought up (i.e. we do a unicast_add) we need
2013 * to initialize the cpu and resource control structure in the
2014 * mac_client_impl_t from the mac_impl_t (i.e if there are any cached
2015 * properties before the flow entry for the unicast address was created).
2018 mac_resource_ctl_set(mac_client_handle_t mch
, mac_resource_props_t
*mrp
)
2020 mac_client_impl_t
*mcip
= (mac_client_impl_t
*)mch
;
2021 mac_impl_t
*mip
= (mac_impl_t
*)mcip
->mci_mip
;
2022 mac_impl_t
*umip
= mcip
->mci_upper_mip
;
2024 flow_entry_t
*flent
= mcip
->mci_flent
;
2025 mac_resource_props_t
*omrp
, *nmrp
= MCIP_RESOURCE_PROPS(mcip
);
2027 ASSERT(MAC_PERIM_HELD((mac_handle_t
)mip
));
2029 err
= mac_validate_props(mcip
->mci_state_flags
& MCIS_IS_VNIC
?
2030 mcip
->mci_upper_mip
: mip
, mrp
);
2035 * Copy over the existing properties since mac_update_resources
2036 * will modify the client's mrp. Currently, the saved property
2037 * is used to determine the difference between existing and
2038 * modified rings property.
2040 omrp
= kmem_zalloc(sizeof (*omrp
), KM_SLEEP
);
2041 bcopy(nmrp
, omrp
, sizeof (*omrp
));
2042 mac_update_resources(mrp
, MCIP_RESOURCE_PROPS(mcip
), B_FALSE
);
2043 if (MCIP_DATAPATH_SETUP(mcip
)) {
2045 * We support rings only for primary client when there are
2046 * multiple clients sharing the same MAC address (e.g. VLAN).
2048 if (mrp
->mrp_mask
& MRP_RX_RINGS
||
2049 mrp
->mrp_mask
& MRP_TX_RINGS
) {
2051 if ((err
= mac_client_set_rings_prop(mcip
, mrp
,
2053 if (omrp
->mrp_mask
& MRP_RX_RINGS
) {
2054 nmrp
->mrp_mask
|= MRP_RX_RINGS
;
2055 nmrp
->mrp_nrxrings
= omrp
->mrp_nrxrings
;
2057 nmrp
->mrp_mask
&= ~MRP_RX_RINGS
;
2058 nmrp
->mrp_nrxrings
= 0;
2060 if (omrp
->mrp_mask
& MRP_TX_RINGS
) {
2061 nmrp
->mrp_mask
|= MRP_TX_RINGS
;
2062 nmrp
->mrp_ntxrings
= omrp
->mrp_ntxrings
;
2064 nmrp
->mrp_mask
&= ~MRP_TX_RINGS
;
2065 nmrp
->mrp_ntxrings
= 0;
2067 if (omrp
->mrp_mask
& MRP_RXRINGS_UNSPEC
)
2068 omrp
->mrp_mask
|= MRP_RXRINGS_UNSPEC
;
2070 omrp
->mrp_mask
&= ~MRP_RXRINGS_UNSPEC
;
2072 if (omrp
->mrp_mask
& MRP_TXRINGS_UNSPEC
)
2073 omrp
->mrp_mask
|= MRP_TXRINGS_UNSPEC
;
2075 omrp
->mrp_mask
&= ~MRP_TXRINGS_UNSPEC
;
2076 kmem_free(omrp
, sizeof (*omrp
));
2081 * If we modified the rings property of the primary
2082 * we need to update the property fields of its
2083 * VLANs as they inherit the primary's properites.
2085 if (mac_is_primary_client(mcip
)) {
2086 mac_set_prim_vlan_rings(mip
,
2087 MCIP_RESOURCE_PROPS(mcip
));
2091 * We have to set this prior to calling mac_flow_modify.
2093 if (mrp
->mrp_mask
& MRP_PRIORITY
) {
2094 if (mrp
->mrp_priority
== MPL_RESET
) {
2095 MAC_CLIENT_SET_PRIORITY_RANGE(mcip
,
2098 MAC_CLIENT_SET_PRIORITY_RANGE(mcip
,
2103 mac_flow_modify(mip
->mi_flow_tab
, flent
, mrp
);
2104 if (mrp
->mrp_mask
& MRP_PRIORITY
)
2105 mac_update_subflow_priority(mcip
);
2107 /* Apply these resource settings to any secondary macs */
2109 ASSERT((umip
->mi_state_flags
& MIS_IS_VNIC
) != 0);
2110 mac_vnic_secondary_update(umip
);
2113 kmem_free(omrp
, sizeof (*omrp
));
2118 mac_unicast_flow_create(mac_client_impl_t
*mcip
, uint8_t *mac_addr
,
2119 uint16_t vid
, boolean_t is_primary
, boolean_t first_flow
,
2120 flow_entry_t
**flent
, mac_resource_props_t
*mrp
)
2122 mac_impl_t
*mip
= (mac_impl_t
*)mcip
->mci_mip
;
2123 flow_desc_t flow_desc
;
2124 char flowname
[MAXFLOWNAMELEN
];
2129 * First unicast address being added, create a new flow
2130 * for that MAC client.
2132 bzero(&flow_desc
, sizeof (flow_desc
));
2134 ASSERT(mac_addr
!= NULL
||
2135 (mcip
->mci_state_flags
& MCIS_NO_UNICAST_ADDR
));
2136 if (mac_addr
!= NULL
) {
2137 flow_desc
.fd_mac_len
= mip
->mi_type
->mt_addr_length
;
2138 bcopy(mac_addr
, flow_desc
.fd_dst_mac
, flow_desc
.fd_mac_len
);
2140 flow_desc
.fd_mask
= FLOW_LINK_DST
;
2142 flow_desc
.fd_vid
= vid
;
2143 flow_desc
.fd_mask
|= FLOW_LINK_VID
;
2147 * XXX-nicolas. For now I'm keeping the FLOW_PRIMARY_MAC
2148 * and FLOW_VNIC. Even though they're a hack inherited
2149 * from the SRS code, we'll keep them for now. They're currently
2150 * consumed by mac_datapath_setup() to create the SRS.
2151 * That code should be eventually moved out of
2152 * mac_datapath_setup() and moved to a mac_srs_create()
2153 * function of some sort to keep things clean.
2155 * Also, there's no reason why the SRS for the primary MAC
2156 * client should be different than any other MAC client. Until
2157 * this is cleaned-up, we support only one MAC unicast address
2160 * We set FLOW_PRIMARY_MAC for the primary MAC address,
2161 * FLOW_VNIC for everything else.
2164 flent_flags
= FLOW_PRIMARY_MAC
;
2166 flent_flags
= FLOW_VNIC_MAC
;
2169 * For the first flow we use the mac client's name - mci_name, for
2170 * subsequent ones we just create a name with the vid. This is
2171 * so that we can add these flows to the same flow table. This is
2172 * fine as the flow name (except for the one with the mac client's
2173 * name) is not visible. When the first flow is removed, we just replace
2174 * its fdesc with another from the list, so we will still retain the
2175 * flent with the MAC client's flow name.
2178 bcopy(mcip
->mci_name
, flowname
, MAXFLOWNAMELEN
);
2180 (void) sprintf(flowname
, "%s%u", mcip
->mci_name
, vid
);
2181 flent_flags
= FLOW_NO_STATS
;
2184 if ((err
= mac_flow_create(&flow_desc
, mrp
, flowname
, NULL
,
2185 flent_flags
, flent
)) != 0)
2188 mac_misc_stat_create(*flent
);
2189 FLOW_MARK(*flent
, FE_INCIPIENT
);
2190 (*flent
)->fe_mcip
= mcip
;
2193 * Place initial creation reference on the flow. This reference
2194 * is released in the corresponding delete action viz.
2195 * mac_unicast_remove after waiting for all transient refs to
2196 * to go away. The wait happens in mac_flow_wait.
2197 * We have already held the reference in mac_client_open().
2200 FLOW_REFHOLD(*flent
);
2204 /* Refresh the multicast grouping for this VID. */
2206 mac_client_update_mcast(void *arg
, boolean_t add
, const uint8_t *addrp
)
2208 flow_entry_t
*flent
= arg
;
2209 mac_client_impl_t
*mcip
= flent
->fe_mcip
;
2211 flow_desc_t flow_desc
;
2213 mac_flow_get_desc(flent
, &flow_desc
);
2214 vid
= (flow_desc
.fd_mask
& FLOW_LINK_VID
) != 0 ?
2215 flow_desc
.fd_vid
: VLAN_ID_NONE
;
2218 * We don't call mac_multicast_add()/mac_multicast_remove() as
2219 * we want to add/remove for this specific vid.
2222 return (mac_bcast_add(mcip
, addrp
, vid
,
2223 MAC_ADDRTYPE_MULTICAST
));
2225 mac_bcast_delete(mcip
, addrp
, vid
);
2231 mac_update_single_active_client(mac_impl_t
*mip
)
2233 mac_client_impl_t
*client
= NULL
;
2235 ASSERT(MAC_PERIM_HELD((mac_handle_t
)mip
));
2237 rw_enter(&mip
->mi_rw_lock
, RW_WRITER
);
2238 if (mip
->mi_nactiveclients
== 1) {
2240 * Find the one active MAC client from the list of MAC
2241 * clients. The active MAC client has at least one
2244 for (client
= mip
->mi_clients_list
; client
!= NULL
;
2245 client
= client
->mci_client_next
) {
2246 if (client
->mci_unicast_list
!= NULL
)
2249 ASSERT(client
!= NULL
);
2253 * mi_single_active_client is protected by the MAC impl's read/writer
2254 * lock, which allows mac_rx() to check the value of that pointer
2257 mip
->mi_single_active_client
= client
;
2258 rw_exit(&mip
->mi_rw_lock
);
2262 * Set up the data path. Called from i_mac_unicast_add after having
2263 * done all the validations including making sure this is an active
2264 * client (i.e that is ready to process packets.)
2267 mac_client_datapath_setup(mac_client_impl_t
*mcip
, uint16_t vid
,
2268 uint8_t *mac_addr
, mac_resource_props_t
*mrp
, boolean_t isprimary
,
2269 mac_unicast_impl_t
*muip
)
2271 mac_impl_t
*mip
= mcip
->mci_mip
;
2272 boolean_t mac_started
= B_FALSE
;
2273 boolean_t bcast_added
= B_FALSE
;
2274 boolean_t nactiveclients_added
= B_FALSE
;
2275 flow_entry_t
*flent
;
2277 boolean_t no_unicast
;
2279 no_unicast
= mcip
->mci_state_flags
& MCIS_NO_UNICAST_ADDR
;
2281 if ((err
= mac_start((mac_handle_t
)mip
)) != 0)
2284 mac_started
= B_TRUE
;
2286 /* add the MAC client to the broadcast address group by default */
2287 if (mip
->mi_type
->mt_brdcst_addr
!= NULL
) {
2288 err
= mac_bcast_add(mcip
, mip
->mi_type
->mt_brdcst_addr
, vid
,
2289 MAC_ADDRTYPE_BROADCAST
);
2292 bcast_added
= B_TRUE
;
2296 * If this is the first unicast address addition for this
2297 * client, reuse the pre-allocated larval flow entry associated with
2300 flent
= (mcip
->mci_nflents
== 0) ? mcip
->mci_flent
: NULL
;
2302 /* We are configuring the unicast flow now */
2303 if (!MCIP_DATAPATH_SETUP(mcip
)) {
2306 MAC_CLIENT_SET_PRIORITY_RANGE(mcip
,
2307 (mrp
->mrp_mask
& MRP_PRIORITY
) ? mrp
->mrp_priority
:
2310 if ((err
= mac_unicast_flow_create(mcip
, mac_addr
, vid
,
2311 isprimary
, B_TRUE
, &flent
, mrp
)) != 0)
2314 mip
->mi_nactiveclients
++;
2315 nactiveclients_added
= B_TRUE
;
2318 * This will allocate the RX ring group if possible for the
2319 * flow and program the software classifier as needed.
2321 if ((err
= mac_datapath_setup(mcip
, flent
, SRST_LINK
)) != 0)
2327 * The unicast MAC address must have been added successfully.
2329 ASSERT(mcip
->mci_unicast
!= NULL
);
2331 * Push down the sub-flows that were defined on this link
2332 * hitherto. The flows are added to the active flow table
2333 * and SRS, softrings etc. are created as needed.
2335 mac_link_init_flows((mac_client_handle_t
)mcip
);
2337 mac_address_t
*map
= mcip
->mci_unicast
;
2339 ASSERT(!no_unicast
);
2341 * A unicast flow already exists for that MAC client,
2342 * this flow must be the same mac address but with
2343 * different VID. It has been checked by mac_addr_in_use().
2345 * We will use the SRS etc. from the mci_flent. Note that
2346 * We don't need to create kstat for this as except for
2347 * the fdesc, everything will be used from in the 1st flent.
2350 if (bcmp(mac_addr
, map
->ma_addr
, map
->ma_len
) != 0) {
2355 if ((err
= mac_unicast_flow_create(mcip
, mac_addr
, vid
,
2356 isprimary
, B_FALSE
, &flent
, NULL
)) != 0) {
2359 if ((err
= mac_flow_add(mip
->mi_flow_tab
, flent
)) != 0) {
2360 FLOW_FINAL_REFRELE(flent
);
2364 /* update the multicast group for this vid */
2365 mac_client_bcast_refresh(mcip
, mac_client_update_mcast
,
2366 (void *)flent
, B_TRUE
);
2370 /* populate the shared MAC address */
2371 muip
->mui_map
= mcip
->mci_unicast
;
2373 rw_enter(&mcip
->mci_rw_lock
, RW_WRITER
);
2374 muip
->mui_next
= mcip
->mci_unicast_list
;
2375 mcip
->mci_unicast_list
= muip
;
2376 rw_exit(&mcip
->mci_rw_lock
);
2380 * First add the flent to the flow list of this mcip. Then set
2381 * the mip's mi_single_active_client if needed. The Rx path assumes
2382 * that mip->mi_single_active_client will always have an associated
2385 mac_client_add_to_flow_list(mcip
, flent
);
2386 if (nactiveclients_added
)
2387 mac_update_single_active_client(mip
);
2389 * Trigger a renegotiation of the capabilities when the number of
2390 * active clients changes from 1 to 2, since some of the capabilities
2391 * might have to be disabled. Also send a MAC_NOTE_LINK notification
2392 * to all the MAC clients whenever physical link is DOWN.
2394 if (mip
->mi_nactiveclients
== 2) {
2395 mac_capab_update((mac_handle_t
)mip
);
2396 mac_virtual_link_update(mip
);
2399 * Now that the setup is complete, clear the INCIPIENT flag.
2400 * The flag was set to avoid incoming packets seeing inconsistent
2401 * structures while the setup was in progress. Clear the mci_tx_flag
2402 * by calling mac_tx_client_block. It is possible that
2403 * mac_unicast_remove was called prior to this mac_unicast_add which
2404 * could have set the MCI_TX_QUIESCE flag.
2406 if (flent
->fe_rx_ring_group
!= NULL
)
2407 mac_rx_group_unmark(flent
->fe_rx_ring_group
, MR_INCIPIENT
);
2408 FLOW_UNMARK(flent
, FE_INCIPIENT
);
2409 FLOW_UNMARK(flent
, FE_MC_NO_DATAPATH
);
2410 mac_tx_client_unblock(mcip
);
2414 mac_bcast_delete(mcip
, mip
->mi_type
->mt_brdcst_addr
, vid
);
2416 if (nactiveclients_added
)
2417 mip
->mi_nactiveclients
--;
2420 mac_stop((mac_handle_t
)mip
);
2426 * Return the passive primary MAC client, if present. The passive client is
2427 * a stand-by client that has the same unicast address as another that is
2428 * currenly active. Once the active client goes away, the passive client
2431 static mac_client_impl_t
*
2432 mac_get_passive_primary_client(mac_impl_t
*mip
)
2434 mac_client_impl_t
*mcip
;
2436 for (mcip
= mip
->mi_clients_list
; mcip
!= NULL
;
2437 mcip
= mcip
->mci_client_next
) {
2438 if (mac_is_primary_client(mcip
) &&
2439 (mcip
->mci_flags
& MAC_CLIENT_FLAGS_PASSIVE_PRIMARY
) != 0) {
2447 * Add a new unicast address to the MAC client.
2449 * The MAC address can be specified either by value, or the MAC client
2450 * can specify that it wants to use the primary MAC address of the
2451 * underlying MAC. See the introductory comments at the beginning
2452 * of this file for more more information on primary MAC addresses.
2454 * Note also the tuple (MAC address, VID) must be unique
2455 * for the MAC clients defined on top of the same underlying MAC
2456 * instance, unless the MAC_UNICAST_NODUPCHECK is specified.
2458 * In no case can a client use the PVID for the MAC, if the MAC has one set.
2461 i_mac_unicast_add(mac_client_handle_t mch
, uint8_t *mac_addr
, uint16_t flags
,
2462 mac_unicast_handle_t
*mah
, uint16_t vid
, mac_diag_t
*diag
)
2464 mac_client_impl_t
*mcip
= (mac_client_impl_t
*)mch
;
2465 mac_impl_t
*mip
= mcip
->mci_mip
;
2467 uint_t mac_len
= mip
->mi_type
->mt_addr_length
;
2468 boolean_t check_dups
= !(flags
& MAC_UNICAST_NODUPCHECK
);
2469 boolean_t fastpath_disabled
= B_FALSE
;
2470 boolean_t is_primary
= (flags
& MAC_UNICAST_PRIMARY
);
2471 boolean_t is_unicast_hw
= (flags
& MAC_UNICAST_HW
);
2472 mac_resource_props_t
*mrp
;
2473 boolean_t passive_client
= B_FALSE
;
2474 mac_unicast_impl_t
*muip
;
2475 boolean_t is_vnic_primary
=
2476 (flags
& MAC_UNICAST_VNIC_PRIMARY
);
2478 /* when VID is non-zero, the underlying MAC can not be VNIC */
2479 ASSERT(!((mip
->mi_state_flags
& MIS_IS_VNIC
) && (vid
!= 0)));
2482 * Can't unicast add if the client asked only for minimal datapath
2485 if (mcip
->mci_state_flags
& MCIS_NO_UNICAST_ADDR
)
2489 * Check for an attempted use of the current Port VLAN ID, if enabled.
2490 * No client may use it.
2492 if (mip
->mi_pvid
!= 0 && vid
== mip
->mi_pvid
)
2496 * Check whether it's the primary client and flag it.
2498 if (!(mcip
->mci_state_flags
& MCIS_IS_VNIC
) && is_primary
&& vid
== 0)
2499 mcip
->mci_flags
|= MAC_CLIENT_FLAGS_PRIMARY
;
2502 * is_vnic_primary is true when we come here as a VLAN VNIC
2503 * which uses the primary mac client's address but with a non-zero
2504 * VID. In this case the MAC address is not specified by an upper
2507 if ((mcip
->mci_state_flags
& MCIS_IS_VNIC
) && is_primary
&&
2510 * The address is being set by the upper MAC client
2511 * of a VNIC. The MAC address was already set by the
2512 * VNIC driver during VNIC creation.
2514 * Note: a VNIC has only one MAC address. We return
2515 * the MAC unicast address handle of the lower MAC client
2516 * corresponding to the VNIC. We allocate a new entry
2517 * which is flagged appropriately, so that mac_unicast_remove()
2518 * doesn't attempt to free the original entry that
2519 * was allocated by the VNIC driver.
2521 ASSERT(mcip
->mci_unicast
!= NULL
);
2523 /* Check for VLAN flags, if present */
2524 if ((flags
& MAC_UNICAST_TAG_DISABLE
) != 0)
2525 mcip
->mci_state_flags
|= MCIS_TAG_DISABLE
;
2527 if ((flags
& MAC_UNICAST_STRIP_DISABLE
) != 0)
2528 mcip
->mci_state_flags
|= MCIS_STRIP_DISABLE
;
2530 if ((flags
& MAC_UNICAST_DISABLE_TX_VID_CHECK
) != 0)
2531 mcip
->mci_state_flags
|= MCIS_DISABLE_TX_VID_CHECK
;
2534 * Ensure that the primary unicast address of the VNIC
2535 * is added only once unless we have the
2536 * MAC_CLIENT_FLAGS_MULTI_PRIMARY set (and this is not
2537 * a passive MAC client).
2539 if ((mcip
->mci_flags
& MAC_CLIENT_FLAGS_VNIC_PRIMARY
) != 0) {
2540 if ((mcip
->mci_flags
&
2541 MAC_CLIENT_FLAGS_MULTI_PRIMARY
) == 0 ||
2543 MAC_CLIENT_FLAGS_PASSIVE_PRIMARY
) != 0) {
2546 mcip
->mci_flags
|= MAC_CLIENT_FLAGS_PASSIVE_PRIMARY
;
2547 passive_client
= B_TRUE
;
2550 mcip
->mci_flags
|= MAC_CLIENT_FLAGS_VNIC_PRIMARY
;
2553 * Create a handle for vid 0.
2556 muip
= kmem_zalloc(sizeof (mac_unicast_impl_t
), KM_SLEEP
);
2557 muip
->mui_vid
= vid
;
2558 *mah
= (mac_unicast_handle_t
)muip
;
2560 * This will be used by the caller to defer setting the
2568 /* primary MAC clients cannot be opened on top of anchor VNICs */
2569 if ((is_vnic_primary
|| is_primary
) &&
2570 i_mac_capab_get((mac_handle_t
)mip
, MAC_CAPAB_ANCHOR_VNIC
, NULL
)) {
2575 * If this is a VNIC/VLAN, disable softmac fast-path.
2577 if (mcip
->mci_state_flags
& MCIS_IS_VNIC
) {
2578 err
= mac_fastpath_disable((mac_handle_t
)mip
);
2581 fastpath_disabled
= B_TRUE
;
2586 * - there is an exclusively active mac client exists.
2587 * - this is an exclusive active mac client but
2588 * a. there is already active mac clients exist, or
2589 * b. fastpath streams are already plumbed on this legacy device
2590 * - the mac creator has disallowed active mac clients.
2592 if (mip
->mi_state_flags
& (MIS_EXCLUSIVE
|MIS_NO_ACTIVE
)) {
2593 if (fastpath_disabled
)
2594 mac_fastpath_enable((mac_handle_t
)mip
);
2598 if (mcip
->mci_state_flags
& MCIS_EXCLUSIVE
) {
2599 ASSERT(!fastpath_disabled
);
2600 if (mip
->mi_nactiveclients
!= 0)
2603 if ((mip
->mi_state_flags
& MIS_LEGACY
) &&
2604 !(mip
->mi_capab_legacy
.ml_active_set(mip
->mi_driver
))) {
2607 mip
->mi_state_flags
|= MIS_EXCLUSIVE
;
2610 mrp
= kmem_zalloc(sizeof (*mrp
), KM_SLEEP
);
2611 if (is_primary
&& !(mcip
->mci_state_flags
& (MCIS_IS_VNIC
|
2612 MCIS_IS_AGGR_PORT
))) {
2614 * Apply the property cached in the mac_impl_t to the primary
2615 * mac client. If the mac client is a VNIC or an aggregation
2616 * port, its property should be set in the mcip when the
2617 * VNIC/aggr was created.
2619 mac_get_resources((mac_handle_t
)mip
, mrp
);
2620 (void) mac_client_set_resources(mch
, mrp
);
2621 } else if (mcip
->mci_state_flags
& MCIS_IS_VNIC
) {
2623 * This is a primary VLAN client, we don't support
2624 * specifying rings property for this as it inherits the
2625 * rings property from its MAC.
2627 if (is_vnic_primary
) {
2628 mac_resource_props_t
*vmrp
;
2630 vmrp
= MCIP_RESOURCE_PROPS(mcip
);
2631 if (vmrp
->mrp_mask
& MRP_RX_RINGS
||
2632 vmrp
->mrp_mask
& MRP_TX_RINGS
) {
2633 if (fastpath_disabled
)
2634 mac_fastpath_enable((mac_handle_t
)mip
);
2635 kmem_free(mrp
, sizeof (*mrp
));
2639 * Additionally we also need to inherit any
2640 * rings property from the MAC.
2642 mac_get_resources((mac_handle_t
)mip
, mrp
);
2643 if (mrp
->mrp_mask
& MRP_RX_RINGS
) {
2644 vmrp
->mrp_mask
|= MRP_RX_RINGS
;
2645 vmrp
->mrp_nrxrings
= mrp
->mrp_nrxrings
;
2647 if (mrp
->mrp_mask
& MRP_TX_RINGS
) {
2648 vmrp
->mrp_mask
|= MRP_TX_RINGS
;
2649 vmrp
->mrp_ntxrings
= mrp
->mrp_ntxrings
;
2652 bcopy(MCIP_RESOURCE_PROPS(mcip
), mrp
, sizeof (*mrp
));
2655 muip
= kmem_zalloc(sizeof (mac_unicast_impl_t
), KM_SLEEP
);
2656 muip
->mui_vid
= vid
;
2658 if (is_primary
|| is_vnic_primary
) {
2659 mac_addr
= mip
->mi_addr
;
2663 * Verify the validity of the specified MAC addresses value.
2665 if (!mac_unicst_verify((mac_handle_t
)mip
, mac_addr
, mac_len
)) {
2666 *diag
= MAC_DIAG_MACADDR_INVALID
;
2672 * Make sure that the specified MAC address is different
2673 * than the unicast MAC address of the underlying NIC.
2675 if (check_dups
&& bcmp(mip
->mi_addr
, mac_addr
, mac_len
) == 0) {
2676 *diag
= MAC_DIAG_MACADDR_NIC
;
2683 * Set the flags here so that if this is a passive client, we
2684 * can return and set it when we call mac_client_datapath_setup
2685 * when this becomes the active client. If we defer to using these
2686 * flags to mac_client_datapath_setup, then for a passive client,
2687 * we'd have to store the flags somewhere (probably fe_flags)
2690 if (!MCIP_DATAPATH_SETUP(mcip
)) {
2691 if (is_unicast_hw
) {
2693 * The client requires a hardware MAC address slot
2694 * for that unicast address. Since we support only
2695 * one unicast MAC address per client, flag the
2696 * MAC client itself.
2698 mcip
->mci_state_flags
|= MCIS_UNICAST_HW
;
2701 /* Check for VLAN flags, if present */
2702 if ((flags
& MAC_UNICAST_TAG_DISABLE
) != 0)
2703 mcip
->mci_state_flags
|= MCIS_TAG_DISABLE
;
2705 if ((flags
& MAC_UNICAST_STRIP_DISABLE
) != 0)
2706 mcip
->mci_state_flags
|= MCIS_STRIP_DISABLE
;
2708 if ((flags
& MAC_UNICAST_DISABLE_TX_VID_CHECK
) != 0)
2709 mcip
->mci_state_flags
|= MCIS_DISABLE_TX_VID_CHECK
;
2712 * Assert that the specified flags are consistent with the
2713 * flags specified by previous calls to mac_unicast_add().
2715 ASSERT(((flags
& MAC_UNICAST_TAG_DISABLE
) != 0 &&
2716 (mcip
->mci_state_flags
& MCIS_TAG_DISABLE
) != 0) ||
2717 ((flags
& MAC_UNICAST_TAG_DISABLE
) == 0 &&
2718 (mcip
->mci_state_flags
& MCIS_TAG_DISABLE
) == 0));
2720 ASSERT(((flags
& MAC_UNICAST_STRIP_DISABLE
) != 0 &&
2721 (mcip
->mci_state_flags
& MCIS_STRIP_DISABLE
) != 0) ||
2722 ((flags
& MAC_UNICAST_STRIP_DISABLE
) == 0 &&
2723 (mcip
->mci_state_flags
& MCIS_STRIP_DISABLE
) == 0));
2725 ASSERT(((flags
& MAC_UNICAST_DISABLE_TX_VID_CHECK
) != 0 &&
2726 (mcip
->mci_state_flags
& MCIS_DISABLE_TX_VID_CHECK
) != 0) ||
2727 ((flags
& MAC_UNICAST_DISABLE_TX_VID_CHECK
) == 0 &&
2728 (mcip
->mci_state_flags
& MCIS_DISABLE_TX_VID_CHECK
) == 0));
2731 * Make sure the client is consistent about its requests
2732 * for MAC addresses. I.e. all requests from the clients
2733 * must have the MAC_UNICAST_HW flag set or clear.
2735 if (((mcip
->mci_state_flags
& MCIS_UNICAST_HW
) != 0 &&
2737 ((mcip
->mci_state_flags
& MCIS_UNICAST_HW
) == 0 &&
2744 * Make sure the MAC address is not already used by
2745 * another MAC client defined on top of the same
2746 * underlying NIC. Unless we have MAC_CLIENT_FLAGS_MULTI_PRIMARY
2747 * set when we allow a passive client to be present which will
2748 * be activated when the currently active client goes away - this
2749 * works only with primary addresses.
2751 if ((check_dups
|| is_primary
|| is_vnic_primary
) &&
2752 mac_addr_in_use(mip
, mac_addr
, vid
)) {
2754 * Must have set the multiple primary address flag when
2755 * we did a mac_client_open AND this should be a primary
2756 * MAC client AND there should not already be a passive
2757 * primary. If all is true then we let this succeed
2758 * even if the address is a dup.
2760 if ((mcip
->mci_flags
& MAC_CLIENT_FLAGS_MULTI_PRIMARY
) == 0 ||
2761 (mcip
->mci_flags
& MAC_CLIENT_FLAGS_PRIMARY
) == 0 ||
2762 mac_get_passive_primary_client(mip
) != NULL
) {
2763 *diag
= MAC_DIAG_MACADDR_INUSE
;
2767 ASSERT((mcip
->mci_flags
&
2768 MAC_CLIENT_FLAGS_PASSIVE_PRIMARY
) == 0);
2769 mcip
->mci_flags
|= MAC_CLIENT_FLAGS_PASSIVE_PRIMARY
;
2770 kmem_free(mrp
, sizeof (*mrp
));
2773 * Stash the unicast address handle, we will use it when
2774 * we set up the passive client.
2776 mcip
->mci_p_unicast_list
= muip
;
2777 *mah
= (mac_unicast_handle_t
)muip
;
2781 err
= mac_client_datapath_setup(mcip
, vid
, mac_addr
, mrp
,
2782 is_primary
|| is_vnic_primary
, muip
);
2786 kmem_free(mrp
, sizeof (*mrp
));
2787 *mah
= (mac_unicast_handle_t
)muip
;
2791 if (fastpath_disabled
)
2792 mac_fastpath_enable((mac_handle_t
)mip
);
2793 if (mcip
->mci_state_flags
& MCIS_EXCLUSIVE
) {
2794 mip
->mi_state_flags
&= ~MIS_EXCLUSIVE
;
2795 if (mip
->mi_state_flags
& MIS_LEGACY
) {
2796 mip
->mi_capab_legacy
.ml_active_clear(
2800 kmem_free(mrp
, sizeof (*mrp
));
2801 kmem_free(muip
, sizeof (mac_unicast_impl_t
));
2806 * Wrapper function to mac_unicast_add when we want to have the same mac
2807 * client open for two instances, one that is currently active and another
2808 * that will become active when the current one is removed. In this case
2809 * mac_unicast_add will return EGAIN and we will save the rx function and
2810 * arg which will be used when we activate the passive client in
2811 * mac_unicast_remove.
2814 mac_unicast_add_set_rx(mac_client_handle_t mch
, uint8_t *mac_addr
,
2815 uint16_t flags
, mac_unicast_handle_t
*mah
, uint16_t vid
, mac_diag_t
*diag
,
2816 mac_rx_t rx_fn
, void *arg
)
2818 mac_client_impl_t
*mcip
= (mac_client_impl_t
*)mch
;
2821 err
= mac_unicast_add(mch
, mac_addr
, flags
, mah
, vid
, diag
);
2822 if (err
!= 0 && err
!= EAGAIN
)
2824 if (err
== EAGAIN
) {
2825 if (rx_fn
!= NULL
) {
2826 mcip
->mci_rx_p_fn
= rx_fn
;
2827 mcip
->mci_rx_p_arg
= arg
;
2832 mac_rx_set(mch
, rx_fn
, arg
);
2837 mac_unicast_add(mac_client_handle_t mch
, uint8_t *mac_addr
, uint16_t flags
,
2838 mac_unicast_handle_t
*mah
, uint16_t vid
, mac_diag_t
*diag
)
2840 mac_impl_t
*mip
= ((mac_client_impl_t
*)mch
)->mci_mip
;
2843 i_mac_perim_enter(mip
);
2844 err
= i_mac_unicast_add(mch
, mac_addr
, flags
, mah
, vid
, diag
);
2845 i_mac_perim_exit(mip
);
2851 mac_client_datapath_teardown(mac_client_handle_t mch
, mac_unicast_impl_t
*muip
,
2852 flow_entry_t
*flent
)
2854 mac_client_impl_t
*mcip
= (mac_client_impl_t
*)mch
;
2855 mac_impl_t
*mip
= mcip
->mci_mip
;
2856 boolean_t no_unicast
;
2859 * If we have not added a unicast address for this MAC client, just
2860 * teardown the datapath.
2862 no_unicast
= mcip
->mci_state_flags
& MCIS_NO_UNICAST_ADDR
;
2866 * We would have initialized subflows etc. only if we brought
2867 * up the primary client and set the unicast unicast address
2868 * etc. Deactivate the flows. The flow entry will be removed
2869 * from the active flow tables, and the associated SRS,
2870 * softrings etc will be deleted. But the flow entry itself
2871 * won't be destroyed, instead it will continue to be archived
2872 * off the the global flow hash list, for a possible future
2873 * activation when say IP is plumbed again.
2875 mac_link_release_flows(mch
);
2877 mip
->mi_nactiveclients
--;
2878 mac_update_single_active_client(mip
);
2880 /* Tear down the data path */
2881 mac_datapath_teardown(mcip
, mcip
->mci_flent
, SRST_LINK
);
2884 * Prevent any future access to the flow entry through the mci_flent
2885 * pointer by setting the mci_flent to NULL. Access to mci_flent in
2886 * mac_bcast_send is also under mi_rw_lock.
2888 rw_enter(&mip
->mi_rw_lock
, RW_WRITER
);
2889 flent
= mcip
->mci_flent
;
2890 mac_client_remove_flow_from_list(mcip
, flent
);
2892 if (mcip
->mci_state_flags
& MCIS_DESC_LOGGED
)
2893 mcip
->mci_state_flags
&= ~MCIS_DESC_LOGGED
;
2896 * This is the last unicast address being removed and there shouldn't
2897 * be any outbound data threads at this point coming down from mac
2898 * clients. We have waited for the data threads to finish before
2899 * starting dld_str_detach. Non-data threads must access TX SRS
2902 rw_exit(&mip
->mi_rw_lock
);
2905 * Don't use FLOW_MARK with FE_MC_NO_DATAPATH, as the flow might
2906 * contain other flags, such as FE_CONDEMNED, which we need to
2907 * cleared. We don't call mac_flow_cleanup() for this unicast
2908 * flow as we have a already cleaned up SRSs etc. (via the teadown
2909 * path). We just clear the stats and reset the initial callback
2910 * function, the rest will be set when we call mac_flow_create,
2913 mutex_enter(&flent
->fe_lock
);
2914 ASSERT(flent
->fe_refcnt
== 1 && flent
->fe_mbg
== NULL
&&
2915 flent
->fe_tx_srs
== NULL
&& flent
->fe_rx_srs_cnt
== 0);
2916 flent
->fe_flags
= FE_MC_NO_DATAPATH
;
2917 flow_stat_destroy(flent
);
2918 mac_misc_stat_delete(flent
);
2920 /* Initialize the receiver function to a safe routine */
2921 flent
->fe_cb_fn
= (flow_fn_t
)mac_pkt_drop
;
2922 flent
->fe_cb_arg1
= NULL
;
2923 flent
->fe_cb_arg2
= NULL
;
2925 flent
->fe_index
= -1;
2926 mutex_exit(&flent
->fe_lock
);
2928 if (mip
->mi_type
->mt_brdcst_addr
!= NULL
) {
2929 ASSERT(muip
!= NULL
|| no_unicast
);
2930 mac_bcast_delete(mcip
, mip
->mi_type
->mt_brdcst_addr
,
2931 muip
!= NULL
? muip
->mui_vid
: VLAN_ID_NONE
);
2934 if (mip
->mi_nactiveclients
== 1) {
2935 mac_capab_update((mac_handle_t
)mip
);
2936 mac_virtual_link_update(mip
);
2939 if (mcip
->mci_state_flags
& MCIS_EXCLUSIVE
) {
2940 mip
->mi_state_flags
&= ~MIS_EXCLUSIVE
;
2942 if (mip
->mi_state_flags
& MIS_LEGACY
)
2943 mip
->mi_capab_legacy
.ml_active_clear(mip
->mi_driver
);
2946 mcip
->mci_state_flags
&= ~MCIS_UNICAST_HW
;
2948 if (mcip
->mci_state_flags
& MCIS_TAG_DISABLE
)
2949 mcip
->mci_state_flags
&= ~MCIS_TAG_DISABLE
;
2951 if (mcip
->mci_state_flags
& MCIS_STRIP_DISABLE
)
2952 mcip
->mci_state_flags
&= ~MCIS_STRIP_DISABLE
;
2954 if (mcip
->mci_state_flags
& MCIS_DISABLE_TX_VID_CHECK
)
2955 mcip
->mci_state_flags
&= ~MCIS_DISABLE_TX_VID_CHECK
;
2958 kmem_free(muip
, sizeof (mac_unicast_impl_t
));
2959 mac_protect_cancel_timer(mcip
);
2960 mac_protect_flush_dynamic(mcip
);
2962 bzero(&mcip
->mci_misc_stat
, sizeof (mcip
->mci_misc_stat
));
2964 * Disable fastpath if this is a VNIC or a VLAN.
2966 if (mcip
->mci_state_flags
& MCIS_IS_VNIC
)
2967 mac_fastpath_enable((mac_handle_t
)mip
);
2968 mac_stop((mac_handle_t
)mip
);
2972 * Remove a MAC address which was previously added by mac_unicast_add().
2975 mac_unicast_remove(mac_client_handle_t mch
, mac_unicast_handle_t mah
)
2977 mac_client_impl_t
*mcip
= (mac_client_impl_t
*)mch
;
2978 mac_unicast_impl_t
*muip
= (mac_unicast_impl_t
*)mah
;
2979 mac_unicast_impl_t
*pre
;
2980 mac_impl_t
*mip
= mcip
->mci_mip
;
2981 flow_entry_t
*flent
;
2984 i_mac_perim_enter(mip
);
2985 if (mcip
->mci_flags
& MAC_CLIENT_FLAGS_VNIC_PRIMARY
) {
2987 * Called made by the upper MAC client of a VNIC.
2988 * There's nothing much to do, the unicast address will
2989 * be removed by the VNIC driver when the VNIC is deleted,
2990 * but let's ensure that all our transmit is done before
2991 * the client does a mac_client_stop lest it trigger an
2992 * assert in the driver.
2994 ASSERT(muip
->mui_vid
== 0);
2996 mac_tx_client_flush(mcip
);
2998 if ((mcip
->mci_flags
& MAC_CLIENT_FLAGS_PASSIVE_PRIMARY
) != 0) {
2999 mcip
->mci_flags
&= ~MAC_CLIENT_FLAGS_PASSIVE_PRIMARY
;
3000 if (mcip
->mci_rx_p_fn
!= NULL
) {
3001 mac_rx_set(mch
, mcip
->mci_rx_p_fn
,
3002 mcip
->mci_rx_p_arg
);
3003 mcip
->mci_rx_p_fn
= NULL
;
3004 mcip
->mci_rx_p_arg
= NULL
;
3006 kmem_free(muip
, sizeof (mac_unicast_impl_t
));
3007 i_mac_perim_exit(mip
);
3010 mcip
->mci_flags
&= ~MAC_CLIENT_FLAGS_VNIC_PRIMARY
;
3012 if (mcip
->mci_state_flags
& MCIS_TAG_DISABLE
)
3013 mcip
->mci_state_flags
&= ~MCIS_TAG_DISABLE
;
3015 if (mcip
->mci_state_flags
& MCIS_STRIP_DISABLE
)
3016 mcip
->mci_state_flags
&= ~MCIS_STRIP_DISABLE
;
3018 if (mcip
->mci_state_flags
& MCIS_DISABLE_TX_VID_CHECK
)
3019 mcip
->mci_state_flags
&= ~MCIS_DISABLE_TX_VID_CHECK
;
3021 kmem_free(muip
, sizeof (mac_unicast_impl_t
));
3022 i_mac_perim_exit(mip
);
3026 ASSERT(muip
!= NULL
);
3029 * We are removing a passive client, we haven't setup the datapath
3030 * for this yet, so nothing much to do.
3032 if ((mcip
->mci_flags
& MAC_CLIENT_FLAGS_PASSIVE_PRIMARY
) != 0) {
3034 ASSERT((mcip
->mci_flent
->fe_flags
& FE_MC_NO_DATAPATH
) != 0);
3035 ASSERT(mcip
->mci_p_unicast_list
== muip
);
3037 mcip
->mci_flags
&= ~MAC_CLIENT_FLAGS_PASSIVE_PRIMARY
;
3039 mcip
->mci_p_unicast_list
= NULL
;
3040 mcip
->mci_rx_p_fn
= NULL
;
3041 mcip
->mci_rx_p_arg
= NULL
;
3043 mcip
->mci_state_flags
&= ~MCIS_UNICAST_HW
;
3045 if (mcip
->mci_state_flags
& MCIS_TAG_DISABLE
)
3046 mcip
->mci_state_flags
&= ~MCIS_TAG_DISABLE
;
3048 if (mcip
->mci_state_flags
& MCIS_STRIP_DISABLE
)
3049 mcip
->mci_state_flags
&= ~MCIS_STRIP_DISABLE
;
3051 if (mcip
->mci_state_flags
& MCIS_DISABLE_TX_VID_CHECK
)
3052 mcip
->mci_state_flags
&= ~MCIS_DISABLE_TX_VID_CHECK
;
3054 kmem_free(muip
, sizeof (mac_unicast_impl_t
));
3055 i_mac_perim_exit(mip
);
3059 * Remove the VID from the list of client's VIDs.
3061 pre
= mcip
->mci_unicast_list
;
3063 mcip
->mci_unicast_list
= muip
->mui_next
;
3065 while ((pre
->mui_next
!= NULL
) && (pre
->mui_next
!= muip
))
3066 pre
= pre
->mui_next
;
3067 ASSERT(pre
->mui_next
== muip
);
3068 rw_enter(&mcip
->mci_rw_lock
, RW_WRITER
);
3069 pre
->mui_next
= muip
->mui_next
;
3070 rw_exit(&mcip
->mci_rw_lock
);
3073 if (!mac_client_single_rcvr(mcip
)) {
3075 * This MAC client is shared by more than one unicast
3076 * addresses, so we will just remove the flent
3077 * corresponding to the address being removed. We don't invoke
3078 * mac_rx_classify_flow_rem() since the additional flow is
3079 * not associated with its own separate set of SRS and rings,
3080 * and these constructs are still needed for the remaining
3083 flent
= mac_client_get_flow(mcip
, muip
);
3084 ASSERT(flent
!= NULL
);
3087 * The first one is disappearing, need to make sure
3088 * we replace it with another from the list of
3091 if (flent
== mcip
->mci_flent
)
3092 flent
= mac_client_swap_mciflent(mcip
);
3093 mac_client_remove_flow_from_list(mcip
, flent
);
3094 mac_flow_remove(mip
->mi_flow_tab
, flent
, B_FALSE
);
3095 mac_flow_wait(flent
, FLOW_DRIVER_UPCALL
);
3098 * The multicast groups that were added by the client so
3099 * far must be removed from the brodcast domain corresponding
3100 * to the VID being removed.
3102 mac_client_bcast_refresh(mcip
, mac_client_update_mcast
,
3103 (void *)flent
, B_FALSE
);
3105 if (mip
->mi_type
->mt_brdcst_addr
!= NULL
) {
3106 mac_bcast_delete(mcip
, mip
->mi_type
->mt_brdcst_addr
,
3110 FLOW_FINAL_REFRELE(flent
);
3111 ASSERT(!(mcip
->mci_state_flags
& MCIS_EXCLUSIVE
));
3113 * Enable fastpath if this is a VNIC or a VLAN.
3115 if (mcip
->mci_state_flags
& MCIS_IS_VNIC
)
3116 mac_fastpath_enable((mac_handle_t
)mip
);
3117 mac_stop((mac_handle_t
)mip
);
3118 i_mac_perim_exit(mip
);
3122 mui_vid
= muip
->mui_vid
;
3123 mac_client_datapath_teardown(mch
, muip
, flent
);
3125 if ((mcip
->mci_flags
& MAC_CLIENT_FLAGS_PRIMARY
) && mui_vid
== 0) {
3126 mcip
->mci_flags
&= ~MAC_CLIENT_FLAGS_PRIMARY
;
3128 i_mac_perim_exit(mip
);
3133 * If we are removing the primary, check if we have a passive primary
3134 * client that we need to activate now.
3136 mcip
= mac_get_passive_primary_client(mip
);
3138 mac_resource_props_t
*mrp
;
3139 mac_unicast_impl_t
*muip
;
3141 mcip
->mci_flags
&= ~MAC_CLIENT_FLAGS_PASSIVE_PRIMARY
;
3142 mrp
= kmem_zalloc(sizeof (*mrp
), KM_SLEEP
);
3145 * Apply the property cached in the mac_impl_t to the
3146 * primary mac client.
3148 mac_get_resources((mac_handle_t
)mip
, mrp
);
3149 (void) mac_client_set_resources(mch
, mrp
);
3150 ASSERT(mcip
->mci_p_unicast_list
!= NULL
);
3151 muip
= mcip
->mci_p_unicast_list
;
3152 mcip
->mci_p_unicast_list
= NULL
;
3153 if (mac_client_datapath_setup(mcip
, VLAN_ID_NONE
,
3154 mip
->mi_addr
, mrp
, B_TRUE
, muip
) == 0) {
3155 if (mcip
->mci_rx_p_fn
!= NULL
) {
3156 mac_rx_set(mch
, mcip
->mci_rx_p_fn
,
3157 mcip
->mci_rx_p_arg
);
3158 mcip
->mci_rx_p_fn
= NULL
;
3159 mcip
->mci_rx_p_arg
= NULL
;
3162 kmem_free(muip
, sizeof (mac_unicast_impl_t
));
3164 kmem_free(mrp
, sizeof (*mrp
));
3166 i_mac_perim_exit(mip
);
3171 * Multicast add function invoked by MAC clients.
3174 mac_multicast_add(mac_client_handle_t mch
, const uint8_t *addr
)
3176 mac_client_impl_t
*mcip
= (mac_client_impl_t
*)mch
;
3177 mac_impl_t
*mip
= mcip
->mci_mip
;
3178 flow_entry_t
*flent
= mcip
->mci_flent_list
;
3179 flow_entry_t
*prev_fe
= NULL
;
3183 /* Verify the address is a valid multicast address */
3184 if ((err
= mip
->mi_type
->mt_ops
.mtops_multicst_verify(addr
,
3185 mip
->mi_pdata
)) != 0)
3188 i_mac_perim_enter(mip
);
3189 while (flent
!= NULL
) {
3190 vid
= i_mac_flow_vid(flent
);
3192 err
= mac_bcast_add((mac_client_impl_t
*)mch
, addr
, vid
,
3193 MAC_ADDRTYPE_MULTICAST
);
3197 flent
= flent
->fe_client_next
;
3201 * If we failed adding, then undo all, rather than partial
3204 if (flent
!= NULL
&& prev_fe
!= NULL
) {
3205 flent
= mcip
->mci_flent_list
;
3206 while (flent
!= prev_fe
->fe_client_next
) {
3207 vid
= i_mac_flow_vid(flent
);
3208 mac_bcast_delete((mac_client_impl_t
*)mch
, addr
, vid
);
3209 flent
= flent
->fe_client_next
;
3212 i_mac_perim_exit(mip
);
3217 * Multicast delete function invoked by MAC clients.
3220 mac_multicast_remove(mac_client_handle_t mch
, const uint8_t *addr
)
3222 mac_client_impl_t
*mcip
= (mac_client_impl_t
*)mch
;
3223 mac_impl_t
*mip
= mcip
->mci_mip
;
3224 flow_entry_t
*flent
;
3227 i_mac_perim_enter(mip
);
3228 for (flent
= mcip
->mci_flent_list
; flent
!= NULL
;
3229 flent
= flent
->fe_client_next
) {
3230 vid
= i_mac_flow_vid(flent
);
3231 mac_bcast_delete((mac_client_impl_t
*)mch
, addr
, vid
);
3233 i_mac_perim_exit(mip
);
3237 * When a MAC client desires to capture packets on an interface,
3238 * it registers a promiscuous call back with mac_promisc_add().
3239 * There are three types of promiscuous callbacks:
3241 * * MAC_CLIENT_PROMISC_ALL
3242 * Captures all packets sent and received by the MAC client,
3243 * the physical interface, as well as all other MAC clients
3244 * defined on top of the same MAC.
3246 * * MAC_CLIENT_PROMISC_FILTERED
3247 * Captures all packets sent and received by the MAC client,
3248 * plus all multicast traffic sent and received by the phyisical
3249 * interface and the other MAC clients.
3251 * * MAC_CLIENT_PROMISC_MULTI
3252 * Captures all broadcast and multicast packets sent and
3253 * received by the MAC clients as well as the physical interface.
3255 * In all cases, the underlying MAC is put in promiscuous mode.
3258 mac_promisc_add(mac_client_handle_t mch
, mac_client_promisc_type_t type
,
3259 mac_rx_t fn
, void *arg
, mac_promisc_handle_t
*mphp
, uint16_t flags
)
3261 mac_client_impl_t
*mcip
= (mac_client_impl_t
*)mch
;
3262 mac_impl_t
*mip
= mcip
->mci_mip
;
3263 mac_promisc_impl_t
*mpip
;
3264 mac_cb_info_t
*mcbi
;
3267 i_mac_perim_enter(mip
);
3269 if ((rc
= mac_start((mac_handle_t
)mip
)) != 0) {
3270 i_mac_perim_exit(mip
);
3274 if ((mcip
->mci_state_flags
& MCIS_IS_VNIC
) &&
3275 type
== MAC_CLIENT_PROMISC_ALL
&&
3276 (mcip
->mci_protect_flags
& MPT_FLAG_PROMISC_FILTERED
)) {
3278 * The function is being invoked by the upper MAC client
3279 * of a VNIC. The VNIC should only see the traffic
3280 * it is entitled to.
3282 type
= MAC_CLIENT_PROMISC_FILTERED
;
3287 * Turn on promiscuous mode for the underlying NIC.
3288 * This is needed even for filtered callbacks which
3289 * expect to receive all multicast traffic on the wire.
3291 * Physical promiscuous mode should not be turned on if
3292 * MAC_PROMISC_FLAGS_NO_PHYS is set.
3294 if ((flags
& MAC_PROMISC_FLAGS_NO_PHYS
) == 0) {
3295 if ((rc
= i_mac_promisc_set(mip
, B_TRUE
)) != 0) {
3296 mac_stop((mac_handle_t
)mip
);
3297 i_mac_perim_exit(mip
);
3302 mpip
= kmem_cache_alloc(mac_promisc_impl_cache
, KM_SLEEP
);
3304 mpip
->mpi_type
= type
;
3306 mpip
->mpi_arg
= arg
;
3307 mpip
->mpi_mcip
= mcip
;
3308 mpip
->mpi_no_tx_loop
= ((flags
& MAC_PROMISC_FLAGS_NO_TX_LOOP
) != 0);
3309 mpip
->mpi_no_phys
= ((flags
& MAC_PROMISC_FLAGS_NO_PHYS
) != 0);
3310 mpip
->mpi_strip_vlan_tag
=
3311 ((flags
& MAC_PROMISC_FLAGS_VLAN_TAG_STRIP
) != 0);
3312 mpip
->mpi_no_copy
= ((flags
& MAC_PROMISC_FLAGS_NO_COPY
) != 0);
3314 mcbi
= &mip
->mi_promisc_cb_info
;
3315 mutex_enter(mcbi
->mcbi_lockp
);
3317 mac_callback_add(&mip
->mi_promisc_cb_info
, &mcip
->mci_promisc_list
,
3318 &mpip
->mpi_mci_link
);
3319 mac_callback_add(&mip
->mi_promisc_cb_info
, &mip
->mi_promisc_list
,
3320 &mpip
->mpi_mi_link
);
3322 mutex_exit(mcbi
->mcbi_lockp
);
3324 *mphp
= (mac_promisc_handle_t
)mpip
;
3326 if (mcip
->mci_state_flags
& MCIS_IS_VNIC
) {
3327 mac_impl_t
*umip
= mcip
->mci_upper_mip
;
3329 ASSERT(umip
!= NULL
);
3330 mac_vnic_secondary_update(umip
);
3333 i_mac_perim_exit(mip
);
3339 * Remove a multicast address previously aded through mac_promisc_add().
3342 mac_promisc_remove(mac_promisc_handle_t mph
)
3344 mac_promisc_impl_t
*mpip
= (mac_promisc_impl_t
*)mph
;
3345 mac_client_impl_t
*mcip
= mpip
->mpi_mcip
;
3346 mac_impl_t
*mip
= mcip
->mci_mip
;
3347 mac_cb_info_t
*mcbi
;
3350 i_mac_perim_enter(mip
);
3353 * Even if the device can't be reset into normal mode, we still
3354 * need to clear the client promisc callbacks. The client may want
3355 * to close the mac end point and we can't have stale callbacks.
3357 if (!(mpip
->mpi_no_phys
)) {
3358 if ((rv
= i_mac_promisc_set(mip
, B_FALSE
)) != 0) {
3359 cmn_err(CE_WARN
, "%s: failed to switch OFF promiscuous"
3360 " mode because of error 0x%x", mip
->mi_name
, rv
);
3363 mcbi
= &mip
->mi_promisc_cb_info
;
3364 mutex_enter(mcbi
->mcbi_lockp
);
3365 if (mac_callback_remove(mcbi
, &mip
->mi_promisc_list
,
3366 &mpip
->mpi_mi_link
)) {
3367 VERIFY(mac_callback_remove(&mip
->mi_promisc_cb_info
,
3368 &mcip
->mci_promisc_list
, &mpip
->mpi_mci_link
));
3369 kmem_cache_free(mac_promisc_impl_cache
, mpip
);
3371 mac_callback_remove_wait(&mip
->mi_promisc_cb_info
);
3374 if (mcip
->mci_state_flags
& MCIS_IS_VNIC
) {
3375 mac_impl_t
*umip
= mcip
->mci_upper_mip
;
3377 ASSERT(umip
!= NULL
);
3378 mac_vnic_secondary_update(umip
);
3381 mutex_exit(mcbi
->mcbi_lockp
);
3382 mac_stop((mac_handle_t
)mip
);
3384 i_mac_perim_exit(mip
);
3388 * Reference count the number of active Tx threads. MCI_TX_QUIESCE indicates
3389 * that a control operation wants to quiesce the Tx data flow in which case
3390 * we return an error. Holding any of the per cpu locks ensures that the
3391 * mci_tx_flag won't change.
3393 * 'CPU' must be accessed just once and used to compute the index into the
3394 * percpu array, and that index must be used for the entire duration of the
3395 * packet send operation. Note that the thread may be preempted and run on
3396 * another cpu any time and so we can't use 'CPU' more than once for the
3399 #define MAC_TX_TRY_HOLD(mcip, mytx, error) \
3402 (mytx) = &(mcip)->mci_tx_pcpu[CPU->cpu_seqid & mac_tx_percpu_cnt]; \
3403 mutex_enter(&(mytx)->pcpu_tx_lock); \
3404 if (!((mcip)->mci_tx_flag & MCI_TX_QUIESCE)) { \
3405 (mytx)->pcpu_tx_refcnt++; \
3409 mutex_exit(&(mytx)->pcpu_tx_lock); \
3413 * Release the reference. If needed, signal any control operation waiting
3414 * for Tx quiescence. The wait and signal are always done using the
3415 * mci_tx_pcpu[0]'s lock
3417 #define MAC_TX_RELE(mcip, mytx) { \
3418 mutex_enter(&(mytx)->pcpu_tx_lock); \
3419 if (--(mytx)->pcpu_tx_refcnt == 0 && \
3420 (mcip)->mci_tx_flag & MCI_TX_QUIESCE) { \
3421 mutex_exit(&(mytx)->pcpu_tx_lock); \
3422 mutex_enter(&(mcip)->mci_tx_pcpu[0].pcpu_tx_lock); \
3423 cv_signal(&(mcip)->mci_tx_cv); \
3424 mutex_exit(&(mcip)->mci_tx_pcpu[0].pcpu_tx_lock); \
3426 mutex_exit(&(mytx)->pcpu_tx_lock); \
3431 * Send function invoked by MAC clients.
3434 mac_tx(mac_client_handle_t mch
, mblk_t
*mp_chain
, uintptr_t hint
,
3435 uint16_t flag
, mblk_t
**ret_mp
)
3437 mac_tx_cookie_t cookie
= (uintptr_t)NULL
;
3439 mac_tx_percpu_t
*mytx
;
3440 mac_soft_ring_set_t
*srs
;
3441 flow_entry_t
*flent
;
3442 boolean_t is_subflow
= B_FALSE
;
3443 mac_client_impl_t
*mcip
= (mac_client_impl_t
*)mch
;
3444 mac_impl_t
*mip
= mcip
->mci_mip
;
3445 mac_srs_tx_t
*srs_tx
;
3448 * Check whether the active Tx threads count is bumped already.
3450 if (!(flag
& MAC_TX_NO_HOLD
)) {
3451 MAC_TX_TRY_HOLD(mcip
, mytx
, error
);
3453 freemsgchain(mp_chain
);
3454 return ((uintptr_t)NULL
);
3459 * If mac protection is enabled, only the permissible packets will be
3460 * returned by mac_protect_check().
3462 if ((mcip
->mci_flent
->
3463 fe_resource_props
.mrp_mask
& MRP_PROTECT
) != 0 &&
3464 (mp_chain
= mac_protect_check(mch
, mp_chain
)) == NULL
)
3467 if (mcip
->mci_subflow_tab
!= NULL
&&
3468 mcip
->mci_subflow_tab
->ft_flow_count
> 0 &&
3469 mac_flow_lookup(mcip
->mci_subflow_tab
, mp_chain
,
3470 FLOW_OUTBOUND
, &flent
) == 0) {
3472 * The main assumption here is that if in the event
3473 * we get a chain, all the packets will be classified
3474 * to the same Flow/SRS. If this changes for any
3475 * reason, the following logic should change as well.
3476 * I suppose the fanout_hint also assumes this .
3478 ASSERT(flent
!= NULL
);
3479 is_subflow
= B_TRUE
;
3481 flent
= mcip
->mci_flent
;
3484 srs
= flent
->fe_tx_srs
;
3486 * This is to avoid panics with PF_PACKET that can call mac_tx()
3487 * against an interface that is not capable of sending. A rewrite
3488 * of the mac datapath is required to remove this limitation.
3491 freemsgchain(mp_chain
);
3495 srs_tx
= &srs
->srs_tx
;
3496 if (srs_tx
->st_mode
== SRS_TX_DEFAULT
&&
3497 (srs
->srs_state
& SRS_ENQUEUED
) == 0 &&
3498 mip
->mi_nactiveclients
== 1 && mp_chain
->b_next
== NULL
) {
3502 * Since dls always opens the underlying MAC, nclients equals
3503 * to 1 means that the only active client is dls itself acting
3504 * as a primary client of the MAC instance. Since dls will not
3505 * send tagged packets in that case, and dls is trusted to send
3506 * packets for its allowed VLAN(s), the VLAN tag insertion and
3507 * check is required only if nclients is greater than 1.
3509 if (mip
->mi_nclients
> 1) {
3510 if (MAC_VID_CHECK_NEEDED(mcip
)) {
3513 MAC_VID_CHECK(mcip
, mp_chain
, err
);
3516 mcip
->mci_misc_stat
.mms_txerrors
++;
3520 if (MAC_TAG_NEEDED(mcip
)) {
3521 mp_chain
= mac_add_vlan_tag(mp_chain
, 0,
3522 mac_client_vid(mch
));
3523 if (mp_chain
== NULL
) {
3524 mcip
->mci_misc_stat
.mms_txerrors
++;
3530 obytes
= (mp_chain
->b_cont
== NULL
? MBLKL(mp_chain
) :
3531 msgdsize(mp_chain
));
3533 MAC_TX(mip
, srs_tx
->st_arg2
, mp_chain
, mcip
);
3534 if (mp_chain
== NULL
) {
3535 cookie
= (uintptr_t)NULL
;
3536 SRS_TX_STAT_UPDATE(srs
, opackets
, 1);
3537 SRS_TX_STAT_UPDATE(srs
, obytes
, obytes
);
3539 mutex_enter(&srs
->srs_lock
);
3540 cookie
= mac_tx_srs_no_desc(srs
, mp_chain
,
3542 mutex_exit(&srs
->srs_lock
);
3545 cookie
= srs_tx
->st_func(srs
, mp_chain
, hint
, flag
, ret_mp
);
3550 FLOW_REFRELE(flent
);
3552 if (!(flag
& MAC_TX_NO_HOLD
))
3553 MAC_TX_RELE(mcip
, mytx
);
3561 * Given a cookie, it returns if the ring identified by the cookie is
3562 * flow-controlled or not. If NULL is passed in place of a cookie,
3563 * then it finds out if any of the underlying rings belonging to the
3564 * SRS is flow controlled or not and returns that status.
3568 mac_tx_is_flow_blocked(mac_client_handle_t mch
, mac_tx_cookie_t cookie
)
3570 mac_client_impl_t
*mcip
= (mac_client_impl_t
*)mch
;
3571 mac_soft_ring_set_t
*mac_srs
;
3572 mac_soft_ring_t
*sringp
;
3573 boolean_t blocked
= B_FALSE
;
3574 mac_tx_percpu_t
*mytx
;
3579 * Bump the reference count so that mac_srs won't be deleted.
3580 * If the client is currently quiesced and we failed to bump
3581 * the reference, return B_TRUE so that flow control stays
3584 * Flow control will then be disabled once the client is no
3587 MAC_TX_TRY_HOLD(mcip
, mytx
, err
);
3591 if ((mac_srs
= MCIP_TX_SRS(mcip
)) == NULL
) {
3592 MAC_TX_RELE(mcip
, mytx
);
3596 mutex_enter(&mac_srs
->srs_lock
);
3598 * Only in the case of TX_FANOUT and TX_AGGR, the underlying
3599 * softring (s_ring_state) will have the HIWAT set. This is
3600 * the multiple Tx ring flow control case. For all other
3601 * case, SRS (srs_state) will store the condition.
3603 if (mac_srs
->srs_tx
.st_mode
== SRS_TX_FANOUT
||
3604 mac_srs
->srs_tx
.st_mode
== SRS_TX_AGGR
) {
3605 if (cookie
!= (uintptr_t)NULL
) {
3606 sringp
= (mac_soft_ring_t
*)cookie
;
3607 mutex_enter(&sringp
->s_ring_lock
);
3608 if (sringp
->s_ring_state
& S_RING_TX_HIWAT
)
3610 mutex_exit(&sringp
->s_ring_lock
);
3612 for (i
= 0; i
< mac_srs
->srs_tx_ring_count
; i
++) {
3613 sringp
= mac_srs
->srs_tx_soft_rings
[i
];
3614 mutex_enter(&sringp
->s_ring_lock
);
3615 if (sringp
->s_ring_state
& S_RING_TX_HIWAT
) {
3617 mutex_exit(&sringp
->s_ring_lock
);
3620 mutex_exit(&sringp
->s_ring_lock
);
3624 blocked
= (mac_srs
->srs_state
& SRS_TX_HIWAT
);
3626 mutex_exit(&mac_srs
->srs_lock
);
3627 MAC_TX_RELE(mcip
, mytx
);
3632 * Check if the MAC client is the primary MAC client.
3635 mac_is_primary_client(mac_client_impl_t
*mcip
)
3637 return (mcip
->mci_flags
& MAC_CLIENT_FLAGS_PRIMARY
);
3641 mac_ioctl(mac_handle_t mh
, queue_t
*wq
, mblk_t
*bp
)
3643 mac_impl_t
*mip
= (mac_impl_t
*)mh
;
3644 int cmd
= ((struct iocblk
*)bp
->b_rptr
)->ioc_cmd
;
3646 if ((cmd
== ND_GET
&& (mip
->mi_callbacks
->mc_callbacks
& MC_GETPROP
)) ||
3647 (cmd
== ND_SET
&& (mip
->mi_callbacks
->mc_callbacks
& MC_SETPROP
))) {
3649 * If ndd props were registered, call them.
3650 * Note that ndd ioctls are Obsolete
3652 mac_ndd_ioctl(mip
, wq
, bp
);
3657 * Call the driver to handle the ioctl. The driver may not support
3658 * any ioctls, in which case we reply with a NAK on its behalf.
3660 if (mip
->mi_callbacks
->mc_callbacks
& MC_IOCTL
)
3661 mip
->mi_ioctl(mip
->mi_driver
, wq
, bp
);
3663 miocnak(wq
, bp
, 0, EINVAL
);
3667 * Return the link state of the specified MAC instance.
3670 mac_link_get(mac_handle_t mh
)
3672 return (((mac_impl_t
*)mh
)->mi_linkstate
);
3676 * Add a mac client specified notification callback. Please see the comments
3677 * above mac_callback_add() for general information about mac callback
3678 * addition/deletion in the presence of mac callback list walkers
3681 mac_notify_add(mac_handle_t mh
, mac_notify_t notify_fn
, void *arg
)
3683 mac_impl_t
*mip
= (mac_impl_t
*)mh
;
3684 mac_notify_cb_t
*mncb
;
3685 mac_cb_info_t
*mcbi
;
3688 * Allocate a notify callback structure, fill in the details and
3689 * use the mac callback list manipulation functions to chain into
3690 * the list of callbacks.
3692 mncb
= kmem_zalloc(sizeof (mac_notify_cb_t
), KM_SLEEP
);
3693 mncb
->mncb_fn
= notify_fn
;
3694 mncb
->mncb_arg
= arg
;
3695 mncb
->mncb_mip
= mip
;
3696 mncb
->mncb_link
.mcb_objp
= mncb
;
3697 mncb
->mncb_link
.mcb_objsize
= sizeof (mac_notify_cb_t
);
3698 mncb
->mncb_link
.mcb_flags
= MCB_NOTIFY_CB_T
;
3700 mcbi
= &mip
->mi_notify_cb_info
;
3702 i_mac_perim_enter(mip
);
3703 mutex_enter(mcbi
->mcbi_lockp
);
3705 mac_callback_add(&mip
->mi_notify_cb_info
, &mip
->mi_notify_cb_list
,
3708 mutex_exit(mcbi
->mcbi_lockp
);
3709 i_mac_perim_exit(mip
);
3710 return ((mac_notify_handle_t
)mncb
);
3714 mac_notify_remove_wait(mac_handle_t mh
)
3716 mac_impl_t
*mip
= (mac_impl_t
*)mh
;
3717 mac_cb_info_t
*mcbi
= &mip
->mi_notify_cb_info
;
3719 mutex_enter(mcbi
->mcbi_lockp
);
3720 mac_callback_remove_wait(&mip
->mi_notify_cb_info
);
3721 mutex_exit(mcbi
->mcbi_lockp
);
3725 * Remove a mac client specified notification callback
3728 mac_notify_remove(mac_notify_handle_t mnh
, boolean_t wait
)
3730 mac_notify_cb_t
*mncb
= (mac_notify_cb_t
*)mnh
;
3731 mac_impl_t
*mip
= mncb
->mncb_mip
;
3732 mac_cb_info_t
*mcbi
;
3735 mcbi
= &mip
->mi_notify_cb_info
;
3737 i_mac_perim_enter(mip
);
3738 mutex_enter(mcbi
->mcbi_lockp
);
3740 ASSERT(mncb
->mncb_link
.mcb_objp
== mncb
);
3742 * If there aren't any list walkers, the remove would succeed
3743 * inline, else we wait for the deferred remove to complete
3745 if (mac_callback_remove(&mip
->mi_notify_cb_info
,
3746 &mip
->mi_notify_cb_list
, &mncb
->mncb_link
)) {
3747 kmem_free(mncb
, sizeof (mac_notify_cb_t
));
3752 mutex_exit(mcbi
->mcbi_lockp
);
3753 i_mac_perim_exit(mip
);
3756 * If we failed to remove the notification callback and "wait" is set
3757 * to be B_TRUE, wait for the callback to finish after we exit the
3760 if (err
!= 0 && wait
) {
3761 mac_notify_remove_wait((mac_handle_t
)mip
);
3769 * Associate resource management callbacks with the specified MAC
3774 mac_resource_set_common(mac_client_handle_t mch
, mac_resource_add_t add
,
3775 mac_resource_remove_t remove
, mac_resource_quiesce_t quiesce
,
3776 mac_resource_restart_t restart
, mac_resource_bind_t bind
,
3779 mac_client_impl_t
*mcip
= (mac_client_impl_t
*)mch
;
3781 mcip
->mci_resource_add
= add
;
3782 mcip
->mci_resource_remove
= remove
;
3783 mcip
->mci_resource_quiesce
= quiesce
;
3784 mcip
->mci_resource_restart
= restart
;
3785 mcip
->mci_resource_bind
= bind
;
3786 mcip
->mci_resource_arg
= arg
;
3790 mac_resource_set(mac_client_handle_t mch
, mac_resource_add_t add
, void *arg
)
3792 /* update the 'resource_add' callback */
3793 mac_resource_set_common(mch
, add
, NULL
, NULL
, NULL
, NULL
, arg
);
3797 * Sets up the client resources and enable the polling interface over all the
3798 * SRS's and the soft rings of the client
3801 mac_client_poll_enable(mac_client_handle_t mch
)
3803 mac_client_impl_t
*mcip
= (mac_client_impl_t
*)mch
;
3804 mac_soft_ring_set_t
*mac_srs
;
3805 flow_entry_t
*flent
;
3808 flent
= mcip
->mci_flent
;
3809 ASSERT(flent
!= NULL
);
3811 mcip
->mci_state_flags
|= MCIS_CLIENT_POLL_CAPABLE
;
3812 for (i
= 0; i
< flent
->fe_rx_srs_cnt
; i
++) {
3813 mac_srs
= (mac_soft_ring_set_t
*)flent
->fe_rx_srs
[i
];
3814 ASSERT(mac_srs
->srs_mcip
== mcip
);
3815 mac_srs_client_poll_enable(mcip
, mac_srs
);
3820 * Tears down the client resources and disable the polling interface over all
3821 * the SRS's and the soft rings of the client
3824 mac_client_poll_disable(mac_client_handle_t mch
)
3826 mac_client_impl_t
*mcip
= (mac_client_impl_t
*)mch
;
3827 mac_soft_ring_set_t
*mac_srs
;
3828 flow_entry_t
*flent
;
3831 flent
= mcip
->mci_flent
;
3832 ASSERT(flent
!= NULL
);
3834 mcip
->mci_state_flags
&= ~MCIS_CLIENT_POLL_CAPABLE
;
3835 for (i
= 0; i
< flent
->fe_rx_srs_cnt
; i
++) {
3836 mac_srs
= (mac_soft_ring_set_t
*)flent
->fe_rx_srs
[i
];
3837 ASSERT(mac_srs
->srs_mcip
== mcip
);
3838 mac_srs_client_poll_disable(mcip
, mac_srs
);
3843 * Associate the CPUs specified by the given property with a MAC client.
3846 mac_cpu_set(mac_client_handle_t mch
, mac_resource_props_t
*mrp
)
3848 mac_client_impl_t
*mcip
= (mac_client_impl_t
*)mch
;
3849 mac_impl_t
*mip
= mcip
->mci_mip
;
3852 ASSERT(MAC_PERIM_HELD((mac_handle_t
)mip
));
3854 if ((err
= mac_validate_props(mcip
->mci_state_flags
& MCIS_IS_VNIC
?
3855 mcip
->mci_upper_mip
: mip
, mrp
)) != 0) {
3858 if (MCIP_DATAPATH_SETUP(mcip
))
3859 mac_flow_modify(mip
->mi_flow_tab
, mcip
->mci_flent
, mrp
);
3861 mac_update_resources(mrp
, MCIP_RESOURCE_PROPS(mcip
), B_FALSE
);
3866 * Apply the specified properties to the specified MAC client.
3869 mac_client_set_resources(mac_client_handle_t mch
, mac_resource_props_t
*mrp
)
3871 mac_client_impl_t
*mcip
= (mac_client_impl_t
*)mch
;
3872 mac_impl_t
*mip
= mcip
->mci_mip
;
3875 i_mac_perim_enter(mip
);
3877 if ((mrp
->mrp_mask
& MRP_MAXBW
) || (mrp
->mrp_mask
& MRP_PRIORITY
)) {
3878 err
= mac_resource_ctl_set(mch
, mrp
);
3883 if (mrp
->mrp_mask
& (MRP_CPUS
|MRP_POOL
)) {
3884 err
= mac_cpu_set(mch
, mrp
);
3889 if (mrp
->mrp_mask
& MRP_PROTECT
) {
3890 err
= mac_protect_set(mch
, mrp
);
3895 if ((mrp
->mrp_mask
& MRP_RX_RINGS
) || (mrp
->mrp_mask
& MRP_TX_RINGS
))
3896 err
= mac_resource_ctl_set(mch
, mrp
);
3899 i_mac_perim_exit(mip
);
3904 * Return the properties currently associated with the specified MAC client.
3907 mac_client_get_resources(mac_client_handle_t mch
, mac_resource_props_t
*mrp
)
3909 mac_client_impl_t
*mcip
= (mac_client_impl_t
*)mch
;
3910 mac_resource_props_t
*mcip_mrp
= MCIP_RESOURCE_PROPS(mcip
);
3912 bcopy(mcip_mrp
, mrp
, sizeof (mac_resource_props_t
));
3916 * Return the effective properties currently associated with the specified
3920 mac_client_get_effective_resources(mac_client_handle_t mch
,
3921 mac_resource_props_t
*mrp
)
3923 mac_client_impl_t
*mcip
= (mac_client_impl_t
*)mch
;
3924 mac_resource_props_t
*mcip_mrp
= MCIP_EFFECTIVE_PROPS(mcip
);
3926 bcopy(mcip_mrp
, mrp
, sizeof (mac_resource_props_t
));
3930 * Pass a copy of the specified packet to the promiscuous callbacks
3931 * of the specified MAC.
3933 * If sender is NULL, the function is being invoked for a packet chain
3934 * received from the wire. If sender is non-NULL, it points to
3935 * the MAC client from which the packet is being sent.
3937 * The packets are distributed to the promiscuous callbacks as follows:
3939 * - all packets are sent to the MAC_CLIENT_PROMISC_ALL callbacks
3940 * - all broadcast and multicast packets are sent to the
3941 * MAC_CLIENT_PROMISC_FILTER and MAC_CLIENT_PROMISC_MULTI.
3943 * The unicast packets of MAC_CLIENT_PROMISC_FILTER callbacks are dispatched
3944 * after classification by mac_rx_deliver().
3948 mac_promisc_dispatch_one(mac_promisc_impl_t
*mpip
, mblk_t
*mp
,
3951 mblk_t
*mp_copy
, *mp_next
;
3953 if (!mpip
->mpi_no_copy
|| mpip
->mpi_strip_vlan_tag
) {
3954 mp_copy
= copymsg(mp
);
3955 if (mp_copy
== NULL
)
3958 if (mpip
->mpi_strip_vlan_tag
) {
3959 mp_copy
= mac_strip_vlan_tag_chain(mp_copy
);
3960 if (mp_copy
== NULL
)
3966 mp_next
= mp
->b_next
;
3968 mp_copy
->b_next
= NULL
;
3970 mpip
->mpi_fn(mpip
->mpi_arg
, NULL
, mp_copy
, loopback
);
3972 mp
->b_next
= mp_next
;
3976 * Return the VID of a packet. Zero if the packet is not tagged.
3979 mac_ether_vid(mblk_t
*mp
)
3981 struct ether_header
*eth
= (struct ether_header
*)mp
->b_rptr
;
3983 if (ntohs(eth
->ether_type
) == ETHERTYPE_VLAN
) {
3984 struct ether_vlan_header
*t_evhp
=
3985 (struct ether_vlan_header
*)mp
->b_rptr
;
3986 return (VLAN_ID(ntohs(t_evhp
->ether_tci
)));
3993 * Return whether the specified packet contains a multicast or broadcast
3994 * destination MAC address.
3997 mac_is_mcast(mac_impl_t
*mip
, mblk_t
*mp
)
3999 mac_header_info_t hdr_info
;
4001 if (mac_header_info((mac_handle_t
)mip
, mp
, &hdr_info
) != 0)
4003 return ((hdr_info
.mhi_dsttype
== MAC_ADDRTYPE_BROADCAST
) ||
4004 (hdr_info
.mhi_dsttype
== MAC_ADDRTYPE_MULTICAST
));
4008 * Send a copy of an mblk chain to the MAC clients of the specified MAC.
4009 * "sender" points to the sender MAC client for outbound packets, and
4010 * is set to NULL for inbound packets.
4013 mac_promisc_dispatch(mac_impl_t
*mip
, mblk_t
*mp_chain
,
4014 mac_client_impl_t
*sender
)
4016 mac_promisc_impl_t
*mpip
;
4019 boolean_t is_mcast
, is_sender
;
4021 MAC_PROMISC_WALKER_INC(mip
);
4022 for (mp
= mp_chain
; mp
!= NULL
; mp
= mp
->b_next
) {
4023 is_mcast
= mac_is_mcast(mip
, mp
);
4024 /* send packet to interested callbacks */
4025 for (mcb
= mip
->mi_promisc_list
; mcb
!= NULL
;
4026 mcb
= mcb
->mcb_nextp
) {
4027 mpip
= (mac_promisc_impl_t
*)mcb
->mcb_objp
;
4028 is_sender
= (mpip
->mpi_mcip
== sender
);
4030 if (is_sender
&& mpip
->mpi_no_tx_loop
)
4032 * The sender doesn't want to receive
4033 * copies of the packets it sends.
4037 /* this client doesn't need any packets (bridge) */
4038 if (mpip
->mpi_fn
== NULL
)
4042 * For an ethernet MAC, don't displatch a multicast
4043 * packet to a non-PROMISC_ALL callbacks unless the VID
4044 * of the packet matches the VID of the client.
4047 mpip
->mpi_type
!= MAC_CLIENT_PROMISC_ALL
&&
4048 !mac_client_check_flow_vid(mpip
->mpi_mcip
,
4053 mpip
->mpi_type
== MAC_CLIENT_PROMISC_ALL
||
4055 mac_promisc_dispatch_one(mpip
, mp
, is_sender
);
4058 MAC_PROMISC_WALKER_DCR(mip
);
4062 mac_promisc_client_dispatch(mac_client_impl_t
*mcip
, mblk_t
*mp_chain
)
4064 mac_impl_t
*mip
= mcip
->mci_mip
;
4065 mac_promisc_impl_t
*mpip
;
4071 * The unicast packets for the MAC client still
4072 * need to be delivered to the MAC_CLIENT_PROMISC_FILTERED
4073 * promiscuous callbacks. The broadcast and multicast
4074 * packets were delivered from mac_rx().
4076 MAC_PROMISC_WALKER_INC(mip
);
4077 for (mp
= mp_chain
; mp
!= NULL
; mp
= mp
->b_next
) {
4078 is_mcast
= mac_is_mcast(mip
, mp
);
4079 for (mcb
= mcip
->mci_promisc_list
; mcb
!= NULL
;
4080 mcb
= mcb
->mcb_nextp
) {
4081 mpip
= (mac_promisc_impl_t
*)mcb
->mcb_objp
;
4082 if (mpip
->mpi_type
== MAC_CLIENT_PROMISC_FILTERED
&&
4084 mac_promisc_dispatch_one(mpip
, mp
, B_FALSE
);
4088 MAC_PROMISC_WALKER_DCR(mip
);
4092 * Return the margin value currently assigned to the specified MAC instance.
4095 mac_margin_get(mac_handle_t mh
, uint32_t *marginp
)
4097 mac_impl_t
*mip
= (mac_impl_t
*)mh
;
4099 rw_enter(&(mip
->mi_rw_lock
), RW_READER
);
4100 *marginp
= mip
->mi_margin
;
4101 rw_exit(&(mip
->mi_rw_lock
));
4105 * mac_info_get() is used for retrieving the mac_info when a DL_INFO_REQ is
4106 * issued before a DL_ATTACH_REQ. we walk the i_mac_impl_hash table and find
4107 * the first mac_impl_t with a matching driver name; then we copy its mac_info_t
4108 * to the caller. we do all this with i_mac_impl_lock held so the mac_impl_t
4109 * cannot disappear while we are accessing it.
4111 typedef struct i_mac_info_state_s
{
4112 const char *mi_name
;
4113 mac_info_t
*mi_infop
;
4114 } i_mac_info_state_t
;
4118 i_mac_info_walker(mod_hash_key_t key
, mod_hash_val_t
*val
, void *arg
)
4120 i_mac_info_state_t
*statep
= arg
;
4121 mac_impl_t
*mip
= (mac_impl_t
*)val
;
4123 if (mip
->mi_state_flags
& MIS_DISABLED
)
4124 return (MH_WALK_CONTINUE
);
4126 if (strcmp(statep
->mi_name
,
4127 ddi_driver_name(mip
->mi_dip
)) != 0)
4128 return (MH_WALK_CONTINUE
);
4130 statep
->mi_infop
= &mip
->mi_info
;
4131 return (MH_WALK_TERMINATE
);
4135 mac_info_get(const char *name
, mac_info_t
*minfop
)
4137 i_mac_info_state_t state
;
4139 rw_enter(&i_mac_impl_lock
, RW_READER
);
4140 state
.mi_name
= name
;
4141 state
.mi_infop
= NULL
;
4142 mod_hash_walk(i_mac_impl_hash
, i_mac_info_walker
, &state
);
4143 if (state
.mi_infop
== NULL
) {
4144 rw_exit(&i_mac_impl_lock
);
4147 *minfop
= *state
.mi_infop
;
4148 rw_exit(&i_mac_impl_lock
);
4153 * To get the capabilities that MAC layer cares about, such as rings, factory
4154 * mac address, vnic or not, it should directly invoke this function. If the
4155 * link is part of a bridge, then the only "capability" it has is the inability
4159 i_mac_capab_get(mac_handle_t mh
, mac_capab_t cap
, void *cap_data
)
4161 mac_impl_t
*mip
= (mac_impl_t
*)mh
;
4163 if (mip
->mi_bridge_link
!= NULL
)
4164 return (cap
== MAC_CAPAB_NO_ZCOPY
);
4165 else if (mip
->mi_callbacks
->mc_callbacks
& MC_GETCAPAB
)
4166 return (mip
->mi_getcapab(mip
->mi_driver
, cap
, cap_data
));
4172 * Capability query function. If number of active mac clients is greater than
4173 * 1, only limited capabilities can be advertised to the caller no matter the
4174 * driver has certain capability or not. Else, we query the driver to get the
4178 mac_capab_get(mac_handle_t mh
, mac_capab_t cap
, void *cap_data
)
4180 mac_impl_t
*mip
= (mac_impl_t
*)mh
;
4183 * if mi_nactiveclients > 1, only MAC_CAPAB_LEGACY, MAC_CAPAB_HCKSUM,
4184 * MAC_CAPAB_NO_NATIVEVLAN and MAC_CAPAB_NO_ZCOPY can be advertised.
4186 if (mip
->mi_nactiveclients
> 1) {
4188 case MAC_CAPAB_NO_ZCOPY
:
4190 case MAC_CAPAB_LEGACY
:
4191 case MAC_CAPAB_HCKSUM
:
4192 case MAC_CAPAB_NO_NATIVEVLAN
:
4199 /* else get capab from driver */
4200 return (i_mac_capab_get(mh
, cap
, cap_data
));
4204 mac_sap_verify(mac_handle_t mh
, uint32_t sap
, uint32_t *bind_sap
)
4206 mac_impl_t
*mip
= (mac_impl_t
*)mh
;
4208 return (mip
->mi_type
->mt_ops
.mtops_sap_verify(sap
, bind_sap
,
4213 mac_header(mac_handle_t mh
, const uint8_t *daddr
, uint32_t sap
, mblk_t
*payload
,
4216 mac_impl_t
*mip
= (mac_impl_t
*)mh
;
4217 const uint8_t *hdr_daddr
;
4220 * If the MAC is point-to-point with a fixed destination address, then
4221 * we must always use that destination in the MAC header.
4223 hdr_daddr
= (mip
->mi_dstaddr_set
? mip
->mi_dstaddr
: daddr
);
4224 return (mip
->mi_type
->mt_ops
.mtops_header(mip
->mi_addr
, hdr_daddr
, sap
,
4225 mip
->mi_pdata
, payload
, extra_len
));
4229 mac_header_info(mac_handle_t mh
, mblk_t
*mp
, mac_header_info_t
*mhip
)
4231 mac_impl_t
*mip
= (mac_impl_t
*)mh
;
4233 return (mip
->mi_type
->mt_ops
.mtops_header_info(mp
, mip
->mi_pdata
,
4238 mac_vlan_header_info(mac_handle_t mh
, mblk_t
*mp
, mac_header_info_t
*mhip
)
4240 mac_impl_t
*mip
= (mac_impl_t
*)mh
;
4241 boolean_t is_ethernet
= (mip
->mi_info
.mi_media
== DL_ETHER
);
4245 * Packets should always be at least 16 bit aligned.
4247 ASSERT(IS_P2ALIGNED(mp
->b_rptr
, sizeof (uint16_t)));
4249 if ((err
= mac_header_info(mh
, mp
, mhip
)) != 0)
4253 * If this is a VLAN-tagged Ethernet packet, then the SAP in the
4254 * mac_header_info_t as returned by mac_header_info() is
4255 * ETHERTYPE_VLAN. We need to grab the ethertype from the VLAN header.
4257 if (is_ethernet
&& (mhip
->mhi_bindsap
== ETHERTYPE_VLAN
)) {
4258 struct ether_vlan_header
*evhp
;
4263 size
= sizeof (struct ether_vlan_header
);
4264 if (MBLKL(mp
) < size
) {
4266 * Pullup the message in order to get the MAC header
4267 * infomation. Note that this is a read-only function,
4268 * we keep the input packet intact.
4270 if ((tmp
= msgpullup(mp
, size
)) == NULL
)
4275 evhp
= (struct ether_vlan_header
*)mp
->b_rptr
;
4276 sap
= ntohs(evhp
->ether_type
);
4277 (void) mac_sap_verify(mh
, sap
, &mhip
->mhi_bindsap
);
4278 mhip
->mhi_hdrsize
= sizeof (struct ether_vlan_header
);
4279 mhip
->mhi_tci
= ntohs(evhp
->ether_tci
);
4280 mhip
->mhi_istagged
= B_TRUE
;
4283 if (VLAN_CFI(mhip
->mhi_tci
) != ETHER_CFI
)
4286 mhip
->mhi_istagged
= B_FALSE
;
4294 mac_header_cook(mac_handle_t mh
, mblk_t
*mp
)
4296 mac_impl_t
*mip
= (mac_impl_t
*)mh
;
4298 if (mip
->mi_type
->mt_ops
.mtops_ops
& MTOPS_HEADER_COOK
) {
4299 if (DB_REF(mp
) > 1) {
4300 mblk_t
*newmp
= copymsg(mp
);
4306 return (mip
->mi_type
->mt_ops
.mtops_header_cook(mp
,
4313 mac_header_uncook(mac_handle_t mh
, mblk_t
*mp
)
4315 mac_impl_t
*mip
= (mac_impl_t
*)mh
;
4317 if (mip
->mi_type
->mt_ops
.mtops_ops
& MTOPS_HEADER_UNCOOK
) {
4318 if (DB_REF(mp
) > 1) {
4319 mblk_t
*newmp
= copymsg(mp
);
4325 return (mip
->mi_type
->mt_ops
.mtops_header_uncook(mp
,
4332 mac_addr_len(mac_handle_t mh
)
4334 mac_impl_t
*mip
= (mac_impl_t
*)mh
;
4336 return (mip
->mi_type
->mt_addr_length
);
4339 /* True if a MAC is a VNIC */
4341 mac_is_vnic(mac_handle_t mh
)
4343 return (((mac_impl_t
*)mh
)->mi_state_flags
& MIS_IS_VNIC
);
4347 mac_get_lower_mac_handle(mac_handle_t mh
)
4349 mac_impl_t
*mip
= (mac_impl_t
*)mh
;
4351 ASSERT(mac_is_vnic(mh
));
4352 return (((vnic_t
*)mip
->mi_driver
)->vn_lower_mh
);
4356 mac_is_vnic_primary(mac_handle_t mh
)
4358 mac_impl_t
*mip
= (mac_impl_t
*)mh
;
4360 ASSERT(mac_is_vnic(mh
));
4361 return (((vnic_t
*)mip
->mi_driver
)->vn_addr_type
==
4362 VNIC_MAC_ADDR_TYPE_PRIMARY
);
4366 mac_update_resources(mac_resource_props_t
*nmrp
, mac_resource_props_t
*cmrp
,
4367 boolean_t is_user_flow
)
4369 if (nmrp
!= NULL
&& cmrp
!= NULL
) {
4370 if (nmrp
->mrp_mask
& MRP_PRIORITY
) {
4371 if (nmrp
->mrp_priority
== MPL_RESET
) {
4372 cmrp
->mrp_mask
&= ~MRP_PRIORITY
;
4374 cmrp
->mrp_priority
=
4375 MPL_SUBFLOW_DEFAULT
;
4377 cmrp
->mrp_priority
= MPL_LINK_DEFAULT
;
4380 cmrp
->mrp_mask
|= MRP_PRIORITY
;
4381 cmrp
->mrp_priority
= nmrp
->mrp_priority
;
4384 if (nmrp
->mrp_mask
& MRP_MAXBW
) {
4385 if (nmrp
->mrp_maxbw
== MRP_MAXBW_RESETVAL
) {
4386 cmrp
->mrp_mask
&= ~MRP_MAXBW
;
4387 cmrp
->mrp_maxbw
= 0;
4389 cmrp
->mrp_mask
|= MRP_MAXBW
;
4390 cmrp
->mrp_maxbw
= nmrp
->mrp_maxbw
;
4393 if (nmrp
->mrp_mask
& MRP_CPUS
)
4394 MAC_COPY_CPUS(nmrp
, cmrp
);
4396 if (nmrp
->mrp_mask
& MRP_POOL
) {
4397 if (strlen(nmrp
->mrp_pool
) == 0) {
4398 cmrp
->mrp_mask
&= ~MRP_POOL
;
4399 bzero(cmrp
->mrp_pool
, sizeof (cmrp
->mrp_pool
));
4401 cmrp
->mrp_mask
|= MRP_POOL
;
4402 (void) strncpy(cmrp
->mrp_pool
, nmrp
->mrp_pool
,
4403 sizeof (cmrp
->mrp_pool
));
4408 if (nmrp
->mrp_mask
& MRP_PROTECT
)
4409 mac_protect_update(nmrp
, cmrp
);
4412 * Update the rings specified.
4414 if (nmrp
->mrp_mask
& MRP_RX_RINGS
) {
4415 if (nmrp
->mrp_mask
& MRP_RINGS_RESET
) {
4416 cmrp
->mrp_mask
&= ~MRP_RX_RINGS
;
4417 if (cmrp
->mrp_mask
& MRP_RXRINGS_UNSPEC
)
4418 cmrp
->mrp_mask
&= ~MRP_RXRINGS_UNSPEC
;
4419 cmrp
->mrp_nrxrings
= 0;
4421 cmrp
->mrp_mask
|= MRP_RX_RINGS
;
4422 cmrp
->mrp_nrxrings
= nmrp
->mrp_nrxrings
;
4425 if (nmrp
->mrp_mask
& MRP_TX_RINGS
) {
4426 if (nmrp
->mrp_mask
& MRP_RINGS_RESET
) {
4427 cmrp
->mrp_mask
&= ~MRP_TX_RINGS
;
4428 if (cmrp
->mrp_mask
& MRP_TXRINGS_UNSPEC
)
4429 cmrp
->mrp_mask
&= ~MRP_TXRINGS_UNSPEC
;
4430 cmrp
->mrp_ntxrings
= 0;
4432 cmrp
->mrp_mask
|= MRP_TX_RINGS
;
4433 cmrp
->mrp_ntxrings
= nmrp
->mrp_ntxrings
;
4436 if (nmrp
->mrp_mask
& MRP_RXRINGS_UNSPEC
)
4437 cmrp
->mrp_mask
|= MRP_RXRINGS_UNSPEC
;
4438 else if (cmrp
->mrp_mask
& MRP_RXRINGS_UNSPEC
)
4439 cmrp
->mrp_mask
&= ~MRP_RXRINGS_UNSPEC
;
4441 if (nmrp
->mrp_mask
& MRP_TXRINGS_UNSPEC
)
4442 cmrp
->mrp_mask
|= MRP_TXRINGS_UNSPEC
;
4443 else if (cmrp
->mrp_mask
& MRP_TXRINGS_UNSPEC
)
4444 cmrp
->mrp_mask
&= ~MRP_TXRINGS_UNSPEC
;
4449 * i_mac_set_resources:
4451 * This routine associates properties with the primary MAC client of
4452 * the specified MAC instance.
4453 * - Cache the properties in mac_impl_t
4454 * - Apply the properties to the primary MAC client if exists
4457 i_mac_set_resources(mac_handle_t mh
, mac_resource_props_t
*mrp
)
4459 mac_impl_t
*mip
= (mac_impl_t
*)mh
;
4460 mac_client_impl_t
*mcip
;
4462 uint32_t resmask
, newresmask
;
4463 mac_resource_props_t
*tmrp
, *umrp
;
4465 ASSERT(MAC_PERIM_HELD((mac_handle_t
)mip
));
4467 err
= mac_validate_props(mip
, mrp
);
4471 umrp
= kmem_zalloc(sizeof (*umrp
), KM_SLEEP
);
4472 bcopy(&mip
->mi_resource_props
, umrp
, sizeof (*umrp
));
4473 resmask
= umrp
->mrp_mask
;
4474 mac_update_resources(mrp
, umrp
, B_FALSE
);
4475 newresmask
= umrp
->mrp_mask
;
4477 if (resmask
== 0 && newresmask
!= 0) {
4479 * Bandwidth, priority, cpu or pool link properties configured,
4480 * must disable fastpath.
4482 if ((err
= mac_fastpath_disable((mac_handle_t
)mip
)) != 0) {
4483 kmem_free(umrp
, sizeof (*umrp
));
4489 * Since bind_cpu may be modified by mac_client_set_resources()
4490 * we use a copy of bind_cpu and finally cache bind_cpu in mip.
4491 * This allows us to cache only user edits in mip.
4493 tmrp
= kmem_zalloc(sizeof (*tmrp
), KM_SLEEP
);
4494 bcopy(mrp
, tmrp
, sizeof (*tmrp
));
4495 mcip
= mac_primary_client_handle(mip
);
4496 if (mcip
!= NULL
&& (mcip
->mci_state_flags
& MCIS_IS_AGGR_PORT
) == 0) {
4497 err
= mac_client_set_resources((mac_client_handle_t
)mcip
, tmrp
);
4498 } else if ((mrp
->mrp_mask
& MRP_RX_RINGS
||
4499 mrp
->mrp_mask
& MRP_TX_RINGS
)) {
4500 mac_client_impl_t
*vmcip
;
4503 * If the primary is not up, we need to check if there
4504 * are any VLANs on this primary. If there are then
4505 * we need to set this property on the VLANs since
4506 * VLANs follow the primary they are based on. Just
4507 * look for the first VLAN and change its properties,
4508 * all the other VLANs should be in the same group.
4510 for (vmcip
= mip
->mi_clients_list
; vmcip
!= NULL
;
4511 vmcip
= vmcip
->mci_client_next
) {
4512 if ((vmcip
->mci_flent
->fe_type
& FLOW_PRIMARY_MAC
) &&
4513 mac_client_vid((mac_client_handle_t
)vmcip
) !=
4518 if (vmcip
!= NULL
) {
4519 mac_resource_props_t
*omrp
;
4520 mac_resource_props_t
*vmrp
;
4522 omrp
= kmem_zalloc(sizeof (*omrp
), KM_SLEEP
);
4523 bcopy(MCIP_RESOURCE_PROPS(vmcip
), omrp
, sizeof (*omrp
));
4525 * We dont' call mac_update_resources since we
4526 * want to take only the ring properties and
4527 * not all the properties that may have changed.
4529 vmrp
= MCIP_RESOURCE_PROPS(vmcip
);
4530 if (mrp
->mrp_mask
& MRP_RX_RINGS
) {
4531 if (mrp
->mrp_mask
& MRP_RINGS_RESET
) {
4532 vmrp
->mrp_mask
&= ~MRP_RX_RINGS
;
4533 if (vmrp
->mrp_mask
&
4534 MRP_RXRINGS_UNSPEC
) {
4536 ~MRP_RXRINGS_UNSPEC
;
4538 vmrp
->mrp_nrxrings
= 0;
4540 vmrp
->mrp_mask
|= MRP_RX_RINGS
;
4541 vmrp
->mrp_nrxrings
= mrp
->mrp_nrxrings
;
4544 if (mrp
->mrp_mask
& MRP_TX_RINGS
) {
4545 if (mrp
->mrp_mask
& MRP_RINGS_RESET
) {
4546 vmrp
->mrp_mask
&= ~MRP_TX_RINGS
;
4547 if (vmrp
->mrp_mask
&
4548 MRP_TXRINGS_UNSPEC
) {
4550 ~MRP_TXRINGS_UNSPEC
;
4552 vmrp
->mrp_ntxrings
= 0;
4554 vmrp
->mrp_mask
|= MRP_TX_RINGS
;
4555 vmrp
->mrp_ntxrings
= mrp
->mrp_ntxrings
;
4558 if (mrp
->mrp_mask
& MRP_RXRINGS_UNSPEC
)
4559 vmrp
->mrp_mask
|= MRP_RXRINGS_UNSPEC
;
4561 if (mrp
->mrp_mask
& MRP_TXRINGS_UNSPEC
)
4562 vmrp
->mrp_mask
|= MRP_TXRINGS_UNSPEC
;
4564 if ((err
= mac_client_set_rings_prop(vmcip
, mrp
,
4566 bcopy(omrp
, MCIP_RESOURCE_PROPS(vmcip
),
4569 mac_set_prim_vlan_rings(mip
, vmrp
);
4571 kmem_free(omrp
, sizeof (*omrp
));
4575 /* Only update the values if mac_client_set_resources succeeded */
4577 bcopy(umrp
, &mip
->mi_resource_props
, sizeof (*umrp
));
4579 * If bandwidth, priority or cpu link properties cleared,
4582 if (resmask
!= 0 && newresmask
== 0)
4583 mac_fastpath_enable((mac_handle_t
)mip
);
4584 } else if (resmask
== 0 && newresmask
!= 0) {
4585 mac_fastpath_enable((mac_handle_t
)mip
);
4587 kmem_free(tmrp
, sizeof (*tmrp
));
4588 kmem_free(umrp
, sizeof (*umrp
));
4593 mac_set_resources(mac_handle_t mh
, mac_resource_props_t
*mrp
)
4597 i_mac_perim_enter((mac_impl_t
*)mh
);
4598 err
= i_mac_set_resources(mh
, mrp
);
4599 i_mac_perim_exit((mac_impl_t
*)mh
);
4604 * Get the properties cached for the specified MAC instance.
4607 mac_get_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
);
4614 mac_client_get_resources((mac_client_handle_t
)mcip
, mrp
);
4617 bcopy(&mip
->mi_resource_props
, mrp
, sizeof (mac_resource_props_t
));
4621 * Get the effective properties from the primary client of the
4622 * specified MAC instance.
4625 mac_get_effective_resources(mac_handle_t mh
, mac_resource_props_t
*mrp
)
4627 mac_impl_t
*mip
= (mac_impl_t
*)mh
;
4628 mac_client_impl_t
*mcip
;
4630 mcip
= mac_primary_client_handle(mip
);
4632 mac_client_get_effective_resources((mac_client_handle_t
)mcip
,
4636 bzero(mrp
, sizeof (mac_resource_props_t
));
4640 mac_set_pvid(mac_handle_t mh
, uint16_t pvid
)
4642 mac_impl_t
*mip
= (mac_impl_t
*)mh
;
4643 mac_client_impl_t
*mcip
;
4644 mac_unicast_impl_t
*muip
;
4646 i_mac_perim_enter(mip
);
4648 for (mcip
= mip
->mi_clients_list
; mcip
!= NULL
;
4649 mcip
= mcip
->mci_client_next
) {
4650 for (muip
= mcip
->mci_unicast_list
; muip
!= NULL
;
4651 muip
= muip
->mui_next
) {
4652 if (muip
->mui_vid
== pvid
) {
4653 i_mac_perim_exit(mip
);
4659 mip
->mi_pvid
= pvid
;
4660 i_mac_perim_exit(mip
);
4665 mac_get_pvid(mac_handle_t mh
)
4667 mac_impl_t
*mip
= (mac_impl_t
*)mh
;
4669 return (mip
->mi_pvid
);
4673 mac_get_llimit(mac_handle_t mh
)
4675 mac_impl_t
*mip
= (mac_impl_t
*)mh
;
4677 return (mip
->mi_llimit
);
4681 mac_get_ldecay(mac_handle_t mh
)
4683 mac_impl_t
*mip
= (mac_impl_t
*)mh
;
4685 return (mip
->mi_ldecay
);
4689 * Rename a mac client, its flow, and the kstat.
4692 mac_rename_primary(mac_handle_t mh
, const char *new_name
)
4694 mac_impl_t
*mip
= (mac_impl_t
*)mh
;
4695 mac_client_impl_t
*cur_clnt
= NULL
;
4698 i_mac_perim_enter(mip
);
4701 * VNICs: we need to change the sys flow name and
4702 * the associated flow kstat.
4704 if (mip
->mi_state_flags
& MIS_IS_VNIC
) {
4705 mac_client_impl_t
*mcip
= mac_vnic_lower(mip
);
4706 ASSERT(new_name
!= NULL
);
4707 mac_rename_flow_names(mcip
, new_name
);
4708 mac_stat_rename(mcip
);
4712 * This mac may itself be an aggr link, or it may have some client
4713 * which is an aggr port. For both cases, we need to change the
4714 * aggr port's mac client name, its flow name and the associated flow
4717 if (mip
->mi_state_flags
& MIS_IS_AGGR
) {
4718 mac_capab_aggr_t aggr_cap
;
4719 mac_rename_fn_t rename_fn
;
4722 ASSERT(new_name
!= NULL
);
4723 ret
= i_mac_capab_get((mac_handle_t
)mip
, MAC_CAPAB_AGGR
,
4724 (void *)(&aggr_cap
));
4725 ASSERT(ret
== B_TRUE
);
4726 rename_fn
= aggr_cap
.mca_rename_fn
;
4727 rename_fn(new_name
, mip
->mi_driver
);
4729 * The aggr's client name and kstat flow name will be
4730 * updated below, i.e. via mac_rename_flow_names.
4734 for (cur_clnt
= mip
->mi_clients_list
; cur_clnt
!= NULL
;
4735 cur_clnt
= cur_clnt
->mci_client_next
) {
4736 if (cur_clnt
->mci_state_flags
& MCIS_IS_AGGR_PORT
) {
4737 if (new_name
!= NULL
) {
4738 char *str_st
= cur_clnt
->mci_name
;
4739 char *str_del
= strchr(str_st
, '-');
4741 ASSERT(str_del
!= NULL
);
4742 bzero(str_del
+ 1, MAXNAMELEN
-
4743 (str_del
- str_st
+ 1));
4744 bcopy(new_name
, str_del
+ 1,
4747 fep
= cur_clnt
->mci_flent
;
4748 mac_rename_flow(fep
, cur_clnt
->mci_name
);
4750 } else if (new_name
!= NULL
&&
4751 cur_clnt
->mci_state_flags
& MCIS_USE_DATALINK_NAME
) {
4752 mac_rename_flow_names(cur_clnt
, new_name
);
4757 /* Recreate kstats associated with aggr pseudo rings */
4758 if (mip
->mi_state_flags
& MIS_IS_AGGR
)
4759 mac_pseudo_ring_stat_rename(mip
);
4762 i_mac_perim_exit(mip
);
4767 * Rename the MAC client's flow names
4770 mac_rename_flow_names(mac_client_impl_t
*mcip
, const char *new_name
)
4772 flow_entry_t
*flent
;
4774 char flowname
[MAXFLOWNAMELEN
];
4775 mac_impl_t
*mip
= mcip
->mci_mip
;
4777 ASSERT(MAC_PERIM_HELD((mac_handle_t
)mip
));
4780 * Use mi_rw_lock to ensure that threads not in the mac perimeter
4781 * see a self-consistent value for mci_name
4783 rw_enter(&mip
->mi_rw_lock
, RW_WRITER
);
4784 (void) strlcpy(mcip
->mci_name
, new_name
, sizeof (mcip
->mci_name
));
4785 rw_exit(&mip
->mi_rw_lock
);
4787 mac_rename_flow(mcip
->mci_flent
, new_name
);
4789 if (mcip
->mci_nflents
== 1)
4793 * We have to rename all the others too, no stats to destroy for
4796 for (flent
= mcip
->mci_flent_list
; flent
!= NULL
;
4797 flent
= flent
->fe_client_next
) {
4798 if (flent
!= mcip
->mci_flent
) {
4799 vid
= i_mac_flow_vid(flent
);
4800 (void) sprintf(flowname
, "%s%u", new_name
, vid
);
4801 mac_flow_set_name(flent
, flowname
);
4808 * Add a flow to the MAC client's flow list - i.e list of MAC/VID tuples
4809 * defined for the specified MAC client.
4812 mac_client_add_to_flow_list(mac_client_impl_t
*mcip
, flow_entry_t
*flent
)
4814 ASSERT(MAC_PERIM_HELD((mac_handle_t
)mcip
->mci_mip
));
4816 * The promisc Rx data path walks the mci_flent_list. Protect by
4819 rw_enter(&mcip
->mci_rw_lock
, RW_WRITER
);
4821 mcip
->mci_vidcache
= MCIP_VIDCACHE_INVALID
;
4823 /* Add it to the head */
4824 flent
->fe_client_next
= mcip
->mci_flent_list
;
4825 mcip
->mci_flent_list
= flent
;
4826 mcip
->mci_nflents
++;
4829 * Keep track of the number of non-zero VIDs addresses per MAC
4830 * client to avoid figuring it out in the data-path.
4832 if (i_mac_flow_vid(flent
) != VLAN_ID_NONE
)
4835 rw_exit(&mcip
->mci_rw_lock
);
4839 * Remove a flow entry from the MAC client's list.
4842 mac_client_remove_flow_from_list(mac_client_impl_t
*mcip
, flow_entry_t
*flent
)
4844 flow_entry_t
*fe
= mcip
->mci_flent_list
;
4845 flow_entry_t
*prev_fe
= NULL
;
4847 ASSERT(MAC_PERIM_HELD((mac_handle_t
)mcip
->mci_mip
));
4849 * The promisc Rx data path walks the mci_flent_list. Protect by
4852 rw_enter(&mcip
->mci_rw_lock
, RW_WRITER
);
4853 mcip
->mci_vidcache
= MCIP_VIDCACHE_INVALID
;
4855 while ((fe
!= NULL
) && (fe
!= flent
)) {
4857 fe
= fe
->fe_client_next
;
4861 if (prev_fe
== NULL
) {
4862 /* Deleting the first node */
4863 mcip
->mci_flent_list
= fe
->fe_client_next
;
4865 prev_fe
->fe_client_next
= fe
->fe_client_next
;
4867 mcip
->mci_nflents
--;
4869 if (i_mac_flow_vid(flent
) != VLAN_ID_NONE
)
4872 rw_exit(&mcip
->mci_rw_lock
);
4876 * Check if the given VID belongs to this MAC client.
4879 mac_client_check_flow_vid(mac_client_impl_t
*mcip
, uint16_t vid
)
4881 flow_entry_t
*flent
;
4883 uint32_t cache
= mcip
->mci_vidcache
;
4886 * In hopes of not having to touch the mci_rw_lock, check to see if
4887 * this vid matches our cached result.
4889 if (MCIP_VIDCACHE_ISVALID(cache
) && MCIP_VIDCACHE_VID(cache
) == vid
)
4890 return (MCIP_VIDCACHE_BOOL(cache
) ? B_TRUE
: B_FALSE
);
4892 /* The mci_flent_list is protected by mci_rw_lock */
4893 rw_enter(&mcip
->mci_rw_lock
, RW_WRITER
);
4894 for (flent
= mcip
->mci_flent_list
; flent
!= NULL
;
4895 flent
= flent
->fe_client_next
) {
4896 mci_vid
= i_mac_flow_vid(flent
);
4897 if (vid
== mci_vid
) {
4898 mcip
->mci_vidcache
= MCIP_VIDCACHE_CACHE(vid
, B_TRUE
);
4899 rw_exit(&mcip
->mci_rw_lock
);
4904 mcip
->mci_vidcache
= MCIP_VIDCACHE_CACHE(vid
, B_FALSE
);
4905 rw_exit(&mcip
->mci_rw_lock
);
4910 * Get the flow entry for the specified <MAC addr, VID> tuple.
4912 static flow_entry_t
*
4913 mac_client_get_flow(mac_client_impl_t
*mcip
, mac_unicast_impl_t
*muip
)
4915 mac_address_t
*map
= mcip
->mci_unicast
;
4916 flow_entry_t
*flent
;
4918 flow_desc_t flow_desc
;
4920 ASSERT(MAC_PERIM_HELD((mac_handle_t
)mcip
->mci_mip
));
4922 mac_flow_get_desc(mcip
->mci_flent
, &flow_desc
);
4923 if (bcmp(flow_desc
.fd_dst_mac
, map
->ma_addr
, map
->ma_len
) != 0)
4926 for (flent
= mcip
->mci_flent_list
; flent
!= NULL
;
4927 flent
= flent
->fe_client_next
) {
4928 vid
= i_mac_flow_vid(flent
);
4929 if (vid
== muip
->mui_vid
) {
4938 * Since mci_flent has the SRSs, when we want to remove it, we replace
4939 * the flow_desc_t in mci_flent with that of an existing flent and then
4940 * remove that flent instead of mci_flent.
4942 static flow_entry_t
*
4943 mac_client_swap_mciflent(mac_client_impl_t
*mcip
)
4945 flow_entry_t
*flent
= mcip
->mci_flent
;
4946 flow_tab_t
*ft
= flent
->fe_flow_tab
;
4947 flow_entry_t
*flent1
;
4948 flow_desc_t fl_desc
;
4949 char fl_name
[MAXFLOWNAMELEN
];
4952 ASSERT(MAC_PERIM_HELD((mac_handle_t
)mcip
->mci_mip
));
4953 ASSERT(mcip
->mci_nflents
> 1);
4955 /* get the next flent following the primary flent */
4956 flent1
= mcip
->mci_flent_list
->fe_client_next
;
4957 ASSERT(flent1
!= NULL
&& flent1
->fe_flow_tab
== ft
);
4960 * Remove the flent from the flow table before updating the
4961 * flow descriptor as the hash depends on the flow descriptor.
4962 * This also helps incoming packet classification avoid having
4963 * to grab fe_lock. Access to fe_flow_desc of a flent not in the
4964 * flow table is done under the fe_lock so that log or stat functions
4965 * see a self-consistent fe_flow_desc. The name and desc are specific
4966 * to a flow, the rest are shared by all the clients, including
4967 * resource control etc.
4969 mac_flow_remove(ft
, flent
, B_TRUE
);
4970 mac_flow_remove(ft
, flent1
, B_TRUE
);
4972 bcopy(&flent
->fe_flow_desc
, &fl_desc
, sizeof (flow_desc_t
));
4973 bcopy(flent
->fe_flow_name
, fl_name
, MAXFLOWNAMELEN
);
4975 /* update the primary flow entry */
4976 mutex_enter(&flent
->fe_lock
);
4977 bcopy(&flent1
->fe_flow_desc
, &flent
->fe_flow_desc
,
4978 sizeof (flow_desc_t
));
4979 bcopy(&flent1
->fe_flow_name
, &flent
->fe_flow_name
, MAXFLOWNAMELEN
);
4980 mutex_exit(&flent
->fe_lock
);
4982 /* update the flow entry that is to be freed */
4983 mutex_enter(&flent1
->fe_lock
);
4984 bcopy(&fl_desc
, &flent1
->fe_flow_desc
, sizeof (flow_desc_t
));
4985 bcopy(fl_name
, &flent1
->fe_flow_name
, MAXFLOWNAMELEN
);
4986 mutex_exit(&flent1
->fe_lock
);
4988 /* now reinsert the flow entries in the table */
4989 err
= mac_flow_add(ft
, flent
);
4992 err
= mac_flow_add(ft
, flent1
);
4999 * Return whether there is only one flow entry associated with this
5003 mac_client_single_rcvr(mac_client_impl_t
*mcip
)
5005 return (mcip
->mci_nflents
== 1);
5009 mac_validate_props(mac_impl_t
*mip
, mac_resource_props_t
*mrp
)
5012 uint32_t rings_needed
;
5013 uint32_t rings_avail
;
5014 mac_group_type_t gtype
;
5015 mac_resource_props_t
*mip_mrp
;
5020 if (mrp
->mrp_mask
& MRP_PRIORITY
) {
5021 mac_priority_level_t pri
= mrp
->mrp_priority
;
5023 if (pri
< MPL_LOW
|| pri
> MPL_RESET
)
5027 if (mrp
->mrp_mask
& MRP_MAXBW
) {
5028 uint64_t maxbw
= mrp
->mrp_maxbw
;
5030 if (maxbw
< MRP_MAXBW_MINVAL
&& maxbw
!= 0)
5033 if (mrp
->mrp_mask
& MRP_CPUS
) {
5035 mac_cpu_mode_t fanout
;
5037 if (mrp
->mrp_ncpus
> ncpus
)
5040 for (i
= 0; i
< mrp
->mrp_ncpus
; i
++) {
5041 for (j
= 0; j
< mrp
->mrp_ncpus
; j
++) {
5043 mrp
->mrp_cpu
[i
] == mrp
->mrp_cpu
[j
]) {
5049 for (i
= 0; i
< mrp
->mrp_ncpus
; i
++) {
5053 mutex_enter(&cpu_lock
);
5054 cp
= cpu_get(mrp
->mrp_cpu
[i
]);
5056 rv
= cpu_is_online(cp
);
5059 mutex_exit(&cpu_lock
);
5064 fanout
= mrp
->mrp_fanout_mode
;
5065 if (fanout
< 0 || fanout
> MCM_CPUS
)
5069 if (mrp
->mrp_mask
& MRP_PROTECT
) {
5070 int err
= mac_protect_validate(mrp
);
5075 if (!(mrp
->mrp_mask
& MRP_RX_RINGS
) &&
5076 !(mrp
->mrp_mask
& MRP_TX_RINGS
)) {
5081 * mip will be null when we come from mac_flow_create or
5082 * mac_link_flow_modify. In the latter case it is a user flow,
5083 * for which we don't support rings. In the former we would
5084 * have validated the props beforehand (i_mac_unicast_add ->
5085 * mac_client_set_resources -> validate for the primary and
5086 * vnic_dev_create -> mac_client_set_resources -> validate for
5093 * We don't support setting rings property for a VNIC that is using a
5094 * primary address (VLAN)
5096 if ((mip
->mi_state_flags
& MIS_IS_VNIC
) &&
5097 mac_is_vnic_primary((mac_handle_t
)mip
)) {
5101 mip_mrp
= &mip
->mi_resource_props
;
5103 * The rings property should be validated against the NICs
5106 if (mip
->mi_state_flags
& MIS_IS_VNIC
)
5107 mip
= (mac_impl_t
*)mac_get_lower_mac_handle((mac_handle_t
)mip
);
5109 reset
= mrp
->mrp_mask
& MRP_RINGS_RESET
;
5111 * If groups are not supported, return error.
5113 if (((mrp
->mrp_mask
& MRP_RX_RINGS
) && mip
->mi_rx_groups
== NULL
) ||
5114 ((mrp
->mrp_mask
& MRP_TX_RINGS
) && mip
->mi_tx_groups
== NULL
)) {
5118 * If we are just resetting, there is no validation needed.
5123 if (mrp
->mrp_mask
& MRP_RX_RINGS
) {
5124 rings_needed
= mrp
->mrp_nrxrings
;
5126 * We just want to check if the number of additional
5127 * rings requested is available.
5129 if (mip_mrp
->mrp_mask
& MRP_RX_RINGS
) {
5130 if (mrp
->mrp_nrxrings
> mip_mrp
->mrp_nrxrings
)
5131 /* Just check for the additional rings */
5132 rings_needed
-= mip_mrp
->mrp_nrxrings
;
5134 /* We are not asking for additional rings */
5137 rings_avail
= mip
->mi_rxrings_avail
;
5138 gtype
= mip
->mi_rx_group_type
;
5140 rings_needed
= mrp
->mrp_ntxrings
;
5141 /* Similarly for the TX rings */
5142 if (mip_mrp
->mrp_mask
& MRP_TX_RINGS
) {
5143 if (mrp
->mrp_ntxrings
> mip_mrp
->mrp_ntxrings
)
5144 /* Just check for the additional rings */
5145 rings_needed
-= mip_mrp
->mrp_ntxrings
;
5147 /* We are not asking for additional rings */
5150 rings_avail
= mip
->mi_txrings_avail
;
5151 gtype
= mip
->mi_tx_group_type
;
5154 /* Error if the group is dynamic .. */
5155 if (gtype
== MAC_GROUP_TYPE_DYNAMIC
) {
5157 * .. and rings specified are more than available.
5159 if (rings_needed
> rings_avail
)
5163 * OR group is static and we have specified some rings.
5165 if (rings_needed
> 0)
5172 * Send a MAC_NOTE_LINK notification to all the MAC clients whenever the
5173 * underlying physical link is down. This is to allow MAC clients to
5174 * communicate with other clients.
5177 mac_virtual_link_update(mac_impl_t
*mip
)
5179 if (mip
->mi_linkstate
!= LINK_STATE_UP
)
5180 i_mac_notify(mip
, MAC_NOTE_LINK
);
5184 * For clients that have a pass-thru MAC, e.g. VNIC, we set the VNIC's
5185 * mac handle in the client.
5188 mac_set_upper_mac(mac_client_handle_t mch
, mac_handle_t mh
,
5189 mac_resource_props_t
*mrp
)
5191 mac_client_impl_t
*mcip
= (mac_client_impl_t
*)mch
;
5192 mac_impl_t
*mip
= (mac_impl_t
*)mh
;
5194 mcip
->mci_upper_mip
= mip
;
5195 /* If there are any properties, copy it over too */
5197 bcopy(mrp
, &mip
->mi_resource_props
,
5198 sizeof (mac_resource_props_t
));
5203 * Mark the mac as being used exclusively by the single mac client that is
5204 * doing some control operation on this mac. No further opens of this mac
5205 * will be allowed until this client calls mac_unmark_exclusive. The mac
5206 * client calling this function must already be in the mac perimeter
5209 mac_mark_exclusive(mac_handle_t mh
)
5211 mac_impl_t
*mip
= (mac_impl_t
*)mh
;
5213 ASSERT(MAC_PERIM_HELD(mh
));
5215 * Look up its entry in the global hash table.
5217 rw_enter(&i_mac_impl_lock
, RW_WRITER
);
5218 if (mip
->mi_state_flags
& MIS_DISABLED
) {
5219 rw_exit(&i_mac_impl_lock
);
5224 * A reference to mac is held even if the link is not plumbed.
5225 * In i_dls_link_create() we open the MAC interface and hold the
5226 * reference. There is an additional reference for the mac_open
5227 * done in acquiring the mac perimeter
5229 if (mip
->mi_ref
!= 2) {
5230 rw_exit(&i_mac_impl_lock
);
5234 ASSERT(!(mip
->mi_state_flags
& MIS_EXCLUSIVE_HELD
));
5235 mip
->mi_state_flags
|= MIS_EXCLUSIVE_HELD
;
5236 rw_exit(&i_mac_impl_lock
);
5241 mac_unmark_exclusive(mac_handle_t mh
)
5243 mac_impl_t
*mip
= (mac_impl_t
*)mh
;
5245 ASSERT(MAC_PERIM_HELD(mh
));
5247 rw_enter(&i_mac_impl_lock
, RW_WRITER
);
5248 /* 1 for the creation and another for the perimeter */
5249 ASSERT(mip
->mi_ref
== 2 && (mip
->mi_state_flags
& MIS_EXCLUSIVE_HELD
));
5250 mip
->mi_state_flags
&= ~MIS_EXCLUSIVE_HELD
;
5251 rw_exit(&i_mac_impl_lock
);
5255 * Set the MTU for the specified MAC.
5258 mac_set_mtu(mac_handle_t mh
, uint_t new_mtu
, uint_t
*old_mtu_arg
)
5260 mac_impl_t
*mip
= (mac_impl_t
*)mh
;
5264 i_mac_perim_enter(mip
);
5266 if (!(mip
->mi_callbacks
->mc_callbacks
& (MC_SETPROP
|MC_GETPROP
))) {
5271 old_mtu
= mip
->mi_sdu_max
;
5273 if (new_mtu
== 0 || new_mtu
< mip
->mi_sdu_min
) {
5278 rw_enter(&mip
->mi_rw_lock
, RW_READER
);
5279 if (mip
->mi_mtrp
!= NULL
&& new_mtu
< mip
->mi_mtrp
->mtr_mtu
) {
5281 rw_exit(&mip
->mi_rw_lock
);
5284 rw_exit(&mip
->mi_rw_lock
);
5286 if (old_mtu
!= new_mtu
) {
5287 rv
= mip
->mi_callbacks
->mc_setprop(mip
->mi_driver
,
5288 "mtu", MAC_PROP_MTU
, sizeof (uint_t
), &new_mtu
);
5291 rv
= mac_maxsdu_update(mh
, new_mtu
);
5296 i_mac_perim_exit(mip
);
5298 if (rv
== 0 && old_mtu_arg
!= NULL
)
5299 *old_mtu_arg
= old_mtu
;
5304 * Return the RX h/w information for the group indexed by grp_num.
5307 mac_get_hwrxgrp_info(mac_handle_t mh
, int grp_index
, uint_t
*grp_num
,
5308 uint_t
*n_rings
, uint_t
*rings
, uint_t
*type
, uint_t
*n_clnts
,
5311 mac_impl_t
*mip
= (mac_impl_t
*)mh
;
5312 mac_grp_client_t
*mcip
;
5313 uint_t i
= 0, index
= 0;
5316 /* Revisit when we implement fully dynamic group allocation */
5317 ASSERT(grp_index
>= 0 && grp_index
< mip
->mi_rx_group_count
);
5319 rw_enter(&mip
->mi_rw_lock
, RW_READER
);
5320 *grp_num
= mip
->mi_rx_groups
[grp_index
].mrg_index
;
5321 *type
= mip
->mi_rx_groups
[grp_index
].mrg_type
;
5322 *n_rings
= mip
->mi_rx_groups
[grp_index
].mrg_cur_count
;
5323 ring
= mip
->mi_rx_groups
[grp_index
].mrg_rings
;
5324 for (index
= 0; index
< mip
->mi_rx_groups
[grp_index
].mrg_cur_count
;
5326 rings
[index
] = ring
->mr_index
;
5327 ring
= ring
->mr_next
;
5329 /* Assuming the 1st is the default group */
5331 if (grp_index
== 0) {
5332 (void) strlcpy(clnts_name
, "<default,mcast>,",
5334 index
+= strlen("<default,mcast>,");
5336 for (mcip
= mip
->mi_rx_groups
[grp_index
].mrg_clients
; mcip
!= NULL
;
5337 mcip
= mcip
->mgc_next
) {
5338 int name_len
= strlen(mcip
->mgc_client
->mci_name
);
5341 * MAXCLIENTNAMELEN is the buffer size reserved for client
5343 * XXXX Formating the client name string needs to be moved
5344 * to user land when fixing the size of dhi_clnts in
5345 * dld_hwgrpinfo_t. We should use n_clients * client_name for
5346 * dhi_clntsin instead of MAXCLIENTNAMELEN
5348 if (index
+ name_len
>= MAXCLIENTNAMELEN
) {
5349 index
= MAXCLIENTNAMELEN
;
5352 bcopy(mcip
->mgc_client
->mci_name
, &(clnts_name
[index
]),
5355 clnts_name
[index
++] = ',';
5359 /* Get rid of the last , */
5361 clnts_name
[index
- 1] = '\0';
5363 rw_exit(&mip
->mi_rw_lock
);
5367 * Return the TX h/w information for the group indexed by grp_num.
5370 mac_get_hwtxgrp_info(mac_handle_t mh
, int grp_index
, uint_t
*grp_num
,
5371 uint_t
*n_rings
, uint_t
*rings
, uint_t
*type
, uint_t
*n_clnts
,
5374 mac_impl_t
*mip
= (mac_impl_t
*)mh
;
5375 mac_grp_client_t
*mcip
;
5376 uint_t i
= 0, index
= 0;
5379 /* Revisit when we implement fully dynamic group allocation */
5380 ASSERT(grp_index
>= 0 && grp_index
<= mip
->mi_tx_group_count
);
5382 rw_enter(&mip
->mi_rw_lock
, RW_READER
);
5383 *grp_num
= mip
->mi_tx_groups
[grp_index
].mrg_index
> 0 ?
5384 mip
->mi_tx_groups
[grp_index
].mrg_index
: grp_index
;
5385 *type
= mip
->mi_tx_groups
[grp_index
].mrg_type
;
5386 *n_rings
= mip
->mi_tx_groups
[grp_index
].mrg_cur_count
;
5387 ring
= mip
->mi_tx_groups
[grp_index
].mrg_rings
;
5388 for (index
= 0; index
< mip
->mi_tx_groups
[grp_index
].mrg_cur_count
;
5390 rings
[index
] = ring
->mr_index
;
5391 ring
= ring
->mr_next
;
5394 /* Default group has an index of -1 */
5395 if (mip
->mi_tx_groups
[grp_index
].mrg_index
< 0) {
5396 (void) strlcpy(clnts_name
, "<default>,",
5398 index
+= strlen("<default>,");
5400 for (mcip
= mip
->mi_tx_groups
[grp_index
].mrg_clients
; mcip
!= NULL
;
5401 mcip
= mcip
->mgc_next
) {
5402 int name_len
= strlen(mcip
->mgc_client
->mci_name
);
5405 * MAXCLIENTNAMELEN is the buffer size reserved for client
5407 * XXXX Formating the client name string needs to be moved
5408 * to user land when fixing the size of dhi_clnts in
5409 * dld_hwgrpinfo_t. We should use n_clients * client_name for
5410 * dhi_clntsin instead of MAXCLIENTNAMELEN
5412 if (index
+ name_len
>= MAXCLIENTNAMELEN
) {
5413 index
= MAXCLIENTNAMELEN
;
5416 bcopy(mcip
->mgc_client
->mci_name
, &(clnts_name
[index
]),
5419 clnts_name
[index
++] = ',';
5423 /* Get rid of the last , */
5425 clnts_name
[index
- 1] = '\0';
5427 rw_exit(&mip
->mi_rw_lock
);
5431 * Return the group count for RX or TX.
5434 mac_hwgrp_num(mac_handle_t mh
, int type
)
5436 mac_impl_t
*mip
= (mac_impl_t
*)mh
;
5439 * Return the Rx and Tx group count; for the Tx we need to
5440 * include the default too.
5442 return (type
== MAC_RING_TYPE_RX
? mip
->mi_rx_group_count
:
5443 mip
->mi_tx_groups
!= NULL
? mip
->mi_tx_group_count
+ 1 : 0);
5447 * The total number of free TX rings for this MAC.
5450 mac_txavail_get(mac_handle_t mh
)
5452 mac_impl_t
*mip
= (mac_impl_t
*)mh
;
5454 return (mip
->mi_txrings_avail
);
5458 * The total number of free RX rings for this MAC.
5461 mac_rxavail_get(mac_handle_t mh
)
5463 mac_impl_t
*mip
= (mac_impl_t
*)mh
;
5465 return (mip
->mi_rxrings_avail
);
5469 * The total number of reserved RX rings on this MAC.
5472 mac_rxrsvd_get(mac_handle_t mh
)
5474 mac_impl_t
*mip
= (mac_impl_t
*)mh
;
5476 return (mip
->mi_rxrings_rsvd
);
5480 * The total number of reserved TX rings on this MAC.
5483 mac_txrsvd_get(mac_handle_t mh
)
5485 mac_impl_t
*mip
= (mac_impl_t
*)mh
;
5487 return (mip
->mi_txrings_rsvd
);
5491 * Total number of free RX groups on this MAC.
5494 mac_rxhwlnksavail_get(mac_handle_t mh
)
5496 mac_impl_t
*mip
= (mac_impl_t
*)mh
;
5498 return (mip
->mi_rxhwclnt_avail
);
5502 * Total number of RX groups reserved on this MAC.
5505 mac_rxhwlnksrsvd_get(mac_handle_t mh
)
5507 mac_impl_t
*mip
= (mac_impl_t
*)mh
;
5509 return (mip
->mi_rxhwclnt_used
);
5513 * Total number of free TX groups on this MAC.
5516 mac_txhwlnksavail_get(mac_handle_t mh
)
5518 mac_impl_t
*mip
= (mac_impl_t
*)mh
;
5520 return (mip
->mi_txhwclnt_avail
);
5524 * Total number of TX groups reserved on this MAC.
5527 mac_txhwlnksrsvd_get(mac_handle_t mh
)
5529 mac_impl_t
*mip
= (mac_impl_t
*)mh
;
5531 return (mip
->mi_txhwclnt_used
);
5535 * Initialize the rings property for a mac client. A non-0 value for
5536 * rxring or txring specifies the number of rings required, a value
5537 * of MAC_RXRINGS_NONE/MAC_TXRINGS_NONE specifies that it doesn't need
5538 * any RX/TX rings and a value of MAC_RXRINGS_DONTCARE/MAC_TXRINGS_DONTCARE
5539 * means the system can decide whether it can give any rings or not.
5542 mac_client_set_rings(mac_client_handle_t mch
, int rxrings
, int txrings
)
5544 mac_client_impl_t
*mcip
= (mac_client_impl_t
*)mch
;
5545 mac_resource_props_t
*mrp
= MCIP_RESOURCE_PROPS(mcip
);
5547 if (rxrings
!= MAC_RXRINGS_DONTCARE
) {
5548 mrp
->mrp_mask
|= MRP_RX_RINGS
;
5549 mrp
->mrp_nrxrings
= rxrings
;
5552 if (txrings
!= MAC_TXRINGS_DONTCARE
) {
5553 mrp
->mrp_mask
|= MRP_TX_RINGS
;
5554 mrp
->mrp_ntxrings
= txrings
;
5559 mac_get_promisc_filtered(mac_client_handle_t mch
)
5561 mac_client_impl_t
*mcip
= (mac_client_impl_t
*)mch
;
5563 return (mcip
->mci_protect_flags
& MPT_FLAG_PROMISC_FILTERED
);
5567 mac_set_promisc_filtered(mac_client_handle_t mch
, boolean_t enable
)
5569 mac_client_impl_t
*mcip
= (mac_client_impl_t
*)mch
;
5571 ASSERT(MAC_PERIM_HELD((mac_handle_t
)mcip
->mci_mip
));
5573 mcip
->mci_protect_flags
|= MPT_FLAG_PROMISC_FILTERED
;
5575 mcip
->mci_protect_flags
&= ~MPT_FLAG_PROMISC_FILTERED
;