* [PATCH RFC 0/2] Multiple VLAN Registration Protocol (IEEE 802.1Q-2011)
@ 2012-09-24 21:07 David Ward
2012-09-24 21:07 ` [PATCH RFC 1/2] net/802: Implement Multiple Registration Protocol (MRP) David Ward
` (3 more replies)
0 siblings, 4 replies; 6+ messages in thread
From: David Ward @ 2012-09-24 21:07 UTC (permalink / raw)
To: netdev; +Cc: Patrick McHardy, Eric Dumazet, Philip Foulkes, David Ward
The Linux kernel currently implements the GARP VLAN Registration
Protocol (GVRP) from IEEE 802.1Q-1998 (applicant-only participant).
When the GVRP flag is set for a VLAN interface on a Linux host, the
host advertises its membership in the VLAN to the attached bridge/
switch, so that it is not necessary to manually configure the bridge/
switch port to participate in the VLAN.
GVRP has been superseded by the Multiple VLAN Registration Protocol
(MVRP) in IEEE 802.1Q-2011, which addresses scalability concerns about
the earlier protocol. The following patches add support for MVRP to
the Linux kernel and iproute2 utility. They are based largely off of
the existing implementation of GVRP, but have been modified for the
new PDU structure and state machine.
Please let me know if you have any comments. This implementation was
tested with two Juniper EX4200 switches and found to work as expected.
If you have access to other switches that implement MVRP, I would of
course welcome additional testing.
Signed-off-by: David Ward <david.ward@ll.mit.edu>
David Ward (2):
net/802: Implement Multiple Registration Protocol (MRP)
net/8021q: Implement Multiple VLAN Registration Protocol (MVRP)
include/linux/if_ether.h | 1 +
include/linux/if_vlan.h | 1 +
include/linux/netdevice.h | 2 +
include/net/mrp.h | 142 ++++++++
net/802/Kconfig | 3 +
net/802/Makefile | 1 +
net/802/mrp.c | 872 +++++++++++++++++++++++++++++++++++++++++++++
net/8021q/Kconfig | 11 +
net/8021q/Makefile | 1 +
net/8021q/vlan.c | 27 ++-
net/8021q/vlan.h | 16 +
net/8021q/vlan_dev.c | 12 +-
net/8021q/vlan_mvrp.c | 72 ++++
net/8021q/vlan_netlink.c | 2 +-
14 files changed, 1156 insertions(+), 7 deletions(-)
create mode 100644 include/net/mrp.h
create mode 100644 net/802/mrp.c
create mode 100644 net/8021q/vlan_mvrp.c
--
1.7.4.1
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH RFC 1/2] net/802: Implement Multiple Registration Protocol (MRP)
2012-09-24 21:07 [PATCH RFC 0/2] Multiple VLAN Registration Protocol (IEEE 802.1Q-2011) David Ward
@ 2012-09-24 21:07 ` David Ward
2012-09-24 21:36 ` Eric Dumazet
2012-09-24 21:07 ` [PATCH RFC 2/2] net/8021q: Implement Multiple VLAN Registration Protocol (MVRP) David Ward
` (2 subsequent siblings)
3 siblings, 1 reply; 6+ messages in thread
From: David Ward @ 2012-09-24 21:07 UTC (permalink / raw)
To: netdev; +Cc: Patrick McHardy, Eric Dumazet, Philip Foulkes, David Ward
Initial implementation of the Multiple Registration Protocol (MRP)
from IEEE 802.1Q-2011, based on the existing implementation of the
Generic Attribute Registration Protocol (GARP).
Signed-off-by: David Ward <david.ward@ll.mit.edu>
---
include/linux/netdevice.h | 2 +
include/net/mrp.h | 142 ++++++++
net/802/Kconfig | 3 +
net/802/Makefile | 1 +
net/802/mrp.c | 872 +++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 1020 insertions(+), 0 deletions(-)
create mode 100644 include/net/mrp.h
create mode 100644 net/802/mrp.c
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 6c131f0..704da15 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -1289,6 +1289,8 @@ struct net_device {
};
/* GARP */
struct garp_port __rcu *garp_port;
+ /* MRP */
+ struct mrp_port __rcu *mrp_port;
/* class/net/name entry */
struct device dev;
diff --git a/include/net/mrp.h b/include/net/mrp.h
new file mode 100644
index 0000000..69677d9
--- /dev/null
+++ b/include/net/mrp.h
@@ -0,0 +1,142 @@
+#ifndef _NET_MRP_H
+#define _NET_MRP_H
+
+#define MRP_END_MARK 0x0
+
+struct mrp_pdu_hdr {
+ u8 version;
+};
+
+struct mrp_msg_hdr {
+ u8 attrtype;
+ u8 attrlen;
+};
+
+struct mrp_vecattr_hdr {
+ __be16 lenflags;
+ unsigned char firstattrvalue[];
+#define MRP_VECATTR_HDR_LEN_MASK cpu_to_be16(0x1FFF)
+#define MRP_VECATTR_HDR_FLAG_LA cpu_to_be16(0x2000)
+};
+
+enum mrp_vecattr_event {
+ MRP_NEW,
+ MRP_JOIN_IN,
+ MRP_IN,
+ MRP_JOIN_MT,
+ MRP_MT,
+ MRP_LV,
+};
+
+struct mrp_skb_cb {
+ struct mrp_msg_hdr *mh;
+ struct mrp_vecattr_hdr *vah;
+ unsigned char attrvalue[];
+};
+
+static inline struct mrp_skb_cb *mrp_cb(struct sk_buff *skb)
+{
+ BUILD_BUG_ON(sizeof(struct mrp_skb_cb) >
+ FIELD_SIZEOF(struct sk_buff, cb));
+ return (struct mrp_skb_cb *)skb->cb;
+}
+
+enum mrp_applicant_state {
+ MRP_APPLICANT_INVALID,
+ MRP_APPLICANT_VO,
+ MRP_APPLICANT_VP,
+ MRP_APPLICANT_VN,
+ MRP_APPLICANT_AN,
+ MRP_APPLICANT_AA,
+ MRP_APPLICANT_QA,
+ MRP_APPLICANT_LA,
+ MRP_APPLICANT_AO,
+ MRP_APPLICANT_QO,
+ MRP_APPLICANT_AP,
+ MRP_APPLICANT_QP,
+ __MRP_APPLICANT_MAX
+};
+#define MRP_APPLICANT_MAX (__MRP_APPLICANT_MAX - 1)
+
+enum mrp_event {
+ MRP_EVENT_NEW,
+ MRP_EVENT_JOIN,
+ MRP_EVENT_LV,
+ MRP_EVENT_TX,
+ MRP_EVENT_R_NEW,
+ MRP_EVENT_R_JOIN_IN,
+ MRP_EVENT_R_IN,
+ MRP_EVENT_R_JOIN_MT,
+ MRP_EVENT_R_MT,
+ MRP_EVENT_R_LV,
+ MRP_EVENT_R_LA,
+ MRP_EVENT_REDECLARE,
+ MRP_EVENT_PERIODIC,
+ __MRP_EVENT_MAX
+};
+#define MRP_EVENT_MAX (__MRP_EVENT_MAX - 1)
+
+enum mrp_tx_action {
+ MRP_TX_ACTION_NONE,
+ MRP_TX_ACTION_S_NEW,
+ MRP_TX_ACTION_S_JOIN_IN,
+ MRP_TX_ACTION_S_JOIN_IN_OPTIONAL,
+ MRP_TX_ACTION_S_IN_OPTIONAL,
+ MRP_TX_ACTION_S_LV,
+};
+
+struct mrp_attr {
+ struct rb_node node;
+ enum mrp_applicant_state state;
+ u8 type;
+ u8 len;
+ unsigned char value[];
+};
+
+enum mrp_applications {
+ MRP_APPLICATION_MVRP,
+ __MRP_APPLICATION_MAX
+};
+#define MRP_APPLICATION_MAX (__MRP_APPLICATION_MAX - 1)
+
+struct mrp_application {
+ enum mrp_applications type;
+ unsigned int maxattr;
+ struct packet_type pkttype;
+ unsigned char group_address[ETH_ALEN];
+ u8 version;
+};
+
+struct mrp_applicant {
+ struct mrp_application *app;
+ struct net_device *dev;
+ struct timer_list join_timer;
+
+ spinlock_t lock;
+ struct sk_buff_head queue;
+ struct sk_buff *pdu;
+ struct rb_root mad;
+ struct rcu_head rcu;
+};
+
+struct mrp_port {
+ struct mrp_applicant __rcu *applicants[MRP_APPLICATION_MAX + 1];
+ struct rcu_head rcu;
+};
+
+extern int mrp_register_application(struct mrp_application *app);
+extern void mrp_unregister_application(struct mrp_application *app);
+
+extern int mrp_init_applicant(struct net_device *dev,
+ struct mrp_application *app);
+extern void mrp_uninit_applicant(struct net_device *dev,
+ struct mrp_application *app);
+
+extern int mrp_request_join(const struct net_device *dev,
+ const struct mrp_application *app,
+ const void *value, u8 len, u8 type);
+extern void mrp_request_leave(const struct net_device *dev,
+ const struct mrp_application *app,
+ const void *value, u8 len, u8 type);
+
+#endif /* _NET_MRP_H */
diff --git a/net/802/Kconfig b/net/802/Kconfig
index be33d27..80d4bf7 100644
--- a/net/802/Kconfig
+++ b/net/802/Kconfig
@@ -5,3 +5,6 @@ config STP
config GARP
tristate
select STP
+
+config MRP
+ tristate
diff --git a/net/802/Makefile b/net/802/Makefile
index a30d6e3..37e654d 100644
--- a/net/802/Makefile
+++ b/net/802/Makefile
@@ -11,3 +11,4 @@ obj-$(CONFIG_IPX) += p8022.o psnap.o p8023.o
obj-$(CONFIG_ATALK) += p8022.o psnap.o
obj-$(CONFIG_STP) += stp.o
obj-$(CONFIG_GARP) += garp.o
+obj-$(CONFIG_MRP) += mrp.o
diff --git a/net/802/mrp.c b/net/802/mrp.c
new file mode 100644
index 0000000..dddc3e0
--- /dev/null
+++ b/net/802/mrp.c
@@ -0,0 +1,872 @@
+/*
+ * IEEE 802.1Q Multiple Registration Protocol (MRP)
+ *
+ * Copyright (c) 2012 Massachusetts Institute of Technology
+ *
+ * Adapted from code in net/802/garp.c
+ * Copyright (c) 2008 Patrick McHardy <kaber@trash.net>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ */
+#include <linux/kernel.h>
+#include <linux/timer.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/rtnetlink.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <net/mrp.h>
+#include <asm/unaligned.h>
+
+static unsigned int mrp_join_time __read_mostly = 200;
+module_param(mrp_join_time, uint, 0644);
+MODULE_PARM_DESC(mrp_join_time, "Join time in ms (default 200ms)");
+MODULE_LICENSE("GPL");
+
+static const u8
+mrp_applicant_state_table[MRP_APPLICANT_MAX + 1][MRP_EVENT_MAX + 1] = {
+ [MRP_APPLICANT_VO] = {
+ [MRP_EVENT_NEW] = MRP_APPLICANT_VN,
+ [MRP_EVENT_JOIN] = MRP_APPLICANT_VP,
+ [MRP_EVENT_LV] = MRP_APPLICANT_VO,
+ [MRP_EVENT_TX] = MRP_APPLICANT_VO,
+ [MRP_EVENT_R_NEW] = MRP_APPLICANT_VO,
+ [MRP_EVENT_R_JOIN_IN] = MRP_APPLICANT_AO,
+ [MRP_EVENT_R_IN] = MRP_APPLICANT_VO,
+ [MRP_EVENT_R_JOIN_MT] = MRP_APPLICANT_VO,
+ [MRP_EVENT_R_MT] = MRP_APPLICANT_VO,
+ [MRP_EVENT_R_LV] = MRP_APPLICANT_VO,
+ [MRP_EVENT_R_LA] = MRP_APPLICANT_VO,
+ [MRP_EVENT_REDECLARE] = MRP_APPLICANT_VO,
+ [MRP_EVENT_PERIODIC] = MRP_APPLICANT_VO,
+ },
+ [MRP_APPLICANT_VP] = {
+ [MRP_EVENT_NEW] = MRP_APPLICANT_VN,
+ [MRP_EVENT_JOIN] = MRP_APPLICANT_VP,
+ [MRP_EVENT_LV] = MRP_APPLICANT_VO,
+ [MRP_EVENT_TX] = MRP_APPLICANT_AA,
+ [MRP_EVENT_R_NEW] = MRP_APPLICANT_VP,
+ [MRP_EVENT_R_JOIN_IN] = MRP_APPLICANT_AP,
+ [MRP_EVENT_R_IN] = MRP_APPLICANT_VP,
+ [MRP_EVENT_R_JOIN_MT] = MRP_APPLICANT_VP,
+ [MRP_EVENT_R_MT] = MRP_APPLICANT_VP,
+ [MRP_EVENT_R_LV] = MRP_APPLICANT_VP,
+ [MRP_EVENT_R_LA] = MRP_APPLICANT_VP,
+ [MRP_EVENT_REDECLARE] = MRP_APPLICANT_VP,
+ [MRP_EVENT_PERIODIC] = MRP_APPLICANT_VP,
+ },
+ [MRP_APPLICANT_VN] = {
+ [MRP_EVENT_NEW] = MRP_APPLICANT_VN,
+ [MRP_EVENT_JOIN] = MRP_APPLICANT_VN,
+ [MRP_EVENT_LV] = MRP_APPLICANT_LA,
+ [MRP_EVENT_TX] = MRP_APPLICANT_AN,
+ [MRP_EVENT_R_NEW] = MRP_APPLICANT_VN,
+ [MRP_EVENT_R_JOIN_IN] = MRP_APPLICANT_VN,
+ [MRP_EVENT_R_IN] = MRP_APPLICANT_VN,
+ [MRP_EVENT_R_JOIN_MT] = MRP_APPLICANT_VN,
+ [MRP_EVENT_R_MT] = MRP_APPLICANT_VN,
+ [MRP_EVENT_R_LV] = MRP_APPLICANT_VN,
+ [MRP_EVENT_R_LA] = MRP_APPLICANT_VN,
+ [MRP_EVENT_REDECLARE] = MRP_APPLICANT_VN,
+ [MRP_EVENT_PERIODIC] = MRP_APPLICANT_VN,
+ },
+ [MRP_APPLICANT_AN] = {
+ [MRP_EVENT_NEW] = MRP_APPLICANT_AN,
+ [MRP_EVENT_JOIN] = MRP_APPLICANT_AN,
+ [MRP_EVENT_LV] = MRP_APPLICANT_LA,
+ [MRP_EVENT_TX] = MRP_APPLICANT_QA,
+ [MRP_EVENT_R_NEW] = MRP_APPLICANT_AN,
+ [MRP_EVENT_R_JOIN_IN] = MRP_APPLICANT_AN,
+ [MRP_EVENT_R_IN] = MRP_APPLICANT_AN,
+ [MRP_EVENT_R_JOIN_MT] = MRP_APPLICANT_AN,
+ [MRP_EVENT_R_MT] = MRP_APPLICANT_AN,
+ [MRP_EVENT_R_LV] = MRP_APPLICANT_VN,
+ [MRP_EVENT_R_LA] = MRP_APPLICANT_VN,
+ [MRP_EVENT_REDECLARE] = MRP_APPLICANT_VN,
+ [MRP_EVENT_PERIODIC] = MRP_APPLICANT_AN,
+ },
+ [MRP_APPLICANT_AA] = {
+ [MRP_EVENT_NEW] = MRP_APPLICANT_VN,
+ [MRP_EVENT_JOIN] = MRP_APPLICANT_AA,
+ [MRP_EVENT_LV] = MRP_APPLICANT_LA,
+ [MRP_EVENT_TX] = MRP_APPLICANT_QA,
+ [MRP_EVENT_R_NEW] = MRP_APPLICANT_AA,
+ [MRP_EVENT_R_JOIN_IN] = MRP_APPLICANT_QA,
+ [MRP_EVENT_R_IN] = MRP_APPLICANT_AA,
+ [MRP_EVENT_R_JOIN_MT] = MRP_APPLICANT_AA,
+ [MRP_EVENT_R_MT] = MRP_APPLICANT_AA,
+ [MRP_EVENT_R_LV] = MRP_APPLICANT_VP,
+ [MRP_EVENT_R_LA] = MRP_APPLICANT_VP,
+ [MRP_EVENT_REDECLARE] = MRP_APPLICANT_VP,
+ [MRP_EVENT_PERIODIC] = MRP_APPLICANT_AA,
+ },
+ [MRP_APPLICANT_QA] = {
+ [MRP_EVENT_NEW] = MRP_APPLICANT_VN,
+ [MRP_EVENT_JOIN] = MRP_APPLICANT_QA,
+ [MRP_EVENT_LV] = MRP_APPLICANT_LA,
+ [MRP_EVENT_TX] = MRP_APPLICANT_QA,
+ [MRP_EVENT_R_NEW] = MRP_APPLICANT_QA,
+ [MRP_EVENT_R_JOIN_IN] = MRP_APPLICANT_QA,
+ [MRP_EVENT_R_IN] = MRP_APPLICANT_QA,
+ [MRP_EVENT_R_JOIN_MT] = MRP_APPLICANT_AA,
+ [MRP_EVENT_R_MT] = MRP_APPLICANT_AA,
+ [MRP_EVENT_R_LV] = MRP_APPLICANT_VP,
+ [MRP_EVENT_R_LA] = MRP_APPLICANT_VP,
+ [MRP_EVENT_REDECLARE] = MRP_APPLICANT_VP,
+ [MRP_EVENT_PERIODIC] = MRP_APPLICANT_AA,
+ },
+ [MRP_APPLICANT_LA] = {
+ [MRP_EVENT_NEW] = MRP_APPLICANT_VN,
+ [MRP_EVENT_JOIN] = MRP_APPLICANT_AA,
+ [MRP_EVENT_LV] = MRP_APPLICANT_LA,
+ [MRP_EVENT_TX] = MRP_APPLICANT_VO,
+ [MRP_EVENT_R_NEW] = MRP_APPLICANT_LA,
+ [MRP_EVENT_R_JOIN_IN] = MRP_APPLICANT_LA,
+ [MRP_EVENT_R_IN] = MRP_APPLICANT_LA,
+ [MRP_EVENT_R_JOIN_MT] = MRP_APPLICANT_LA,
+ [MRP_EVENT_R_MT] = MRP_APPLICANT_LA,
+ [MRP_EVENT_R_LV] = MRP_APPLICANT_LA,
+ [MRP_EVENT_R_LA] = MRP_APPLICANT_LA,
+ [MRP_EVENT_REDECLARE] = MRP_APPLICANT_LA,
+ [MRP_EVENT_PERIODIC] = MRP_APPLICANT_LA,
+ },
+ [MRP_APPLICANT_AO] = {
+ [MRP_EVENT_NEW] = MRP_APPLICANT_VN,
+ [MRP_EVENT_JOIN] = MRP_APPLICANT_AP,
+ [MRP_EVENT_LV] = MRP_APPLICANT_AO,
+ [MRP_EVENT_TX] = MRP_APPLICANT_AO,
+ [MRP_EVENT_R_NEW] = MRP_APPLICANT_AO,
+ [MRP_EVENT_R_JOIN_IN] = MRP_APPLICANT_QO,
+ [MRP_EVENT_R_IN] = MRP_APPLICANT_AO,
+ [MRP_EVENT_R_JOIN_MT] = MRP_APPLICANT_AO,
+ [MRP_EVENT_R_MT] = MRP_APPLICANT_AO,
+ [MRP_EVENT_R_LV] = MRP_APPLICANT_VO,
+ [MRP_EVENT_R_LA] = MRP_APPLICANT_VO,
+ [MRP_EVENT_REDECLARE] = MRP_APPLICANT_VO,
+ [MRP_EVENT_PERIODIC] = MRP_APPLICANT_AO,
+ },
+ [MRP_APPLICANT_QO] = {
+ [MRP_EVENT_NEW] = MRP_APPLICANT_VN,
+ [MRP_EVENT_JOIN] = MRP_APPLICANT_QP,
+ [MRP_EVENT_LV] = MRP_APPLICANT_QO,
+ [MRP_EVENT_TX] = MRP_APPLICANT_QO,
+ [MRP_EVENT_R_NEW] = MRP_APPLICANT_QO,
+ [MRP_EVENT_R_JOIN_IN] = MRP_APPLICANT_QO,
+ [MRP_EVENT_R_IN] = MRP_APPLICANT_QO,
+ [MRP_EVENT_R_JOIN_MT] = MRP_APPLICANT_AO,
+ [MRP_EVENT_R_MT] = MRP_APPLICANT_AO,
+ [MRP_EVENT_R_LV] = MRP_APPLICANT_VO,
+ [MRP_EVENT_R_LA] = MRP_APPLICANT_VO,
+ [MRP_EVENT_REDECLARE] = MRP_APPLICANT_VO,
+ [MRP_EVENT_PERIODIC] = MRP_APPLICANT_QO,
+ },
+ [MRP_APPLICANT_AP] = {
+ [MRP_EVENT_NEW] = MRP_APPLICANT_VN,
+ [MRP_EVENT_JOIN] = MRP_APPLICANT_AP,
+ [MRP_EVENT_LV] = MRP_APPLICANT_AO,
+ [MRP_EVENT_TX] = MRP_APPLICANT_QA,
+ [MRP_EVENT_R_NEW] = MRP_APPLICANT_AP,
+ [MRP_EVENT_R_JOIN_IN] = MRP_APPLICANT_QP,
+ [MRP_EVENT_R_IN] = MRP_APPLICANT_AP,
+ [MRP_EVENT_R_JOIN_MT] = MRP_APPLICANT_AP,
+ [MRP_EVENT_R_MT] = MRP_APPLICANT_AP,
+ [MRP_EVENT_R_LV] = MRP_APPLICANT_VP,
+ [MRP_EVENT_R_LA] = MRP_APPLICANT_VP,
+ [MRP_EVENT_REDECLARE] = MRP_APPLICANT_VP,
+ [MRP_EVENT_PERIODIC] = MRP_APPLICANT_AP,
+ },
+ [MRP_APPLICANT_QP] = {
+ [MRP_EVENT_NEW] = MRP_APPLICANT_VN,
+ [MRP_EVENT_JOIN] = MRP_APPLICANT_QP,
+ [MRP_EVENT_LV] = MRP_APPLICANT_QO,
+ [MRP_EVENT_TX] = MRP_APPLICANT_QP,
+ [MRP_EVENT_R_NEW] = MRP_APPLICANT_QP,
+ [MRP_EVENT_R_JOIN_IN] = MRP_APPLICANT_QP,
+ [MRP_EVENT_R_IN] = MRP_APPLICANT_QP,
+ [MRP_EVENT_R_JOIN_MT] = MRP_APPLICANT_AP,
+ [MRP_EVENT_R_MT] = MRP_APPLICANT_AP,
+ [MRP_EVENT_R_LV] = MRP_APPLICANT_VP,
+ [MRP_EVENT_R_LA] = MRP_APPLICANT_VP,
+ [MRP_EVENT_REDECLARE] = MRP_APPLICANT_VP,
+ [MRP_EVENT_PERIODIC] = MRP_APPLICANT_AP,
+ },
+};
+
+static const u8
+mrp_tx_action_table[MRP_APPLICANT_MAX + 1] = {
+ [MRP_APPLICANT_VO] = MRP_TX_ACTION_S_IN_OPTIONAL,
+ [MRP_APPLICANT_VP] = MRP_TX_ACTION_S_JOIN_IN,
+ [MRP_APPLICANT_VN] = MRP_TX_ACTION_S_NEW,
+ [MRP_APPLICANT_AN] = MRP_TX_ACTION_S_NEW,
+ [MRP_APPLICANT_AA] = MRP_TX_ACTION_S_JOIN_IN,
+ [MRP_APPLICANT_QA] = MRP_TX_ACTION_S_JOIN_IN_OPTIONAL,
+ [MRP_APPLICANT_LA] = MRP_TX_ACTION_S_LV,
+ [MRP_APPLICANT_AO] = MRP_TX_ACTION_S_IN_OPTIONAL,
+ [MRP_APPLICANT_QO] = MRP_TX_ACTION_S_IN_OPTIONAL,
+ [MRP_APPLICANT_AP] = MRP_TX_ACTION_S_JOIN_IN,
+ [MRP_APPLICANT_QP] = MRP_TX_ACTION_S_IN_OPTIONAL,
+};
+
+static void mrp_attrvalue_inc(void *value, u8 len)
+{
+ u8 *v = (u8 *)value;
+
+ /* Add 1 to the last byte. If it becomes zero,
+ * go to the previous byte and repeat. */
+ while (len > 0 && !++v[--len])
+ ;
+}
+
+static int mrp_attr_cmp(const struct mrp_attr *attr,
+ const void *value, u8 len, u8 type)
+{
+ if (attr->type != type)
+ return attr->type - type;
+ if (attr->len != len)
+ return attr->len - len;
+ return memcmp(attr->value, value, len);
+}
+
+static struct mrp_attr *mrp_attr_lookup(const struct mrp_applicant *app,
+ const void *value, u8 len, u8 type)
+{
+ struct rb_node *parent = app->mad.rb_node;
+ struct mrp_attr *attr;
+ int d;
+
+ while (parent) {
+ attr = rb_entry(parent, struct mrp_attr, node);
+ d = mrp_attr_cmp(attr, value, len, type);
+ if (d > 0)
+ parent = parent->rb_left;
+ else if (d < 0)
+ parent = parent->rb_right;
+ else
+ return attr;
+ }
+ return NULL;
+}
+
+static struct mrp_attr *mrp_attr_create(struct mrp_applicant *app,
+ const void *value, u8 len, u8 type)
+{
+ struct rb_node *parent = NULL, **p = &app->mad.rb_node;
+ struct mrp_attr *attr;
+ int d;
+
+ while (*p) {
+ parent = *p;
+ attr = rb_entry(parent, struct mrp_attr, node);
+ d = mrp_attr_cmp(attr, value, len, type);
+ if (d > 0)
+ p = &parent->rb_left;
+ else if (d < 0)
+ p = &parent->rb_right;
+ else {
+ /* The attribute already exists; re-use it. */
+ return attr;
+ }
+ }
+ attr = kmalloc(sizeof(*attr) + len, GFP_ATOMIC);
+ if (!attr)
+ return attr;
+ attr->state = MRP_APPLICANT_VO;
+ attr->type = type;
+ attr->len = len;
+ memcpy(attr->value, value, len);
+
+ rb_link_node(&attr->node, parent, p);
+ rb_insert_color(&attr->node, &app->mad);
+ return attr;
+}
+
+static void mrp_attr_destroy(struct mrp_applicant *app, struct mrp_attr *attr)
+{
+ rb_erase(&attr->node, &app->mad);
+ kfree(attr);
+}
+
+static int mrp_pdu_init(struct mrp_applicant *app)
+{
+ struct sk_buff *skb;
+ struct mrp_pdu_hdr *ph;
+
+ skb = alloc_skb(app->dev->mtu + LL_RESERVED_SPACE(app->dev),
+ GFP_ATOMIC);
+ if (!skb)
+ return -ENOMEM;
+
+ skb->dev = app->dev;
+ skb->protocol = app->app->pkttype.type;
+ skb_reserve(skb, LL_RESERVED_SPACE(app->dev));
+ skb_reset_network_header(skb);
+ skb_reset_transport_header(skb);
+
+ ph = (struct mrp_pdu_hdr *)__skb_put(skb, sizeof(*ph));
+ ph->version = app->app->version;
+
+ app->pdu = skb;
+ return 0;
+}
+
+static int mrp_pdu_append_end_mark(struct mrp_applicant *app)
+{
+ __be16 *endmark;
+
+ if (skb_tailroom(app->pdu) < sizeof(*endmark))
+ return -1;
+ endmark = (__be16 *)__skb_put(app->pdu, sizeof(*endmark));
+ put_unaligned(MRP_END_MARK, endmark);
+ return 0;
+}
+
+static void mrp_pdu_queue(struct mrp_applicant *app)
+{
+ if (!app->pdu)
+ return;
+
+ if (mrp_cb(app->pdu)->mh)
+ mrp_pdu_append_end_mark(app);
+ mrp_pdu_append_end_mark(app);
+
+ dev_hard_header(app->pdu, app->dev, ntohs(app->app->pkttype.type),
+ app->app->group_address, app->dev->dev_addr,
+ app->pdu->len);
+
+ skb_queue_tail(&app->queue, app->pdu);
+ app->pdu = NULL;
+}
+
+static void mrp_queue_xmit(struct mrp_applicant *app)
+{
+ struct sk_buff *skb;
+
+ while ((skb = skb_dequeue(&app->queue)))
+ dev_queue_xmit(skb);
+}
+
+static int mrp_pdu_append_msg_hdr(struct mrp_applicant *app,
+ u8 attrtype, u8 attrlen)
+{
+ struct mrp_msg_hdr *mh;
+
+ if (mrp_cb(app->pdu)->mh) {
+ if (mrp_pdu_append_end_mark(app) < 0)
+ return -1;
+ mrp_cb(app->pdu)->mh = NULL;
+ mrp_cb(app->pdu)->vah = NULL;
+ }
+
+ if (skb_tailroom(app->pdu) < sizeof(*mh))
+ return -1;
+ mh = (struct mrp_msg_hdr *)__skb_put(app->pdu, sizeof(*mh));
+ mh->attrtype = attrtype;
+ mh->attrlen = attrlen;
+ mrp_cb(app->pdu)->mh = mh;
+ return 0;
+}
+
+static int mrp_pdu_append_vecattr_hdr(struct mrp_applicant *app,
+ const void *firstattrvalue, u8 attrlen)
+{
+ struct mrp_vecattr_hdr *vah;
+
+ if (skb_tailroom(app->pdu) < sizeof(*vah) + attrlen)
+ return -1;
+ vah = (struct mrp_vecattr_hdr *)__skb_put(app->pdu,
+ sizeof(*vah) + attrlen);
+ put_unaligned(0, &vah->lenflags);
+ memcpy(vah->firstattrvalue, firstattrvalue, attrlen);
+ mrp_cb(app->pdu)->vah = vah;
+ memcpy(mrp_cb(app->pdu)->attrvalue, firstattrvalue, attrlen);
+ return 0;
+}
+
+static int mrp_pdu_append_event(struct mrp_applicant *app,
+ const struct mrp_attr *attr,
+ enum mrp_vecattr_event event)
+{
+ u16 len, pos;
+ u8 *events;
+ int err;
+again:
+ if (!app->pdu) {
+ err = mrp_pdu_init(app);
+ if (err < 0)
+ return err;
+ }
+
+ /* If there is no Message header in the PDU, or the Message header is
+ * for a different attribute type, add an EndMark (if necessary) and a
+ * new Message header to the PDU. */
+ if (!mrp_cb(app->pdu)->mh ||
+ mrp_cb(app->pdu)->mh->attrtype != attr->type ||
+ mrp_cb(app->pdu)->mh->attrlen != attr->len) {
+ if (mrp_pdu_append_msg_hdr(app, attr->type, attr->len) < 0)
+ goto queue;
+ }
+
+ /* If there is no VectorAttribute header for this Message in the PDU,
+ * or this attribute's value does not sequentially follow the previous
+ * attribute's value, add a new VectorAttribute header to the PDU. */
+ if (!mrp_cb(app->pdu)->vah ||
+ memcmp(mrp_cb(app->pdu)->attrvalue, attr->value, attr->len)) {
+ if (mrp_pdu_append_vecattr_hdr(app, attr->value, attr->len) < 0)
+ goto queue;
+ }
+
+ len = be16_to_cpu(get_unaligned(&mrp_cb(app->pdu)->vah->lenflags));
+ pos = len % 3;
+
+ /* Events are packed into Vectors in the PDU, three to a byte. Add a
+ * byte to the end of the Vector if necessary. */
+ if (!pos) {
+ if (skb_tailroom(app->pdu) < sizeof(u8))
+ goto queue;
+ events = (u8 *)__skb_put(app->pdu, sizeof(u8));
+ } else {
+ events = (u8 *)(skb_tail_pointer(app->pdu) - sizeof(u8));
+ }
+
+ switch (pos) {
+ case 0:
+ *events = event * 36;
+ break;
+ case 1:
+ *events += event * 6;
+ break;
+ case 2:
+ *events += event;
+ break;
+ default:
+ WARN_ON(1);
+ }
+
+ /* Increment the length of the VectorAttribute in the PDU, as well as
+ * the value of the next attribute that would continue its Vector. */
+ put_unaligned(cpu_to_be16(++len), &mrp_cb(app->pdu)->vah->lenflags);
+ mrp_attrvalue_inc(mrp_cb(app->pdu)->attrvalue, attr->len);
+
+ return 0;
+
+queue:
+ mrp_pdu_queue(app);
+ goto again;
+}
+
+static void mrp_attr_event(struct mrp_applicant *app,
+ struct mrp_attr *attr, enum mrp_event event)
+{
+ enum mrp_applicant_state state;
+
+ state = mrp_applicant_state_table[attr->state][event];
+ if (state == MRP_APPLICANT_INVALID) {
+ WARN_ON(1);
+ return;
+ }
+
+ if (event == MRP_EVENT_TX) {
+ /* When appending the attribute fails, don't update its state
+ * in order to retry at the next TX event. */
+
+ switch (mrp_tx_action_table[attr->state]) {
+ case MRP_TX_ACTION_NONE:
+ case MRP_TX_ACTION_S_JOIN_IN_OPTIONAL:
+ case MRP_TX_ACTION_S_IN_OPTIONAL:
+ break;
+ case MRP_TX_ACTION_S_NEW:
+ if (mrp_pdu_append_event(app, attr, MRP_NEW) < 0)
+ return;
+ break;
+ case MRP_TX_ACTION_S_JOIN_IN:
+ if (mrp_pdu_append_event(app, attr, MRP_JOIN_IN) < 0)
+ return;
+ break;
+ case MRP_TX_ACTION_S_LV:
+ if (mrp_pdu_append_event(app, attr, MRP_LV) < 0)
+ return;
+ /* As a pure applicant, sending a leave message
+ * implies that the attribute was unregistered and
+ * can be destroyed. */
+ mrp_attr_destroy(app, attr);
+ return;
+ default:
+ WARN_ON(1);
+ }
+ }
+
+ attr->state = state;
+}
+
+int mrp_request_join(const struct net_device *dev,
+ const struct mrp_application *appl,
+ const void *value, u8 len, u8 type)
+{
+ struct mrp_port *port = rtnl_dereference(dev->mrp_port);
+ struct mrp_applicant *app = rtnl_dereference(
+ port->applicants[appl->type]);
+ struct mrp_attr *attr;
+
+ if (sizeof(struct mrp_skb_cb) + len >
+ FIELD_SIZEOF(struct sk_buff, cb))
+ return -ENOMEM;
+
+ spin_lock_bh(&app->lock);
+ attr = mrp_attr_create(app, value, len, type);
+ if (!attr) {
+ spin_unlock_bh(&app->lock);
+ return -ENOMEM;
+ }
+ mrp_attr_event(app, attr, MRP_EVENT_JOIN);
+ spin_unlock_bh(&app->lock);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mrp_request_join);
+
+void mrp_request_leave(const struct net_device *dev,
+ const struct mrp_application *appl,
+ const void *value, u8 len, u8 type)
+{
+ struct mrp_port *port = rtnl_dereference(dev->mrp_port);
+ struct mrp_applicant *app = rtnl_dereference(
+ port->applicants[appl->type]);
+ struct mrp_attr *attr;
+
+ if (sizeof(struct mrp_skb_cb) + len >
+ FIELD_SIZEOF(struct sk_buff, cb))
+ return;
+
+ spin_lock_bh(&app->lock);
+ attr = mrp_attr_lookup(app, value, len, type);
+ if (!attr) {
+ spin_unlock_bh(&app->lock);
+ return;
+ }
+ mrp_attr_event(app, attr, MRP_EVENT_LV);
+ spin_unlock_bh(&app->lock);
+}
+EXPORT_SYMBOL_GPL(mrp_request_leave);
+
+static void mrp_mad_event(struct mrp_applicant *app, enum mrp_event event)
+{
+ struct rb_node *node, *next;
+ struct mrp_attr *attr;
+
+ for (node = rb_first(&app->mad);
+ next = node ? rb_next(node) : NULL, node != NULL;
+ node = next) {
+ attr = rb_entry(node, struct mrp_attr, node);
+ mrp_attr_event(app, attr, event);
+ }
+}
+
+static void mrp_join_timer_arm(struct mrp_applicant *app)
+{
+ unsigned long delay;
+
+ delay = (u64)msecs_to_jiffies(mrp_join_time) * net_random() >> 32;
+ mod_timer(&app->join_timer, jiffies + delay);
+}
+
+static void mrp_join_timer(unsigned long data)
+{
+ struct mrp_applicant *app = (struct mrp_applicant *)data;
+
+ spin_lock(&app->lock);
+ mrp_mad_event(app, MRP_EVENT_TX);
+ mrp_pdu_queue(app);
+ spin_unlock(&app->lock);
+
+ mrp_queue_xmit(app);
+ mrp_join_timer_arm(app);
+}
+
+static int mrp_pdu_parse_end_mark(struct sk_buff *skb)
+{
+ __be16 *endmark;
+
+ if (!pskb_may_pull(skb, sizeof(*endmark)))
+ return -1;
+ endmark = (__be16 *)skb->data;
+ if (get_unaligned(endmark) == MRP_END_MARK) {
+ skb_pull(skb, sizeof(*endmark));
+ return -1;
+ }
+ return 0;
+}
+
+static void mrp_pdu_parse_vecattr_event(struct mrp_applicant *app,
+ struct sk_buff *skb,
+ enum mrp_vecattr_event vaevent)
+{
+ struct mrp_attr *attr;
+ enum mrp_event event;
+
+ attr = mrp_attr_lookup(app, mrp_cb(skb)->attrvalue,
+ mrp_cb(skb)->mh->attrlen,
+ mrp_cb(skb)->mh->attrtype);
+ if (attr == NULL)
+ return;
+
+ switch (vaevent) {
+ case MRP_NEW:
+ event = MRP_EVENT_R_NEW;
+ break;
+ case MRP_JOIN_IN:
+ event = MRP_EVENT_R_JOIN_IN;
+ break;
+ case MRP_IN:
+ event = MRP_EVENT_R_IN;
+ break;
+ case MRP_JOIN_MT:
+ event = MRP_EVENT_R_JOIN_MT;
+ break;
+ case MRP_MT:
+ event = MRP_EVENT_R_MT;
+ break;
+ case MRP_LV:
+ event = MRP_EVENT_R_LV;
+ break;
+ default:
+ return;
+ }
+
+ mrp_attr_event(app, attr, event);
+}
+
+static int mrp_pdu_parse_vecattr(struct mrp_applicant *app,
+ struct sk_buff *skb)
+{
+ u16 valen;
+ u8 vaevents, vaevent;
+
+ if (!pskb_may_pull(skb, sizeof(*mrp_cb(skb)->vah) +
+ mrp_cb(skb)->mh->attrlen))
+ return -1;
+ mrp_cb(skb)->vah = (struct mrp_vecattr_hdr *)skb->data;
+ if (get_unaligned(&mrp_cb(skb)->vah->lenflags) &
+ MRP_VECATTR_HDR_FLAG_LA)
+ mrp_mad_event(app, MRP_EVENT_R_LA);
+ valen = be16_to_cpu(get_unaligned(&mrp_cb(skb)->vah->lenflags) &
+ MRP_VECATTR_HDR_LEN_MASK);
+
+ /* The VectorAttribute structure in a PDU carries event information
+ * about one or more attributes having consecutive values. Only the
+ * value for the first attribute is contained in the structure. So
+ * we make a copy of that value, and then increment it each time we
+ * advance to the next event in its Vector. */
+ memcpy(mrp_cb(skb)->attrvalue,
+ mrp_cb(skb)->vah->firstattrvalue,
+ mrp_cb(skb)->mh->attrlen);
+ skb_pull(skb, sizeof(*mrp_cb(skb)->vah) +
+ mrp_cb(skb)->mh->attrlen);
+
+ /* In a VectorAttribute, the Vector contains events which are packed
+ * three to a byte. We process one byte of the Vector at a time. */
+ while (valen > 0) {
+ if (!pskb_may_pull(skb, sizeof(u8)))
+ return -1;
+ vaevents = *(u8 *)skb->data;
+ skb_pull(skb, sizeof(u8));
+
+ /* Extract and process the first event. */
+ vaevent = vaevents / 36;
+ vaevents %= 36;
+ if (vaevent >= 6) {
+ /* The byte is malformed; stop processing. */
+ return -1;
+ }
+ mrp_pdu_parse_vecattr_event(app, skb, vaevent);
+
+ /* If present, extract and process the second event. */
+ if (!--valen)
+ break;
+ mrp_attrvalue_inc(mrp_cb(skb)->attrvalue,
+ mrp_cb(skb)->mh->attrlen);
+ vaevent = vaevents / 6;
+ vaevents %= 6;
+ mrp_pdu_parse_vecattr_event(app, skb, vaevent);
+
+ /* If present, extract and process the third event. */
+ if (!--valen)
+ break;
+ mrp_attrvalue_inc(mrp_cb(skb)->attrvalue,
+ mrp_cb(skb)->mh->attrlen);
+ vaevent = vaevents;
+ mrp_pdu_parse_vecattr_event(app, skb, vaevent);
+ }
+ return 0;
+}
+
+static int mrp_pdu_parse_msg(struct mrp_applicant *app, struct sk_buff *skb)
+{
+ if (!pskb_may_pull(skb, sizeof(*mrp_cb(skb)->mh)))
+ return -1;
+ mrp_cb(skb)->mh = (struct mrp_msg_hdr *)skb->data;
+ if (mrp_cb(skb)->mh->attrtype == 0 ||
+ mrp_cb(skb)->mh->attrtype > app->app->maxattr ||
+ mrp_cb(skb)->mh->attrlen == 0)
+ return -1;
+ if (sizeof(struct mrp_skb_cb) + mrp_cb(skb)->mh->attrlen >
+ FIELD_SIZEOF(struct sk_buff, cb))
+ return -1;
+ skb_pull(skb, sizeof(*mrp_cb(skb)->mh));
+
+ while (skb->len > 0) {
+ if (mrp_pdu_parse_end_mark(skb) < 0)
+ break;
+ if (mrp_pdu_parse_vecattr(app, skb) < 0)
+ return -1;
+ }
+ return 0;
+}
+
+int mrp_rcv(struct sk_buff *skb, struct net_device *dev,
+ struct packet_type *pt, struct net_device *orig_dev)
+{
+ struct mrp_application *appl = container_of(pt, struct mrp_application,
+ pkttype);
+ struct mrp_port *port;
+ struct mrp_applicant *app;
+ const struct mrp_pdu_hdr *ph;
+
+ /*
+ * If the interface is in promiscuous mode, drop the packet if
+ * it was unicast to another host.
+ */
+ if (unlikely(skb->pkt_type == PACKET_OTHERHOST))
+ goto out;
+ skb = skb_share_check(skb, GFP_ATOMIC);
+ if (unlikely(!skb))
+ goto out;
+ port = rcu_dereference(dev->mrp_port);
+ if (unlikely(!port))
+ goto out;
+ app = rcu_dereference(port->applicants[appl->type]);
+ if (unlikely(!app))
+ goto out;
+
+ if (!pskb_may_pull(skb, sizeof(*ph)))
+ goto out;
+ ph = (struct mrp_pdu_hdr *)skb->data;
+ if (ph->version != app->app->version)
+ goto out;
+ skb_pull(skb, sizeof(*ph));
+
+ spin_lock(&app->lock);
+ while (skb->len > 0) {
+ if (mrp_pdu_parse_end_mark(skb) < 0)
+ break;
+ if (mrp_pdu_parse_msg(app, skb) < 0)
+ break;
+ }
+ spin_unlock(&app->lock);
+out:
+ kfree_skb(skb);
+ return 0;
+}
+
+static int mrp_init_port(struct net_device *dev)
+{
+ struct mrp_port *port;
+
+ port = kzalloc(sizeof(*port), GFP_KERNEL);
+ if (!port)
+ return -ENOMEM;
+ rcu_assign_pointer(dev->mrp_port, port);
+ return 0;
+}
+
+static void mrp_release_port(struct net_device *dev)
+{
+ struct mrp_port *port = rtnl_dereference(dev->mrp_port);
+ unsigned int i;
+
+ for (i = 0; i <= MRP_APPLICATION_MAX; i++) {
+ if (rtnl_dereference(port->applicants[i]))
+ return;
+ }
+ RCU_INIT_POINTER(dev->mrp_port, NULL);
+ kfree_rcu(port, rcu);
+}
+
+int mrp_init_applicant(struct net_device *dev, struct mrp_application *appl)
+{
+ struct mrp_applicant *app;
+ int err;
+
+ ASSERT_RTNL();
+
+ if (!rtnl_dereference(dev->mrp_port)) {
+ err = mrp_init_port(dev);
+ if (err < 0)
+ goto err1;
+ }
+
+ err = -ENOMEM;
+ app = kzalloc(sizeof(*app), GFP_KERNEL);
+ if (!app)
+ goto err2;
+
+ err = dev_mc_add(dev, appl->group_address);
+ if (err < 0)
+ goto err3;
+
+ app->dev = dev;
+ app->app = appl;
+ app->mad = RB_ROOT;
+ spin_lock_init(&app->lock);
+ skb_queue_head_init(&app->queue);
+ rcu_assign_pointer(dev->mrp_port->applicants[appl->type], app);
+ setup_timer(&app->join_timer, mrp_join_timer, (unsigned long)app);
+ mrp_join_timer_arm(app);
+ return 0;
+
+err3:
+ kfree(app);
+err2:
+ mrp_release_port(dev);
+err1:
+ return err;
+}
+EXPORT_SYMBOL_GPL(mrp_init_applicant);
+
+void mrp_uninit_applicant(struct net_device *dev, struct mrp_application *appl)
+{
+ struct mrp_port *port = rtnl_dereference(dev->mrp_port);
+ struct mrp_applicant *app = rtnl_dereference(
+ port->applicants[appl->type]);
+
+ ASSERT_RTNL();
+
+ RCU_INIT_POINTER(port->applicants[appl->type], NULL);
+
+ /* Delete timer and generate a final TX event to flush out
+ * all pending messages before the applicant is gone. */
+ del_timer_sync(&app->join_timer);
+ mrp_mad_event(app, MRP_EVENT_TX);
+ mrp_pdu_queue(app);
+ mrp_queue_xmit(app);
+
+ dev_mc_del(dev, appl->group_address);
+ kfree_rcu(app, rcu);
+ mrp_release_port(dev);
+}
+EXPORT_SYMBOL_GPL(mrp_uninit_applicant);
+
+int mrp_register_application(struct mrp_application *appl)
+{
+ appl->pkttype.func = mrp_rcv;
+ dev_add_pack(&appl->pkttype);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mrp_register_application);
+
+void mrp_unregister_application(struct mrp_application *appl)
+{
+ dev_remove_pack(&appl->pkttype);
+}
+EXPORT_SYMBOL_GPL(mrp_unregister_application);
--
1.7.4.1
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH RFC 2/2] net/8021q: Implement Multiple VLAN Registration Protocol (MVRP)
2012-09-24 21:07 [PATCH RFC 0/2] Multiple VLAN Registration Protocol (IEEE 802.1Q-2011) David Ward
2012-09-24 21:07 ` [PATCH RFC 1/2] net/802: Implement Multiple Registration Protocol (MRP) David Ward
@ 2012-09-24 21:07 ` David Ward
2012-09-24 21:07 ` [PATCH RFC iproute2] iplink_vlan: Add flag for " David Ward
2013-09-11 0:22 ` [PATCH RFC 0/2] Multiple VLAN Registration Protocol (IEEE 802.1Q-2011) Noel Burton-Krahn
3 siblings, 0 replies; 6+ messages in thread
From: David Ward @ 2012-09-24 21:07 UTC (permalink / raw)
To: netdev; +Cc: Patrick McHardy, Eric Dumazet, Philip Foulkes, David Ward
Initial implementation of the Multiple VLAN Registration Protocol
(MVRP) from IEEE 802.1Q-2011, based on the existing implementation
of the GARP VLAN Registration Protocol (GVRP).
Signed-off-by: David Ward <david.ward@ll.mit.edu>
---
include/linux/if_ether.h | 1 +
include/linux/if_vlan.h | 1 +
net/8021q/Kconfig | 11 +++++++
net/8021q/Makefile | 1 +
net/8021q/vlan.c | 27 ++++++++++++++---
net/8021q/vlan.h | 16 ++++++++++
net/8021q/vlan_dev.c | 12 +++++++-
net/8021q/vlan_mvrp.c | 72 ++++++++++++++++++++++++++++++++++++++++++++++
net/8021q/vlan_netlink.c | 2 +-
9 files changed, 136 insertions(+), 7 deletions(-)
create mode 100644 net/8021q/vlan_mvrp.c
diff --git a/include/linux/if_ether.h b/include/linux/if_ether.h
index 167ce5b..6476705 100644
--- a/include/linux/if_ether.h
+++ b/include/linux/if_ether.h
@@ -82,6 +82,7 @@
#define ETH_P_802_EX1 0x88B5 /* 802.1 Local Experimental 1. */
#define ETH_P_TIPC 0x88CA /* TIPC */
#define ETH_P_8021AH 0x88E7 /* 802.1ah Backbone Service Tag */
+#define ETH_P_MVRP 0x88F5 /* 802.1Q MVRP */
#define ETH_P_1588 0x88F7 /* IEEE 1588 Timesync */
#define ETH_P_FCOE 0x8906 /* Fibre Channel over Ethernet */
#define ETH_P_TDLS 0x890D /* TDLS */
diff --git a/include/linux/if_vlan.h b/include/linux/if_vlan.h
index e6ff12d..576444f 100644
--- a/include/linux/if_vlan.h
+++ b/include/linux/if_vlan.h
@@ -383,6 +383,7 @@ enum vlan_flags {
VLAN_FLAG_REORDER_HDR = 0x1,
VLAN_FLAG_GVRP = 0x2,
VLAN_FLAG_LOOSE_BINDING = 0x4,
+ VLAN_FLAG_MVRP = 0x8,
};
enum vlan_name_types {
diff --git a/net/8021q/Kconfig b/net/8021q/Kconfig
index fa073a5..8f7517d 100644
--- a/net/8021q/Kconfig
+++ b/net/8021q/Kconfig
@@ -27,3 +27,14 @@ config VLAN_8021Q_GVRP
automatic propagation of registered VLANs to switches.
If unsure, say N.
+
+config VLAN_8021Q_MVRP
+ bool "MVRP (Multiple VLAN Registration Protocol) support"
+ depends on VLAN_8021Q
+ select MRP
+ help
+ Select this to enable MVRP end-system support. MVRP is used for
+ automatic propagation of registered VLANs to switches; it
+ supersedes GVRP and is not backwards-compatible.
+
+ If unsure, say N.
diff --git a/net/8021q/Makefile b/net/8021q/Makefile
index 9f4f174..7bc8db0 100644
--- a/net/8021q/Makefile
+++ b/net/8021q/Makefile
@@ -6,5 +6,6 @@ obj-$(CONFIG_VLAN_8021Q) += 8021q.o
8021q-y := vlan.o vlan_dev.o vlan_netlink.o
8021q-$(CONFIG_VLAN_8021Q_GVRP) += vlan_gvrp.o
+8021q-$(CONFIG_VLAN_8021Q_MVRP) += vlan_mvrp.o
8021q-$(CONFIG_PROC_FS) += vlanproc.o
diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c
index 9096bcb..290e377 100644
--- a/net/8021q/vlan.c
+++ b/net/8021q/vlan.c
@@ -95,6 +95,8 @@ void unregister_vlan_dev(struct net_device *dev, struct list_head *head)
grp->nr_vlan_devs--;
+ if (vlan->flags & VLAN_FLAG_MVRP)
+ vlan_mvrp_request_leave(dev);
if (vlan->flags & VLAN_FLAG_GVRP)
vlan_gvrp_request_leave(dev);
@@ -105,8 +107,10 @@ void unregister_vlan_dev(struct net_device *dev, struct list_head *head)
*/
unregister_netdevice_queue(dev, head);
- if (grp->nr_vlan_devs == 0)
+ if (grp->nr_vlan_devs == 0) {
+ vlan_mvrp_uninit_applicant(real_dev);
vlan_gvrp_uninit_applicant(real_dev);
+ }
/* Get rid of the vlan's reference to real_dev */
dev_put(real_dev);
@@ -156,15 +160,18 @@ int register_vlan_dev(struct net_device *dev)
err = vlan_gvrp_init_applicant(real_dev);
if (err < 0)
goto out_vid_del;
+ err = vlan_mvrp_init_applicant(real_dev);
+ if (err < 0)
+ goto out_uninit_gvrp;
}
err = vlan_group_prealloc_vid(grp, vlan_id);
if (err < 0)
- goto out_uninit_applicant;
+ goto out_uninit_mvrp;
err = register_netdevice(dev);
if (err < 0)
- goto out_uninit_applicant;
+ goto out_uninit_mvrp;
/* Account for reference in struct vlan_dev_priv */
dev_hold(real_dev);
@@ -180,7 +187,10 @@ int register_vlan_dev(struct net_device *dev)
return 0;
-out_uninit_applicant:
+out_uninit_mvrp:
+ if (grp->nr_vlan_devs == 0)
+ vlan_mvrp_uninit_applicant(real_dev);
+out_uninit_gvrp:
if (grp->nr_vlan_devs == 0)
vlan_gvrp_uninit_applicant(real_dev);
out_vid_del:
@@ -651,13 +661,19 @@ static int __init vlan_proto_init(void)
if (err < 0)
goto err3;
- err = vlan_netlink_init();
+ err = vlan_mvrp_init();
if (err < 0)
goto err4;
+ err = vlan_netlink_init();
+ if (err < 0)
+ goto err5;
+
vlan_ioctl_set(vlan_ioctl_handler);
return 0;
+err5:
+ vlan_mvrp_uninit();
err4:
vlan_gvrp_uninit();
err3:
@@ -678,6 +694,7 @@ static void __exit vlan_cleanup_module(void)
unregister_pernet_subsys(&vlan_net_ops);
rcu_barrier(); /* Wait for completion of call_rcu()'s */
+ vlan_mvrp_uninit();
vlan_gvrp_uninit();
}
diff --git a/net/8021q/vlan.h b/net/8021q/vlan.h
index a4886d9..670f1e8 100644
--- a/net/8021q/vlan.h
+++ b/net/8021q/vlan.h
@@ -171,6 +171,22 @@ static inline int vlan_gvrp_init(void) { return 0; }
static inline void vlan_gvrp_uninit(void) {}
#endif
+#ifdef CONFIG_VLAN_8021Q_MVRP
+extern int vlan_mvrp_request_join(const struct net_device *dev);
+extern void vlan_mvrp_request_leave(const struct net_device *dev);
+extern int vlan_mvrp_init_applicant(struct net_device *dev);
+extern void vlan_mvrp_uninit_applicant(struct net_device *dev);
+extern int vlan_mvrp_init(void);
+extern void vlan_mvrp_uninit(void);
+#else
+static inline int vlan_mvrp_request_join(const struct net_device *dev) { return 0; }
+static inline void vlan_mvrp_request_leave(const struct net_device *dev) {}
+static inline int vlan_mvrp_init_applicant(struct net_device *dev) { return 0; }
+static inline void vlan_mvrp_uninit_applicant(struct net_device *dev) {}
+static inline int vlan_mvrp_init(void) { return 0; }
+static inline void vlan_mvrp_uninit(void) {}
+#endif
+
extern const char vlan_fullname[];
extern const char vlan_version[];
extern int vlan_netlink_init(void);
diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c
index 4024424..f547faa 100644
--- a/net/8021q/vlan_dev.c
+++ b/net/8021q/vlan_dev.c
@@ -261,7 +261,7 @@ int vlan_dev_change_flags(const struct net_device *dev, u32 flags, u32 mask)
u32 old_flags = vlan->flags;
if (mask & ~(VLAN_FLAG_REORDER_HDR | VLAN_FLAG_GVRP |
- VLAN_FLAG_LOOSE_BINDING))
+ VLAN_FLAG_LOOSE_BINDING | VLAN_FLAG_MVRP))
return -EINVAL;
vlan->flags = (old_flags & ~mask) | (flags & mask);
@@ -272,6 +272,13 @@ int vlan_dev_change_flags(const struct net_device *dev, u32 flags, u32 mask)
else
vlan_gvrp_request_leave(dev);
}
+
+ if (netif_running(dev) && (vlan->flags ^ old_flags) & VLAN_FLAG_MVRP) {
+ if (vlan->flags & VLAN_FLAG_MVRP)
+ vlan_mvrp_request_join(dev);
+ else
+ vlan_mvrp_request_leave(dev);
+ }
return 0;
}
@@ -312,6 +319,9 @@ static int vlan_dev_open(struct net_device *dev)
if (vlan->flags & VLAN_FLAG_GVRP)
vlan_gvrp_request_join(dev);
+ if (vlan->flags & VLAN_FLAG_MVRP)
+ vlan_mvrp_request_join(dev);
+
if (netif_carrier_ok(real_dev))
netif_carrier_on(dev);
return 0;
diff --git a/net/8021q/vlan_mvrp.c b/net/8021q/vlan_mvrp.c
new file mode 100644
index 0000000..d9ec1d5
--- /dev/null
+++ b/net/8021q/vlan_mvrp.c
@@ -0,0 +1,72 @@
+/*
+ * IEEE 802.1Q Multiple VLAN Registration Protocol (MVRP)
+ *
+ * Copyright (c) 2012 Massachusetts Institute of Technology
+ *
+ * Adapted from code in net/8021q/vlan_gvrp.c
+ * Copyright (c) 2008 Patrick McHardy <kaber@trash.net>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ */
+#include <linux/types.h>
+#include <linux/if_ether.h>
+#include <linux/if_vlan.h>
+#include <net/mrp.h>
+#include "vlan.h"
+
+#define MRP_MVRP_ADDRESS { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x21 }
+
+enum mvrp_attributes {
+ MVRP_ATTR_INVALID,
+ MVRP_ATTR_VID,
+ __MVRP_ATTR_MAX
+};
+#define MVRP_ATTR_MAX (__MVRP_ATTR_MAX - 1)
+
+static struct mrp_application vlan_mrp_app __read_mostly = {
+ .type = MRP_APPLICATION_MVRP,
+ .maxattr = MVRP_ATTR_MAX,
+ .pkttype.type = htons(ETH_P_MVRP),
+ .group_address = MRP_MVRP_ADDRESS,
+ .version = 0,
+};
+
+int vlan_mvrp_request_join(const struct net_device *dev)
+{
+ const struct vlan_dev_priv *vlan = vlan_dev_priv(dev);
+ __be16 vlan_id = htons(vlan->vlan_id);
+
+ return mrp_request_join(vlan->real_dev, &vlan_mrp_app,
+ &vlan_id, sizeof(vlan_id), MVRP_ATTR_VID);
+}
+
+void vlan_mvrp_request_leave(const struct net_device *dev)
+{
+ const struct vlan_dev_priv *vlan = vlan_dev_priv(dev);
+ __be16 vlan_id = htons(vlan->vlan_id);
+
+ mrp_request_leave(vlan->real_dev, &vlan_mrp_app,
+ &vlan_id, sizeof(vlan_id), MVRP_ATTR_VID);
+}
+
+int vlan_mvrp_init_applicant(struct net_device *dev)
+{
+ return mrp_init_applicant(dev, &vlan_mrp_app);
+}
+
+void vlan_mvrp_uninit_applicant(struct net_device *dev)
+{
+ mrp_uninit_applicant(dev, &vlan_mrp_app);
+}
+
+int __init vlan_mvrp_init(void)
+{
+ return mrp_register_application(&vlan_mrp_app);
+}
+
+void vlan_mvrp_uninit(void)
+{
+ mrp_unregister_application(&vlan_mrp_app);
+}
diff --git a/net/8021q/vlan_netlink.c b/net/8021q/vlan_netlink.c
index 708c80e..1789658 100644
--- a/net/8021q/vlan_netlink.c
+++ b/net/8021q/vlan_netlink.c
@@ -62,7 +62,7 @@ static int vlan_validate(struct nlattr *tb[], struct nlattr *data[])
flags = nla_data(data[IFLA_VLAN_FLAGS]);
if ((flags->flags & flags->mask) &
~(VLAN_FLAG_REORDER_HDR | VLAN_FLAG_GVRP |
- VLAN_FLAG_LOOSE_BINDING))
+ VLAN_FLAG_LOOSE_BINDING | VLAN_FLAG_MVRP))
return -EINVAL;
}
--
1.7.4.1
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH RFC iproute2] iplink_vlan: Add flag for Multiple VLAN Registration Protocol (MVRP)
2012-09-24 21:07 [PATCH RFC 0/2] Multiple VLAN Registration Protocol (IEEE 802.1Q-2011) David Ward
2012-09-24 21:07 ` [PATCH RFC 1/2] net/802: Implement Multiple Registration Protocol (MRP) David Ward
2012-09-24 21:07 ` [PATCH RFC 2/2] net/8021q: Implement Multiple VLAN Registration Protocol (MVRP) David Ward
@ 2012-09-24 21:07 ` David Ward
2013-09-11 0:22 ` [PATCH RFC 0/2] Multiple VLAN Registration Protocol (IEEE 802.1Q-2011) Noel Burton-Krahn
3 siblings, 0 replies; 6+ messages in thread
From: David Ward @ 2012-09-24 21:07 UTC (permalink / raw)
To: netdev; +Cc: Patrick McHardy, Eric Dumazet, Philip Foulkes, David Ward
Signed-off-by: David Ward <david.ward@ll.mit.edu>
---
include/linux/if_vlan.h | 1 +
ip/iplink_vlan.c | 12 +++++++++++-
2 files changed, 12 insertions(+), 1 deletions(-)
diff --git a/include/linux/if_vlan.h b/include/linux/if_vlan.h
index 5b808eb..38052c2 100644
--- a/include/linux/if_vlan.h
+++ b/include/linux/if_vlan.h
@@ -34,6 +34,7 @@ enum vlan_flags {
VLAN_FLAG_REORDER_HDR = 0x1,
VLAN_FLAG_GVRP = 0x2,
VLAN_FLAG_LOOSE_BINDING = 0x4,
+ VLAN_FLAG_MVRP = 0x8,
};
enum vlan_name_types {
diff --git a/ip/iplink_vlan.c b/ip/iplink_vlan.c
index 97af8d6..4d155b6 100644
--- a/ip/iplink_vlan.c
+++ b/ip/iplink_vlan.c
@@ -26,7 +26,7 @@ static void explain(void)
"\n"
"VLANID := 0-4095\n"
"FLAG-LIST := [ FLAG-LIST ] FLAG\n"
- "FLAG := [ reorder_hdr { on | off } ] [ gvrp { on | off } ]\n"
+ "FLAG := [ reorder_hdr { on | off } ] [ gvrp { on | off } ] [ mvrp { on | off } ]\n"
" [ loose_binding { on | off } ]\n"
"QOS-MAP := [ QOS-MAP ] QOS-MAPPING\n"
"QOS-MAPPING := FROM:TO\n"
@@ -103,6 +103,15 @@ static int vlan_parse_opt(struct link_util *lu, int argc, char **argv,
flags.flags &= ~VLAN_FLAG_GVRP;
else
return on_off("gvrp");
+ } else if (matches(*argv, "mvrp") == 0) {
+ NEXT_ARG();
+ flags.mask |= VLAN_FLAG_MVRP;
+ if (strcmp(*argv, "on") == 0)
+ flags.flags |= VLAN_FLAG_MVRP;
+ else if (strcmp(*argv, "off") == 0)
+ flags.flags &= ~VLAN_FLAG_MVRP;
+ else
+ return on_off("mvrp");
} else if (matches(*argv, "loose_binding") == 0) {
NEXT_ARG();
flags.mask |= VLAN_FLAG_LOOSE_BINDING;
@@ -166,6 +175,7 @@ static void vlan_print_flags(FILE *fp, __u32 flags)
}
_PF(REORDER_HDR);
_PF(GVRP);
+ _PF(MVRP);
_PF(LOOSE_BINDING);
#undef _PF
if (flags)
--
1.7.4.1
^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [PATCH RFC 1/2] net/802: Implement Multiple Registration Protocol (MRP)
2012-09-24 21:07 ` [PATCH RFC 1/2] net/802: Implement Multiple Registration Protocol (MRP) David Ward
@ 2012-09-24 21:36 ` Eric Dumazet
0 siblings, 0 replies; 6+ messages in thread
From: Eric Dumazet @ 2012-09-24 21:36 UTC (permalink / raw)
To: David Ward; +Cc: netdev, Patrick McHardy, Philip Foulkes
On Mon, 2012-09-24 at 17:07 -0400, David Ward wrote:
...
> +static int mrp_pdu_parse_end_mark(struct sk_buff *skb)
> +{
> + __be16 *endmark;
> +
> + if (!pskb_may_pull(skb, sizeof(*endmark)))
> + return -1;
> + endmark = (__be16 *)skb->data;
> + if (get_unaligned(endmark) == MRP_END_MARK) {
You might try get_unaligned_be16(skb->data) ...
> + skb_pull(skb, sizeof(*endmark));
> + return -1;
> + }
> + return 0;
> +}
> +
...
> +
> +static int mrp_pdu_parse_msg(struct mrp_applicant *app, struct sk_buff *skb)
> +{
> + if (!pskb_may_pull(skb, sizeof(*mrp_cb(skb)->mh)))
> + return -1;
> + mrp_cb(skb)->mh = (struct mrp_msg_hdr *)skb->data;
here you store a pointer to skb->data, in skb>cb[]
> + if (mrp_cb(skb)->mh->attrtype == 0 ||
> + mrp_cb(skb)->mh->attrtype > app->app->maxattr ||
> + mrp_cb(skb)->mh->attrlen == 0)
> + return -1;
> + if (sizeof(struct mrp_skb_cb) + mrp_cb(skb)->mh->attrlen >
> + FIELD_SIZEOF(struct sk_buff, cb))
> + return -1;
> + skb_pull(skb, sizeof(*mrp_cb(skb)->mh));
> +
> + while (skb->len > 0) {
> + if (mrp_pdu_parse_end_mark(skb) < 0)
> + break;
but skb->head can be reallocated by other pskb_may_pull() calls
done in mrp_pdu_parse_end_mark() (and elsewhere)
So skb->cb[] might contain a pointer to a freed memory.
> + if (mrp_pdu_parse_vecattr(app, skb) < 0)
> + return -1;
> + }
> + return 0;
> +}
> +
You might consider using skb_header_pointer() instead of
pskb_may_pull()/skb_pull(), it might be easier when you have such nested
headers...
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH RFC 0/2] Multiple VLAN Registration Protocol (IEEE 802.1Q-2011)
2012-09-24 21:07 [PATCH RFC 0/2] Multiple VLAN Registration Protocol (IEEE 802.1Q-2011) David Ward
` (2 preceding siblings ...)
2012-09-24 21:07 ` [PATCH RFC iproute2] iplink_vlan: Add flag for " David Ward
@ 2013-09-11 0:22 ` Noel Burton-Krahn
3 siblings, 0 replies; 6+ messages in thread
From: Noel Burton-Krahn @ 2013-09-11 0:22 UTC (permalink / raw)
To: netdev
David Ward <david.ward <at> ll.mit.edu> writes:
> The following patches add support for MVRP to
> the Linux kernel and iproute2 utility. They are based largely off of
> the existing implementation of GVRP, but have been modified for the
> new PDU structure and state machine.
>
> Please let me know if you have any comments. This implementation was
> tested with two Juniper EX4200 switches and found to work as expected.
> If you have access to other switches that implement MVRP, I would of
> course welcome additional testing.
>
> Signed-off-by: David Ward <david.ward <at> ll.mit.edu>
>
David,
Thanks for your MVRP implementation. I ran into a problem with MVRP where
it would fail to register if MVRP started too soon after the network
interface came up. There's a few seconds from when an interface is up until
it can actually send packets, even after it reports it's up, so the first
few MVRP JoinIn packets would get lost. The Linux MRP implementation that
sends JoinIn packets was missing the periodic timer required by
[802.1Q-2011], so after the JoinIn's were lost, the MVRP registration would
never retry, and MVRP would fail to register:
10.7.4.4 periodictimer
The Periodic Transmission timer, periodictimer, controls the
frequency with which the PeriodicTransmission state machine
generates periodic! events. The timer is required on a per-Port
basis. The Periodic Transmission timer is set to one second when it
is started.
The weird thing about the periodictimer is that it fires every second
forever, and the MRP Applicant state machine bounces from QA to AA states
and back every second, sending a MRP request every time. There's no state
to be quiet after the applicant receives a rJoinIn acknowledgement. See
Section 10.7.7 (Applicant state machine) in [802.1Q-2011]. The result is
that the MRP application sends JoinIn every second, which seems a little
noisy. Am I missing something?
[802.1Q-2011]
http://standards.ieee.org/findstds/standard/802.1Q-2011.html
Here's a patch for net/mrp.c that adds the periodic timer. My working fork
is at https://github.com/noelbk/linux.
Cheers,
--
Noel
diff --git a/include/net/mrp.h b/include/net/mrp.h
index 4fbf02a..0f7558b 100644
--- a/include/net/mrp.h
+++ b/include/net/mrp.h
@@ -112,6 +112,7 @@ struct mrp_applicant {
struct mrp_application *app;
struct net_device *dev;
struct timer_list join_timer;
+ struct timer_list periodic_timer;
spinlock_t lock;
struct sk_buff_head queue;
diff --git a/net/802/mrp.c b/net/802/mrp.c
index 1eb05d8..8f1fa4f 100644
--- a/net/802/mrp.c
+++ b/net/802/mrp.c
@@ -1,3 +1,5 @@
+#define pr_fmt(fmt) KBUILD_MODNAME ": %s: " fmt, __func__
+
/*
* IEEE 802.1Q Multiple Registration Protocol (MRP)
*
@@ -24,6 +26,12 @@
static unsigned int mrp_join_time __read_mostly = 200;
module_param(mrp_join_time, uint, 0644);
MODULE_PARM_DESC(mrp_join_time, "Join time in ms (default 200ms)");
+
+static unsigned int mrp_periodic_time __read_mostly = 1000;
+module_param(mrp_periodic_time, uint, 0644);
+MODULE_PARM_DESC(mrp_periodic_time, "Periodic time in ms (default 1s)");
+
+
MODULE_LICENSE("GPL");
static const u8
@@ -210,6 +218,52 @@ mrp_tx_action_table[MRP_APPLICANT_MAX + 1] = {
[MRP_APPLICANT_QP] = MRP_TX_ACTION_S_IN_OPTIONAL,
};
+
+// debug
+static char *
+mrp_event_str(enum mrp_event event) {
+ char *s = "unknown";
+ switch(event) {
+ case MRP_EVENT_NEW: s = "NEW"; break;
+ case MRP_EVENT_JOIN: s = "JOIN"; break;
+ case MRP_EVENT_LV: s = "LV"; break;
+ case MRP_EVENT_TX: s = "TX"; break;
+ case MRP_EVENT_R_NEW: s = "R_NEW"; break;
+ case MRP_EVENT_R_JOIN_IN: s = "R_JOIN_IN"; break;
+ case MRP_EVENT_R_IN: s = "R_IN"; break;
+ case MRP_EVENT_R_JOIN_MT: s = "R_JOIN_MT"; break;
+ case MRP_EVENT_R_MT: s = "R_MT"; break;
+ case MRP_EVENT_R_LV: s = "R_LV"; break;
+ case MRP_EVENT_R_LA: s = "R_LA"; break;
+ case MRP_EVENT_REDECLARE: s = "REDECLARE"; break;
+ case MRP_EVENT_PERIODIC: s = "PERIODIC"; break;
+ case __MRP_EVENT_MAX: break;
+ }
+ return s;
+}
+
+// debug
+static char *
+mrp_applicant_state_str(enum mrp_applicant_state state) {
+ char *s = "unknown";
+ switch(state) {
+ case MRP_APPLICANT_INVALID: s = "INVALID"; break;
+ case MRP_APPLICANT_VO: s = "VO"; break;
+ case MRP_APPLICANT_VP: s = "VP"; break;
+ case MRP_APPLICANT_VN: s = "VN"; break;
+ case MRP_APPLICANT_AN: s = "AN"; break;
+ case MRP_APPLICANT_AA: s = "AA"; break;
+ case MRP_APPLICANT_QA: s = "QA"; break;
+ case MRP_APPLICANT_LA: s = "LA"; break;
+ case MRP_APPLICANT_AO: s = "AO"; break;
+ case MRP_APPLICANT_QO: s = "QO"; break;
+ case MRP_APPLICANT_AP: s = "AP"; break;
+ case MRP_APPLICANT_QP: s = "QP"; break;
+ case __MRP_APPLICANT_MAX: break;
+ }
+ return s;
+}
+
static void mrp_attrvalue_inc(void *value, u8 len)
{
u8 *v = (u8 *)value;
@@ -345,8 +399,15 @@ static void mrp_queue_xmit(struct mrp_applicant *app)
{
struct sk_buff *skb;
- while ((skb = skb_dequeue(&app->queue)))
- dev_queue_xmit(skb);
+ while ((skb = skb_dequeue(&app->queue))) {
+ int xmit_err = dev_queue_xmit(skb);
+ pr_debug("dev=%s len=%d dev_queue_xmit=%d carrier_ok=%d dormant=%d\n"
+ ,skb->dev->name, (int)skb->len
+ ,(int)xmit_err
+ ,(int)netif_carrier_ok(skb->dev)
+ ,(int)netif_dormant(skb->dev)
+ );
+ }
}
static int mrp_pdu_append_msg_hdr(struct mrp_applicant *app,
@@ -474,6 +535,13 @@ static void mrp_attr_event(struct mrp_applicant *app,
return;
}
+ pr_debug("attr_type=%d event=%s attr->state=%s new state=%s\n"
+ ,(int)attr->type
+ ,mrp_event_str(event)
+ ,mrp_applicant_state_str(attr->state)
+ ,mrp_applicant_state_str(state));
+
+
if (event == MRP_EVENT_TX) {
/* When appending the attribute fails, don't update its state
* in order to retry at the next TX event.
@@ -521,6 +589,8 @@ int mrp_request_join(const struct net_device *dev,
port->applicants[appl->type]);
struct mrp_attr *attr;
+ pr_debug("dev->name=%s attr_type=%d\n", dev->name, (int)type);
+
if (sizeof(struct mrp_skb_cb) + len >
FIELD_SIZEOF(struct sk_buff, cb))
return -ENOMEM;
@@ -546,6 +616,8 @@ void mrp_request_leave(const struct net_device *dev,
port->applicants[appl->type]);
struct mrp_attr *attr;
+ pr_debug("dev->name=%s attr_type=%d\n", dev->name, (int)type);
+
if (sizeof(struct mrp_skb_cb) + len >
FIELD_SIZEOF(struct sk_buff, cb))
return;
@@ -595,6 +667,52 @@ static void mrp_join_timer(unsigned long data)
mrp_join_timer_arm(app);
}
+static void mrp_periodic_timer_arm(struct mrp_applicant *app)
+{
+ unsigned long delay;
+
+ delay = (u64)msecs_to_jiffies(mrp_periodic_time);
+ mod_timer(&app->periodic_timer, jiffies + delay);
+}
+
+
+/*
+
+from [802.1Q-2011]
+http://standards.ieee.org/findstds/standard/802.1Q-2011.html
+
+
+10.7.4.4 periodictimer
+
+The Periodic Transmission timer, periodictimer, controls the frequency
+with which the PeriodicTransmission state machine generates periodic!
+events. The timer is required on a per-Port basis. The Periodic
+Transmission timer is set to one second when it is started.
+
+10.7.5.10 periodic!
+
+This event indicates to the Applicant state machine that the timer
+used to stimulate periodic transmission has expired.
+
+10.7.5.23 periodictimer!
+
+For an instance of the PeriodicTransmission state machine, the
+periodictimer! event is deemed to have occurred when the periodictimer
+associated with that state machine expires.
+
+*/
+static void mrp_periodic_timer(unsigned long data)
+{
+ struct mrp_applicant *app = (struct mrp_applicant *)data;
+
+ spin_lock(&app->lock);
+ mrp_mad_event(app, MRP_EVENT_PERIODIC);
+ mrp_pdu_queue(app);
+ spin_unlock(&app->lock);
+
+ mrp_periodic_timer_arm(app);
+}
+
static int mrp_pdu_parse_end_mark(struct sk_buff *skb, int *offset)
{
__be16 endmark;
@@ -791,10 +909,13 @@ out:
return 0;
}
+
static int mrp_init_port(struct net_device *dev)
{
struct mrp_port *port;
+ pr_debug("dev->name=%s\n", dev->name);
+
port = kzalloc(sizeof(*port), GFP_KERNEL);
if (!port)
return -ENOMEM;
@@ -807,6 +928,8 @@ static void mrp_release_port(struct net_device *dev)
struct mrp_port *port = rtnl_dereference(dev->mrp_port);
unsigned int i;
+ pr_debug("dev->name=%s\n", dev->name);
+
for (i = 0; i <= MRP_APPLICATION_MAX; i++) {
if (rtnl_dereference(port->applicants[i]))
return;
@@ -820,6 +943,8 @@ int mrp_init_applicant(struct net_device *dev, struct
mrp_application *appl)
struct mrp_applicant *app;
int err;
+ pr_debug("dev->name=%s\n", dev->name);
+
ASSERT_RTNL();
if (!rtnl_dereference(dev->mrp_port)) {
@@ -845,6 +970,8 @@ int mrp_init_applicant(struct net_device *dev, struct
mrp_application *appl)
rcu_assign_pointer(dev->mrp_port->applicants[appl->type], app);
setup_timer(&app->join_timer, mrp_join_timer, (unsigned long)app);
mrp_join_timer_arm(app);
+ setup_timer(&app->periodic_timer, mrp_periodic_timer, (unsigned long)app);
+ mrp_periodic_timer_arm(app);
return 0;
err3:
@@ -862,6 +989,8 @@ void mrp_uninit_applicant(struct net_device *dev, struct
mrp_application *appl)
struct mrp_applicant *app = rtnl_dereference(
port->applicants[appl->type]);
+ pr_debug("dev->name=%s\n", dev->name);
+
ASSERT_RTNL();
RCU_INIT_POINTER(port->applicants[appl->type], NULL);
@@ -870,6 +999,7 @@ void mrp_uninit_applicant(struct net_device *dev, struct
mrp_application *appl)
* all pending messages before the applicant is gone.
*/
del_timer_sync(&app->join_timer);
+ del_timer_sync(&app->periodic_timer);
spin_lock_bh(&app->lock);
mrp_mad_event(app, MRP_EVENT_TX);
@@ -897,3 +1027,4 @@ void mrp_unregister_application(struct mrp_application
*appl)
dev_remove_pack(&appl->pkttype);
}
EXPORT_SYMBOL_GPL(mrp_unregister_application);
+
^ permalink raw reply related [flat|nested] 6+ messages in thread
end of thread, other threads:[~2013-09-11 0:25 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-09-24 21:07 [PATCH RFC 0/2] Multiple VLAN Registration Protocol (IEEE 802.1Q-2011) David Ward
2012-09-24 21:07 ` [PATCH RFC 1/2] net/802: Implement Multiple Registration Protocol (MRP) David Ward
2012-09-24 21:36 ` Eric Dumazet
2012-09-24 21:07 ` [PATCH RFC 2/2] net/8021q: Implement Multiple VLAN Registration Protocol (MVRP) David Ward
2012-09-24 21:07 ` [PATCH RFC iproute2] iplink_vlan: Add flag for " David Ward
2013-09-11 0:22 ` [PATCH RFC 0/2] Multiple VLAN Registration Protocol (IEEE 802.1Q-2011) Noel Burton-Krahn
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).