Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 26 May 2013 12:17:56 -0400
From:      Landon Fuller <landonf@plausible.coop>
To:        freebsd-emulation@freebsd.org
Subject:   Re: [PATCH] VLAN trunking support in VirtualBox vboxnetflt
Message-ID:  <2E7892C4-F9BD-41A3-9269-D9A24D0DB695@plausible.coop>
In-Reply-To: <6BCC0BDE-C9FD-47F0-96AE-88F797EFB074@plausible.coop>
References:  <6BCC0BDE-C9FD-47F0-96AE-88F797EFB074@plausible.coop>

next in thread | previous in thread | raw e-mail | index | archive | help

--Apple-Mail=_A25C6A19-0F06-4FEE-B1C0-CD2A395AF4BA
Content-Transfer-Encoding: quoted-printable
Content-Type: text/plain;
	charset=us-ascii

Hello,

This patch has been in the vbox kmod port for some time now, and I've =
been running it without incident; however, I recently ran into a =
configuration that the patch does not correctly handle:
	- A single host interface (eg, em0) bridged to a VM
	- VLANs also configured on the host interface (em0.vlan0, =
em0.vlan1)

The packet flow in this situation should be:
	- The ng filter is handed a packet from em0
	- The filter re-adds the VLAN header to the top of the packet =
and strips the M_VLANTAG flag
	- After passing to the virtual switch, the packet is re-injected =
into the host via ether_demux().
	- ether_demux() extracts the embedded VLAN tag and hands the =
packet off to vlan_input_p().

As it turns out, ether_demux() does not handle frames with embedded VLAN =
tags, and at this point, the packet is dropped, rather than being routed =
to the host's VLAN handling:
	=
http://lists.freebsd.org/pipermail/freebsd-net/2011-October/030201.html

The result is as follows:
	- Packets received via the host interface are handled correctly.
	- Packets (including VLAN tagged packets) are passed to sub-VMs =
correctly.
	- Packets that *should* be handled by vlan* sub-interfaces on =
the host are never received by those interfaces as they're dropped in =
ether_demux().

This worked in my existing configuration because the host and the VMs =
actually use two different VLAN trunks (em0 and em1), and so em0 packets =
being dropped after injection into the virtual switch does not affect =
the host's handling of packets on em1.

I've attached an updated patch that should resolve this issue; I'm =
currently testing it locally on my home deployment and so far it is =
working fine. The patch simply restores the VLAN flags and stripped =
ethernet header after injecting the packet into the virtual ethernet =
switch. With this change in place, ether_demux() correctly hands the =
packet off to vlan_input_p().

Cheers,
Landon


--Apple-Mail=_A25C6A19-0F06-4FEE-B1C0-CD2A395AF4BA
Content-Disposition: attachment;
	filename*0=patch-src-VBox-HostDrivers-VBoxNetFlt-freebsd-VBoxNetFlt-freebsd;
	filename*1=.c
Content-Type: application/octet-stream;
	name="patch-src-VBox-HostDrivers-VBoxNetFlt-freebsd-VBoxNetFlt-freebsd.c"
Content-Transfer-Encoding: 7bit

--- ./src/VBox/HostDrivers/VBoxNetFlt/freebsd/VBoxNetFlt-freebsd.c.orig	2013-04-12 06:38:11.000000000 -0400
+++ ./src/VBox/HostDrivers/VBoxNetFlt/freebsd/VBoxNetFlt-freebsd.c	2013-05-25 20:14:52.152180452 -0400
@@ -51,6 +51,7 @@
 #include <net/if_dl.h>
 #include <net/if_types.h>
 #include <net/ethernet.h>
+#include <net/if_vlan_var.h>
 
 #include <netgraph/ng_message.h>
 #include <netgraph/netgraph.h>
@@ -427,6 +428,8 @@
     struct ifnet *ifp = pThis->u.s.ifp;
     unsigned int cSegs = 0;
     bool fDropIt = false, fActive;
+    bool is_vl_tagged = false;
+    uint16_t vl_tag;
     PINTNETSG pSG;
 
     VBOXCURVNET_SET(ifp->if_vnet);
@@ -439,6 +442,19 @@
         if (m == NULL)
             break;
 
