Hi,
by default, the ether_input() checks the destination MAC address of
incoming unicast packets only if the interface is in promiscous mode. If
not, it is assumed that the NIC filters unicast packets reliably.
Unfortunately, for virtio-net this is not the case. There, unicast
filtering is only best effort, and (depending on configuration) if the
bridge on the VM host does unicast flodding, unicast packets that are not
for the VM guest may still be delivered to the VM guest. This is a rather
annoying problem because it can cause pf to send RST packets to foreign
connections. (Kudos to mpf@ for debugging this).
There are two possible approaches to fix this problem. Either make the
vio(4) driver filter out unicast packets that are not for the local MAC,
which would involve duplicating quite a bit of code from ether_input() in
vio(4). Or, and I would prefer this, allow the driver to tell
ether_input() that it needs to check the MAC always, and not only if the
interface is in promiscous mode.
This could be done with a new flag. There seem to be three possible places
where this flag could be put:
* ifnet.if_flags
This is a short and there is no free bit. But the IFF_NOTRAILERS bit has
become unused recently and could be recycled.
* ifnet.if_xflags
An int, lots of free bits. But comment says 'extra softnet flags'
* if_data.ifi_capabilities
An u_int32_t, lots of free bits.
In the diff below, I went with the first choice because the new IFF_NOMACFILTER
is somewhat similar to IFF_SIMPLEX and because the the check can then be
nicely folded into the existing check for IFF_PROMISC.
I would welcome any comments, suggestions for a better flag name, OKs, ...
Cheers,
Stefan
diff --git sys/dev/pci/if_vio.c sys/dev/pci/if_vio.c
index 4cd80d5..22fd7cf 100644
--- sys/dev/pci/if_vio.c
+++ sys/dev/pci/if_vio.c
@@ -582,21 +582,21 @@ vio_attach(struct device *parent, struct device *self,
void *aux)
virtio_start_vq_intr(vsc, &sc->sc_vq[VQCTL]);
vsc->sc_nvqs = 3;
}
}
if (vio_alloc_mem(sc) < 0)
goto err;
strlcpy(ifp->if_xname, self->dv_xname, IFNAMSIZ);
ifp->if_softc = sc;
- ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
+ ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST |
IFF_NOMACFILTER;
ifp->if_start = vio_start;
ifp->if_ioctl = vio_ioctl;
ifp->if_capabilities = IFCAP_VLAN_MTU;
if (features & VIRTIO_NET_F_CSUM)
ifp->if_capabilities |= IFCAP_CSUM_TCPv4|IFCAP_CSUM_UDPv4;
IFQ_SET_MAXLEN(&ifp->if_snd, vsc->sc_vqs[1].vq_num - 1);
IFQ_SET_READY(&ifp->if_snd);
ifmedia_init(&sc->sc_media, 0, vio_media_change, vio_media_status);
ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_AUTO, 0, NULL);
ifmedia_set(&sc->sc_media, IFM_ETHER | IFM_AUTO);
diff --git sys/net/if.h sys/net/if.h
index 8d7e390..91c6d18 100644
--- sys/net/if.h
+++ sys/net/if.h
@@ -182,36 +182,37 @@ struct if_status_description {
/*
* Length of interface description, including terminating '\0'.
*/
#define IFDESCRSIZE 64
#define IFF_UP 0x1 /* interface is up */
#define IFF_BROADCAST 0x2 /* broadcast address valid */
#define IFF_DEBUG 0x4 /* turn on debugging */
#define IFF_LOOPBACK 0x8 /* is a loopback net */
#define IFF_POINTOPOINT 0x10 /* interface is point-to-point
link */
-#define IFF_NOTRAILERS 0x20 /* avoid use of trailers */
+#define IFF_NOMACFILTER 0x20 /* Does not reliably filter
unicast MACs */
#define IFF_RUNNING 0x40 /* resources allocated */
#define IFF_NOARP 0x80 /* no address resolution
protocol */
#define IFF_PROMISC 0x100 /* receive all packets */
#define IFF_ALLMULTI 0x200 /* receive all multicast
packets */
#define IFF_OACTIVE 0x400 /* transmission in progress */
#define IFF_SIMPLEX 0x800 /* can't hear own transmissions
*/
#define IFF_LINK0 0x1000 /* per link layer defined bit */
#define IFF_LINK1 0x2000 /* per link layer defined bit */
#define IFF_LINK2 0x4000 /* per link layer defined bit */
#define IFF_MULTICAST 0x8000 /* supports multicast */
+
/* flags set internally only: */
#define IFF_CANTCHANGE \
(IFF_BROADCAST|IFF_POINTOPOINT|IFF_RUNNING|IFF_OACTIVE|\
- IFF_SIMPLEX|IFF_MULTICAST|IFF_ALLMULTI)
+ IFF_SIMPLEX|IFF_MULTICAST|IFF_ALLMULTI|IFF_NOMACFILTER)
#define IFXF_MPSAFE 0x1 /* if_start is mpsafe */
#define IFXF_INET6_NOPRIVACY 0x4 /* don't autoconf
privacy */
#define IFXF_MPLS 0x8 /* supports MPLS */
#define IFXF_WOL 0x10 /* wake on lan enabled
*/
#define IFXF_AUTOCONF6 0x20 /* v6 autoconf enabled
*/
#define IFXF_CANTCHANGE \
(IFXF_MPSAFE)
diff --git sys/net/if_ethersubr.c sys/net/if_ethersubr.c
index 2a44161..296e6f6 100644
--- sys/net/if_ethersubr.c
+++ sys/net/if_ethersubr.c
@@ -347,21 +347,21 @@ ether_input(struct ifnet *ifp, struct mbuf *m, void
*cookie)
if (m->m_flags & (M_FILDROP | M_VLANTAG)) {
m_freem(m);
return (1);
}
/*
* If packet is unicast and we're in promiscuous mode, make sure it
* is for us. Drop otherwise.
*/
if ((m->m_flags & (M_BCAST|M_MCAST)) == 0 &&
- (ifp->if_flags & IFF_PROMISC)) {
+ (ifp->if_flags & (IFF_PROMISC|IFF_NOMACFILTER))) {
if (memcmp(ac->ac_enaddr, eh->ether_dhost, ETHER_ADDR_LEN)) {
m_freem(m);
return (1);
}
}
etype = ntohs(eh->ether_type);
decapsulate:
switch (etype) {