diff options
author | Patrick McHardy <kaber@trash.net> | 2008-07-06 00:26:57 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-07-06 00:26:57 -0400 |
commit | 70c03b49b80ba3634958acc31853771019c0ebd3 (patch) | |
tree | 097861a5da46fc10696c97f21720c1e5053b322f /net/8021q | |
parent | ce305002e1c9b90c2c151ce18bab0b895dd55ae6 (diff) |
vlan: Add GVRP support
Add GVRP support for dynamically registering VLANs with switches.
By default GVRP is disabled because we only support the applicant-only
participant model, which means it should not be enabled on vlans that
are members of a bridge. Since there is currently no way to cleanly
determine that, the user is responsible for enabling it.
The code is pretty small and low impact, its wrapped in a config
option though because it depends on the GARP implementation and
the STP core.
Signed-off-by: Patrick McHardy <kaber@trash.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/8021q')
-rw-r--r-- | net/8021q/Kconfig | 10 | ||||
-rw-r--r-- | net/8021q/Makefile | 9 | ||||
-rw-r--r-- | net/8021q/vlan.c | 23 | ||||
-rw-r--r-- | net/8021q/vlan.h | 16 | ||||
-rw-r--r-- | net/8021q/vlan_dev.c | 18 | ||||
-rw-r--r-- | net/8021q/vlan_gvrp.c | 66 | ||||
-rw-r--r-- | net/8021q/vlan_netlink.c | 3 |
7 files changed, 132 insertions, 13 deletions
diff --git a/net/8021q/Kconfig b/net/8021q/Kconfig index c4a382e450e2..fa073a54963e 100644 --- a/net/8021q/Kconfig +++ b/net/8021q/Kconfig | |||
@@ -17,3 +17,13 @@ config VLAN_8021Q | |||
17 | will be called 8021q. | 17 | will be called 8021q. |
18 | 18 | ||
19 | If unsure, say N. | 19 | If unsure, say N. |
20 | |||
21 | config VLAN_8021Q_GVRP | ||
22 | bool "GVRP (GARP VLAN Registration Protocol) support" | ||
23 | depends on VLAN_8021Q | ||
24 | select GARP | ||
25 | help | ||
26 | Select this to enable GVRP end-system support. GVRP is used for | ||
27 | automatic propagation of registered VLANs to switches. | ||
28 | |||
29 | If unsure, say N. | ||
diff --git a/net/8021q/Makefile b/net/8021q/Makefile index 10ca7f486c3a..3006e9ed7b08 100644 --- a/net/8021q/Makefile +++ b/net/8021q/Makefile | |||
@@ -4,9 +4,6 @@ | |||
4 | 4 | ||
5 | obj-$(CONFIG_VLAN_8021Q) += 8021q.o | 5 | obj-$(CONFIG_VLAN_8021Q) += 8021q.o |
6 | 6 | ||
7 | 8021q-objs := vlan.o vlan_dev.o vlan_netlink.o | 7 | 8021q-y := vlan.o vlan_dev.o vlan_netlink.o |
8 | 8 | 8021q-$(CONFIG_VLAN_8021Q_GVRP) += vlan_gvrp.o | |
9 | ifeq ($(CONFIG_PROC_FS),y) | 9 | 8021q-$(CONFIG_PROC_FS) += vlanproc.o |
10 | 8021q-objs += vlanproc.o | ||
11 | endif | ||
12 | |||
diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c index 8cae2daeb1cc..b529110c9355 100644 --- a/net/8021q/vlan.c +++ b/net/8021q/vlan.c | |||
@@ -169,6 +169,8 @@ void unregister_vlan_dev(struct net_device *dev) | |||
169 | 169 | ||
170 | /* If the group is now empty, kill off the group. */ | 170 | /* If the group is now empty, kill off the group. */ |
171 | if (grp->nr_vlans == 0) { | 171 | if (grp->nr_vlans == 0) { |
172 | vlan_gvrp_uninit_applicant(real_dev); | ||
173 | |||
172 | if (real_dev->features & NETIF_F_HW_VLAN_RX) | 174 | if (real_dev->features & NETIF_F_HW_VLAN_RX) |
173 | real_dev->vlan_rx_register(real_dev, NULL); | 175 | real_dev->vlan_rx_register(real_dev, NULL); |
174 | 176 | ||
@@ -249,15 +251,18 @@ int register_vlan_dev(struct net_device *dev) | |||
249 | ngrp = grp = vlan_group_alloc(real_dev); | 251 | ngrp = grp = vlan_group_alloc(real_dev); |
250 | if (!grp) | 252 | if (!grp) |
251 | return -ENOBUFS; | 253 | return -ENOBUFS; |
254 | err = vlan_gvrp_init_applicant(real_dev); | ||
255 | if (err < 0) | ||
256 | goto out_free_group; | ||
252 | } | 257 | } |
253 | 258 | ||
254 | err = vlan_group_prealloc_vid(grp, vlan_id); | 259 | err = vlan_group_prealloc_vid(grp, vlan_id); |
255 | if (err < 0) | 260 | if (err < 0) |
256 | goto out_free_group; | 261 | goto out_uninit_applicant; |
257 | 262 | ||
258 | err = register_netdevice(dev); | 263 | err = register_netdevice(dev); |
259 | if (err < 0) | 264 | if (err < 0) |
260 | goto out_free_group; | 265 | goto out_uninit_applicant; |
261 | 266 | ||
262 | /* Account for reference in struct vlan_dev_info */ | 267 | /* Account for reference in struct vlan_dev_info */ |
263 | dev_hold(real_dev); | 268 | dev_hold(real_dev); |
@@ -278,6 +283,9 @@ int register_vlan_dev(struct net_device *dev) | |||
278 | 283 | ||
279 | return 0; | 284 | return 0; |
280 | 285 | ||
286 | out_uninit_applicant: | ||
287 | if (ngrp) | ||
288 | vlan_gvrp_uninit_applicant(real_dev); | ||
281 | out_free_group: | 289 | out_free_group: |
282 | if (ngrp) | 290 | if (ngrp) |
283 | vlan_group_free(ngrp); | 291 | vlan_group_free(ngrp); |
@@ -713,14 +721,20 @@ static int __init vlan_proto_init(void) | |||
713 | if (err < 0) | 721 | if (err < 0) |
714 | goto err2; | 722 | goto err2; |
715 | 723 | ||
716 | err = vlan_netlink_init(); | 724 | err = vlan_gvrp_init(); |
717 | if (err < 0) | 725 | if (err < 0) |
718 | goto err3; | 726 | goto err3; |
719 | 727 | ||
728 | err = vlan_netlink_init(); | ||
729 | if (err < 0) | ||
730 | goto err4; | ||
731 | |||
720 | dev_add_pack(&vlan_packet_type); | 732 | dev_add_pack(&vlan_packet_type); |
721 | vlan_ioctl_set(vlan_ioctl_handler); | 733 | vlan_ioctl_set(vlan_ioctl_handler); |
722 | return 0; | 734 | return 0; |
723 | 735 | ||
736 | err4: | ||
737 | vlan_gvrp_uninit(); | ||
724 | err3: | 738 | err3: |
725 | unregister_netdevice_notifier(&vlan_notifier_block); | 739 | unregister_netdevice_notifier(&vlan_notifier_block); |
726 | err2: | 740 | err2: |
@@ -745,8 +759,9 @@ static void __exit vlan_cleanup_module(void) | |||
745 | BUG_ON(!hlist_empty(&vlan_group_hash[i])); | 759 | BUG_ON(!hlist_empty(&vlan_group_hash[i])); |
746 | 760 | ||
747 | unregister_pernet_gen_device(vlan_net_id, &vlan_net_ops); | 761 | unregister_pernet_gen_device(vlan_net_id, &vlan_net_ops); |
748 | |||
749 | synchronize_net(); | 762 | synchronize_net(); |
763 | |||
764 | vlan_gvrp_uninit(); | ||
750 | } | 765 | } |
751 | 766 | ||
752 | module_init(vlan_proto_init); | 767 | module_init(vlan_proto_init); |
diff --git a/net/8021q/vlan.h b/net/8021q/vlan.h index 639e2544a804..097b2e04c928 100644 --- a/net/8021q/vlan.h +++ b/net/8021q/vlan.h | |||
@@ -37,6 +37,22 @@ void vlan_setup(struct net_device *dev); | |||
37 | int register_vlan_dev(struct net_device *dev); | 37 | int register_vlan_dev(struct net_device *dev); |
38 | void unregister_vlan_dev(struct net_device *dev); | 38 | void unregister_vlan_dev(struct net_device *dev); |
39 | 39 | ||
40 | #ifdef CONFIG_VLAN_8021Q_GVRP | ||
41 | extern int vlan_gvrp_request_join(const struct net_device *dev); | ||
42 | extern void vlan_gvrp_request_leave(const struct net_device *dev); | ||
43 | extern int vlan_gvrp_init_applicant(struct net_device *dev); | ||
44 | extern void vlan_gvrp_uninit_applicant(struct net_device *dev); | ||
45 | extern int vlan_gvrp_init(void); | ||
46 | extern void vlan_gvrp_uninit(void); | ||
47 | #else | ||
48 | static inline int vlan_gvrp_request_join(const struct net_device *dev) { return 0; } | ||
49 | static inline void vlan_gvrp_request_leave(const struct net_device *dev) {} | ||
50 | static inline int vlan_gvrp_init_applicant(struct net_device *dev) { return 0; } | ||
51 | static inline void vlan_gvrp_uninit_applicant(struct net_device *dev) {} | ||
52 | static inline int vlan_gvrp_init(void) { return 0; } | ||
53 | static inline void vlan_gvrp_uninit(void) {} | ||
54 | #endif | ||
55 | |||
40 | int vlan_netlink_init(void); | 56 | int vlan_netlink_init(void); |
41 | void vlan_netlink_fini(void); | 57 | void vlan_netlink_fini(void); |
42 | 58 | ||
diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c index 76c665cdab66..a0617bf7cec6 100644 --- a/net/8021q/vlan_dev.c +++ b/net/8021q/vlan_dev.c | |||
@@ -512,10 +512,17 @@ int vlan_dev_change_flags(const struct net_device *dev, u32 flags, u32 mask) | |||
512 | struct vlan_dev_info *vlan = vlan_dev_info(dev); | 512 | struct vlan_dev_info *vlan = vlan_dev_info(dev); |
513 | u32 old_flags = vlan->flags; | 513 | u32 old_flags = vlan->flags; |
514 | 514 | ||
515 | if (mask & ~VLAN_FLAG_REORDER_HDR) | 515 | if (mask & ~(VLAN_FLAG_REORDER_HDR | VLAN_FLAG_GVRP)) |
516 | return -EINVAL; | 516 | return -EINVAL; |
517 | 517 | ||
518 | vlan->flags = (old_flags & ~mask) | (flags & mask); | 518 | vlan->flags = (old_flags & ~mask) | (flags & mask); |
519 | |||
520 | if (netif_running(dev) && (vlan->flags ^ old_flags) & VLAN_FLAG_GVRP) { | ||
521 | if (vlan->flags & VLAN_FLAG_GVRP) | ||
522 | vlan_gvrp_request_join(dev); | ||
523 | else | ||
524 | vlan_gvrp_request_leave(dev); | ||
525 | } | ||
519 | return 0; | 526 | return 0; |
520 | } | 527 | } |
521 | 528 | ||
@@ -550,12 +557,19 @@ static int vlan_dev_open(struct net_device *dev) | |||
550 | if (dev->flags & IFF_PROMISC) | 557 | if (dev->flags & IFF_PROMISC) |
551 | dev_set_promiscuity(real_dev, 1); | 558 | dev_set_promiscuity(real_dev, 1); |
552 | 559 | ||
560 | if (vlan->flags & VLAN_FLAG_GVRP) | ||
561 | vlan_gvrp_request_join(dev); | ||
562 | |||
553 | return 0; | 563 | return 0; |
554 | } | 564 | } |
555 | 565 | ||
556 | static int vlan_dev_stop(struct net_device *dev) | 566 | static int vlan_dev_stop(struct net_device *dev) |
557 | { | 567 | { |
558 | struct net_device *real_dev = vlan_dev_info(dev)->real_dev; | 568 | struct vlan_dev_info *vlan = vlan_dev_info(dev); |
569 | struct net_device *real_dev = vlan->real_dev; | ||
570 | |||
571 | if (vlan->flags & VLAN_FLAG_GVRP) | ||
572 | vlan_gvrp_request_leave(dev); | ||
559 | 573 | ||
560 | dev_mc_unsync(real_dev, dev); | 574 | dev_mc_unsync(real_dev, dev); |
561 | dev_unicast_unsync(real_dev, dev); | 575 | dev_unicast_unsync(real_dev, dev); |
diff --git a/net/8021q/vlan_gvrp.c b/net/8021q/vlan_gvrp.c new file mode 100644 index 000000000000..db9781608362 --- /dev/null +++ b/net/8021q/vlan_gvrp.c | |||
@@ -0,0 +1,66 @@ | |||
1 | /* | ||
2 | * IEEE 802.1Q GARP VLAN Registration Protocol (GVRP) | ||
3 | * | ||
4 | * Copyright (c) 2008 Patrick McHardy <kaber@trash.net> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License | ||
8 | * version 2 as published by the Free Software Foundation. | ||
9 | */ | ||
10 | #include <linux/types.h> | ||
11 | #include <linux/if_vlan.h> | ||
12 | #include <net/garp.h> | ||
13 | #include "vlan.h" | ||
14 | |||
15 | #define GARP_GVRP_ADDRESS { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x21 } | ||
16 | |||
17 | enum gvrp_attributes { | ||
18 | GVRP_ATTR_INVALID, | ||
19 | GVRP_ATTR_VID, | ||
20 | __GVRP_ATTR_MAX | ||
21 | }; | ||
22 | #define GVRP_ATTR_MAX (__GVRP_ATTR_MAX - 1) | ||
23 | |||
24 | static struct garp_application vlan_gvrp_app __read_mostly = { | ||
25 | .proto.group_address = GARP_GVRP_ADDRESS, | ||
26 | .maxattr = GVRP_ATTR_MAX, | ||
27 | .type = GARP_APPLICATION_GVRP, | ||
28 | }; | ||
29 | |||
30 | int vlan_gvrp_request_join(const struct net_device *dev) | ||
31 | { | ||
32 | const struct vlan_dev_info *vlan = vlan_dev_info(dev); | ||
33 | __be16 vid = htons(vlan->vlan_id); | ||
34 | |||
35 | return garp_request_join(vlan->real_dev, &vlan_gvrp_app, | ||
36 | &vid, sizeof(vid), GVRP_ATTR_VID); | ||
37 | } | ||
38 | |||
39 | void vlan_gvrp_request_leave(const struct net_device *dev) | ||
40 | { | ||
41 | const struct vlan_dev_info *vlan = vlan_dev_info(dev); | ||
42 | __be16 vid = htons(vlan->vlan_id); | ||
43 | |||
44 | garp_request_leave(vlan->real_dev, &vlan_gvrp_app, | ||
45 | &vid, sizeof(vid), GVRP_ATTR_VID); | ||
46 | } | ||
47 | |||
48 | int vlan_gvrp_init_applicant(struct net_device *dev) | ||
49 | { | ||
50 | return garp_init_applicant(dev, &vlan_gvrp_app); | ||
51 | } | ||
52 | |||
53 | void vlan_gvrp_uninit_applicant(struct net_device *dev) | ||
54 | { | ||
55 | garp_uninit_applicant(dev, &vlan_gvrp_app); | ||
56 | } | ||
57 | |||
58 | int __init vlan_gvrp_init(void) | ||
59 | { | ||
60 | return garp_register_application(&vlan_gvrp_app); | ||
61 | } | ||
62 | |||
63 | void vlan_gvrp_uninit(void) | ||
64 | { | ||
65 | garp_unregister_application(&vlan_gvrp_app); | ||
66 | } | ||
diff --git a/net/8021q/vlan_netlink.c b/net/8021q/vlan_netlink.c index fd7cb195d53f..e9c91dcecc9b 100644 --- a/net/8021q/vlan_netlink.c +++ b/net/8021q/vlan_netlink.c | |||
@@ -59,7 +59,8 @@ static int vlan_validate(struct nlattr *tb[], struct nlattr *data[]) | |||
59 | } | 59 | } |
60 | if (data[IFLA_VLAN_FLAGS]) { | 60 | if (data[IFLA_VLAN_FLAGS]) { |
61 | flags = nla_data(data[IFLA_VLAN_FLAGS]); | 61 | flags = nla_data(data[IFLA_VLAN_FLAGS]); |
62 | if ((flags->flags & flags->mask) & ~VLAN_FLAG_REORDER_HDR) | 62 | if ((flags->flags & flags->mask) & |
63 | ~(VLAN_FLAG_REORDER_HDR | VLAN_FLAG_GVRP)) | ||
63 | return -EINVAL; | 64 | return -EINVAL; |
64 | } | 65 | } |
65 | 66 | ||