+        /* Prepend a VLAN header for consumption by the virtual switch */
+        if (m->m_flags & M_VLANTAG) {
+            vl_tag = m->m_pkthdr.ether_vtag;
+            is_vl_tagged = true;
+
+            m = ether_vlanencap(m, m->m_pkthdr.ether_vtag);
+            if (m == NULL) {
+                printf("vboxflt: unable to prepend VLAN header\n");
+                break;
+            }
+            m->m_flags &= ~M_VLANTAG;
+        }
+
         for (m0 = m; m0 != NULL; m0 = m0->m_next)
             if (m0->m_len > 0)
                 cSegs++;
@@ -453,6 +469,27 @@
         vboxNetFltFreeBSDMBufToSG(pThis, m, pSG, cSegs, 0);
         fDropIt = pThis->pSwitchPort->pfnRecv(pThis->pSwitchPort, NULL /* pvIf */, pSG, INTNETTRUNKDIR_WIRE);
         RTMemTmpFree(pSG);
+
+        /* Restore the VLAN flags before re-injecting the packet */
+        if (is_vl_tagged && !fDropIt) {
+            struct ether_vlan_header *vl_hdr;
+
+            /* This shouldn't fail, as the header was just prepended */
+            if (m->m_len < sizeof(*vl_hdr) && (m = m_pullup(m, sizeof(*vl_hdr))) == NULL) {
+                printf("vboxflt: unable to pullup VLAN header\n");
+                m_freem(m);
+                break;
+            }
+
+            /* Copy the MAC dhost/shost over the 802.1q field */
+            vl_hdr = mtod(m, struct ether_vlan_header *);
+            bcopy((char *)vl_hdr, (char *)vl_hdr + ETHER_VLAN_ENCAP_LEN, ETHER_HDR_LEN - ETHER_TYPE_LEN);
+            m_adj(m, ETHER_VLAN_ENCAP_LEN);
+
+            m->m_pkthdr.ether_vtag = vl_tag;
+            m->m_flags |= M_VLANTAG;
+        }
+
         if (fDropIt)
             m_freem(m);
         else

--Apple-Mail=_A25C6A19-0F06-4FEE-B1C0-CD2A395AF4BA
Content-Transfer-Encoding: quoted-printable
Content-Type: text/plain;
	charset=us-ascii



On Apr 13, 2012, at 2:51 PM, Landon J Fuller <landonf@plausible.coop> =
wrote:

> Howdy,
>=20
> I was looking into trunking VLANs into a virtual machine via bridging, =
and noted that transmit of 802.1q tagged packets worked from the guest =
VM, but upon reception, the VLAN tag seemed to be stripped before the =
packets hit the guest's interface.
>=20
> Taking a look at the netgraph-based bridging implementation, it looks =
like the VLAN tag is not being re-inserted at the head of the ethernet =
frame prior to handing off the to VirtualBox, and VBox doesn't seem to =
have an equivalent 'ether_vtag' field in its INTNETSG struct to handle =
this.
>=20
> Thus, to preserve the VLAN tag, I modified vboxNetFltFreeBSDMBufToSG() =
to ether_vlanencap() to insert the VLAN tag before handing off to VBox. =
With this in place, I was able to successfully trunk VLANs to a virtual =
machine.=20
>=20
> Some caveats:
> 	- If using virtio-kmod's if_vtnet, you must set vlanhwfilter (or =
promisc) flags on the guest interface before virtualbox will pass the =
VLAN tagged packets through. Otherwise, the VBox virtio-net device =
implementation will filter out the incoming packets before handing them =
to the VM hardware.
> 	- VBox's em(4) host implementation does not appear to support =
'hardware' VLAN tagging, but it does declare it. If using a em(4) =
virtualized NIC, you must set -vlanhwtag on the guest interface.
>=20
> I welcome someone(s) with more experience than I eyeballing the (tiny) =
attached patch. I'm also especially concerned as to whether this should =
be considered supported functionality in VBox, or I'm just getting lucky =
with the virtio-net code path.
>=20
> Thanks,
> Landon
>=20
> =
<patch-src-VBox-HostDrivers-VBoxNetFlt-freebsd-VBoxNetFlt-freebsd.c>______=
_________________________________________
> freebsd-emulation@freebsd.org mailing list
> http://lists.freebsd.org/mailman/listinfo/freebsd-emulation
> To unsubscribe, send any mail to =
"freebsd-emulation-unsubscribe@freebsd.org"


--Apple-Mail=_A25C6A19-0F06-4FEE-B1C0-CD2A395AF4BA--



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?2E7892C4-F9BD-41A3-9269-D9A24D0DB695>