xref: /illumos-gate/usr/src/uts/intel/io/viona/viona_rx.c (revision a4955f4fa65e38d70c07d38e657a9aff43fa155f)
1 /*
2  * Copyright (c) 2013  Chris Torek <torek @ torek net>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26 /*
27  * This file and its contents are supplied under the terms of the
28  * Common Development and Distribution License ("CDDL"), version 1.0.
29  * You may only use this file in accordance with the terms of version
30  * 1.0 of the CDDL.
31  *
32  * A full copy of the text of the CDDL should have accompanied this
33  * source.  A copy of the CDDL is also available via the Internet at
34  * http://www.illumos.org/license/CDDL.
35  *
36  * Copyright 2015 Pluribus Networks Inc.
37  * Copyright 2019 Joyent, Inc.
38  * Copyright 2022 Oxide Computer Company
39  * Copyright 2022 Michael Zeller
40  */
41 
42 #include <sys/types.h>
43 #include <sys/strsubr.h>
44 
45 #include <sys/dlpi.h>
46 #include <sys/pattr.h>
47 #include <sys/vlan.h>
48 
49 #include "viona_impl.h"
50 
51 
52 
53 #define	VTNET_MAXSEGS		32
54 
55 /* Min. octets in an ethernet frame minus FCS */
56 #define	MIN_BUF_SIZE		60
57 #define	NEED_VLAN_PAD_SIZE	(MIN_BUF_SIZE - VLAN_TAGSZ)
58 
59 static mblk_t *viona_vlan_pad_mp;
60 
61 void
62 viona_rx_init(void)
63 {
64 	mblk_t *mp;
65 
66 	ASSERT(viona_vlan_pad_mp == NULL);
67 
68 	/* Create mblk for padding when VLAN tags are stripped */
69 	mp = allocb_wait(VLAN_TAGSZ, BPRI_HI, STR_NOSIG, NULL);
70 	bzero(mp->b_rptr, VLAN_TAGSZ);
71 	mp->b_wptr += VLAN_TAGSZ;
72 	viona_vlan_pad_mp = mp;
73 }
74 
75 void
76 viona_rx_fini(void)
77 {
78 	mblk_t *mp;
79 
80 	/* Clean up the VLAN padding mblk */
81 	mp = viona_vlan_pad_mp;
82 	viona_vlan_pad_mp = NULL;
83 	VERIFY(mp != NULL && mp->b_cont == NULL);
84 	freemsg(mp);
85 }
86 
87 void
88 viona_worker_rx(viona_vring_t *ring, viona_link_t *link)
89 {
90 	(void) thread_vsetname(curthread, "viona_rx_%p", ring);
91 
92 	ASSERT(MUTEX_HELD(&ring->vr_lock));
93 	ASSERT3U(ring->vr_state, ==, VRS_RUN);
94 
95 	viona_ring_disable_notify(ring);
96 
97 	do {
98 		if (vmm_drv_lease_expired(ring->vr_lease)) {
99 			/*
100 			 * Set the renewal flag, causing incoming traffic to be
101 			 * dropped, and issue an RX barrier to ensure any
102 			 * threads in the RX callbacks will have finished.
103 			 * The vr_lock cannot be held across the barrier as it
104 			 * poses a deadlock risk.
105 			 */
106 			ring->vr_state_flags |= VRSF_RENEW;
107 			mutex_exit(&ring->vr_lock);
108 			mac_rx_barrier(link->l_mch);
109 			mutex_enter(&ring->vr_lock);
110 
111 			if (!viona_ring_lease_renew(ring)) {
112 				break;
113 			}
114 			ring->vr_state_flags &= ~VRSF_RENEW;
115 		}
116 
117 		/*
118 		 * For now, there is little to do in the RX worker as inbound
119 		 * data is delivered by MAC via the RX callbacks.  If tap-like
120 		 * functionality is added later, this would be a convenient
121 		 * place to inject frames into the guest.
122 		 */
123 		(void) cv_wait_sig(&ring->vr_cv, &ring->vr_lock);
124 	} while (!vring_need_bail(ring));
125 
126 	ring->vr_state = VRS_STOP;
127 
128 	/*
129 	 * The RX ring is stopping, before we start tearing it down it
130 	 * is imperative that we perform an RX barrier so that
131 	 * incoming packets are dropped at viona_rx_classified().
132 	 */
133 	mutex_exit(&ring->vr_lock);
134 	mac_rx_barrier(link->l_mch);
135 	mutex_enter(&ring->vr_lock);
136 
137 	/*
138 	 * If we bailed while renewing the ring lease, we cannot reset
139 	 * USED_NO_NOTIFY, since we lack a valid mapping to do so.
140 	 */
141 	if (ring->vr_lease != NULL) {
142 		viona_ring_enable_notify(ring);
143 	}
144 }
145 
146 static size_t
147 viona_copy_mblk(const mblk_t *mp, size_t seek, caddr_t buf, size_t len,
148     boolean_t *end)
149 {
150 	size_t copied = 0;
151 	size_t off = 0;
152 
153 	/* Seek past already-consumed data */
154 	while (seek > 0 && mp != NULL) {
155 		const size_t chunk = MBLKL(mp);
156 
157 		if (chunk > seek) {
158 			off = seek;
159 			break;
160 		}
161 		mp = mp->b_cont;
162 		seek -= chunk;
163 	}
164 
165 	while (mp != NULL) {
166 		const size_t chunk = MBLKL(mp) - off;
167 		const size_t to_copy = MIN(chunk, len);
168 
169 		bcopy(mp->b_rptr + off, buf, to_copy);
170 		copied += to_copy;
171 		buf += to_copy;
172 		len -= to_copy;
173 
174 		/*
175 		 * If all the remaining data in the mblk_t was copied, move on
176 		 * to the next one in the chain.  Any seek offset applied to
177 		 * the first mblk copy is zeroed out for subsequent operations.
178 		 */
179 		if (chunk == to_copy) {
180 			mp = mp->b_cont;
181 			off = 0;
182 		}
183 #ifdef DEBUG
184 		else {
185 			/*
186 			 * The only valid reason for the copy to consume less
187 			 * than the entire contents of the mblk_t is because
188 			 * the output buffer has been filled.
189 			 */
190 			ASSERT0(len);
191 		}
192 #endif
193 
194 		/* Go no further if the buffer has been filled */
195 		if (len == 0) {
196 			break;
197 		}
198 
199 	}
200 	*end = (mp == NULL);
201 	return (copied);
202 }
203 
204 static int
205 viona_recv_plain(viona_vring_t *ring, const mblk_t *mp, size_t msz)
206 {
207 	struct iovec iov[VTNET_MAXSEGS];
208 	uint16_t cookie;
209 	int n;
210 	const size_t hdr_sz = sizeof (struct virtio_net_hdr);
211 	struct virtio_net_hdr *hdr;
212 	size_t len, copied = 0;
213 	caddr_t buf = NULL;
214 	boolean_t end = B_FALSE;
215 	const uint32_t features = ring->vr_link->l_features;
216 	vmm_page_t *pages = NULL;
217 
218 	ASSERT(msz >= MIN_BUF_SIZE);
219 
220 	n = vq_popchain(ring, iov, VTNET_MAXSEGS, &cookie, &pages);
221 	if (n <= 0) {
222 		/* Without available buffers, the frame must be dropped. */
223 		return (ENOSPC);
224 	}
225 	if (iov[0].iov_len < hdr_sz) {
226 		/*
227 		 * There is little to do if there is not even space available
228 		 * for the sole header.  Zero the buffer and bail out as a last
229 		 * act of desperation.
230 		 */
231 		bzero(iov[0].iov_base, iov[0].iov_len);
232 		goto bad_frame;
233 	}
234 
235 	/* Grab the address of the header before anything else */
236 	hdr = (struct virtio_net_hdr *)iov[0].iov_base;
237 
238 	/*
239 	 * If there is any space remaining in the first buffer after writing
240 	 * the header, fill it with frame data.
241 	 */
242 	if (iov[0].iov_len > hdr_sz) {
243 		buf = (caddr_t)iov[0].iov_base + hdr_sz;
244 		len = iov[0].iov_len - hdr_sz;
245 
246 		copied += viona_copy_mblk(mp, copied, buf, len, &end);
247 	}
248 
249 	/* Copy any remaining data into subsequent buffers, if present */
250 	for (int i = 1; i < n && !end; i++) {
251 		buf = (caddr_t)iov[i].iov_base;
252 		len = iov[i].iov_len;
253 
254 		copied += viona_copy_mblk(mp, copied, buf, len, &end);
255 	}
256 
257 	/* Was the expected amount of data copied? */
258 	if (copied != msz) {
259 		VIONA_PROBE5(too_short, viona_vring_t *, ring,
260 		    uint16_t, cookie, mblk_t *, mp, size_t, copied,
261 		    size_t, msz);
262 		VIONA_RING_STAT_INCR(ring, too_short);
263 		goto bad_frame;
264 	}
265 
266 	/* Populate (read: zero) the header and account for it in the size */
267 	bzero(hdr, hdr_sz);
268 	copied += hdr_sz;
269 
270 	/* Add chksum bits, if needed */
271 	if ((features & VIRTIO_NET_F_GUEST_CSUM) != 0) {
272 		uint32_t cksum_flags;
273 
274 		if (((features & VIRTIO_NET_F_GUEST_TSO4) != 0) &&
275 		    ((DB_CKSUMFLAGS(mp) & HW_LSO) != 0)) {
276 			hdr->vrh_gso_type |= VIRTIO_NET_HDR_GSO_TCPV4;
277 			hdr->vrh_gso_size = DB_LSOMSS(mp);
278 		}
279 
280 		mac_hcksum_get((mblk_t *)mp, NULL, NULL, NULL, NULL,
281 		    &cksum_flags);
282 		if ((cksum_flags & HCK_FULLCKSUM_OK) != 0) {
283 			hdr->vrh_flags |= VIRTIO_NET_HDR_F_DATA_VALID;
284 		}
285 	}
286 
287 	/* Release this chain */
288 	vmm_drv_page_release_chain(pages);
289 	vq_pushchain(ring, copied, cookie);
290 	return (0);
291 
292 bad_frame:
293 	VIONA_PROBE3(bad_rx_frame, viona_vring_t *, ring, uint16_t, cookie,
294 	    mblk_t *, mp);
295 	VIONA_RING_STAT_INCR(ring, bad_rx_frame);
296 
297 	vmm_drv_page_release_chain(pages);
298 	vq_pushchain(ring, MAX(copied, MIN_BUF_SIZE + hdr_sz), cookie);
299 	return (EINVAL);
300 }
301 
302 static int
303 viona_recv_merged(viona_vring_t *ring, const mblk_t *mp, size_t msz)
304 {
305 	struct iovec iov[VTNET_MAXSEGS];
306 	used_elem_t uelem[VTNET_MAXSEGS];
307 	vmm_page_t *pages = NULL, *hdr_pages = NULL;
308 	int n, i = 0, buf_idx = 0, err = 0;
309 	uint16_t cookie;
310 	caddr_t buf;
311 	size_t len, copied = 0, chunk = 0;
312 	struct virtio_net_mrgrxhdr *hdr = NULL;
313 	const size_t hdr_sz = sizeof (struct virtio_net_mrgrxhdr);
314 	boolean_t end = B_FALSE;
315 	const uint32_t features = ring->vr_link->l_features;
316 
317 	ASSERT(msz >= MIN_BUF_SIZE);
318 
319 	n = vq_popchain(ring, iov, VTNET_MAXSEGS, &cookie, &hdr_pages);
320 	if (n <= 0) {
321 		/* Without available buffers, the frame must be dropped. */
322 		VIONA_PROBE2(no_space, viona_vring_t *, ring, mblk_t *, mp);
323 		VIONA_RING_STAT_INCR(ring, no_space);
324 		return (ENOSPC);
325 	}
326 	if (iov[0].iov_len < hdr_sz) {
327 		/*
328 		 * There is little to do if there is not even space available
329 		 * for the sole header.  Zero the buffer and bail out as a last
330 		 * act of desperation.
331 		 */
332 		bzero(iov[0].iov_base, iov[0].iov_len);
333 		uelem[0].id = cookie;
334 		uelem[0].len = iov[0].iov_len;
335 		err = EINVAL;
336 		goto done;
337 	}
338 
339 	/* Grab the address of the header and do initial population */
340 	hdr = (struct virtio_net_mrgrxhdr *)iov[0].iov_base;
341 	bzero(hdr, hdr_sz);
342 	hdr->vrh_bufs = 1;
343 
344 	/*
345 	 * If there is any space remaining in the first buffer after writing
346 	 * the header, fill it with frame data.  The size of the header itself
347 	 * is accounted for later.
348 	 */
349 	if (iov[0].iov_len > hdr_sz) {
350 		buf = iov[0].iov_base + hdr_sz;
351 		len = iov[0].iov_len - hdr_sz;
352 
353 		size_t copy_len;
354 		copy_len = viona_copy_mblk(mp, copied, buf, len, &end);
355 		chunk += copy_len;
356 		copied += copy_len;
357 	}
358 	i = 1;
359 
360 	do {
361 		while (i < n && !end) {
362 			buf = iov[i].iov_base;
363 			len = iov[i].iov_len;
364 
365 			size_t copy_len;
366 			copy_len = viona_copy_mblk(mp, copied, buf, len, &end);
367 			chunk += copy_len;
368 			copied += copy_len;
369 			i++;
370 		}
371 
372 		uelem[buf_idx].id = cookie;
373 		uelem[buf_idx].len = chunk;
374 
375 		/*
376 		 * Try to grab another buffer from the ring if the mblk has not
377 		 * yet been entirely copied out.
378 		 */
379 		if (!end) {
380 			if (buf_idx == (VTNET_MAXSEGS - 1)) {
381 				/*
382 				 * Our arbitrary limit on the number of buffers
383 				 * to offer for merge has already been reached.
384 				 */
385 				err = EOVERFLOW;
386 				break;
387 			}
388 			if (pages != NULL) {
389 				vmm_drv_page_release_chain(pages);
390 				pages = NULL;
391 			}
392 			n = vq_popchain(ring, iov, VTNET_MAXSEGS, &cookie,
393 			    &pages);
394 			if (n <= 0) {
395 				/*
396 				 * Without more immediate space to perform the
397 				 * copying, there is little choice left but to
398 				 * drop the packet.
399 				 */
400 				err = EMSGSIZE;
401 				break;
402 			}
403 			chunk = 0;
404 			i = 0;
405 			buf_idx++;
406 			/*
407 			 * Keep the header up-to-date with the number of
408 			 * buffers, but never reference its value since the
409 			 * guest could meddle with it.
410 			 */
411 			hdr->vrh_bufs++;
412 		}
413 	} while (!end && copied < msz);
414 
415 	/* Account for the header size in the first buffer */
416 	uelem[0].len += hdr_sz;
417 
418 	/*
419 	 * If no other errors were encounted during the copy, was the expected
420 	 * amount of data transfered?
421 	 */
422 	if (err == 0 && copied != msz) {
423 		VIONA_PROBE5(too_short, viona_vring_t *, ring,
424 		    uint16_t, cookie, mblk_t *, mp, size_t, copied,
425 		    size_t, msz);
426 		VIONA_RING_STAT_INCR(ring, too_short);
427 		err = EINVAL;
428 	}
429 
430 	/* Add chksum bits, if needed */
431 	if ((features & VIRTIO_NET_F_GUEST_CSUM) != 0) {
432 		uint32_t cksum_flags;
433 
434 		if (((features & VIRTIO_NET_F_GUEST_TSO4) != 0) &&
435 		    ((DB_CKSUMFLAGS(mp) & HW_LSO) != 0)) {
436 			hdr->vrh_gso_type |= VIRTIO_NET_HDR_GSO_TCPV4;
437 			hdr->vrh_gso_size = DB_LSOMSS(mp);
438 		}
439 
440 		mac_hcksum_get((mblk_t *)mp, NULL, NULL, NULL, NULL,
441 		    &cksum_flags);
442 		if ((cksum_flags & HCK_FULLCKSUM_OK) != 0) {
443 			hdr->vrh_flags |= VIRTIO_NET_HDR_F_DATA_VALID;
444 		}
445 	}
446 
447 done:
448 	switch (err) {
449 	case 0:
450 		/* Success can fall right through to ring delivery */
451 		break;
452 
453 	case EMSGSIZE:
454 		VIONA_PROBE3(rx_merge_underrun, viona_vring_t *, ring,
455 		    uint16_t, cookie, mblk_t *, mp);
456 		VIONA_RING_STAT_INCR(ring, rx_merge_underrun);
457 		break;
458 
459 	case EOVERFLOW:
460 		VIONA_PROBE3(rx_merge_overrun, viona_vring_t *, ring,
461 		    uint16_t, cookie, mblk_t *, mp);
462 		VIONA_RING_STAT_INCR(ring, rx_merge_overrun);
463 		break;
464 
465 	default:
466 		VIONA_PROBE3(bad_rx_frame, viona_vring_t *, ring,
467 		    uint16_t, cookie, mblk_t *, mp);
468 		VIONA_RING_STAT_INCR(ring, bad_rx_frame);
469 	}
470 
471 	if (hdr_pages != NULL) {
472 		vmm_drv_page_release_chain(hdr_pages);
473 	}
474 	if (pages != NULL) {
475 		vmm_drv_page_release_chain(pages);
476 	}
477 	vq_pushchain_many(ring, buf_idx + 1, uelem);
478 	return (err);
479 }
480 
481 static void
482 viona_rx_common(viona_vring_t *ring, mblk_t *mp, boolean_t is_loopback)
483 {
484 	viona_link_t *link = ring->vr_link;
485 	mblk_t *mprx = NULL, **mprx_prevp = &mprx;
486 	mblk_t *mpdrop = NULL, **mpdrop_prevp = &mpdrop;
487 	const boolean_t do_merge =
488 	    ((link->l_features & VIRTIO_NET_F_MRG_RXBUF) != 0);
489 
490 	size_t nrx = 0, ndrop = 0;
491 
492 	while (mp != NULL) {
493 		mblk_t *next = mp->b_next;
494 		mblk_t *pad = NULL;
495 		size_t size = msgsize(mp);
496 		int err = 0;
497 
498 		mp->b_next = NULL;
499 
500 		/*
501 		 * We treat both a 'drop' response and errors the same here
502 		 * and put the packet on the drop chain.  As packets may be
503 		 * subject to different actions in ipf (which do not all
504 		 * return the same set of error values), an error processing
505 		 * one packet doesn't mean the next packet will also generate
506 		 * an error.
507 		 */
508 		if (VNETHOOK_INTERESTED_IN(link->l_neti) &&
509 		    viona_hook(link, ring, &mp, B_FALSE) != 0) {
510 			if (mp != NULL) {
511 				*mpdrop_prevp = mp;
512 				mpdrop_prevp = &mp->b_next;
513 			} else {
514 				/*
515 				 * If the hook consumer (e.g. ipf) already
516 				 * freed the mblk_t, update the drop count now.
517 				 */
518 				ndrop++;
519 			}
520 			mp = next;
521 			continue;
522 		}
523 
524 		/*
525 		 * Ethernet frames are expected to be padded out in order to
526 		 * meet the minimum size.
527 		 *
528 		 * A special case is made for frames which are short by
529 		 * VLAN_TAGSZ, having been stripped of their VLAN tag while
530 		 * traversing MAC.  A preallocated (and recycled) mblk is used
531 		 * for that specific condition.
532 		 *
533 		 * All other frames that fall short on length will have custom
534 		 * zero-padding allocated appended to them.
535 		 */
536 		if (size == NEED_VLAN_PAD_SIZE) {
537 			ASSERT(MBLKL(viona_vlan_pad_mp) == VLAN_TAGSZ);
538 			ASSERT(viona_vlan_pad_mp->b_cont == NULL);
539 
540 			for (pad = mp; pad->b_cont != NULL; pad = pad->b_cont)
541 				;
542 
543 			pad->b_cont = viona_vlan_pad_mp;
544 			size += VLAN_TAGSZ;
545 		} else if (size < MIN_BUF_SIZE) {
546 			const size_t pad_size = MIN_BUF_SIZE - size;
547 			mblk_t *zero_mp;
548 
549 			zero_mp = allocb(pad_size, BPRI_MED);
550 			if (zero_mp == NULL) {
551 				err = ENOMEM;
552 				goto pad_drop;
553 			}
554 
555 			VIONA_PROBE3(rx_pad_short, viona_vring_t *, ring,
556 			    mblk_t *, mp, size_t, pad_size);
557 			VIONA_RING_STAT_INCR(ring, rx_pad_short);
558 			zero_mp->b_wptr += pad_size;
559 			bzero(zero_mp->b_rptr, pad_size);
560 			linkb(mp, zero_mp);
561 			size += pad_size;
562 		}
563 
564 		if (do_merge) {
565 			err = viona_recv_merged(ring, mp, size);
566 		} else {
567 			err = viona_recv_plain(ring, mp, size);
568 		}
569 
570 		/*
571 		 * The VLAN padding mblk is meant for continual reuse, so
572 		 * remove it from the chain to prevent it from being freed.
573 		 *
574 		 * Custom allocated padding does not require this treatment and
575 		 * is freed normally.
576 		 */
577 		if (pad != NULL) {
578 			pad->b_cont = NULL;
579 		}
580 
581 pad_drop:
582 		/*
583 		 * While an error during rx processing
584 		 * (viona_recv_{merged,plain}) does not free mp on error,
585 		 * hook processing might or might not free mp.  Handle either
586 		 * scenario -- if mp is not yet free, it is queued up and
587 		 * freed after the guest has been notified.  If mp is
588 		 * already NULL, just proceed on.
589 		 */
590 		if (err != 0) {
591 			*mpdrop_prevp = mp;
592 			mpdrop_prevp = &mp->b_next;
593 
594 			/*
595 			 * If the available ring is empty, do not bother
596 			 * attempting to deliver any more frames.  Count the
597 			 * rest as dropped too.
598 			 */
599 			if (err == ENOSPC) {
600 				mp->b_next = next;
601 				break;
602 			}
603 		} else {
604 			/* Chain successful mblks to be freed later */
605 			*mprx_prevp = mp;
606 			mprx_prevp = &mp->b_next;
607 			nrx++;
608 		}
609 		mp = next;
610 	}
611 
612 	membar_enter();
613 	viona_intr_ring(ring, B_FALSE);
614 
615 	/* Free successfully received frames */
616 	if (mprx != NULL) {
617 		freemsgchain(mprx);
618 	}
619 
620 	/* Free dropped frames, also tallying them */
621 	mp = mpdrop;
622 	while (mp != NULL) {
623 		mblk_t *next = mp->b_next;
624 
625 		mp->b_next = NULL;
626 		freemsg(mp);
627 		mp = next;
628 		ndrop++;
629 	}
630 	VIONA_PROBE3(rx, viona_link_t *, link, size_t, nrx, size_t, ndrop);
631 }
632 
633 static void
634 viona_rx_classified(void *arg, mac_resource_handle_t mrh, mblk_t *mp,
635     boolean_t is_loopback)
636 {
637 	viona_vring_t *ring = (viona_vring_t *)arg;
638 
639 	/* Drop traffic if ring is inactive or renewing its lease */
640 	if (ring->vr_state != VRS_RUN ||
641 	    (ring->vr_state_flags & VRSF_RENEW) != 0) {
642 		freemsgchain(mp);
643 		return;
644 	}
645 
646 	viona_rx_common(ring, mp, is_loopback);
647 }
648 
649 static void
650 viona_rx_mcast(void *arg, mac_resource_handle_t mrh, mblk_t *mp,
651     boolean_t is_loopback)
652 {
653 	viona_vring_t *ring = (viona_vring_t *)arg;
654 	mac_handle_t mh = ring->vr_link->l_mh;
655 	mblk_t *mp_mcast_only = NULL;
656 	mblk_t **mpp = &mp_mcast_only;
657 
658 	/* Drop traffic if ring is inactive or renewing its lease */
659 	if (ring->vr_state != VRS_RUN ||
660 	    (ring->vr_state_flags & VRSF_RENEW) != 0) {
661 		freemsgchain(mp);
662 		return;
663 	}
664 
665 	/*
666 	 * In addition to multicast traffic, broadcast packets will also arrive
667 	 * via the MAC_CLIENT_PROMISC_MULTI handler. The mac_rx_set() callback
668 	 * for fully-classified traffic has already delivered that broadcast
669 	 * traffic, so it should be suppressed here, rather than duplicating it
670 	 * to the guest.
671 	 */
672 	while (mp != NULL) {
673 		mblk_t *mp_next;
674 		mac_header_info_t mhi;
675 		int err;
676 
677 		mp_next = mp->b_next;
678 		mp->b_next = NULL;
679 
680 		/* Determine the packet type */
681 		err = mac_vlan_header_info(mh, mp, &mhi);
682 		if (err != 0) {
683 			mblk_t *pull;
684 
685 			/*
686 			 * It is possible that gathering of the header
687 			 * information was impeded by a leading mblk_t which
688 			 * was of inadequate length to reference the needed
689 			 * fields.  Try again, in case that could be solved
690 			 * with a pull-up.
691 			 */
692 			pull = msgpullup(mp, sizeof (struct ether_vlan_header));
693 			if (pull == NULL) {
694 				err = ENOMEM;
695 			} else {
696 				err = mac_vlan_header_info(mh, pull, &mhi);
697 				freemsg(pull);
698 			}
699 
700 			if (err != 0) {
701 				VIONA_RING_STAT_INCR(ring, rx_mcast_check);
702 			}
703 		}
704 
705 		/* Chain up matching packets while discarding others */
706 		if (err == 0 && mhi.mhi_dsttype == MAC_ADDRTYPE_MULTICAST) {
707 			*mpp = mp;
708 			mpp = &mp->b_next;
709 		} else {
710 			freemsg(mp);
711 		}
712 
713 		mp = mp_next;
714 	}
715 
716 	if (mp_mcast_only != NULL) {
717 		viona_rx_common(ring, mp_mcast_only, is_loopback);
718 	}
719 }
720 
721 int
722 viona_rx_set(viona_link_t *link)
723 {
724 	viona_vring_t *ring = &link->l_vrings[VIONA_VQ_RX];
725 	int err;
726 
727 	mac_rx_set(link->l_mch, viona_rx_classified, ring);
728 	err = mac_promisc_add(link->l_mch, MAC_CLIENT_PROMISC_MULTI,
729 	    viona_rx_mcast, ring, &link->l_mph,
730 	    MAC_PROMISC_FLAGS_NO_TX_LOOP | MAC_PROMISC_FLAGS_VLAN_TAG_STRIP);
731 	if (err != 0) {
732 		mac_rx_clear(link->l_mch);
733 	}
734 
735 	return (err);
736 }
737 
738 void
739 viona_rx_clear(viona_link_t *link)
740 {
741 	mac_promisc_remove(link->l_mph);
742 	mac_rx_clear(link->l_mch);
743 }
744