Skip to content

Commit f350a0a

Browse files
Jiri Pirkodavem330
authored andcommitted
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 <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent a35e2c1 commit f350a0a

File tree

20 files changed

+71
-50
lines changed

20 files changed

+71
-50
lines changed

drivers/net/ksz884x.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5718,7 +5718,7 @@ static void dev_set_promiscuous(struct net_device *dev, struct dev_priv *priv,
57185718
* from the bridge.
57195719
*/
57205720
if ((hw->features & STP_SUPPORT) && !promiscuous &&
5721-
dev->br_port) {
5721+
(dev->priv_flags & IFF_BRIDGE_PORT)) {
57225722
struct ksz_switch *sw = hw->ksz_switch;
57235723
int port = priv->port.first_port;
57245724

drivers/staging/batman-adv/hard-interface.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ static int is_valid_iface(struct net_device *net_dev)
7171
#endif
7272

7373
/* Device is being bridged */
74-
/* if (net_dev->br_port != NULL)
74+
/* if (net_dev->priv_flags & IFF_BRIDGE_PORT)
7575
return 0; */
7676

7777
return 1;

include/linux/if.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@
7474
#define IFF_IN_NETPOLL 0x1000 /* whether we are processing netpoll */
7575
#define IFF_DISABLE_NETPOLL 0x2000 /* disable netpoll at run-time */
7676
#define IFF_MACVLAN_PORT 0x4000 /* device used as macvlan port */
77+
#define IFF_BRIDGE_PORT 0x8000 /* device used as bridge port */
7778

7879
#define IF_GET_IFACE 0x0001 /* for querying only */
7980
#define IF_GET_PROTO 0x0002

include/linux/netdevice.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1047,8 +1047,6 @@ struct net_device {
10471047
/* mid-layer private */
10481048
void *ml_priv;
10491049

1050-
/* bridge stuff */
1051-
struct net_bridge_port *br_port;
10521050
/* GARP */
10531051
struct garp_port *garp_port;
10541052

net/bridge/br_fdb.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -242,11 +242,11 @@ int br_fdb_test_addr(struct net_device *dev, unsigned char *addr)
242242
struct net_bridge_fdb_entry *fdb;
243243
int ret;
244244

245-
if (!dev->br_port)
245+
if (!br_port_exists(dev))
246246
return 0;
247247

248248
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);
250250
ret = fdb && fdb->dst->dev != dev &&
251251
fdb->dst->state == BR_STATE_FORWARDING;
252252
rcu_read_unlock();

net/bridge/br_if.c

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -147,8 +147,9 @@ static void del_nbp(struct net_bridge_port *p)
147147

148148
list_del_rcu(&p->list);
149149

150+
dev->priv_flags &= ~IFF_BRIDGE_PORT;
151+
150152
netdev_rx_handler_unregister(dev);
151-
rcu_assign_pointer(dev->br_port, NULL);
152153

153154
br_multicast_del_port(p);
154155

@@ -400,7 +401,7 @@ int br_add_if(struct net_bridge *br, struct net_device *dev)
400401
return -ELOOP;
401402

402403
/* Device is already being bridged */
403-
if (dev->br_port != NULL)
404+
if (br_port_exists(dev))
404405
return -EBUSY;
405406

406407
/* No bridging devices that dislike that (e.g. wireless) */
@@ -431,11 +432,11 @@ int br_add_if(struct net_bridge *br, struct net_device *dev)
431432
if (br_netpoll_info(br) && ((err = br_netpoll_enable(p))))
432433
goto err3;
433434

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);
437436
if (err)
438-
goto err4;
437+
goto err3;
438+
439+
dev->priv_flags |= IFF_BRIDGE_PORT;
439440

440441
dev_disable_lro(dev);
441442

@@ -457,8 +458,6 @@ int br_add_if(struct net_bridge *br, struct net_device *dev)
457458
kobject_uevent(&p->kobj, KOBJ_ADD);
458459

459460
return 0;
460-
err4:
461-
rcu_assign_pointer(dev->br_port, NULL);
462461
err3:
463462
sysfs_remove_link(br->ifobj, p->dev->name);
464463
err2:
@@ -477,9 +476,13 @@ int br_add_if(struct net_bridge *br, struct net_device *dev)
477476
/* called with RTNL */
478477
int br_del_if(struct net_bridge *br, struct net_device *dev)
479478
{
480-
struct net_bridge_port *p = dev->br_port;
479+
struct net_bridge_port *p;
480+
481+
if (!br_port_exists(dev))
482+
return -EINVAL;
481483

482-
if (!p || p->br != br)
484+
p = br_port_get(dev);
485+
if (p->br != br)
483486
return -EINVAL;
484487

485488
del_nbp(p);

net/bridge/br_input.c

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ static int br_pass_frame_up(struct sk_buff *skb)
4141
int br_handle_frame_finish(struct sk_buff *skb)
4242
{
4343
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);
4545
struct net_bridge *br;
4646
struct net_bridge_fdb_entry *dst;
4747
struct net_bridge_mdb_entry *mdst;
@@ -111,10 +111,9 @@ int br_handle_frame_finish(struct sk_buff *skb)
111111
/* note: already called with rcu_read_lock (preempt_disabled) */
112112
static int br_handle_local_finish(struct sk_buff *skb)
113113
{
114-
struct net_bridge_port *p = rcu_dereference(skb->dev->br_port);
114+
struct net_bridge_port *p = br_port_get_rcu(skb->dev);
115115

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);
118117
return 0; /* process further */
119118
}
120119

@@ -151,7 +150,7 @@ struct sk_buff *br_handle_frame(struct sk_buff *skb)
151150
if (!skb)
152151
return NULL;
153152

154-
p = rcu_dereference(skb->dev->br_port);
153+
p = br_port_get_rcu(skb->dev);
155154

156155
if (unlikely(is_link_local(dest))) {
157156
/* Pause frames shouldn't be passed up by driver anyway */

net/bridge/br_netfilter.c

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -127,16 +127,17 @@ void br_netfilter_rtable_init(struct net_bridge *br)
127127

128128
static inline struct rtable *bridge_parent_rtable(const struct net_device *dev)
129129
{
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;
133133
}
134134

135135
static inline struct net_device *bridge_parent(const struct net_device *dev)
136136
{
137-
struct net_bridge_port *port = rcu_dereference(dev->br_port);
137+
if (!br_port_exists(dev))
138+
return NULL;
138139

139-
return port ? port->br->dev : NULL;
140+
return br_port_get_rcu(dev)->br->dev;
140141
}
141142

142143
static inline struct nf_bridge_info *nf_bridge_alloc(struct sk_buff *skb)

net/bridge/br_netlink.c

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -120,10 +120,11 @@ static int br_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb)
120120
idx = 0;
121121
for_each_netdev(net, dev) {
122122
/* not a bridge port */
123-
if (dev->br_port == NULL || idx < cb->args[0])
123+
if (!br_port_exists(dev) || idx < cb->args[0])
124124
goto skip;
125125

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,
127128
cb->nlh->nlmsg_seq, RTM_NEWLINK,
128129
NLM_F_MULTI) < 0)
129130
break;
@@ -168,9 +169,9 @@ static int br_rtm_setlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
168169
if (!dev)
169170
return -ENODEV;
170171

