Date: Wed, 19 Oct 2005 23:25:59 +1300 From: Andrew Thompson <thompsa@freebsd.org> To: freebsd-net@freebsd.org Subject: vlan patch Message-ID: <20051019102559.GA45909@heff.fud.org.nz>
next in thread | raw e-mail | index | archive | help
--SUOF0GtieIMvvwua Content-Type: text/plain; charset=us-ascii Content-Disposition: inline Hi, It has always bugged me how the vlan code traverses the linked-list for each incoming packet to find the right ifvlan, I have this patch which attempts to fix this. What it does is replace the linear search for the vlan with a constant time lookup. It does this by allocating an array for each vlan enabled parent interface so the tag can be directly indexed. This has an overhead of ~16kb on 32bit, this is not too bad as there is usually only one physical interface when using a large number of vlans. I have measured a 1.6% pps increase with 100 vlans, and 8% with 500, and yes, some people use this many in production. It also has the benefit of enforcing unique vlan tags per parent which the current code doesn't do. Comments welcome. Andrew --SUOF0GtieIMvvwua Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="if_vlan.diff" Index: if_var.h =================================================================== RCS file: /home/ncvs/src/sys/net/if_var.h,v retrieving revision 1.103 diff -u -p -r1.103 if_var.h --- if_var.h 1 Oct 2005 18:56:18 -0000 1.103 +++ if_var.h 19 Oct 2005 07:22:45 -0000 @@ -134,6 +134,7 @@ struct ifnet { u_short if_index; /* numeric abbreviation for this if */ short if_timer; /* time 'til if_watchdog called */ u_short if_nvlans; /* number of active vlans */ + void *if_vlantags; /* array to hold active vlans */ int if_flags; /* up/down, broadcast, etc. */ int if_capabilities; /* interface capabilities */ int if_capenable; /* enabled features */ Index: if_vlan.c =================================================================== RCS file: /home/ncvs/src/sys/net/if_vlan.c,v retrieving revision 1.88 diff -u -p -r1.88 if_vlan.c --- if_vlan.c 3 Oct 2005 02:24:21 -0000 1.88 +++ if_vlan.c 19 Oct 2005 07:24:58 -0000 @@ -133,7 +133,7 @@ static int vlan_setflag(struct ifnet *if static int vlan_setflags(struct ifnet *ifp, int status); static int vlan_setmulti(struct ifnet *ifp); static int vlan_unconfig(struct ifnet *ifp); -static int vlan_config(struct ifvlan *ifv, struct ifnet *p); +static int vlan_config(struct ifvlan *ifv, struct ifnet *p, int tag); static void vlan_link_state(struct ifnet *ifp, int link); static struct ifnet *vlan_clone_match_ethertag(struct if_clone *, @@ -406,7 +406,7 @@ vlan_clone_create(struct if_clone *ifc, if (ethertag) { VLAN_LOCK(); - error = vlan_config(ifv, p); + error = vlan_config(ifv, p, tag); if (error != 0) { /* * Since we've partialy failed, we need to back @@ -422,7 +422,6 @@ vlan_clone_create(struct if_clone *ifc, return (error); } - ifv->ifv_tag = tag; ifp->if_drv_flags |= IFF_DRV_RUNNING; VLAN_UNLOCK(); @@ -568,10 +567,13 @@ static void vlan_input(struct ifnet *ifp, struct mbuf *m) { struct ether_vlan_header *evl; - struct ifvlan *ifv; + struct ifvlan *ifv = NULL; + struct ifvlan **ifv_tags; struct m_tag *mtag; u_int tag; + ifv_tags = ifp->if_vlantags; + if (m->m_flags & M_VLANTAG) { /* * Packet is tagged, but m contains a normal @@ -620,9 +622,15 @@ vlan_input(struct ifnet *ifp, struct mbu } VLAN_LOCK(); +#if 1 + /* Look up the vlan in the parents tag array. O(1) */ + if (ifp->if_vlantags != NULL) + ifv = ifv_tags[tag]; +#else LIST_FOREACH(ifv, &ifv_list, ifv_list) if (ifp == ifv->ifv_p && tag == ifv->ifv_tag) break; +#endif if (ifv == NULL || (ifv->ifv_ifp->if_flags & IFF_UP) == 0) { VLAN_UNLOCK(); @@ -658,18 +666,26 @@ vlan_input(struct ifnet *ifp, struct mbu } static int -vlan_config(struct ifvlan *ifv, struct ifnet *p) +vlan_config(struct ifvlan *ifv, struct ifnet *p, int tag) { struct ifaddr *ifa1, *ifa2; struct ifnet *ifp; struct sockaddr_dl *sdl1, *sdl2; + struct ifvlan **ifv_tags; VLAN_LOCK_ASSERT(); + ifv_tags = p->if_vlantags; + + /* VID numbers 0x0 and 0xFFF are reserved */ + if (tag == 0 || tag == EVL_VLID_MASK) + return (EINVAL); if (p->if_type != IFT_ETHER) return (EPROTONOSUPPORT); if (ifv->ifv_p) return (EBUSY); + if (p->if_vlantags != NULL && ifv_tags[tag] != NULL) + return (EBUSY); ifv->ifv_encaplen = ETHER_VLAN_ENCAP_LEN; ifv->ifv_mintu = ETHERMIN; @@ -680,7 +696,18 @@ vlan_config(struct ifvlan *ifv, struct i * at various places to see if there is a vlan(4) * attached to this physical interface. */ + + /* Allocate the parents tag array */ + if (p->if_nvlans == 0) { + p->if_vlantags = malloc( + (int)(EVL_VLID_MASK * sizeof(struct ifvlan *)), + M_VLAN, M_WAITOK | M_ZERO); + ifv_tags = p->if_vlantags; + } + p->if_nvlans++; + ifv_tags[tag] = ifv; + ifv->ifv_tag = tag; /* * If the parent supports the VLAN_MTU capability, @@ -763,6 +790,7 @@ vlan_unconfig(struct ifnet *ifp) struct sockaddr_dl *sdl; struct vlan_mc_entry *mc; struct ifvlan *ifv; + struct ifvlan **ifv_tags; struct ifnet *p; int error; @@ -798,7 +826,17 @@ vlan_unconfig(struct ifnet *ifp) } vlan_setflags(ifp, 0); /* clear special flags on parent */ + + ifv_tags = p->if_vlantags; + if (ifv->ifv_tag > 0) + ifv_tags[ifv->ifv_tag] = NULL; + p->if_nvlans--; + /* Deallocate the parents tag array */ + if (p->if_nvlans == 0) { + free(p->if_vlantags, M_VLAN); + p->if_vlantags = NULL; + } } /* Disconnect from parent. */ @@ -998,12 +1036,11 @@ vlan_ioctl(struct ifnet *ifp, u_long cmd break; } VLAN_LOCK(); - error = vlan_config(ifv, p); + error = vlan_config(ifv, p, vlr.vlr_tag); if (error) { VLAN_UNLOCK(); break; } - ifv->ifv_tag = vlr.vlr_tag; ifp->if_drv_flags |= IFF_DRV_RUNNING; VLAN_UNLOCK(); --SUOF0GtieIMvvwua--
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20051019102559.GA45909>