aboutsummaryrefslogtreecommitdiffstats
path: root/net/bridge
diff options
context:
space:
mode:
authorstephen hemminger <shemminger@vyatta.com>2011-10-03 14:14:46 -0400
committerDavid S. Miller <davem@davemloft.net>2011-10-06 15:27:56 -0400
commit515853ccecc6987dfb8ed809dd8bf8900286f29e (patch)
treeddd361a7bacb3d37a95f6101ef541af91c01d9ba /net/bridge
parent45b58465acaa9d98354e7fa730e3172c5355da06 (diff)
bridge: allow forwarding some link local frames
This is based on an earlier patch by Nick Carter with comments by David Lamparter but with some refinements. Thanks for their patience this is a confusing area with overlap of standards, user requirements, and compatibility with earlier releases. It adds a new sysfs attribute /sys/class/net/brX/bridge/group_fwd_mask that controls forwarding of frames with address of: 01-80-C2-00-00-0X The default setting has no forwarding to retain compatibility. One change from earlier releases is that forwarding of group addresses is not dependent on STP being enabled or disabled. This choice was made based on interpretation of tie 802.1 standards. I expect complaints will arise because of this, but better to follow the standard than continue acting incorrectly by default. The filtering mask is writeable, but only values that don't forward known control frames are allowed. It intentionally blocks attempts to filter control protocols. For example: writing a 8 allows forwarding 802.1X PAE addresses which is the most common request. Reported-by: David Lamparter <equinox@diac24.net> Original-patch-by: Nick Carter <ncarter100@gmail.com> Signed-off-by: Stephen Hemminger <shemminger@vyatta.com> Tested-by: Benjamin Poirier <benjamin.poirier@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/bridge')
-rw-r--r--net/bridge/br_device.c2
-rw-r--r--net/bridge/br_input.c33
-rw-r--r--net/bridge/br_private.h7
-rw-r--r--net/bridge/br_sysfs_br.c34
4 files changed, 71 insertions, 5 deletions
diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c
index ee68eee79e52..28325d15773b 100644
--- a/net/bridge/br_device.c
+++ b/net/bridge/br_device.c
@@ -361,6 +361,8 @@ void br_dev_setup(struct net_device *dev)
361 memcpy(br->group_addr, br_group_address, ETH_ALEN); 361 memcpy(br->group_addr, br_group_address, ETH_ALEN);
362 362
363 br->stp_enabled = BR_NO_STP; 363 br->stp_enabled = BR_NO_STP;
364 br->group_fwd_mask = BR_GROUPFWD_DEFAULT;
365
364 br->designated_root = br->bridge_id; 366 br->designated_root = br->bridge_id;
365 br->bridge_max_age = br->max_age = 20 * HZ; 367 br->bridge_max_age = br->max_age = 20 * HZ;
366 br->bridge_hello_time = br->hello_time = 2 * HZ; 368 br->bridge_hello_time = br->hello_time = 2 * HZ;
diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c
index f06ee39c73fd..6f9f8c014725 100644
--- a/net/bridge/br_input.c
+++ b/net/bridge/br_input.c
@@ -162,14 +162,37 @@ rx_handler_result_t br_handle_frame(struct sk_buff **pskb)
162 p = br_port_get_rcu(skb->dev); 162 p = br_port_get_rcu(skb->dev);
163 163
164 if (unlikely(is_link_local(dest))) { 164 if (unlikely(is_link_local(dest))) {
165 /* Pause frames shouldn't be passed up by driver anyway */ 165 /*
166 if (skb->protocol == htons(ETH_P_PAUSE)) 166 * See IEEE 802.1D Table 7-10 Reserved addresses
167 *
168 * Assignment Value
169 * Bridge Group Address 01-80-C2-00-00-00
170 * (MAC Control) 802.3 01-80-C2-00-00-01
171 * (Link Aggregation) 802.3 01-80-C2-00-00-02
172 * 802.1X PAE address 01-80-C2-00-00-03
173 *
174 * 802.1AB LLDP 01-80-C2-00-00-0E
175 *
176 * Others reserved for future standardization
177 */
178 switch (dest[5]) {
179 case 0x00: /* Bridge Group Address */
180 /* If STP is turned off,
181 then must forward to keep loop detection */
182 if (p->br->stp_enabled == BR_NO_STP)
183 goto forward;
184 break;
185
186 case 0x01: /* IEEE MAC (Pause) */
167 goto drop; 187 goto drop;
168 188
169 /* If STP is turned off, then forward */ 189 default:
170 if (p->br->stp_enabled == BR_NO_STP && dest[5] == 0) 190 /* Allow selective forwarding for most other protocols */
171 goto forward; 191 if (p->br->group_fwd_mask & (1u << dest[5]))
192 goto forward;
193 }
172 194
195 /* Deliver packet to local host only */
173 if (NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_IN, skb, skb->dev, 196 if (NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_IN, skb, skb->dev,
174 NULL, br_handle_local_finish)) { 197 NULL, br_handle_local_finish)) {
175 return RX_HANDLER_CONSUMED; /* consumed by filter */ 198 return RX_HANDLER_CONSUMED; /* consumed by filter */
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
index 78cc364997d9..a248fe65b29a 100644
--- a/net/bridge/br_private.h
+++ b/net/bridge/br_private.h
@@ -29,6 +29,11 @@
29 29
30#define BR_VERSION "2.3" 30#define BR_VERSION "2.3"
31 31
32/* Control of forwarding link local multicast */
33#define BR_GROUPFWD_DEFAULT 0
34/* Don't allow forwarding control protocols like STP and LLDP */
35#define BR_GROUPFWD_RESTRICTED 0x4007u
36
32/* Path to usermode spanning tree program */ 37/* Path to usermode spanning tree program */
33#define BR_STP_PROG "/sbin/bridge-stp" 38#define BR_STP_PROG "/sbin/bridge-stp"
34 39
@@ -193,6 +198,8 @@ struct net_bridge
193 unsigned long flags; 198 unsigned long flags;
194#define BR_SET_MAC_ADDR 0x00000001 199#define BR_SET_MAC_ADDR 0x00000001
195 200
201 u16 group_fwd_mask;
202
196 /* STP */ 203 /* STP */
197 bridge_id designated_root; 204 bridge_id designated_root;
198 bridge_id bridge_id; 205 bridge_id bridge_id;
diff --git a/net/bridge/br_sysfs_br.c b/net/bridge/br_sysfs_br.c
index 68b893ea8c3a..c236c0e43984 100644
--- a/net/bridge/br_sysfs_br.c
+++ b/net/bridge/br_sysfs_br.c
@@ -149,6 +149,39 @@ static ssize_t store_stp_state(struct device *d,
149static DEVICE_ATTR(stp_state, S_IRUGO | S_IWUSR, show_stp_state, 149static DEVICE_ATTR(stp_state, S_IRUGO | S_IWUSR, show_stp_state,
150 store_stp_state); 150 store_stp_state);
151 151
152static ssize_t show_group_fwd_mask(struct device *d,
153 struct device_attribute *attr, char *buf)
154{
155 struct net_bridge *br = to_bridge(d);
156 return sprintf(buf, "%#x\n", br->group_fwd_mask);
157}
158
159
160static ssize_t store_group_fwd_mask(struct device *d,
161 struct device_attribute *attr, const char *buf,
162 size_t len)
163{
164 struct net_bridge *br = to_bridge(d);
165 char *endp;
166 unsigned long val;
167
168 if (!capable(CAP_NET_ADMIN))
169 return -EPERM;
170
171 val = simple_strtoul(buf, &endp, 0);
172 if (endp == buf)
173 return -EINVAL;
174
175 if (val & BR_GROUPFWD_RESTRICTED)
176 return -EINVAL;
177
178 br->group_fwd_mask = val;
179
180 return len;
181}
182static DEVICE_ATTR(group_fwd_mask, S_IRUGO | S_IWUSR, show_group_fwd_mask,
183 store_group_fwd_mask);
184
152static ssize_t show_priority(struct device *d, struct device_attribute *attr, 185static ssize_t show_priority(struct device *d, struct device_attribute *attr,
153 char *buf) 186 char *buf)
154{ 187{
@@ -652,6 +685,7 @@ static struct attribute *bridge_attrs[] = {
652 &dev_attr_max_age.attr, 685 &dev_attr_max_age.attr,
653 &dev_attr_ageing_time.attr, 686 &dev_attr_ageing_time.attr,
654 &dev_attr_stp_state.attr, 687 &dev_attr_stp_state.attr,
688 &dev_attr_group_fwd_mask.attr,
655 &dev_attr_priority.attr, 689 &dev_attr_priority.attr,
656 &dev_attr_bridge_id.attr, 690 &dev_attr_bridge_id.attr,
657 &dev_attr_root_id.attr, 691 &dev_attr_root_id.attr,