net: use rx_handler_data pointer for bridge and macvlan ports
Subsystems (6)
cover net: use rx_handler_data pointer for bridge and macvlan ports
Since recent changes ensured that only one rx_handler can be present at a time, always either macvlan_port or br_port pointer in net_device structure is not used. So introduce rx_handler_data pointer into net_device structure to store this data pointer and safe some space. Also this pointer is right next rx_handler pointer most likely on the same cache line.
Jirka
PATCH 1/3 net: add rx_handler data pointer
Add possibility to register rx_handler data pointer along with a rx_handler.
--- drivers/net/macvlan.c | 2 +- include/linux/netdevice.h | 4 +++- net/bridge/br_if.c | 2 +- net/core/dev.c | 6 +++++- 4 files changed, 10 insertions(+), 4 deletions(-)
drivers/net/macvlan.c +1 -1
@@ -532,7 +532,7 @@ static int macvlan_port_create(struct net_device *dev)INIT_HLIST_HEAD (&port->vlan_hash[i]);rcu_assign_pointer (dev->macvlan_port, port); - err =netdev_rx_handler_register (dev, macvlan_handle_frame); + err =netdev_rx_handler_register (dev, macvlan_handle_frame,NULL );if (err) {rcu_assign_pointer (dev->macvlan_port,NULL );kfree (port);
include/linux/netdevice.h +3 -1
@@ -960,6 +960,7 @@ struct net_device {struct netdev_queue rx_queue;rx_handler_func_t *rx_handler; +void *rx_handler_data;struct netdev_queue *_tx____cacheline_aligned_in_smp ;
@@ -1693,7 +1694,8 @@ static inline void napi_free_frags(struct napi_struct *napi) }extern int netdev_rx_handler_register (struct net_device *dev, -rx_handler_func_t *rx_handler); +rx_handler_func_t *rx_handler, +void *rx_handler_data);extern void netdev_rx_handler_unregister (struct net_device *dev);extern void netif_nit_deliver (struct sk_buff *skb);
net/bridge/br_if.c +1 -1
@@ -431,7 +431,7 @@ int br_add_if(struct net_bridge *br, struct net_device *dev)rcu_assign_pointer (dev->br_port, p); - err =netdev_rx_handler_register (dev, br_handle_frame); + err =netdev_rx_handler_register (dev, br_handle_frame,NULL );if (err) goto err3;
net/core/dev.c +5 -1
@@ -2705,6 +2705,7 @@ void netif_nit_deliver(struct sk_buff *skb)* netdev_rx_handler_register - register receive handler * @dev: device to register a handler for * @rx_handler: receive handler to register +* @rx_handler_data: data pointer that is used by rx handler * * Register a receive hander for a device. This handler will then be * called from __netif_receive_skb. A negative errno code is returned
@@ -2713,13 +2714,15 @@ void netif_nit_deliver(struct sk_buff *skb)* The caller must hold the rtnl_mutex. */ int netdev_rx_handler_register (struct net_device *dev, -rx_handler_func_t *rx_handler) +rx_handler_func_t *rx_handler, +void *rx_handler_data) {ASSERT_RTNL ();if (dev->rx_handler)return -EBUSY ; +rcu_assign_pointer (dev->rx_handler_data, rx_handler_data);rcu_assign_pointer (dev->rx_handler, rx_handler);return 0 ;
@@ -2739,6 +2742,7 @@ void netdev_rx_handler_unregister(struct net_device *dev)ASSERT_RTNL ();rcu_assign_pointer (dev->rx_handler,NULL ); +rcu_assign_pointer (dev->rx_handler_data,NULL ); }EXPORT_SYMBOL_GPL (netdev_rx_handler_unregister);
Signature · 1 line
1.7.0.1
Re: [PATCH net-next-2.6 1/3] net: add rx_handler data pointer
From: Jiri Pirko <[email protected]>
Date: Thu, 10 Jun 2010 15:34:59 +0200
Quoted 3 lines
Add possibility to register
rx_handlerdata pointer along with arx_handler.Signed-off-by Jiri Pirko <[email protected]>
Applied.
PATCH 2/3 macvlan: use rx_handler_data pointer to store macvlan_port pointer
In reply to Jiri PirkoRegister macvlan_port pointer as rx_handler data pointer. As macvlan_port is removed from struct net_device, another netdev priv_flag is added to indicate the device serves as a macvlan port.
--- drivers/net/macvlan.c | 27 +++++++++++++++------------ include/linux/if.h | 1 + include/linux/netdevice.h | 2 -- 3 files changed, 16 insertions(+), 14 deletions(-)
drivers/net/macvlan.c +15 -12
@@ -40,6 +40,10 @@ struct macvlan_port {struct rcu_head rcu; }; +#define macvlan_port_get_rcu (dev) ((struct macvlan_port *) rcu_dereference(dev->rx_handler_data)) +#define macvlan_port_get (dev) ((struct macvlan_port *) dev->rx_handler_data) +#define macvlan_port_exists (dev) (dev->priv_flags & IFF_MACVLAN_PORT) +static struct macvlan_dev *macvlan_hash_lookup (const struct macvlan_port *port,const unsigned char *addr) {
@@ -155,7 +159,7 @@ static struct sk_buff *macvlan_handle_frame(struct sk_buff *skb)struct net_device *dev;unsigned int len; - port =rcu_dereference (skb->dev->macvlan_port); + port =macvlan_port_get_rcu (skb->dev);if (is_multicast_ether_addr (eth->h_dest)) { src =macvlan_hash_lookup (port, eth->h_source);if (!src)
@@ -530,14 +534,12 @@ static int macvlan_port_create(struct net_device *dev)INIT_LIST_HEAD (&port->vlans);for (i =0 ; i <MACVLAN_HASH_SIZE ; i++)INIT_HLIST_HEAD (&port->vlan_hash[i]); -rcu_assign_pointer (dev->macvlan_port, port); - err =netdev_rx_handler_register (dev, macvlan_handle_frame,NULL ); -if (err) { -rcu_assign_pointer (dev->macvlan_port,NULL ); + err =netdev_rx_handler_register (dev, macvlan_handle_frame, port); +if (err)kfree (port); - } + dev->priv_flags |=IFF_MACVLAN_PORT ;return err; }
@@ -551,10 +553,10 @@ static void macvlan_port_rcu_free(struct rcu_head *head)static void macvlan_port_destroy (struct net_device *dev) { -struct macvlan_port *port = dev->macvlan_port; +struct macvlan_port *port =macvlan_port_get (dev); + dev->priv_flags &= ~IFF_MACVLAN_PORT ;netdev_rx_handler_unregister (dev); -rcu_assign_pointer (dev->macvlan_port,NULL );call_rcu (&port->rcu, macvlan_port_rcu_free); }
@@ -633,12 +635,12 @@ int macvlan_common_newlink(struct net *src_net, struct net_device *dev,if (!tb[IFLA_ADDRESS ])random_ether_addr (dev->dev_addr); -if (lowerdev->macvlan_port ==NULL ) { +if (!macvlan_port_exists (lowerdev)) { err =macvlan_port_create (lowerdev);if (err <0 )return err; } - port = lowerdev->macvlan_port; + port =macvlan_port_get (lowerdev); vlan->lowerdev = lowerdev; vlan->dev = dev;
@@ -748,10 +750,11 @@ static int macvlan_device_event(struct notifier_block *unused,struct macvlan_dev *vlan, *next;struct macvlan_port *port; - port = dev->macvlan_port; -if (port ==NULL ) +if (!macvlan_port_exists (dev))return NOTIFY_DONE ; + port =macvlan_port_get (dev); +switch (event) {case NETDEV_CHANGE :list_for_each_entry (vlan, &port->vlans, list)
include/linux/if.h +1 -0
@@ -73,6 +73,7 @@#define IFF_DONT_BRIDGE 0x800/* disallow bridging this ether dev */ #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 IF_GET_IFACE 0x0001/* for querying only */ #define IF_GET_PROTO 0x0002
include/linux/netdevice.h +0 -2
@@ -1030,8 +1030,6 @@ struct net_device {/* bridge stuff */ struct net_bridge_port *br_port; -/* macvlan */ -struct macvlan_port *macvlan_port;/* GARP */ struct garp_port *garp_port;
Signature · 1 line
1.7.0.1
Re: [PATCH net-next-2.6 2/3] macvlan: use rx_handler_data pointer to store macvlan_port pointer
Quoted 3 lines · Jiri Pirko
Register
macvlan_portpointer asrx_handlerdata pointer. Asmacvlan_portis removed from structnet_device, another netdevpriv_flagis added to indicate the device serves as a macvlan port.
Looks fine to me.
PATCH 2/3 macvlan: use rx_handler_data pointer to store macvlan_port pointer V2
In reply to Jiri PirkoRegister macvlan_port pointer as rx_handler data pointer. As macvlan_port is removed from struct net_device, another netdev priv_flag is added to indicate the device serves as a macvlan port.
---v1->v2:
- coding style corrections
drivers/net/macvlan.c | 28 ++++++++++++++++------------ include/linux/if.h | 1 + include/linux/netdevice.h | 2 -- 3 files changed, 17 insertions(+), 14 deletions(-)
drivers/net/macvlan.c +16 -12
@@ -40,6 +40,11 @@ struct macvlan_port {struct rcu_head rcu; }; +#define macvlan_port_get_rcu (dev) \ + ((struct macvlan_port *) rcu_dereference(dev->rx_handler_data)) +#define macvlan_port_get (dev) ((struct macvlan_port *) dev->rx_handler_data) +#define macvlan_port_exists (dev) (dev->priv_flags & IFF_MACVLAN_PORT) +static struct macvlan_dev *macvlan_hash_lookup (const struct macvlan_port *port,const unsigned char *addr) {
@@ -155,7 +160,7 @@ static struct sk_buff *macvlan_handle_frame(struct sk_buff *skb)struct net_device *dev;unsigned int len; - port =rcu_dereference (skb->dev->macvlan_port); + port =macvlan_port_get_rcu (skb->dev);if (is_multicast_ether_addr (eth->h_dest)) { src =macvlan_hash_lookup (port, eth->h_source);if (!src)
@@ -530,14 +535,12 @@ static int macvlan_port_create(struct net_device *dev)INIT_LIST_HEAD (&port->vlans);for (i =0 ; i <MACVLAN_HASH_SIZE ; i++)INIT_HLIST_HEAD (&port->vlan_hash[i]); -rcu_assign_pointer (dev->macvlan_port, port); - err =netdev_rx_handler_register (dev, macvlan_handle_frame,NULL ); -if (err) { -rcu_assign_pointer (dev->macvlan_port,NULL ); + err =netdev_rx_handler_register (dev, macvlan_handle_frame, port); +if (err)kfree (port); - } + dev->priv_flags |=IFF_MACVLAN_PORT ;return err; }
@@ -551,10 +554,10 @@ static void macvlan_port_rcu_free(struct rcu_head *head)static void macvlan_port_destroy (struct net_device *dev) { -struct macvlan_port *port = dev->macvlan_port; +struct macvlan_port *port =macvlan_port_get (dev); + dev->priv_flags &= ~IFF_MACVLAN_PORT ;netdev_rx_handler_unregister (dev); -rcu_assign_pointer (dev->macvlan_port,NULL );call_rcu (&port->rcu, macvlan_port_rcu_free); }
@@ -633,12 +636,12 @@ int macvlan_common_newlink(struct net *src_net, struct net_device *dev,if (!tb[IFLA_ADDRESS ])random_ether_addr (dev->dev_addr); -if (lowerdev->macvlan_port ==NULL ) { +if (!macvlan_port_exists (lowerdev)) { err =macvlan_port_create (lowerdev);if (err <0 )return err; } - port = lowerdev->macvlan_port; + port =macvlan_port_get (lowerdev); vlan->lowerdev = lowerdev; vlan->dev = dev;
@@ -748,10 +751,11 @@ static int macvlan_device_event(struct notifier_block *unused,struct macvlan_dev *vlan, *next;struct macvlan_port *port; - port = dev->macvlan_port; -if (port ==NULL ) +if (!macvlan_port_exists (dev))return NOTIFY_DONE ; + port =macvlan_port_get (dev); +switch (event) {case NETDEV_CHANGE :list_for_each_entry (vlan, &port->vlans, list)
include/linux/if.h +1 -0
@@ -73,6 +73,7 @@#define IFF_DONT_BRIDGE 0x800/* disallow bridging this ether dev */ #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 IF_GET_IFACE 0x0001/* for querying only */ #define IF_GET_PROTO 0x0002
include/linux/netdevice.h +0 -2
@@ -1047,8 +1047,6 @@ struct net_device {/* bridge stuff */ struct net_bridge_port *br_port; -/* macvlan */ -struct macvlan_port *macvlan_port;/* GARP */ struct garp_port *garp_port;
Signature · 1 line
1.7.0.1
Re: [PATCH net-next-2.6 2/3] macvlan: use rx_handler_data pointer to store macvlan_port pointer V2
From: Jiri Pirko <[email protected]>
Date: Tue, 15 Jun 2010 15:27:57 +0200
Quoted 6 lines
Register
macvlan_portpointer asrx_handlerdata pointer. Asmacvlan_portis removed from structnet_device, another netdevpriv_flagis added to indicate the device serves as a macvlan port.Signed-off-by Jiri Pirko <[email protected]>Acked-by Patrick McHardy <[email protected]>
Applied.
PATCH 3/3 bridge: use rx_handler_data pointer to store net_bridge_port pointer
In reply to Jiri PirkoRegister 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.
--- drivers/net/ksz884x.c | 2 +- drivers/staging/batman-adv/hard-interface.c | 2 +- include/linux/if.h | 1 + include/linux/netdevice.h | 2 -- net/bridge/br_fdb.c | 4 ++-- net/bridge/br_if.c | 23 +++++++++++++---------- net/bridge/br_input.c | 9 ++++----- net/bridge/br_netfilter.c | 11 ++++++----- net/bridge/br_netlink.c | 9 +++++---- net/bridge/br_notify.c | 5 +++-- net/bridge/br_private.h | 4 ++++ net/bridge/br_stp_bpdu.c | 5 +++-- net/bridge/netfilter/ebt_redirect.c | 3 ++- net/bridge/netfilter/ebt_ulog.c | 8 +++++--- net/bridge/netfilter/ebtables.c | 11 +++++++---- net/core/dev.c | 3 ++- net/netfilter/nfnetlink_log.c | 6 ++++-- net/netfilter/nfnetlink_queue.c | 6 ++++-- net/wireless/nl80211.c | 2 +- net/wireless/util.c | 4 ++-- 20 files changed, 70 insertions(+), 50 deletions(-)
drivers/net/ksz884x.c +1 -1
@@ -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;
drivers/staging/batman-adv/hard-interface.c +1 -1
@@ -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 ;
include/linux/if.h +1 -0
@@ -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
include/linux/netdevice.h +0 -2
@@ -1028,8 +1028,6 @@ struct net_device {/* mid-layer private */ void *ml_priv; -/* bridge stuff */ -struct net_bridge_port *br_port;/* GARP */ struct garp_port *garp_port;
net/bridge/br_fdb.c +2 -2
@@ -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 ();
net/bridge/br_if.c +13 -10
@@ -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);
@@ -401,7 +402,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) */
@@ -429,11 +430,11 @@ int br_add_if(struct net_bridge *br, struct net_device *dev)if (err) goto err2; -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 err3; + goto err2; + + 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)br_netpoll_enable (br, dev);return 0 ; -err3: -rcu_assign_pointer (dev->br_port,NULL ); err2:br_fdb_delete_by_port (br, p,1 ); err1:
@@ -475,9 +474,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 (!br_port_exists (dev)) +return -EINVAL ; -if (!p || p->br != br) + p =br_port_get (dev); +if (p->br != br)return -EINVAL ;del_nbp (p);
net/bridge/br_input.c +4 -5
@@ -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 */
net/bridge/br_netfilter.c +6 -5
@@ -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)
net/bridge/br_netlink.c +5 -4
@@ -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 )
net/bridge/br_notify.c +3 -2
@@ -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) {
net/bridge/br_private.h +4 -0
@@ -145,6 +145,10 @@ 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;
net/bridge/br_stp_bpdu.c +3 -2
@@ -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;
net/bridge/netfilter/ebt_redirect.c +2 -1
@@ -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 ;
net/bridge/netfilter/ebt_ulog.c +5 -3
@@ -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' ;
net/bridge/netfilter/ebtables.c +7 -4
@@ -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 ) {
net/core/dev.c +2 -1
@@ -2767,7 +2767,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.
net/netfilter/nfnetlink_log.c +4 -2
@@ -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) */
net/netfilter/nfnetlink_queue.c +4 -2
@@ -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) */
net/wireless/nl80211.c +1 -1
@@ -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 ; }
net/wireless/util.c +2 -2
@@ -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) {
Signature · 1 line
1.7.0.1
PATCH 3/3 bridge: use rx_handler_data pointer to store net_bridge_port pointer V2
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.
---v1->v2:
coding style corrections
drivers/net/ksz884x.c | 2 +- drivers/staging/batman-adv/hard-interface.c | 2 +- include/linux/if.h | 1 + include/linux/netdevice.h | 2 -- net/bridge/br_fdb.c | 4 ++-- net/bridge/br_if.c | 23 +++++++++++++---------- net/bridge/br_input.c | 9 ++++----- net/bridge/br_netfilter.c | 11 ++++++----- net/bridge/br_netlink.c | 9 +++++---- net/bridge/br_notify.c | 5 +++-- net/bridge/br_private.h | 5 +++++ net/bridge/br_stp_bpdu.c | 5 +++-- net/bridge/netfilter/ebt_redirect.c | 3 ++- net/bridge/netfilter/ebt_ulog.c | 8 +++++--- net/bridge/netfilter/ebtables.c | 11 +++++++---- net/core/dev.c | 3 ++- net/netfilter/nfnetlink_log.c | 6 ++++-- net/netfilter/nfnetlink_queue.c | 6 ++++-- net/wireless/nl80211.c | 2 +- net/wireless/util.c | 4 ++-- 20 files changed, 71 insertions(+), 50 deletions(-)
drivers/net/ksz884x.c +1 -1
@@ -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;
drivers/staging/batman-adv/hard-interface.c +1 -1
@@ -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 ;
include/linux/if.h +1 -0
@@ -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
include/linux/netdevice.h +0 -2
@@ -1045,8 +1045,6 @@ struct net_device {/* mid-layer private */ void *ml_priv; -/* bridge stuff */ -struct net_bridge_port *br_port;/* GARP */ struct garp_port *garp_port;
net/bridge/br_fdb.c +2 -2
@@ -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 ();
net/bridge/br_if.c +13 -10
@@ -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);
@@ -401,7 +402,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) */
@@ -429,11 +430,11 @@ int br_add_if(struct net_bridge *br, struct net_device *dev)if (err) goto err2; -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 err3; + goto err2; + + 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)br_netpoll_enable (br, dev);return 0 ; -err3: -rcu_assign_pointer (dev->br_port,NULL ); err2:br_fdb_delete_by_port (br, p,1 ); err1:
@@ -475,9 +474,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 (!br_port_exists (dev)) +return -EINVAL ; -if (!p || p->br != br) + p =br_port_get (dev); +if (p->br != br)return -EINVAL ;del_nbp (p);
net/bridge/br_input.c +4 -5
@@ -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 */
net/bridge/br_netfilter.c +6 -5
@@ -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)
net/bridge/br_netlink.c +5 -4
@@ -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 )
net/bridge/br_notify.c +3 -2
@@ -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) {
net/bridge/br_private.h +5 -0
@@ -145,6 +145,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;
net/bridge/br_stp_bpdu.c +3 -2
@@ -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;
net/bridge/netfilter/ebt_redirect.c +2 -1
@@ -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 ;
net/bridge/netfilter/ebt_ulog.c +5 -3
@@ -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' ;
net/bridge/netfilter/ebtables.c +7 -4
@@ -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 ) {
net/core/dev.c +2 -1
@@ -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.
net/netfilter/nfnetlink_log.c +4 -2
@@ -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) */
net/netfilter/nfnetlink_queue.c +4 -2
@@ -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) */
net/wireless/nl80211.c +1 -1
@@ -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 ; }
net/wireless/util.c +2 -2
@@ -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) {
Signature · 1 line
1.7.0.1
Re: [PATCH net-next-2.6 3/3] bridge: use rx_handler_data pointer to store net_bridge_port pointer V2
drivers/net/ksz884x.c static void dev_set_promiscuous(struct net_device *dev, struct dev_priv *priv, · line 5721
Quoted 10 lines · On Tue, 15 Jun 2010 15:28:34 +0200 Jiri Pirko <[email protected]> wrote:
drivers/net/ksz884x.c +1
-1@@ -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 ) {
I like this patch except for one thing. The mask here should be surrounded by paren's to avoid the possible confusion about && and & in same if statement. The C precedence rules allow this but humans get confused.
Re: [PATCH net-next-2.6 3/3] bridge: use rx_handler_data pointer to store net_bridge_port pointer V2
Quoted 17 lines · Tue, Jun 15, 2010 at 06:30:35PM CEST, [email protected] wrote:
drivers/net/ksz884x.c static void dev_set_promiscuous(struct net_device *dev, struct dev_priv *priv, · line 5721
Quoted 10 lines · On Tue, 15 Jun 2010 15:28:34 +0200 Jiri Pirko <[email protected]> wrote:
drivers/net/ksz884x.c +1
-1@@ -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 ) {I like this patch except for one thing. The mask here should be surrounded by paren's to avoid the possible confusion about && and & in same if statement. The C precedence rules allow this but humans get confused.
Right, reposted.
Thanks for review
PATCH v3 3/3 bridge: use rx_handler_data pointer to store net_bridge_port pointer
In reply to Jiri PirkoRegister 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.
---v2->v3:
added () around & in ksz884x.cv1->v2:
coding style corrections
drivers/net/ksz884x.c | 2 +- drivers/staging/batman-adv/hard-interface.c | 2 +- include/linux/if.h | 1 + include/linux/netdevice.h | 2 -- net/bridge/br_fdb.c | 4 ++-- net/bridge/br_if.c | 23 +++++++++++++---------- net/bridge/br_input.c | 9 ++++----- net/bridge/br_netfilter.c | 11 ++++++----- net/bridge/br_netlink.c | 9 +++++---- net/bridge/br_notify.c | 5 +++-- net/bridge/br_private.h | 5 +++++ net/bridge/br_stp_bpdu.c | 5 +++-- net/bridge/netfilter/ebt_redirect.c | 3 ++- net/bridge/netfilter/ebt_ulog.c | 8 +++++--- net/bridge/netfilter/ebtables.c | 11 +++++++---- net/core/dev.c | 3 ++- net/netfilter/nfnetlink_log.c | 6 ++++-- net/netfilter/nfnetlink_queue.c | 6 ++++-- net/wireless/nl80211.c | 2 +- net/wireless/util.c | 4 ++-- 20 files changed, 71 insertions(+), 50 deletions(-)
drivers/net/ksz884x.c +1 -1
@@ -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;
drivers/staging/batman-adv/hard-interface.c +1 -1
@@ -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 ;
include/linux/if.h +1 -0
@@ -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
include/linux/netdevice.h +0 -2
@@ -1045,8 +1045,6 @@ struct net_device {/* mid-layer private */ void *ml_priv; -/* bridge stuff */ -struct net_bridge_port *br_port;/* GARP */ struct garp_port *garp_port;
net/bridge/br_fdb.c +2 -2
@@ -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 ();
net/bridge/br_if.c +13 -10
@@ -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);
@@ -401,7 +402,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) */
@@ -429,11 +430,11 @@ int br_add_if(struct net_bridge *br, struct net_device *dev)if (err) goto err2; -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 err3; + goto err2; + + 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)br_netpoll_enable (br, dev);return 0 ; -err3: -rcu_assign_pointer (dev->br_port,NULL ); err2:br_fdb_delete_by_port (br, p,1 ); err1:
@@ -475,9 +474,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 (!br_port_exists (dev)) +return -EINVAL ; -if (!p || p->br != br) + p =br_port_get (dev); +if (p->br != br)return -EINVAL ;del_nbp (p);
net/bridge/br_input.c +4 -5
@@ -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 */
net/bridge/br_netfilter.c +6 -5
@@ -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)
net/bridge/br_netlink.c +5 -4
@@ -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 )
net/bridge/br_notify.c +3 -2
@@ -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) {
net/bridge/br_private.h +5 -0
@@ -145,6 +145,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;
net/bridge/br_stp_bpdu.c +3 -2
@@ -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;
net/bridge/netfilter/ebt_redirect.c +2 -1
@@ -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 ;
net/bridge/netfilter/ebt_ulog.c +5 -3
@@ -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' ;
net/bridge/netfilter/ebtables.c +7 -4
@@ -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 ) {
net/core/dev.c +2 -1
@@ -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.
net/netfilter/nfnetlink_log.c +4 -2
@@ -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) */
net/netfilter/nfnetlink_queue.c +4 -2
@@ -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) */
net/wireless/nl80211.c +1 -1
@@ -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 ; }
net/wireless/util.c +2 -2
@@ -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) {
Signature · 1 line
1.7.0.1
Re: [PATCH net-next-2.6 3/3 v3] bridge: use rx_handler_data pointer to store net_bridge_port pointer
From: Jiri Pirko <[email protected]>
Date: Tue, 15 Jun 2010 18:50:45 +0200
Quoted 6 lines
Register
net_bridge_portpointer asrx_handlerdata pointer. Asbr_portis removed from structnet_device, another netdevpriv_flagis added to indicate the device serves as a bridge port. Also rcuized pointers are now correctly dereferenced inbr_fdb.cand in netfilter parts.Signed-off-by Jiri Pirko <[email protected]>
Applied.