diff options
Diffstat (limited to 'net/bridge')
-rw-r--r-- | net/bridge/br.c | 2 | ||||
-rw-r--r-- | net/bridge/br_device.c | 142 | ||||
-rw-r--r-- | net/bridge/br_fdb.c | 6 | ||||
-rw-r--r-- | net/bridge/br_forward.c | 11 | ||||
-rw-r--r-- | net/bridge/br_if.c | 33 | ||||
-rw-r--r-- | net/bridge/br_input.c | 24 | ||||
-rw-r--r-- | net/bridge/br_multicast.c | 11 | ||||
-rw-r--r-- | net/bridge/br_netfilter.c | 60 | ||||
-rw-r--r-- | net/bridge/br_netlink.c | 9 | ||||
-rw-r--r-- | net/bridge/br_notify.c | 5 | ||||
-rw-r--r-- | net/bridge/br_private.h | 67 | ||||
-rw-r--r-- | net/bridge/br_stp_bpdu.c | 7 | ||||
-rw-r--r-- | net/bridge/br_sysfs_br.c | 72 | ||||
-rw-r--r-- | net/bridge/netfilter/ebt_redirect.c | 3 | ||||
-rw-r--r-- | net/bridge/netfilter/ebt_ulog.c | 8 | ||||
-rw-r--r-- | net/bridge/netfilter/ebtables.c | 11 |
16 files changed, 331 insertions, 140 deletions
diff --git a/net/bridge/br.c b/net/bridge/br.c index 76357b547752..c8436fa31344 100644 --- a/net/bridge/br.c +++ b/net/bridge/br.c | |||
@@ -63,7 +63,6 @@ static int __init br_init(void) | |||
63 | goto err_out4; | 63 | goto err_out4; |
64 | 64 | ||
65 | brioctl_set(br_ioctl_deviceless_stub); | 65 | brioctl_set(br_ioctl_deviceless_stub); |
66 | br_handle_frame_hook = br_handle_frame; | ||
67 | 66 | ||
68 | #if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE) | 67 | #if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE) |
69 | br_fdb_test_addr_hook = br_fdb_test_addr; | 68 | br_fdb_test_addr_hook = br_fdb_test_addr; |
@@ -100,7 +99,6 @@ static void __exit br_deinit(void) | |||
100 | br_fdb_test_addr_hook = NULL; | 99 | br_fdb_test_addr_hook = NULL; |
101 | #endif | 100 | #endif |
102 | 101 | ||
103 | br_handle_frame_hook = NULL; | ||
104 | br_fdb_fini(); | 102 | br_fdb_fini(); |
105 | } | 103 | } |
106 | 104 | ||
diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c index 753fc4221f3c..cf09fe591fc2 100644 --- a/net/bridge/br_device.c +++ b/net/bridge/br_device.c | |||
@@ -22,7 +22,7 @@ | |||
22 | #include <asm/uaccess.h> | 22 | #include <asm/uaccess.h> |
23 | #include "br_private.h" | 23 | #include "br_private.h" |
24 | 24 | ||
25 | /* net device transmit always called with no BH (preempt_disabled) */ | 25 | /* net device transmit always called with BH disabled */ |
26 | netdev_tx_t br_dev_xmit(struct sk_buff *skb, struct net_device *dev) | 26 | netdev_tx_t br_dev_xmit(struct sk_buff *skb, struct net_device *dev) |
27 | { | 27 | { |
28 | struct net_bridge *br = netdev_priv(dev); | 28 | struct net_bridge *br = netdev_priv(dev); |
@@ -38,17 +38,26 @@ netdev_tx_t br_dev_xmit(struct sk_buff *skb, struct net_device *dev) | |||
38 | } | 38 | } |
39 | #endif | 39 | #endif |
40 | 40 | ||
41 | u64_stats_update_begin(&brstats->syncp); | ||
41 | brstats->tx_packets++; | 42 | brstats->tx_packets++; |
42 | brstats->tx_bytes += skb->len; | 43 | brstats->tx_bytes += skb->len; |
44 | u64_stats_update_end(&brstats->syncp); | ||
43 | 45 | ||
44 | BR_INPUT_SKB_CB(skb)->brdev = dev; | 46 | BR_INPUT_SKB_CB(skb)->brdev = dev; |
45 | 47 | ||
46 | skb_reset_mac_header(skb); | 48 | skb_reset_mac_header(skb); |
47 | skb_pull(skb, ETH_HLEN); | 49 | skb_pull(skb, ETH_HLEN); |
48 | 50 | ||
51 | rcu_read_lock(); | ||
49 | if (is_multicast_ether_addr(dest)) { | 52 | if (is_multicast_ether_addr(dest)) { |
50 | if (br_multicast_rcv(br, NULL, skb)) | 53 | if (unlikely(netpoll_tx_running(dev))) { |
54 | br_flood_deliver(br, skb); | ||
55 | goto out; | ||
56 | } | ||
57 | if (br_multicast_rcv(br, NULL, skb)) { | ||
58 | kfree_skb(skb); | ||
51 | goto out; | 59 | goto out; |
60 | } | ||
52 | 61 | ||
53 | mdst = br_mdb_get(br, skb); | 62 | mdst = br_mdb_get(br, skb); |
54 | if (mdst || BR_INPUT_SKB_CB_MROUTERS_ONLY(skb)) | 63 | if (mdst || BR_INPUT_SKB_CB_MROUTERS_ONLY(skb)) |
@@ -61,6 +70,7 @@ netdev_tx_t br_dev_xmit(struct sk_buff *skb, struct net_device *dev) | |||
61 | br_flood_deliver(br, skb); | 70 | br_flood_deliver(br, skb); |
62 | 71 | ||
63 | out: | 72 | out: |
73 | rcu_read_unlock(); | ||
64 | return NETDEV_TX_OK; | 74 | return NETDEV_TX_OK; |
65 | } | 75 | } |
66 | 76 | ||
@@ -92,21 +102,25 @@ static int br_dev_stop(struct net_device *dev) | |||
92 | return 0; | 102 | return 0; |
93 | } | 103 | } |
94 | 104 | ||
95 | static struct net_device_stats *br_get_stats(struct net_device *dev) | 105 | static struct rtnl_link_stats64 *br_get_stats64(struct net_device *dev, |
106 | struct rtnl_link_stats64 *stats) | ||
96 | { | 107 | { |
97 | struct net_bridge *br = netdev_priv(dev); | 108 | struct net_bridge *br = netdev_priv(dev); |
98 | struct net_device_stats *stats = &dev->stats; | 109 | struct br_cpu_netstats tmp, sum = { 0 }; |
99 | struct br_cpu_netstats sum = { 0 }; | ||
100 | unsigned int cpu; | 110 | unsigned int cpu; |
101 | 111 | ||
102 | for_each_possible_cpu(cpu) { | 112 | for_each_possible_cpu(cpu) { |
113 | unsigned int start; | ||
103 | const struct br_cpu_netstats *bstats | 114 | const struct br_cpu_netstats *bstats |
104 | = per_cpu_ptr(br->stats, cpu); | 115 | = per_cpu_ptr(br->stats, cpu); |
105 | 116 | do { | |
106 | sum.tx_bytes += bstats->tx_bytes; | 117 | start = u64_stats_fetch_begin(&bstats->syncp); |
107 | sum.tx_packets += bstats->tx_packets; | 118 | memcpy(&tmp, bstats, sizeof(tmp)); |
108 | sum.rx_bytes += bstats->rx_bytes; | 119 | } while (u64_stats_fetch_retry(&bstats->syncp, start)); |
109 | sum.rx_packets += bstats->rx_packets; | 120 | sum.tx_bytes += tmp.tx_bytes; |
121 | sum.tx_packets += tmp.tx_packets; | ||
122 | sum.rx_bytes += tmp.rx_bytes; | ||
123 | sum.rx_packets += tmp.rx_packets; | ||
110 | } | 124 | } |
111 | 125 | ||
112 | stats->tx_bytes = sum.tx_bytes; | 126 | stats->tx_bytes = sum.tx_bytes; |
@@ -127,7 +141,7 @@ static int br_change_mtu(struct net_device *dev, int new_mtu) | |||
127 | 141 | ||
128 | #ifdef CONFIG_BRIDGE_NETFILTER | 142 | #ifdef CONFIG_BRIDGE_NETFILTER |
129 | /* remember the MTU in the rtable for PMTU */ | 143 | /* remember the MTU in the rtable for PMTU */ |
130 | br->fake_rtable.u.dst.metrics[RTAX_MTU - 1] = new_mtu; | 144 | br->fake_rtable.dst.metrics[RTAX_MTU - 1] = new_mtu; |
131 | #endif | 145 | #endif |
132 | 146 | ||
133 | return 0; | 147 | return 0; |
@@ -199,65 +213,81 @@ static int br_set_tx_csum(struct net_device *dev, u32 data) | |||
199 | } | 213 | } |
200 | 214 | ||
201 | #ifdef CONFIG_NET_POLL_CONTROLLER | 215 | #ifdef CONFIG_NET_POLL_CONTROLLER |
202 | static bool br_devices_support_netpoll(struct net_bridge *br) | 216 | static void br_poll_controller(struct net_device *br_dev) |
203 | { | 217 | { |
204 | struct net_bridge_port *p; | ||
205 | bool ret = true; | ||
206 | int count = 0; | ||
207 | unsigned long flags; | ||
208 | |||
209 | spin_lock_irqsave(&br->lock, flags); | ||
210 | list_for_each_entry(p, &br->port_list, list) { | ||
211 | count++; | ||
212 | if ((p->dev->priv_flags & IFF_DISABLE_NETPOLL) || | ||
213 | !p->dev->netdev_ops->ndo_poll_controller) | ||
214 | ret = false; | ||
215 | } | ||
216 | spin_unlock_irqrestore(&br->lock, flags); | ||
217 | return count != 0 && ret; | ||
218 | } | 218 | } |
219 | 219 | ||
220 | void br_netpoll_cleanup(struct net_device *dev) | 220 | static void br_netpoll_cleanup(struct net_device *dev) |
221 | { | 221 | { |
222 | struct net_bridge *br = netdev_priv(dev); | 222 | struct net_bridge *br = netdev_priv(dev); |
223 | struct net_bridge_port *p, *n; | 223 | struct net_bridge_port *p, *n; |
224 | const struct net_device_ops *ops; | ||
225 | 224 | ||
226 | br->dev->npinfo = NULL; | ||
227 | list_for_each_entry_safe(p, n, &br->port_list, list) { | 225 | list_for_each_entry_safe(p, n, &br->port_list, list) { |
228 | if (p->dev) { | 226 | br_netpoll_disable(p); |
229 | ops = p->dev->netdev_ops; | ||
230 | if (ops->ndo_netpoll_cleanup) | ||
231 | ops->ndo_netpoll_cleanup(p->dev); | ||
232 | else | ||
233 | p->dev->npinfo = NULL; | ||
234 | } | ||
235 | } | 227 | } |
236 | } | 228 | } |
237 | 229 | ||
238 | void br_netpoll_disable(struct net_bridge *br, | 230 | static int br_netpoll_setup(struct net_device *dev, struct netpoll_info *ni) |
239 | struct net_device *dev) | ||
240 | { | 231 | { |
241 | if (br_devices_support_netpoll(br)) | 232 | struct net_bridge *br = netdev_priv(dev); |
242 | br->dev->priv_flags &= ~IFF_DISABLE_NETPOLL; | 233 | struct net_bridge_port *p, *n; |
243 | if (dev->netdev_ops->ndo_netpoll_cleanup) | 234 | int err = 0; |
244 | dev->netdev_ops->ndo_netpoll_cleanup(dev); | 235 | |
245 | else | 236 | list_for_each_entry_safe(p, n, &br->port_list, list) { |
246 | dev->npinfo = NULL; | 237 | if (!p->dev) |
238 | continue; | ||
239 | |||
240 | err = br_netpoll_enable(p); | ||
241 | if (err) | ||
242 | goto fail; | ||
243 | } | ||
244 | |||
245 | out: | ||
246 | return err; | ||
247 | |||
248 | fail: | ||
249 | br_netpoll_cleanup(dev); | ||
250 | goto out; | ||
247 | } | 251 | } |
248 | 252 | ||
249 | void br_netpoll_enable(struct net_bridge *br, | 253 | int br_netpoll_enable(struct net_bridge_port *p) |
250 | struct net_device *dev) | ||
251 | { | 254 | { |
252 | if (br_devices_support_netpoll(br)) { | 255 | struct netpoll *np; |
253 | br->dev->priv_flags &= ~IFF_DISABLE_NETPOLL; | 256 | int err = 0; |
254 | if (br->dev->npinfo) | 257 | |
255 | dev->npinfo = br->dev->npinfo; | 258 | np = kzalloc(sizeof(*p->np), GFP_KERNEL); |
256 | } else if (!(br->dev->priv_flags & IFF_DISABLE_NETPOLL)) { | 259 | err = -ENOMEM; |
257 | br->dev->priv_flags |= IFF_DISABLE_NETPOLL; | 260 | if (!np) |
258 | br_info(br,"new device %s does not support netpoll (disabling)", | 261 | goto out; |
259 | dev->name); | 262 | |
263 | np->dev = p->dev; | ||
264 | |||
265 | err = __netpoll_setup(np); | ||
266 | if (err) { | ||
267 | kfree(np); | ||
268 | goto out; | ||
260 | } | 269 | } |
270 | |||
271 | p->np = np; | ||
272 | |||
273 | out: | ||
274 | return err; | ||
275 | } | ||
276 | |||
277 | void br_netpoll_disable(struct net_bridge_port *p) | ||
278 | { | ||
279 | struct netpoll *np = p->np; | ||
280 | |||
281 | if (!np) | ||
282 | return; | ||
283 | |||
284 | p->np = NULL; | ||
285 | |||
286 | /* Wait for transmitting packets to finish before freeing. */ | ||
287 | synchronize_rcu_bh(); | ||
288 | |||
289 | __netpoll_cleanup(np); | ||
290 | kfree(np); | ||
261 | } | 291 | } |
262 | 292 | ||
263 | #endif | 293 | #endif |
@@ -280,13 +310,15 @@ static const struct net_device_ops br_netdev_ops = { | |||
280 | .ndo_open = br_dev_open, | 310 | .ndo_open = br_dev_open, |
281 | .ndo_stop = br_dev_stop, | 311 | .ndo_stop = br_dev_stop, |
282 | .ndo_start_xmit = br_dev_xmit, | 312 | .ndo_start_xmit = br_dev_xmit, |
283 | .ndo_get_stats = br_get_stats, | 313 | .ndo_get_stats64 = br_get_stats64, |
284 | .ndo_set_mac_address = br_set_mac_address, | 314 | .ndo_set_mac_address = br_set_mac_address, |
285 | .ndo_set_multicast_list = br_dev_set_multicast_list, | 315 | .ndo_set_multicast_list = br_dev_set_multicast_list, |
286 | .ndo_change_mtu = br_change_mtu, | 316 | .ndo_change_mtu = br_change_mtu, |
287 | .ndo_do_ioctl = br_dev_ioctl, | 317 | .ndo_do_ioctl = br_dev_ioctl, |
288 | #ifdef CONFIG_NET_POLL_CONTROLLER | 318 | #ifdef CONFIG_NET_POLL_CONTROLLER |
319 | .ndo_netpoll_setup = br_netpoll_setup, | ||
289 | .ndo_netpoll_cleanup = br_netpoll_cleanup, | 320 | .ndo_netpoll_cleanup = br_netpoll_cleanup, |
321 | .ndo_poll_controller = br_poll_controller, | ||
290 | #endif | 322 | #endif |
291 | }; | 323 | }; |
292 | 324 | ||
diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c index b01dde35a69e..90512ccfd3e9 100644 --- a/net/bridge/br_fdb.c +++ b/net/bridge/br_fdb.c | |||
@@ -214,7 +214,7 @@ void br_fdb_delete_by_port(struct net_bridge *br, | |||
214 | spin_unlock_bh(&br->hash_lock); | 214 | spin_unlock_bh(&br->hash_lock); |
215 | } | 215 | } |
216 | 216 | ||
217 | /* No locking or refcounting, assumes caller has no preempt (rcu_read_lock) */ | 217 | /* No locking or refcounting, assumes caller has rcu_read_lock */ |
218 | struct net_bridge_fdb_entry *__br_fdb_get(struct net_bridge *br, | 218 | struct net_bridge_fdb_entry *__br_fdb_get(struct net_bridge *br, |
219 | const unsigned char *addr) | 219 | const unsigned char *addr) |
220 | { | 220 | { |
@@ -240,11 +240,11 @@ int br_fdb_test_addr(struct net_device *dev, unsigned char *addr) | |||
240 | struct net_bridge_fdb_entry *fdb; | 240 | struct net_bridge_fdb_entry *fdb; |
241 | int ret; | 241 | int ret; |
242 | 242 | ||
243 | if (!dev->br_port) | 243 | if (!br_port_exists(dev)) |
244 | return 0; | 244 | return 0; |
245 | 245 | ||
246 | rcu_read_lock(); | 246 | rcu_read_lock(); |
247 | fdb = __br_fdb_get(dev->br_port->br, addr); | 247 | fdb = __br_fdb_get(br_port_get_rcu(dev)->br, addr); |
248 | ret = fdb && fdb->dst->dev != dev && | 248 | ret = fdb && fdb->dst->dev != dev && |
249 | fdb->dst->state == BR_STATE_FORWARDING; | 249 | fdb->dst->state == BR_STATE_FORWARDING; |
250 | rcu_read_unlock(); | 250 | rcu_read_unlock(); |
diff --git a/net/bridge/br_forward.c b/net/bridge/br_forward.c index 595da45f9088..cbfe87f0f34a 100644 --- a/net/bridge/br_forward.c +++ b/net/bridge/br_forward.c | |||
@@ -67,6 +67,17 @@ int br_forward_finish(struct sk_buff *skb) | |||
67 | static void __br_deliver(const struct net_bridge_port *to, struct sk_buff *skb) | 67 | static void __br_deliver(const struct net_bridge_port *to, struct sk_buff *skb) |
68 | { | 68 | { |
69 | skb->dev = to->dev; | 69 | skb->dev = to->dev; |
70 | |||
71 | if (unlikely(netpoll_tx_running(to->dev))) { | ||
72 | if (packet_length(skb) > skb->dev->mtu && !skb_is_gso(skb)) | ||
73 | kfree_skb(skb); | ||
74 | else { | ||
75 | skb_push(skb, ETH_HLEN); | ||
76 | br_netpoll_send_skb(to, skb); | ||
77 | } | ||
78 | return; | ||
79 | } | ||
80 | |||
70 | NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_OUT, skb, NULL, skb->dev, | 81 | NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_OUT, skb, NULL, skb->dev, |
71 | br_forward_finish); | 82 | br_forward_finish); |
72 | } | 83 | } |
diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c index 18b245e2c00e..c03d2c3ff03e 100644 --- a/net/bridge/br_if.c +++ b/net/bridge/br_if.c | |||
@@ -147,14 +147,17 @@ static void del_nbp(struct net_bridge_port *p) | |||
147 | 147 | ||
148 | list_del_rcu(&p->list); | 148 | list_del_rcu(&p->list); |
149 | 149 | ||
150 | rcu_assign_pointer(dev->br_port, NULL); | 150 | dev->priv_flags &= ~IFF_BRIDGE_PORT; |
151 | |||
152 | netdev_rx_handler_unregister(dev); | ||
151 | 153 | ||
152 | br_multicast_del_port(p); | 154 | br_multicast_del_port(p); |
153 | 155 | ||
154 | kobject_uevent(&p->kobj, KOBJ_REMOVE); | 156 | kobject_uevent(&p->kobj, KOBJ_REMOVE); |
155 | kobject_del(&p->kobj); | 157 | kobject_del(&p->kobj); |
156 | 158 | ||
157 | br_netpoll_disable(br, dev); | 159 | br_netpoll_disable(p); |
160 | |||
158 | call_rcu(&p->rcu, destroy_nbp_rcu); | 161 | call_rcu(&p->rcu, destroy_nbp_rcu); |
159 | } | 162 | } |
160 | 163 | ||
@@ -167,8 +170,6 @@ static void del_br(struct net_bridge *br, struct list_head *head) | |||
167 | del_nbp(p); | 170 | del_nbp(p); |
168 | } | 171 | } |
169 | 172 | ||
170 | br_netpoll_cleanup(br->dev); | ||
171 | |||
172 | del_timer_sync(&br->gc_timer); | 173 | del_timer_sync(&br->gc_timer); |
173 | 174 | ||
174 | br_sysfs_delbr(br->dev); | 175 | br_sysfs_delbr(br->dev); |
@@ -400,7 +401,7 @@ int br_add_if(struct net_bridge *br, struct net_device *dev) | |||
400 | return -ELOOP; | 401 | return -ELOOP; |
401 | 402 | ||
402 | /* Device is already being bridged */ | 403 | /* Device is already being bridged */ |
403 | if (dev->br_port != NULL) | 404 | if (br_port_exists(dev)) |
404 | return -EBUSY; | 405 | return -EBUSY; |
405 | 406 | ||
406 | /* No bridging devices that dislike that (e.g. wireless) */ | 407 | /* No bridging devices that dislike that (e.g. wireless) */ |
@@ -428,7 +429,15 @@ int br_add_if(struct net_bridge *br, struct net_device *dev) | |||
428 | if (err) | 429 | if (err) |
429 | goto err2; | 430 | goto err2; |
430 | 431 | ||
431 | rcu_assign_pointer(dev->br_port, p); | 432 | if (br_netpoll_info(br) && ((err = br_netpoll_enable(p)))) |
433 | goto err3; | ||
434 | |||
435 | err = netdev_rx_handler_register(dev, br_handle_frame, p); | ||
436 | if (err) | ||
437 | goto err3; | ||
438 | |||
439 | dev->priv_flags |= IFF_BRIDGE_PORT; | ||
440 | |||
432 | dev_disable_lro(dev); | 441 | dev_disable_lro(dev); |
433 | 442 | ||
434 | list_add_rcu(&p->list, &br->port_list); | 443 | list_add_rcu(&p->list, &br->port_list); |
@@ -448,9 +457,9 @@ int br_add_if(struct net_bridge *br, struct net_device *dev) | |||
448 | 457 | ||
449 | kobject_uevent(&p->kobj, KOBJ_ADD); | 458 | kobject_uevent(&p->kobj, KOBJ_ADD); |
450 | 459 | ||
451 | br_netpoll_enable(br, dev); | ||
452 | |||
453 | return 0; | 460 | return 0; |
461 | err3: | ||
462 | sysfs_remove_link(br->ifobj, p->dev->name); | ||
454 | err2: | 463 | err2: |
455 | br_fdb_delete_by_port(br, p, 1); | 464 | br_fdb_delete_by_port(br, p, 1); |
456 | err1: | 465 | err1: |
@@ -467,9 +476,13 @@ put_back: | |||
467 | /* called with RTNL */ | 476 | /* called with RTNL */ |
468 | int br_del_if(struct net_bridge *br, struct net_device *dev) | 477 | int br_del_if(struct net_bridge *br, struct net_device *dev) |
469 | { | 478 | { |
470 | struct net_bridge_port *p = dev->br_port; | 479 | struct net_bridge_port *p; |
480 | |||
481 | if (!br_port_exists(dev)) | ||
482 | return -EINVAL; | ||
471 | 483 | ||
472 | if (!p || p->br != br) | 484 | p = br_port_get(dev); |
485 | if (p->br != br) | ||
473 | return -EINVAL; | 486 | return -EINVAL; |
474 | 487 | ||
475 | del_nbp(p); | 488 | del_nbp(p); |
diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c index d36e700f7a26..826cd5221536 100644 --- a/net/bridge/br_input.c +++ b/net/bridge/br_input.c | |||
@@ -27,8 +27,10 @@ static int br_pass_frame_up(struct sk_buff *skb) | |||
27 | struct net_bridge *br = netdev_priv(brdev); | 27 | struct net_bridge *br = netdev_priv(brdev); |
28 | struct br_cpu_netstats *brstats = this_cpu_ptr(br->stats); | 28 | struct br_cpu_netstats *brstats = this_cpu_ptr(br->stats); |
29 | 29 | ||
30 | u64_stats_update_begin(&brstats->syncp); | ||
30 | brstats->rx_packets++; | 31 | brstats->rx_packets++; |
31 | brstats->rx_bytes += skb->len; | 32 | brstats->rx_bytes += skb->len; |
33 | u64_stats_update_end(&brstats->syncp); | ||
32 | 34 | ||
33 | indev = skb->dev; | 35 | indev = skb->dev; |
34 | skb->dev = brdev; | 36 | skb->dev = brdev; |
@@ -37,11 +39,11 @@ static int br_pass_frame_up(struct sk_buff *skb) | |||
37 | netif_receive_skb); | 39 | netif_receive_skb); |
38 | } | 40 | } |
39 | 41 | ||
40 | /* note: already called with rcu_read_lock (preempt_disabled) */ | 42 | /* note: already called with rcu_read_lock */ |
41 | int br_handle_frame_finish(struct sk_buff *skb) | 43 | int br_handle_frame_finish(struct sk_buff *skb) |
42 | { | 44 | { |
43 | const unsigned char *dest = eth_hdr(skb)->h_dest; | 45 | const unsigned char *dest = eth_hdr(skb)->h_dest; |
44 | struct net_bridge_port *p = rcu_dereference(skb->dev->br_port); | 46 | struct net_bridge_port *p = br_port_get_rcu(skb->dev); |
45 | struct net_bridge *br; | 47 | struct net_bridge *br; |
46 | struct net_bridge_fdb_entry *dst; | 48 | struct net_bridge_fdb_entry *dst; |
47 | struct net_bridge_mdb_entry *mdst; | 49 | struct net_bridge_mdb_entry *mdst; |
@@ -108,13 +110,12 @@ drop: | |||
108 | goto out; | 110 | goto out; |
109 | } | 111 | } |
110 | 112 | ||
111 | /* note: already called with rcu_read_lock (preempt_disabled) */ | 113 | /* note: already called with rcu_read_lock */ |
112 | static int br_handle_local_finish(struct sk_buff *skb) | 114 | static int br_handle_local_finish(struct sk_buff *skb) |
113 | { | 115 | { |
114 | struct net_bridge_port *p = rcu_dereference(skb->dev->br_port); | 116 | struct net_bridge_port *p = br_port_get_rcu(skb->dev); |
115 | 117 | ||
116 | if (p) | 118 | br_fdb_update(p->br, p, eth_hdr(skb)->h_source); |
117 | br_fdb_update(p->br, p, eth_hdr(skb)->h_source); | ||
118 | return 0; /* process further */ | 119 | return 0; /* process further */ |
119 | } | 120 | } |
120 | 121 | ||
@@ -131,15 +132,18 @@ static inline int is_link_local(const unsigned char *dest) | |||
131 | } | 132 | } |
132 | 133 | ||
133 | /* | 134 | /* |
134 | * Called via br_handle_frame_hook. | ||
135 | * Return NULL if skb is handled | 135 | * Return NULL if skb is handled |
136 | * note: already called with rcu_read_lock (preempt_disabled) | 136 | * note: already called with rcu_read_lock |
137 | */ | 137 | */ |
138 | struct sk_buff *br_handle_frame(struct net_bridge_port *p, struct sk_buff *skb) | 138 | struct sk_buff *br_handle_frame(struct sk_buff *skb) |
139 | { | 139 | { |
140 | struct net_bridge_port *p; | ||
140 | const unsigned char *dest = eth_hdr(skb)->h_dest; | 141 | const unsigned char *dest = eth_hdr(skb)->h_dest; |
141 | int (*rhook)(struct sk_buff *skb); | 142 | int (*rhook)(struct sk_buff *skb); |
142 | 143 | ||
144 | if (skb->pkt_type == PACKET_LOOPBACK) | ||
145 | return skb; | ||
146 | |||
143 | if (!is_valid_ether_addr(eth_hdr(skb)->h_source)) | 147 | if (!is_valid_ether_addr(eth_hdr(skb)->h_source)) |
144 | goto drop; | 148 | goto drop; |
145 | 149 | ||
@@ -147,6 +151,8 @@ struct sk_buff *br_handle_frame(struct net_bridge_port *p, struct sk_buff *skb) | |||
147 | if (!skb) | 151 | if (!skb) |
148 | return NULL; | 152 | return NULL; |
149 | 153 | ||
154 | p = br_port_get_rcu(skb->dev); | ||
155 | |||
150 | if (unlikely(is_link_local(dest))) { | 156 | if (unlikely(is_link_local(dest))) { |
151 | /* Pause frames shouldn't be passed up by driver anyway */ | 157 | /* Pause frames shouldn't be passed up by driver anyway */ |
152 | if (skb->protocol == htons(ETH_P_PAUSE)) | 158 | if (skb->protocol == htons(ETH_P_PAUSE)) |
diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c index 27ae946363f1..eb5b256ffc88 100644 --- a/net/bridge/br_multicast.c +++ b/net/bridge/br_multicast.c | |||
@@ -1435,7 +1435,7 @@ static int br_multicast_ipv6_rcv(struct net_bridge *br, | |||
1435 | struct icmp6hdr *icmp6h; | 1435 | struct icmp6hdr *icmp6h; |
1436 | u8 nexthdr; | 1436 | u8 nexthdr; |
1437 | unsigned len; | 1437 | unsigned len; |
1438 | unsigned offset; | 1438 | int offset; |
1439 | int err; | 1439 | int err; |
1440 | 1440 | ||
1441 | if (!pskb_may_pull(skb, sizeof(*ip6h))) | 1441 | if (!pskb_may_pull(skb, sizeof(*ip6h))) |
@@ -1728,13 +1728,9 @@ unlock: | |||
1728 | int br_multicast_toggle(struct net_bridge *br, unsigned long val) | 1728 | int br_multicast_toggle(struct net_bridge *br, unsigned long val) |
1729 | { | 1729 | { |
1730 | struct net_bridge_port *port; | 1730 | struct net_bridge_port *port; |
1731 | int err = -ENOENT; | 1731 | int err = 0; |
1732 | 1732 | ||
1733 | spin_lock(&br->multicast_lock); | 1733 | spin_lock(&br->multicast_lock); |
1734 | if (!netif_running(br->dev)) | ||
1735 | goto unlock; | ||
1736 | |||
1737 | err = 0; | ||
1738 | if (br->multicast_disabled == !val) | 1734 | if (br->multicast_disabled == !val) |
1739 | goto unlock; | 1735 | goto unlock; |
1740 | 1736 | ||
@@ -1742,6 +1738,9 @@ int br_multicast_toggle(struct net_bridge *br, unsigned long val) | |||
1742 | if (br->multicast_disabled) | 1738 | if (br->multicast_disabled) |
1743 | goto unlock; | 1739 | goto unlock; |
1744 | 1740 | ||
1741 | if (!netif_running(br->dev)) | ||
1742 | goto unlock; | ||
1743 | |||
1745 | if (br->mdb) { | 1744 | if (br->mdb) { |
1746 | if (br->mdb->old) { | 1745 | if (br->mdb->old) { |
1747 | err = -EEXIST; | 1746 | err = -EEXIST; |
diff --git a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c index 8fb75f89c4aa..2c911c0759c2 100644 --- a/net/bridge/br_netfilter.c +++ b/net/bridge/br_netfilter.c | |||
@@ -55,6 +55,9 @@ static int brnf_call_arptables __read_mostly = 1; | |||
55 | static int brnf_filter_vlan_tagged __read_mostly = 0; | 55 | static int brnf_filter_vlan_tagged __read_mostly = 0; |
56 | static int brnf_filter_pppoe_tagged __read_mostly = 0; | 56 | static int brnf_filter_pppoe_tagged __read_mostly = 0; |
57 | #else | 57 | #else |
58 | #define brnf_call_iptables 1 | ||
59 | #define brnf_call_ip6tables 1 | ||
60 | #define brnf_call_arptables 1 | ||
58 | #define brnf_filter_vlan_tagged 0 | 61 | #define brnf_filter_vlan_tagged 0 |
59 | #define brnf_filter_pppoe_tagged 0 | 62 | #define brnf_filter_pppoe_tagged 0 |
60 | #endif | 63 | #endif |
@@ -117,26 +120,27 @@ void br_netfilter_rtable_init(struct net_bridge *br) | |||
117 | { | 120 | { |
118 | struct rtable *rt = &br->fake_rtable; | 121 | struct rtable *rt = &br->fake_rtable; |
119 | 122 | ||
120 | atomic_set(&rt->u.dst.__refcnt, 1); | 123 | atomic_set(&rt->dst.__refcnt, 1); |
121 | rt->u.dst.dev = br->dev; | 124 | rt->dst.dev = br->dev; |
122 | rt->u.dst.path = &rt->u.dst; | 125 | rt->dst.path = &rt->dst; |
123 | rt->u.dst.metrics[RTAX_MTU - 1] = 1500; | 126 | rt->dst.metrics[RTAX_MTU - 1] = 1500; |
124 | rt->u.dst.flags = DST_NOXFRM; | 127 | rt->dst.flags = DST_NOXFRM; |
125 | rt->u.dst.ops = &fake_dst_ops; | 128 | rt->dst.ops = &fake_dst_ops; |
126 | } | 129 | } |
127 | 130 | ||
128 | static inline struct rtable *bridge_parent_rtable(const struct net_device *dev) | 131 | static inline struct rtable *bridge_parent_rtable(const struct net_device *dev) |
129 | { | 132 | { |
130 | struct net_bridge_port *port = rcu_dereference(dev->br_port); | 133 | if (!br_port_exists(dev)) |
131 | 134 | return NULL; | |
132 | return port ? &port->br->fake_rtable : NULL; | 135 | return &br_port_get_rcu(dev)->br->fake_rtable; |
133 | } | 136 | } |
134 | 137 | ||
135 | static inline struct net_device *bridge_parent(const struct net_device *dev) | 138 | static inline struct net_device *bridge_parent(const struct net_device *dev) |
136 | { | 139 | { |
137 | struct net_bridge_port *port = rcu_dereference(dev->br_port); | 140 | if (!br_port_exists(dev)) |
141 | return NULL; | ||
138 | 142 | ||
139 | return port ? port->br->dev : NULL; | 143 | return br_port_get_rcu(dev)->br->dev; |
140 | } | 144 | } |
141 | 145 | ||
142 | static inline struct nf_bridge_info *nf_bridge_alloc(struct sk_buff *skb) | 146 | static inline struct nf_bridge_info *nf_bridge_alloc(struct sk_buff *skb) |
@@ -244,8 +248,7 @@ static int br_nf_pre_routing_finish_ipv6(struct sk_buff *skb) | |||
244 | kfree_skb(skb); | 248 | kfree_skb(skb); |
245 | return 0; | 249 | return 0; |
246 | } | 250 | } |
247 | dst_hold(&rt->u.dst); | 251 | skb_dst_set_noref(skb, &rt->dst); |
248 | skb_dst_set(skb, &rt->u.dst); | ||
249 | 252 | ||
250 | skb->dev = nf_bridge->physindev; | 253 | skb->dev = nf_bridge->physindev; |
251 | nf_bridge_update_protocol(skb); | 254 | nf_bridge_update_protocol(skb); |
@@ -396,8 +399,7 @@ bridged_dnat: | |||
396 | kfree_skb(skb); | 399 | kfree_skb(skb); |
397 | return 0; | 400 | return 0; |
398 | } | 401 | } |
399 | dst_hold(&rt->u.dst); | 402 | skb_dst_set_noref(skb, &rt->dst); |
400 | skb_dst_set(skb, &rt->u.dst); | ||
401 | } | 403 | } |
402 | 404 | ||
403 | skb->dev = nf_bridge->physindev; | 405 | skb->dev = nf_bridge->physindev; |
@@ -545,25 +547,30 @@ static unsigned int br_nf_pre_routing(unsigned int hook, struct sk_buff *skb, | |||
545 | const struct net_device *out, | 547 | const struct net_device *out, |
546 | int (*okfn)(struct sk_buff *)) | 548 | int (*okfn)(struct sk_buff *)) |
547 | { | 549 | { |
550 | struct net_bridge_port *p; | ||
551 | struct net_bridge *br; | ||
548 | struct iphdr *iph; | 552 | struct iphdr *iph; |
549 | __u32 len = nf_bridge_encap_header_len(skb); | 553 | __u32 len = nf_bridge_encap_header_len(skb); |
550 | 554 | ||
551 | if (unlikely(!pskb_may_pull(skb, len))) | 555 | if (unlikely(!pskb_may_pull(skb, len))) |
552 | goto out; | 556 | goto out; |
553 | 557 | ||
558 | p = br_port_get_rcu(in); | ||
559 | if (p == NULL) | ||
560 | goto out; | ||
561 | br = p->br; | ||
562 | |||
554 | if (skb->protocol == htons(ETH_P_IPV6) || IS_VLAN_IPV6(skb) || | 563 | if (skb->protocol == htons(ETH_P_IPV6) || IS_VLAN_IPV6(skb) || |
555 | IS_PPPOE_IPV6(skb)) { | 564 | IS_PPPOE_IPV6(skb)) { |
556 | #ifdef CONFIG_SYSCTL | 565 | if (!brnf_call_ip6tables && !br->nf_call_ip6tables) |
557 | if (!brnf_call_ip6tables) | ||
558 | return NF_ACCEPT; | 566 | return NF_ACCEPT; |
559 | #endif | 567 | |
560 | nf_bridge_pull_encap_header_rcsum(skb); | 568 | nf_bridge_pull_encap_header_rcsum(skb); |
561 | return br_nf_pre_routing_ipv6(hook, skb, in, out, okfn); | 569 | return br_nf_pre_routing_ipv6(hook, skb, in, out, okfn); |
562 | } | 570 | } |
563 | #ifdef CONFIG_SYSCTL | 571 | |
564 | if (!brnf_call_iptables) | 572 | if (!brnf_call_iptables && !br->nf_call_iptables) |
565 | return NF_ACCEPT; | 573 | return NF_ACCEPT; |
566 | #endif | ||
567 | 574 | ||
568 | if (skb->protocol != htons(ETH_P_IP) && !IS_VLAN_IP(skb) && | 575 | if (skb->protocol != htons(ETH_P_IP) && !IS_VLAN_IP(skb) && |
569 | !IS_PPPOE_IP(skb)) | 576 | !IS_PPPOE_IP(skb)) |
@@ -719,12 +726,17 @@ static unsigned int br_nf_forward_arp(unsigned int hook, struct sk_buff *skb, | |||
719 | const struct net_device *out, | 726 | const struct net_device *out, |
720 | int (*okfn)(struct sk_buff *)) | 727 | int (*okfn)(struct sk_buff *)) |
721 | { | 728 | { |
729 | struct net_bridge_port *p; | ||
730 | struct net_bridge *br; | ||
722 | struct net_device **d = (struct net_device **)(skb->cb); | 731 | struct net_device **d = (struct net_device **)(skb->cb); |
723 | 732 | ||
724 | #ifdef CONFIG_SYSCTL | 733 | p = br_port_get_rcu(out); |
725 | if (!brnf_call_arptables) | 734 | if (p == NULL) |
735 | return NF_ACCEPT; | ||
736 | br = p->br; | ||
737 | |||
738 | if (!brnf_call_arptables && !br->nf_call_arptables) | ||
726 | return NF_ACCEPT; | 739 | return NF_ACCEPT; |
727 | #endif | ||
728 | 740 | ||
729 | if (skb->protocol != htons(ETH_P_ARP)) { | 741 | if (skb->protocol != htons(ETH_P_ARP)) { |
730 | if (!IS_VLAN_ARP(skb)) | 742 | if (!IS_VLAN_ARP(skb)) |
diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c index fe0a79018ab2..4a6a378c84e3 100644 --- a/net/bridge/br_netlink.c +++ b/net/bridge/br_netlink.c | |||
@@ -120,10 +120,11 @@ static int br_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb) | |||
120 | idx = 0; | 120 | idx = 0; |
121 | for_each_netdev(net, dev) { | 121 | for_each_netdev(net, dev) { |
122 | /* not a bridge port */ | 122 | /* not a bridge port */ |
123 | if (dev->br_port == NULL || idx < cb->args[0]) | 123 | if (!br_port_exists(dev) || idx < cb->args[0]) |
124 | goto skip; | 124 | goto skip; |
125 | 125 | ||
126 | if (br_fill_ifinfo(skb, dev->br_port, NETLINK_CB(cb->skb).pid, | 126 | if (br_fill_ifinfo(skb, br_port_get(dev), |
127 | NETLINK_CB(cb->skb).pid, | ||
127 | cb->nlh->nlmsg_seq, RTM_NEWLINK, | 128 | cb->nlh->nlmsg_seq, RTM_NEWLINK, |
128 | NLM_F_MULTI) < 0) | 129 | NLM_F_MULTI) < 0) |
129 | break; | 130 | break; |
@@ -168,9 +169,9 @@ static int br_rtm_setlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | |||
168 | if (!dev) | 169 | if (!dev) |
169 | return -ENODEV; | 170 | return -ENODEV; |
170 | 171 | ||
171 | p = dev->br_port; | 172 | if (!br_port_exists(dev)) |
172 | if (!p) | ||
173 | return -EINVAL; | 173 | return -EINVAL; |
174 | p = br_port_get(dev); | ||
174 | 175 | ||
175 | /* if kernel STP is running, don't allow changes */ | 176 | /* if kernel STP is running, don't allow changes */ |
176 | if (p->br->stp_enabled == BR_KERNEL_STP) | 177 | if (p->br->stp_enabled == BR_KERNEL_STP) |
diff --git a/net/bridge/br_notify.c b/net/bridge/br_notify.c index 717e1fd6133c..404d4e14c6a7 100644 --- a/net/bridge/br_notify.c +++ b/net/bridge/br_notify.c | |||
@@ -32,14 +32,15 @@ struct notifier_block br_device_notifier = { | |||
32 | static int br_device_event(struct notifier_block *unused, unsigned long event, void *ptr) | 32 | static int br_device_event(struct notifier_block *unused, unsigned long event, void *ptr) |
33 | { | 33 | { |
34 | struct net_device *dev = ptr; | 34 | struct net_device *dev = ptr; |
35 | struct net_bridge_port *p = dev->br_port; | 35 | struct net_bridge_port *p = br_port_get(dev); |
36 | struct net_bridge *br; | 36 | struct net_bridge *br; |
37 | int err; | 37 | int err; |
38 | 38 | ||
39 | /* not a port of a bridge */ | 39 | /* not a port of a bridge */ |
40 | if (p == NULL) | 40 | if (!br_port_exists(dev)) |
41 | return NOTIFY_DONE; | 41 | return NOTIFY_DONE; |
42 | 42 | ||
43 | p = br_port_get(dev); | ||
43 | br = p->br; | 44 | br = p->br; |
44 | 45 | ||
45 | switch (event) { | 46 | switch (event) { |
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h index 0f4a74bc6a9b..75c90edaf7db 100644 --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h | |||
@@ -15,6 +15,8 @@ | |||
15 | 15 | ||
16 | #include <linux/netdevice.h> | 16 | #include <linux/netdevice.h> |
17 | #include <linux/if_bridge.h> | 17 | #include <linux/if_bridge.h> |
18 | #include <linux/netpoll.h> | ||
19 | #include <linux/u64_stats_sync.h> | ||
18 | #include <net/route.h> | 20 | #include <net/route.h> |
19 | 21 | ||
20 | #define BR_HASH_BITS 8 | 22 | #define BR_HASH_BITS 8 |
@@ -143,13 +145,23 @@ struct net_bridge_port | |||
143 | #ifdef CONFIG_SYSFS | 145 | #ifdef CONFIG_SYSFS |
144 | char sysfs_name[IFNAMSIZ]; | 146 | char sysfs_name[IFNAMSIZ]; |
145 | #endif | 147 | #endif |
148 | |||
149 | #ifdef CONFIG_NET_POLL_CONTROLLER | ||
150 | struct netpoll *np; | ||
151 | #endif | ||
146 | }; | 152 | }; |
147 | 153 | ||
154 | #define br_port_get_rcu(dev) \ | ||
155 | ((struct net_bridge_port *) rcu_dereference(dev->rx_handler_data)) | ||
156 | #define br_port_get(dev) ((struct net_bridge_port *) dev->rx_handler_data) | ||
157 | #define br_port_exists(dev) (dev->priv_flags & IFF_BRIDGE_PORT) | ||
158 | |||
148 | struct br_cpu_netstats { | 159 | struct br_cpu_netstats { |
149 | unsigned long rx_packets; | 160 | u64 rx_packets; |
150 | unsigned long rx_bytes; | 161 | u64 rx_bytes; |
151 | unsigned long tx_packets; | 162 | u64 tx_packets; |
152 | unsigned long tx_bytes; | 163 | u64 tx_bytes; |
164 | struct u64_stats_sync syncp; | ||
153 | }; | 165 | }; |
154 | 166 | ||
155 | struct net_bridge | 167 | struct net_bridge |
@@ -164,6 +176,9 @@ struct net_bridge | |||
164 | unsigned long feature_mask; | 176 | unsigned long feature_mask; |
165 | #ifdef CONFIG_BRIDGE_NETFILTER | 177 | #ifdef CONFIG_BRIDGE_NETFILTER |
166 | struct rtable fake_rtable; | 178 | struct rtable fake_rtable; |
179 | bool nf_call_iptables; | ||
180 | bool nf_call_ip6tables; | ||
181 | bool nf_call_arptables; | ||
167 | #endif | 182 | #endif |
168 | unsigned long flags; | 183 | unsigned long flags; |
169 | #define BR_SET_MAC_ADDR 0x00000001 | 184 | #define BR_SET_MAC_ADDR 0x00000001 |
@@ -273,16 +288,41 @@ extern void br_dev_setup(struct net_device *dev); | |||
273 | extern netdev_tx_t br_dev_xmit(struct sk_buff *skb, | 288 | extern netdev_tx_t br_dev_xmit(struct sk_buff *skb, |
274 | struct net_device *dev); | 289 | struct net_device *dev); |
275 | #ifdef CONFIG_NET_POLL_CONTROLLER | 290 | #ifdef CONFIG_NET_POLL_CONTROLLER |
276 | extern void br_netpoll_cleanup(struct net_device *dev); | 291 | static inline struct netpoll_info *br_netpoll_info(struct net_bridge *br) |
277 | extern void br_netpoll_enable(struct net_bridge *br, | 292 | { |
278 | struct net_device *dev); | 293 | return br->dev->npinfo; |
279 | extern void br_netpoll_disable(struct net_bridge *br, | 294 | } |
280 | struct net_device *dev); | 295 | |
296 | static inline void br_netpoll_send_skb(const struct net_bridge_port *p, | ||
297 | struct sk_buff *skb) | ||
298 | { | ||
299 | struct netpoll *np = p->np; | ||
300 | |||
301 | if (np) | ||
302 | netpoll_send_skb(np, skb); | ||
303 | } | ||
304 | |||
305 | extern int br_netpoll_enable(struct net_bridge_port *p); | ||
306 | extern void br_netpoll_disable(struct net_bridge_port *p); | ||
281 | #else | 307 | #else |
282 | #define br_netpoll_cleanup(br) | 308 | static inline struct netpoll_info *br_netpoll_info(struct net_bridge *br) |
283 | #define br_netpoll_enable(br, dev) | 309 | { |
284 | #define br_netpoll_disable(br, dev) | 310 | return NULL; |
311 | } | ||
312 | |||
313 | static inline void br_netpoll_send_skb(const struct net_bridge_port *p, | ||
314 | struct sk_buff *skb) | ||
315 | { | ||
316 | } | ||
285 | 317 | ||
318 | static inline int br_netpoll_enable(struct net_bridge_port *p) | ||
319 | { | ||
320 | return 0; | ||
321 | } | ||
322 | |||
323 | static inline void br_netpoll_disable(struct net_bridge_port *p) | ||
324 | { | ||
325 | } | ||
286 | #endif | 326 | #endif |
287 | 327 | ||
288 | /* br_fdb.c */ | 328 | /* br_fdb.c */ |
@@ -331,8 +371,7 @@ extern void br_features_recompute(struct net_bridge *br); | |||
331 | 371 | ||
332 | /* br_input.c */ | 372 | /* br_input.c */ |
333 | extern int br_handle_frame_finish(struct sk_buff *skb); | 373 | extern int br_handle_frame_finish(struct sk_buff *skb); |
334 | extern struct sk_buff *br_handle_frame(struct net_bridge_port *p, | 374 | extern struct sk_buff *br_handle_frame(struct sk_buff *skb); |
335 | struct sk_buff *skb); | ||
336 | 375 | ||
337 | /* br_ioctl.c */ | 376 | /* br_ioctl.c */ |
338 | extern int br_dev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); | 377 | extern int br_dev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); |
diff --git a/net/bridge/br_stp_bpdu.c b/net/bridge/br_stp_bpdu.c index 217bd225a42f..35cf27087b56 100644 --- a/net/bridge/br_stp_bpdu.c +++ b/net/bridge/br_stp_bpdu.c | |||
@@ -131,18 +131,19 @@ void br_send_tcn_bpdu(struct net_bridge_port *p) | |||
131 | /* | 131 | /* |
132 | * Called from llc. | 132 | * Called from llc. |
133 | * | 133 | * |
134 | * NO locks, but rcu_read_lock (preempt_disabled) | 134 | * NO locks, but rcu_read_lock |
135 | */ | 135 | */ |
136 | void br_stp_rcv(const struct stp_proto *proto, struct sk_buff *skb, | 136 | void br_stp_rcv(const struct stp_proto *proto, struct sk_buff *skb, |
137 | struct net_device *dev) | 137 | struct net_device *dev) |
138 | { | 138 | { |
139 | const unsigned char *dest = eth_hdr(skb)->h_dest; | 139 | const unsigned char *dest = eth_hdr(skb)->h_dest; |
140 | struct net_bridge_port *p = rcu_dereference(dev->br_port); | 140 | struct net_bridge_port *p; |
141 | struct net_bridge *br; | 141 | struct net_bridge *br; |
142 | const unsigned char *buf; | 142 | const unsigned char *buf; |
143 | 143 | ||
144 | if (!p) | 144 | if (!br_port_exists(dev)) |
145 | goto err; | 145 | goto err; |
146 | p = br_port_get_rcu(dev); | ||
146 | 147 | ||
147 | if (!pskb_may_pull(skb, 4)) | 148 | if (!pskb_may_pull(skb, 4)) |
148 | goto err; | 149 | goto err; |
diff --git a/net/bridge/br_sysfs_br.c b/net/bridge/br_sysfs_br.c index 486b8f3861d2..5c1e5559ebba 100644 --- a/net/bridge/br_sysfs_br.c +++ b/net/bridge/br_sysfs_br.c | |||
@@ -611,6 +611,73 @@ static DEVICE_ATTR(multicast_startup_query_interval, S_IRUGO | S_IWUSR, | |||
611 | show_multicast_startup_query_interval, | 611 | show_multicast_startup_query_interval, |
612 | store_multicast_startup_query_interval); | 612 | store_multicast_startup_query_interval); |
613 | #endif | 613 | #endif |
614 | #ifdef CONFIG_BRIDGE_NETFILTER | ||
615 | static ssize_t show_nf_call_iptables( | ||
616 | struct device *d, struct device_attribute *attr, char *buf) | ||
617 | { | ||
618 | struct net_bridge *br = to_bridge(d); | ||
619 | return sprintf(buf, "%u\n", br->nf_call_iptables); | ||
620 | } | ||
621 | |||
622 | static int set_nf_call_iptables(struct net_bridge *br, unsigned long val) | ||
623 | { | ||
624 | br->nf_call_iptables = val ? true : false; | ||
625 | return 0; | ||
626 | } | ||
627 | |||
628 | static ssize_t store_nf_call_iptables( | ||
629 | struct device *d, struct device_attribute *attr, const char *buf, | ||
630 | size_t len) | ||
631 | { | ||
632 | return store_bridge_parm(d, buf, len, set_nf_call_iptables); | ||
633 | } | ||
634 | static DEVICE_ATTR(nf_call_iptables, S_IRUGO | S_IWUSR, | ||
635 | show_nf_call_iptables, store_nf_call_iptables); | ||
636 | |||
637 | static ssize_t show_nf_call_ip6tables( | ||
638 | struct device *d, struct device_attribute *attr, char *buf) | ||
639 | { | ||
640 | struct net_bridge *br = to_bridge(d); | ||
641 | return sprintf(buf, "%u\n", br->nf_call_ip6tables); | ||
642 | } | ||
643 | |||
644 | static int set_nf_call_ip6tables(struct net_bridge *br, unsigned long val) | ||
645 | { | ||
646 | br->nf_call_ip6tables = val ? true : false; | ||
647 | return 0; | ||
648 | } | ||
649 | |||
650 | static ssize_t store_nf_call_ip6tables( | ||
651 | struct device *d, struct device_attribute *attr, const char *buf, | ||
652 | size_t len) | ||
653 | { | ||
654 | return store_bridge_parm(d, buf, len, set_nf_call_ip6tables); | ||
655 | } | ||
656 | static DEVICE_ATTR(nf_call_ip6tables, S_IRUGO | S_IWUSR, | ||
657 | show_nf_call_ip6tables, store_nf_call_ip6tables); | ||
658 | |||
659 | static ssize_t show_nf_call_arptables( | ||
660 | struct device *d, struct device_attribute *attr, char *buf) | ||
661 | { | ||
662 | struct net_bridge *br = to_bridge(d); | ||
663 | return sprintf(buf, "%u\n", br->nf_call_arptables); | ||
664 | } | ||
665 | |||
666 | static int set_nf_call_arptables(struct net_bridge *br, unsigned long val) | ||
667 | { | ||
668 | br->nf_call_arptables = val ? true : false; | ||
669 | return 0; | ||
670 | } | ||
671 | |||
672 | static ssize_t store_nf_call_arptables( | ||
673 | struct device *d, struct device_attribute *attr, const char *buf, | ||
674 | size_t len) | ||
675 | { | ||
676 | return store_bridge_parm(d, buf, len, set_nf_call_arptables); | ||
677 | } | ||
678 | static DEVICE_ATTR(nf_call_arptables, S_IRUGO | S_IWUSR, | ||
679 | show_nf_call_arptables, store_nf_call_arptables); | ||
680 | #endif | ||
614 | 681 | ||
615 | static struct attribute *bridge_attrs[] = { | 682 | static struct attribute *bridge_attrs[] = { |
616 | &dev_attr_forward_delay.attr, | 683 | &dev_attr_forward_delay.attr, |
@@ -645,6 +712,11 @@ static struct attribute *bridge_attrs[] = { | |||
645 | &dev_attr_multicast_query_response_interval.attr, | 712 | &dev_attr_multicast_query_response_interval.attr, |
646 | &dev_attr_multicast_startup_query_interval.attr, | 713 | &dev_attr_multicast_startup_query_interval.attr, |
647 | #endif | 714 | #endif |
715 | #ifdef CONFIG_BRIDGE_NETFILTER | ||
716 | &dev_attr_nf_call_iptables.attr, | ||
717 | &dev_attr_nf_call_ip6tables.attr, | ||
718 | &dev_attr_nf_call_arptables.attr, | ||
719 | #endif | ||
648 | NULL | 720 | NULL |
649 | }; | 721 | }; |
650 | 722 | ||
diff --git a/net/bridge/netfilter/ebt_redirect.c b/net/bridge/netfilter/ebt_redirect.c index 9e19166ba453..46624bb6d9be 100644 --- a/net/bridge/netfilter/ebt_redirect.c +++ b/net/bridge/netfilter/ebt_redirect.c | |||
@@ -24,8 +24,9 @@ ebt_redirect_tg(struct sk_buff *skb, const struct xt_action_param *par) | |||
24 | return EBT_DROP; | 24 | return EBT_DROP; |
25 | 25 | ||
26 | if (par->hooknum != NF_BR_BROUTING) | 26 | if (par->hooknum != NF_BR_BROUTING) |
27 | /* rcu_read_lock()ed by nf_hook_slow */ | ||
27 | memcpy(eth_hdr(skb)->h_dest, | 28 | memcpy(eth_hdr(skb)->h_dest, |
28 | par->in->br_port->br->dev->dev_addr, ETH_ALEN); | 29 | br_port_get_rcu(par->in)->br->dev->dev_addr, ETH_ALEN); |
29 | else | 30 | else |
30 | memcpy(eth_hdr(skb)->h_dest, par->in->dev_addr, ETH_ALEN); | 31 | memcpy(eth_hdr(skb)->h_dest, par->in->dev_addr, ETH_ALEN); |
31 | skb->pkt_type = PACKET_HOST; | 32 | skb->pkt_type = PACKET_HOST; |
diff --git a/net/bridge/netfilter/ebt_ulog.c b/net/bridge/netfilter/ebt_ulog.c index ae3c7cef1484..26377e96fa1c 100644 --- a/net/bridge/netfilter/ebt_ulog.c +++ b/net/bridge/netfilter/ebt_ulog.c | |||
@@ -177,8 +177,9 @@ static void ebt_ulog_packet(unsigned int hooknr, const struct sk_buff *skb, | |||
177 | if (in) { | 177 | if (in) { |
178 | strcpy(pm->physindev, in->name); | 178 | strcpy(pm->physindev, in->name); |
179 | /* If in isn't a bridge, then physindev==indev */ | 179 | /* If in isn't a bridge, then physindev==indev */ |
180 | if (in->br_port) | 180 | if (br_port_exists(in)) |
181 | strcpy(pm->indev, in->br_port->br->dev->name); | 181 | /* rcu_read_lock()ed by nf_hook_slow */ |
182 | strcpy(pm->indev, br_port_get_rcu(in)->br->dev->name); | ||
182 | else | 183 | else |
183 | strcpy(pm->indev, in->name); | 184 | strcpy(pm->indev, in->name); |
184 | } else | 185 | } else |
@@ -187,7 +188,8 @@ static void ebt_ulog_packet(unsigned int hooknr, const struct sk_buff *skb, | |||
187 | if (out) { | 188 | if (out) { |
188 | /* If out exists, then out is a bridge port */ | 189 | /* If out exists, then out is a bridge port */ |
189 | strcpy(pm->physoutdev, out->name); | 190 | strcpy(pm->physoutdev, out->name); |
190 | strcpy(pm->outdev, out->br_port->br->dev->name); | 191 | /* rcu_read_lock()ed by nf_hook_slow */ |
192 | strcpy(pm->outdev, br_port_get_rcu(out)->br->dev->name); | ||
191 | } else | 193 | } else |
192 | pm->outdev[0] = pm->physoutdev[0] = '\0'; | 194 | pm->outdev[0] = pm->physoutdev[0] = '\0'; |
193 | 195 | ||
diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c index 59ca00e40dec..bcc102e3be4d 100644 --- a/net/bridge/netfilter/ebtables.c +++ b/net/bridge/netfilter/ebtables.c | |||
@@ -140,11 +140,14 @@ ebt_basic_match(const struct ebt_entry *e, const struct ethhdr *h, | |||
140 | return 1; | 140 | return 1; |
141 | if (FWINV2(ebt_dev_check(e->out, out), EBT_IOUT)) | 141 | if (FWINV2(ebt_dev_check(e->out, out), EBT_IOUT)) |
142 | return 1; | 142 | return 1; |
143 | if ((!in || !in->br_port) ? 0 : FWINV2(ebt_dev_check( | 143 | /* rcu_read_lock()ed by nf_hook_slow */ |
144 | e->logical_in, in->br_port->br->dev), EBT_ILOGICALIN)) | 144 | if (in && br_port_exists(in) && |
145 | FWINV2(ebt_dev_check(e->logical_in, br_port_get_rcu(in)->br->dev), | ||
146 | EBT_ILOGICALIN)) | ||
145 | return 1; | 147 | return 1; |
146 | if ((!out || !out->br_port) ? 0 : FWINV2(ebt_dev_check( | 148 | if (out && br_port_exists(out) && |
147 | e->logical_out, out->br_port->br->dev), EBT_ILOGICALOUT)) | 149 | FWINV2(ebt_dev_check(e->logical_out, br_port_get_rcu(out)->br->dev), |
150 | EBT_ILOGICALOUT)) | ||
148 | return 1; | 151 | return 1; |
149 | 152 | ||
150 | if (e->bitmask & EBT_SOURCEMAC) { | 153 | if (e->bitmask & EBT_SOURCEMAC) { |