diff mbox

[net-next,mlxsw,v2,1/7] net: bridge: Publish bridge accessor functions

Message ID a2d8197bdfb3e681a88f0c219dc74b298a759737.1524610426.git.petrm@mellanox.com (mailing list archive)
State Changes Requested
Delegated to: Ido Schimmel
Headers show

Commit Message

Petr Machata April 24, 2018, 11:08 p.m. UTC
To allow querying FDB and vlan settings of a bridge, publish several
existing functions and add some new ones.

Signed-off-by: Petr Machata <petrm@mellanox.com>
---

Notes:
    Changes from v1 to v2:
    
    - Change from the two functions br_fdb_find_rtnl() and
      br_fdb_entry_dev() to a single br_fdb_find_port(). Take hash_lock
      before looking up the FDB entry.

 include/linux/if_bridge.h | 55 +++++++++++++++++++++++++++++++++++++++++++++++
 net/bridge/br_fdb.c       | 23 ++++++++++++++++++++
 net/bridge/br_private.h   | 17 +++++++++------
 net/bridge/br_vlan.c      | 32 +++++++++++++++++++++++++++
 4 files changed, 121 insertions(+), 6 deletions(-)

Comments

Ido Schimmel April 25, 2018, 7:01 a.m. UTC | #1
On Wed, Apr 25, 2018 at 01:08:44AM +0200, Petr Machata wrote:
> +struct net_device *br_fdb_find_port(const struct net_device *br_dev,
> +				    const unsigned char *addr,
> +				    __u16 vid)
> +{
> +	struct net_bridge_fdb_entry *f;
> +	struct net_device *dev = NULL;
> +	struct net_bridge *br;
> +
> +	if (!netif_is_bridge_master(br_dev))
> +		return NULL;
> +
> +	br = netdev_priv(br_dev);
> +
> +	spin_lock_bh(&br->hash_lock);
> +	f = br_fdb_find(br, addr, vid);
> +	if (f)
> +		dev = f->dst->dev;

What about the case where f->dst is NULL? Such as when the FDB entry
points to the bridge device itself?

Also, I believe a reference should be taken on the resulting device.

> +	spin_unlock_bh(&br->hash_lock);
> +
> +	return dev;
> +}
> +EXPORT_SYMBOL_GPL(br_fdb_find_port);
diff mbox

Patch

diff --git a/include/linux/if_bridge.h b/include/linux/if_bridge.h
index 02639eb..b6b5222 100644
--- a/include/linux/if_bridge.h
+++ b/include/linux/if_bridge.h
@@ -93,11 +93,66 @@  static inline bool br_multicast_router(const struct net_device *dev)
 
 #if IS_ENABLED(CONFIG_BRIDGE) && IS_ENABLED(CONFIG_BRIDGE_VLAN_FILTERING)
 bool br_vlan_enabled(const struct net_device *dev);
+
+struct net_bridge_vlan_group *
+br_vlan_group_rtnl(const struct net_device *br_dev);
+
+struct net_bridge_vlan_group *
+br_port_vlan_group_rtnl(const struct net_device *dev);
+
+u16 br_vlan_group_pvid(const struct net_bridge_vlan_group *vg);
+
+struct net_bridge_vlan *br_vlan_find(struct net_bridge_vlan_group *vg, u16 vid);
+
+u16 br_vlan_flags(const struct net_bridge_vlan *v);
+
 #else
 static inline bool br_vlan_enabled(const struct net_device *dev)
 {
 	return false;
 }
+
+static inline struct net_bridge_vlan_group *
+br_vlan_group_rtnl(const struct net_device *br_dev)
+{
+	return NULL;
+}
+
+static inline struct net_bridge_vlan_group *
+br_port_vlan_group_rtnl(const struct net_device *dev)
+{
+	return NULL;
+}
+
+static inline u16 br_vlan_group_pvid(const struct net_bridge_vlan_group *vg)
+{
+	return 0;
+}
+
+static inline struct net_bridge_vlan *
+br_vlan_find(struct net_bridge_vlan_group *vg, u16 vid)
+{
+	return NULL;
+}
+
+static inline u16 br_vlan_flags(const struct net_bridge_vlan *v)
+{
+	return 0;
+}
+#endif
+
+#if IS_ENABLED(CONFIG_BRIDGE)
+struct net_device *br_fdb_find_port(const struct net_device *br_dev,
+				    const unsigned char *addr,
+				    __u16 vid);
+#else
+static inline struct net_device *
+br_fdb_find_port(const struct net_device *br_dev,
+		 const unsigned char *addr,
+		 __u16 vid)
+{
+	return NULL;
+}
 #endif
 
 #endif
diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c
index d9e69e4..bc819d7 100644
--- a/net/bridge/br_fdb.c
+++ b/net/bridge/br_fdb.c
@@ -121,6 +121,29 @@  static struct net_bridge_fdb_entry *br_fdb_find(struct net_bridge *br,
 	return fdb;
 }
 
+struct net_device *br_fdb_find_port(const struct net_device *br_dev,
+				    const unsigned char *addr,
+				    __u16 vid)
+{
+	struct net_bridge_fdb_entry *f;
+	struct net_device *dev = NULL;
+	struct net_bridge *br;
+
+	if (!netif_is_bridge_master(br_dev))
+		return NULL;
+
+	br = netdev_priv(br_dev);
+
+	spin_lock_bh(&br->hash_lock);
+	f = br_fdb_find(br, addr, vid);
+	if (f)
+		dev = f->dst->dev;
+	spin_unlock_bh(&br->hash_lock);
+
+	return dev;
+}
+EXPORT_SYMBOL_GPL(br_fdb_find_port);
+
 struct net_bridge_fdb_entry *br_fdb_find_rcu(struct net_bridge *br,
 					     const unsigned char *addr,
 					     __u16 vid)
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
index a7cb3ec..3c929d5 100644
--- a/net/bridge/br_private.h
+++ b/net/bridge/br_private.h
@@ -594,11 +594,22 @@  static inline bool br_rx_handler_check_rcu(const struct net_device *dev)
 	return rcu_dereference(dev->rx_handler) == br_handle_frame;
 }
 
+static inline bool br_rx_handler_check_rtnl(const struct net_device *dev)
+{
+	return rcu_dereference_rtnl(dev->rx_handler) == br_handle_frame;
+}
+
 static inline struct net_bridge_port *br_port_get_check_rcu(const struct net_device *dev)
 {
 	return br_rx_handler_check_rcu(dev) ? br_port_get_rcu(dev) : NULL;
 }
 
+static inline struct net_bridge_port *
+br_port_get_check_rtnl(const struct net_device *dev)
+{
+	return br_rx_handler_check_rtnl(dev) ? br_port_get_rtnl_rcu(dev) : NULL;
+}
+
 /* br_ioctl.c */
 int br_dev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
 int br_ioctl_deviceless_stub(struct net *net, unsigned int cmd,
@@ -955,12 +966,6 @@  static inline void nbp_vlan_flush(struct net_bridge_port *port)
 {
 }
 
-static inline struct net_bridge_vlan *br_vlan_find(struct net_bridge_vlan_group *vg,
-						   u16 vid)
-{
-	return NULL;
-}
-
 static inline int nbp_vlan_init(struct net_bridge_port *port)
 {
 	return 0;
diff --git a/net/bridge/br_vlan.c b/net/bridge/br_vlan.c
index 9896f49..1c118c1 100644
--- a/net/bridge/br_vlan.c
+++ b/net/bridge/br_vlan.c
@@ -671,6 +671,7 @@  struct net_bridge_vlan *br_vlan_find(struct net_bridge_vlan_group *vg, u16 vid)
 
 	return br_vlan_lookup(&vg->vlan_hash, vid);
 }
+EXPORT_SYMBOL_GPL(br_vlan_find);
 
 /* Must be protected by RTNL. */
 static void recalculate_group_addr(struct net_bridge *br)
@@ -1149,3 +1150,34 @@  void br_vlan_get_stats(const struct net_bridge_vlan *v,
 		stats->tx_packets += txpackets;
 	}
 }
+
+struct net_bridge_vlan_group *
+br_vlan_group_rtnl(const struct net_device *br_dev)
+{
+	if (netif_is_bridge_master(br_dev))
+		return br_vlan_group(netdev_priv(br_dev));
+	else
+		return NULL;
+}
+EXPORT_SYMBOL_GPL(br_vlan_group_rtnl);
+
+struct net_bridge_vlan_group *
+br_port_vlan_group_rtnl(const struct net_device *dev)
+{
+	struct net_bridge_port *p = br_port_get_check_rtnl(dev);
+
+	return p ? nbp_vlan_group(p) : NULL;
+}
+EXPORT_SYMBOL_GPL(br_port_vlan_group_rtnl);
+
+u16 br_vlan_group_pvid(const struct net_bridge_vlan_group *vg)
+{
+	return br_get_pvid(vg);
+}
+EXPORT_SYMBOL_GPL(br_vlan_group_pvid);
+
+u16 br_vlan_flags(const struct net_bridge_vlan *v)
+{
+	return v->flags;
+}
+EXPORT_SYMBOL_GPL(br_vlan_flags);