Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 25 Jun 2011 02:08:17 +0900
From:      rozhuk.im@gmail.com
To:        <freebsd-net@freebsd.org>
Subject:   ng_vlan improvements
Message-ID:  <4e04c489.d899cc0a.43e4.4ad6@mx.google.com>

next in thread | raw e-mail | index | archive | help

[-- Attachment #1 --]

Diffs

 
--
Rozhuk Ivan
  



[-- Attachment #2 --]
--- ng_vlan.h.orig	2009-08-03 17:13:06.000000000 +0900
+++ ng_vlan.h	2011-06-24 05:35:05.000000000 +0900
@@ -43,7 +43,9 @@
 enum {
 	NGM_VLAN_ADD_FILTER = 1,
 	NGM_VLAN_DEL_FILTER,
-	NGM_VLAN_GET_TABLE
+	NGM_VLAN_GET_TABLE,
+	NGM_VLAN_GET_ENCAP,
+	NGM_VLAN_SET_ENCAP
 };
 
 /* For NGM_VLAN_ADD_FILTER control message. */

[-- Attachment #3 --]
--- ng_vlan.c.orig	2009-08-03 17:13:06.000000000 +0900
+++ ng_vlan.c	2011-06-24 21:00:22.000000000 +0900
@@ -110,6 +110,20 @@
 	  NULL,
 	  &ng_vlan_table_type
 	},
+	{
+	  NGM_VLAN_COOKIE,
+	  NGM_VLAN_GET_ENCAP,
+	  "getencap",
+	  NULL,
+	  &ng_parse_int32_type
+	},
+	{
+	  NGM_VLAN_COOKIE,
+	  NGM_VLAN_SET_ENCAP,
+	  "setencap",
+	  &ng_parse_int32_type,
+	  NULL
+	},
 	{ 0 }
 };
 
@@ -126,47 +140,27 @@
 };
 NETGRAPH_INIT(vlan, &ng_vlan_typestruct);
 
-struct filter {
-	LIST_ENTRY(filter) next;
-	u_int16_t	vlan;
-	hook_p		hook;
-};
 
-#define	HASHSIZE	16
-#define	HASH(id)	((((id) >> 8) ^ ((id) >> 4) ^ (id)) & 0x0f)
-LIST_HEAD(filterhead, filter);
 
 typedef struct {
 	hook_p		downstream_hook;
 	hook_p		nomatch_hook;
-	struct filterhead hashtable[HASHSIZE];
-	u_int32_t	nent;
+	hook_p		vlan_hook[(EVL_VLID_MASK + 1)];
+	int		vlan_encap;
 } *priv_p;
+#define HOOK_VLAN_SET_MASK ((uintptr_t)((~0) & ~(EVL_VLID_MASK)))
 
-static struct filter *
-ng_vlan_findentry(priv_p priv, u_int16_t vlan)
-{
-	struct filterhead *chain = &priv->hashtable[HASH(vlan)];
-	struct filter *f;
-
-	LIST_FOREACH(f, chain, next)
-		if (f->vlan == vlan)
-			return (f);
-	return (NULL);
-}
 
 static int
 ng_vlan_constructor(node_p node)
 {
 	priv_p priv;
-	int i;
 
 	priv = malloc(sizeof(*priv), M_NETGRAPH, M_NOWAIT | M_ZERO);
 	if (priv == NULL)
 		return (ENOMEM);
-	for (i = 0; i < HASHSIZE; i++)
-		LIST_INIT(&priv->hashtable[i]);
-	NG_NODE_SET_PRIVATE(node, priv);
+	priv->vlan_encap = 1;
+
 	return (0);
 }
 
@@ -193,13 +187,12 @@
 ng_vlan_rcvmsg(node_p node, item_p item, hook_p lasthook)
 {
 	const priv_p priv = NG_NODE_PRIVATE(node);
-	int error = 0;
 	struct ng_mesg *msg, *resp = NULL;
 	struct ng_vlan_filter *vf;
-	struct filter *f;
 	hook_p hook;
 	struct ng_vlan_table *t;
-	int i;
+	uintptr_t vlan, vlan_count;
+	int error = 0;
 
 	NGI_GET_MSG(item, msg);
 	/* Deal with message according to cookie and command. */
@@ -231,30 +224,18 @@
 				break;
 			}
 			/* And is not already in service. */
