diff --git a/include/linux/if_bridge.h b/include/linux/if_bridge.h index 9e57c4411734..6009f14c9cfc 100644 --- a/include/linux/if_bridge.h +++ b/include/linux/if_bridge.h @@ -52,6 +52,11 @@ struct br_ip_list { extern void brioctl_set(int (*ioctl_hook)(struct net *, unsigned int, void __user *)); +#ifdef CONFIG_ENABLE_SFE +extern struct net_device *br_port_dev_get(struct net_device *dev, + unsigned char *addr); +#endif + #if IS_ENABLED(CONFIG_BRIDGE) && IS_ENABLED(CONFIG_BRIDGE_IGMP_SNOOPING) int br_multicast_list_adjacent(struct net_device *dev, struct list_head *br_ip_list); diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c index 4fe30b182ee7..ad682004ebb1 100644 --- a/net/bridge/br_if.c +++ b/net/bridge/br_if.c @@ -757,3 +757,36 @@ bool br_port_flag_is_set(const struct net_device *dev, unsigned long flag) return p->flags & flag; } EXPORT_SYMBOL_GPL(br_port_flag_is_set); + +#ifdef CONFIG_ENABLE_SFE +/* br_port_dev_get() + * Using the given addr, identify the port to which it is reachable, + * returing a reference to the net device associated with that port. + * + * NOTE: Return NULL if given dev is not a bridge or + * the mac has no associated port + */ +struct net_device *br_port_dev_get(struct net_device *dev, unsigned char *addr) +{ + struct net_bridge_fdb_entry *fdbe; + struct net_bridge *br; + struct net_device *netdev = NULL; + + /* Is this a bridge? */ + if (!(dev->priv_flags & IFF_EBRIDGE)) + return NULL; + + br = netdev_priv(dev); + + /* Lookup the fdb entry and get reference to the port dev */ + rcu_read_lock(); + fdbe = br_fdb_find_rcu(br, addr, 0); + if (fdbe && fdbe->dst) { + netdev = fdbe->dst->dev; /* port device */ + dev_hold(netdev); + } + rcu_read_unlock(); + return netdev; +} +EXPORT_SYMBOL(br_port_dev_get); +#endif