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