diff options
author | David Ward <david.ward@ll.mit.edu> | 2013-02-08 12:17:07 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2013-02-10 20:37:22 -0500 |
commit | 86fbe9bb599fcaf7e92e38dbfdad0414a2d68f7d (patch) | |
tree | 2e8b109de2f0e3b5c1b59f8dd2737388109ef982 | |
parent | febf018d22347b5df94066bca05d0c11a84e839d (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.h | 1 | ||||
-rw-r--r-- | include/uapi/linux/if_vlan.h | 1 | ||||
-rw-r--r-- | net/8021q/Kconfig | 11 | ||||
-rw-r--r-- | net/8021q/Makefile | 1 | ||||
-rw-r--r-- | net/8021q/vlan.c | 27 | ||||
-rw-r--r-- | net/8021q/vlan.h | 16 | ||||
-rw-r--r-- | net/8021q/vlan_dev.c | 12 | ||||
-rw-r--r-- | net/8021q/vlan_mvrp.c | 72 | ||||
-rw-r--r-- | net/8021q/vlan_netlink.c | 2 |
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 | ||
39 | enum vlan_name_types { | 40 | enum 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 | |||
31 | config 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 | ||
7 | 8021q-y := vlan.o vlan_dev.o vlan_netlink.o | 7 | 8021q-y := vlan.o vlan_dev.o vlan_netlink.o |
8 | 8021q-$(CONFIG_VLAN_8021Q_GVRP) += vlan_gvrp.o | 8 | 8021q-$(CONFIG_VLAN_8021Q_GVRP) += vlan_gvrp.o |
9 | 8021q-$(CONFIG_VLAN_8021Q_MVRP) += vlan_mvrp.o | ||
9 | 8021q-$(CONFIG_PROC_FS) += vlanproc.o | 10 | 8021q-$(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 | ||
182 | out_upper_dev_unlink: | 189 | out_upper_dev_unlink: |
183 | netdev_upper_dev_unlink(real_dev, dev); | 190 | netdev_upper_dev_unlink(real_dev, dev); |
184 | out_uninit_applicant: | 191 | out_uninit_mvrp: |
192 | if (grp->nr_vlan_devs == 0) | ||
193 | vlan_mvrp_uninit_applicant(real_dev); | ||
194 | out_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); |
187 | out_vid_del: | 197 | out_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 | ||
679 | err5: | ||
680 | vlan_mvrp_uninit(); | ||
665 | err4: | 681 | err4: |
666 | vlan_gvrp_uninit(); | 682 | vlan_gvrp_uninit(); |
667 | err3: | 683 | err3: |
@@ -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; } | |||
171 | static inline void vlan_gvrp_uninit(void) {} | 171 | static inline void vlan_gvrp_uninit(void) {} |
172 | #endif | 172 | #endif |
173 | 173 | ||
174 | #ifdef CONFIG_VLAN_8021Q_MVRP | ||
175 | extern int vlan_mvrp_request_join(const struct net_device *dev); | ||
176 | extern void vlan_mvrp_request_leave(const struct net_device *dev); | ||
177 | extern int vlan_mvrp_init_applicant(struct net_device *dev); | ||
178 | extern void vlan_mvrp_uninit_applicant(struct net_device *dev); | ||
179 | extern int vlan_mvrp_init(void); | ||
180 | extern void vlan_mvrp_uninit(void); | ||
181 | #else | ||
182 | static inline int vlan_mvrp_request_join(const struct net_device *dev) { return 0; } | ||
183 | static inline void vlan_mvrp_request_leave(const struct net_device *dev) {} | ||
184 | static inline int vlan_mvrp_init_applicant(struct net_device *dev) { return 0; } | ||
185 | static inline void vlan_mvrp_uninit_applicant(struct net_device *dev) {} | ||
186 | static inline int vlan_mvrp_init(void) { return 0; } | ||
187 | static inline void vlan_mvrp_uninit(void) {} | ||
188 | #endif | ||
189 | |||
174 | extern const char vlan_fullname[]; | 190 | extern const char vlan_fullname[]; |
175 | extern const char vlan_version[]; | 191 | extern const char vlan_version[]; |
176 | extern int vlan_netlink_init(void); | 192 | extern 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 | |||
21 | enum 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 | |||
28 | static 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 | |||
36 | int 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 | |||
45 | void 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 | |||
54 | int vlan_mvrp_init_applicant(struct net_device *dev) | ||
55 | { | ||
56 | return mrp_init_applicant(dev, &vlan_mrp_app); | ||
57 | } | ||
58 | |||
59 | void vlan_mvrp_uninit_applicant(struct net_device *dev) | ||
60 | { | ||
61 | mrp_uninit_applicant(dev, &vlan_mrp_app); | ||
62 | } | ||
63 | |||
64 | int __init vlan_mvrp_init(void) | ||
65 | { | ||
66 | return mrp_register_application(&vlan_mrp_app); | ||
67 | } | ||
68 | |||
69 | void 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 | ||