Blame view
net/bridge/br_if.c
9.2 KB
1da177e4c Linux-2.6.12-rc2 |
1 2 3 4 5 6 7 |
/* * Userspace interface * Linux ethernet bridge * * Authors: * Lennert Buytenhek <buytenh@gnu.org> * |
1da177e4c Linux-2.6.12-rc2 |
8 9 10 11 12 13 14 15 |
* 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/kernel.h> #include <linux/netdevice.h> |
77f985983 bridge: fix order... |
16 |
#include <linux/etherdevice.h> |
c06ee961d bridge: make brid... |
17 |
#include <linux/netpoll.h> |
1da177e4c Linux-2.6.12-rc2 |
18 19 20 21 22 |
#include <linux/ethtool.h> #include <linux/if_arp.h> #include <linux/module.h> #include <linux/init.h> #include <linux/rtnetlink.h> |
46f25dffb [NET]: Change 150... |
23 |
#include <linux/if_ether.h> |
5a0e3ad6a include cleanup: ... |
24 |
#include <linux/slab.h> |
1da177e4c Linux-2.6.12-rc2 |
25 26 27 28 29 30 31 32 |
#include <net/sock.h> #include "br_private.h" /* * Determine initial path cost based on speed. * using recommendations from 802.1d standard * |
61a44b9c4 [NET]: ethtool op... |
33 |
* Since driver might sleep need to not be holding any locks. |
1da177e4c Linux-2.6.12-rc2 |
34 |
*/ |
4433f420e [BRIDGE]: handle ... |
35 |
static int port_cost(struct net_device *dev) |
1da177e4c Linux-2.6.12-rc2 |
36 |
{ |
fa3df928e br: remove redund... |
37 |
struct ethtool_cmd ecmd; |
b4a488d18 [BRIDGE]: Fix OOP... |
38 |
|
4bc71cb98 net: consolidate ... |
39 |
if (!__ethtool_get_settings(dev, &ecmd)) { |
fa3df928e br: remove redund... |
40 41 42 43 44 45 46 47 48 |
switch (ethtool_cmd_speed(&ecmd)) { case SPEED_10000: return 2; case SPEED_1000: return 4; case SPEED_100: return 19; case SPEED_10: return 100; |
1da177e4c Linux-2.6.12-rc2 |
49 50 51 52 53 54 55 56 57 58 59 60 |
} } /* Old silly heuristics based on name */ if (!strncmp(dev->name, "lec", 3)) return 7; if (!strncmp(dev->name, "plip", 4)) return 2500; return 100; /* assume old 10Mbps */ } |
4433f420e [BRIDGE]: handle ... |
61 |
|
944c794d6 bridge: fix locki... |
62 |
/* Check for port carrier transistions. */ |
269def7c5 [BRIDGE]: elimina... |
63 |
void br_port_carrier_check(struct net_bridge_port *p) |
4433f420e [BRIDGE]: handle ... |
64 |
{ |
269def7c5 [BRIDGE]: elimina... |
65 66 |
struct net_device *dev = p->dev; struct net_bridge *br = p->br; |
6e86b8908 [BRIDGE]: fix cra... |
67 |
|
aa7c6e5fa bridge: avoid eth... |
68 |
if (netif_running(dev) && netif_carrier_ok(dev)) |
6e86b8908 [BRIDGE]: fix cra... |
69 |
p->path_cost = port_cost(dev); |
aa7c6e5fa bridge: avoid eth... |
70 71 72 73 74 75 76 77 78 79 |
if (!netif_running(br->dev)) return; spin_lock_bh(&br->lock); if (netif_running(dev) && netif_carrier_ok(dev)) { if (p->state == BR_STATE_DISABLED) br_stp_enable_port(p); } else { if (p->state != BR_STATE_DISABLED) br_stp_disable_port(p); |
4433f420e [BRIDGE]: handle ... |
80 |
} |
aa7c6e5fa bridge: avoid eth... |
81 |
spin_unlock_bh(&br->lock); |
4433f420e [BRIDGE]: handle ... |
82 |
} |
bab1deea3 [BRIDGE]: fix err... |
83 84 85 86 87 88 89 90 91 92 93 94 95 |
static void release_nbp(struct kobject *kobj) { struct net_bridge_port *p = container_of(kobj, struct net_bridge_port, kobj); kfree(p); } static struct kobj_type brport_ktype = { #ifdef CONFIG_SYSFS .sysfs_ops = &brport_sysfs_ops, #endif .release = release_nbp, }; |
1da177e4c Linux-2.6.12-rc2 |
96 97 98 |
static void destroy_nbp(struct net_bridge_port *p) { struct net_device *dev = p->dev; |
1da177e4c Linux-2.6.12-rc2 |
99 100 101 |
p->br = NULL; p->dev = NULL; dev_put(dev); |
bab1deea3 [BRIDGE]: fix err... |
102 |
kobject_put(&p->kobj); |
1da177e4c Linux-2.6.12-rc2 |
103 104 105 106 107 108 109 110 |
} static void destroy_nbp_rcu(struct rcu_head *head) { struct net_bridge_port *p = container_of(head, struct net_bridge_port, rcu); destroy_nbp(p); } |
3f4cfc2d1 [BRIDGE]: Fix dev... |
111 112 113 114 115 116 117 118 119 |
/* Delete port(interface) from bridge is done in two steps. * via RCU. First step, marks device as down. That deletes * all the timers and stops new packets from flowing through. * * Final cleanup doesn't occur until after all CPU's finished * processing packets. * * Protected from multiple admin operations by RTNL mutex */ |
1da177e4c Linux-2.6.12-rc2 |
120 121 122 123 |
static void del_nbp(struct net_bridge_port *p) { struct net_bridge *br = p->br; struct net_device *dev = p->dev; |
b3bcb72ed bridge: fix build... |
124 |
sysfs_remove_link(br->ifobj, p->dev->name); |
bab1deea3 [BRIDGE]: fix err... |
125 |
|
1da177e4c Linux-2.6.12-rc2 |
126 127 128 129 130 |
dev_set_promiscuity(dev, -1); spin_lock_bh(&br->lock); br_stp_disable_port(p); spin_unlock_bh(&br->lock); |
b86c45035 bridge: change wh... |
131 |
br_ifinfo_notify(RTM_DELLINK, p); |
1a620698c [BRIDGE]: flush f... |
132 |
br_fdb_delete_by_port(br, p, 1); |
1da177e4c Linux-2.6.12-rc2 |
133 134 |
list_del_rcu(&p->list); |
f350a0a87 bridge: use rx_ha... |
135 |
dev->priv_flags &= ~IFF_BRIDGE_PORT; |
ab95bfe01 net: replace hook... |
136 |
netdev_rx_handler_unregister(dev); |
6df427fe8 net: remove synch... |
137 |
synchronize_net(); |
b3f1be4b5 [BRIDGE]: fix for... |
138 |
|
afc6151a7 bridge: implement... |
139 |
netdev_set_master(dev, NULL); |
3fe2d7c70 bridge: Add multi... |
140 |
br_multicast_del_port(p); |
125a12ccf [BRIDGE]: generat... |
141 |
kobject_uevent(&p->kobj, KOBJ_REMOVE); |
bab1deea3 [BRIDGE]: fix err... |
142 |
kobject_del(&p->kobj); |
91d2c34a4 bridge: Fix netpo... |
143 |
br_netpoll_disable(p); |
1da177e4c Linux-2.6.12-rc2 |
144 145 |
call_rcu(&p->rcu, destroy_nbp_rcu); } |
1ce5cce89 bridge: fix hang ... |
146 147 |
/* Delete bridge device */ void br_dev_delete(struct net_device *dev, struct list_head *head) |
1da177e4c Linux-2.6.12-rc2 |
148 |
{ |
1ce5cce89 bridge: fix hang ... |
149 |
struct net_bridge *br = netdev_priv(dev); |
1da177e4c Linux-2.6.12-rc2 |
150 151 152 |
struct net_bridge_port *p, *n; list_for_each_entry_safe(p, n, &br->port_list, list) { |
1da177e4c Linux-2.6.12-rc2 |
153 154 155 156 157 158 |
del_nbp(p); } del_timer_sync(&br->gc_timer); br_sysfs_delbr(br->dev); |
8c56ba053 bridge: Optimize ... |
159 |
unregister_netdevice_queue(br->dev, head); |
1da177e4c Linux-2.6.12-rc2 |
160 |
} |
1da177e4c Linux-2.6.12-rc2 |
161 162 163 164 165 166 |
/* find an available port number */ static int find_portno(struct net_bridge *br) { int index; struct net_bridge_port *p; unsigned long *inuse; |
3b781fa10 [BRIDGE]: use kca... |
167 |
inuse = kcalloc(BITS_TO_LONGS(BR_MAX_PORTS), sizeof(unsigned long), |
1da177e4c Linux-2.6.12-rc2 |
168 169 170 |
GFP_KERNEL); if (!inuse) return -ENOMEM; |
1da177e4c Linux-2.6.12-rc2 |
171 172 173 174 175 176 177 178 179 |
set_bit(0, inuse); /* zero is reserved */ list_for_each_entry(p, &br->port_list, list) { set_bit(p->port_no, inuse); } index = find_first_zero_bit(inuse, BR_MAX_PORTS); kfree(inuse); return (index >= BR_MAX_PORTS) ? -EXFULL : index; } |
4433f420e [BRIDGE]: handle ... |
180 |
/* called with RTNL but without bridge lock */ |
9d6f229fc [NET] BRIDGE: Fix... |
181 |
static struct net_bridge_port *new_nbp(struct net_bridge *br, |
4433f420e [BRIDGE]: handle ... |
182 |
struct net_device *dev) |
1da177e4c Linux-2.6.12-rc2 |
183 184 185 |
{ int index; struct net_bridge_port *p; |
9d6f229fc [NET] BRIDGE: Fix... |
186 |
|
1da177e4c Linux-2.6.12-rc2 |
187 188 189 |
index = find_portno(br); if (index < 0) return ERR_PTR(index); |
cee485412 [BRIDGE]: use kza... |
190 |
p = kzalloc(sizeof(*p), GFP_KERNEL); |
1da177e4c Linux-2.6.12-rc2 |
191 192 |
if (p == NULL) return ERR_PTR(-ENOMEM); |
1da177e4c Linux-2.6.12-rc2 |
193 194 195 |
p->br = br; dev_hold(dev); p->dev = dev; |
4433f420e [BRIDGE]: handle ... |
196 |
p->path_cost = port_cost(dev); |
9d6f229fc [NET] BRIDGE: Fix... |
197 |
p->priority = 0x8000 >> BR_PORT_BITS; |
1da177e4c Linux-2.6.12-rc2 |
198 |
p->port_no = index; |
3982d3d28 net/bridge: Add '... |
199 |
p->flags = 0; |
1da177e4c Linux-2.6.12-rc2 |
200 201 |
br_init_port(p); p->state = BR_STATE_DISABLED; |
d32439c0d [BRIDGE]: port ti... |
202 |
br_stp_port_timer_init(p); |
3fe2d7c70 bridge: Add multi... |
203 |
br_multicast_add_port(p); |
1da177e4c Linux-2.6.12-rc2 |
204 205 206 |
return p; } |
4aa678ba4 netns bridge: all... |
207 |
int br_add_bridge(struct net *net, const char *name) |
1da177e4c Linux-2.6.12-rc2 |
208 209 |
{ struct net_device *dev; |
11f3a6bdc bridge: fix a pos... |
210 |
int res; |
1da177e4c Linux-2.6.12-rc2 |
211 |
|
bb900b27a bridge: allow cre... |
212 213 |
dev = alloc_netdev(sizeof(struct net_bridge), name, br_dev_setup); |
9d6f229fc [NET] BRIDGE: Fix... |
214 |
if (!dev) |
1da177e4c Linux-2.6.12-rc2 |
215 |
return -ENOMEM; |
bb900b27a bridge: allow cre... |
216 |
dev_net_set(dev, net); |
e340a90e6 bridge: Consolida... |
217 |
|
11f3a6bdc bridge: fix a pos... |
218 219 220 221 |
res = register_netdev(dev); if (res) free_netdev(dev); return res; |
1da177e4c Linux-2.6.12-rc2 |
222 |
} |
4aa678ba4 netns bridge: all... |
223 |
int br_del_bridge(struct net *net, const char *name) |
1da177e4c Linux-2.6.12-rc2 |
224 225 226 227 228 |
{ struct net_device *dev; int ret = 0; rtnl_lock(); |
4aa678ba4 netns bridge: all... |
229 |
dev = __dev_get_by_name(net, name); |
9d6f229fc [NET] BRIDGE: Fix... |
230 |
if (dev == NULL) |
1da177e4c Linux-2.6.12-rc2 |
231 232 233 234 235 236 237 238 239 240 |
ret = -ENXIO; /* Could not find device */ else if (!(dev->priv_flags & IFF_EBRIDGE)) { /* Attempt to delete non bridge device! */ ret = -EPERM; } else if (dev->flags & IFF_UP) { /* Not shutdown yet. */ ret = -EBUSY; |
9d6f229fc [NET] BRIDGE: Fix... |
241 |
} |
1da177e4c Linux-2.6.12-rc2 |
242 |
|
9d6f229fc [NET] BRIDGE: Fix... |
243 |
else |
1ce5cce89 bridge: fix hang ... |
244 |
br_dev_delete(dev, NULL); |
1da177e4c Linux-2.6.12-rc2 |
245 246 247 248 |
rtnl_unlock(); return ret; } |
46f25dffb [NET]: Change 150... |
249 |
/* MTU of the bridge pseudo-device: ETH_DATA_LEN or the minimum of the ports */ |
1da177e4c Linux-2.6.12-rc2 |
250 251 252 253 254 255 256 257 |
int br_min_mtu(const struct net_bridge *br) { const struct net_bridge_port *p; int mtu = 0; ASSERT_RTNL(); if (list_empty(&br->port_list)) |
46f25dffb [NET]: Change 150... |
258 |
mtu = ETH_DATA_LEN; |
1da177e4c Linux-2.6.12-rc2 |
259 260 261 262 263 264 265 266 |
else { list_for_each_entry(p, &br->port_list, list) { if (!mtu || p->dev->mtu < mtu) mtu = p->dev->mtu; } } return mtu; } |
81d35307d [BRIDGE]: set fea... |
267 268 269 |
/* * Recomputes features using slave's features */ |
c8f44affb net: introduce an... |
270 271 |
netdev_features_t br_features_recompute(struct net_bridge *br, netdev_features_t features) |
81d35307d [BRIDGE]: set fea... |
272 273 |
{ struct net_bridge_port *p; |
c8f44affb net: introduce an... |
274 |
netdev_features_t mask; |
81d35307d [BRIDGE]: set fea... |
275 |
|
b63365a2d net: Fix disjunct... |
276 |
if (list_empty(&br->port_list)) |
c4d27ef95 bridge: convert b... |
277 |
return features; |
b63365a2d net: Fix disjunct... |
278 |
|
c4d27ef95 bridge: convert b... |
279 |
mask = features; |
b63365a2d net: Fix disjunct... |
280 |
features &= ~NETIF_F_ONE_FOR_ALL; |
81d35307d [BRIDGE]: set fea... |
281 282 |
list_for_each_entry(p, &br->port_list, list) { |
b63365a2d net: Fix disjunct... |
283 284 |
features = netdev_increment_features(features, p->dev->features, mask); |
81d35307d [BRIDGE]: set fea... |
285 |
} |
c4d27ef95 bridge: convert b... |
286 |
return features; |
81d35307d [BRIDGE]: set fea... |
287 |
} |
1da177e4c Linux-2.6.12-rc2 |
288 289 290 291 292 |
/* called with RTNL */ int br_add_if(struct net_bridge *br, struct net_device *dev) { struct net_bridge_port *p; int err = 0; |
edf947f10 bridge: notify ap... |
293 |
bool changed_addr; |
1da177e4c Linux-2.6.12-rc2 |
294 |
|
1056bd516 bridge: prevent b... |
295 296 |
/* Don't allow bridging non-ethernet like devices */ if ((dev->flags & IFF_LOOPBACK) || |
77f985983 bridge: fix order... |
297 298 |
dev->type != ARPHRD_ETHER || dev->addr_len != ETH_ALEN || !is_valid_ether_addr(dev->dev_addr)) |
1da177e4c Linux-2.6.12-rc2 |
299 |
return -EINVAL; |
1056bd516 bridge: prevent b... |
300 |
/* No bridging of bridges */ |
008298231 netdev: add more ... |
301 |
if (dev->netdev_ops->ndo_start_xmit == br_dev_xmit) |
1da177e4c Linux-2.6.12-rc2 |
302 |
return -ELOOP; |
1056bd516 bridge: prevent b... |
303 |
/* Device is already being bridged */ |
f350a0a87 bridge: use rx_ha... |
304 |
if (br_port_exists(dev)) |
1da177e4c Linux-2.6.12-rc2 |
305 |
return -EBUSY; |
ad4bb6f88 cfg80211: disallo... |
306 307 308 |
/* No bridging devices that dislike that (e.g. wireless) */ if (dev->priv_flags & IFF_DONT_BRIDGE) return -EOPNOTSUPP; |
bab1deea3 [BRIDGE]: fix err... |
309 310 |
p = new_nbp(br, dev); if (IS_ERR(p)) |
1da177e4c Linux-2.6.12-rc2 |
311 |
return PTR_ERR(p); |
bb8ed6302 bridge: call NETD... |
312 |
call_netdevice_notifiers(NETDEV_JOIN, dev); |
bc3f9076f bridge: Check ret... |
313 314 315 |
err = dev_set_promiscuity(dev, 1); if (err) goto put_back; |
e32cc7366 Kobject: convert ... |
316 317 |
err = kobject_init_and_add(&p->kobj, &brport_ktype, &(dev->dev.kobj), SYSFS_BRIDGE_PORT_ATTR); |
bab1deea3 [BRIDGE]: fix err... |
318 |
if (err) |
bab1deea3 [BRIDGE]: fix err... |
319 |
goto err1; |
1da177e4c Linux-2.6.12-rc2 |
320 |
|
bab1deea3 [BRIDGE]: fix err... |
321 322 323 |
err = br_sysfs_addif(p); if (err) goto err2; |
1da177e4c Linux-2.6.12-rc2 |
324 |
|
91d2c34a4 bridge: Fix netpo... |
325 326 |
if (br_netpoll_info(br) && ((err = br_netpoll_enable(p)))) goto err3; |
afc6151a7 bridge: implement... |
327 |
err = netdev_set_master(dev, br->dev); |
ab95bfe01 net: replace hook... |
328 |
if (err) |
f350a0a87 bridge: use rx_ha... |
329 |
goto err3; |
afc6151a7 bridge: implement... |
330 331 332 |
err = netdev_rx_handler_register(dev, br_handle_frame, p); if (err) goto err4; |
f350a0a87 bridge: use rx_ha... |
333 |
dev->priv_flags |= IFF_BRIDGE_PORT; |
ab95bfe01 net: replace hook... |
334 |
|
0187bdfb0 net: Disable LRO ... |
335 |
dev_disable_lro(dev); |
bab1deea3 [BRIDGE]: fix err... |
336 337 |
list_add_rcu(&p->list, &br->port_list); |
c4d27ef95 bridge: convert b... |
338 |
netdev_update_features(br->dev); |
bab1deea3 [BRIDGE]: fix err... |
339 |
spin_lock_bh(&br->lock); |
edf947f10 bridge: notify ap... |
340 |
changed_addr = br_stp_recalculate_bridge_id(br); |
de79059ec [BRIDGE]: adding ... |
341 342 343 344 |
if ((dev->flags & IFF_UP) && netif_carrier_ok(dev) && (br->dev->flags & IFF_UP)) br_stp_enable_port(p); |
bab1deea3 [BRIDGE]: fix err... |
345 |
spin_unlock_bh(&br->lock); |
b86c45035 bridge: change wh... |
346 |
br_ifinfo_notify(RTM_NEWLINK, p); |
edf947f10 bridge: notify ap... |
347 |
if (changed_addr) |
56139fc5b bridge: notifier ... |
348 |
call_netdevice_notifiers(NETDEV_CHANGEADDR, br->dev); |
edf947f10 bridge: notify ap... |
349 |
|
bab1deea3 [BRIDGE]: fix err... |
350 |
dev_set_mtu(br->dev, br_min_mtu(br)); |
269def7c5 [BRIDGE]: elimina... |
351 |
|
77f985983 bridge: fix order... |
352 353 354 |
if (br_fdb_insert(br, p, dev->dev_addr)) netdev_err(dev, "failed insert local address bridge forwarding table "); |
bab1deea3 [BRIDGE]: fix err... |
355 |
kobject_uevent(&p->kobj, KOBJ_ADD); |
1da177e4c Linux-2.6.12-rc2 |
356 |
|
bab1deea3 [BRIDGE]: fix err... |
357 |
return 0; |
afc6151a7 bridge: implement... |
358 359 360 |
err4: netdev_set_master(dev, NULL); |
91d2c34a4 bridge: Fix netpo... |
361 362 |
err3: sysfs_remove_link(br->ifobj, p->dev->name); |
bab1deea3 [BRIDGE]: fix err... |
363 |
err2: |
c587aea95 net/bridge: use k... |
364 |
kobject_put(&p->kobj); |
30df94f80 bridge: Fix doubl... |
365 |
p = NULL; /* kobject_put frees */ |
77f985983 bridge: fix order... |
366 |
err1: |
bc3f9076f bridge: Check ret... |
367 |
dev_set_promiscuity(dev, -1); |
43af8532e bridge: fix error... |
368 369 |
put_back: dev_put(dev); |
bc3f9076f bridge: Check ret... |
370 |
kfree(p); |
1da177e4c Linux-2.6.12-rc2 |
371 372 373 374 375 376 |
return err; } /* called with RTNL */ int br_del_if(struct net_bridge *br, struct net_device *dev) { |
f350a0a87 bridge: use rx_ha... |
377 |
struct net_bridge_port *p; |
9be6dd651 Bridge: Always se... |
378 |
bool changed_addr; |
f350a0a87 bridge: use rx_ha... |
379 |
|
ec1e5610c bridge: add RCU a... |
380 |
p = br_port_get_rtnl(dev); |
b5ed54e94 bridge: fix RCU r... |
381 |
if (!p || p->br != br) |
1da177e4c Linux-2.6.12-rc2 |
382 |
return -EINVAL; |
1da177e4c Linux-2.6.12-rc2 |
383 384 385 |
del_nbp(p); spin_lock_bh(&br->lock); |
9be6dd651 Bridge: Always se... |
386 |
changed_addr = br_stp_recalculate_bridge_id(br); |
1da177e4c Linux-2.6.12-rc2 |
387 |
spin_unlock_bh(&br->lock); |
9be6dd651 Bridge: Always se... |
388 389 |
if (changed_addr) call_netdevice_notifiers(NETDEV_CHANGEADDR, br->dev); |
c4d27ef95 bridge: convert b... |
390 |
netdev_update_features(br->dev); |
1da177e4c Linux-2.6.12-rc2 |
391 392 |
return 0; } |
2c8c1e729 net: spread __net... |
393 |
void __net_exit br_net_exit(struct net *net) |
1da177e4c Linux-2.6.12-rc2 |
394 |
{ |
ab1b20467 bridge: fix use-a... |
395 |
struct net_device *dev; |
8c56ba053 bridge: Optimize ... |
396 |
LIST_HEAD(list); |
1da177e4c Linux-2.6.12-rc2 |
397 398 |
rtnl_lock(); |
8c56ba053 bridge: Optimize ... |
399 400 |
for_each_netdev(net, dev) if (dev->priv_flags & IFF_EBRIDGE) |
1ce5cce89 bridge: fix hang ... |
401 |
br_dev_delete(dev, &list); |
8c56ba053 bridge: Optimize ... |
402 403 |
unregister_netdevice_many(&list); |
1da177e4c Linux-2.6.12-rc2 |
404 405 406 |
rtnl_unlock(); } |