Commit f350a0a87374418635689471606454abc7beaa3a
Committed by
David S. Miller
1 parent
a35e2c1b6d
Exists in
master
and in
7 other branches
bridge: use rx_handler_data pointer to store net_bridge_port pointer
Register net_bridge_port pointer as rx_handler data pointer. As br_port is removed from struct net_device, another netdev priv_flag is added to indicate the device serves as a bridge port. Also rcuized pointers are now correctly dereferenced in br_fdb.c and in netfilter parts. Signed-off-by: Jiri Pirko <jpirko@redhat.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Showing 20 changed files with 71 additions and 50 deletions Side-by-side Diff
- drivers/net/ksz884x.c
- drivers/staging/batman-adv/hard-interface.c
- include/linux/if.h
- include/linux/netdevice.h
- net/bridge/br_fdb.c
- net/bridge/br_if.c
- net/bridge/br_input.c
- net/bridge/br_netfilter.c
- net/bridge/br_netlink.c
- net/bridge/br_notify.c
- net/bridge/br_private.h
- net/bridge/br_stp_bpdu.c
- net/bridge/netfilter/ebt_redirect.c
- net/bridge/netfilter/ebt_ulog.c
- net/bridge/netfilter/ebtables.c
- net/core/dev.c
- net/netfilter/nfnetlink_log.c
- net/netfilter/nfnetlink_queue.c
- net/wireless/nl80211.c
- net/wireless/util.c
drivers/net/ksz884x.c
... | ... | @@ -5718,7 +5718,7 @@ |
5718 | 5718 | * from the bridge. |
5719 | 5719 | */ |
5720 | 5720 | if ((hw->features & STP_SUPPORT) && !promiscuous && |
5721 | - dev->br_port) { | |
5721 | + (dev->priv_flags & IFF_BRIDGE_PORT)) { | |
5722 | 5722 | struct ksz_switch *sw = hw->ksz_switch; |
5723 | 5723 | int port = priv->port.first_port; |
5724 | 5724 |
drivers/staging/batman-adv/hard-interface.c
include/linux/if.h
... | ... | @@ -74,6 +74,7 @@ |
74 | 74 | #define IFF_IN_NETPOLL 0x1000 /* whether we are processing netpoll */ |
75 | 75 | #define IFF_DISABLE_NETPOLL 0x2000 /* disable netpoll at run-time */ |
76 | 76 | #define IFF_MACVLAN_PORT 0x4000 /* device used as macvlan port */ |
77 | +#define IFF_BRIDGE_PORT 0x8000 /* device used as bridge port */ | |
77 | 78 | |
78 | 79 | #define IF_GET_IFACE 0x0001 /* for querying only */ |
79 | 80 | #define IF_GET_PROTO 0x0002 |
include/linux/netdevice.h
net/bridge/br_fdb.c
... | ... | @@ -242,11 +242,11 @@ |
242 | 242 | struct net_bridge_fdb_entry *fdb; |
243 | 243 | int ret; |
244 | 244 | |
245 | - if (!dev->br_port) | |
245 | + if (!br_port_exists(dev)) | |
246 | 246 | return 0; |
247 | 247 | |
248 | 248 | rcu_read_lock(); |
249 | - fdb = __br_fdb_get(dev->br_port->br, addr); | |
249 | + fdb = __br_fdb_get(br_port_get_rcu(dev)->br, addr); | |
250 | 250 | ret = fdb && fdb->dst->dev != dev && |
251 | 251 | fdb->dst->state == BR_STATE_FORWARDING; |
252 | 252 | rcu_read_unlock(); |
net/bridge/br_if.c
... | ... | @@ -147,8 +147,9 @@ |
147 | 147 | |
148 | 148 | list_del_rcu(&p->list); |
149 | 149 | |
150 | + dev->priv_flags &= ~IFF_BRIDGE_PORT; | |
151 | + | |
150 | 152 | netdev_rx_handler_unregister(dev); |
151 | - rcu_assign_pointer(dev->br_port, NULL); | |
152 | 153 | |
153 | 154 | br_multicast_del_port(p); |
154 | 155 | |
... | ... | @@ -400,7 +401,7 @@ |
400 | 401 | return -ELOOP; |
401 | 402 | |
402 | 403 | /* Device is already being bridged */ |
403 | - if (dev->br_port != NULL) | |
404 | + if (br_port_exists(dev)) | |
404 | 405 | return -EBUSY; |
405 | 406 | |
406 | 407 | /* No bridging devices that dislike that (e.g. wireless) */ |
407 | 408 | |
408 | 409 | |
... | ... | @@ -431,12 +432,12 @@ |
431 | 432 | if (br_netpoll_info(br) && ((err = br_netpoll_enable(p)))) |
432 | 433 | goto err3; |
433 | 434 | |
434 | - rcu_assign_pointer(dev->br_port, p); | |
435 | - | |
436 | - err = netdev_rx_handler_register(dev, br_handle_frame, NULL); | |
435 | + err = netdev_rx_handler_register(dev, br_handle_frame, p); | |
437 | 436 | if (err) |
438 | - goto err4; | |
437 | + goto err3; | |
439 | 438 | |
439 | + dev->priv_flags |= IFF_BRIDGE_PORT; | |
440 | + | |
440 | 441 | dev_disable_lro(dev); |
441 | 442 | |
442 | 443 | list_add_rcu(&p->list, &br->port_list); |
... | ... | @@ -457,8 +458,6 @@ |
457 | 458 | kobject_uevent(&p->kobj, KOBJ_ADD); |
458 | 459 | |
459 | 460 | return 0; |
460 | -err4: | |
461 | - rcu_assign_pointer(dev->br_port, NULL); | |
462 | 461 | err3: |
463 | 462 | sysfs_remove_link(br->ifobj, p->dev->name); |
464 | 463 | err2: |
465 | 464 | |
... | ... | @@ -477,9 +476,13 @@ |
477 | 476 | /* called with RTNL */ |
478 | 477 | int br_del_if(struct net_bridge *br, struct net_device *dev) |
479 | 478 | { |
480 | - struct net_bridge_port *p = dev->br_port; | |
479 | + struct net_bridge_port *p; | |
481 | 480 | |
482 | - if (!p || p->br != br) | |
481 | + if (!br_port_exists(dev)) | |
482 | + return -EINVAL; | |
483 | + | |
484 | + p = br_port_get(dev); | |
485 | + if (p->br != br) | |
483 | 486 | return -EINVAL; |
484 | 487 | |
485 | 488 | del_nbp(p); |
net/bridge/br_input.c
... | ... | @@ -41,7 +41,7 @@ |
41 | 41 | int br_handle_frame_finish(struct sk_buff *skb) |
42 | 42 | { |
43 | 43 | const unsigned char *dest = eth_hdr(skb)->h_dest; |
44 | - struct net_bridge_port *p = rcu_dereference(skb->dev->br_port); | |
44 | + struct net_bridge_port *p = br_port_get_rcu(skb->dev); | |
45 | 45 | struct net_bridge *br; |
46 | 46 | struct net_bridge_fdb_entry *dst; |
47 | 47 | struct net_bridge_mdb_entry *mdst; |
48 | 48 | |
... | ... | @@ -111,10 +111,9 @@ |
111 | 111 | /* note: already called with rcu_read_lock (preempt_disabled) */ |
112 | 112 | static int br_handle_local_finish(struct sk_buff *skb) |
113 | 113 | { |
114 | - struct net_bridge_port *p = rcu_dereference(skb->dev->br_port); | |
114 | + struct net_bridge_port *p = br_port_get_rcu(skb->dev); | |
115 | 115 | |
116 | - if (p) | |
117 | - br_fdb_update(p->br, p, eth_hdr(skb)->h_source); | |
116 | + br_fdb_update(p->br, p, eth_hdr(skb)->h_source); | |
118 | 117 | return 0; /* process further */ |
119 | 118 | } |
120 | 119 | |
... | ... | @@ -151,7 +150,7 @@ |
151 | 150 | if (!skb) |
152 | 151 | return NULL; |
153 | 152 | |
154 | - p = rcu_dereference(skb->dev->br_port); | |
153 | + p = br_port_get_rcu(skb->dev); | |
155 | 154 | |
156 | 155 | if (unlikely(is_link_local(dest))) { |
157 | 156 | /* Pause frames shouldn't be passed up by driver anyway */ |
net/bridge/br_netfilter.c
... | ... | @@ -127,16 +127,17 @@ |
127 | 127 | |
128 | 128 | static inline struct rtable *bridge_parent_rtable(const struct net_device *dev) |
129 | 129 | { |
130 | - struct net_bridge_port *port = rcu_dereference(dev->br_port); | |
131 | - | |
132 | - return port ? &port->br->fake_rtable : NULL; | |
130 | + if (!br_port_exists(dev)) | |
131 | + return NULL; | |
132 | + return &br_port_get_rcu(dev)->br->fake_rtable; | |
133 | 133 | } |
134 | 134 | |
135 | 135 | static inline struct net_device *bridge_parent(const struct net_device *dev) |
136 | 136 | { |
137 | - struct net_bridge_port *port = rcu_dereference(dev->br_port); | |
137 | + if (!br_port_exists(dev)) | |
138 | + return NULL; | |
138 | 139 | |
139 | - return port ? port->br->dev : NULL; | |
140 | + return br_port_get_rcu(dev)->br->dev; | |
140 | 141 | } |
141 | 142 | |
142 | 143 | static inline struct nf_bridge_info *nf_bridge_alloc(struct sk_buff *skb) |
net/bridge/br_netlink.c
... | ... | @@ -120,10 +120,11 @@ |
120 | 120 | idx = 0; |
121 | 121 | for_each_netdev(net, dev) { |
122 | 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 | 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 | 128 | cb->nlh->nlmsg_seq, RTM_NEWLINK, |
128 | 129 | NLM_F_MULTI) < 0) |
129 | 130 | break; |
130 | 131 | |
... | ... | @@ -168,9 +169,9 @@ |
168 | 169 | if (!dev) |
169 | 170 | return -ENODEV; |
170 | 171 | |
171 | - p = dev->br_port; | |
172 | - if (!p) | |
172 | + if (!br_port_exists(dev)) | |
173 | 173 | return -EINVAL; |
174 | + p = br_port_get(dev); | |
174 | 175 | |
175 | 176 | /* if kernel STP is running, don't allow changes */ |
176 | 177 | if (p->br->stp_enabled == BR_KERNEL_STP) |
net/bridge/br_notify.c
... | ... | @@ -32,14 +32,15 @@ |
32 | 32 | static int br_device_event(struct notifier_block *unused, unsigned long event, void *ptr) |
33 | 33 | { |
34 | 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 | 36 | struct net_bridge *br; |
37 | 37 | int err; |
38 | 38 | |
39 | 39 | /* not a port of a bridge */ |
40 | - if (p == NULL) | |
40 | + if (!br_port_exists(dev)) | |
41 | 41 | return NOTIFY_DONE; |
42 | 42 | |
43 | + p = br_port_get(dev); | |
43 | 44 | br = p->br; |
44 | 45 | |
45 | 46 | switch (event) { |
net/bridge/br_private.h
... | ... | @@ -150,6 +150,11 @@ |
150 | 150 | #endif |
151 | 151 | }; |
152 | 152 | |
153 | +#define br_port_get_rcu(dev) \ | |
154 | + ((struct net_bridge_port *) rcu_dereference(dev->rx_handler_data)) | |
155 | +#define br_port_get(dev) ((struct net_bridge_port *) dev->rx_handler_data) | |
156 | +#define br_port_exists(dev) (dev->priv_flags & IFF_BRIDGE_PORT) | |
157 | + | |
153 | 158 | struct br_cpu_netstats { |
154 | 159 | unsigned long rx_packets; |
155 | 160 | unsigned long rx_bytes; |
net/bridge/br_stp_bpdu.c
... | ... | @@ -137,12 +137,13 @@ |
137 | 137 | struct net_device *dev) |
138 | 138 | { |
139 | 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 | 141 | struct net_bridge *br; |
142 | 142 | const unsigned char *buf; |
143 | 143 | |
144 | - if (!p) | |
144 | + if (!br_port_exists(dev)) | |
145 | 145 | goto err; |
146 | + p = br_port_get_rcu(dev); | |
146 | 147 | |
147 | 148 | if (!pskb_may_pull(skb, 4)) |
148 | 149 | goto err; |
net/bridge/netfilter/ebt_redirect.c
... | ... | @@ -24,8 +24,9 @@ |
24 | 24 | return EBT_DROP; |
25 | 25 | |
26 | 26 | if (par->hooknum != NF_BR_BROUTING) |
27 | + /* rcu_read_lock()ed by nf_hook_slow */ | |
27 | 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 | 30 | else |
30 | 31 | memcpy(eth_hdr(skb)->h_dest, par->in->dev_addr, ETH_ALEN); |
31 | 32 | skb->pkt_type = PACKET_HOST; |
net/bridge/netfilter/ebt_ulog.c
... | ... | @@ -177,8 +177,9 @@ |
177 | 177 | if (in) { |
178 | 178 | strcpy(pm->physindev, in->name); |
179 | 179 | /* If in isn't a bridge, then physindev==indev */ |
180 | - if (in->br_port) | |
181 | - strcpy(pm->indev, in->br_port->br->dev->name); | |
180 | + if (br_port_exists(in)) | |
181 | + /* rcu_read_lock()ed by nf_hook_slow */ | |
182 | + strcpy(pm->indev, br_port_get_rcu(in)->br->dev->name); | |
182 | 183 | else |
183 | 184 | strcpy(pm->indev, in->name); |
184 | 185 | } else |
... | ... | @@ -187,7 +188,8 @@ |
187 | 188 | if (out) { |
188 | 189 | /* If out exists, then out is a bridge port */ |
189 | 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 | 193 | } else |
192 | 194 | pm->outdev[0] = pm->physoutdev[0] = '\0'; |
193 | 195 |
net/bridge/netfilter/ebtables.c
... | ... | @@ -140,11 +140,14 @@ |
140 | 140 | return 1; |
141 | 141 | if (FWINV2(ebt_dev_check(e->out, out), EBT_IOUT)) |
142 | 142 | return 1; |
143 | - if ((!in || !in->br_port) ? 0 : FWINV2(ebt_dev_check( | |
144 | - e->logical_in, in->br_port->br->dev), EBT_ILOGICALIN)) | |
143 | + /* rcu_read_lock()ed by nf_hook_slow */ | |
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 | 147 | return 1; |
146 | - if ((!out || !out->br_port) ? 0 : FWINV2(ebt_dev_check( | |
147 | - e->logical_out, out->br_port->br->dev), EBT_ILOGICALOUT)) | |
148 | + if (out && br_port_exists(out) && | |
149 | + FWINV2(ebt_dev_check(e->logical_out, br_port_get_rcu(out)->br->dev), | |
150 | + EBT_ILOGICALOUT)) | |
148 | 151 | return 1; |
149 | 152 | |
150 | 153 | if (e->bitmask & EBT_SOURCEMAC) { |
net/core/dev.c
... | ... | @@ -2765,7 +2765,8 @@ |
2765 | 2765 | if (master->priv_flags & IFF_MASTER_ARPMON) |
2766 | 2766 | dev->last_rx = jiffies; |
2767 | 2767 | |
2768 | - if ((master->priv_flags & IFF_MASTER_ALB) && master->br_port) { | |
2768 | + if ((master->priv_flags & IFF_MASTER_ALB) && | |
2769 | + (master->priv_flags & IFF_BRIDGE_PORT)) { | |
2769 | 2770 | /* Do address unmangle. The local destination address |
2770 | 2771 | * will be always the one master has. Provides the right |
2771 | 2772 | * functionality in a bridge. |
net/netfilter/nfnetlink_log.c
... | ... | @@ -403,8 +403,9 @@ |
403 | 403 | NLA_PUT_BE32(inst->skb, NFULA_IFINDEX_PHYSINDEV, |
404 | 404 | htonl(indev->ifindex)); |
405 | 405 | /* this is the bridge group "brX" */ |
406 | + /* rcu_read_lock()ed by nf_hook_slow or nf_log_packet */ | |
406 | 407 | NLA_PUT_BE32(inst->skb, NFULA_IFINDEX_INDEV, |
407 | - htonl(indev->br_port->br->dev->ifindex)); | |
408 | + htonl(br_port_get_rcu(indev)->br->dev->ifindex)); | |
408 | 409 | } else { |
409 | 410 | /* Case 2: indev is bridge group, we need to look for |
410 | 411 | * physical device (when called from ipv4) */ |
411 | 412 | |
... | ... | @@ -430,8 +431,9 @@ |
430 | 431 | NLA_PUT_BE32(inst->skb, NFULA_IFINDEX_PHYSOUTDEV, |
431 | 432 | htonl(outdev->ifindex)); |
432 | 433 | /* this is the bridge group "brX" */ |
434 | + /* rcu_read_lock()ed by nf_hook_slow or nf_log_packet */ | |
433 | 435 | NLA_PUT_BE32(inst->skb, NFULA_IFINDEX_OUTDEV, |
434 | - htonl(outdev->br_port->br->dev->ifindex)); | |
436 | + htonl(br_port_get_rcu(outdev)->br->dev->ifindex)); | |
435 | 437 | } else { |
436 | 438 | /* Case 2: indev is a bridge group, we need to look |
437 | 439 | * for physical device (when called from ipv4) */ |
net/netfilter/nfnetlink_queue.c
... | ... | @@ -296,8 +296,9 @@ |
296 | 296 | NLA_PUT_BE32(skb, NFQA_IFINDEX_PHYSINDEV, |
297 | 297 | htonl(indev->ifindex)); |
298 | 298 | /* this is the bridge group "brX" */ |
299 | + /* rcu_read_lock()ed by __nf_queue */ | |
299 | 300 | NLA_PUT_BE32(skb, NFQA_IFINDEX_INDEV, |
300 | - htonl(indev->br_port->br->dev->ifindex)); | |
301 | + htonl(br_port_get_rcu(indev)->br->dev->ifindex)); | |
301 | 302 | } else { |
302 | 303 | /* Case 2: indev is bridge group, we need to look for |
303 | 304 | * physical device (when called from ipv4) */ |
304 | 305 | |
... | ... | @@ -321,8 +322,9 @@ |
321 | 322 | NLA_PUT_BE32(skb, NFQA_IFINDEX_PHYSOUTDEV, |
322 | 323 | htonl(outdev->ifindex)); |
323 | 324 | /* this is the bridge group "brX" */ |
325 | + /* rcu_read_lock()ed by __nf_queue */ | |
324 | 326 | NLA_PUT_BE32(skb, NFQA_IFINDEX_OUTDEV, |
325 | - htonl(outdev->br_port->br->dev->ifindex)); | |
327 | + htonl(br_port_get_rcu(outdev)->br->dev->ifindex)); | |
326 | 328 | } else { |
327 | 329 | /* Case 2: outdev is bridge group, we need to look for |
328 | 330 | * physical output device (when called from ipv4) */ |
net/wireless/nl80211.c
net/wireless/util.c
... | ... | @@ -770,8 +770,8 @@ |
770 | 770 | return -EOPNOTSUPP; |
771 | 771 | |
772 | 772 | /* if it's part of a bridge, reject changing type to station/ibss */ |
773 | - if (dev->br_port && (ntype == NL80211_IFTYPE_ADHOC || | |
774 | - ntype == NL80211_IFTYPE_STATION)) | |
773 | + if ((dev->priv_flags & IFF_BRIDGE_PORT) && | |
774 | + (ntype == NL80211_IFTYPE_ADHOC || ntype == NL80211_IFTYPE_STATION)) | |
775 | 775 | return -EBUSY; |
776 | 776 | |
777 | 777 | if (ntype != otype) { |