On Sun, 3 Jan 2016, Theo de Raadt wrote: > >On Friday 01 January 2016 16:25:59, 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. > > I tried to read the rest of what you wrote. It makes no sense. Since > these mbufs are coming off a ring, aren't they already linear; aren't > these mbufs already normalzed ie. "pulled up". The performance cost > seems to be one condition in a mbuf macro which decides to do no work. > > 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,