Skip site navigation (1)Skip section navigation (2)
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>