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