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).
Unified · Split
| @@ -83,6 +83,7 @@ · 82 unmodified lines | |||
| 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 */ |
| @@ -34,6 +34,7 @@ enum vlan_flags { · 33 unmodified lines | |||
| 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 { |
| @@ -27,3 +27,14 @@ config VLAN_8021Q_GVRP · 26 unmodified lines | |||
| 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. | ||
| @@ -6,5 +6,6 @@ obj-$(CONFIG_VLAN_8021Q) += 8021q.o · 5 unmodified lines | |||
| 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 | ||
| @@ -95,6 +95,8 @@ void unregister_vlan_dev(struct net_device *dev, struct list_head *head) · 94 unmodified lines | |||
| 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) · 6 unmodified lines | |||
| 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) · 36 unmodified lines | |||
| 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) · 15 unmodified lines | |||
| 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) · 467 unmodified lines | |||
| 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) · 14 unmodified lines | |||
| 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 | ||
| @@ -171,6 +171,22 @@ static inline int vlan_gvrp_init(void) { return 0; } · 170 unmodified lines | |||
| 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); |
| @@ -261,7 +261,7 @@ int vlan_dev_change_flags(const struct net_device *dev, u32 flags, u32 mask) · 260 unmodified lines | |||
| 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) · 4 unmodified lines | |||
| 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) · 34 unmodified lines | |||
| 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; |
| @@ -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 | } | ||
| @@ -62,7 +62,7 @@ static int vlan_validate(struct nlattr *tb[], struct nlattr *data[]) · 61 unmodified lines | |||
| 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 | ||