tag lookups consider the type of interface as well as its tag, so it isnt necessary to have separate hashes for vlans and svlans.
following on from this, i would like to widen the tag hash and maybe xor some more bits in to get the key. vlan tags are 12 bits, so the following appeals to me: #define TAG_HASH_SIZE 64 #define TAG_HASH(tag) ((tag & vlan_tagmask) ^ ((tag >> 6) & vlan_tagmask)) it would also be nice to have vlan interfaces refer to their parents by interface indexes instead of actual pointers. that would allow the hash lookup to be done without necessarily calling if_get in vlan_input, but that would also require not accounting errors on the parent interface. anyway. tests? Index: if_vlan.c =================================================================== RCS file: /cvs/src/sys/net/if_vlan.c,v retrieving revision 1.132 diff -u -p -r1.132 if_vlan.c --- if_vlan.c 29 Jun 2015 10:32:29 -0000 1.132 +++ if_vlan.c 1 Jul 2015 07:26:18 -0000 @@ -74,7 +74,7 @@ u_long vlan_tagmask, svlan_tagmask; #define TAG_HASH_SIZE 32 #define TAG_HASH(tag) (tag & vlan_tagmask) -LIST_HEAD(vlan_taghash, ifvlan) *vlan_tagh, *svlan_tagh; +LIST_HEAD(vlan_taghash, ifvlan) *vlan_tagh; int vlan_input(struct mbuf *); @@ -102,18 +102,15 @@ struct if_clone svlan_cloner = void vlanattach(int count) { - /* Normal VLAN */ vlan_tagh = hashinit(TAG_HASH_SIZE, M_DEVBUF, M_NOWAIT, &vlan_tagmask); if (vlan_tagh == NULL) panic("vlanattach: hashinit"); + + /* Normal VLAN */ if_clone_attach(&vlan_cloner); /* Service-VLAN for QinQ/802.1ad provider bridges */ - svlan_tagh = hashinit(TAG_HASH_SIZE, M_DEVBUF, M_NOWAIT, - &svlan_tagmask); - if (svlan_tagh == NULL) - panic("vlanattach: hashinit"); if_clone_attach(&svlan_cloner); } @@ -249,7 +246,6 @@ vlan_input(struct mbuf *m) struct ifnet *ifp; struct ether_vlan_header *evl; struct ether_header *eh; - struct vlan_taghash *tagh; u_int tag; struct mbuf_list ml = MBUF_LIST_INITIALIZER(); u_int16_t etype; @@ -266,7 +262,6 @@ vlan_input(struct mbuf *m) if (m->m_flags & M_VLANTAG) { etype = ETHERTYPE_VLAN; - tagh = vlan_tagh; } else if ((etype == ETHERTYPE_VLAN) || (etype == ETHERTYPE_QINQ)) { if (m->m_len < EVL_ENCAPLEN && (m = m_pullup(m, EVL_ENCAPLEN)) == NULL) { @@ -276,7 +271,6 @@ vlan_input(struct mbuf *m) evl = mtod(m, struct ether_vlan_header *); m->m_pkthdr.ether_vtag = ntohs(evl->evl_tag); - tagh = etype == ETHERTYPE_QINQ ? svlan_tagh : vlan_tagh; } else { /* Skip non-VLAN packets. */ return (0); @@ -290,7 +284,7 @@ vlan_input(struct mbuf *m) if (m->m_pkthdr.pf.prio <= 1) m->m_pkthdr.pf.prio = !m->m_pkthdr.pf.prio; - LIST_FOREACH(ifv, &tagh[TAG_HASH(tag)], ifv_list) { + LIST_FOREACH(ifv, &vlan_tagh[TAG_HASH(tag)], ifv_list) { if (ifp == ifv->ifv_p && tag == ifv->ifv_tag && etype == ifv->ifv_type) break; @@ -344,7 +338,6 @@ int vlan_config(struct ifvlan *ifv, struct ifnet *p, u_int16_t tag) { struct sockaddr_dl *sdl1, *sdl2; - struct vlan_taghash *tagh; u_int flags; int s; @@ -429,14 +422,12 @@ vlan_config(struct ifvlan *ifv, struct i vlan_vlandev_state(ifv); - tagh = ifv->ifv_type == ETHERTYPE_QINQ ? svlan_tagh : vlan_tagh; - s = splnet(); /* Change input handler of the physical interface. */ if (++ifv->ifv_ifih->ifih_refcnt == 1) SLIST_INSERT_HEAD(&p->if_inputs, ifv->ifv_ifih, ifih_next); - LIST_INSERT_HEAD(&tagh[TAG_HASH(tag)], ifv, ifv_list); + LIST_INSERT_HEAD(&vlan_tagh[TAG_HASH(tag)], ifv, ifv_list); splx(s); return (0);