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>
This commit is contained in:
parent
a35e2c1b6d
commit
f350a0a873
|
@ -5718,7 +5718,7 @@ static void dev_set_promiscuous(struct net_device *dev, struct dev_priv *priv,
|
|||
* from the bridge.
|
||||
*/
|
||||
if ((hw->features & STP_SUPPORT) && !promiscuous &&
|
||||
dev->br_port) {
|
||||
(dev->priv_flags & IFF_BRIDGE_PORT)) {
|
||||
struct ksz_switch *sw = hw->ksz_switch;
|
||||
int port = priv->port.first_port;
|
||||
|
||||
|
|
|
@ -71,7 +71,7 @@ static int is_valid_iface(struct net_device *net_dev)
|
|||
#endif
|
||||
|
||||
/* Device is being bridged */
|
||||
/* if (net_dev->br_port != NULL)
|
||||
/* if (net_dev->priv_flags & IFF_BRIDGE_PORT)
|
||||
return 0; */
|
||||
|
||||
return 1;
|
||||
|
|
|
@ -74,6 +74,7 @@
|
|||
#define IFF_IN_NETPOLL 0x1000 /* whether we are processing netpoll */
|
||||
#define IFF_DISABLE_NETPOLL 0x2000 /* disable netpoll at run-time */
|
||||
#define IFF_MACVLAN_PORT 0x4000 /* device used as macvlan port */
|
||||
#define IFF_BRIDGE_PORT 0x8000 /* device used as bridge port */
|
||||
|
||||
#define IF_GET_IFACE 0x0001 /* for querying only */
|
||||
#define IF_GET_PROTO 0x0002
|
||||
|
|
|
@ -1047,8 +1047,6 @@ struct net_device {
|
|||
/* mid-layer private */
|
||||
void *ml_priv;
|
||||
|
||||
/* bridge stuff */
|
||||
struct net_bridge_port *br_port;
|
||||
/* GARP */
|
||||
struct garp_port *garp_port;
|
||||
|
||||
|
|
|
@ -242,11 +242,11 @@ int br_fdb_test_addr(struct net_device *dev, unsigned char *addr)
|
|||
struct net_bridge_fdb_entry *fdb;
|
||||
int ret;
|
||||
|
||||
if (!dev->br_port)
|
||||
if (!br_port_exists(dev))
|
||||
return 0;
|
||||
|
||||
rcu_read_lock();
|
||||
fdb = __br_fdb_get(dev->br_port->br, addr);
|
||||
fdb = __br_fdb_get(br_port_get_rcu(dev)->br, addr);
|
||||
ret = fdb && fdb->dst->dev != dev &&
|
||||
fdb->dst->state == BR_STATE_FORWARDING;
|
||||
rcu_read_unlock();
|
||||
|
|
|
@ -147,8 +147,9 @@ static void del_nbp(struct net_bridge_port *p)
|
|||
|
||||
list_del_rcu(&p->list);
|
||||
|
||||
dev->priv_flags &= ~IFF_BRIDGE_PORT;
|
||||
|
||||
netdev_rx_handler_unregister(dev);
|
||||
rcu_assign_pointer(dev->br_port, NULL);
|
||||
|
||||
br_multicast_del_port(p);
|
||||
|
||||
|
@ -400,7 +401,7 @@ int br_add_if(struct net_bridge *br, struct net_device *dev)
|
|||
return -ELOOP;
|
||||
|
||||
/* Device is already being bridged */
|
||||
if (dev->br_port != NULL)
|
||||
if (br_port_exists(dev))
|
||||
return -EBUSY;
|
||||
|
||||
/* 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)
|
|||
if (br_netpoll_info(br) && ((err = br_netpoll_enable(p))))
|
||||
goto err3;
|
||||
|
||||
rcu_assign_pointer(dev->br_port, p);
|
||||
|
||||
err = netdev_rx_handler_register(dev, br_handle_frame, NULL);
|
||||
err = netdev_rx_handler_register(dev, br_handle_frame, p);
|
||||
if (err)
|
||||
goto err4;
|
||||
goto err3;
|
||||
|
||||
dev->priv_flags |= IFF_BRIDGE_PORT;
|
||||
|
||||
dev_disable_lro(dev);
|
||||
|
||||
|
@ -457,8 +458,6 @@ int br_add_if(struct net_bridge *br, struct net_device *dev)
|
|||
kobject_uevent(&p->kobj, KOBJ_ADD);
|
||||
|
||||
return 0;
|
||||
err4:
|
||||
rcu_assign_pointer(dev->br_port, NULL);
|
||||
err3:
|
||||
sysfs_remove_link(br->ifobj, p->dev->name);
|
||||
err2:
|
||||
|
@ -477,9 +476,13 @@ put_back:
|
|||
/* called with RTNL */
|
||||
int br_del_if(struct net_bridge *br, struct net_device *dev)
|
||||
{
|
||||
struct net_bridge_port *p = dev->br_port;
|
||||
struct net_bridge_port *p;
|
||||
|
||||
if (!p || p->br != br)
|
||||
if (!br_port_exists(dev))
|
||||
return -EINVAL;
|
||||
|
||||
p = br_port_get(dev);
|
||||
if (p->br != br)
|
||||
return -EINVAL;
|
||||
|
||||
del_nbp(p);
|
||||
|
|
|
@ -41,7 +41,7 @@ static int br_pass_frame_up(struct sk_buff *skb)
|
|||
int br_handle_frame_finish(struct sk_buff *skb)
|
||||
{
|
||||
const unsigned char *dest = eth_hdr(skb)->h_dest;
|
||||
struct net_bridge_port *p = rcu_dereference(skb->dev->br_port);
|
||||
struct net_bridge_port *p = br_port_get_rcu(skb->dev);
|
||||
struct net_bridge *br;
|
||||
struct net_bridge_fdb_entry *dst;
|
||||
struct net_bridge_mdb_entry *mdst;
|
||||
|
@ -111,10 +111,9 @@ drop:
|
|||
/* note: already called with rcu_read_lock (preempt_disabled) */
|
||||
static int br_handle_local_finish(struct sk_buff *skb)
|
||||
{
|
||||
struct net_bridge_port *p = rcu_dereference(skb->dev->br_port);
|
||||
struct net_bridge_port *p = br_port_get_rcu(skb->dev);
|
||||
|
||||
if (p)
|
||||
br_fdb_update(p->br, p, eth_hdr(skb)->h_source);
|
||||
br_fdb_update(p->br, p, eth_hdr(skb)->h_source);
|
||||
return 0; /* process further */
|
||||
}
|
||||
|
||||
|
@ -151,7 +150,7 @@ struct sk_buff *br_handle_frame(struct sk_buff *skb)
|
|||
if (!skb)
|
||||
return NULL;
|
||||
|
||||
p = rcu_dereference(skb->dev->br_port);
|
||||
p = br_port_get_rcu(skb->dev);
|
||||
|
||||
if (unlikely(is_link_local(dest))) {
|
||||
/* Pause frames shouldn't be passed up by driver anyway */
|
||||
|
|
|
@ -127,16 +127,17 @@ void br_netfilter_rtable_init(struct net_bridge *br)
|
|||
|
||||
static inline struct rtable *bridge_parent_rtable(const struct net_device *dev)
|
||||
{
|
||||
struct net_bridge_port *port = rcu_dereference(dev->br_port);
|
||||
|
||||
return port ? &port->br->fake_rtable : NULL;
|
||||
if (!br_port_exists(dev))
|
||||
return NULL;
|
||||
return &br_port_get_rcu(dev)->br->fake_rtable;
|
||||
}
|
||||
|
||||
static inline struct net_device *bridge_parent(const struct net_device *dev)
|
||||
{
|
||||
struct net_bridge_port *port = rcu_dereference(dev->br_port);
|
||||
if (!br_port_exists(dev))
|
||||
return NULL;
|
||||
|
||||
return port ? port->br->dev : NULL;
|
||||
return br_port_get_rcu(dev)->br->dev;
|
||||
}
|
||||
|
||||
static inline struct nf_bridge_info *nf_bridge_alloc(struct sk_buff *skb)
|
||||
|
|
|
@ -120,10 +120,11 @@ static int br_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb)
|
|||
idx = 0;
|
||||
for_each_netdev(net, dev) {
|
||||
/* not a bridge port */
|
||||
if (dev->br_port == NULL || idx < cb->args[0])
|
||||
if (!br_port_exists(dev) || idx < cb->args[0])
|
||||
goto skip;
|
||||
|
||||
if (br_fill_ifinfo(skb, dev->br_port, NETLINK_CB(cb->skb).pid,
|
||||
if (br_fill_ifinfo(skb, br_port_get(dev),
|
||||
NETLINK_CB(cb->skb).pid,
|
||||
cb->nlh->nlmsg_seq, RTM_NEWLINK,
|
||||
NLM_F_MULTI) < 0)
|
||||
break;
|
||||
|
@ -168,9 +169,9 @@ static int br_rtm_setlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
|
|||
if (!dev)
|
||||
return -ENODEV;
|
||||
|
||||
p = dev->br_port;
|
||||
if (!p)
|
||||
if (!br_port_exists(dev))
|
||||
return -EINVAL;
|
||||
p = br_port_get(dev);
|
||||
|
||||
/* if kernel STP is running, don't allow changes */
|
||||
if (p->br->stp_enabled == BR_KERNEL_STP)
|
||||
|
|
|
@ -32,14 +32,15 @@ struct notifier_block br_device_notifier = {
|
|||
static int br_device_event(struct notifier_block *unused, unsigned long event, void *ptr)
|
||||
{
|
||||
struct net_device *dev = ptr;
|
||||
struct net_bridge_port *p = dev->br_port;
|
||||
struct net_bridge_port *p = br_port_get(dev);
|
||||
struct net_bridge *br;
|
||||
int err;
|
||||
|
||||
/* not a port of a bridge */
|
||||
if (p == NULL)
|
||||
if (!br_port_exists(dev))
|
||||
return NOTIFY_DONE;
|
||||
|
||||
p = br_port_get(dev);
|
||||
br = p->br;
|
||||
|
||||
switch (event) {
|
||||
|
|
|
@ -150,6 +150,11 @@ struct net_bridge_port
|
|||
#endif
|
||||
};
|
||||
|
||||
#define br_port_get_rcu(dev) \
|
||||
((struct net_bridge_port *) rcu_dereference(dev->rx_handler_data))
|
||||
#define br_port_get(dev) ((struct net_bridge_port *) dev->rx_handler_data)
|
||||
#define br_port_exists(dev) (dev->priv_flags & IFF_BRIDGE_PORT)
|
||||
|
||||
struct br_cpu_netstats {
|
||||
unsigned long rx_packets;
|
||||
unsigned long rx_bytes;
|
||||
|
|
|
@ -137,12 +137,13 @@ void br_stp_rcv(const struct stp_proto *proto, struct sk_buff *skb,
|
|||
struct net_device *dev)
|
||||
{
|
||||
const unsigned char *dest = eth_hdr(skb)->h_dest;
|
||||
struct net_bridge_port *p = rcu_dereference(dev->br_port);
|
||||
struct net_bridge_port *p;
|
||||
struct net_bridge *br;
|
||||
const unsigned char *buf;
|
||||
|
||||
if (!p)
|
||||
if (!br_port_exists(dev))
|
||||
goto err;
|
||||
p = br_port_get_rcu(dev);
|
||||
|
||||
if (!pskb_may_pull(skb, 4))
|
||||
goto err;
|
||||
|
|
|
@ -24,8 +24,9 @@ ebt_redirect_tg(struct sk_buff *skb, const struct xt_action_param *par)
|
|||
return EBT_DROP;
|
||||
|
||||
if (par->hooknum != NF_BR_BROUTING)
|
||||
/* rcu_read_lock()ed by nf_hook_slow */
|
||||
memcpy(eth_hdr(skb)->h_dest,
|
||||
par->in->br_port->br->dev->dev_addr, ETH_ALEN);
|
||||
br_port_get_rcu(par->in)->br->dev->dev_addr, ETH_ALEN);
|
||||
else
|
||||
memcpy(eth_hdr(skb)->h_dest, par->in->dev_addr, ETH_ALEN);
|
||||
skb->pkt_type = PACKET_HOST;
|
||||
|
|
|
@ -177,8 +177,9 @@ static void ebt_ulog_packet(unsigned int hooknr, const struct sk_buff *skb,
|
|||
if (in) {
|
||||
strcpy(pm->physindev, in->name);
|
||||
/* If in isn't a bridge, then physindev==indev */
|
||||
if (in->br_port)
|
||||
strcpy(pm->indev, in->br_port->br->dev->name);
|
||||
if (br_port_exists(in))
|
||||
/* rcu_read_lock()ed by nf_hook_slow */
|
||||
strcpy(pm->indev, br_port_get_rcu(in)->br->dev->name);
|
||||
else
|
||||
strcpy(pm->indev, in->name);
|
||||
} else
|
||||
|
@ -187,7 +188,8 @@ static void ebt_ulog_packet(unsigned int hooknr, const struct sk_buff *skb,
|
|||
if (out) {
|
||||
/* If out exists, then out is a bridge port */
|
||||
strcpy(pm->physoutdev, out->name);
|
||||
strcpy(pm->outdev, out->br_port->br->dev->name);
|
||||
/* rcu_read_lock()ed by nf_hook_slow */
|
||||
strcpy(pm->outdev, br_port_get_rcu(out)->br->dev->name);
|
||||
} else
|
||||
pm->outdev[0] = pm->physoutdev[0] = '\0';
|
||||
|
||||
|
|
|
@ -140,11 +140,14 @@ ebt_basic_match(const struct ebt_entry *e, const struct ethhdr *h,
|
|||
return 1;
|
||||
if (FWINV2(ebt_dev_check(e->out, out), EBT_IOUT))
|
||||
return 1;
|
||||
if ((!in || !in->br_port) ? 0 : FWINV2(ebt_dev_check(
|
||||
e->logical_in, in->br_port->br->dev), EBT_ILOGICALIN))
|
||||
/* rcu_read_lock()ed by nf_hook_slow */
|
||||
if (in && br_port_exists(in) &&
|
||||
FWINV2(ebt_dev_check(e->logical_in, br_port_get_rcu(in)->br->dev),
|
||||
EBT_ILOGICALIN))
|
||||
return 1;
|
||||
if ((!out || !out->br_port) ? 0 : FWINV2(ebt_dev_check(
|
||||
e->logical_out, out->br_port->br->dev), EBT_ILOGICALOUT))
|
||||
if (out && br_port_exists(out) &&
|
||||
FWINV2(ebt_dev_check(e->logical_out, br_port_get_rcu(out)->br->dev),
|
||||
EBT_ILOGICALOUT))
|
||||
return 1;
|
||||
|
||||
if (e->bitmask & EBT_SOURCEMAC) {
|
||||
|
|
|
@ -2765,7 +2765,8 @@ int __skb_bond_should_drop(struct sk_buff *skb, struct net_device *master)
|
|||
if (master->priv_flags & IFF_MASTER_ARPMON)
|
||||
dev->last_rx = jiffies;
|
||||
|
||||
if ((master->priv_flags & IFF_MASTER_ALB) && master->br_port) {
|
||||
if ((master->priv_flags & IFF_MASTER_ALB) &&
|
||||
(master->priv_flags & IFF_BRIDGE_PORT)) {
|
||||
/* Do address unmangle. The local destination address
|
||||
* will be always the one master has. Provides the right
|
||||
* functionality in a bridge.
|
||||
|
|
|
@ -403,8 +403,9 @@ __build_packet_message(struct nfulnl_instance *inst,
|
|||
NLA_PUT_BE32(inst->skb, NFULA_IFINDEX_PHYSINDEV,
|
||||
htonl(indev->ifindex));
|
||||
/* this is the bridge group "brX" */
|
||||
/* rcu_read_lock()ed by nf_hook_slow or nf_log_packet */
|
||||
NLA_PUT_BE32(inst->skb, NFULA_IFINDEX_INDEV,
|
||||
htonl(indev->br_port->br->dev->ifindex));
|
||||
htonl(br_port_get_rcu(indev)->br->dev->ifindex));
|
||||
} else {
|
||||
/* Case 2: indev is bridge group, we need to look for
|
||||
* physical device (when called from ipv4) */
|
||||
|
@ -430,8 +431,9 @@ __build_packet_message(struct nfulnl_instance *inst,
|
|||
NLA_PUT_BE32(inst->skb, NFULA_IFINDEX_PHYSOUTDEV,
|
||||
htonl(outdev->ifindex));
|
||||
/* this is the bridge group "brX" */
|
||||
/* rcu_read_lock()ed by nf_hook_slow or nf_log_packet */
|
||||
NLA_PUT_BE32(inst->skb, NFULA_IFINDEX_OUTDEV,
|
||||
htonl(outdev->br_port->br->dev->ifindex));
|
||||
htonl(br_port_get_rcu(outdev)->br->dev->ifindex));
|
||||
} else {
|
||||
/* Case 2: indev is a bridge group, we need to look
|
||||
* for physical device (when called from ipv4) */
|
||||
|
|
|
@ -296,8 +296,9 @@ nfqnl_build_packet_message(struct nfqnl_instance *queue,
|
|||
NLA_PUT_BE32(skb, NFQA_IFINDEX_PHYSINDEV,
|
||||
htonl(indev->ifindex));
|
||||
/* this is the bridge group "brX" */
|
||||
/* rcu_read_lock()ed by __nf_queue */
|
||||
NLA_PUT_BE32(skb, NFQA_IFINDEX_INDEV,
|
||||
htonl(indev->br_port->br->dev->ifindex));
|
||||
htonl(br_port_get_rcu(indev)->br->dev->ifindex));
|
||||
} else {
|
||||
/* Case 2: indev is bridge group, we need to look for
|
||||
* physical device (when called from ipv4) */
|
||||
|
@ -321,8 +322,9 @@ nfqnl_build_packet_message(struct nfqnl_instance *queue,
|
|||
NLA_PUT_BE32(skb, NFQA_IFINDEX_PHYSOUTDEV,
|
||||
htonl(outdev->ifindex));
|
||||
/* this is the bridge group "brX" */
|
||||
/* rcu_read_lock()ed by __nf_queue */
|
||||
NLA_PUT_BE32(skb, NFQA_IFINDEX_OUTDEV,
|
||||
htonl(outdev->br_port->br->dev->ifindex));
|
||||
htonl(br_port_get_rcu(outdev)->br->dev->ifindex));
|
||||
} else {
|
||||
/* Case 2: outdev is bridge group, we need to look for
|
||||
* physical output device (when called from ipv4) */
|
||||
|
|
|
@ -1107,7 +1107,7 @@ static int nl80211_valid_4addr(struct cfg80211_registered_device *rdev,
|
|||
enum nl80211_iftype iftype)
|
||||
{
|
||||
if (!use_4addr) {
|
||||
if (netdev && netdev->br_port)
|
||||
if (netdev && (netdev->priv_flags & IFF_BRIDGE_PORT))
|
||||
return -EBUSY;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -770,8 +770,8 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev,
|
|||
return -EOPNOTSUPP;
|
||||
|
||||
/* if it's part of a bridge, reject changing type to station/ibss */
|
||||
if (dev->br_port && (ntype == NL80211_IFTYPE_ADHOC ||
|
||||
ntype == NL80211_IFTYPE_STATION))
|
||||
if ((dev->priv_flags & IFF_BRIDGE_PORT) &&
|
||||
(ntype == NL80211_IFTYPE_ADHOC || ntype == NL80211_IFTYPE_STATION))
|
||||
return -EBUSY;
|
||||
|
||||
if (ntype != otype) {
|
||||
|
|
Loading…
Reference in New Issue