171-
p = dev->br_port;
172-
if (!p)
172+
if (!br_port_exists(dev))
173173
return -EINVAL;
174+
p = br_port_get(dev);
174175

175176
/* if kernel STP is running, don't allow changes */
176177
if (p->br->stp_enabled == BR_KERNEL_STP)

net/bridge/br_notify.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,14 +32,15 @@ struct notifier_block br_device_notifier = {
3232
static int br_device_event(struct notifier_block *unused, unsigned long event, void *ptr)
3333
{
3434
struct net_device *dev = ptr;
35-
struct net_bridge_port *p = dev->br_port;
35+
struct net_bridge_port *p = br_port_get(dev);
3636
struct net_bridge *br;
3737
int err;
3838

3939
/* not a port of a bridge */
40-
if (p == NULL)
40+
if (!br_port_exists(dev))
4141
return NOTIFY_DONE;
4242

43+
p = br_port_get(dev);
4344
br = p->br;
4445

4546
switch (event) {

net/bridge/br_private.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,11 @@ struct net_bridge_port
150150
#endif
151151
};
152152

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+
153158
struct br_cpu_netstats {
154159
unsigned long rx_packets;
155160
unsigned long rx_bytes;

net/bridge/br_stp_bpdu.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -137,12 +137,13 @@ void br_stp_rcv(const struct stp_proto *proto, struct sk_buff *skb,
137137
struct net_device *dev)
138138
{
139139
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;
141141
struct net_bridge *br;
142142
const unsigned char *buf;
143143

144-
if (!p)
144+
if (!br_port_exists(dev))
145145
goto err;
146+
p = br_port_get_rcu(dev);
146147

147148
if (!pskb_may_pull(skb, 4))
148149
goto err;

net/bridge/netfilter/ebt_redirect.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,9 @@ ebt_redirect_tg(struct sk_buff *skb, const struct xt_action_param *par)
2424
return EBT_DROP;
2525

2626
if (par->hooknum != NF_BR_BROUTING)
27+
/* rcu_read_lock()ed by nf_hook_slow */
2728
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);
2930
else
3031
memcpy(eth_hdr(skb)->h_dest, par->in->dev_addr, ETH_ALEN);
3132
skb->pkt_type = PACKET_HOST;

net/bridge/netfilter/ebt_ulog.c

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -177,8 +177,9 @@ static void ebt_ulog_packet(unsigned int hooknr, const struct sk_buff *skb,
177177
if (in) {
178178
strcpy(pm->physindev, in->name);
179179
/* 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);
182183
else
183184
strcpy(pm->indev, in->name);
184185
} else
@@ -187,7 +188,8 @@ static void ebt_ulog_packet(unsigned int hooknr, const struct sk_buff *skb,
187188
if (out) {
188189
/* If out exists, then out is a bridge port */
189190
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);
191193
} else
192194
pm->outdev[0] = pm->physoutdev[0] = '\0';
193195

net/bridge/netfilter/ebtables.c

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -140,11 +140,14 @@ ebt_basic_match(const struct ebt_entry *e, const struct ethhdr *h,
140140
return 1;
141141
if (FWINV2(ebt_dev_check(e->out, out), EBT_IOUT))
142142
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))
145147
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))
148151
return 1;
149152

