Print this page
10687 Service routine cast changes need smatch fixes
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/common/io/softmac/softmac_fp.c
+++ new/usr/src/uts/common/io/softmac/softmac_fp.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
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
↓ open down ↓ |
16 lines elided |
↑ open up ↑ |
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21 /*
22 22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 23 * Use is subject to license terms.
24 24 */
25 25
26 26 /*
27 + * Copyright 2019, Joyent, Inc.
28 + */
29 +
30 +/*
27 31 * Softmac data-path switching:
28 32 *
29 33 * - Fast-path model
30 34 *
31 35 * When the softmac fast-path is used, a dedicated lower-stream
32 36 * will be opened over the legacy device for each IP/ARP (upper-)stream
33 37 * over the softMAC, and all DLPI messages (including control messages
34 38 * and data messages) will be exchanged between the upper-stream and
35 39 * the corresponding lower-stream directly. Therefore, the data
36 40 * demultiplexing, filtering and classification processing will be done
37 41 * by the lower-stream, and the GLDv3 DLS/MAC layer processing will be
38 42 * no longer needed.
39 43 *
40 44 * - Slow-path model
41 45 *
42 46 * Some GLDv3 features requires the GLDv3 DLS/MAC layer processing to
43 47 * not be bypassed to assure its function correctness. For example,
44 48 * softmac fast-path must be disabled to support GLDv3 VNIC functionality.
45 49 * In this case, a shared lower-stream will be opened over the legacy
46 50 * device, which is responsible for implementing the GLDv3 callbacks
47 51 * and passing RAW data messages between the legacy devices and the GLDv3
48 52 * framework.
49 53 *
50 54 * By default, the softmac fast-path mode will be used to assure the
51 55 * performance; MAC clients will be able to request to disable the softmac
52 56 * fast-path mode to support certain features, and if that succeeds,
53 57 * the system will fallback to the slow-path softmac data-path model.
54 58 *
55 59 *
56 60 * The details of the softmac data fast-path model is stated as below
57 61 *
58 62 * 1. When a stream is opened on a softMAC, the softmac module will takes
59 63 * over the DLPI processing on this stream;
60 64 *
61 65 * 2. For IP/ARP streams over a softMAC, softmac data fast-path will be
62 66 * used by default, unless fast-path is disabled by any MAC client
63 67 * explicitly. The softmac module first identifies an IP/ARP stream
64 68 * by seeing whether there is a SIOCSLIFNAME ioctl sent from upstream,
65 69 * if there is one, this stream is either an IP or an ARP stream
66 70 * and will use fast-path potentially;
67 71 *
68 72 * 3. When the softmac fast-path is used, an dedicated lower-stream will
69 73 * be setup for each IP/ARP stream (1-1 mapping). From that point on,
70 74 * all control and data messages will be exchanged between the IP/ARP
71 75 * upper-stream and the legacy device through this dedicated
72 76 * lower-stream. As a result, the DLS/MAC layer processing in GLDv3
73 77 * will be skipped, and this greatly improves the performance;
74 78 *
75 79 * 4. When the softmac data fast-path is disabled by a MAC client (e.g.,
76 80 * by a VNIC), all the IP/ARP upper streams will try to switch from
77 81 * the fast-path to the slow-path. The dedicated lower-stream will be
78 82 * destroyed, and all the control and data-messages will go through the
79 83 * existing GLDv3 code path and (in the end) the shared lower-stream;
80 84 *
81 85 * 5. On the other hand, when the last MAC client cancels its fast-path
82 86 * disable request, all the IP/ARP streams will try to switch back to
83 87 * the fast-path mode;
84 88 *
85 89 * Step 5 and 6 both rely on the data-path mode switching process
86 90 * described below:
87 91 *
88 92 * 1) To switch the softmac data-path mode (between fast-path and slow-path),
89 93 * softmac will first send a DL_NOTE_REPLUMB DL_NOTIFY_IND message
90 94 * upstream over each IP/ARP streams that needs data-path mode switching;
91 95 *
92 96 * 2) When IP receives this DL_NOTE_REPLUMB message, it will bring down
93 97 * all the IP interfaces on the corresponding ill (IP Lower level
94 98 * structure), and bring up those interfaces over again; this will in
95 99 * turn cause the ARP to "replumb" the interface.
96 100 *
97 101 * During the replumb process, both IP and ARP will send downstream the
98 102 * necessary DL_DISABMULTI_REQ and DL_UNBIND_REQ messages and cleanup
99 103 * the old state of the underlying softMAC, following with the necessary
100 104 * DL_BIND_REQ and DL_ENABMULTI_REQ messages to setup the new state.
101 105 * Between the cleanup and re-setup process, IP/ARP will also send down
102 106 * a DL_NOTE_REPLUMB_DONE DL_NOTIFY_CONF messages to the softMAC to
103 107 * indicate the *switching point*;
104 108 *
105 109 * 3) When softmac receives the DL_NOTE_REPLUMB_DONE message, it either
106 110 * creates or destroys the dedicated lower-stream (depending on which
107 111 * data-path mode the softMAC switches to), and change the softmac
108 112 * data-path mode. From then on, softmac will process all the succeeding
109 113 * control messages (including the DL_BIND_REQ and DL_ENABMULTI_REQ
110 114 * messages) and data messages based on new data-path mode.
111 115 */
112 116
113 117 #include <sys/types.h>
114 118 #include <sys/disp.h>
115 119 #include <sys/callb.h>
116 120 #include <sys/sysmacros.h>
117 121 #include <sys/file.h>
118 122 #include <sys/vlan.h>
119 123 #include <sys/dld.h>
120 124 #include <sys/sockio.h>
121 125 #include <sys/softmac_impl.h>
122 126 #include <net/if.h>
123 127
124 128 static kmutex_t softmac_taskq_lock;
125 129 static kcondvar_t softmac_taskq_cv;
126 130 static list_t softmac_taskq_list; /* List of softmac_upper_t */
127 131 boolean_t softmac_taskq_quit;
128 132 boolean_t softmac_taskq_done;
129 133
130 134 static void softmac_taskq_dispatch();
131 135 static int softmac_fastpath_setup(softmac_upper_t *);
132 136 static mac_tx_cookie_t softmac_fastpath_wput_data(softmac_upper_t *, mblk_t *,
133 137 uintptr_t, uint16_t);
134 138 static void softmac_datapath_switch_done(softmac_upper_t *);
135 139
136 140 void
137 141 softmac_fp_init()
138 142 {
139 143 mutex_init(&softmac_taskq_lock, NULL, MUTEX_DRIVER, NULL);
140 144 cv_init(&softmac_taskq_cv, NULL, CV_DRIVER, NULL);
141 145
142 146 softmac_taskq_quit = B_FALSE;
143 147 softmac_taskq_done = B_FALSE;
144 148 list_create(&softmac_taskq_list, sizeof (softmac_upper_t),
145 149 offsetof(softmac_upper_t, su_taskq_list_node));
146 150 (void) thread_create(NULL, 0, softmac_taskq_dispatch, NULL, 0,
147 151 &p0, TS_RUN, minclsyspri);
148 152 }
149 153
150 154 void
151 155 softmac_fp_fini()
152 156 {
153 157 /*
154 158 * Request the softmac_taskq thread to quit and wait for it to be done.
155 159 */
156 160 mutex_enter(&softmac_taskq_lock);
157 161 softmac_taskq_quit = B_TRUE;
158 162 cv_signal(&softmac_taskq_cv);
159 163 while (!softmac_taskq_done)
160 164 cv_wait(&softmac_taskq_cv, &softmac_taskq_lock);
161 165 mutex_exit(&softmac_taskq_lock);
162 166 list_destroy(&softmac_taskq_list);
163 167
164 168 mutex_destroy(&softmac_taskq_lock);
165 169 cv_destroy(&softmac_taskq_cv);
166 170 }
167 171
168 172 static boolean_t
169 173 check_ip_above(queue_t *q)
170 174 {
171 175 queue_t *next_q;
172 176 boolean_t ret = B_TRUE;
173 177
174 178 claimstr(q);
175 179 next_q = q->q_next;
176 180 if (strcmp(next_q->q_qinfo->qi_minfo->mi_idname, "ip") != 0)
177 181 ret = B_FALSE;
178 182 releasestr(q);
179 183 return (ret);
180 184 }
181 185
182 186 /* ARGSUSED */
183 187 static int
184 188 softmac_capab_perim(softmac_upper_t *sup, void *data, uint_t flags)
185 189 {
186 190 switch (flags) {
187 191 case DLD_ENABLE:
188 192 mutex_enter(&sup->su_mutex);
189 193 break;
190 194 case DLD_DISABLE:
191 195 mutex_exit(&sup->su_mutex);
192 196 break;
193 197 case DLD_QUERY:
194 198 return (MUTEX_HELD(&sup->su_mutex));
195 199 }
196 200 return (0);
197 201 }
198 202
199 203 static mac_tx_notify_handle_t
200 204 softmac_client_tx_notify(softmac_upper_t *sup, mac_tx_notify_t func, void *arg)
201 205 {
202 206 ASSERT(MUTEX_HELD(&sup->su_mutex));
203 207
204 208 if (func != NULL) {
205 209 sup->su_tx_notify_func = func;
206 210 sup->su_tx_notify_arg = arg;
207 211 } else {
208 212 /*
209 213 * Wait for all tx_notify_func call to be done.
210 214 */
211 215 while (sup->su_tx_inprocess != 0)
212 216 cv_wait(&sup->su_cv, &sup->su_mutex);
213 217
214 218 sup->su_tx_notify_func = NULL;
215 219 sup->su_tx_notify_arg = NULL;
216 220 }
217 221 return ((mac_tx_notify_handle_t)sup);
218 222 }
219 223
220 224 static boolean_t
221 225 softmac_tx_is_flow_blocked(softmac_upper_t *sup, mac_tx_cookie_t cookie)
222 226 {
223 227 ASSERT(cookie == (mac_tx_cookie_t)sup);
224 228 return (sup->su_tx_busy);
225 229 }
226 230
227 231 static int
228 232 softmac_capab_direct(softmac_upper_t *sup, void *data, uint_t flags)
229 233 {
230 234 dld_capab_direct_t *direct = data;
231 235 softmac_lower_t *slp = sup->su_slp;
232 236
233 237 ASSERT(MUTEX_HELD(&sup->su_mutex));
234 238
235 239 ASSERT(sup->su_mode == SOFTMAC_FASTPATH);
236 240
237 241 switch (flags) {
238 242 case DLD_ENABLE:
239 243 if (sup->su_direct)
240 244 return (0);
241 245
242 246 sup->su_direct_rxinfo.slr_rx = (softmac_rx_t)direct->di_rx_cf;
243 247 sup->su_direct_rxinfo.slr_arg = direct->di_rx_ch;
244 248 slp->sl_rxinfo = &sup->su_direct_rxinfo;
245 249 direct->di_tx_df = (uintptr_t)softmac_fastpath_wput_data;
246 250 direct->di_tx_dh = sup;
247 251 direct->di_tx_fctl_df = (uintptr_t)softmac_tx_is_flow_blocked;
248 252 direct->di_tx_fctl_dh = sup;
249 253 direct->di_tx_cb_df = (uintptr_t)softmac_client_tx_notify;
250 254 direct->di_tx_cb_dh = sup;
251 255 sup->su_direct = B_TRUE;
252 256 return (0);
253 257
254 258 case DLD_DISABLE:
255 259 if (!sup->su_direct)
256 260 return (0);
257 261
258 262 slp->sl_rxinfo = &sup->su_rxinfo;
259 263 sup->su_direct = B_FALSE;
260 264 return (0);
261 265 }
262 266 return (ENOTSUP);
263 267 }
264 268
265 269 static int
266 270 softmac_dld_capab(softmac_upper_t *sup, uint_t type, void *data, uint_t flags)
267 271 {
268 272 int err;
269 273
270 274 /*
271 275 * Don't enable direct callback capabilities unless the caller is
272 276 * the IP client. When a module is inserted in a stream (_I_INSERT)
273 277 * the stack initiates capability disable, but due to races, the
274 278 * module insertion may complete before the capability disable
275 279 * completes. So we limit the check to DLD_ENABLE case.
276 280 */
277 281 if ((flags == DLD_ENABLE && type != DLD_CAPAB_PERIM) &&
278 282 !check_ip_above(sup->su_rq)) {
279 283 return (ENOTSUP);
280 284 }
281 285
282 286 switch (type) {
283 287 case DLD_CAPAB_DIRECT:
284 288 err = softmac_capab_direct(sup, data, flags);
285 289 break;
286 290
287 291 case DLD_CAPAB_PERIM:
288 292 err = softmac_capab_perim(sup, data, flags);
289 293 break;
290 294
291 295 default:
292 296 err = ENOTSUP;
293 297 break;
294 298 }
295 299 return (err);
296 300 }
297 301
298 302 static void
299 303 softmac_capability_advertise(softmac_upper_t *sup, mblk_t *mp)
300 304 {
301 305 dl_capability_ack_t *dlap;
302 306 dl_capability_sub_t *dlsp;
303 307 t_uscalar_t subsize;
304 308 uint8_t *ptr;
305 309 queue_t *q = sup->su_wq;
306 310 mblk_t *mp1;
307 311 softmac_t *softmac = sup->su_softmac;
308 312 boolean_t dld_capable = B_FALSE;
309 313 boolean_t hcksum_capable = B_FALSE;
310 314 boolean_t zcopy_capable = B_FALSE;
311 315 boolean_t mdt_capable = B_FALSE;
312 316
313 317 ASSERT(sup->su_mode == SOFTMAC_FASTPATH);
314 318
315 319 /*
316 320 * Initially assume no capabilities.
317 321 */
318 322 subsize = 0;
319 323
320 324 /*
321 325 * Direct capability negotiation interface between IP and softmac
322 326 */
323 327 if (check_ip_above(sup->su_rq)) {
324 328 dld_capable = B_TRUE;
325 329 subsize += sizeof (dl_capability_sub_t) +
326 330 sizeof (dl_capab_dld_t);
327 331 }
328 332
329 333 /*
330 334 * Check if checksum offload is supported on this MAC.
331 335 */
332 336 if (softmac->smac_capab_flags & MAC_CAPAB_HCKSUM) {
333 337 hcksum_capable = B_TRUE;
334 338 subsize += sizeof (dl_capability_sub_t) +
335 339 sizeof (dl_capab_hcksum_t);
336 340 }
337 341
338 342 /*
339 343 * Check if zerocopy is supported on this interface.
340 344 */
341 345 if (!(softmac->smac_capab_flags & MAC_CAPAB_NO_ZCOPY)) {
342 346 zcopy_capable = B_TRUE;
343 347 subsize += sizeof (dl_capability_sub_t) +
344 348 sizeof (dl_capab_zerocopy_t);
345 349 }
346 350
347 351 if (softmac->smac_mdt) {
348 352 mdt_capable = B_TRUE;
349 353 subsize += sizeof (dl_capability_sub_t) +
350 354 sizeof (dl_capab_mdt_t);
351 355 }
352 356
353 357 /*
354 358 * If there are no capabilities to advertise or if we
355 359 * can't allocate a response, send a DL_ERROR_ACK.
356 360 */
357 361 if ((subsize == 0) || (mp1 = reallocb(mp,
358 362 sizeof (dl_capability_ack_t) + subsize, 0)) == NULL) {
359 363 dlerrorack(q, mp, DL_CAPABILITY_REQ, DL_NOTSUPPORTED, 0);
360 364 return;
361 365 }
362 366
363 367 mp = mp1;
364 368 DB_TYPE(mp) = M_PROTO;
365 369 mp->b_wptr = mp->b_rptr + sizeof (dl_capability_ack_t) + subsize;
366 370 bzero(mp->b_rptr, MBLKL(mp));
367 371 dlap = (dl_capability_ack_t *)mp->b_rptr;
368 372 dlap->dl_primitive = DL_CAPABILITY_ACK;
369 373 dlap->dl_sub_offset = sizeof (dl_capability_ack_t);
370 374 dlap->dl_sub_length = subsize;
371 375 ptr = (uint8_t *)&dlap[1];
372 376
373 377 /*
374 378 * IP polling interface.
375 379 */
376 380 if (dld_capable) {
377 381 dl_capab_dld_t dld;
378 382
379 383 dlsp = (dl_capability_sub_t *)ptr;
380 384 dlsp->dl_cap = DL_CAPAB_DLD;
381 385 dlsp->dl_length = sizeof (dl_capab_dld_t);
382 386 ptr += sizeof (dl_capability_sub_t);
383 387
384 388 bzero(&dld, sizeof (dl_capab_dld_t));
385 389 dld.dld_version = DLD_CURRENT_VERSION;
386 390 dld.dld_capab = (uintptr_t)softmac_dld_capab;
387 391 dld.dld_capab_handle = (uintptr_t)sup;
388 392
389 393 dlcapabsetqid(&(dld.dld_mid), sup->su_rq);
390 394 bcopy(&dld, ptr, sizeof (dl_capab_dld_t));
391 395 ptr += sizeof (dl_capab_dld_t);
392 396 }
393 397
394 398 /*
395 399 * TCP/IP checksum offload.
396 400 */
397 401 if (hcksum_capable) {
398 402 dl_capab_hcksum_t hcksum;
399 403
400 404 dlsp = (dl_capability_sub_t *)ptr;
401 405
402 406 dlsp->dl_cap = DL_CAPAB_HCKSUM;
403 407 dlsp->dl_length = sizeof (dl_capab_hcksum_t);
404 408 ptr += sizeof (dl_capability_sub_t);
405 409
406 410 bzero(&hcksum, sizeof (dl_capab_hcksum_t));
407 411 hcksum.hcksum_version = HCKSUM_VERSION_1;
408 412 hcksum.hcksum_txflags = softmac->smac_hcksum_txflags;
409 413 dlcapabsetqid(&(hcksum.hcksum_mid), sup->su_rq);
410 414 bcopy(&hcksum, ptr, sizeof (dl_capab_hcksum_t));
411 415 ptr += sizeof (dl_capab_hcksum_t);
412 416 }
413 417
414 418 /*
415 419 * Zero copy
416 420 */
417 421 if (zcopy_capable) {
418 422 dl_capab_zerocopy_t zcopy;
419 423
420 424 dlsp = (dl_capability_sub_t *)ptr;
421 425
422 426 dlsp->dl_cap = DL_CAPAB_ZEROCOPY;
423 427 dlsp->dl_length = sizeof (dl_capab_zerocopy_t);
424 428 ptr += sizeof (dl_capability_sub_t);
425 429
426 430 bzero(&zcopy, sizeof (dl_capab_zerocopy_t));
427 431 zcopy.zerocopy_version = ZEROCOPY_VERSION_1;
428 432 zcopy.zerocopy_flags = DL_CAPAB_VMSAFE_MEM;
429 433 dlcapabsetqid(&(zcopy.zerocopy_mid), sup->su_rq);
430 434 bcopy(&zcopy, ptr, sizeof (dl_capab_zerocopy_t));
431 435 ptr += sizeof (dl_capab_zerocopy_t);
432 436 }
433 437
434 438 /*
435 439 * MDT
436 440 */
437 441 if (mdt_capable) {
438 442 dl_capab_mdt_t mdt;
439 443
440 444 dlsp = (dl_capability_sub_t *)ptr;
441 445
442 446 dlsp->dl_cap = DL_CAPAB_MDT;
443 447 dlsp->dl_length = sizeof (dl_capab_mdt_t);
444 448 ptr += sizeof (dl_capability_sub_t);
445 449
446 450 bzero(&mdt, sizeof (dl_capab_mdt_t));
447 451 mdt.mdt_version = MDT_VERSION_2;
448 452 mdt.mdt_flags = DL_CAPAB_MDT_ENABLE;
449 453 mdt.mdt_hdr_head = softmac->smac_mdt_capab.mdt_hdr_head;
450 454 mdt.mdt_hdr_tail = softmac->smac_mdt_capab.mdt_hdr_tail;
451 455 mdt.mdt_max_pld = softmac->smac_mdt_capab.mdt_max_pld;
452 456 mdt.mdt_span_limit = softmac->smac_mdt_capab.mdt_span_limit;
453 457 dlcapabsetqid(&(mdt.mdt_mid), sup->su_rq);
454 458 bcopy(&mdt, ptr, sizeof (dl_capab_mdt_t));
455 459 ptr += sizeof (dl_capab_mdt_t);
456 460 }
457 461
458 462 ASSERT(ptr == mp->b_rptr + sizeof (dl_capability_ack_t) + subsize);
459 463 qreply(q, mp);
460 464 }
461 465
462 466 static void
463 467 softmac_capability_req(softmac_upper_t *sup, mblk_t *mp)
464 468 {
465 469 dl_capability_req_t *dlp = (dl_capability_req_t *)mp->b_rptr;
466 470 dl_capability_sub_t *sp;
467 471 size_t size, len;
468 472 offset_t off, end;
469 473 t_uscalar_t dl_err;
470 474 queue_t *q = sup->su_wq;
471 475
472 476 ASSERT(sup->su_mode == SOFTMAC_FASTPATH);
473 477 if (MBLKL(mp) < sizeof (dl_capability_req_t)) {
474 478 dl_err = DL_BADPRIM;
475 479 goto failed;
476 480 }
477 481
478 482 if (!sup->su_bound) {
479 483 dl_err = DL_OUTSTATE;
480 484 goto failed;
481 485 }
482 486
483 487 /*
484 488 * This request is overloaded. If there are no requested capabilities
485 489 * then we just want to acknowledge with all the capabilities we
486 490 * support. Otherwise we enable the set of capabilities requested.
487 491 */
488 492 if (dlp->dl_sub_length == 0) {
489 493 softmac_capability_advertise(sup, mp);
490 494 return;
491 495 }
492 496
493 497 if (!MBLKIN(mp, dlp->dl_sub_offset, dlp->dl_sub_length)) {
494 498 dl_err = DL_BADPRIM;
495 499 goto failed;
496 500 }
497 501
498 502 dlp->dl_primitive = DL_CAPABILITY_ACK;
499 503
500 504 off = dlp->dl_sub_offset;
501 505 len = dlp->dl_sub_length;
502 506
503 507 /*
504 508 * Walk the list of capabilities to be enabled.
505 509 */
506 510 for (end = off + len; off < end; ) {
507 511 sp = (dl_capability_sub_t *)(mp->b_rptr + off);
508 512 size = sizeof (dl_capability_sub_t) + sp->dl_length;
509 513
510 514 if (off + size > end ||
511 515 !IS_P2ALIGNED(off, sizeof (uint32_t))) {
512 516 dl_err = DL_BADPRIM;
513 517 goto failed;
514 518 }
515 519
516 520 switch (sp->dl_cap) {
517 521 /*
518 522 * TCP/IP checksum offload to hardware.
519 523 */
520 524 case DL_CAPAB_HCKSUM: {
521 525 dl_capab_hcksum_t *hcksump;
522 526 dl_capab_hcksum_t hcksum;
523 527
524 528 hcksump = (dl_capab_hcksum_t *)&sp[1];
525 529 /*
526 530 * Copy for alignment.
527 531 */
528 532 bcopy(hcksump, &hcksum, sizeof (dl_capab_hcksum_t));
529 533 dlcapabsetqid(&(hcksum.hcksum_mid), sup->su_rq);
530 534 bcopy(&hcksum, hcksump, sizeof (dl_capab_hcksum_t));
531 535 break;
532 536 }
533 537
534 538 default:
535 539 break;
536 540 }
537 541
538 542 off += size;
539 543 }
540 544 qreply(q, mp);
541 545 return;
542 546 failed:
543 547 dlerrorack(q, mp, DL_CAPABILITY_REQ, dl_err, 0);
544 548 }
545 549
546 550 static void
547 551 softmac_bind_req(softmac_upper_t *sup, mblk_t *mp)
548 552 {
549 553 softmac_lower_t *slp = sup->su_slp;
550 554 softmac_t *softmac = sup->su_softmac;
551 555 mblk_t *ackmp, *mp1;
552 556 int err;
553 557
554 558 if (MBLKL(mp) < DL_BIND_REQ_SIZE) {
555 559 freemsg(mp);
556 560 return;
557 561 }
558 562
559 563 /*
560 564 * Allocate ackmp incase the underlying driver does not ack timely.
561 565 */
562 566 if ((mp1 = allocb(sizeof (dl_error_ack_t), BPRI_HI)) == NULL) {
563 567 dlerrorack(sup->su_wq, mp, DL_BIND_REQ, DL_SYSERR, ENOMEM);
564 568 return;
565 569 }
566 570
567 571 err = softmac_output(slp, mp, DL_BIND_REQ, DL_BIND_ACK, &ackmp);
568 572 if (ackmp != NULL) {
569 573 freemsg(mp1);
570 574 } else {
571 575 /*
572 576 * The driver does not ack timely.
573 577 */
574 578 ASSERT(err == ENOMSG);
575 579 ackmp = mp1;
576 580 }
577 581 if (err != 0)
578 582 goto failed;
579 583
580 584 /*
581 585 * Enable capabilities the underlying driver claims to support.
582 586 */
583 587 if ((err = softmac_capab_enable(slp)) != 0)
584 588 goto failed;
585 589
586 590 /*
587 591 * Check whether this softmac is already marked as exclusively used,
588 592 * e.g., an aggregation is created over it. Fail the BIND_REQ if so.
589 593 */
590 594 mutex_enter(&softmac->smac_active_mutex);
591 595 if (softmac->smac_active) {
592 596 mutex_exit(&softmac->smac_active_mutex);
593 597 err = EBUSY;
594 598 goto failed;
595 599 }
596 600 softmac->smac_nactive++;
597 601 sup->su_active = B_TRUE;
598 602 mutex_exit(&softmac->smac_active_mutex);
599 603 sup->su_bound = B_TRUE;
600 604
601 605 qreply(sup->su_wq, ackmp);
602 606 return;
603 607 failed:
604 608 if (err != 0) {
605 609 dlerrorack(sup->su_wq, ackmp, DL_BIND_REQ, DL_SYSERR, err);
606 610 return;
607 611 }
608 612 }
609 613
610 614 static void
611 615 softmac_unbind_req(softmac_upper_t *sup, mblk_t *mp)
612 616 {
613 617 softmac_lower_t *slp = sup->su_slp;
614 618 softmac_t *softmac = sup->su_softmac;
615 619 mblk_t *ackmp, *mp1;
616 620 int err;
617 621
618 622 if (MBLKL(mp) < DL_UNBIND_REQ_SIZE) {
619 623 freemsg(mp);
620 624 return;
621 625 }
622 626
623 627 if (!sup->su_bound) {
624 628 dlerrorack(sup->su_wq, mp, DL_UNBIND_REQ, DL_OUTSTATE, 0);
625 629 return;
626 630 }
627 631
628 632 /*
629 633 * Allocate ackmp incase the underlying driver does not ack timely.
630 634 */
631 635 if ((mp1 = allocb(sizeof (dl_error_ack_t), BPRI_HI)) == NULL) {
632 636 dlerrorack(sup->su_wq, mp, DL_UNBIND_REQ, DL_SYSERR, ENOMEM);
633 637 return;
634 638 }
635 639
636 640 err = softmac_output(slp, mp, DL_UNBIND_REQ, DL_OK_ACK, &ackmp);
637 641 if (ackmp != NULL) {
638 642 freemsg(mp1);
639 643 } else {
640 644 /*
641 645 * The driver does not ack timely.
642 646 */
643 647 ASSERT(err == ENOMSG);
644 648 ackmp = mp1;
645 649 }
646 650 if (err != 0) {
647 651 dlerrorack(sup->su_wq, ackmp, DL_UNBIND_REQ, DL_SYSERR, err);
648 652 return;
649 653 }
650 654
651 655 sup->su_bound = B_FALSE;
652 656
653 657 mutex_enter(&softmac->smac_active_mutex);
654 658 if (sup->su_active) {
655 659 ASSERT(!softmac->smac_active);
656 660 softmac->smac_nactive--;
657 661 sup->su_active = B_FALSE;
658 662 }
659 663 mutex_exit(&softmac->smac_active_mutex);
660 664
661 665 done:
662 666 qreply(sup->su_wq, ackmp);
663 667 }
664 668
665 669 /*
666 670 * Process the non-data mblk.
667 671 */
668 672 static void
669 673 softmac_wput_single_nondata(softmac_upper_t *sup, mblk_t *mp)
670 674 {
671 675 softmac_t *softmac = sup->su_softmac;
672 676 softmac_lower_t *slp = sup->su_slp;
673 677 unsigned char dbtype;
674 678 t_uscalar_t prim;
675 679
676 680 dbtype = DB_TYPE(mp);
677 681 sup->su_is_arp = 0;
678 682 switch (dbtype) {
679 683 case M_CTL:
680 684 sup->su_is_arp = 1;
681 685 /* FALLTHROUGH */
682 686 case M_IOCTL: {
683 687 uint32_t expected_mode;
684 688
685 689 if (((struct iocblk *)(mp->b_rptr))->ioc_cmd != SIOCSLIFNAME)
686 690 break;
687 691
688 692 /*
689 693 * Nak the M_IOCTL based on the STREAMS specification.
690 694 */
691 695 if (dbtype == M_IOCTL)
692 696 miocnak(sup->su_wq, mp, 0, EINVAL);
693 697 else
694 698 freemsg(mp);
695 699
696 700 /*
697 701 * This stream is either IP or ARP. See whether
698 702 * we need to setup a dedicated-lower-stream for it.
699 703 */
700 704 mutex_enter(&softmac->smac_fp_mutex);
701 705
702 706 expected_mode = DATAPATH_MODE(softmac);
703 707 if (expected_mode == SOFTMAC_SLOWPATH)
704 708 sup->su_mode = SOFTMAC_SLOWPATH;
705 709 list_insert_head(&softmac->smac_sup_list, sup);
706 710 mutex_exit(&softmac->smac_fp_mutex);
707 711
708 712 /*
709 713 * Setup the fast-path dedicated lower stream if fast-path
710 714 * is expected. Note that no lock is held here, and if
711 715 * smac_expected_mode is changed from SOFTMAC_FASTPATH to
712 716 * SOFTMAC_SLOWPATH, the DL_NOTE_REPLUMB message used for
713 717 * data-path switching would already be queued and will
714 718 * be processed by softmac_wput_single_nondata() later.
715 719 */
716 720 if (expected_mode == SOFTMAC_FASTPATH)
717 721 (void) softmac_fastpath_setup(sup);
718 722 return;
719 723 }
720 724 case M_PROTO:
721 725 case M_PCPROTO:
722 726 if (MBLKL(mp) < sizeof (t_uscalar_t)) {
723 727 freemsg(mp);
724 728 return;
725 729 }
726 730 prim = ((union DL_primitives *)mp->b_rptr)->dl_primitive;
727 731 switch (prim) {
728 732 case DL_NOTIFY_IND:
729 733 if (MBLKL(mp) < sizeof (dl_notify_ind_t) ||
730 734 ((dl_notify_ind_t *)mp->b_rptr)->dl_notification !=
731 735 DL_NOTE_REPLUMB) {
732 736 freemsg(mp);
733 737 return;
734 738 }
735 739 /*
736 740 * This DL_NOTE_REPLUMB message is initiated
737 741 * and queued by the softmac itself, when the
738 742 * sup is trying to switching its datapath mode
739 743 * between SOFTMAC_SLOWPATH and SOFTMAC_FASTPATH.
740 744 * Send this message upstream.
741 745 */
742 746 qreply(sup->su_wq, mp);
743 747 return;
744 748 case DL_NOTIFY_CONF:
745 749 if (MBLKL(mp) < sizeof (dl_notify_conf_t) ||
746 750 ((dl_notify_conf_t *)mp->b_rptr)->dl_notification !=
747 751 DL_NOTE_REPLUMB_DONE) {
748 752 freemsg(mp);
749 753 return;
750 754 }
751 755 /*
752 756 * This is an indication from IP/ARP that the
753 757 * fastpath->slowpath switch is done.
754 758 */
755 759 freemsg(mp);
756 760 softmac_datapath_switch_done(sup);
↓ open down ↓ |
720 lines elided |
↑ open up ↑ |
757 761 return;
758 762 }
759 763 break;
760 764 }
761 765
762 766 /*
763 767 * No need to hold lock to check su_mode, since su_mode updating only
764 768 * operation is is serialized by softmac_wput_nondata_task().
765 769 */
766 770 if (sup->su_mode != SOFTMAC_FASTPATH) {
767 - dld_wput(sup->su_wq, mp);
771 + (void) dld_wput(sup->su_wq, mp);
768 772 return;
769 773 }
770 774
771 775 /*
772 776 * Fastpath non-data message processing. Most of non-data messages
773 777 * can be directly passed down to the dedicated-lower-stream, aside
774 778 * from the following M_PROTO/M_PCPROTO messages.
775 779 */
776 780 switch (dbtype) {
777 781 case M_PROTO:
778 782 case M_PCPROTO:
779 783 switch (prim) {
780 784 case DL_BIND_REQ:
781 785 softmac_bind_req(sup, mp);
782 786 break;
783 787 case DL_UNBIND_REQ:
784 788 softmac_unbind_req(sup, mp);
785 789 break;
786 790 case DL_CAPABILITY_REQ:
787 791 softmac_capability_req(sup, mp);
788 792 break;
789 793 default:
790 794 putnext(slp->sl_wq, mp);
791 795 break;
792 796 }
793 797 break;
794 798 default:
795 799 putnext(slp->sl_wq, mp);
796 800 break;
797 801 }
798 802 }
799 803
800 804 /*
801 805 * The worker thread which processes non-data messages. Note we only process
802 806 * one message at one time in order to be able to "flush" the queued message
803 807 * and serialize the processing.
804 808 */
805 809 static void
806 810 softmac_wput_nondata_task(void *arg)
807 811 {
808 812 softmac_upper_t *sup = arg;
809 813 mblk_t *mp;
810 814
811 815 mutex_enter(&sup->su_disp_mutex);
812 816
813 817 while (sup->su_pending_head != NULL) {
814 818 if (sup->su_closing)
815 819 break;
816 820
817 821 SOFTMAC_DQ_PENDING(sup, &mp);
818 822 mutex_exit(&sup->su_disp_mutex);
819 823 softmac_wput_single_nondata(sup, mp);
820 824 mutex_enter(&sup->su_disp_mutex);
821 825 }
822 826
823 827 /*
824 828 * If the stream is closing, flush all queued messages and inform
825 829 * the stream to be closed.
826 830 */
827 831 freemsgchain(sup->su_pending_head);
828 832 sup->su_pending_head = sup->su_pending_tail = NULL;
829 833 sup->su_dlpi_pending = B_FALSE;
830 834 cv_signal(&sup->su_disp_cv);
831 835 mutex_exit(&sup->su_disp_mutex);
832 836 }
833 837
834 838 /*
835 839 * Kernel thread to handle taskq dispatch failures in softmac_wput_nondata().
836 840 * This thread is started when the softmac module is first loaded.
837 841 */
838 842 static void
839 843 softmac_taskq_dispatch(void)
840 844 {
841 845 callb_cpr_t cprinfo;
842 846 softmac_upper_t *sup;
843 847
844 848 CALLB_CPR_INIT(&cprinfo, &softmac_taskq_lock, callb_generic_cpr,
845 849 "softmac_taskq_dispatch");
846 850 mutex_enter(&softmac_taskq_lock);
847 851
848 852 while (!softmac_taskq_quit) {
849 853 sup = list_head(&softmac_taskq_list);
850 854 while (sup != NULL) {
851 855 list_remove(&softmac_taskq_list, sup);
852 856 sup->su_taskq_scheduled = B_FALSE;
853 857 mutex_exit(&softmac_taskq_lock);
854 858 VERIFY(taskq_dispatch(system_taskq,
855 859 softmac_wput_nondata_task, sup, TQ_SLEEP) !=
856 860 TASKQID_INVALID);
857 861 mutex_enter(&softmac_taskq_lock);
858 862 sup = list_head(&softmac_taskq_list);
859 863 }
860 864
861 865 CALLB_CPR_SAFE_BEGIN(&cprinfo);
862 866 cv_wait(&softmac_taskq_cv, &softmac_taskq_lock);
863 867 CALLB_CPR_SAFE_END(&cprinfo, &softmac_taskq_lock);
864 868 }
865 869
866 870 softmac_taskq_done = B_TRUE;
867 871 cv_signal(&softmac_taskq_cv);
868 872 CALLB_CPR_EXIT(&cprinfo);
869 873 thread_exit();
870 874 }
871 875
872 876 void
873 877 softmac_wput_nondata(softmac_upper_t *sup, mblk_t *mp)
874 878 {
875 879 /*
876 880 * The processing of the message might block. Enqueue the
877 881 * message for later processing.
878 882 */
879 883 mutex_enter(&sup->su_disp_mutex);
880 884
881 885 if (sup->su_closing) {
882 886 mutex_exit(&sup->su_disp_mutex);
883 887 freemsg(mp);
884 888 return;
885 889 }
886 890
887 891 SOFTMAC_EQ_PENDING(sup, mp);
888 892
889 893 if (sup->su_dlpi_pending) {
890 894 mutex_exit(&sup->su_disp_mutex);
891 895 return;
892 896 }
893 897 sup->su_dlpi_pending = B_TRUE;
894 898 mutex_exit(&sup->su_disp_mutex);
895 899
896 900 if (taskq_dispatch(system_taskq, softmac_wput_nondata_task,
897 901 sup, TQ_NOSLEEP) != TASKQID_INVALID) {
898 902 return;
899 903 }
900 904
901 905 mutex_enter(&softmac_taskq_lock);
902 906 if (!sup->su_taskq_scheduled) {
903 907 list_insert_tail(&softmac_taskq_list, sup);
904 908 cv_signal(&softmac_taskq_cv);
905 909 }
906 910 sup->su_taskq_scheduled = B_TRUE;
907 911 mutex_exit(&softmac_taskq_lock);
908 912 }
909 913
910 914 /*
911 915 * Setup the dedicated-lower-stream (fast-path) for the IP/ARP upperstream.
912 916 */
913 917 static int
914 918 softmac_fastpath_setup(softmac_upper_t *sup)
915 919 {
916 920 softmac_t *softmac = sup->su_softmac;
917 921 softmac_lower_t *slp;
918 922 int err;
919 923
920 924 err = softmac_lower_setup(softmac, sup, &slp);
921 925
922 926 mutex_enter(&sup->su_mutex);
923 927 /*
924 928 * Wait for all data messages to be processed so that we can change
925 929 * the su_mode.
926 930 */
927 931 while (sup->su_tx_inprocess != 0)
928 932 cv_wait(&sup->su_cv, &sup->su_mutex);
929 933
930 934 ASSERT(sup->su_mode != SOFTMAC_FASTPATH);
931 935 ASSERT(sup->su_slp == NULL);
932 936 if (err != 0) {
933 937 sup->su_mode = SOFTMAC_SLOWPATH;
934 938 } else {
935 939 sup->su_slp = slp;
936 940 sup->su_mode = SOFTMAC_FASTPATH;
937 941 }
938 942 mutex_exit(&sup->su_mutex);
939 943 return (err);
940 944 }
941 945
942 946 /*
943 947 * Tear down the dedicated-lower-stream (fast-path) for the IP/ARP upperstream.
944 948 */
945 949 static void
946 950 softmac_fastpath_tear(softmac_upper_t *sup)
947 951 {
948 952 mutex_enter(&sup->su_mutex);
949 953 /*
950 954 * Wait for all data messages in the dedicated-lower-stream
951 955 * to be processed.
952 956 */
953 957 while (sup->su_tx_inprocess != 0)
954 958 cv_wait(&sup->su_cv, &sup->su_mutex);
955 959
956 960 /*
957 961 * Note that this function is called either when the stream is closed,
958 962 * or the stream is unbound (fastpath-slowpath-switch). Therefore,
959 963 * No need to call the tx_notify callback.
960 964 */
961 965 sup->su_tx_notify_func = NULL;
962 966 sup->su_tx_notify_arg = NULL;
963 967 if (sup->su_tx_busy) {
964 968 ASSERT(sup->su_tx_flow_mp == NULL);
965 969 VERIFY((sup->su_tx_flow_mp = getq(sup->su_wq)) != NULL);
966 970 sup->su_tx_busy = B_FALSE;
967 971 }
968 972
969 973 sup->su_mode = SOFTMAC_SLOWPATH;
970 974
971 975 /*
972 976 * Destroy the dedicated-lower-stream. Note that slp is destroyed
973 977 * when lh is closed.
974 978 */
975 979 (void) ldi_close(sup->su_slp->sl_lh, FREAD|FWRITE, kcred);
976 980 sup->su_slp = NULL;
977 981 mutex_exit(&sup->su_mutex);
978 982 }
↓ open down ↓ |
201 lines elided |
↑ open up ↑ |
979 983
980 984 void
981 985 softmac_wput_data(softmac_upper_t *sup, mblk_t *mp)
982 986 {
983 987 /*
984 988 * No lock is required to access the su_mode field since the data
985 989 * traffic is quiesce by IP when the data-path mode is in the
986 990 * process of switching.
987 991 */
988 992 if (sup->su_mode != SOFTMAC_FASTPATH)
989 - dld_wput(sup->su_wq, mp);
993 + (void) dld_wput(sup->su_wq, mp);
990 994 else
991 995 (void) softmac_fastpath_wput_data(sup, mp, NULL, 0);
992 996 }
993 997
994 998 /*ARGSUSED*/
995 999 static mac_tx_cookie_t
996 1000 softmac_fastpath_wput_data(softmac_upper_t *sup, mblk_t *mp, uintptr_t f_hint,
997 1001 uint16_t flag)
998 1002 {
999 1003 queue_t *wq = sup->su_slp->sl_wq;
1000 1004
1001 1005 /*
1002 1006 * This function is called from IP, only the MAC_DROP_ON_NO_DESC
1003 1007 * flag can be specified.
1004 1008 */
1005 1009 ASSERT((flag & ~MAC_DROP_ON_NO_DESC) == 0);
1006 1010 ASSERT(mp->b_next == NULL);
1007 1011
1008 1012 /*
1009 1013 * Check wether the dedicated-lower-stream is able to handle more
1010 1014 * messages, and enable the flow-control if it is not.
1011 1015 *
1012 1016 * Note that in order not to introduce any packet reordering, we
1013 1017 * always send the message down to the dedicated-lower-stream:
1014 1018 *
1015 1019 * If the flow-control is already enabled, but we still get
1016 1020 * the messages from the upper-stream, it means that the upper
1017 1021 * stream does not respect STREAMS flow-control (e.g., TCP). Simply
1018 1022 * pass the message down to the lower-stream in that case.
1019 1023 */
1020 1024 if (SOFTMAC_CANPUTNEXT(wq)) {
1021 1025 putnext(wq, mp);
1022 1026 return (NULL);
1023 1027 }
1024 1028
1025 1029 if (sup->su_tx_busy) {
1026 1030 if ((flag & MAC_DROP_ON_NO_DESC) != 0)
1027 1031 freemsg(mp);
1028 1032 else
1029 1033 putnext(wq, mp);
1030 1034 return ((mac_tx_cookie_t)sup);
1031 1035 }
1032 1036
1033 1037 mutex_enter(&sup->su_mutex);
1034 1038 if (!sup->su_tx_busy) {
1035 1039 /*
1036 1040 * If DLD_CAPAB_DIRECT is enabled, the notify callback will be
1037 1041 * called when the flow control can be disabled. Otherwise,
1038 1042 * put the tx_flow_mp into the wq to make use of the old
1039 1043 * streams flow control.
1040 1044 */
1041 1045 ASSERT(sup->su_tx_flow_mp != NULL);
1042 1046 (void) putq(sup->su_wq, sup->su_tx_flow_mp);
1043 1047 sup->su_tx_flow_mp = NULL;
1044 1048 sup->su_tx_busy = B_TRUE;
1045 1049 qenable(wq);
1046 1050 }
1047 1051 mutex_exit(&sup->su_mutex);
1048 1052
1049 1053 if ((flag & MAC_DROP_ON_NO_DESC) != 0)
1050 1054 freemsg(mp);
1051 1055 else
1052 1056 putnext(wq, mp);
1053 1057 return ((mac_tx_cookie_t)sup);
1054 1058 }
1055 1059
1056 1060 boolean_t
1057 1061 softmac_active_set(void *arg)
1058 1062 {
1059 1063 softmac_t *softmac = arg;
1060 1064
1061 1065 mutex_enter(&softmac->smac_active_mutex);
1062 1066 if (softmac->smac_nactive != 0) {
1063 1067 mutex_exit(&softmac->smac_active_mutex);
1064 1068 return (B_FALSE);
1065 1069 }
1066 1070 softmac->smac_active = B_TRUE;
1067 1071 mutex_exit(&softmac->smac_active_mutex);
1068 1072 return (B_TRUE);
1069 1073 }
1070 1074
1071 1075 void
1072 1076 softmac_active_clear(void *arg)
1073 1077 {
1074 1078 softmac_t *softmac = arg;
1075 1079
1076 1080 mutex_enter(&softmac->smac_active_mutex);
1077 1081 ASSERT(softmac->smac_active && (softmac->smac_nactive == 0));
1078 1082 softmac->smac_active = B_FALSE;
1079 1083 mutex_exit(&softmac->smac_active_mutex);
1080 1084 }
1081 1085
1082 1086 /*
1083 1087 * Disable/reenable fastpath on given softmac. This request could come from a
1084 1088 * MAC client or directly from administrators.
1085 1089 */
1086 1090 int
1087 1091 softmac_datapath_switch(softmac_t *softmac, boolean_t disable, boolean_t admin)
1088 1092 {
1089 1093 softmac_upper_t *sup;
1090 1094 mblk_t *head = NULL, *tail = NULL, *mp;
1091 1095 list_t reqlist;
1092 1096 softmac_switch_req_t *req;
1093 1097 uint32_t current_mode, expected_mode;
1094 1098 int err = 0;
1095 1099
1096 1100 mutex_enter(&softmac->smac_fp_mutex);
1097 1101
1098 1102 current_mode = DATAPATH_MODE(softmac);
1099 1103 if (admin) {
1100 1104 if (softmac->smac_fastpath_admin_disabled == disable) {
1101 1105 mutex_exit(&softmac->smac_fp_mutex);
1102 1106 return (0);
1103 1107 }
1104 1108 softmac->smac_fastpath_admin_disabled = disable;
1105 1109 } else if (disable) {
1106 1110 softmac->smac_fp_disable_clients++;
1107 1111 } else {
1108 1112 ASSERT(softmac->smac_fp_disable_clients != 0);
1109 1113 softmac->smac_fp_disable_clients--;
1110 1114 }
1111 1115
1112 1116 expected_mode = DATAPATH_MODE(softmac);
1113 1117 if (current_mode == expected_mode) {
1114 1118 mutex_exit(&softmac->smac_fp_mutex);
1115 1119 return (0);
1116 1120 }
1117 1121
1118 1122 /*
1119 1123 * The expected mode is different from whatever datapath mode
1120 1124 * this softmac is expected from last request, enqueue the data-path
1121 1125 * switch request.
1122 1126 */
1123 1127 list_create(&reqlist, sizeof (softmac_switch_req_t),
1124 1128 offsetof(softmac_switch_req_t, ssq_req_list_node));
1125 1129
1126 1130 /*
1127 1131 * Allocate all DL_NOTIFY_IND messages and request structures that
1128 1132 * are required to switch each IP/ARP stream to the expected mode.
1129 1133 */
1130 1134 for (sup = list_head(&softmac->smac_sup_list); sup != NULL;
1131 1135 sup = list_next(&softmac->smac_sup_list, sup)) {
1132 1136 dl_notify_ind_t *dlip;
1133 1137
1134 1138 req = kmem_alloc(sizeof (softmac_switch_req_t), KM_NOSLEEP);
1135 1139 if (req == NULL)
1136 1140 break;
1137 1141
1138 1142 req->ssq_expected_mode = expected_mode;
1139 1143 if (sup->su_is_arp) {
1140 1144 list_insert_tail(&reqlist, req);
1141 1145 continue;
1142 1146 }
1143 1147 /*
1144 1148 * Allocate the DL_NOTE_REPLUMB message.
1145 1149 */
1146 1150 if ((mp = allocb(sizeof (dl_notify_ind_t), BPRI_LO)) == NULL) {
1147 1151 kmem_free(req, sizeof (softmac_switch_req_t));
1148 1152 break;
1149 1153 }
1150 1154
1151 1155 list_insert_tail(&reqlist, req);
1152 1156
1153 1157 mp->b_wptr = mp->b_rptr + sizeof (dl_notify_ind_t);
1154 1158 mp->b_datap->db_type = M_PROTO;
1155 1159 bzero(mp->b_rptr, sizeof (dl_notify_ind_t));
1156 1160 dlip = (dl_notify_ind_t *)mp->b_rptr;
1157 1161 dlip->dl_primitive = DL_NOTIFY_IND;
1158 1162 dlip->dl_notification = DL_NOTE_REPLUMB;
1159 1163 if (head == NULL) {
1160 1164 head = tail = mp;
1161 1165 } else {
1162 1166 tail->b_next = mp;
1163 1167 tail = mp;
1164 1168 }
1165 1169 }
1166 1170
1167 1171 /*
1168 1172 * Note that it is fine if the expected data-path mode is fast-path
1169 1173 * and some of streams fails to switch. Only return failure if we
1170 1174 * are expected to switch to the slow-path.
1171 1175 */
1172 1176 if (sup != NULL && expected_mode == SOFTMAC_SLOWPATH) {
1173 1177 err = ENOMEM;
1174 1178 goto fail;
1175 1179 }
1176 1180
1177 1181 /*
1178 1182 * Start switching for each IP/ARP stream. The switching operation
1179 1183 * will eventually succeed and there is no need to wait for it
1180 1184 * to finish.
1181 1185 */
1182 1186 for (sup = list_head(&softmac->smac_sup_list); sup != NULL;
1183 1187 sup = list_next(&softmac->smac_sup_list, sup)) {
1184 1188 if (!sup->su_is_arp) {
1185 1189 mp = head->b_next;
1186 1190 head->b_next = NULL;
1187 1191 softmac_wput_nondata(sup, head);
1188 1192 head = mp;
1189 1193 }
1190 1194 /*
1191 1195 * Add the switch request to the requests list of the stream.
1192 1196 */
1193 1197 req = list_head(&reqlist);
1194 1198 ASSERT(req != NULL);
1195 1199 list_remove(&reqlist, req);
1196 1200 list_insert_tail(&sup->su_req_list, req);
1197 1201 }
1198 1202
1199 1203 mutex_exit(&softmac->smac_fp_mutex);
1200 1204 ASSERT(list_is_empty(&reqlist));
1201 1205 list_destroy(&reqlist);
1202 1206 return (0);
1203 1207 fail:
1204 1208 if (admin) {
1205 1209 softmac->smac_fastpath_admin_disabled = !disable;
1206 1210 } else if (disable) {
1207 1211 softmac->smac_fp_disable_clients--;
1208 1212 } else {
1209 1213 softmac->smac_fp_disable_clients++;
1210 1214 }
1211 1215
1212 1216 mutex_exit(&softmac->smac_fp_mutex);
1213 1217 while ((req = list_head(&reqlist)) != NULL) {
1214 1218 list_remove(&reqlist, req);
1215 1219 kmem_free(req, sizeof (softmac_switch_req_t));
1216 1220 }
1217 1221 freemsgchain(head);
1218 1222 list_destroy(&reqlist);
1219 1223 return (err);
1220 1224 }
1221 1225
1222 1226 int
1223 1227 softmac_fastpath_disable(void *arg)
1224 1228 {
1225 1229 return (softmac_datapath_switch((softmac_t *)arg, B_TRUE, B_FALSE));
1226 1230 }
1227 1231
1228 1232 void
1229 1233 softmac_fastpath_enable(void *arg)
1230 1234 {
1231 1235 VERIFY(softmac_datapath_switch((softmac_t *)arg, B_FALSE,
1232 1236 B_FALSE) == 0);
1233 1237 }
1234 1238
1235 1239 void
1236 1240 softmac_upperstream_close(softmac_upper_t *sup)
1237 1241 {
1238 1242 softmac_t *softmac = sup->su_softmac;
1239 1243 softmac_switch_req_t *req;
1240 1244
1241 1245 mutex_enter(&softmac->smac_fp_mutex);
1242 1246
1243 1247 if (sup->su_mode == SOFTMAC_FASTPATH)
1244 1248 softmac_fastpath_tear(sup);
1245 1249
1246 1250 if (sup->su_mode != SOFTMAC_UNKNOWN) {
1247 1251 list_remove(&softmac->smac_sup_list, sup);
1248 1252 sup->su_mode = SOFTMAC_UNKNOWN;
1249 1253 }
1250 1254
1251 1255 /*
1252 1256 * Cleanup all the switch requests queueed on this stream.
1253 1257 */
1254 1258 while ((req = list_head(&sup->su_req_list)) != NULL) {
1255 1259 list_remove(&sup->su_req_list, req);
1256 1260 kmem_free(req, sizeof (softmac_switch_req_t));
1257 1261 }
1258 1262 mutex_exit(&softmac->smac_fp_mutex);
1259 1263 }
1260 1264
1261 1265 /*
1262 1266 * Handle the DL_NOTE_REPLUMB_DONE indication from IP/ARP. Change the upper
1263 1267 * stream from the fastpath mode to the slowpath mode.
1264 1268 */
1265 1269 static void
1266 1270 softmac_datapath_switch_done(softmac_upper_t *sup)
1267 1271 {
1268 1272 softmac_t *softmac = sup->su_softmac;
1269 1273 softmac_switch_req_t *req;
1270 1274 uint32_t expected_mode;
1271 1275
1272 1276 mutex_enter(&softmac->smac_fp_mutex);
1273 1277 req = list_head(&sup->su_req_list);
1274 1278 list_remove(&sup->su_req_list, req);
1275 1279 expected_mode = req->ssq_expected_mode;
1276 1280 kmem_free(req, sizeof (softmac_switch_req_t));
1277 1281
1278 1282 if (expected_mode == sup->su_mode) {
1279 1283 mutex_exit(&softmac->smac_fp_mutex);
1280 1284 return;
1281 1285 }
1282 1286
1283 1287 ASSERT(!sup->su_bound);
1284 1288 mutex_exit(&softmac->smac_fp_mutex);
1285 1289
1286 1290 /*
1287 1291 * It is fine if the expected mode is fast-path and we fail
1288 1292 * to enable fastpath on this stream.
1289 1293 */
1290 1294 if (expected_mode == SOFTMAC_SLOWPATH)
1291 1295 softmac_fastpath_tear(sup);
1292 1296 else
1293 1297 (void) softmac_fastpath_setup(sup);
1294 1298 }
↓ open down ↓ |
295 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX