diff options
Diffstat (limited to 'net/bridge')
-rw-r--r-- | net/bridge/br_if.c | 49 | ||||
-rw-r--r-- | net/bridge/br_notify.c | 14 | ||||
-rw-r--r-- | net/bridge/br_private.h | 3 |
3 files changed, 44 insertions, 22 deletions
diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c index 975abe254b7a..e6b8bb51d613 100644 --- a/net/bridge/br_if.c +++ b/net/bridge/br_if.c | |||
@@ -32,9 +32,8 @@ | |||
32 | * ethtool, use ethtool_ops. Also, since driver might sleep need to | 32 | * ethtool, use ethtool_ops. Also, since driver might sleep need to |
33 | * not be holding any locks. | 33 | * not be holding any locks. |
34 | */ | 34 | */ |
35 | static int br_initial_port_cost(struct net_device *dev) | 35 | static int port_cost(struct net_device *dev) |
36 | { | 36 | { |
37 | |||
38 | struct ethtool_cmd ecmd = { ETHTOOL_GSET }; | 37 | struct ethtool_cmd ecmd = { ETHTOOL_GSET }; |
39 | struct ifreq ifr; | 38 | struct ifreq ifr; |
40 | mm_segment_t old_fs; | 39 | mm_segment_t old_fs; |
@@ -58,10 +57,6 @@ static int br_initial_port_cost(struct net_device *dev) | |||
58 | return 2; | 57 | return 2; |
59 | case SPEED_10: | 58 | case SPEED_10: |
60 | return 100; | 59 | return 100; |
61 | default: | ||
62 | pr_info("bridge: can't decode speed from %s: %d\n", | ||
63 | dev->name, ecmd.speed); | ||
64 | return 100; | ||
65 | } | 60 | } |
66 | } | 61 | } |
67 | 62 | ||
@@ -75,6 +70,35 @@ static int br_initial_port_cost(struct net_device *dev) | |||
75 | return 100; /* assume old 10Mbps */ | 70 | return 100; /* assume old 10Mbps */ |
76 | } | 71 | } |
77 | 72 | ||
73 | |||
74 | /* | ||
75 | * Check for port carrier transistions. | ||
76 | * Called from work queue to allow for calling functions that | ||
77 | * might sleep (such as speed check), and to debounce. | ||
78 | */ | ||
79 | static void port_carrier_check(void *arg) | ||
80 | { | ||
81 | struct net_bridge_port *p = arg; | ||
82 | |||
83 | rtnl_lock(); | ||
84 | if (netif_carrier_ok(p->dev)) { | ||
85 | u32 cost = port_cost(p->dev); | ||
86 | |||
87 | spin_lock_bh(&p->br->lock); | ||
88 | if (p->state == BR_STATE_DISABLED) { | ||
89 | p->path_cost = cost; | ||
90 | br_stp_enable_port(p); | ||
91 | } | ||
92 | spin_unlock_bh(&p->br->lock); | ||
93 | } else { | ||
94 | spin_lock_bh(&p->br->lock); | ||
95 | if (p->state != BR_STATE_DISABLED) | ||
96 | br_stp_disable_port(p); | ||
97 | spin_unlock_bh(&p->br->lock); | ||
98 | } | ||
99 | rtnl_unlock(); | ||
100 | } | ||
101 | |||
78 | static void destroy_nbp(struct net_bridge_port *p) | 102 | static void destroy_nbp(struct net_bridge_port *p) |
79 | { | 103 | { |
80 | struct net_device *dev = p->dev; | 104 | struct net_device *dev = p->dev; |
@@ -102,6 +126,9 @@ static void del_nbp(struct net_bridge_port *p) | |||
102 | dev->br_port = NULL; | 126 | dev->br_port = NULL; |
103 | dev_set_promiscuity(dev, -1); | 127 | dev_set_promiscuity(dev, -1); |
104 | 128 | ||
129 | cancel_delayed_work(&p->carrier_check); | ||
130 | flush_scheduled_work(); | ||
131 | |||
105 | spin_lock_bh(&br->lock); | 132 | spin_lock_bh(&br->lock); |
106 | br_stp_disable_port(p); | 133 | br_stp_disable_port(p); |
107 | spin_unlock_bh(&br->lock); | 134 | spin_unlock_bh(&br->lock); |
@@ -195,10 +222,9 @@ static int find_portno(struct net_bridge *br) | |||
195 | return (index >= BR_MAX_PORTS) ? -EXFULL : index; | 222 | return (index >= BR_MAX_PORTS) ? -EXFULL : index; |
196 | } | 223 | } |
197 | 224 | ||
198 | /* called with RTNL */ | 225 | /* called with RTNL but without bridge lock */ |
199 | static struct net_bridge_port *new_nbp(struct net_bridge *br, | 226 | static struct net_bridge_port *new_nbp(struct net_bridge *br, |
200 | struct net_device *dev, | 227 | struct net_device *dev) |
201 | unsigned long cost) | ||
202 | { | 228 | { |
203 | int index; | 229 | int index; |
204 | struct net_bridge_port *p; | 230 | struct net_bridge_port *p; |
@@ -215,12 +241,13 @@ static struct net_bridge_port *new_nbp(struct net_bridge *br, | |||
215 | p->br = br; | 241 | p->br = br; |
216 | dev_hold(dev); | 242 | dev_hold(dev); |
217 | p->dev = dev; | 243 | p->dev = dev; |
218 | p->path_cost = cost; | 244 | p->path_cost = port_cost(dev); |
219 | p->priority = 0x8000 >> BR_PORT_BITS; | 245 | p->priority = 0x8000 >> BR_PORT_BITS; |
220 | dev->br_port = p; | 246 | dev->br_port = p; |
221 | p->port_no = index; | 247 | p->port_no = index; |
222 | br_init_port(p); | 248 | br_init_port(p); |
223 | p->state = BR_STATE_DISABLED; | 249 | p->state = BR_STATE_DISABLED; |
250 | INIT_WORK(&p->carrier_check, port_carrier_check, p); | ||
224 | kobject_init(&p->kobj); | 251 | kobject_init(&p->kobj); |
225 | 252 | ||
226 | return p; | 253 | return p; |
@@ -351,7 +378,7 @@ int br_add_if(struct net_bridge *br, struct net_device *dev) | |||
351 | if (dev->br_port != NULL) | 378 | if (dev->br_port != NULL) |
352 | return -EBUSY; | 379 | return -EBUSY; |
353 | 380 | ||
354 | if (IS_ERR(p = new_nbp(br, dev, br_initial_port_cost(dev)))) | 381 | if (IS_ERR(p = new_nbp(br, dev))) |
355 | return PTR_ERR(p); | 382 | return PTR_ERR(p); |
356 | 383 | ||
357 | if ((err = br_fdb_insert(br, p, dev->dev_addr))) | 384 | if ((err = br_fdb_insert(br, p, dev->dev_addr))) |
diff --git a/net/bridge/br_notify.c b/net/bridge/br_notify.c index 917311c6828b..a43a9c1d50d7 100644 --- a/net/bridge/br_notify.c +++ b/net/bridge/br_notify.c | |||
@@ -52,17 +52,9 @@ static int br_device_event(struct notifier_block *unused, unsigned long event, v | |||
52 | br_stp_recalculate_bridge_id(br); | 52 | br_stp_recalculate_bridge_id(br); |
53 | break; | 53 | break; |
54 | 54 | ||
55 | case NETDEV_CHANGE: /* device is up but carrier changed */ | 55 | case NETDEV_CHANGE: |
56 | if (!(br->dev->flags & IFF_UP)) | 56 | if (br->dev->flags & IFF_UP) |
57 | break; | 57 | schedule_delayed_work(&p->carrier_check, BR_PORT_DEBOUNCE); |
58 | |||
59 | if (netif_carrier_ok(dev)) { | ||
60 | if (p->state == BR_STATE_DISABLED) | ||
61 | br_stp_enable_port(p); | ||
62 | } else { | ||
63 | if (p->state != BR_STATE_DISABLED) | ||
64 | br_stp_disable_port(p); | ||
65 | } | ||
66 | break; | 58 | break; |
67 | 59 | ||
68 | case NETDEV_FEAT_CHANGE: | 60 | case NETDEV_FEAT_CHANGE: |
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h index 2c249486476f..7ad53c2aa684 100644 --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h | |||
@@ -27,6 +27,8 @@ | |||
27 | #define BR_PORT_BITS 10 | 27 | #define BR_PORT_BITS 10 |
28 | #define BR_MAX_PORTS (1<<BR_PORT_BITS) | 28 | #define BR_MAX_PORTS (1<<BR_PORT_BITS) |
29 | 29 | ||
30 | #define BR_PORT_DEBOUNCE (HZ/10) | ||
31 | |||
30 | typedef struct bridge_id bridge_id; | 32 | typedef struct bridge_id bridge_id; |
31 | typedef struct mac_addr mac_addr; | 33 | typedef struct mac_addr mac_addr; |
32 | typedef __u16 port_id; | 34 | typedef __u16 port_id; |
@@ -78,6 +80,7 @@ struct net_bridge_port | |||
78 | struct timer_list hold_timer; | 80 | struct timer_list hold_timer; |
79 | struct timer_list message_age_timer; | 81 | struct timer_list message_age_timer; |
80 | struct kobject kobj; | 82 | struct kobject kobj; |
83 | struct work_struct carrier_check; | ||
81 | struct rcu_head rcu; | 84 | struct rcu_head rcu; |
82 | }; | 85 | }; |
83 | 86 | ||