* [PATCH net-next-2.6 0/3] net: use rx_handler_data pointer for bridge and macvlan ports @ 2010-06-10 13:34 Jiri Pirko 2010-06-10 13:34 ` [PATCH net-next-2.6 1/3] net: add rx_handler data pointer Jiri Pirko ` (2 more replies) 0 siblings, 3 replies; 13+ messages in thread From: Jiri Pirko @ 2010-06-10 13:34 UTC (permalink / raw) To: netdev; +Cc: davem, shemminger, kaber, eric.dumazet 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 ^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH net-next-2.6 1/3] net: add rx_handler data pointer 2010-06-10 13:34 [PATCH net-next-2.6 0/3] net: use rx_handler_data pointer for bridge and macvlan ports Jiri Pirko @ 2010-06-10 13:34 ` Jiri Pirko 2010-06-15 18:49 ` David Miller 2010-06-10 13:35 ` [PATCH net-next-2.6 2/3] macvlan: use rx_handler_data pointer to store macvlan_port pointer Jiri Pirko 2010-06-10 13:36 ` [PATCH net-next-2.6 3/3] bridge: use rx_handler_data pointer to store net_bridge_port pointer Jiri Pirko 2 siblings, 1 reply; 13+ messages in thread From: Jiri Pirko @ 2010-06-10 13:34 UTC (permalink / raw) To: netdev; +Cc: davem, shemminger, kaber, eric.dumazet Add possibility to register rx_handler data pointer along with a rx_handler. Signed-off-by: Jiri Pirko <jpirko@redhat.com> --- 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(-) diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index 59c3155..87a3bf6 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -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); diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index c319f28..32cc219 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -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); diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c index d924234..90ac003 100644 --- a/net/bridge/br_if.c +++ b/net/bridge/br_if.c @@ -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; diff --git a/net/core/dev.c b/net/core/dev.c index 6f330ce..c49dda0 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -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); -- 1.7.0.1 ^ permalink raw reply related [flat|nested] 13+ messages in thread
* Re: [PATCH net-next-2.6 1/3] net: add rx_handler data pointer 2010-06-10 13:34 ` [PATCH net-next-2.6 1/3] net: add rx_handler data pointer Jiri Pirko @ 2010-06-15 18:49 ` David Miller 0 siblings, 0 replies; 13+ messages in thread From: David Miller @ 2010-06-15 18:49 UTC (permalink / raw) To: jpirko; +Cc: netdev, shemminger, kaber, eric.dumazet From: Jiri Pirko <jpirko@redhat.com> Date: Thu, 10 Jun 2010 15:34:59 +0200 > Add possibility to register rx_handler data pointer along with a rx_handler. > > Signed-off-by: Jiri Pirko <jpirko@redhat.com> Applied. ^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH net-next-2.6 2/3] macvlan: use rx_handler_data pointer to store macvlan_port pointer 2010-06-10 13:34 [PATCH net-next-2.6 0/3] net: use rx_handler_data pointer for bridge and macvlan ports Jiri Pirko 2010-06-10 13:34 ` [PATCH net-next-2.6 1/3] net: add rx_handler data pointer Jiri Pirko @ 2010-06-10 13:35 ` Jiri Pirko 2010-06-15 12:48 ` Patrick McHardy 2010-06-15 13:27 ` [PATCH net-next-2.6 2/3] macvlan: use rx_handler_data pointer to store macvlan_port pointer V2 Jiri Pirko 2010-06-10 13:36 ` [PATCH net-next-2.6 3/3] bridge: use rx_handler_data pointer to store net_bridge_port pointer Jiri Pirko 2 siblings, 2 replies; 13+ messages in thread From: Jiri Pirko @ 2010-06-10 13:35 UTC (permalink / raw) To: netdev; +Cc: davem, shemminger, kaber, eric.dumazet Register 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. Signed-off-by: Jiri Pirko <jpirko@redhat.com> --- drivers/net/macvlan.c | 27 +++++++++++++++------------ include/linux/if.h | 1 + include/linux/netdevice.h | 2 -- 3 files changed, 16 insertions(+), 14 deletions(-) diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index 87a3bf6..dec3e8f 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -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) diff --git a/include/linux/if.h b/include/linux/if.h index be350e6..31f2e27 100644 --- a/include/linux/if.h +++ b/include/linux/if.h @@ -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 diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 32cc219..37faf51 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -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; -- 1.7.0.1 ^ permalink raw reply related [flat|nested] 13+ messages in thread
* Re: [PATCH net-next-2.6 2/3] macvlan: use rx_handler_data pointer to store macvlan_port pointer 2010-06-10 13:35 ` [PATCH net-next-2.6 2/3] macvlan: use rx_handler_data pointer to store macvlan_port pointer Jiri Pirko @ 2010-06-15 12:48 ` Patrick McHardy 2010-06-15 13:27 ` [PATCH net-next-2.6 2/3] macvlan: use rx_handler_data pointer to store macvlan_port pointer V2 Jiri Pirko 1 sibling, 0 replies; 13+ messages in thread From: Patrick McHardy @ 2010-06-15 12:48 UTC (permalink / raw) To: Jiri Pirko; +Cc: netdev, davem, shemminger, eric.dumazet Jiri Pirko wrote: > Register 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. Looks fine to me. Acked-by: Patrick McHardy <kaber@trash.net> ^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH net-next-2.6 2/3] macvlan: use rx_handler_data pointer to store macvlan_port pointer V2 2010-06-10 13:35 ` [PATCH net-next-2.6 2/3] macvlan: use rx_handler_data pointer to store macvlan_port pointer Jiri Pirko 2010-06-15 12:48 ` Patrick McHardy @ 2010-06-15 13:27 ` Jiri Pirko 2010-06-15 18:50 ` David Miller 1 sibling, 1 reply; 13+ messages in thread From: Jiri Pirko @ 2010-06-15 13:27 UTC (permalink / raw) To: netdev; +Cc: davem, shemminger, kaber, eric.dumazet Register 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. Signed-off-by: Jiri Pirko <jpirko@redhat.com> Acked-by: Patrick McHardy <kaber@trash.net> --- 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(-) diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index 87a3bf6..e096875 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -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) diff --git a/include/linux/if.h b/include/linux/if.h index be350e6..31f2e27 100644 --- a/include/linux/if.h +++ b/include/linux/if.h @@ -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 diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index cb2c4e7..d8d00fa 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -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; -- 1.7.0.1 ^ permalink raw reply related [flat|nested] 13+ messages in thread
* Re: [PATCH net-next-2.6 2/3] macvlan: use rx_handler_data pointer to store macvlan_port pointer V2 2010-06-15 13:27 ` [PATCH net-next-2.6 2/3] macvlan: use rx_handler_data pointer to store macvlan_port pointer V2 Jiri Pirko @ 2010-06-15 18:50 ` David Miller 0 siblings, 0 replies; 13+ messages in thread From: David Miller @ 2010-06-15 18:50 UTC (permalink / raw) To: jpirko; +Cc: netdev, shemminger, kaber, eric.dumazet From: Jiri Pirko <jpirko@redhat.com> Date: Tue, 15 Jun 2010 15:27:57 +0200 > Register 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. > > Signed-off-by: Jiri Pirko <jpirko@redhat.com> > Acked-by: Patrick McHardy <kaber@trash.net> Applied. ^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH net-next-2.6 3/3] bridge: use rx_handler_data pointer to store net_bridge_port pointer 2010-06-10 13:34 [PATCH net-next-2.6 0/3] net: use rx_handler_data pointer for bridge and macvlan ports Jiri Pirko 2010-06-10 13:34 ` [PATCH net-next-2.6 1/3] net: add rx_handler data pointer Jiri Pirko 2010-06-10 13:35 ` [PATCH net-next-2.6 2/3] macvlan: use rx_handler_data pointer to store macvlan_port pointer Jiri Pirko @ 2010-06-10 13:36 ` Jiri Pirko 2010-06-15 13:28 ` [PATCH net-next-2.6 3/3] bridge: use rx_handler_data pointer to store net_bridge_port pointer V2 Jiri Pirko 2 siblings, 1 reply; 13+ messages in thread From: Jiri Pirko @ 2010-06-10 13:36 UTC (permalink / raw) To: netdev; +Cc: davem, shemminger, kaber, eric.dumazet 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> --- 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(-) diff --git a/drivers/net/ksz884x.c b/drivers/net/ksz884x.c index 7805bbf..b0c876d 100644 --- a/drivers/net/ksz884x.c +++ b/drivers/net/ksz884x.c @@ -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; diff --git a/drivers/staging/batman-adv/hard-interface.c b/drivers/staging/batman-adv/hard-interface.c index 7a582e8..5ede9c2 100644 --- a/drivers/staging/batman-adv/hard-interface.c +++ b/drivers/staging/batman-adv/hard-interface.c @@ -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; diff --git a/include/linux/if.h b/include/linux/if.h index 31f2e27..53558ec 100644 --- a/include/linux/if.h +++ b/include/linux/if.h @@ -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 diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 37faf51..f4e1f75 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -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; diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c index 2663743..6818e60 100644 --- a/net/bridge/br_fdb.c +++ b/net/bridge/br_fdb.c @@ -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(); diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c index 90ac003..099495e 100644 --- a/net/bridge/br_if.c +++ b/net/bridge/br_if.c @@ -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); diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c index 99647d8..f076c9d 100644 --- a/net/bridge/br_input.c +++ b/net/bridge/br_input.c @@ -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 */ diff --git a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c index 4442099..7d7af6e 100644 --- a/net/bridge/br_netfilter.c +++ b/net/bridge/br_netfilter.c @@ -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) diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c index fe0a790..4a6a378 100644 --- a/net/bridge/br_netlink.c +++ b/net/bridge/br_netlink.c @@ -120,10 +120,11 @@ static int br_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb) 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) diff --git a/net/bridge/br_notify.c b/net/bridge/br_notify.c index 717e1fd..404d4e1 100644 --- a/net/bridge/br_notify.c +++ b/net/bridge/br_notify.c @@ -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) { diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h index c83519b..94f41b7 100644 --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h @@ -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; diff --git a/net/bridge/br_stp_bpdu.c b/net/bridge/br_stp_bpdu.c index 217bd22..70aecb4 100644 --- a/net/bridge/br_stp_bpdu.c +++ b/net/bridge/br_stp_bpdu.c @@ -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; diff --git a/net/bridge/netfilter/ebt_redirect.c b/net/bridge/netfilter/ebt_redirect.c index 9e19166..46624bb 100644 --- a/net/bridge/netfilter/ebt_redirect.c +++ b/net/bridge/netfilter/ebt_redirect.c @@ -24,8 +24,9 @@ ebt_redirect_tg(struct sk_buff *skb, const struct xt_action_param *par) 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; diff --git a/net/bridge/netfilter/ebt_ulog.c b/net/bridge/netfilter/ebt_ulog.c index ae3c7ce..26377e9 100644 --- a/net/bridge/netfilter/ebt_ulog.c +++ b/net/bridge/netfilter/ebt_ulog.c @@ -177,8 +177,9 @@ static void ebt_ulog_packet(unsigned int hooknr, const struct sk_buff *skb, 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'; diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c index 59ca00e..bcc102e 100644 --- a/net/bridge/netfilter/ebtables.c +++ b/net/bridge/netfilter/ebtables.c @@ -140,11 +140,14 @@ ebt_basic_match(const struct ebt_entry *e, const struct ethhdr *h, 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) { diff --git a/net/core/dev.c b/net/core/dev.c index c49dda0..cf95489 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -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. diff --git a/net/netfilter/nfnetlink_log.c b/net/netfilter/nfnetlink_log.c index fc9a211..e0504e9 100644 --- a/net/netfilter/nfnetlink_log.c +++ b/net/netfilter/nfnetlink_log.c @@ -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) */ diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c index 12e1ab3..cc3ae86 100644 --- a/net/netfilter/nfnetlink_queue.c +++ b/net/netfilter/nfnetlink_queue.c @@ -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) */ diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index db71150..9ee021f 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -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; } diff --git a/net/wireless/util.c b/net/wireless/util.c index 3416373..0c8a1e8 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c @@ -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) { -- 1.7.0.1 ^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH net-next-2.6 3/3] bridge: use rx_handler_data pointer to store net_bridge_port pointer V2 2010-06-10 13:36 ` [PATCH net-next-2.6 3/3] bridge: use rx_handler_data pointer to store net_bridge_port pointer Jiri Pirko @ 2010-06-15 13:28 ` Jiri Pirko 2010-06-15 16:30 ` Stephen Hemminger 2010-06-15 16:50 ` [PATCH net-next-2.6 3/3 v3] bridge: use rx_handler_data pointer to store net_bridge_port pointer Jiri Pirko 0 siblings, 2 replies; 13+ messages in thread From: Jiri Pirko @ 2010-06-15 13:28 UTC (permalink / raw) To: netdev; +Cc: davem, shemminger, kaber, eric.dumazet 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> --- 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(-) diff --git a/drivers/net/ksz884x.c b/drivers/net/ksz884x.c index 7805bbf..e7f4703 100644 --- a/drivers/net/ksz884x.c +++ b/drivers/net/ksz884x.c @@ -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; diff --git a/drivers/staging/batman-adv/hard-interface.c b/drivers/staging/batman-adv/hard-interface.c index 7a582e8..5ede9c2 100644 --- a/drivers/staging/batman-adv/hard-interface.c +++ b/drivers/staging/batman-adv/hard-interface.c @@ -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; diff --git a/include/linux/if.h b/include/linux/if.h index 31f2e27..53558ec 100644 --- a/include/linux/if.h +++ b/include/linux/if.h @@ -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 diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index d8d00fa..727404d 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -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; diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c index 2663743..6818e60 100644 --- a/net/bridge/br_fdb.c +++ b/net/bridge/br_fdb.c @@ -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(); diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c index 90ac003..099495e 100644 --- a/net/bridge/br_if.c +++ b/net/bridge/br_if.c @@ -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); diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c index 99647d8..f076c9d 100644 --- a/net/bridge/br_input.c +++ b/net/bridge/br_input.c @@ -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 */ diff --git a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c index 0685b25..f54404d 100644 --- a/net/bridge/br_netfilter.c +++ b/net/bridge/br_netfilter.c @@ -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) diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c index fe0a790..4a6a378 100644 --- a/net/bridge/br_netlink.c +++ b/net/bridge/br_netlink.c @@ -120,10 +120,11 @@ static int br_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb) 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) diff --git a/net/bridge/br_notify.c b/net/bridge/br_notify.c index 717e1fd..404d4e1 100644 --- a/net/bridge/br_notify.c +++ b/net/bridge/br_notify.c @@ -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) { diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h index c83519b..5837052 100644 --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h @@ -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; diff --git a/net/bridge/br_stp_bpdu.c b/net/bridge/br_stp_bpdu.c index 217bd22..70aecb4 100644 --- a/net/bridge/br_stp_bpdu.c +++ b/net/bridge/br_stp_bpdu.c @@ -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; diff --git a/net/bridge/netfilter/ebt_redirect.c b/net/bridge/netfilter/ebt_redirect.c index 9e19166..46624bb 100644 --- a/net/bridge/netfilter/ebt_redirect.c +++ b/net/bridge/netfilter/ebt_redirect.c @@ -24,8 +24,9 @@ ebt_redirect_tg(struct sk_buff *skb, const struct xt_action_param *par) 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; diff --git a/net/bridge/netfilter/ebt_ulog.c b/net/bridge/netfilter/ebt_ulog.c index ae3c7ce..26377e9 100644 --- a/net/bridge/netfilter/ebt_ulog.c +++ b/net/bridge/netfilter/ebt_ulog.c @@ -177,8 +177,9 @@ static void ebt_ulog_packet(unsigned int hooknr, const struct sk_buff *skb, 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'; diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c index 59ca00e..bcc102e 100644 --- a/net/bridge/netfilter/ebtables.c +++ b/net/bridge/netfilter/ebtables.c @@ -140,11 +140,14 @@ ebt_basic_match(const struct ebt_entry *e, const struct ethhdr *h, 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) { diff --git a/net/core/dev.c b/net/core/dev.c index abdb19e..5902426 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -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. diff --git a/net/netfilter/nfnetlink_log.c b/net/netfilter/nfnetlink_log.c index fc9a211..e0504e9 100644 --- a/net/netfilter/nfnetlink_log.c +++ b/net/netfilter/nfnetlink_log.c @@ -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) */ diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c index 12e1ab3..cc3ae86 100644 --- a/net/netfilter/nfnetlink_queue.c +++ b/net/netfilter/nfnetlink_queue.c @@ -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) */ diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 90ab3c8..3a7b8a2 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -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; } diff --git a/net/wireless/util.c b/net/wireless/util.c index 3416373..0c8a1e8 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c @@ -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) { -- 1.7.0.1 ^ permalink raw reply related [flat|nested] 13+ messages in thread
* Re: [PATCH net-next-2.6 3/3] bridge: use rx_handler_data pointer to store net_bridge_port pointer V2 2010-06-15 13:28 ` [PATCH net-next-2.6 3/3] bridge: use rx_handler_data pointer to store net_bridge_port pointer V2 Jiri Pirko @ 2010-06-15 16:30 ` Stephen Hemminger 2010-06-15 16:51 ` Jiri Pirko 2010-06-15 16:50 ` [PATCH net-next-2.6 3/3 v3] bridge: use rx_handler_data pointer to store net_bridge_port pointer Jiri Pirko 1 sibling, 1 reply; 13+ messages in thread From: Stephen Hemminger @ 2010-06-15 16:30 UTC (permalink / raw) To: Jiri Pirko; +Cc: netdev, davem, kaber, eric.dumazet On Tue, 15 Jun 2010 15:28:34 +0200 Jiri Pirko <jpirko@redhat.com> wrote: > diff --git a/drivers/net/ksz884x.c b/drivers/net/ksz884x.c > index 7805bbf..e7f4703 100644 > --- a/drivers/net/ksz884x.c > +++ b/drivers/net/ksz884x.c > @@ -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. ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH net-next-2.6 3/3] bridge: use rx_handler_data pointer to store net_bridge_port pointer V2 2010-06-15 16:30 ` Stephen Hemminger @ 2010-06-15 16:51 ` Jiri Pirko 0 siblings, 0 replies; 13+ messages in thread From: Jiri Pirko @ 2010-06-15 16:51 UTC (permalink / raw) To: Stephen Hemminger; +Cc: netdev, davem, kaber, eric.dumazet Tue, Jun 15, 2010 at 06:30:35PM CEST, shemminger@vyatta.com wrote: >On Tue, 15 Jun 2010 15:28:34 +0200 >Jiri Pirko <jpirko@redhat.com> wrote: > >> diff --git a/drivers/net/ksz884x.c b/drivers/net/ksz884x.c >> index 7805bbf..e7f4703 100644 >> --- a/drivers/net/ksz884x.c >> +++ b/drivers/net/ksz884x.c >> @@ -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 ^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH net-next-2.6 3/3 v3] bridge: use rx_handler_data pointer to store net_bridge_port pointer 2010-06-15 13:28 ` [PATCH net-next-2.6 3/3] bridge: use rx_handler_data pointer to store net_bridge_port pointer V2 Jiri Pirko 2010-06-15 16:30 ` Stephen Hemminger @ 2010-06-15 16:50 ` Jiri Pirko 2010-06-15 18:50 ` David Miller 1 sibling, 1 reply; 13+ messages in thread From: Jiri Pirko @ 2010-06-15 16:50 UTC (permalink / raw) To: netdev; +Cc: davem, shemminger, kaber, eric.dumazet 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> --- v2->v3: added () around & in ksz884x.c 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(-) diff --git a/drivers/net/ksz884x.c b/drivers/net/ksz884x.c index 7805bbf..62362b4 100644 --- a/drivers/net/ksz884x.c +++ b/drivers/net/ksz884x.c @@ -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; diff --git a/drivers/staging/batman-adv/hard-interface.c b/drivers/staging/batman-adv/hard-interface.c index 7a582e8..5ede9c2 100644 --- a/drivers/staging/batman-adv/hard-interface.c +++ b/drivers/staging/batman-adv/hard-interface.c @@ -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; diff --git a/include/linux/if.h b/include/linux/if.h index 31f2e27..53558ec 100644 --- a/include/linux/if.h +++ b/include/linux/if.h @@ -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 diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index d8d00fa..727404d 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -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; diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c index 2663743..6818e60 100644 --- a/net/bridge/br_fdb.c +++ b/net/bridge/br_fdb.c @@ -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(); diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c index 90ac003..099495e 100644 --- a/net/bridge/br_if.c +++ b/net/bridge/br_if.c @@ -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); diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c index 99647d8..f076c9d 100644 --- a/net/bridge/br_input.c +++ b/net/bridge/br_input.c @@ -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 */ diff --git a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c index 0685b25..f54404d 100644 --- a/net/bridge/br_netfilter.c +++ b/net/bridge/br_netfilter.c @@ -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) diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c index fe0a790..4a6a378 100644 --- a/net/bridge/br_netlink.c +++ b/net/bridge/br_netlink.c @@ -120,10 +120,11 @@ static int br_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb) 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) diff --git a/net/bridge/br_notify.c b/net/bridge/br_notify.c index 717e1fd..404d4e1 100644 --- a/net/bridge/br_notify.c +++ b/net/bridge/br_notify.c @@ -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) { diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h index c83519b..5837052 100644 --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h @@ -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; diff --git a/net/bridge/br_stp_bpdu.c b/net/bridge/br_stp_bpdu.c index 217bd22..70aecb4 100644 --- a/net/bridge/br_stp_bpdu.c +++ b/net/bridge/br_stp_bpdu.c @@ -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; diff --git a/net/bridge/netfilter/ebt_redirect.c b/net/bridge/netfilter/ebt_redirect.c index 9e19166..46624bb 100644 --- a/net/bridge/netfilter/ebt_redirect.c +++ b/net/bridge/netfilter/ebt_redirect.c @@ -24,8 +24,9 @@ ebt_redirect_tg(struct sk_buff *skb, const struct xt_action_param *par) 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; diff --git a/net/bridge/netfilter/ebt_ulog.c b/net/bridge/netfilter/ebt_ulog.c index ae3c7ce..26377e9 100644 --- a/net/bridge/netfilter/ebt_ulog.c +++ b/net/bridge/netfilter/ebt_ulog.c @@ -177,8 +177,9 @@ static void ebt_ulog_packet(unsigned int hooknr, const struct sk_buff *skb, 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'; diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c index 59ca00e..bcc102e 100644 --- a/net/bridge/netfilter/ebtables.c +++ b/net/bridge/netfilter/ebtables.c @@ -140,11 +140,14 @@ ebt_basic_match(const struct ebt_entry *e, const struct ethhdr *h, 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) { diff --git a/net/core/dev.c b/net/core/dev.c index abdb19e..5902426 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -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. diff --git a/net/netfilter/nfnetlink_log.c b/net/netfilter/nfnetlink_log.c index fc9a211..e0504e9 100644 --- a/net/netfilter/nfnetlink_log.c +++ b/net/netfilter/nfnetlink_log.c @@ -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) */ diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c index 12e1ab3..cc3ae86 100644 --- a/net/netfilter/nfnetlink_queue.c +++ b/net/netfilter/nfnetlink_queue.c @@ -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) */ diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 90ab3c8..3a7b8a2 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -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; } diff --git a/net/wireless/util.c b/net/wireless/util.c index 3416373..0c8a1e8 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c @@ -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) { -- 1.7.0.1 ^ permalink raw reply related [flat|nested] 13+ messages in thread
* Re: [PATCH net-next-2.6 3/3 v3] bridge: use rx_handler_data pointer to store net_bridge_port pointer 2010-06-15 16:50 ` [PATCH net-next-2.6 3/3 v3] bridge: use rx_handler_data pointer to store net_bridge_port pointer Jiri Pirko @ 2010-06-15 18:50 ` David Miller 0 siblings, 0 replies; 13+ messages in thread From: David Miller @ 2010-06-15 18:50 UTC (permalink / raw) To: jpirko; +Cc: netdev, shemminger, kaber, eric.dumazet From: Jiri Pirko <jpirko@redhat.com> Date: Tue, 15 Jun 2010 18:50:45 +0200 > 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> Applied. ^ permalink raw reply [flat|nested] 13+ messages in thread
end of thread, other threads:[~2010-06-15 18:49 UTC | newest] Thread overview: 13+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2010-06-10 13:34 [PATCH net-next-2.6 0/3] net: use rx_handler_data pointer for bridge and macvlan ports Jiri Pirko 2010-06-10 13:34 ` [PATCH net-next-2.6 1/3] net: add rx_handler data pointer Jiri Pirko 2010-06-15 18:49 ` David Miller 2010-06-10 13:35 ` [PATCH net-next-2.6 2/3] macvlan: use rx_handler_data pointer to store macvlan_port pointer Jiri Pirko 2010-06-15 12:48 ` Patrick McHardy 2010-06-15 13:27 ` [PATCH net-next-2.6 2/3] macvlan: use rx_handler_data pointer to store macvlan_port pointer V2 Jiri Pirko 2010-06-15 18:50 ` David Miller 2010-06-10 13:36 ` [PATCH net-next-2.6 3/3] bridge: use rx_handler_data pointer to store net_bridge_port pointer Jiri Pirko 2010-06-15 13:28 ` [PATCH net-next-2.6 3/3] bridge: use rx_handler_data pointer to store net_bridge_port pointer V2 Jiri Pirko 2010-06-15 16:30 ` Stephen Hemminger 2010-06-15 16:51 ` Jiri Pirko 2010-06-15 16:50 ` [PATCH net-next-2.6 3/3 v3] bridge: use rx_handler_data pointer to store net_bridge_port pointer Jiri Pirko 2010-06-15 18:50 ` David Miller
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).