As there isn't any consensus for one of the other solutions, I am going to
commit the patch that fixes this inside vio(4).
On Thu, 14 Jan 2016, Stefan Fritsch wrote:
> On Mon, 4 Jan 2016, Stefan Fritsch wrote:
> > On Sun, 3 Jan 2016, Theo de Raadt wrote:
> > > >> dlg writes:
> > > >> > should we just do it unconditionally? is there a downside to that?
> > > >
> > > >It may decrease performance a tiny bit. Since such bits tend to add
> > > >up, I would be hesitant to enable the check for drivers that don't
> > > >need it. OTOH, freebsd and linux seem to always do the check.
> > >
> > > How does it decrease performance?
> >
> > I am talking about this diff in ether_input():
> >
> > diff --git sys/net/if_ethersubr.c sys/net/if_ethersubr.c
> > --- sys/net/if_ethersubr.c
> > +++ sys/net/if_ethersubr.c
> > @@ -353,8 +353,7 @@ ether_input(struct ifnet *ifp, struct mbuf *m, void
> > *cookie)
> > * 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)) {
> > + if ((m->m_flags & (M_BCAST|M_MCAST)) == 0) {
> > if (memcmp(ac->ac_enaddr, eh->ether_dhost, ETHER_ADDR_LEN)) {
> > m_freem(m);
> > return (1);
> >
> > For other drivers than vio this means an additional 6 byte memcmp where
> > one operand is already in the cache, and the other operand may or may not
> > be in the cache. 'tiny performance impact' seems about right.
>
> Hrvoje Popovski was very helpful and did some performance tests with the
> patch above. There is only measurable difference at very high package
> rates, but I must admit that there the difference is a bit larger than I
> expected:
>
> > i'm sending 64byte packets from host connected to ix2 and counting then
> > on host connected to ix3
>
> > without your patch
>
> sending receiving
> 400kpps 400kpps
> 600kpps 600kpps
> 800kpps 690kpps
> 1Mpps 610kpps
> 1.4Mpps 580kpps
> 12Mpps 580kpps
>
>
> > with your patch
>
> sending receiving
> 400kpps 400kpps - 0%
> 600kpps 600kpps - 0%
> 800kpps 680kpps - 1.4%
> 1Mpps 600kpps - 1.6%
> 1.4Mpps 560kpps - 3.4%
> 12Mpps 560kpps - 3.4%
>
>
>
> So, which variant should I commit?
>
> - do the check unconditionally
> - add some flag so that ether_input() does the check for vio(4)
> unconditionally
> - do the check in vio(4)
>
> mpi fixed a similar bug in trunk(4) in July, but that does not use
> ether_input() and would not profit from the flag approach.
>
>
>
> > > Maybe you should show the diff which does the check in the driver
> > > itself, then then it will be easier to see the performance cost. Right
> > > now I can't perceive the problem.
> >
> > It's not very expensive. But it's more code duplication than I like:
> >
> > diff --git sys/dev/pci/if_vio.c sys/dev/pci/if_vio.c
> > --- sys/dev/pci/if_vio.c
> > +++ sys/dev/pci/if_vio.c
> > @@ -1005,6 +1005,9 @@ vio_rxeof(struct vio_softc *sc)
> > int r = 0;
> > int slot, len, bufs_left;
> > struct virtio_net_hdr *hdr;
> > + int promisc = (ifp->if_flags & IFF_PROMISC);
> > + u_int8_t *enaddr = sc->sc_ac.ac_enaddr;
> > + struct ether_header *eh;
> >
> > while (virtio_dequeue(vsc, vq, &slot, &len) == 0) {
> > r = 1;
> > @@ -1035,10 +1038,33 @@ vio_rxeof(struct vio_softc *sc)
> > bufs_left--;
> > }
> >
> > - if (bufs_left == 0) {
> > - ml_enqueue(&ml, m0);
> > - m0 = NULL;
> > + if (bufs_left > 0)
> > + continue;
> > +
> > + /*
> > + * Unfortunately, mac filtering is only best effort
> > + * in virtio-net. Unwanted packets may still arrive.
> > + * If we are not promiscous, we have to check if the
> > + * packet is actually for us.
> > + */
> > + if (!promisc) {
> > + m0 = m_pullup(m0, ETHER_HDR_LEN);
> > + /*
> > + * no need to check m0 == NULL, we know m0 has enough
> > + * space
> > + */
> > +
> > + eh = mtod(m0, struct ether_header *);
> > + if (!ETHER_IS_MULTICAST(eh->ether_dhost) &&
> > + memcmp(enaddr, eh->ether_dhost, ETHER_ADDR_LEN) !=
> > 0) {
> > + m_freem(m0);
> > + m0 = NULL;
> > + continue;
> > + }
> > }
> > +
> > + ml_enqueue(&ml, m0);
> > + m0 = NULL;
> > }
> > if (m0 != NULL) {
> > DBGPRINT("expected %d buffers, got %d", (int)hdr->num_buffers,
> >
> >
>
>