150153
if (e->bitmask & EBT_SOURCEMAC) {

net/core/dev.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2765,7 +2765,8 @@ int __skb_bond_should_drop(struct sk_buff *skb, struct net_device *master)
27652765
if (master->priv_flags & IFF_MASTER_ARPMON)
27662766
dev->last_rx = jiffies;
27672767

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)) {
27692770
/* Do address unmangle. The local destination address
27702771
* will be always the one master has. Provides the right
27712772
* functionality in a bridge.

net/netfilter/nfnetlink_log.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -403,8 +403,9 @@ __build_packet_message(struct nfulnl_instance *inst,
403403
NLA_PUT_BE32(inst->skb, NFULA_IFINDEX_PHYSINDEV,
404404
htonl(indev->ifindex));
405405
/* this is the bridge group "brX" */
406+
/* rcu_read_lock()ed by nf_hook_slow or nf_log_packet */
406407
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));
408409
} else {
409410
/* Case 2: indev is bridge group, we need to look for
410411
* physical device (when called from ipv4) */
@@ -430,8 +431,9 @@ __build_packet_message(struct nfulnl_instance *inst,
430431
NLA_PUT_BE32(inst->skb, NFULA_IFINDEX_PHYSOUTDEV,
431432
htonl(outdev->ifindex));
432433
/* this is the bridge group "brX" */
434+
/* rcu_read_lock()ed by nf_hook_slow or nf_log_packet */
433435
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));
435437
} else {
436438
/* Case 2: indev is a bridge group, we need to look
437439
* for physical device (when called from ipv4) */

net/netfilter/nfnetlink_queue.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -296,8 +296,9 @@ nfqnl_build_packet_message(struct nfqnl_instance *queue,
296296
NLA_PUT_BE32(skb, NFQA_IFINDEX_PHYSINDEV,
297297
htonl(indev->ifindex));
298298
/* this is the bridge group "brX" */
299+
/* rcu_read_lock()ed by __nf_queue */
299300
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));
301302
} else {
302303
/* Case 2: indev is bridge group, we need to look for
303304
* physical device (when called from ipv4) */
@@ -321,8 +322,9 @@ nfqnl_build_packet_message(struct nfqnl_instance *queue,
321322
NLA_PUT_BE32(skb, NFQA_IFINDEX_PHYSOUTDEV,
322323
htonl(outdev->ifindex));
323324
/* this is the bridge group "brX" */
325+
/* rcu_read_lock()ed by __nf_queue */
324326
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));
326328
} else {
327329
/* Case 2: outdev is bridge group, we need to look for
328330
* physical output device (when called from ipv4) */

net/wireless/nl80211.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1107,7 +1107,7 @@ static int nl80211_valid_4addr(struct cfg80211_registered_device *rdev,
11071107
enum nl80211_iftype iftype)
11081108
{
11091109
if (!use_4addr) {
1110-
if (netdev && netdev->br_port)
1110+
if (netdev && (netdev->priv_flags & IFF_BRIDGE_PORT))
11111111
return -EBUSY;
11121112
return 0;
11131113
}

net/wireless/util.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -770,8 +770,8 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev,
770770
return -EOPNOTSUPP;
771771

772772
/* 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))
775775
return -EBUSY;
776776

777777
if (ntype != otype) {

0 commit comments

Comments
 (0)