190 mutex_exit(&mux->omux_lock);
191 OVERLAY_FREEMSG(mp, "dev dropped");
192 freemsg(mp);
193 continue;
194 }
195 overlay_io_start(odd, OVERLAY_F_IN_RX);
196 mutex_exit(&odd->odd_lock);
197 mutex_exit(&mux->omux_lock);
198
199 mac_rx(odd->odd_mh, NULL, mp);
200
201 mutex_enter(&odd->odd_lock);
202 overlay_io_done(odd, OVERLAY_F_IN_RX);
203 mutex_exit(&odd->odd_lock);
204 }
205
206 return (B_TRUE);
207 }
208
209 /*
210 * Register a given device with a socket backend. If no such device socket
211 * exists, create a new one.
212 */
213 overlay_mux_t *
214 overlay_mux_open(overlay_plugin_t *opp, int domain, int family, int protocol,
215 struct sockaddr *addr, socklen_t len, int *errp)
216 {
217 int err;
218 overlay_mux_t *mux;
219 ksocket_t ksock;
220
221 if (errp == NULL)
222 errp = &err;
223
224 mutex_enter(&overlay_mux_lock);
225 for (mux = list_head(&overlay_mux_list); mux != NULL;
226 mux = list_next(&overlay_mux_list, mux)) {
227 if (domain == mux->omux_domain &&
228 family == mux->omux_family &&
229 protocol == mux->omux_protocol &&
230 len == mux->omux_alen &&
231 bcmp(addr, mux->omux_addr, len) == 0) {
232
233 if (opp != mux->omux_plugin) {
234 *errp = EEXIST;
235 return (NULL);
236 }
237
238 mutex_enter(&mux->omux_lock);
239 mux->omux_count++;
273 mutex_exit(&overlay_mux_lock);
274 ksocket_close(ksock, kcred);
275 return (NULL);
276 }
277
278 mux = kmem_alloc(sizeof (overlay_mux_t), KM_SLEEP);
279 list_link_init(&mux->omux_lnode);
280 mux->omux_ksock = ksock;
281 mux->omux_plugin = opp;
282 mux->omux_domain = domain;
283 mux->omux_family = family;
284 mux->omux_protocol = protocol;
285 mux->omux_addr = kmem_alloc(len, KM_SLEEP);
286 bcopy(addr, mux->omux_addr, len);
287 mux->omux_alen = len;
288 mux->omux_count = 1;
289 avl_create(&mux->omux_devices, overlay_mux_comparator,
290 sizeof (overlay_dev_t), offsetof(overlay_dev_t, odd_muxnode));
291 mutex_init(&mux->omux_lock, NULL, MUTEX_DRIVER, NULL);
292
293
294 /* Once this is called, we need to expect to rx data */
295 *errp = ksocket_krecv_set(ksock, overlay_mux_recv, mux);
296 if (*errp != 0) {
297 ksocket_close(ksock, kcred);
298 mutex_destroy(&mux->omux_lock);
299 avl_destroy(&mux->omux_devices);
300 kmem_free(mux->omux_addr, len);
301 kmem_free(mux, sizeof (overlay_mux_t));
302 return (NULL);
303 }
304
305 list_insert_tail(&overlay_mux_list, mux);
306 mutex_exit(&overlay_mux_lock);
307
308 *errp = 0;
309 return (mux);
310 }
311
312 void
313 overlay_mux_close(overlay_mux_t *mux)
337 avl_add(&mux->omux_devices, odd);
338 mutex_exit(&mux->omux_lock);
339 }
340
341 void
342 overlay_mux_remove_dev(overlay_mux_t *mux, overlay_dev_t *odd)
343 {
344 mutex_enter(&mux->omux_lock);
345 avl_remove(&mux->omux_devices, odd);
346 mutex_exit(&mux->omux_lock);
347 }
348
349 int
350 overlay_mux_tx(overlay_mux_t *mux, struct msghdr *hdr, mblk_t *mp)
351 {
352 int ret;
353
354 /*
355 * It'd be nice to be able to use MSG_MBLK_QUICKRELE, unfortunately,
356 * that isn't actually supported by UDP at this time.
357 */
358 ret = ksocket_sendmblk(mux->omux_ksock, hdr, 0, &mp, kcred);
359 if (ret != 0)
360 freemsg(mp);
361
362 return (ret);
363 }
|
190 mutex_exit(&mux->omux_lock);
191 OVERLAY_FREEMSG(mp, "dev dropped");
192 freemsg(mp);
193 continue;
194 }
195 overlay_io_start(odd, OVERLAY_F_IN_RX);
196 mutex_exit(&odd->odd_lock);
197 mutex_exit(&mux->omux_lock);
198
199 mac_rx(odd->odd_mh, NULL, mp);
200
201 mutex_enter(&odd->odd_lock);
202 overlay_io_done(odd, OVERLAY_F_IN_RX);
203 mutex_exit(&odd->odd_lock);
204 }
205
206 return (B_TRUE);
207 }
208
209 /*
210 * Kernel socket callback to indicate the socket itself is able to send
211 * data again. Check for devices on this mux that were send-blocked,
212 * and clear them.
213 */
214 /* ARGSUSED */
215 static void
216 overlay_mux_cansend_now(ksocket_t ksock, ksocket_callback_event_t event,
217 void *arg, uintptr_t ignore_me)
218 {
219 overlay_mux_t *mux = (overlay_mux_t *)arg;
220 overlay_dev_t *odd;
221 mac_handle_t *mhs_to_update, *current_mh;
222 size_t allocsize;
223
224 ASSERT3P(ksock, ==, mux->omux_ksock);
225 ASSERT3U(event, ==, KSOCKET_EV_CANSEND);
226
227 /* Traverse omux_devices and check for ones marked as send-blocked. */
228 mutex_enter(&mux->omux_lock);
229 if (mux->omux_count == 0) {
230 /* Nothing to wake up. */
231 mutex_exit(&mux->omux_lock);
232 return;
233 }
234 allocsize = sizeof (mac_handle_t) * mux->omux_count;
235 mhs_to_update = kmem_zalloc(allocsize, KM_NOSLEEP);
236 VERIFY(mhs_to_update != NULL); /* Failure should be rare. */
237 current_mh = mhs_to_update;
238
239 for (odd = avl_first(&mux->omux_devices); odd != NULL;
240 odd = AVL_NEXT(&mux->omux_devices, odd)) {
241 mac_handle_t odd_mh = NULL;
242
243 mutex_enter(&odd->odd_lock);
244 if ((odd->odd_flags & OVERLAY_F_TXSTOPPED) != 0) {
245 /* Get ready to tell MAC it can transmit again. */
246 odd->odd_flags &= ~OVERLAY_F_TXSTOPPED;
247 odd_mh = odd->odd_mh;
248 }
249 mutex_exit(&odd->odd_lock);
250 if (odd_mh != NULL) {
251 *current_mh = odd_mh;
252 current_mh++;
253 }
254 }
255 mutex_exit(&mux->omux_lock);
256
257 /*
258 * Yes, I'm using the value-then-decrement. "current_mh" is
259 * guaranteed to be at least one ahead of mhs_to_update if there are
260 * any mac handles that need updating. I also have to do this outside
261 * the omux lock because the tx_update may trigger immediate or
262 * concurrent packet transmission.
263 */
264 while (current_mh-- != mhs_to_update)
265 mac_tx_update(*current_mh);
266
267 kmem_free(mhs_to_update, allocsize);
268 }
269
270 /*
271 * Register a given device with a socket backend. If no such device socket
272 * exists, create a new one.
273 */
274 overlay_mux_t *
275 overlay_mux_open(overlay_plugin_t *opp, int domain, int family, int protocol,
276 struct sockaddr *addr, socklen_t len, int *errp)
277 {
278 int err;
279 overlay_mux_t *mux;
280 ksocket_t ksock;
281 ksocket_callbacks_t ks_cb = { 0 };
282
283 if (errp == NULL)
284 errp = &err;
285
286 mutex_enter(&overlay_mux_lock);
287 for (mux = list_head(&overlay_mux_list); mux != NULL;
288 mux = list_next(&overlay_mux_list, mux)) {
289 if (domain == mux->omux_domain &&
290 family == mux->omux_family &&
291 protocol == mux->omux_protocol &&
292 len == mux->omux_alen &&
293 bcmp(addr, mux->omux_addr, len) == 0) {
294
295 if (opp != mux->omux_plugin) {
296 *errp = EEXIST;
297 return (NULL);
298 }
299
300 mutex_enter(&mux->omux_lock);
301 mux->omux_count++;
335 mutex_exit(&overlay_mux_lock);
336 ksocket_close(ksock, kcred);
337 return (NULL);
338 }
339
340 mux = kmem_alloc(sizeof (overlay_mux_t), KM_SLEEP);
341 list_link_init(&mux->omux_lnode);
342 mux->omux_ksock = ksock;
343 mux->omux_plugin = opp;
344 mux->omux_domain = domain;
345 mux->omux_family = family;
346 mux->omux_protocol = protocol;
347 mux->omux_addr = kmem_alloc(len, KM_SLEEP);
348 bcopy(addr, mux->omux_addr, len);
349 mux->omux_alen = len;
350 mux->omux_count = 1;
351 avl_create(&mux->omux_devices, overlay_mux_comparator,
352 sizeof (overlay_dev_t), offsetof(overlay_dev_t, odd_muxnode));
353 mutex_init(&mux->omux_lock, NULL, MUTEX_DRIVER, NULL);
354
355 #if defined(OVERLAY_PINCH) || defined(OVERLAY_FC_TEST)
356 /* Set the xmit buf to a REALLY SMALL value, say 12k (1-3 packets) */
357 int bufsize = 12 * 1024;
358
359 if (ksocket_setsockopt(ksock, SOL_SOCKET, SO_SNDBUF,
360 (const void *)&bufsize, sizeof (bufsize), CRED()) != 0) {
361 ksocket_close(ksock, kcred);
362 mutex_destroy(&mux->omux_lock);
363 avl_destroy(&mux->omux_devices);
364 kmem_free(mux->omux_addr, len);
365 kmem_free(mux, sizeof (overlay_mux_t));
366 return (NULL);
367 }
368 #endif
369 /*
370 * Set a callback in case we hit socket flow control and need to know
371 * when it's ready to send again. See the aforementioned
372 * ksocket_socket() comments about the use of kcred vs. being
373 * zone-aware.
374 */
375 ks_cb.ksock_cb_cansend = overlay_mux_cansend_now;
376 if (ksocket_setcallbacks(ksock, &ks_cb, mux, kcred) != 0) {
377 ksocket_close(ksock, kcred);
378 mutex_destroy(&mux->omux_lock);
379 avl_destroy(&mux->omux_devices);
380 kmem_free(mux->omux_addr, len);
381 kmem_free(mux, sizeof (overlay_mux_t));
382 return (NULL);
383 }
384
385 /* Once this is called, we need to expect to rx data */
386 *errp = ksocket_krecv_set(ksock, overlay_mux_recv, mux);
387 if (*errp != 0) {
388 ksocket_close(ksock, kcred);
389 mutex_destroy(&mux->omux_lock);
390 avl_destroy(&mux->omux_devices);
391 kmem_free(mux->omux_addr, len);
392 kmem_free(mux, sizeof (overlay_mux_t));
393 return (NULL);
394 }
395
396 list_insert_tail(&overlay_mux_list, mux);
397 mutex_exit(&overlay_mux_lock);
398
399 *errp = 0;
400 return (mux);
401 }
402
403 void
404 overlay_mux_close(overlay_mux_t *mux)
428 avl_add(&mux->omux_devices, odd);
429 mutex_exit(&mux->omux_lock);
430 }
431
432 void
433 overlay_mux_remove_dev(overlay_mux_t *mux, overlay_dev_t *odd)
434 {
435 mutex_enter(&mux->omux_lock);
436 avl_remove(&mux->omux_devices, odd);
437 mutex_exit(&mux->omux_lock);
438 }
439
440 int
441 overlay_mux_tx(overlay_mux_t *mux, struct msghdr *hdr, mblk_t *mp)
442 {
443 int ret;
444
445 /*
446 * It'd be nice to be able to use MSG_MBLK_QUICKRELE, unfortunately,
447 * that isn't actually supported by UDP at this time.
448 *
449 * Send with MSG_DONTWAIT to indicate clogged UDP sockets upstack.
450 */
451 ret = ksocket_sendmblk(mux->omux_ksock, hdr, MSG_DONTWAIT, &mp, kcred);
452 /*
453 * NOTE: ksocket_sendmblk() may send partial packets downstack,
454 * returning what's not sent in &mp (i.e. mp pre-call might be a
455 * b_cont of mp post-call). We can't hold up this message (it's a
456 * datagram), so we drop, and let the caller cope.
457 */
458 if (ret != 0)
459 freemsg(mp);
460
461 return (ret);
462 }
|