-			if (NG_HOOK_PRIVATE(hook) != NULL) {
+			if (((uintptr_t)NG_HOOK_PRIVATE(hook) & HOOK_VLAN_SET_MASK) == HOOK_VLAN_SET_MASK) {
 				error = EEXIST;
 				break;
 			}
 			/* Check we don't already trap this VLAN. */
-			if (ng_vlan_findentry(priv, vf->vlan)) {
+			if (priv->vlan_hook[vf->vlan] != NULL) {
 				error = EEXIST;
 				break;
 			}
-			/* Create filter. */
-			f = malloc(sizeof(*f),
-			    M_NETGRAPH, M_NOWAIT | M_ZERO);
-			if (f == NULL) {
-				error = ENOMEM;
-				break;
-			}
-			/* Link filter and hook together. */
-			f->hook = hook;
-			f->vlan = vf->vlan;
-			NG_HOOK_SET_PRIVATE(hook, f);
-			/* Register filter in a hash table. */
-			LIST_INSERT_HEAD(
-			    &priv->hashtable[HASH(f->vlan)], f, next);
-			priv->nent++;
+			/* Link vlan and hook together. */
+			priv->vlan_hook[vf->vlan] = hook;
+			NG_HOOK_SET_PRIVATE(hook, (void *)(HOOK_VLAN_SET_MASK | vf->vlan));
 			break;
 		case NGM_VLAN_DEL_FILTER:
 			/* Check that message is long enough. */
@@ -264,35 +245,64 @@
 			}
 			/* Check that hook exists and is active. */
 			hook = ng_findhook(node, (char *)msg->data);
-			if (hook == NULL ||
-			    (f = NG_HOOK_PRIVATE(hook)) == NULL) {
+			if (hook == NULL)
+				error = ENOENT;
+				break;
+			vlan = (uintptr_t)NG_HOOK_PRIVATE(hook);
+			if ((vlan & HOOK_VLAN_SET_MASK) != HOOK_VLAN_SET_MASK) {
 				error = ENOENT;
 				break;
 			}
+			vlan &= EVL_VLID_MASK; /* remove HOOK_VLAN_SET_MASK from vlan num */
+
 			/* Purge a rule that refers to this hook. */
 			NG_HOOK_SET_PRIVATE(hook, NULL);
-			LIST_REMOVE(f, next);
-			priv->nent--;
-			free(f, M_NETGRAPH);
+			priv->vlan_hook[vlan] = NULL;
 			break;
 		case NGM_VLAN_GET_TABLE:
+			/* calculate vlans */
+			vlan_count = 0;
+			for (vlan = 0; vlan < (EVL_VLID_MASK + 1); vlan ++) {
+				if (priv->vlan_hook[vlan] != NULL)
+					vlan_count ++;
+			}
+
+			/* allocate memory for responce */
 			NG_MKRESPONSE(resp, msg, sizeof(*t) +
-			    priv->nent * sizeof(*t->filter), M_NOWAIT);
+			    vlan_count * sizeof(*t->filter), M_NOWAIT);
 			if (resp == NULL) {
 				error = ENOMEM;
 				break;
 			}
+
+			/* pack data to responce */
 			t = (struct ng_vlan_table *)resp->data;
-			t->n = priv->nent;
+			t->n = vlan_count;
 			vf = &t->filter[0];
-			for (i = 0; i < HASHSIZE; i++) {
-				LIST_FOREACH(f, &priv->hashtable[i], next) {
-					vf->vlan = f->vlan;
-					strncpy(vf->hook, NG_HOOK_NAME(f->hook),
+			for (vlan = 0; vlan < (EVL_VLID_MASK + 1); vlan ++) {
+				if (priv->vlan_hook[vlan] == NULL)
+					continue;
+
+				vf->vlan = vlan;
+				strncpy(vf->hook, NG_HOOK_NAME(priv->vlan_hook[vlan]),
 					    NG_HOOKSIZ);
-					vf++;
-				}
+				vf ++;
+			}
+			break;
+		case NGM_VLAN_GET_ENCAP:
+			NG_MKRESPONSE(resp, msg, sizeof(u_int32_t), M_NOWAIT);
+			if (resp == NULL) {
+				error = ENOMEM;
+				break;
 			}
+			(*((u_int32_t *)resp->data)) = priv->vlan_encap;
+			break;
+		case NGM_VLAN_SET_ENCAP:
+			if (msg->header.arglen != sizeof(u_int32_t)) {
+				error = EINVAL;
+				break;
+			}
+			priv->vlan_encap = ((*((u_int32_t *)msg->data)) != 0);
 			break;
 		default:		/* Unknown command. */
 			error = EINVAL;
@@ -302,8 +312,6 @@
 	case NGM_FLOW_COOKIE:
 	    {
 		struct ng_mesg *copy;
-		struct filterhead *chain;
-		struct filter *f;
 
 		/*
 		 * Flow control messages should come only
@@ -316,15 +324,15 @@
 			break;
 
 		/* Broadcast the event to all uplinks. */
-		for (i = 0, chain = priv->hashtable; i < HASHSIZE;
-		    i++, chain++)
-		LIST_FOREACH(f, chain, next) {
+		for (vlan = 0; vlan < (EVL_VLID_MASK + 1); vlan ++) {
+			if (priv->vlan_hook[vlan] == NULL)
+				continue;
+
 			NG_COPYMESSAGE(copy, msg, M_NOWAIT);
 			if (copy == NULL)
-				continue;
-			NG_SEND_MSG_HOOK(error, node, copy, f->hook, 0);
+					continue;
+			NG_SEND_MSG_HOOK(error, node, copy, priv->vlan_hook[vlan], 0);
 		}
-
 		break;
 	    }
 	default:			/* Unknown type cookie. */
@@ -343,9 +351,9 @@
 	struct ether_header *eh;
 	struct ether_vlan_header *evl = NULL;
 	int error;
-	u_int16_t vlan;
+	uintptr_t vlan;
 	struct mbuf *m;
-	struct filter *f;
+	hook_p vlan_hook;
 
 	/* Make sure we have an entire header. */
 	NGI_GET_M(item, m);
@@ -360,6 +368,7 @@
 		 * If from downstream, select between a match hook
 		 * or the nomatch hook.
 		 */
+		vlan_hook = priv->nomatch_hook;
 		if (m->m_flags & M_VLANTAG ||
 		    eh->ether_type == htons(ETHERTYPE_VLAN)) {
 			if (m->m_flags & M_VLANTAG) {
@@ -377,25 +386,20 @@
 				evl = mtod(m, struct ether_vlan_header *);
 				vlan = EVL_VLANOFTAG(ntohs(evl->evl_tag));
 			}
-			if ((f = ng_vlan_findentry(priv, vlan)) != NULL) {
+
+			if (priv->vlan_hook[vlan] != NULL) {
+				vlan_hook = priv->vlan_hook[vlan];
 				if (m->m_flags & M_VLANTAG) {
 					m->m_pkthdr.ether_vtag = 0;
 					m->m_flags &= ~M_VLANTAG;
 				} else {
-					evl->evl_encap_proto = evl->evl_proto;
-					bcopy(mtod(m, caddr_t),
-					    mtod(m, caddr_t) +
-					    ETHER_VLAN_ENCAP_LEN,
-					    ETHER_HDR_LEN);
+					bcopy((char *)evl, (char *)evl + ETHER_VLAN_ENCAP_LEN,
+						(ETHER_HDR_LEN - ETHER_TYPE_LEN));
 					m_adj(m, ETHER_VLAN_ENCAP_LEN);
 				}
 			}
-		} else
-			f = NULL;
-		if (f != NULL)
-			NG_FWD_NEW_DATA(error, item, f->hook, m);
-		else
-			NG_FWD_NEW_DATA(error, item, priv->nomatch_hook, m);
+		}
+		NG_FWD_NEW_DATA(error, item, vlan_hook, m);
 	} else {
 		/*
 		 * It is heading towards the downstream.
@@ -403,28 +407,35 @@
 		 * Otherwise, do the VLAN encapsulation.
 		 */
 		if (hook != priv->nomatch_hook) {
-			if ((f = NG_HOOK_PRIVATE(hook)) == NULL) {
+			vlan = (uintptr_t)NG_HOOK_PRIVATE(hook);
+			if ((vlan & HOOK_VLAN_SET_MASK) != HOOK_VLAN_SET_MASK) {
 				NG_FREE_ITEM(item);
 				NG_FREE_M(m);
 				return (EOPNOTSUPP);
 			}
-			M_PREPEND(m, ETHER_VLAN_ENCAP_LEN, M_DONTWAIT);
-			/* M_PREPEND takes care of m_len and m_pkthdr.len. */
-			if (m == NULL || (m->m_len < sizeof(*evl) &&
-			    (m = m_pullup(m, sizeof(*evl))) == NULL)) {
-				NG_FREE_ITEM(item);
-				return (ENOMEM);
+			vlan &= EVL_VLID_MASK; /* remove HOOK_VLAN_SET_MASK from vlan num */
+			
+			if (priv->vlan_encap == 0) {
+				m->m_flags |= M_VLANTAG;
+				m->m_pkthdr.ether_vtag = vlan;
+			} else {
+				M_PREPEND(m, ETHER_VLAN_ENCAP_LEN, M_DONTWAIT);
+				/* M_PREPEND takes care of m_len and m_pkthdr.len. */
+				if (m == NULL || (m->m_len < sizeof(*evl) &&
+				    (m = m_pullup(m, sizeof(*evl))) == NULL)) {
+					NG_FREE_ITEM(item);
+					return (ENOMEM);
+				}
+				/*
+				 * Transform the Ethernet header into an Ethernet header
+				 * with 802.1Q encapsulation.
+				 */
+				evl = mtod(m, struct ether_vlan_header *);
+				bcopy((char *)evl + ETHER_VLAN_ENCAP_LEN,
+					(char *)evl, (ETHER_HDR_LEN - ETHER_TYPE_LEN));
+				evl->evl_encap_proto = htons(ETHERTYPE_VLAN);
+				evl->evl_tag = htons(vlan);
 			}
-			/*
-			 * Transform the Ethernet header into an Ethernet header
-			 * with 802.1Q encapsulation.
-			 */
-			bcopy(mtod(m, char *) + ETHER_VLAN_ENCAP_LEN,
-			    mtod(m, char *), ETHER_HDR_LEN);
-			evl = mtod(m, struct ether_vlan_header *);
-			evl->evl_proto = evl->evl_encap_proto;
-			evl->evl_encap_proto = htons(ETHERTYPE_VLAN);
-			evl->evl_tag = htons(f->vlan);
 		}
 		NG_FWD_NEW_DATA(error, item, priv->downstream_hook, m);
 	}
@@ -446,7 +457,7 @@
 ng_vlan_disconnect(hook_p hook)
 {
 	const priv_p priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
-	struct filter *f;
+	uintptr_t vlan;
 
 	if (hook == priv->downstream_hook)
 		priv->downstream_hook = NULL;
@@ -454,11 +465,9 @@
 		priv->nomatch_hook = NULL;
 	else {
 		/* Purge a rule that refers to this hook. */
-		if ((f = NG_HOOK_PRIVATE(hook)) != NULL) {
-			LIST_REMOVE(f, next);
-			priv->nent--;
-			free(f, M_NETGRAPH);
-		}
+		vlan = (uintptr_t)NG_HOOK_PRIVATE(hook);
+		if ((vlan & HOOK_VLAN_SET_MASK) == HOOK_VLAN_SET_MASK)
+			priv->vlan_hook[(vlan & EVL_VLID_MASK)] = NULL;
 	}
 	NG_HOOK_SET_PRIVATE(hook, NULL);
 	if ((NG_NODE_NUMHOOKS(NG_HOOK_NODE(hook)) == 0) &&

Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?4e04c489.d899cc0a.43e4.4ad6>