aboutsummaryrefslogtreecommitdiffstats
path: root/net/bridge
diff options
context:
space:
mode:
Diffstat (limited to 'net/bridge')
-rw-r--r--net/bridge/br_device.c4
-rw-r--r--net/bridge/br_fdb.c23
-rw-r--r--net/bridge/br_if.c50
-rw-r--r--net/bridge/br_input.c33
-rw-r--r--net/bridge/br_netlink.c1
-rw-r--r--net/bridge/br_private.h8
-rw-r--r--net/bridge/br_sysfs_br.c34
-rw-r--r--net/bridge/netfilter/ebtable_broute.c4
8 files changed, 116 insertions, 41 deletions
diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c
index ff3ed6086ce1..feb77ea7b58e 100644
--- a/net/bridge/br_device.c
+++ b/net/bridge/br_device.c
@@ -301,7 +301,7 @@ static const struct net_device_ops br_netdev_ops = {
301 .ndo_start_xmit = br_dev_xmit, 301 .ndo_start_xmit = br_dev_xmit,
302 .ndo_get_stats64 = br_get_stats64, 302 .ndo_get_stats64 = br_get_stats64,
303 .ndo_set_mac_address = br_set_mac_address, 303 .ndo_set_mac_address = br_set_mac_address,
304 .ndo_set_multicast_list = br_dev_set_multicast_list, 304 .ndo_set_rx_mode = br_dev_set_multicast_list,
305 .ndo_change_mtu = br_change_mtu, 305 .ndo_change_mtu = br_change_mtu,
306 .ndo_do_ioctl = br_dev_ioctl, 306 .ndo_do_ioctl = br_dev_ioctl,
307#ifdef CONFIG_NET_POLL_CONTROLLER 307#ifdef CONFIG_NET_POLL_CONTROLLER
@@ -358,6 +358,8 @@ void br_dev_setup(struct net_device *dev)
358 memcpy(br->group_addr, br_group_address, ETH_ALEN); 358 memcpy(br->group_addr, br_group_address, ETH_ALEN);
359 359
360 br->stp_enabled = BR_NO_STP; 360 br->stp_enabled = BR_NO_STP;
361 br->group_fwd_mask = BR_GROUPFWD_DEFAULT;
362
361 br->designated_root = br->bridge_id; 363 br->designated_root = br->bridge_id;
362 br->bridge_max_age = br->max_age = 20 * HZ; 364 br->bridge_max_age = br->max_age = 20 * HZ;
363 br->bridge_hello_time = br->hello_time = 2 * HZ; 365 br->bridge_hello_time = br->hello_time = 2 * HZ;
diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c
index 68def3b7fb49..c8e7861b88b0 100644
--- a/net/bridge/br_fdb.c
+++ b/net/bridge/br_fdb.c
@@ -558,19 +558,28 @@ skip:
558 558
559/* Create new static fdb entry */ 559/* Create new static fdb entry */
560static int fdb_add_entry(struct net_bridge_port *source, const __u8 *addr, 560static int fdb_add_entry(struct net_bridge_port *source, const __u8 *addr,
561 __u16 state) 561 __u16 state, __u16 flags)
562{ 562{
563 struct net_bridge *br = source->br; 563 struct net_bridge *br = source->br;
564 struct hlist_head *head = &br->hash[br_mac_hash(addr)]; 564 struct hlist_head *head = &br->hash[br_mac_hash(addr)];
565 struct net_bridge_fdb_entry *fdb; 565 struct net_bridge_fdb_entry *fdb;
566 566
567 fdb = fdb_find(head, addr); 567 fdb = fdb_find(head, addr);
568 if (fdb) 568 if (fdb == NULL) {
569 return -EEXIST; 569 if (!(flags & NLM_F_CREATE))
570 return -ENOENT;
570 571
571 fdb = fdb_create(head, source, addr); 572 fdb = fdb_create(head, source, addr);
572 if (!fdb) 573 if (!fdb)
573 return -ENOMEM; 574 return -ENOMEM;
575 } else {
576 if (flags & NLM_F_EXCL)
577 return -EEXIST;
578
579 if (flags & NLM_F_REPLACE)
580 fdb->updated = fdb->used = jiffies;
581 fdb->is_local = fdb->is_static = 0;
582 }
574 583
575 if (state & NUD_PERMANENT) 584 if (state & NUD_PERMANENT)
576 fdb->is_local = fdb->is_static = 1; 585 fdb->is_local = fdb->is_static = 1;
@@ -626,7 +635,7 @@ int br_fdb_add(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
626 } 635 }
627 636
628 spin_lock_bh(&p->br->hash_lock); 637 spin_lock_bh(&p->br->hash_lock);
629 err = fdb_add_entry(p, addr, ndm->ndm_state); 638 err = fdb_add_entry(p, addr, ndm->ndm_state, nlh->nlmsg_flags);
630 spin_unlock_bh(&p->br->hash_lock); 639 spin_unlock_bh(&p->br->hash_lock);
631 640
632 return err; 641 return err;
diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c
index e73815456adf..f603e5b0b930 100644
--- a/net/bridge/br_if.c
+++ b/net/bridge/br_if.c
@@ -13,6 +13,7 @@
13 13
14#include <linux/kernel.h> 14#include <linux/kernel.h>
15#include <linux/netdevice.h> 15#include <linux/netdevice.h>
16#include <linux/etherdevice.h>
16#include <linux/netpoll.h> 17#include <linux/netpoll.h>
17#include <linux/ethtool.h> 18#include <linux/ethtool.h>
18#include <linux/if_arp.h> 19#include <linux/if_arp.h>
@@ -33,20 +34,18 @@
33 */ 34 */
34static int port_cost(struct net_device *dev) 35static int port_cost(struct net_device *dev)
35{ 36{
36 if (dev->ethtool_ops && dev->ethtool_ops->get_settings) { 37 struct ethtool_cmd ecmd;
37 struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET, }; 38
38 39 if (!__ethtool_get_settings(dev, &ecmd)) {
39 if (!dev_ethtool_get_settings(dev, &ecmd)) { 40 switch (ethtool_cmd_speed(&ecmd)) {
40 switch (ethtool_cmd_speed(&ecmd)) { 41 case SPEED_10000:
41 case SPEED_10000: 42 return 2;
42 return 2; 43 case SPEED_1000:
43 case SPEED_1000: 44 return 4;
44 return 4; 45 case SPEED_100:
45 case SPEED_100: 46 return 19;
46 return 19; 47 case SPEED_10:
47 case SPEED_10: 48 return 100;
48 return 100;
49 }
50 } 49 }
51 } 50 }
52 51
@@ -161,9 +160,10 @@ static void del_nbp(struct net_bridge_port *p)
161 call_rcu(&p->rcu, destroy_nbp_rcu); 160 call_rcu(&p->rcu, destroy_nbp_rcu);
162} 161}
163 162
164/* called with RTNL */ 163/* Delete bridge device */
165static void del_br(struct net_bridge *br, struct list_head *head) 164void br_dev_delete(struct net_device *dev, struct list_head *head)
166{ 165{
166 struct net_bridge *br = netdev_priv(dev);
167 struct net_bridge_port *p, *n; 167 struct net_bridge_port *p, *n;
168 168
169 list_for_each_entry_safe(p, n, &br->port_list, list) { 169 list_for_each_entry_safe(p, n, &br->port_list, list) {
@@ -268,7 +268,7 @@ int br_del_bridge(struct net *net, const char *name)
268 } 268 }
269 269
270 else 270 else
271 del_br(netdev_priv(dev), NULL); 271 br_dev_delete(dev, NULL);
272 272
273 rtnl_unlock(); 273 rtnl_unlock();
274 return ret; 274 return ret;
@@ -324,7 +324,8 @@ int br_add_if(struct net_bridge *br, struct net_device *dev)
324 324
325 /* Don't allow bridging non-ethernet like devices */ 325 /* Don't allow bridging non-ethernet like devices */
326 if ((dev->flags & IFF_LOOPBACK) || 326 if ((dev->flags & IFF_LOOPBACK) ||
327 dev->type != ARPHRD_ETHER || dev->addr_len != ETH_ALEN) 327 dev->type != ARPHRD_ETHER || dev->addr_len != ETH_ALEN ||
328 !is_valid_ether_addr(dev->dev_addr))
328 return -EINVAL; 329 return -EINVAL;
329 330
330 /* No bridging of bridges */ 331 /* No bridging of bridges */
@@ -352,10 +353,6 @@ int br_add_if(struct net_bridge *br, struct net_device *dev)
352 err = kobject_init_and_add(&p->kobj, &brport_ktype, &(dev->dev.kobj), 353 err = kobject_init_and_add(&p->kobj, &brport_ktype, &(dev->dev.kobj),
353 SYSFS_BRIDGE_PORT_ATTR); 354 SYSFS_BRIDGE_PORT_ATTR);
354 if (err) 355 if (err)
355 goto err0;
356
357 err = br_fdb_insert(br, p, dev->dev_addr);
358 if (err)
359 goto err1; 356 goto err1;
360 357
361 err = br_sysfs_addif(p); 358 err = br_sysfs_addif(p);
@@ -396,6 +393,9 @@ int br_add_if(struct net_bridge *br, struct net_device *dev)
396 393
397 dev_set_mtu(br->dev, br_min_mtu(br)); 394 dev_set_mtu(br->dev, br_min_mtu(br));
398 395
396 if (br_fdb_insert(br, p, dev->dev_addr))
397 netdev_err(dev, "failed insert local address bridge forwarding table\n");
398
399 kobject_uevent(&p->kobj, KOBJ_ADD); 399 kobject_uevent(&p->kobj, KOBJ_ADD);
400 400
401 return 0; 401 return 0;
@@ -405,11 +405,9 @@ err4:
405err3: 405err3:
406 sysfs_remove_link(br->ifobj, p->dev->name); 406 sysfs_remove_link(br->ifobj, p->dev->name);
407err2: 407err2:
408 br_fdb_delete_by_port(br, p, 1);
409err1:
410 kobject_put(&p->kobj); 408 kobject_put(&p->kobj);
411 p = NULL; /* kobject_put frees */ 409 p = NULL; /* kobject_put frees */
412err0: 410err1:
413 dev_set_promiscuity(dev, -1); 411 dev_set_promiscuity(dev, -1);
414put_back: 412put_back:
415 dev_put(dev); 413 dev_put(dev);
@@ -449,7 +447,7 @@ void __net_exit br_net_exit(struct net *net)
449 rtnl_lock(); 447 rtnl_lock();
450 for_each_netdev(net, dev) 448 for_each_netdev(net, dev)
451 if (dev->priv_flags & IFF_EBRIDGE) 449 if (dev->priv_flags & IFF_EBRIDGE)
452 del_br(netdev_priv(dev), &list); 450 br_dev_delete(dev, &list);
453 451
454 unregister_netdevice_many(&list); 452 unregister_netdevice_many(&list);
455 rtnl_unlock(); 453 rtnl_unlock();
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_netlink.c b/net/bridge/br_netlink.c
index 5b1ed1ba9aa7..e5f9ece3c9a0 100644
--- a/net/bridge/br_netlink.c
+++ b/net/bridge/br_netlink.c
@@ -210,6 +210,7 @@ static struct rtnl_link_ops br_link_ops __read_mostly = {
210 .priv_size = sizeof(struct net_bridge), 210 .priv_size = sizeof(struct net_bridge),
211 .setup = br_dev_setup, 211 .setup = br_dev_setup,
212 .validate = br_validate, 212 .validate = br_validate,
213 .dellink = br_dev_delete,
213}; 214};
214 215
215int __init br_netlink_init(void) 216int __init br_netlink_init(void)
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
index 78cc364997d9..d7d6fb05411f 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;
@@ -294,6 +301,7 @@ static inline int br_is_root_bridge(const struct net_bridge *br)
294 301
295/* br_device.c */ 302/* br_device.c */
296extern void br_dev_setup(struct net_device *dev); 303extern void br_dev_setup(struct net_device *dev);
304extern void br_dev_delete(struct net_device *dev, struct list_head *list);
297extern netdev_tx_t br_dev_xmit(struct sk_buff *skb, 305extern netdev_tx_t br_dev_xmit(struct sk_buff *skb,
298 struct net_device *dev); 306 struct net_device *dev);
299#ifdef CONFIG_NET_POLL_CONTROLLER 307#ifdef CONFIG_NET_POLL_CONTROLLER
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,
diff --git a/net/bridge/netfilter/ebtable_broute.c b/net/bridge/netfilter/ebtable_broute.c
index 1bcaf36ad612..40d8258bf74f 100644
--- a/net/bridge/netfilter/ebtable_broute.c
+++ b/net/bridge/netfilter/ebtable_broute.c
@@ -87,14 +87,14 @@ static int __init ebtable_broute_init(void)
87 if (ret < 0) 87 if (ret < 0)
88 return ret; 88 return ret;
89 /* see br_input.c */ 89 /* see br_input.c */
90 rcu_assign_pointer(br_should_route_hook, 90 RCU_INIT_POINTER(br_should_route_hook,
91 (br_should_route_hook_t *)ebt_broute); 91 (br_should_route_hook_t *)ebt_broute);
92 return 0; 92 return 0;
93} 93}
94 94
95static void __exit ebtable_broute_fini(void) 95static void __exit ebtable_broute_fini(void)
96{ 96{
97 rcu_assign_pointer(br_should_route_hook, NULL); 97 RCU_INIT_POINTER(br_should_route_hook, NULL);
98 synchronize_net(); 98 synchronize_net();
99 unregister_pernet_subsys(&broute_net_ops); 99 unregister_pernet_subsys(&broute_net_ops);
100} 100}