kern/161908: ng_vlan update for QinQ support
Ivan
rozhuk.im at gmail.com
Sat Oct 22 20:00:28 UTC 2011
>Number: 161908
>Category: kern
>Synopsis: ng_vlan update for QinQ support
>Confidential: no
>Severity: non-critical
>Priority: medium
>Responsible: freebsd-bugs
>State: open
>Quarter:
>Keywords:
>Date-Required:
>Class: update
>Submitter-Id: current-users
>Arrival-Date: Sat Oct 22 20:00:28 UTC 2011
>Closed-Date:
>Last-Modified:
>Originator: Ivan
>Release: FreeBSD 8.2-STABLE
>Organization:
>Environment:
FreeBSD firewall 8.2-STABLE FreeBSD 8.2-STABLE #16: Sat Oct 22 07:46:34 IRKST 2011 root at firewall:/usr/obj/usr/src/sys/RIMx64 amd64
>Description:
+ ethernet_type for VLAN encapsulation is tunable, default is: 0x8100 (33024)
+ PCP (Priority Code Point) and CFI (Canonical Format Indicator) for VLAN encapsulation is tunable per VID
+ VLAN filter can be deleted by VID
+ tunable encapsulation: on - do 802.1Q encapsulation, off - set M_VLANTAG and ether_vtag
* improved encapsulation/decapsulation code
* "vlan" changed to "vid" in "addfilter" and "gettable" messages
* many other canges
kldunload ng_vlan
kldload ng_ether
ngctl msg re0: setpromisc 1
ngctl msg re0: setautosrc 0
ngctl mkpeer re0: vlan lower downstream
ngctl connect re0: re0:lower upper nomatch
ngctl mkpeer re0:lower eiface vlan1001 ether
ngctl mkpeer re0:lower eiface vlan1002 ether
ngctl name re0:lower:vlan1001 ngeth0
ifconfig ngeth0 link 00:1a:4d:55:9a:43
ifconfig ngeth0 inet 192.168.0.36 netmask 255.255.255.0
ngctl name re0:lower:vlan1002 ngeth1
ifconfig ngeth1 link 00:1a:4d:55:9a:44
ifconfig ngeth1 inet 192.168.254.36 netmask 255.255.255.0
ngctl msg re0:lower addfilter '{ vid=1001 hook="vlan1001" }'
ngctl msg re0:lower addfilter '{ vid=1002 pcp=6 cfi=1 hook="vlan1002" }'
# ngctl msg re0:lower gettable
Rec'd response "gettable" (4) from "[156]:":
Args: { n=2 filter=[ { hook="vlan1001" vid=1001 } { hook="vlan1002" vid=1002 pcp=6 cfi=1 } ] }
# ngctl msg re0:lower getencap
Rec'd response "getencap" (5) from "[156]:":
Args: 1
# ngctl msg re0:lower getencapproto
Rec'd response "getencapproto" (7) from "[156]:":
Args: 33024
# ngctl msg re0:lower delvidflt 1001
# ngctl msg re0:lower gettable
Rec'd response "gettable" (4) from "[156]:":
Args: { n=1 filter=[ { hook="vlan1002" vid=1002 pcp=6 cfi=1 } ] }
# ngctl msg re0:lower delfilter '"vlan1002"'
# ngctl msg re0:lower gettable
Rec'd response "gettable" (4) from "[156]:":
Args: {}
NOTE:
1.1 Use "setencap" = 0 with care: node connected to "downstream" must handle M_VLANTAG + ether_vtag. If it ng_ether, then IFCAP_VLAN_HWTAGGING must be enabled on attached network adapter.
1.2 Then "setencap" = 0, "setencapproto" value is ignored and assumed that 0x8100 (M_VLANTAG + ether_vtag - allways encapsulated with tag 0x8100)
2. "addfilter" syntax changed!!!
was:
ngctl msg re0:lower addfilter '{ vlan=1001 hook="vlan1001" }'
now:
ngctl msg re0:lower addfilter '{ vid=1001 hook="vlan1001" }'
ngctl msg re0:lower addfilter '{ vid=1001 hook="vlan1001" pcp=0 cfi=0 }'
(equivalent)
3. Trick:
kern.ipc.max_linkhdr should be increased via sysctl for best perfomance:
20 - 1 VLAN tag (.Q)
24 - 2 VLAN tags (QinQ)
28 - 3 VLAN tags (QinQinQ)
32 - 4 VLAN tags (...)
>How-To-Repeat:
>Fix:
Patch attached with submission follows:
--- /usr/src/sys/netgraph/ng_vlan.c.orig 2009-08-03 17:13:06.000000000 +0900
+++ /usr/src/sys/netgraph/ng_vlan.c 2011-10-23 03:41:00.000000000 +0900
@@ -1,5 +1,6 @@
/*-
* Copyright (c) 2003 IPNET Internet Communication Company
+ * Copyright (c) 2011 Rozhuk Ivan <rozhuk.im at gmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -46,6 +47,22 @@
#include <netgraph/ng_vlan.h>
#include <netgraph/netgraph.h>
+
+
+struct ng_vlan_private {
+ hook_p downstream_hook;
+ hook_p nomatch_hook;
+ int encap_enable;
+ u_int16_t encap_proto;
+ hook_p vlan_hook[(EVL_VLID_MASK + 1)];
+};
+typedef struct ng_vlan_private *priv_p;
+
+#define VLAN_TAG_MASK 0xFFFF
+#define HOOK_VLAN_TAG_SET_MASK ((uintptr_t)((~0) & ~(VLAN_TAG_MASK)))
+#define IS_HOOK_VLAN_SET(hook_data) ((((uintptr_t)hook_data) & HOOK_VLAN_TAG_SET_MASK) == HOOK_VLAN_TAG_SET_MASK)
+
+
static ng_constructor_t ng_vlan_constructor;
static ng_rcvmsg_t ng_vlan_rcvmsg;
static ng_shutdown_t ng_vlan_shutdown;
@@ -105,11 +122,46 @@
},
{
NGM_VLAN_COOKIE,
+ NGM_VLAN_DEL_VID_FLT,
+ "delvidflt",
+ &ng_parse_int16_type,
+ NULL
+ },
+ {
+ NGM_VLAN_COOKIE,
NGM_VLAN_GET_TABLE,
"gettable",
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
+ },
+ {
+ NGM_VLAN_COOKIE,
+ NGM_VLAN_GET_ENCAP_PROTO,
+ "getencapproto",
+ NULL,
+ &ng_parse_int32_type
+ },
+ {
+ NGM_VLAN_COOKIE,
+ NGM_VLAN_SET_ENCAP_PROTO,
+ "setencapproto",
+ &ng_parse_int32_type,
+ NULL
+ },
{ 0 }
};
@@ -126,47 +178,43 @@
};
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;
-} *priv_p;
+//************************************************************************
+// HELPER STUFF
+//************************************************************************
-static struct filter *
-ng_vlan_findentry(priv_p priv, u_int16_t vlan)
+static __inline int
+m_chk(struct mbuf **mp, int len)
{
- struct filterhead *chain = &priv->hashtable[HASH(vlan)];
- struct filter *f;
+ if ((*mp)->m_pkthdr.len < len) {
+ m_freem((*mp));
+ (*mp) = NULL;
+ return (EINVAL);
+ }
+ if ((*mp)->m_len < len && ((*mp) = m_pullup((*mp), len)) == NULL)
+ return (ENOBUFS);
- LIST_FOREACH(f, chain, next)
- if (f->vlan == vlan)
- return (f);
- return (NULL);
+return (0);
}
+//************************************************************************
+// NETGRAPH NODE STUFF
+//************************************************************************
+
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]);
+ priv->encap_enable = 1;
+ priv->encap_proto = htons(ETHERTYPE_VLAN);
+
NG_NODE_SET_PRIVATE(node, priv);
+
return (0);
}
@@ -193,13 +241,14 @@
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 hook_data;
+ int i, vlan_count;
+ u_int16_t vid;
+ int error = 0;
NGI_GET_MSG(item, msg);
/* Deal with message according to cookie and command. */
@@ -214,12 +263,12 @@
}
vf = (struct ng_vlan_filter *)msg->data;
/* Sanity check the VLAN ID value. */
- if (vf->vlan & ~EVL_VLID_MASK) {
+ if (vf->vid & ~EVL_VLID_MASK || vf->pcp & ~7 || vf->cfi & ~1) {
error = EINVAL;
break;
}
/* Check that a referenced hook exists. */
- hook = ng_findhook(node, vf->hook);
+ hook = ng_findhook(node, vf->hook_name);
if (hook == NULL) {
error = ENOENT;
break;
@@ -231,30 +280,18 @@
break;
}
/* And is not already in service. */
- if (NG_HOOK_PRIVATE(hook) != NULL) {
+ if (IS_HOOK_VLAN_SET(NG_HOOK_PRIVATE(hook))) {
error = EEXIST;
break;
}
/* Check we don't already trap this VLAN. */
- if (ng_vlan_findentry(priv, vf->vlan)) {
+ if (priv->vlan_hook[vf->vid] != 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. */
+ NG_HOOK_SET_PRIVATE(hook, (void *)(HOOK_VLAN_TAG_SET_MASK | EVL_MAKETAG(vf->vid, vf->pcp, vf->cfi)));
+ priv->vlan_hook[vf->vid] = hook;
break;
case NGM_VLAN_DEL_FILTER:
/* Check that message is long enough. */
@@ -264,35 +301,125 @@
}
/* 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;
+ }
+ hook_data = (uintptr_t)NG_HOOK_PRIVATE(hook);
+ if (IS_HOOK_VLAN_SET(hook_data) == 0) {
+ error = ENOENT;
+ break;
+ }
+#ifdef NETGRAPH_DEBUG
+ if (priv->vlan_hook[EVL_VLANOFTAG(hook_data)] != hook)
+ printf("%s: NGM_VLAN_DEL_FILTER: Invalid VID for Hook = %s\n", __func__, (char *)msg->data);
+#endif
+ /* Purge a rule that refers to this hook. */
+ priv->vlan_hook[EVL_VLANOFTAG(hook_data)] = NULL;
+ NG_HOOK_SET_PRIVATE(hook, NULL);
+ break;
+ case NGM_VLAN_DEL_VID_FLT:
+ /* Check that message is long enough. */
+ if (msg->header.arglen != sizeof(u_int16_t)) {
+ error = EINVAL;
+ break;
+ }
+ vid = (*((u_int16_t *)msg->data));
+ /* Sanity check the VLAN ID value. */
+ if (vid & ~EVL_VLID_MASK) {
+ error = EINVAL;
+ break;
+ }
+ /* Check that hook exists and is active. */
+ hook = priv->vlan_hook[vid];
+ if (hook == NULL) {
+ error = ENOENT;
+ break;
+ }
+ hook_data = (uintptr_t)NG_HOOK_PRIVATE(hook);
+ if (IS_HOOK_VLAN_SET(hook_data) == 0) {
error = ENOENT;
break;
}
+#ifdef NETGRAPH_DEBUG
+ if (EVL_VLANOFTAG(hook_data) != vid)
+ printf("%s: NGM_VLAN_DEL_VID_FLT: Invalid VID Hook = %us, must be: %us\n", __func__, (u_int16_t)EVL_VLANOFTAG(hook_data), vid);
+#endif
/* Purge a rule that refers to this hook. */
+ priv->vlan_hook[vid] = NULL;
NG_HOOK_SET_PRIVATE(hook, NULL);
- LIST_REMOVE(f, next);
- priv->nent--;
- free(f, M_NETGRAPH);
break;
case NGM_VLAN_GET_TABLE:
+ /* calculate vlans */
+ vlan_count = 0;
+ for (i = 0; i < (EVL_VLID_MASK + 1); i ++) {
+ if (priv->vlan_hook[i] != NULL
+ && NG_HOOK_IS_VALID(priv->vlan_hook[i]))
+ 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 = 0;
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 (i = 0; i < (EVL_VLID_MASK + 1); i ++) {
+ hook = priv->vlan_hook[i];
+ if (hook == NULL
+ || NG_HOOK_NOT_VALID(hook))
+ continue;
+ hook_data = (uintptr_t)NG_HOOK_PRIVATE(hook);
+ if (IS_HOOK_VLAN_SET(hook_data) == 0)
+ continue;
+#ifdef NETGRAPH_DEBUG
+ if (EVL_VLANOFTAG(hook_data) != i)
+ printf("%s: NGM_VLAN_GET_TABLE: hook %s VID = %us, must be: %i\n", __func__, NG_HOOK_NAME(hook), (u_int16_t)EVL_VLANOFTAG(hook_data), i);
+#endif
+ vf->vid = i;
+ vf->pcp = EVL_PRIOFTAG(hook_data);
+ vf->cfi = EVL_CFIOFTAG(hook_data);
+ strncpy(vf->hook_name, NG_HOOK_NAME(hook),
NG_HOOKSIZ);
- vf++;
- }
+ vf ++;
+ t->n ++;
+ }
+ 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->encap_enable;
+ break;
+ case NGM_VLAN_SET_ENCAP:
+ if (msg->header.arglen != sizeof(u_int32_t)) {
+ error = EINVAL;
+ break;
+ }
+ priv->encap_enable = ((*((u_int32_t *)msg->data)) != 0);
+ break;
+ case NGM_VLAN_GET_ENCAP_PROTO:
+ NG_MKRESPONSE(resp, msg, sizeof(u_int16_t), M_NOWAIT);
+ if (resp == NULL) {
+ error = ENOMEM;
+ break;
+ }
+ (*((u_int16_t *)resp->data)) = ntohs(priv->encap_proto);
+ break;
+ case NGM_VLAN_SET_ENCAP_PROTO:
+ if (msg->header.arglen != sizeof(u_int16_t)) {
+ error = EINVAL;
+ break;
}
+ priv->encap_proto = htons((*((u_int16_t *)msg->data)));
break;
default: /* Unknown command. */
error = EINVAL;
@@ -302,8 +429,6 @@
case NGM_FLOW_COOKIE:
{
struct ng_mesg *copy;
- struct filterhead *chain;
- struct filter *f;
/*
* Flow control messages should come only
@@ -314,17 +439,16 @@
break;
if (lasthook != priv->downstream_hook)
break;
-
/* Broadcast the event to all uplinks. */
- for (i = 0, chain = priv->hashtable; i < HASHSIZE;
- i++, chain++)
- LIST_FOREACH(f, chain, next) {
+ for (i = 0; i < (EVL_VLID_MASK + 1); i ++) {
+ if (priv->vlan_hook[i] == 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[i], 0);
}
-
break;
}
default: /* Unknown type cookie. */
@@ -343,16 +467,19 @@
struct ether_header *eh;
struct ether_vlan_header *evl = NULL;
int error;
- u_int16_t vlan;
+ uintptr_t hook_data;
+ u_int16_t vid;
struct mbuf *m;
- struct filter *f;
+ hook_p dst_hook;
+
- /* Make sure we have an entire header. */
NGI_GET_M(item, m);
- if (m->m_len < sizeof(*eh) &&
- (m = m_pullup(m, sizeof(*eh))) == NULL) {
+
+ /* Make sure we have an entire header. */
+ error = m_chk(&m, ETHER_HDR_LEN);
+ if (error != 0) {
NG_FREE_ITEM(item);
- return (EINVAL);
+ return (error);
}
eh = mtod(m, struct ether_header *);
if (hook == priv->downstream_hook) {
@@ -360,75 +487,104 @@
* If from downstream, select between a match hook
* or the nomatch hook.
*/
+ dst_hook = priv->nomatch_hook;
if (m->m_flags & M_VLANTAG ||
- eh->ether_type == htons(ETHERTYPE_VLAN)) {
+ eh->ether_type == priv->encap_proto) {
if (m->m_flags & M_VLANTAG) {
/*
* Packet is tagged, m contains a normal
* Ethernet frame; tag is stored out-of-band.
*/
- vlan = EVL_VLANOFTAG(m->m_pkthdr.ether_vtag);
- } else {
- if (m->m_len < sizeof(*evl) &&
- (m = m_pullup(m, sizeof(*evl))) == NULL) {
+ vid = EVL_VLANOFTAG(m->m_pkthdr.ether_vtag);
+ } else { /* eh->ether_type == priv->encap_proto */
+ error = m_chk(&m, (ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN));
+ if (error != 0) {
NG_FREE_ITEM(item);
- return (EINVAL);
+ return (error);
}
evl = mtod(m, struct ether_vlan_header *);
- vlan = EVL_VLANOFTAG(ntohs(evl->evl_tag));
+ vid = EVL_VLANOFTAG(ntohs(evl->evl_tag));
}
- if ((f = ng_vlan_findentry(priv, vlan)) != NULL) {
+
+ if (priv->vlan_hook[vid] != NULL) {
+ dst_hook = priv->vlan_hook[vid];
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);
+ /*
+ * move DstMAC and SrcMAC to ETHER_TYPE
+ * before: [dst_mac] [src_mac] [ether_type_encap(TPID)] [PCP/CFI/VID] [ether_type] [payload]
+ * |-----------------| >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> |---------------------|
+ * after: [free space] [dst_mac] [src_mac] [ether_type] [payload]
+ * |-----------------| |---------------------|
+ */
+ bcopy((char *)evl, ((char *)evl + ETHER_VLAN_ENCAP_LEN),
+ (ETHER_ADDR_LEN * 2));
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);
+ }
} else {
/*
* It is heading towards the downstream.
* If from nomatch, pass it unmodified.
* Otherwise, do the VLAN encapsulation.
*/
- if (hook != priv->nomatch_hook) {
- if ((f = NG_HOOK_PRIVATE(hook)) == NULL) {
+ dst_hook = priv->downstream_hook;
+ if (dst_hook != NULL && hook != priv->nomatch_hook) {
+ hook_data = (uintptr_t)NG_HOOK_PRIVATE(hook);
+ if (IS_HOOK_VLAN_SET(hook_data) == 0) {
+ m_freem(m);
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);
+ if (priv->encap_enable == 0) {
+ /* just set packet header tag */
+ m->m_flags |= M_VLANTAG;
+ m->m_pkthdr.ether_vtag = (hook_data & VLAN_TAG_MASK);
+ } else {
+ /*
+ * Transform the Ethernet header into an Ethernet header
+ * with 802.1Q encapsulation.
+ * mod of: ether_vlanencap
+ */
+ M_PREPEND(m, ETHER_VLAN_ENCAP_LEN, M_DONTWAIT);
+ /* M_PREPEND takes care of m_len and m_pkthdr.len. */
+ if (m == NULL)
+ error = ENOMEM;
+ else
+ error = m_chk(&m, (ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN));
+ if (error != 0) {
+ NG_FREE_ITEM(item);
+ return (error);
+ }
+ /* move DstMAC and SrcMAC from ETHER_TYPE
+ * before: [free - prepended space] [dst_mac] [src_mac] [ether_type] [payload]
+ * <<<<<<<<<<<<<<<<<<<<<< |-----------------| |--------------------|
+ * after: [dst_mac] [src_mac] [ether_type_encap(TPID)] [PCP/CFI/VID] [ether_type] [payload]
+ * |-----------------| |----------- inserted tag -----------| |--------------------|
+ */
+ evl = mtod(m, struct ether_vlan_header *);
+ bcopy(((char *)evl + ETHER_VLAN_ENCAP_LEN),
+ (char *)evl, (ETHER_ADDR_LEN * 2));
+ evl->evl_encap_proto = priv->encap_proto;
+ evl->evl_tag = htons((hook_data & VLAN_TAG_MASK));
}
- /*
- * 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);
}
- return (error);
+
+ /* send packet */
+ if (dst_hook != NULL) {
+ NG_FWD_NEW_DATA(error, item, dst_hook, m);
+ return (error);
+ }
+
+ /* no hook to send */
+ m_freem(m);
+ NG_FREE_ITEM(item);
+
+ return (ENETDOWN);
}
static int
@@ -446,7 +602,7 @@
ng_vlan_disconnect(hook_p hook)
{
const priv_p priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
- struct filter *f;
+ uintptr_t hook_data;
if (hook == priv->downstream_hook)
priv->downstream_hook = NULL;
@@ -454,11 +610,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);
- }
+ hook_data = (uintptr_t)NG_HOOK_PRIVATE(hook);
+ if (IS_HOOK_VLAN_SET(hook_data) == 0)
+ priv->vlan_hook[EVL_VLANOFTAG(hook_data)] = NULL;
}
NG_HOOK_SET_PRIVATE(hook, NULL);
if ((NG_NODE_NUMHOOKS(NG_HOOK_NODE(hook)) == 0) &&
--- /usr/src/sys/netgraph/ng_vlan.h.orig 2009-08-03 17:13:06.000000000 +0900
+++ /usr/src/sys/netgraph/ng_vlan.h 2011-10-22 19:11:01.000000000 +0900
@@ -1,5 +1,6 @@
/*-
* Copyright (c) 2003 IPNET Internet Communication Company
+ * Copyright (c) 2011 Rozhuk Ivan <rozhuk.im at gmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -43,19 +44,28 @@
enum {
NGM_VLAN_ADD_FILTER = 1,
NGM_VLAN_DEL_FILTER,
- NGM_VLAN_GET_TABLE
+ NGM_VLAN_DEL_VID_FLT,
+ NGM_VLAN_GET_TABLE,
+ NGM_VLAN_GET_ENCAP,
+ NGM_VLAN_SET_ENCAP,
+ NGM_VLAN_GET_ENCAP_PROTO,
+ NGM_VLAN_SET_ENCAP_PROTO,
};
/* For NGM_VLAN_ADD_FILTER control message. */
struct ng_vlan_filter {
- char hook[NG_HOOKSIZ];
- u_int16_t vlan;
-};
+ char hook_name[NG_HOOKSIZ];
+ u_int16_t vid; /* VID - VLAN Identifier */
+ u_int8_t pcp; /* PCP - Priority Code Point */
+ u_int8_t cfi; /* CFI - Canonical Format Indicator */
+};
/* Keep this in sync with the above structure definition. */
#define NG_VLAN_FILTER_FIELDS { \
- { "hook", &ng_parse_hookbuf_type }, \
- { "vlan", &ng_parse_uint16_type }, \
+ { "hook", &ng_parse_hookbuf_type }, \
+ { "vid", &ng_parse_uint16_type }, \
+ { "pcp", &ng_parse_uint8_type }, \
+ { "cfi", &ng_parse_uint8_type }, \
{ NULL } \
}
>Release-Note:
>Audit-Trail:
>Unformatted:
More information about the freebsd-bugs
mailing list