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,
> > 
> > 
> 
> 

Reply via email to