Re: [RFC] bridge: allow passing link-local multicast
From: Nick Carter <hidden>
Date: 2011-08-18 15:06:20
Also in:
bridge
On 15 August 2011 23:05, Stephen Hemminger [off-list ref] wrote:
quoted hunk ↗ jump to hunk
Several users have wanted to forward 802.1x EAP multicast packets through a bridge. And there has been a couple of attempts at allowing some form of this in the past. If a bridge does not have spanning tree turned on, then it should act like a pure hub and forward all traffic. This makes it fully transparent, and if there is another bridge using spanning tree the STP packets will still work for detecting loops in the network. If bridge has STP enabled, then the default behavior is to process all link-local multicasts locally. The expectation is that if 802.1x or other protocol using link-local multicasts that a service (or proxy) for that protocol will be used. Optionally, a sysctl value can be set to allow non STP packets to still be forwarded. I chose sysctl for this because it is where such modifications exist when doing IP or netfilter. There are other filtering/configuration options that are needed and this is a better way to enable them. Thanks to David Lamparter, and others for bringing this up. Users who need this facility should provide feedback, is this a usable solution? Signed-off-by: Stephen Hemminger <redacted> --- Patch against net-next Documentation/networking/ip-sysctl.txt | 4 ++ net/bridge/Makefile | 2 - net/bridge/br.c | 12 ++++++ net/bridge/br_input.c | 30 ++++++++++++++++- net/bridge/br_private.h | 5 ++ net/bridge/br_sysctl.c | 57 +++++++++++++++++++++++++++++++++ 6 files changed, 107 insertions(+), 3 deletions(-)--- a/Documentation/networking/ip-sysctl.txt 2011-08-15 10:58:36.451532115 -0700 +++ b/Documentation/networking/ip-sysctl.txt 2011-08-15 11:39:57.719438766 -0700@@ -1289,6 +1289,10 @@ bridge-nf-filter-pppoe-tagged - BOOLEAN0 : disable this. Default: 1 +bridge-forward-link-local - BOOLEAN + 1 : pass link-local multicasts through bridge in STP mode + 0 : disable this. + Default: 0 proc/sys/net/sctp/* Variables:--- a/net/bridge/Makefile 2011-08-15 10:30:25.203595742 -0700 +++ b/net/bridge/Makefile 2011-08-15 11:22:38.139477877 -0700@@ -9,7 +9,7 @@ bridge-y := br.o br_device.o br_fdb.o brbr_stp_if.o br_stp_timer.o br_netlink.o bridge-$(CONFIG_SYSFS) += br_sysfs_if.o br_sysfs_br.o - +bridge-$(CONFIG_SYSCTL) += br_sysctl.o bridge-$(CONFIG_BRIDGE_NETFILTER) += br_netfilter.o bridge-$(CONFIG_BRIDGE_IGMP_SNOOPING) += br_multicast.o--- a/net/bridge/br.c 2011-08-15 10:30:48.755594855 -0700 +++ b/net/bridge/br.c 2011-08-15 10:33:07.215589647 -0700@@ -60,6 +60,12 @@ static int __init br_init(void)if (err) goto err_out4; +#ifdef CONFIG_SYSCTL + err = br_sysctl_init(); + if (err) + goto err_out5; +#endif + brioctl_set(br_ioctl_deviceless_stub); #if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE)@@ -67,6 +73,9 @@ static int __init br_init(void)#endif return 0; + +err_out5: + br_netlink_fini(); err_out4: unregister_netdevice_notifier(&br_device_notifier); err_out3:@@ -84,6 +93,9 @@ static void __exit br_deinit(void){ stp_proto_unregister(&br_stp_proto); +#ifdef CONFIG_SYSCTL + br_sysctl_fini(); +#endif br_netlink_fini(); unregister_netdevice_notifier(&br_device_notifier); brioctl_set(NULL);--- a/net/bridge/br_input.c 2011-08-15 10:40:21.435573311 -0700 +++ b/net/bridge/br_input.c 2011-08-15 11:39:57.719438766 -0700@@ -16,11 +16,18 @@#include <linux/netdevice.h> #include <linux/etherdevice.h> #include <linux/netfilter_bridge.h> +#include <linux/llc.h> +#include <net/llc.h> +#include <net/llc_pdu.h> + #include "br_private.h" /* Bridge group multicast address 802.1d (pg 51). */ const u8 br_group_address[ETH_ALEN] = { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x00 }; +/* Should link-local packets be forwarded (in STP mode) */ +int br_forward_link_local; + /* Hook for brouter */ br_should_route_hook_t __rcu *br_should_route_hook __read_mostly; EXPORT_SYMBOL(br_should_route_hook);@@ -138,6 +145,17 @@ static inline int is_link_local(const unreturn ((a[0] ^ b[0]) | (a[1] ^ b[1]) | ((a[2] ^ b[2]) & m)) == 0; } +/* Identify Spanning Tree packets based on header */
Why can't we use the 802.1D specified STP group address to identify ? The existing code uses that address. I know you said on another thread that there are people using other addresses. Who are these people ? Are they following any standard ? What address / address range are they using ? Thanks, Nick
quoted hunk ↗ jump to hunk
+static bool is_stp_bpdu(struct sk_buff *skb) +{ + struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb); + + return skb->protocol == htons(ETH_P_802_2) && + pdu->ctrl_1 == LLC_PDU_TYPE_U && + pdu->dsap == LLC_SAP_BSPAN && + pdu->ssap == LLC_SAP_BSPAN; +} + /* * Return NULL if skb is handled * note: already called with rcu_read_lock@@ -166,8 +184,16 @@ rx_handler_result_t br_handle_frame(struif (skb->protocol == htons(ETH_P_PAUSE)) goto drop; - /* If STP is turned off, then forward */ - if (p->br->stp_enabled == BR_NO_STP && dest[5] == 0) + /* If STP is turned off, then in hub mode */ + if (p->br->stp_enabled == BR_NO_STP) + goto forward; + + /* + * If STP is on + * then Always handle STP packets locally, + * other packets can be forwarded if sysctl is enabled. + */ + if (!is_stp_bpdu(skb) && br_forward_link_local) goto forward; if (NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_IN, skb, skb->dev,--- a/net/bridge/br_private.h 2011-08-15 10:38:35.587577293 -0700 +++ b/net/bridge/br_private.h 2011-08-15 10:57:36.983534352 -0700@@ -284,6 +284,7 @@ struct br_input_skb_cb {pr_debug("%s: " format, (br)->dev->name, ##args) extern struct notifier_block br_device_notifier; +extern int br_forward_link_local; extern const u8 br_group_address[ETH_ALEN]; /* called under bridge lock */@@ -546,6 +547,10 @@ extern int br_sysfs_renameif(struct net_extern int br_sysfs_addbr(struct net_device *dev); extern void br_sysfs_delbr(struct net_device *dev); +/* br_sysctl.c */ +extern int br_sysctl_init(void); +extern void br_sysctl_fini(void); + #else #define br_sysfs_addif(p) (0)--- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ b/net/bridge/br_sysctl.c 2011-08-15 11:41:00.819436393 -0700@@ -0,0 +1,57 @@ +/* + * Sysctl settings for bridge + * + * Authors: + * Stephen Hemminger <shemminger@osdl.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/ip.h> +#include <linux/netdevice.h> +#include <linux/skbuff.h> +#include <linux/if_arp.h> +#include <linux/if_ether.h> +#include <linux/if_vlan.h> +#include <linux/if_pppox.h> +#include <linux/sysctl.h> + +#include "br_private.h" + +static struct ctl_table bridge_table[] = { + { + .procname = "bridge-forward-link-local", + .data = &br_forward_link_local, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec + }, +}; + +static struct ctl_path bridge_ctl_path[] = { + { .procname = "net", }, + { .procname = "bridge", }, + { }, +}; + +static struct ctl_table_header *br_sysctl; + +int __init br_sysctl_init(void) +{ + br_sysctl = register_sysctl_paths(bridge_ctl_path, bridge_table); + if (br_sysctl == NULL) + return -ENOMEM; + + return 0; +} + +void __exit br_sysctl_fini(void) +{ + unregister_net_sysctl_table(br_sysctl); +}