> On 2 Jan 2016, at 7:55 AM, Stefan Fritsch <s...@sfritsch.de> 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) { >