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>
