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,