aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Ward <david.ward@ll.mit.edu>2013-02-08 12:17:07 -0500
committerDavid S. Miller <davem@davemloft.net>2013-02-10 20:37:22 -0500
commit86fbe9bb599fcaf7e92e38dbfdad0414a2d68f7d (patch)
tree2e8b109de2f0e3b5c1b59f8dd2737388109ef982
parentfebf018d22347b5df94066bca05d0c11a84e839d (diff)
net/8021q: Implement Multiple VLAN Registration Protocol (MVRP)
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> Acked-by: Patrick McHardy <kaber@trash.net> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/uapi/linux/if_ether.h1
-rw-r--r--include/uapi/linux/if_vlan.h1
-rw-r--r--net/8021q/Kconfig11
-rw-r--r--net/8021q/Makefile1
-rw-r--r--net/8021q/vlan.c27
-rw-r--r--net/8021q/vlan.h16
-rw-r--r--net/8021q/vlan_dev.c12
-rw-r--r--net/8021q/vlan_mvrp.c72
-rw-r--r--net/8021q/vlan_netlink.c2
9 files changed, 136 insertions, 7 deletions
diff --git a/include/uapi/linux/if_ether.h b/include/uapi/linux/if_ether.h
index 67fb87ca1094..798032d01112 100644
--- a/include/uapi/linux/if_ether.h
+++ b/include/uapi/linux/if_ether.h
@@ -83,6 +83,7 @@
83#define ETH_P_802_EX1 0x88B5 /* 802.1 Local Experimental 1. */ 83#define ETH_P_802_EX1 0x88B5 /* 802.1 Local Experimental 1. */
84#define ETH_P_TIPC 0x88CA /* TIPC */ 84#define ETH_P_TIPC 0x88CA /* TIPC */
85#define ETH_P_8021AH 0x88E7 /* 802.1ah Backbone Service Tag */ 85#define ETH_P_8021AH 0x88E7 /* 802.1ah Backbone Service Tag */
86#define ETH_P_MVRP 0x88F5 /* 802.1Q MVRP */
86#define ETH_P_1588 0x88F7 /* IEEE 1588 Timesync */ 87#define ETH_P_1588 0x88F7 /* IEEE 1588 Timesync */
87#define ETH_P_FCOE 0x8906 /* Fibre Channel over Ethernet */ 88#define ETH_P_FCOE 0x8906 /* Fibre Channel over Ethernet */
88#define ETH_P_TDLS 0x890D /* TDLS */ 89#define ETH_P_TDLS 0x890D /* TDLS */
diff --git a/include/uapi/linux/if_vlan.h b/include/uapi/linux/if_vlan.h
index 0744f8e65d15..7e5e6b397332 100644
--- a/include/uapi/linux/if_vlan.h
+++ b/include/uapi/linux/if_vlan.h
@@ -34,6 +34,7 @@ enum vlan_flags {
34 VLAN_FLAG_REORDER_HDR = 0x1, 34 VLAN_FLAG_REORDER_HDR = 0x1,
35 VLAN_FLAG_GVRP = 0x2, 35 VLAN_FLAG_GVRP = 0x2,
36 VLAN_FLAG_LOOSE_BINDING = 0x4, 36 VLAN_FLAG_LOOSE_BINDING = 0x4,
37 VLAN_FLAG_MVRP = 0x8,
37}; 38};
38 39
39enum vlan_name_types { 40enum vlan_name_types {
diff --git a/net/8021q/Kconfig b/net/8021q/Kconfig
index fa073a54963e..8f7517df41a5 100644
--- a/net/8021q/Kconfig
+++ b/net/8021q/Kconfig
@@ -27,3 +27,14 @@ config VLAN_8021Q_GVRP
27 automatic propagation of registered VLANs to switches. 27 automatic propagation of registered VLANs to switches.
28 28
29 If unsure, say N. 29 If unsure, say N.
30
31config VLAN_8021Q_MVRP
32 bool "MVRP (Multiple VLAN Registration Protocol) support"
33 depends on VLAN_8021Q
34 select MRP
35 help
36 Select this to enable MVRP end-system support. MVRP is used for
37 automatic propagation of registered VLANs to switches; it
38 supersedes GVRP and is not backwards-compatible.
39
40 If unsure, say N.
diff --git a/net/8021q/Makefile b/net/8021q/Makefile
index 9f4f174ead1c..7bc8db08d7ef 100644
--- a/net/8021q/Makefile
+++ b/net/8021q/Makefile
@@ -6,5 +6,6 @@ obj-$(CONFIG_VLAN_8021Q) += 8021q.o
6 6
78021q-y := vlan.o vlan_dev.o vlan_netlink.o 78021q-y := vlan.o vlan_dev.o vlan_netlink.o
88021q-$(CONFIG_VLAN_8021Q_GVRP) += vlan_gvrp.o 88021q-$(CONFIG_VLAN_8021Q_GVRP) += vlan_gvrp.o
98021q-$(CONFIG_VLAN_8021Q_MVRP) += vlan_mvrp.o
98021q-$(CONFIG_PROC_FS) += vlanproc.o 108021q-$(CONFIG_PROC_FS) += vlanproc.o
10 11
diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c
index addc578d5443..a18714469bf7 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)
95 95
96 grp->nr_vlan_devs--; 96 grp->nr_vlan_devs--;
97 97
98 if (vlan->flags & VLAN_FLAG_MVRP)
99 vlan_mvrp_request_leave(dev);
98 if (vlan->flags & VLAN_FLAG_GVRP) 100 if (vlan->flags & VLAN_FLAG_GVRP)
99 vlan_gvrp_request_leave(dev); 101 vlan_gvrp_request_leave(dev);
100 102
@@ -107,8 +109,10 @@ void unregister_vlan_dev(struct net_device *dev, struct list_head *head)
107 109
108 netdev_upper_dev_unlink(real_dev, dev); 110 netdev_upper_dev_unlink(real_dev, dev);
109 111
110 if (grp->nr_vlan_devs == 0) 112 if (grp->nr_vlan_devs == 0) {
113 vlan_mvrp_uninit_applicant(real_dev);
111 vlan_gvrp_uninit_applicant(real_dev); 114 vlan_gvrp_uninit_applicant(real_dev);
115 }
112 116
113 /* Get rid of the vlan's reference to real_dev */ 117 /* Get rid of the vlan's reference to real_dev */
114 dev_put(real_dev); 118 dev_put(real_dev);
@@ -151,15 +155,18 @@ int register_vlan_dev(struct net_device *dev)
151 err = vlan_gvrp_init_applicant(real_dev); 155 err = vlan_gvrp_init_applicant(real_dev);
152 if (err < 0) 156 if (err < 0)
153 goto out_vid_del; 157 goto out_vid_del;
158 err = vlan_mvrp_init_applicant(real_dev);
159 if (err < 0)
160 goto out_uninit_gvrp;
154 } 161 }
155 162
156 err = vlan_group_prealloc_vid(grp, vlan_id); 163 err = vlan_group_prealloc_vid(grp, vlan_id);
157 if (err < 0) 164 if (err < 0)
158 goto out_uninit_applicant; 165 goto out_uninit_mvrp;
159 166
160 err = netdev_upper_dev_link(real_dev, dev); 167 err = netdev_upper_dev_link(real_dev, dev);
161 if (err) 168 if (err)
162 goto out_uninit_applicant; 169 goto out_uninit_mvrp;
163 170
164 err = register_netdevice(dev); 171 err = register_netdevice(dev);
165 if (err < 0) 172 if (err < 0)
@@ -181,7 +188,10 @@ int register_vlan_dev(struct net_device *dev)
181 188
182out_upper_dev_unlink: 189out_upper_dev_unlink:
183 netdev_upper_dev_unlink(real_dev, dev); 190 netdev_upper_dev_unlink(real_dev, dev);
184out_uninit_applicant: 191out_uninit_mvrp:
192 if (grp->nr_vlan_devs == 0)
193 vlan_mvrp_uninit_applicant(real_dev);
194out_uninit_gvrp:
185 if (grp->nr_vlan_devs == 0) 195 if (grp->nr_vlan_devs == 0)
186 vlan_gvrp_uninit_applicant(real_dev); 196 vlan_gvrp_uninit_applicant(real_dev);
187out_vid_del: 197out_vid_del:
@@ -655,13 +665,19 @@ static int __init vlan_proto_init(void)
655 if (err < 0) 665 if (err < 0)
656 goto err3; 666 goto err3;
657 667
658 err = vlan_netlink_init(); 668 err = vlan_mvrp_init();
659 if (err < 0) 669 if (err < 0)
660 goto err4; 670 goto err4;
661 671
672 err = vlan_netlink_init();
673 if (err < 0)
674 goto err5;
675
662 vlan_ioctl_set(vlan_ioctl_handler); 676 vlan_ioctl_set(vlan_ioctl_handler);
663 return 0; 677 return 0;
664 678
679err5:
680 vlan_mvrp_uninit();
665err4: 681err4:
666 vlan_gvrp_uninit(); 682 vlan_gvrp_uninit();
667err3: 683err3:
@@ -682,6 +698,7 @@ static void __exit vlan_cleanup_module(void)
682 unregister_pernet_subsys(&vlan_net_ops); 698 unregister_pernet_subsys(&vlan_net_ops);
683 rcu_barrier(); /* Wait for completion of call_rcu()'s */ 699 rcu_barrier(); /* Wait for completion of call_rcu()'s */
684 700
701 vlan_mvrp_uninit();
685 vlan_gvrp_uninit(); 702 vlan_gvrp_uninit();
686} 703}
687 704
diff --git a/net/8021q/vlan.h b/net/8021q/vlan.h
index a4886d94c40c..670f1e8cfc0f 100644
--- a/net/8021q/vlan.h
+++ b/net/8021q/vlan.h
@@ -171,6 +171,22 @@ static inline int vlan_gvrp_init(void) { return 0; }
171static inline void vlan_gvrp_uninit(void) {} 171static inline void vlan_gvrp_uninit(void) {}
172#endif 172#endif
173 173
174#ifdef CONFIG_VLAN_8021Q_MVRP
175extern int vlan_mvrp_request_join(const struct net_device *dev);
176extern void vlan_mvrp_request_leave(const struct net_device *dev);
177extern int vlan_mvrp_init_applicant(struct net_device *dev);
178extern void vlan_mvrp_uninit_applicant(struct net_device *dev);
179extern int vlan_mvrp_init(void);
180extern void vlan_mvrp_uninit(void);
181#else
182static inline int vlan_mvrp_request_join(const struct net_device *dev) { return 0; }
183static inline void vlan_mvrp_request_leave(const struct net_device *dev) {}
184static inline int vlan_mvrp_init_applicant(struct net_device *dev) { return 0; }
185static inline void vlan_mvrp_uninit_applicant(struct net_device *dev) {}
186static inline int vlan_mvrp_init(void) { return 0; }
187static inline void vlan_mvrp_uninit(void) {}
188#endif
189
174extern const char vlan_fullname[]; 190extern const char vlan_fullname[];
175extern const char vlan_version[]; 191extern const char vlan_version[];
176extern int vlan_netlink_init(void); 192extern int vlan_netlink_init(void);
diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c
index 09f9108d4688..34df5b3c9b75 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)
261 u32 old_flags = vlan->flags; 261 u32 old_flags = vlan->flags;
262 262
263 if (mask & ~(VLAN_FLAG_REORDER_HDR | VLAN_FLAG_GVRP | 263 if (mask & ~(VLAN_FLAG_REORDER_HDR | VLAN_FLAG_GVRP |
264 VLAN_FLAG_LOOSE_BINDING)) 264 VLAN_FLAG_LOOSE_BINDING | VLAN_FLAG_MVRP))
265 return -EINVAL; 265 return -EINVAL;
266 266
267 vlan->flags = (old_flags & ~mask) | (flags & mask); 267 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)
272 else 272 else
273 vlan_gvrp_request_leave(dev); 273 vlan_gvrp_request_leave(dev);
274 } 274 }
275
276 if (netif_running(dev) && (vlan->flags ^ old_flags) & VLAN_FLAG_MVRP) {
277 if (vlan->flags & VLAN_FLAG_MVRP)
278 vlan_mvrp_request_join(dev);
279 else
280 vlan_mvrp_request_leave(dev);
281 }
275 return 0; 282 return 0;
276} 283}
277 284
@@ -312,6 +319,9 @@ static int vlan_dev_open(struct net_device *dev)
312 if (vlan->flags & VLAN_FLAG_GVRP) 319 if (vlan->flags & VLAN_FLAG_GVRP)
313 vlan_gvrp_request_join(dev); 320 vlan_gvrp_request_join(dev);
314 321
322 if (vlan->flags & VLAN_FLAG_MVRP)
323 vlan_mvrp_request_join(dev);
324
315 if (netif_carrier_ok(real_dev)) 325 if (netif_carrier_ok(real_dev))
316 netif_carrier_on(dev); 326 netif_carrier_on(dev);
317 return 0; 327 return 0;
diff --git a/net/8021q/vlan_mvrp.c b/net/8021q/vlan_mvrp.c
new file mode 100644
index 000000000000..d9ec1d5964aa
--- /dev/null
+++ b/net/8021q/vlan_mvrp.c
@@ -0,0 +1,72 @@
1/*
2 * IEEE 802.1Q Multiple VLAN Registration Protocol (MVRP)
3 *
4 * Copyright (c) 2012 Massachusetts Institute of Technology
5 *
6 * Adapted from code in net/8021q/vlan_gvrp.c
7 * Copyright (c) 2008 Patrick McHardy <kaber@trash.net>
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * version 2 as published by the Free Software Foundation.
12 */
13#include <linux/types.h>
14#include <linux/if_ether.h>
15#include <linux/if_vlan.h>
16#include <net/mrp.h>
17#include "vlan.h"
18
19#define MRP_MVRP_ADDRESS { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x21 }
20
21enum mvrp_attributes {
22 MVRP_ATTR_INVALID,
23 MVRP_ATTR_VID,
24 __MVRP_ATTR_MAX
25};
26#define MVRP_ATTR_MAX (__MVRP_ATTR_MAX - 1)
27
28static struct mrp_application vlan_mrp_app __read_mostly = {
29 .type = MRP_APPLICATION_MVRP,
30 .maxattr = MVRP_ATTR_MAX,
31 .pkttype.type = htons(ETH_P_MVRP),
32 .group_address = MRP_MVRP_ADDRESS,
33 .version = 0,
34};
35
36int vlan_mvrp_request_join(const struct net_device *dev)
37{
38 const struct vlan_dev_priv *vlan = vlan_dev_priv(dev);
39 __be16 vlan_id = htons(vlan->vlan_id);
40
41 return mrp_request_join(vlan->real_dev, &vlan_mrp_app,
42 &vlan_id, sizeof(vlan_id), MVRP_ATTR_VID);
43}
44
45void vlan_mvrp_request_leave(const struct net_device *dev)
46{
47 const struct vlan_dev_priv *vlan = vlan_dev_priv(dev);
48 __be16 vlan_id = htons(vlan->vlan_id);
49
50 mrp_request_leave(vlan->real_dev, &vlan_mrp_app,
51 &vlan_id, sizeof(vlan_id), MVRP_ATTR_VID);
52}
53
54int vlan_mvrp_init_applicant(struct net_device *dev)
55{
56 return mrp_init_applicant(dev, &vlan_mrp_app);
57}
58
59void vlan_mvrp_uninit_applicant(struct net_device *dev)
60{
61 mrp_uninit_applicant(dev, &vlan_mrp_app);
62}
63
64int __init vlan_mvrp_init(void)
65{
66 return mrp_register_application(&vlan_mrp_app);
67}
68
69void vlan_mvrp_uninit(void)
70{
71 mrp_unregister_application(&vlan_mrp_app);
72}
diff --git a/net/8021q/vlan_netlink.c b/net/8021q/vlan_netlink.c
index 708c80ea1874..1789658b7cd7 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[])
62 flags = nla_data(data[IFLA_VLAN_FLAGS]); 62 flags = nla_data(data[IFLA_VLAN_FLAGS]);
63 if ((flags->flags & flags->mask) & 63 if ((flags->flags & flags->mask) &
64 ~(VLAN_FLAG_REORDER_HDR | VLAN_FLAG_GVRP | 64 ~(VLAN_FLAG_REORDER_HDR | VLAN_FLAG_GVRP |
65 VLAN_FLAG_LOOSE_BINDING)) 65 VLAN_FLAG_LOOSE_BINDING | VLAN_FLAG_MVRP))
66 return -EINVAL; 66 return -EINVAL;
67 } 67 }
68 68