> On 2 Jan 2016, at 7:55 AM, Stefan Fritsch <[email protected]> wrote:
>
> 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, ...
should we just do it unconditionally? is there a downside to that?
dlg
>
> 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) {
>