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 | 83 | #define ETH_P_802_EX1 0x88B5 /* 802.1 Local Experimental 1. */ |
| 84 | 84 | #define ETH_P_TIPC 0x88CA /* TIPC */ |
| 85 | 85 | #define ETH_P_8021AH 0x88E7 /* 802.1ah Backbone Service Tag */ |
| 86 | +#define ETH_P_MVRP 0x88F5 /* 802.1Q MVRP */ | |
| 86 | 87 | #define ETH_P_1588 0x88F7 /* IEEE 1588 Timesync */ |
| 87 | 88 | #define ETH_P_FCOE 0x8906 /* Fibre Channel over Ethernet */ |
| 88 | 89 | #define ETH_P_TDLS 0x890D /* TDLS */ |
| @@ -34,6 +34,7 @@ enum vlan_flags { · 33 unmodified lines | ||
| 34 | 34 | VLAN_FLAG_REORDER_HDR = 0x1, |
| 35 | 35 | VLAN_FLAG_GVRP = 0x2, |
| 36 | 36 | VLAN_FLAG_LOOSE_BINDING = 0x4, |
| 37 | + VLAN_FLAG_MVRP = 0x8, | |
| 37 | 38 | }; |
| 38 | 39 | |
| 39 | 40 | enum vlan_name_types { |
| @@ -27,3 +27,14 @@ config VLAN_8021Q_GVRP · 26 unmodified lines | ||
| 27 | 27 | automatic propagation of registered VLANs to switches. |
| 28 | 28 | |
| 29 | 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 | 7 | 8021q-y := vlan.o vlan_dev.o vlan_netlink.o |
| 8 | 8 | 8021q-$(CONFIG_VLAN_8021Q_GVRP) += vlan_gvrp.o |
| 9 | +8021q-$(CONFIG_VLAN_8021Q_MVRP) += vlan_mvrp.o | |
| 9 | 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 | 96 | grp->nr_vlan_devs--; |
| 97 | 97 | |
| 98 | + if (vlan->flags & VLAN_FLAG_MVRP) | |
| 99 | + vlan_mvrp_request_leave(dev); | |
| 98 | 100 | if (vlan->flags & VLAN_FLAG_GVRP) |
| 99 | 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 | 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 | 114 | vlan_gvrp_uninit_applicant(real_dev); |
| 115 | + } | |
| 112 | 116 | |
| 113 | 117 | /* Get rid of the vlan's reference to real_dev */ |
| 114 | 118 | dev_put(real_dev); |
| @@ -151,15 +155,18 @@ int register_vlan_dev(struct net_device *dev) · 36 unmodified lines | ||
| 151 | 155 | err = vlan_gvrp_init_applicant(real_dev); |
| 152 | 156 | if (err < 0) |
| 153 | 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 | 163 | err = vlan_group_prealloc_vid(grp, vlan_id); |
| 157 | 164 | if (err < 0) |
| 158 | − goto out_uninit_applicant; | |
| 165 | + goto out_uninit_mvrp; | |
| 159 | 166 | |
| 160 | 167 | err = netdev_upper_dev_link(real_dev, dev); |
| 161 | 168 | if (err) |
| 162 | − goto out_uninit_applicant; | |
| 169 | + goto out_uninit_mvrp; | |
| 163 | 170 | |
| 164 | 171 | err = register_netdevice(dev); |
| 165 | 172 | if (err < 0) |
| @@ -181,7 +188,10 @@ int register_vlan_dev(struct net_device *dev) · 15 unmodified lines | ||
| 181 | 188 | |
| 182 | 189 | out_upper_dev_unlink: |
| 183 | 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 | 195 | if (grp->nr_vlan_devs == 0) |
| 186 | 196 | vlan_gvrp_uninit_applicant(real_dev); |
| 187 | 197 | out_vid_del: |
| @@ -655,13 +665,19 @@ static int __init vlan_proto_init(void) · 467 unmodified lines | ||
| 655 | 665 | if (err < 0) |
| 656 | 666 | goto err3; |
| 657 | 667 | |
| 658 | − err = vlan_netlink_init(); | |
| 668 | + err = vlan_mvrp_init(); | |
| 659 | 669 | if (err < 0) |
| 660 | 670 | goto err4; |
| 661 | 671 | |
| 672 | + err = vlan_netlink_init(); | |
| 673 | + if (err < 0) | |
| 674 | + goto err5; | |
| 675 | + | |
| 662 | 676 | vlan_ioctl_set(vlan_ioctl_handler); |
| 663 | 677 | return 0; |
| 664 | 678 | |
| 679 | +err5: | |
| 680 | + vlan_mvrp_uninit(); | |
| 665 | 681 | err4: |
| 666 | 682 | vlan_gvrp_uninit(); |
| 667 | 683 | err3: |
| @@ -682,6 +698,7 @@ static void __exit vlan_cleanup_module(void) · 14 unmodified lines | ||
| 682 | 698 | unregister_pernet_subsys(&vlan_net_ops); |
| 683 | 699 | rcu_barrier(); /* Wait for completion of call_rcu()'s */ |
| 684 | 700 | |
| 701 | + vlan_mvrp_uninit(); | |
| 685 | 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 | 171 | static inline void vlan_gvrp_uninit(void) {} |
| 172 | 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 | 190 | extern const char vlan_fullname[]; |
| 175 | 191 | extern const char vlan_version[]; |
| 176 | 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 | 261 | u32 old_flags = vlan->flags; |
| 262 | 262 | |
| 263 | 263 | if (mask & ~(VLAN_FLAG_REORDER_HDR | VLAN_FLAG_GVRP | |
| 264 | − VLAN_FLAG_LOOSE_BINDING)) | |
| 264 | + VLAN_FLAG_LOOSE_BINDING | VLAN_FLAG_MVRP)) | |
| 265 | 265 | return -EINVAL; |
| 266 | 266 | |
| 267 | 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 | 272 | else |
| 273 | 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 | 282 | return 0; |
| 276 | 283 | } |
| 277 | 284 | |
| @@ -312,6 +319,9 @@ static int vlan_dev_open(struct net_device *dev) · 34 unmodified lines | ||
| 312 | 319 | if (vlan->flags & VLAN_FLAG_GVRP) |
| 313 | 320 | vlan_gvrp_request_join(dev); |
| 314 | 321 | |
| 322 | + if (vlan->flags & VLAN_FLAG_MVRP) | |
| 323 | + vlan_mvrp_request_join(dev); | |
| 324 | + | |
| 315 | 325 | if (netif_carrier_ok(real_dev)) |
| 316 | 326 | netif_carrier_on(dev); |
| 317 | 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 | 62 | flags = nla_data(data[IFLA_VLAN_FLAGS]); |
| 63 | 63 | if ((flags->flags & flags->mask) & |
| 64 | 64 | ~(VLAN_FLAG_REORDER_HDR | VLAN_FLAG_GVRP | |
| 65 | − VLAN_FLAG_LOOSE_BINDING)) | |
| 65 | + VLAN_FLAG_LOOSE_BINDING | VLAN_FLAG_MVRP)) | |
| 66 | 66 | return -EINVAL; |
| 67 | 67 | } |
| 68 | 68 | |