Print this page
11493 aggr needs support for multiple pseudo rx groups
Portions contributed by: Dan McDonald <danmcd@joyent.com>
Reviewed by: Patrick Mooney <patrick.mooney@joyent.com>
Reviewed by: Jerry Jelinek <jerry.jelinek@joyent.com>
Reviewed by: Robert Mustacchi <rm@joyent.com>
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/common/sys/mac_impl.h
+++ new/usr/src/uts/common/sys/mac_impl.h
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21 /*
22 22 * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
23 23 * Copyright (c) 2018, Joyent, Inc.
24 24 */
25 25
26 26 #ifndef _SYS_MAC_IMPL_H
27 27 #define _SYS_MAC_IMPL_H
28 28
29 29 #include <sys/cpupart.h>
30 30 #include <sys/modhash.h>
31 31 #include <sys/mac_client.h>
32 32 #include <sys/mac_provider.h>
33 33 #include <sys/note.h>
34 34 #include <sys/avl.h>
35 35 #include <net/if.h>
36 36 #include <sys/mac_flow_impl.h>
37 37 #include <netinet/ip6.h>
38 38
39 39 #ifdef __cplusplus
40 40 extern "C" {
41 41 #endif
42 42
43 43 /*
44 44 * This is the first minor number available for MAC provider private
45 45 * use. This makes it possible to deliver a driver that is both a MAC
46 46 * provider and a regular character/block device. See PSARC 2009/380
47 47 * for more detail about the construction of such devices. The value
48 48 * chosen leaves half of the 32-bit minor numbers (which are really
49 49 * only 18 bits wide) available for driver private use. Drivers can
50 50 * easily identify their private number by the presence of this value
51 51 * in the bits that make up the minor number, since its just the
52 52 * highest bit available for such minor numbers.
53 53 */
54 54 #define MAC_PRIVATE_MINOR ((MAXMIN32 + 1) / 2)
55 55
56 56 /*
57 57 * The maximum minor number that corresponds to a real instance. This
58 58 * limits the number of physical ports that a mac provider can offer.
59 59 * Note that this macro must be synchronized with DLS_MAX_MINOR in
60 60 * <sys/dls.h>
61 61 */
62 62 #define MAC_MAX_MINOR 1000
63 63
64 64 typedef struct mac_margin_req_s mac_margin_req_t;
65 65
66 66 struct mac_margin_req_s {
67 67 mac_margin_req_t *mmr_nextp;
68 68 uint_t mmr_ref;
69 69 uint32_t mmr_margin;
70 70 };
71 71
72 72 typedef struct mac_mtu_req_s mac_mtu_req_t;
73 73 struct mac_mtu_req_s {
74 74 mac_mtu_req_t *mtr_nextp;
75 75 uint_t mtr_ref;
76 76 uint32_t mtr_mtu;
77 77 };
78 78
79 79 /* Generic linked chain type */
80 80 typedef struct mac_chain_s {
81 81 struct mac_chain_s *next;
82 82 void *item;
83 83 } mac_chain_t;
84 84
85 85 /*
86 86 * Generic mac callback list manipulation structures and macros. The mac_cb_t
87 87 * represents a general callback list element embedded in a particular
88 88 * data structure such as a mac_notify_cb_t or a mac_promisc_impl_t.
89 89 * The mac_cb_info_t represents general information about list walkers.
90 90 * Please see the comments above mac_callback_add for more information.
91 91 */
92 92 /* mcb_flags */
93 93 #define MCB_CONDEMNED 0x1 /* Logically deleted */
94 94 #define MCB_NOTIFY_CB_T 0x2
95 95 #define MCB_TX_NOTIFY_CB_T 0x4
96 96
97 97 extern boolean_t mac_tx_serialize;
98 98
99 99 typedef struct mac_cb_s {
100 100 struct mac_cb_s *mcb_nextp; /* Linked list of callbacks */
101 101 void *mcb_objp; /* Ptr to enclosing object */
102 102 size_t mcb_objsize; /* Sizeof the enclosing obj */
103 103 uint_t mcb_flags;
104 104 } mac_cb_t;
105 105
106 106 typedef struct mac_cb_info_s {
107 107 kmutex_t *mcbi_lockp;
108 108 kcondvar_t mcbi_cv;
109 109 uint_t mcbi_del_cnt; /* Deleted callback cnt */
110 110 uint_t mcbi_walker_cnt; /* List walker count */
111 111 } mac_cb_info_t;
112 112
113 113 typedef struct mac_notify_cb_s {
114 114 mac_cb_t mncb_link; /* Linked list of callbacks */
115 115 mac_notify_t mncb_fn; /* callback function */
116 116 void *mncb_arg; /* callback argument */
117 117 struct mac_impl_s *mncb_mip;
118 118 } mac_notify_cb_t;
119 119
120 120 /*
121 121 * mac_callback_add(listinfo, listhead, listelement)
122 122 * mac_callback_remove(listinfo, listhead, listelement)
123 123 */
124 124 typedef boolean_t (*mcb_func_t)(mac_cb_info_t *, mac_cb_t **, mac_cb_t *);
125 125
126 126 #define MAC_CALLBACK_WALKER_INC(mcbi) { \
127 127 mutex_enter((mcbi)->mcbi_lockp); \
128 128 (mcbi)->mcbi_walker_cnt++; \
129 129 mutex_exit((mcbi)->mcbi_lockp); \
130 130 }
131 131
132 132 #define MAC_CALLBACK_WALKER_INC_HELD(mcbi) (mcbi)->mcbi_walker_cnt++;
133 133
134 134 #define MAC_CALLBACK_WALKER_DCR(mcbi, headp) { \
135 135 mac_cb_t *rmlist; \
136 136 \
137 137 mutex_enter((mcbi)->mcbi_lockp); \
138 138 if (--(mcbi)->mcbi_walker_cnt == 0 && (mcbi)->mcbi_del_cnt != 0) { \
139 139 rmlist = mac_callback_walker_cleanup((mcbi), headp); \
140 140 mac_callback_free(rmlist); \
141 141 cv_broadcast(&(mcbi)->mcbi_cv); \
142 142 } \
143 143 mutex_exit((mcbi)->mcbi_lockp); \
144 144 }
145 145
146 146 #define MAC_PROMISC_WALKER_INC(mip) \
147 147 MAC_CALLBACK_WALKER_INC(&(mip)->mi_promisc_cb_info)
148 148
149 149 #define MAC_PROMISC_WALKER_DCR(mip) { \
150 150 mac_cb_info_t *mcbi; \
151 151 \
152 152 mcbi = &(mip)->mi_promisc_cb_info; \
153 153 mutex_enter(mcbi->mcbi_lockp); \
154 154 if (--mcbi->mcbi_walker_cnt == 0 && mcbi->mcbi_del_cnt != 0) { \
155 155 i_mac_promisc_walker_cleanup(mip); \
156 156 cv_broadcast(&mcbi->mcbi_cv); \
157 157 } \
158 158 mutex_exit(mcbi->mcbi_lockp); \
159 159 }
160 160
161 161 typedef struct mactype_s {
162 162 const char *mt_ident;
163 163 uint32_t mt_ref;
164 164 uint_t mt_type;
165 165 uint_t mt_nativetype;
166 166 size_t mt_addr_length;
167 167 uint8_t *mt_brdcst_addr;
168 168 mactype_ops_t mt_ops;
169 169 mac_stat_info_t *mt_stats; /* array of mac_stat_info_t elements */
170 170 size_t mt_statcount; /* number of elements in mt_stats */
171 171 mac_ndd_mapping_t *mt_mapping;
172 172 size_t mt_mappingcount;
173 173 } mactype_t;
174 174
175 175 /*
176 176 * Multiple rings implementation.
177 177 */
178 178 typedef enum {
179 179 MAC_GROUP_STATE_UNINIT = 0, /* initial state of data structure */
180 180 MAC_GROUP_STATE_REGISTERED, /* hooked with h/w group */
181 181 MAC_GROUP_STATE_RESERVED, /* group is reserved and opened */
182 182 MAC_GROUP_STATE_SHARED /* default group shared among */
183 183 /* multiple mac clients */
184 184 } mac_group_state_t;
185 185
186 186 typedef struct mac_ring_s mac_ring_t;
187 187 typedef struct mac_group_s mac_group_t;
188 188
189 189 /*
190 190 * Ring data structure for ring control and management.
191 191 */
192 192 typedef enum {
193 193 MR_FREE, /* Available for assignment to flows */
194 194 MR_NEWLY_ADDED, /* Just assigned to another group */
195 195 MR_INUSE /* Assigned to an SRS */
196 196 } mac_ring_state_t;
197 197
198 198 /* mr_flag values */
199 199 #define MR_INCIPIENT 0x1
200 200 #define MR_CONDEMNED 0x2
↓ open down ↓ |
200 lines elided |
↑ open up ↑ |
201 201 #define MR_QUIESCE 0x4
202 202
203 203 typedef struct mac_impl_s mac_impl_t;
204 204
205 205 struct mac_ring_s {
206 206 int mr_index; /* index in the original list */
207 207 mac_ring_type_t mr_type; /* ring type */
208 208 mac_ring_t *mr_next; /* next ring in the chain */
209 209 mac_group_handle_t mr_gh; /* reference to group */
210 210
211 - mac_classify_type_t mr_classify_type; /* HW vs SW */
211 + mac_classify_type_t mr_classify_type;
212 212 struct mac_soft_ring_set_s *mr_srs; /* associated SRS */
213 - mac_ring_handle_t mr_prh; /* associated pseudo ring hdl */
213 + mac_ring_handle_t mr_prh; /* associated pseudo ring hdl */
214 +
215 + /*
216 + * Ring passthru callback and arguments. See the
217 + * MAC_PASSTHRU_CLASSIFIER comment in mac_provider.h.
218 + */
219 + mac_rx_t mr_pt_fn;
220 + void *mr_pt_arg1;
221 + mac_resource_handle_t mr_pt_arg2;
222 +
214 223 uint_t mr_refcnt; /* Ring references */
215 224 /* ring generation no. to guard against drivers using stale rings */
216 225 uint64_t mr_gen_num;
217 226
218 227 kstat_t *mr_ksp; /* ring kstats */
219 228 mac_impl_t *mr_mip; /* pointer to primary's mip */
220 229
221 230 kmutex_t mr_lock;
222 231 kcondvar_t mr_cv; /* mr_lock */
223 232 mac_ring_state_t mr_state; /* mr_lock */
224 233 uint_t mr_flag; /* mr_lock */
225 234
226 235 mac_ring_info_t mr_info; /* driver supplied info */
227 236 };
228 237 #define mr_driver mr_info.mri_driver
229 238 #define mr_start mr_info.mri_start
230 239 #define mr_stop mr_info.mri_stop
231 240 #define mr_stat mr_info.mri_stat
232 241
233 242 #define MAC_RING_MARK(mr, flag) \
234 243 (mr)->mr_flag |= flag;
235 244
236 245 #define MAC_RING_UNMARK(mr, flag) \
237 246 (mr)->mr_flag &= ~flag;
238 247
239 248 /*
240 249 * Reference hold and release on mac_ring_t 'mr'
241 250 */
242 251 #define MR_REFHOLD_LOCKED(mr) { \
243 252 ASSERT(MUTEX_HELD(&mr->mr_lock)); \
244 253 (mr)->mr_refcnt++; \
245 254 }
246 255
247 256 #define MR_REFRELE(mr) { \
248 257 mutex_enter(&(mr)->mr_lock); \
249 258 ASSERT((mr)->mr_refcnt != 0); \
250 259 (mr)->mr_refcnt--; \
251 260 if ((mr)->mr_refcnt == 0 && \
252 261 ((mr)->mr_flag & (MR_CONDEMNED | MR_QUIESCE))) \
253 262 cv_signal(&(mr)->mr_cv); \
254 263 mutex_exit(&(mr)->mr_lock); \
255 264 }
256 265
257 266 /*
258 267 * Used to attach MAC clients to an Rx group. The members are SL
259 268 * protected.
260 269 */
261 270 typedef struct mac_grp_client {
262 271 struct mac_grp_client *mgc_next;
263 272 struct mac_client_impl_s *mgc_client;
264 273 } mac_grp_client_t;
265 274
266 275 #define MAC_GROUP_NO_CLIENT(g) ((g)->mrg_clients == NULL)
267 276
268 277 #define MAC_GROUP_ONLY_CLIENT(g) \
269 278 ((((g)->mrg_clients != NULL) && \
270 279 ((g)->mrg_clients->mgc_next == NULL)) ? \
271 280 (g)->mrg_clients->mgc_client : NULL)
272 281
273 282 #define MAC_GROUP_HW_VLAN(g) \
274 283 (((g) != NULL) && \
275 284 ((g)->mrg_info.mgi_addvlan != NULL) && \
276 285 ((g)->mrg_info.mgi_remvlan != NULL))
277 286
278 287 /*
279 288 * Common ring group data structure for ring control and management.
280 289 * The entire structure is SL protected.
281 290 */
282 291 struct mac_group_s {
283 292 int mrg_index; /* index in the list */
284 293 mac_ring_type_t mrg_type; /* ring type */
285 294 mac_group_state_t mrg_state; /* state of the group */
286 295 mac_group_t *mrg_next; /* next group in the chain */
287 296 mac_handle_t mrg_mh; /* reference to MAC */
288 297 mac_ring_t *mrg_rings; /* grouped rings */
289 298 uint_t mrg_cur_count; /* actual size of group */
290 299
291 300 mac_grp_client_t *mrg_clients; /* clients list */
292 301
293 302 mac_group_info_t mrg_info; /* driver supplied info */
294 303 };
295 304
296 305 #define mrg_driver mrg_info.mgi_driver
297 306 #define mrg_start mrg_info.mgi_start
298 307 #define mrg_stop mrg_info.mgi_stop
299 308
300 309 #define GROUP_INTR_HANDLE(g) (g)->mrg_info.mgi_intr.mi_handle
301 310 #define GROUP_INTR_ENABLE_FUNC(g) (g)->mrg_info.mgi_intr.mi_enable
302 311 #define GROUP_INTR_DISABLE_FUNC(g) (g)->mrg_info.mgi_intr.mi_disable
303 312
304 313 #define MAC_RING_TX(mhp, rh, mp, rest) { \
305 314 mac_ring_handle_t mrh = rh; \
306 315 mac_impl_t *mimpl = (mac_impl_t *)mhp; \
307 316 /* \
308 317 * Send packets through a selected tx ring, or through the \
309 318 * default handler if there is no selected ring. \
310 319 */ \
311 320 if (mrh == NULL) \
312 321 mrh = mimpl->mi_default_tx_ring; \
313 322 if (mrh == NULL) { \
314 323 rest = mimpl->mi_tx(mimpl->mi_driver, mp); \
315 324 } else { \
316 325 rest = mac_hwring_tx(mrh, mp); \
317 326 } \
318 327 }
319 328
320 329 /*
321 330 * This is the final stop before reaching the underlying driver
322 331 * or aggregation, so this is where the bridging hook is implemented.
323 332 * Packets that are bridged will return through mac_bridge_tx(), with
324 333 * rh nulled out if the bridge chooses to send output on a different
325 334 * link due to forwarding.
326 335 */
327 336 #define MAC_TX(mip, rh, mp, src_mcip) { \
328 337 mac_ring_handle_t rhandle = (rh); \
329 338 /* \
330 339 * If there is a bound Hybrid I/O share, send packets through \
331 340 * the default tx ring. (When there's a bound Hybrid I/O share, \
332 341 * the tx rings of this client are mapped in the guest domain \
333 342 * and not accessible from here.) \
334 343 */ \
335 344 _NOTE(CONSTANTCONDITION) \
336 345 if ((src_mcip)->mci_state_flags & MCIS_SHARE_BOUND) \
337 346 rhandle = (mip)->mi_default_tx_ring; \
338 347 if (mip->mi_promisc_list != NULL) \
339 348 mac_promisc_dispatch(mip, mp, src_mcip); \
340 349 /* \
341 350 * Grab the proper transmit pointer and handle. Special \
342 351 * optimization: we can test mi_bridge_link itself atomically, \
343 352 * and if that indicates no bridge send packets through tx ring.\
344 353 */ \
345 354 if (mip->mi_bridge_link == NULL) { \
346 355 MAC_RING_TX(mip, rhandle, mp, mp); \
347 356 } else { \
348 357 mp = mac_bridge_tx(mip, rhandle, mp); \
349 358 } \
350 359 }
351 360
352 361 /* mci_tx_flag */
353 362 #define MCI_TX_QUIESCE 0x1
354 363
355 364 typedef struct mac_factory_addr_s {
356 365 boolean_t mfa_in_use;
357 366 uint8_t mfa_addr[MAXMACADDRLEN];
358 367 struct mac_client_impl_s *mfa_client;
359 368 } mac_factory_addr_t;
360 369
361 370 typedef struct mac_mcast_addrs_s {
362 371 struct mac_mcast_addrs_s *mma_next;
363 372 uint8_t mma_addr[MAXMACADDRLEN];
364 373 int mma_ref;
365 374 } mac_mcast_addrs_t;
366 375
367 376 typedef enum {
368 377 MAC_ADDRESS_TYPE_UNICAST_CLASSIFIED = 1, /* HW classification */
369 378 MAC_ADDRESS_TYPE_UNICAST_PROMISC /* promiscuous mode */
370 379 } mac_address_type_t;
371 380
372 381 typedef struct mac_vlan_s {
373 382 struct mac_vlan_s *mv_next;
374 383 uint16_t mv_vid;
375 384 } mac_vlan_t;
376 385
377 386 typedef struct mac_address_s {
378 387 mac_address_type_t ma_type; /* address type */
379 388 int ma_nusers; /* num users of addr */
380 389 struct mac_address_s *ma_next; /* next address */
381 390 uint8_t ma_addr[MAXMACADDRLEN]; /* address value */
382 391 size_t ma_len; /* address length */
383 392 mac_vlan_t *ma_vlans; /* VLANs on this addr */
384 393 boolean_t ma_untagged; /* accept untagged? */
385 394 mac_group_t *ma_group; /* asscociated group */
386 395 mac_impl_t *ma_mip; /* MAC handle */
387 396 } mac_address_t;
388 397
389 398 extern krwlock_t i_mac_impl_lock;
390 399 extern mod_hash_t *i_mac_impl_hash;
391 400 extern kmem_cache_t *i_mac_impl_cachep;
392 401 extern uint_t i_mac_impl_count;
393 402
394 403 /*
395 404 * Each registered MAC is associated with a mac_impl_t structure. The
396 405 * structure represents the undelying hardware, in terms of definition,
397 406 * resources (transmit, receive rings etc.), callback functions etc. It
398 407 * also holds the table of MAC clients that are configured on the device.
399 408 * The table is used for classifying incoming packets in software.
400 409 *
401 410 * The protection scheme uses 2 elements, a coarse serialization mechanism
402 411 * called perimeter and a finer traditional lock based scheme. More details
403 412 * can be found in the big block comment in mac.c.
404 413 *
405 414 * The protection scheme for each member of the mac_impl_t is described below.
406 415 *
407 416 * Write Once Only (WO): Typically these don't change for the lifetime of the
408 417 * data structure. For example something in mac_impl_t that stays the same
409 418 * from mac_register to mac_unregister, or something in a mac_client_impl_t
410 419 * that stays the same from mac_client_open to mac_client_close.
411 420 *
412 421 * Serializer (SL): Protected by the Serializer. All SLOP operations on a
413 422 * mac endpoint go through the serializer. MTOPs don't care about reading
414 423 * these fields atomically.
415 424 *
416 425 * Lock: Traditional mutex/rw lock. Modify operations still go through the
417 426 * mac serializer, the lock helps synchronize readers with writers.
418 427 */
419 428 struct mac_impl_s {
420 429 krwlock_t mi_rw_lock;
421 430 list_node_t mi_node;
422 431 char mi_name[LIFNAMSIZ]; /* WO */
423 432 uint32_t mi_state_flags;
424 433 void *mi_driver; /* Driver private, WO */
425 434 mac_info_t mi_info; /* WO */
426 435 mactype_t *mi_type; /* WO */
427 436 void *mi_pdata; /* WO */
428 437 size_t mi_pdata_size; /* WO */
429 438 mac_callbacks_t *mi_callbacks; /* WO */
430 439 dev_info_t *mi_dip; /* WO */
431 440 uint32_t mi_ref; /* i_mac_impl_lock */
432 441 uint_t mi_active; /* SL */
433 442 link_state_t mi_linkstate; /* none */
434 443 link_state_t mi_lowlinkstate; /* none */
435 444 link_state_t mi_lastlowlinkstate; /* none */
436 445 uint_t mi_devpromisc; /* SL */
437 446 uint8_t mi_addr[MAXMACADDRLEN]; /* mi_rw_lock */
438 447 uint8_t mi_dstaddr[MAXMACADDRLEN]; /* mi_rw_lock */
439 448 boolean_t mi_dstaddr_set;
440 449
441 450 /*
442 451 * The mac perimeter. All client initiated create/modify operations
443 452 * on a mac end point go through this.
444 453 */
445 454 kmutex_t mi_perim_lock;
446 455 kthread_t *mi_perim_owner; /* mi_perim_lock */
447 456 uint_t mi_perim_ocnt; /* mi_perim_lock */
448 457 kcondvar_t mi_perim_cv; /* mi_perim_lock */
449 458
450 459 /* mac notification callbacks */
451 460 kmutex_t mi_notify_lock;
452 461 mac_cb_info_t mi_notify_cb_info; /* mi_notify_lock */
453 462 mac_cb_t *mi_notify_cb_list; /* mi_notify_lock */
454 463 kthread_t *mi_notify_thread; /* mi_notify_lock */
455 464 uint_t mi_notify_bits; /* mi_notify_lock */
456 465
457 466 uint32_t mi_v12n_level; /* Virt'ion readiness */
458 467
459 468 /*
460 469 * RX groups, ring capability
461 470 * Fields of this block are SL protected.
462 471 */
463 472 mac_group_type_t mi_rx_group_type; /* grouping type */
464 473 uint_t mi_rx_group_count;
465 474 mac_group_t *mi_rx_groups;
466 475 mac_group_t *mi_rx_donor_grp;
467 476 uint_t mi_rxrings_rsvd;
468 477 uint_t mi_rxrings_avail;
469 478 uint_t mi_rxhwclnt_avail;
470 479 uint_t mi_rxhwclnt_used;
471 480
472 481 mac_capab_rings_t mi_rx_rings_cap;
473 482
474 483 /*
475 484 * TX groups and ring capability, SL Protected.
476 485 */
477 486 mac_group_type_t mi_tx_group_type; /* grouping type */
478 487 uint_t mi_tx_group_count;
479 488 uint_t mi_tx_group_free;
480 489 mac_group_t *mi_tx_groups;
481 490 mac_capab_rings_t mi_tx_rings_cap;
482 491 uint_t mi_txrings_rsvd;
483 492 uint_t mi_txrings_avail;
484 493 uint_t mi_txhwclnt_avail;
485 494 uint_t mi_txhwclnt_used;
486 495
487 496 mac_ring_handle_t mi_default_tx_ring;
488 497
489 498 /*
490 499 * Transceiver capabilities. SL protected.
491 500 */
492 501 mac_capab_transceiver_t mi_transceiver;
493 502
494 503 /*
495 504 * LED Capability information. SL protected.
496 505 */
497 506 mac_led_mode_t mi_led_modes;
498 507 mac_capab_led_t mi_led;
499 508
500 509 /*
501 510 * MAC address and VLAN lists. SL protected.
502 511 */
503 512 mac_address_t *mi_addresses;
504 513
505 514 /*
506 515 * This MAC's table of sub-flows
507 516 */
508 517 flow_tab_t *mi_flow_tab; /* WO */
509 518
510 519 kstat_t *mi_ksp; /* WO */
511 520 uint_t mi_kstat_count; /* WO */
512 521 uint_t mi_nactiveclients; /* SL */
513 522
514 523 /* for broadcast and multicast support */
515 524 struct mac_mcast_addrs_s *mi_mcast_addrs; /* mi_rw_lock */
516 525 struct mac_bcast_grp_s *mi_bcast_grp; /* mi_rw_lock */
517 526 uint_t mi_bcast_ngrps; /* mi_rw_lock */
518 527
519 528 /* list of MAC clients which opened this MAC */
520 529 struct mac_client_impl_s *mi_clients_list; /* mi_rw_lock */
521 530 uint_t mi_nclients; /* mi_rw_lock */
522 531 struct mac_client_impl_s *mi_single_active_client; /* mi_rw_lock */
523 532
524 533 uint32_t mi_margin; /* mi_rw_lock */
525 534 uint_t mi_sdu_min; /* mi_rw_lock */
526 535 uint_t mi_sdu_max; /* mi_rw_lock */
527 536 uint_t mi_sdu_multicast; /* mi_rw_lock */
528 537
529 538 /*
530 539 * Cache of factory MAC addresses provided by the driver. If
531 540 * the driver doesn't provide multiple factory MAC addresses,
532 541 * the mi_factory_addr is set to NULL, and mi_factory_addr_num
533 542 * is set to zero.
534 543 */
535 544 mac_factory_addr_t *mi_factory_addr; /* mi_rw_lock */
536 545 uint_t mi_factory_addr_num; /* mi_rw_lock */
537 546
538 547 /* for promiscuous mode support */
539 548 kmutex_t mi_promisc_lock;
540 549 mac_cb_t *mi_promisc_list; /* mi_promisc_lock */
541 550 mac_cb_info_t mi_promisc_cb_info; /* mi_promisc_lock */
542 551
543 552 /* cache of rings over this mac_impl */
544 553 kmutex_t mi_ring_lock;
545 554 mac_ring_t *mi_ring_freelist; /* mi_ring_lock */
546 555
547 556 /*
548 557 * These are used for caching the properties, if any, for the
549 558 * primary MAC client. If the MAC client is not yet in place
550 559 * when the properties are set then we cache them here to be
551 560 * applied to the MAC client when it is created.
552 561 */
553 562 mac_resource_props_t mi_resource_props; /* SL */
554 563 uint16_t mi_pvid; /* SL */
555 564
556 565 minor_t mi_minor; /* WO */
557 566 uint32_t mi_oref; /* SL */
558 567 mac_capab_legacy_t mi_capab_legacy; /* WO */
559 568 dev_t mi_phy_dev; /* WO */
560 569
561 570 /*
562 571 * List of margin value requests added by mac clients. This list is
563 572 * sorted: the first one has the greatest value.
564 573 */
565 574 mac_margin_req_t *mi_mmrp;
566 575 mac_mtu_req_t *mi_mtrp;
567 576 char **mi_priv_prop;
568 577 uint_t mi_priv_prop_count;
569 578
570 579 /*
571 580 * Hybrid I/O related definitions.
572 581 */
573 582 mac_capab_share_t mi_share_capab;
574 583
575 584 /*
576 585 * Bridging hooks and limit values. Uses mutex and reference counts
577 586 * (bridging only) for data path. Limits need no synchronization.
578 587 */
579 588 mac_handle_t mi_bridge_link;
580 589 kmutex_t mi_bridge_lock;
581 590 uint32_t mi_llimit;
582 591 uint32_t mi_ldecay;
583 592
584 593 /* This should be the last block in this structure */
585 594 #ifdef DEBUG
586 595 #define MAC_PERIM_STACK_DEPTH 15
587 596 int mi_perim_stack_depth;
588 597 pc_t mi_perim_stack[MAC_PERIM_STACK_DEPTH];
589 598 #endif
590 599 };
591 600
592 601 /*
593 602 * The default TX group is the last one in the list.
594 603 */
595 604 #define MAC_DEFAULT_TX_GROUP(mip) \
596 605 (mip)->mi_tx_groups + (mip)->mi_tx_group_count
597 606
598 607 /*
599 608 * The default RX group is the first one in the list
600 609 */
601 610 #define MAC_DEFAULT_RX_GROUP(mip) (mip)->mi_rx_groups
602 611
603 612 /* Reserved RX rings */
604 613 #define MAC_RX_RING_RESERVED(m, cnt) { \
605 614 ASSERT((m)->mi_rxrings_avail >= (cnt)); \
606 615 (m)->mi_rxrings_rsvd += (cnt); \
607 616 (m)->mi_rxrings_avail -= (cnt); \
608 617 }
609 618
610 619 /* Released RX rings */
611 620 #define MAC_RX_RING_RELEASED(m, cnt) { \
612 621 ASSERT((m)->mi_rxrings_rsvd >= (cnt)); \
613 622 (m)->mi_rxrings_rsvd -= (cnt); \
614 623 (m)->mi_rxrings_avail += (cnt); \
615 624 }
616 625
617 626 /* Reserved a RX group */
618 627 #define MAC_RX_GRP_RESERVED(m) { \
619 628 ASSERT((m)->mi_rxhwclnt_avail > 0); \
620 629 (m)->mi_rxhwclnt_avail--; \
621 630 (m)->mi_rxhwclnt_used++; \
622 631 }
623 632
624 633 /* Released a RX group */
625 634 #define MAC_RX_GRP_RELEASED(m) { \
626 635 ASSERT((m)->mi_rxhwclnt_used > 0); \
627 636 (m)->mi_rxhwclnt_avail++; \
628 637 (m)->mi_rxhwclnt_used--; \
629 638 }
630 639
631 640 /* Reserved TX rings */
632 641 #define MAC_TX_RING_RESERVED(m, cnt) { \
633 642 ASSERT((m)->mi_txrings_avail >= (cnt)); \
634 643 (m)->mi_txrings_rsvd += (cnt); \
635 644 (m)->mi_txrings_avail -= (cnt); \
636 645 }
637 646 /* Released TX rings */
638 647 #define MAC_TX_RING_RELEASED(m, cnt) { \
639 648 ASSERT((m)->mi_txrings_rsvd >= (cnt)); \
640 649 (m)->mi_txrings_rsvd -= (cnt); \
641 650 (m)->mi_txrings_avail += (cnt); \
642 651 }
643 652
644 653 /* Reserved a TX group */
645 654 #define MAC_TX_GRP_RESERVED(m) { \
646 655 ASSERT((m)->mi_txhwclnt_avail > 0); \
647 656 (m)->mi_txhwclnt_avail--; \
648 657 (m)->mi_txhwclnt_used++; \
649 658 }
650 659
651 660 /* Released a TX group */
652 661 #define MAC_TX_GRP_RELEASED(m) { \
653 662 ASSERT((m)->mi_txhwclnt_used > 0); \
654 663 (m)->mi_txhwclnt_avail++; \
655 664 (m)->mi_txhwclnt_used--; \
656 665 }
657 666
658 667 /* for mi_state_flags */
659 668 #define MIS_DISABLED 0x0001
660 669 #define MIS_IS_VNIC 0x0002
661 670 #define MIS_IS_AGGR 0x0004
662 671 #define MIS_NOTIFY_DONE 0x0008
663 672 #define MIS_EXCLUSIVE 0x0010
664 673 #define MIS_EXCLUSIVE_HELD 0x0020
665 674 #define MIS_LEGACY 0x0040
666 675 #define MIS_NO_ACTIVE 0x0080
667 676 #define MIS_POLL_DISABLE 0x0100
668 677
669 678 #define mi_getstat mi_callbacks->mc_getstat
670 679 #define mi_start mi_callbacks->mc_start
671 680 #define mi_stop mi_callbacks->mc_stop
672 681 #define mi_open mi_callbacks->mc_open
673 682 #define mi_close mi_callbacks->mc_close
674 683 #define mi_setpromisc mi_callbacks->mc_setpromisc
675 684 #define mi_multicst mi_callbacks->mc_multicst
676 685 #define mi_unicst mi_callbacks->mc_unicst
677 686 #define mi_tx mi_callbacks->mc_tx
678 687 #define mi_ioctl mi_callbacks->mc_ioctl
679 688 #define mi_getcapab mi_callbacks->mc_getcapab
680 689
681 690 typedef struct mac_notify_task_arg {
682 691 mac_impl_t *mnt_mip;
683 692 mac_notify_type_t mnt_type;
684 693 mac_ring_t *mnt_ring;
685 694 } mac_notify_task_arg_t;
686 695
687 696 /*
688 697 * The mac_perim_handle_t is an opaque type that encodes the 'mip' pointer
689 698 * and whether internally a mac_open was done when acquiring the perimeter.
690 699 */
691 700 #define MAC_ENCODE_MPH(mph, mh, need_close) \
692 701 (mph) = (mac_perim_handle_t)((uintptr_t)(mh) | need_close)
693 702
694 703 #define MAC_DECODE_MPH(mph, mip, need_close) { \
695 704 mip = (mac_impl_t *)(((uintptr_t)mph) & ~0x1); \
696 705 (need_close) = ((uintptr_t)mph & 0x1); \
697 706 }
698 707
699 708 /*
700 709 * Type of property information that can be returned by a driver.
701 710 * Valid flags of the pr_flags of the mac_prop_info_t data structure.
702 711 */
703 712 #define MAC_PROP_INFO_DEFAULT 0x0001
704 713 #define MAC_PROP_INFO_RANGE 0x0002
705 714 #define MAC_PROP_INFO_PERM 0x0004
706 715
707 716 /*
708 717 * Property information. pr_flags is a combination of one of the
709 718 * MAC_PROP_INFO_* flags, it is reset by the framework before invoking
710 719 * the driver's prefix_propinfo() entry point.
711 720 *
712 721 * Drivers should use MAC_PROP_INFO_SET_*() macros to provide
713 722 * information about a property.
714 723 */
715 724 typedef struct mac_prop_info_state_s {
716 725 uint8_t pr_flags;
717 726 uint8_t pr_perm;
718 727 uint8_t pr_errno;
719 728 void *pr_default;
720 729 size_t pr_default_size;
721 730 mac_propval_range_t *pr_range;
722 731 uint_t pr_range_cur_count;
723 732 } mac_prop_info_state_t;
724 733
725 734 #define MAC_PROTECT_ENABLED(mcip, type) \
726 735 (((mcip)->mci_flent-> \
727 736 fe_resource_props.mrp_mask & MRP_PROTECT) != 0 && \
728 737 ((mcip)->mci_flent-> \
729 738 fe_resource_props.mrp_protect.mp_types & (type)) != 0)
730 739
731 740 typedef struct mac_client_impl_s mac_client_impl_t;
732 741
733 742 extern void mac_init(void);
734 743 extern int mac_fini(void);
735 744
736 745 extern void mac_ndd_ioctl(mac_impl_t *, queue_t *, mblk_t *);
737 746 extern boolean_t mac_ip_hdr_length_v6(ip6_t *, uint8_t *, uint16_t *,
738 747 uint8_t *, ip6_frag_t **);
739 748
740 749 extern mblk_t *mac_copymsgchain_cksum(mblk_t *);
741 750 extern mblk_t *mac_fix_cksum(mblk_t *);
742 751 extern void mac_packet_print(mac_handle_t, mblk_t *);
743 752 extern void mac_rx_deliver(void *, mac_resource_handle_t, mblk_t *,
744 753 mac_header_info_t *);
745 754 extern void mac_tx_notify(mac_impl_t *);
746 755
747 756 extern boolean_t mac_callback_find(mac_cb_info_t *, mac_cb_t **, mac_cb_t *);
748 757 extern void mac_callback_add(mac_cb_info_t *, mac_cb_t **, mac_cb_t *);
749 758 extern boolean_t mac_callback_remove(mac_cb_info_t *, mac_cb_t **, mac_cb_t *);
750 759 extern void mac_callback_remove_wait(mac_cb_info_t *);
751 760 extern void mac_callback_free(mac_cb_t *);
752 761 extern mac_cb_t *mac_callback_walker_cleanup(mac_cb_info_t *, mac_cb_t **);
753 762
754 763 /* in mac_bcast.c */
755 764 extern void mac_bcast_init(void);
756 765 extern void mac_bcast_fini(void);
757 766 extern mac_impl_t *mac_bcast_grp_mip(void *);
758 767 extern int mac_bcast_add(mac_client_impl_t *, const uint8_t *, uint16_t,
759 768 mac_addrtype_t);
760 769 extern void mac_bcast_delete(mac_client_impl_t *, const uint8_t *, uint16_t);
761 770 extern void mac_bcast_send(void *, void *, mblk_t *, boolean_t);
762 771 extern void mac_bcast_grp_free(void *);
763 772 extern void mac_bcast_refresh(mac_impl_t *, mac_multicst_t, void *,
764 773 boolean_t);
765 774 extern void mac_client_bcast_refresh(mac_client_impl_t *, mac_multicst_t,
766 775 void *, boolean_t);
767 776
768 777 /*
769 778 * Grouping functions are used internally by MAC layer.
770 779 */
771 780 extern int mac_group_addmac(mac_group_t *, const uint8_t *);
772 781 extern int mac_group_remmac(mac_group_t *, const uint8_t *);
773 782 extern int mac_group_addvlan(mac_group_t *, uint16_t);
774 783 extern int mac_group_remvlan(mac_group_t *, uint16_t);
775 784 extern int mac_rx_group_add_flow(mac_client_impl_t *, flow_entry_t *,
776 785 mac_group_t *);
777 786 extern mblk_t *mac_hwring_tx(mac_ring_handle_t, mblk_t *);
778 787 extern mblk_t *mac_bridge_tx(mac_impl_t *, mac_ring_handle_t, mblk_t *);
779 788 extern mac_group_t *mac_reserve_rx_group(mac_client_impl_t *, uint8_t *,
780 789 boolean_t);
781 790 extern void mac_release_rx_group(mac_client_impl_t *, mac_group_t *);
782 791 extern int mac_rx_switch_group(mac_client_impl_t *, mac_group_t *,
783 792 mac_group_t *);
784 793 extern mac_ring_t *mac_reserve_tx_ring(mac_impl_t *, mac_ring_t *);
785 794 extern mac_group_t *mac_reserve_tx_group(mac_client_impl_t *, boolean_t);
786 795 extern void mac_release_tx_group(mac_client_impl_t *, mac_group_t *);
787 796 extern void mac_tx_switch_group(mac_client_impl_t *, mac_group_t *,
788 797 mac_group_t *);
789 798 extern void mac_rx_switch_grp_to_sw(mac_group_t *);
790 799
791 800 /*
792 801 * MAC address functions are used internally by MAC layer.
793 802 */
794 803 extern mac_address_t *mac_find_macaddr(mac_impl_t *, uint8_t *);
795 804 extern mac_address_t *mac_find_macaddr_vlan(mac_impl_t *, uint8_t *, uint16_t);
796 805 extern boolean_t mac_check_macaddr_shared(mac_address_t *);
797 806 extern int mac_update_macaddr(mac_address_t *, uint8_t *);
798 807 extern void mac_freshen_macaddr(mac_address_t *, uint8_t *);
799 808 extern void mac_retrieve_macaddr(mac_address_t *, uint8_t *);
800 809 extern void mac_init_macaddr(mac_impl_t *);
801 810 extern void mac_fini_macaddr(mac_impl_t *);
802 811
803 812 /*
804 813 * Flow construction/destruction routines.
805 814 * Not meant to be used by mac clients.
806 815 */
807 816 extern int mac_link_flow_init(mac_client_handle_t, flow_entry_t *);
808 817 extern void mac_link_flow_clean(mac_client_handle_t, flow_entry_t *);
809 818
810 819 /*
811 820 * Fanout update routines called when the link speed of the NIC changes
812 821 * or when a MAC client's share is unbound.
813 822 */
814 823 extern void mac_fanout_recompute_client(mac_client_impl_t *, cpupart_t *);
815 824 extern void mac_fanout_recompute(mac_impl_t *);
816 825
817 826 /*
818 827 * The following functions are used internally by the MAC layer to
819 828 * add/remove/update flows associated with a mac_impl_t. They should
820 829 * never be used directly by MAC clients.
821 830 */
822 831 extern int mac_datapath_setup(mac_client_impl_t *, flow_entry_t *, uint32_t);
823 832 extern void mac_datapath_teardown(mac_client_impl_t *, flow_entry_t *,
824 833 uint32_t);
825 834 extern void mac_rx_srs_group_setup(mac_client_impl_t *, flow_entry_t *,
826 835 uint32_t);
827 836 extern void mac_tx_srs_group_setup(mac_client_impl_t *, flow_entry_t *,
828 837 uint32_t);
829 838 extern void mac_rx_srs_group_teardown(flow_entry_t *, boolean_t);
830 839 extern void mac_tx_srs_group_teardown(mac_client_impl_t *, flow_entry_t *,
831 840 uint32_t);
832 841 extern int mac_rx_classify_flow_quiesce(flow_entry_t *, void *);
833 842 extern int mac_rx_classify_flow_restart(flow_entry_t *, void *);
834 843 extern void mac_client_quiesce(mac_client_impl_t *);
835 844 extern void mac_client_restart(mac_client_impl_t *);
836 845
837 846 extern void mac_flow_update_priority(mac_client_impl_t *, flow_entry_t *);
838 847
839 848 extern void mac_flow_rem_subflow(flow_entry_t *);
840 849 extern void mac_rename_flow(flow_entry_t *, const char *);
841 850 extern void mac_flow_set_name(flow_entry_t *, const char *);
842 851
843 852 extern mblk_t *mac_add_vlan_tag(mblk_t *, uint_t, uint16_t);
844 853 extern mblk_t *mac_add_vlan_tag_chain(mblk_t *, uint_t, uint16_t);
845 854 extern mblk_t *mac_strip_vlan_tag_chain(mblk_t *);
846 855 extern void mac_pkt_drop(void *, mac_resource_handle_t, mblk_t *, boolean_t);
847 856 extern mblk_t *mac_rx_flow(mac_handle_t, mac_resource_handle_t, mblk_t *);
848 857
849 858 extern void i_mac_share_alloc(mac_client_impl_t *);
850 859 extern void i_mac_share_free(mac_client_impl_t *);
851 860 extern void i_mac_perim_enter(mac_impl_t *);
852 861 extern void i_mac_perim_exit(mac_impl_t *);
853 862 extern int i_mac_perim_enter_nowait(mac_impl_t *);
854 863 extern void i_mac_tx_srs_notify(mac_impl_t *, mac_ring_handle_t);
855 864 extern int mac_hold(const char *, mac_impl_t **);
856 865 extern void mac_rele(mac_impl_t *);
857 866 extern int i_mac_disable(mac_impl_t *);
858 867 extern void i_mac_notify(mac_impl_t *, mac_notify_type_t);
859 868 extern void i_mac_notify_exit(mac_impl_t *);
860 869 extern void mac_rx_group_unmark(mac_group_t *, uint_t);
861 870 extern void mac_tx_client_flush(mac_client_impl_t *);
862 871 extern void mac_tx_client_block(mac_client_impl_t *);
863 872 extern void mac_tx_client_unblock(mac_client_impl_t *);
864 873 extern void mac_tx_invoke_callbacks(mac_client_impl_t *, mac_tx_cookie_t);
865 874 extern int i_mac_promisc_set(mac_impl_t *, boolean_t);
866 875 extern void i_mac_promisc_walker_cleanup(mac_impl_t *);
867 876 extern mactype_t *mactype_getplugin(const char *);
868 877 extern void mac_addr_factory_init(mac_impl_t *);
869 878 extern void mac_addr_factory_fini(mac_impl_t *);
870 879 extern void mac_register_priv_prop(mac_impl_t *, char **);
871 880 extern void mac_unregister_priv_prop(mac_impl_t *);
872 881 extern int mac_init_rings(mac_impl_t *, mac_ring_type_t);
873 882 extern void mac_free_rings(mac_impl_t *, mac_ring_type_t);
874 883 extern void mac_compare_ddi_handle(mac_group_t *, uint_t, mac_ring_t *);
875 884
876 885 extern int mac_start_group(mac_group_t *);
877 886 extern void mac_stop_group(mac_group_t *);
878 887 extern int mac_start_ring(mac_ring_t *);
879 888 extern void mac_stop_ring(mac_ring_t *);
880 889 extern int mac_add_macaddr_vlan(mac_impl_t *, mac_group_t *, uint8_t *,
881 890 uint16_t, boolean_t);
882 891 extern int mac_remove_macaddr_vlan(mac_address_t *, uint16_t);
883 892
884 893 extern void mac_set_group_state(mac_group_t *, mac_group_state_t);
885 894 extern void mac_group_add_client(mac_group_t *, mac_client_impl_t *);
886 895 extern void mac_group_remove_client(mac_group_t *, mac_client_impl_t *);
887 896
888 897 extern int i_mac_group_add_ring(mac_group_t *, mac_ring_t *, int);
889 898 extern void i_mac_group_rem_ring(mac_group_t *, mac_ring_t *, boolean_t);
890 899 extern int mac_group_ring_modify(mac_client_impl_t *, mac_group_t *,
891 900 mac_group_t *);
892 901 extern void mac_poll_state_change(mac_handle_t, boolean_t);
893 902
894 903 extern mac_group_state_t mac_group_next_state(mac_group_t *,
895 904 mac_client_impl_t **, mac_group_t *, boolean_t);
896 905
897 906 extern mblk_t *mac_protect_check(mac_client_handle_t, mblk_t *);
898 907 extern int mac_protect_set(mac_client_handle_t, mac_resource_props_t *);
899 908 extern boolean_t mac_protect_enabled(mac_client_handle_t, uint32_t);
900 909 extern int mac_protect_validate(mac_resource_props_t *);
901 910 extern void mac_protect_update(mac_resource_props_t *, mac_resource_props_t *);
902 911 extern void mac_protect_update_mac_token(mac_client_impl_t *);
903 912 extern void mac_protect_intercept_dynamic(mac_client_impl_t *, mblk_t *);
904 913 extern void mac_protect_flush_dynamic(mac_client_impl_t *);
905 914 extern void mac_protect_cancel_timer(mac_client_impl_t *);
906 915 extern void mac_protect_init(mac_client_impl_t *);
907 916 extern void mac_protect_fini(mac_client_impl_t *);
908 917
909 918 extern int mac_set_resources(mac_handle_t, mac_resource_props_t *);
910 919 extern void mac_get_resources(mac_handle_t, mac_resource_props_t *);
911 920 extern void mac_get_effective_resources(mac_handle_t, mac_resource_props_t *);
912 921 extern void mac_set_promisc_filtered(mac_client_handle_t, boolean_t);
913 922 extern boolean_t mac_get_promisc_filtered(mac_client_handle_t);
914 923
915 924 extern cpupart_t *mac_pset_find(mac_resource_props_t *, boolean_t *);
916 925 extern void mac_set_pool_effective(boolean_t, cpupart_t *,
917 926 mac_resource_props_t *, mac_resource_props_t *);
918 927 extern void mac_set_rings_effective(mac_client_impl_t *);
919 928 extern mac_client_impl_t *mac_check_primary_relocation(mac_client_impl_t *,
920 929 boolean_t);
921 930
922 931 /* Global callbacks into the bridging module (when loaded) */
923 932 extern mac_bridge_tx_t mac_bridge_tx_cb;
924 933 extern mac_bridge_rx_t mac_bridge_rx_cb;
925 934 extern mac_bridge_ref_t mac_bridge_ref_cb;
926 935 extern mac_bridge_ls_t mac_bridge_ls_cb;
927 936
928 937 /*
929 938 * MAC Transceiver related functions
930 939 */
931 940 struct mac_transceiver_info {
932 941 boolean_t mti_present;
933 942 boolean_t mti_usable;
934 943 };
935 944
936 945 extern void mac_transceiver_init(mac_impl_t *);
937 946 extern int mac_transceiver_count(mac_handle_t, uint_t *);
938 947 extern int mac_transceiver_info(mac_handle_t, uint_t, boolean_t *, boolean_t *);
939 948 extern int mac_transceiver_read(mac_handle_t, uint_t, uint_t, void *, size_t,
940 949 off_t, size_t *);
941 950
942 951 /*
943 952 * MAC LED related functions
944 953 */
945 954 #define MAC_LED_ALL (MAC_LED_DEFAULT | MAC_LED_OFF | MAC_LED_IDENT | \
946 955 MAC_LED_ON)
947 956 extern void mac_led_init(mac_impl_t *);
948 957 extern int mac_led_get(mac_handle_t, mac_led_mode_t *, mac_led_mode_t *);
949 958 extern int mac_led_set(mac_handle_t, mac_led_mode_t);
950 959
951 960 #ifdef __cplusplus
952 961 }
953 962 #endif
954 963
955 964 #endif /* _SYS_MAC_IMPL_H */
↓ open down ↓ |
732 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX