xref: /openbmc/linux/net/bridge/br_fdb.c (revision ca2478a7d974f38d29d27acb42a952c7f168916e)
12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds  *	Forwarding database
41da177e4SLinus Torvalds  *	Linux ethernet bridge
51da177e4SLinus Torvalds  *
61da177e4SLinus Torvalds  *	Authors:
71da177e4SLinus Torvalds  *	Lennert Buytenhek		<buytenh@gnu.org>
81da177e4SLinus Torvalds  */
91da177e4SLinus Torvalds 
101da177e4SLinus Torvalds #include <linux/kernel.h>
111da177e4SLinus Torvalds #include <linux/init.h>
1282524746SFranck Bui-Huu #include <linux/rculist.h>
131da177e4SLinus Torvalds #include <linux/spinlock.h>
141da177e4SLinus Torvalds #include <linux/times.h>
151da177e4SLinus Torvalds #include <linux/netdevice.h>
161da177e4SLinus Torvalds #include <linux/etherdevice.h>
171da177e4SLinus Torvalds #include <linux/jhash.h>
183f890923SStephen Hemminger #include <linux/random.h>
195a0e3ad6STejun Heo #include <linux/slab.h>
2060063497SArun Sharma #include <linux/atomic.h>
213f890923SStephen Hemminger #include <asm/unaligned.h>
222ba071ecSVlad Yasevich #include <linux/if_vlan.h>
23b4ad7baaSScott Feldman #include <net/switchdev.h>
24b74fd306SRoopa Prabhu #include <trace/events/bridge.h>
251da177e4SLinus Torvalds #include "br_private.h"
261da177e4SLinus Torvalds 
27eb793583SNikolay Aleksandrov static const struct rhashtable_params br_fdb_rht_params = {
28eb793583SNikolay Aleksandrov 	.head_offset = offsetof(struct net_bridge_fdb_entry, rhnode),
29eb793583SNikolay Aleksandrov 	.key_offset = offsetof(struct net_bridge_fdb_entry, key),
30eb793583SNikolay Aleksandrov 	.key_len = sizeof(struct net_bridge_fdb_key),
31eb793583SNikolay Aleksandrov 	.automatic_shrinking = true,
32eb793583SNikolay Aleksandrov };
33eb793583SNikolay Aleksandrov 
34e18b890bSChristoph Lameter static struct kmem_cache *br_fdb_cache __read_mostly;
351da177e4SLinus Torvalds 
br_fdb_init(void)3687a596e0SAkinobu Mita int __init br_fdb_init(void)
371da177e4SLinus Torvalds {
381da177e4SLinus Torvalds 	br_fdb_cache = kmem_cache_create("bridge_fdb_cache",
391da177e4SLinus Torvalds 					 sizeof(struct net_bridge_fdb_entry),
401da177e4SLinus Torvalds 					 0,
4120c2df83SPaul Mundt 					 SLAB_HWCACHE_ALIGN, NULL);
4287a596e0SAkinobu Mita 	if (!br_fdb_cache)
4387a596e0SAkinobu Mita 		return -ENOMEM;
4487a596e0SAkinobu Mita 
4587a596e0SAkinobu Mita 	return 0;
461da177e4SLinus Torvalds }
471da177e4SLinus Torvalds 
br_fdb_fini(void)4873afc906SAndrew Morton void br_fdb_fini(void)
491da177e4SLinus Torvalds {
501da177e4SLinus Torvalds 	kmem_cache_destroy(br_fdb_cache);
511da177e4SLinus Torvalds }
521da177e4SLinus Torvalds 
br_fdb_hash_init(struct net_bridge * br)53eb793583SNikolay Aleksandrov int br_fdb_hash_init(struct net_bridge *br)
54eb793583SNikolay Aleksandrov {
55eb793583SNikolay Aleksandrov 	return rhashtable_init(&br->fdb_hash_tbl, &br_fdb_rht_params);
56eb793583SNikolay Aleksandrov }
57eb793583SNikolay Aleksandrov 
br_fdb_hash_fini(struct net_bridge * br)58eb793583SNikolay Aleksandrov void br_fdb_hash_fini(struct net_bridge *br)
59eb793583SNikolay Aleksandrov {
60eb793583SNikolay Aleksandrov 	rhashtable_destroy(&br->fdb_hash_tbl);
61eb793583SNikolay Aleksandrov }
621da177e4SLinus Torvalds 
631da177e4SLinus Torvalds /* if topology_changing then use forward_delay (default 15 sec)
641da177e4SLinus Torvalds  * otherwise keep longer (default 5 minutes)
651da177e4SLinus Torvalds  */
hold_time(const struct net_bridge * br)663f890923SStephen Hemminger static inline unsigned long hold_time(const struct net_bridge *br)
671da177e4SLinus Torvalds {
681da177e4SLinus Torvalds 	return br->topology_change ? br->forward_delay : br->ageing_time;
691da177e4SLinus Torvalds }
701da177e4SLinus Torvalds 
has_expired(const struct net_bridge * br,const struct net_bridge_fdb_entry * fdb)713f890923SStephen Hemminger static inline int has_expired(const struct net_bridge *br,
721da177e4SLinus Torvalds 				  const struct net_bridge_fdb_entry *fdb)
731da177e4SLinus Torvalds {
7429e63fffSNikolay Aleksandrov 	return !test_bit(BR_FDB_STATIC, &fdb->flags) &&
75b5cd9f7cSNikolay Aleksandrov 	       !test_bit(BR_FDB_ADDED_BY_EXT_LEARN, &fdb->flags) &&
767cd8861aSstephen hemminger 	       time_before_eq(fdb->updated + hold_time(br), jiffies);
771da177e4SLinus Torvalds }
781da177e4SLinus Torvalds 
fdb_rcu_free(struct rcu_head * head)79da678292SMichał Mirosław static void fdb_rcu_free(struct rcu_head *head)
80da678292SMichał Mirosław {
81da678292SMichał Mirosław 	struct net_bridge_fdb_entry *ent
82da678292SMichał Mirosław 		= container_of(head, struct net_bridge_fdb_entry, rcu);
83da678292SMichał Mirosław 	kmem_cache_free(br_fdb_cache, ent);
84da678292SMichał Mirosław }
85da678292SMichał Mirosław 
fdb_to_nud(const struct net_bridge * br,const struct net_bridge_fdb_entry * fdb)864682048aSVladimir Oltean static int fdb_to_nud(const struct net_bridge *br,
874682048aSVladimir Oltean 		      const struct net_bridge_fdb_entry *fdb)
884682048aSVladimir Oltean {
894682048aSVladimir Oltean 	if (test_bit(BR_FDB_LOCAL, &fdb->flags))
904682048aSVladimir Oltean 		return NUD_PERMANENT;
914682048aSVladimir Oltean 	else if (test_bit(BR_FDB_STATIC, &fdb->flags))
924682048aSVladimir Oltean 		return NUD_NOARP;
934682048aSVladimir Oltean 	else if (has_expired(br, fdb))
944682048aSVladimir Oltean 		return NUD_STALE;
954682048aSVladimir Oltean 	else
964682048aSVladimir Oltean 		return NUD_REACHABLE;
974682048aSVladimir Oltean }
984682048aSVladimir Oltean 
fdb_fill_info(struct sk_buff * skb,const struct net_bridge * br,const struct net_bridge_fdb_entry * fdb,u32 portid,u32 seq,int type,unsigned int flags)994682048aSVladimir Oltean static int fdb_fill_info(struct sk_buff *skb, const struct net_bridge *br,
1004682048aSVladimir Oltean 			 const struct net_bridge_fdb_entry *fdb,
1014682048aSVladimir Oltean 			 u32 portid, u32 seq, int type, unsigned int flags)
1024682048aSVladimir Oltean {
1034682048aSVladimir Oltean 	const struct net_bridge_port *dst = READ_ONCE(fdb->dst);
1044682048aSVladimir Oltean 	unsigned long now = jiffies;
1054682048aSVladimir Oltean 	struct nda_cacheinfo ci;
1064682048aSVladimir Oltean 	struct nlmsghdr *nlh;
1074682048aSVladimir Oltean 	struct ndmsg *ndm;
108a35ec8e3SHans J. Schultz 	u32 ext_flags = 0;
1094682048aSVladimir Oltean 
1104682048aSVladimir Oltean 	nlh = nlmsg_put(skb, portid, seq, type, sizeof(*ndm), flags);
1114682048aSVladimir Oltean 	if (nlh == NULL)
1124682048aSVladimir Oltean 		return -EMSGSIZE;
1134682048aSVladimir Oltean 
1144682048aSVladimir Oltean 	ndm = nlmsg_data(nlh);
1154682048aSVladimir Oltean 	ndm->ndm_family	 = AF_BRIDGE;
1164682048aSVladimir Oltean 	ndm->ndm_pad1    = 0;
1174682048aSVladimir Oltean 	ndm->ndm_pad2    = 0;
1184682048aSVladimir Oltean 	ndm->ndm_flags	 = 0;
1194682048aSVladimir Oltean 	ndm->ndm_type	 = 0;
1204682048aSVladimir Oltean 	ndm->ndm_ifindex = dst ? dst->dev->ifindex : br->dev->ifindex;
1214682048aSVladimir Oltean 	ndm->ndm_state   = fdb_to_nud(br, fdb);
1224682048aSVladimir Oltean 
1234682048aSVladimir Oltean 	if (test_bit(BR_FDB_OFFLOADED, &fdb->flags))
1244682048aSVladimir Oltean 		ndm->ndm_flags |= NTF_OFFLOADED;
1254682048aSVladimir Oltean 	if (test_bit(BR_FDB_ADDED_BY_EXT_LEARN, &fdb->flags))
1264682048aSVladimir Oltean 		ndm->ndm_flags |= NTF_EXT_LEARNED;
1274682048aSVladimir Oltean 	if (test_bit(BR_FDB_STICKY, &fdb->flags))
1284682048aSVladimir Oltean 		ndm->ndm_flags |= NTF_STICKY;
129a35ec8e3SHans J. Schultz 	if (test_bit(BR_FDB_LOCKED, &fdb->flags))
130a35ec8e3SHans J. Schultz 		ext_flags |= NTF_EXT_LOCKED;
1314682048aSVladimir Oltean 
1324682048aSVladimir Oltean 	if (nla_put(skb, NDA_LLADDR, ETH_ALEN, &fdb->key.addr))
1334682048aSVladimir Oltean 		goto nla_put_failure;
1344682048aSVladimir Oltean 	if (nla_put_u32(skb, NDA_MASTER, br->dev->ifindex))
1354682048aSVladimir Oltean 		goto nla_put_failure;
136a35ec8e3SHans J. Schultz 	if (nla_put_u32(skb, NDA_FLAGS_EXT, ext_flags))
137a35ec8e3SHans J. Schultz 		goto nla_put_failure;
138a35ec8e3SHans J. Schultz 
1394682048aSVladimir Oltean 	ci.ndm_used	 = jiffies_to_clock_t(now - fdb->used);
1404682048aSVladimir Oltean 	ci.ndm_confirmed = 0;
1414682048aSVladimir Oltean 	ci.ndm_updated	 = jiffies_to_clock_t(now - fdb->updated);
1424682048aSVladimir Oltean 	ci.ndm_refcnt	 = 0;
1434682048aSVladimir Oltean 	if (nla_put(skb, NDA_CACHEINFO, sizeof(ci), &ci))
1444682048aSVladimir Oltean 		goto nla_put_failure;
1454682048aSVladimir Oltean 
1464682048aSVladimir Oltean 	if (fdb->key.vlan_id && nla_put(skb, NDA_VLAN, sizeof(u16),
1474682048aSVladimir Oltean 					&fdb->key.vlan_id))
1484682048aSVladimir Oltean 		goto nla_put_failure;
1494682048aSVladimir Oltean 
1504682048aSVladimir Oltean 	if (test_bit(BR_FDB_NOTIFY, &fdb->flags)) {
1514682048aSVladimir Oltean 		struct nlattr *nest = nla_nest_start(skb, NDA_FDB_EXT_ATTRS);
1524682048aSVladimir Oltean 		u8 notify_bits = FDB_NOTIFY_BIT;
1534682048aSVladimir Oltean 
1544682048aSVladimir Oltean 		if (!nest)
1554682048aSVladimir Oltean 			goto nla_put_failure;
1564682048aSVladimir Oltean 		if (test_bit(BR_FDB_NOTIFY_INACTIVE, &fdb->flags))
1574682048aSVladimir Oltean 			notify_bits |= FDB_NOTIFY_INACTIVE_BIT;
1584682048aSVladimir Oltean 
1594682048aSVladimir Oltean 		if (nla_put_u8(skb, NFEA_ACTIVITY_NOTIFY, notify_bits)) {
1604682048aSVladimir Oltean 			nla_nest_cancel(skb, nest);
1614682048aSVladimir Oltean 			goto nla_put_failure;
1624682048aSVladimir Oltean 		}
1634682048aSVladimir Oltean 
1644682048aSVladimir Oltean 		nla_nest_end(skb, nest);
1654682048aSVladimir Oltean 	}
1664682048aSVladimir Oltean 
1674682048aSVladimir Oltean 	nlmsg_end(skb, nlh);
1684682048aSVladimir Oltean 	return 0;
1694682048aSVladimir Oltean 
1704682048aSVladimir Oltean nla_put_failure:
1714682048aSVladimir Oltean 	nlmsg_cancel(skb, nlh);
1724682048aSVladimir Oltean 	return -EMSGSIZE;
1734682048aSVladimir Oltean }
1744682048aSVladimir Oltean 
fdb_nlmsg_size(void)1754682048aSVladimir Oltean static inline size_t fdb_nlmsg_size(void)
1764682048aSVladimir Oltean {
1774682048aSVladimir Oltean 	return NLMSG_ALIGN(sizeof(struct ndmsg))
1784682048aSVladimir Oltean 		+ nla_total_size(ETH_ALEN) /* NDA_LLADDR */
1794682048aSVladimir Oltean 		+ nla_total_size(sizeof(u32)) /* NDA_MASTER */
180a35ec8e3SHans J. Schultz 		+ nla_total_size(sizeof(u32)) /* NDA_FLAGS_EXT */
1814682048aSVladimir Oltean 		+ nla_total_size(sizeof(u16)) /* NDA_VLAN */
1824682048aSVladimir Oltean 		+ nla_total_size(sizeof(struct nda_cacheinfo))
1834682048aSVladimir Oltean 		+ nla_total_size(0) /* NDA_FDB_EXT_ATTRS */
1844682048aSVladimir Oltean 		+ nla_total_size(sizeof(u8)); /* NFEA_ACTIVITY_NOTIFY */
1854682048aSVladimir Oltean }
1864682048aSVladimir Oltean 
fdb_notify(struct net_bridge * br,const struct net_bridge_fdb_entry * fdb,int type,bool swdev_notify)1874682048aSVladimir Oltean static void fdb_notify(struct net_bridge *br,
1884682048aSVladimir Oltean 		       const struct net_bridge_fdb_entry *fdb, int type,
1894682048aSVladimir Oltean 		       bool swdev_notify)
1904682048aSVladimir Oltean {
1914682048aSVladimir Oltean 	struct net *net = dev_net(br->dev);
1924682048aSVladimir Oltean 	struct sk_buff *skb;
1934682048aSVladimir Oltean 	int err = -ENOBUFS;
1944682048aSVladimir Oltean 
1954682048aSVladimir Oltean 	if (swdev_notify)
1964682048aSVladimir Oltean 		br_switchdev_fdb_notify(br, fdb, type);
1974682048aSVladimir Oltean 
1984682048aSVladimir Oltean 	skb = nlmsg_new(fdb_nlmsg_size(), GFP_ATOMIC);
1994682048aSVladimir Oltean 	if (skb == NULL)
2004682048aSVladimir Oltean 		goto errout;
2014682048aSVladimir Oltean 
2024682048aSVladimir Oltean 	err = fdb_fill_info(skb, br, fdb, 0, 0, type, 0);
2034682048aSVladimir Oltean 	if (err < 0) {
2044682048aSVladimir Oltean 		/* -EMSGSIZE implies BUG in fdb_nlmsg_size() */
2054682048aSVladimir Oltean 		WARN_ON(err == -EMSGSIZE);
2064682048aSVladimir Oltean 		kfree_skb(skb);
2074682048aSVladimir Oltean 		goto errout;
2084682048aSVladimir Oltean 	}
2094682048aSVladimir Oltean 	rtnl_notify(skb, net, 0, RTNLGRP_NEIGH, NULL, GFP_ATOMIC);
2104682048aSVladimir Oltean 	return;
2114682048aSVladimir Oltean errout:
2124682048aSVladimir Oltean 	rtnl_set_sk_err(net, RTNLGRP_NEIGH, err);
2134682048aSVladimir Oltean }
2144682048aSVladimir Oltean 
fdb_find_rcu(struct rhashtable * tbl,const unsigned char * addr,__u16 vid)215eb793583SNikolay Aleksandrov static struct net_bridge_fdb_entry *fdb_find_rcu(struct rhashtable *tbl,
216bfd0aeacSNikolay Aleksandrov 						 const unsigned char *addr,
217bfd0aeacSNikolay Aleksandrov 						 __u16 vid)
218bfd0aeacSNikolay Aleksandrov {
219eb793583SNikolay Aleksandrov 	struct net_bridge_fdb_key key;
220bfd0aeacSNikolay Aleksandrov 
221410b3d48SNikolay Aleksandrov 	WARN_ON_ONCE(!rcu_read_lock_held());
222410b3d48SNikolay Aleksandrov 
223eb793583SNikolay Aleksandrov 	key.vlan_id = vid;
224eb793583SNikolay Aleksandrov 	memcpy(key.addr.addr, addr, sizeof(key.addr.addr));
225bfd0aeacSNikolay Aleksandrov 
226eb793583SNikolay Aleksandrov 	return rhashtable_lookup(tbl, &key, br_fdb_rht_params);
227bfd0aeacSNikolay Aleksandrov }
228bfd0aeacSNikolay Aleksandrov 
229bfd0aeacSNikolay Aleksandrov /* requires bridge hash_lock */
br_fdb_find(struct net_bridge * br,const unsigned char * addr,__u16 vid)230bfd0aeacSNikolay Aleksandrov static struct net_bridge_fdb_entry *br_fdb_find(struct net_bridge *br,
231bfd0aeacSNikolay Aleksandrov 						const unsigned char *addr,
232bfd0aeacSNikolay Aleksandrov 						__u16 vid)
233bfd0aeacSNikolay Aleksandrov {
234bfd0aeacSNikolay Aleksandrov 	struct net_bridge_fdb_entry *fdb;
235bfd0aeacSNikolay Aleksandrov 
236d12c9176SWANG Cong 	lockdep_assert_held_once(&br->hash_lock);
237410b3d48SNikolay Aleksandrov 
238bfd0aeacSNikolay Aleksandrov 	rcu_read_lock();
239eb793583SNikolay Aleksandrov 	fdb = fdb_find_rcu(&br->fdb_hash_tbl, addr, vid);
240bfd0aeacSNikolay Aleksandrov 	rcu_read_unlock();
241bfd0aeacSNikolay Aleksandrov 
242bfd0aeacSNikolay Aleksandrov 	return fdb;
243bfd0aeacSNikolay Aleksandrov }
244bfd0aeacSNikolay Aleksandrov 
br_fdb_find_port(const struct net_device * br_dev,const unsigned char * addr,__u16 vid)2454d4fd361SPetr Machata struct net_device *br_fdb_find_port(const struct net_device *br_dev,
2464d4fd361SPetr Machata 				    const unsigned char *addr,
2474d4fd361SPetr Machata 				    __u16 vid)
2484d4fd361SPetr Machata {
2494d4fd361SPetr Machata 	struct net_bridge_fdb_entry *f;
2504d4fd361SPetr Machata 	struct net_device *dev = NULL;
2514d4fd361SPetr Machata 	struct net_bridge *br;
2524d4fd361SPetr Machata 
2534d4fd361SPetr Machata 	ASSERT_RTNL();
2544d4fd361SPetr Machata 
2554d4fd361SPetr Machata 	if (!netif_is_bridge_master(br_dev))
2564d4fd361SPetr Machata 		return NULL;
2574d4fd361SPetr Machata 
2584d4fd361SPetr Machata 	br = netdev_priv(br_dev);
259873aca2eSPetr Machata 	rcu_read_lock();
260873aca2eSPetr Machata 	f = br_fdb_find_rcu(br, addr, vid);
2614d4fd361SPetr Machata 	if (f && f->dst)
2624d4fd361SPetr Machata 		dev = f->dst->dev;
263873aca2eSPetr Machata 	rcu_read_unlock();
2644d4fd361SPetr Machata 
2654d4fd361SPetr Machata 	return dev;
2664d4fd361SPetr Machata }
2674d4fd361SPetr Machata EXPORT_SYMBOL_GPL(br_fdb_find_port);
2684d4fd361SPetr Machata 
br_fdb_find_rcu(struct net_bridge * br,const unsigned char * addr,__u16 vid)269bfd0aeacSNikolay Aleksandrov struct net_bridge_fdb_entry *br_fdb_find_rcu(struct net_bridge *br,
270bfd0aeacSNikolay Aleksandrov 					     const unsigned char *addr,
271bfd0aeacSNikolay Aleksandrov 					     __u16 vid)
272bfd0aeacSNikolay Aleksandrov {
273eb793583SNikolay Aleksandrov 	return fdb_find_rcu(&br->fdb_hash_tbl, addr, vid);
274bfd0aeacSNikolay Aleksandrov }
275bfd0aeacSNikolay Aleksandrov 
276145beee8SVlad Yasevich /* When a static FDB entry is added, the mac address from the entry is
277145beee8SVlad Yasevich  * added to the bridge private HW address list and all required ports
278145beee8SVlad Yasevich  * are then updated with the new information.
279145beee8SVlad Yasevich  * Called under RTNL.
280145beee8SVlad Yasevich  */
fdb_add_hw_addr(struct net_bridge * br,const unsigned char * addr)281020ec6baSJiri Pirko static void fdb_add_hw_addr(struct net_bridge *br, const unsigned char *addr)
282145beee8SVlad Yasevich {
283145beee8SVlad Yasevich 	int err;
284a3f5ee71SLi RongQing 	struct net_bridge_port *p;
285145beee8SVlad Yasevich 
286145beee8SVlad Yasevich 	ASSERT_RTNL();
287145beee8SVlad Yasevich 
288145beee8SVlad Yasevich 	list_for_each_entry(p, &br->port_list, list) {
289145beee8SVlad Yasevich 		if (!br_promisc_port(p)) {
290145beee8SVlad Yasevich 			err = dev_uc_add(p->dev, addr);
291145beee8SVlad Yasevich 			if (err)
292145beee8SVlad Yasevich 				goto undo;
293145beee8SVlad Yasevich 		}
294145beee8SVlad Yasevich 	}
295145beee8SVlad Yasevich 
296145beee8SVlad Yasevich 	return;
297145beee8SVlad Yasevich undo:
298a3f5ee71SLi RongQing 	list_for_each_entry_continue_reverse(p, &br->port_list, list) {
299a3f5ee71SLi RongQing 		if (!br_promisc_port(p))
300a3f5ee71SLi RongQing 			dev_uc_del(p->dev, addr);
301145beee8SVlad Yasevich 	}
302145beee8SVlad Yasevich }
303145beee8SVlad Yasevich 
304145beee8SVlad Yasevich /* When a static FDB entry is deleted, the HW address from that entry is
305145beee8SVlad Yasevich  * also removed from the bridge private HW address list and updates all
306145beee8SVlad Yasevich  * the ports with needed information.
307145beee8SVlad Yasevich  * Called under RTNL.
308145beee8SVlad Yasevich  */
fdb_del_hw_addr(struct net_bridge * br,const unsigned char * addr)309020ec6baSJiri Pirko static void fdb_del_hw_addr(struct net_bridge *br, const unsigned char *addr)
310145beee8SVlad Yasevich {
311145beee8SVlad Yasevich 	struct net_bridge_port *p;
312145beee8SVlad Yasevich 
313145beee8SVlad Yasevich 	ASSERT_RTNL();
314145beee8SVlad Yasevich 
315145beee8SVlad Yasevich 	list_for_each_entry(p, &br->port_list, list) {
316145beee8SVlad Yasevich 		if (!br_promisc_port(p))
317145beee8SVlad Yasevich 			dev_uc_del(p->dev, addr);
318145beee8SVlad Yasevich 	}
319145beee8SVlad Yasevich }
320145beee8SVlad Yasevich 
fdb_delete(struct net_bridge * br,struct net_bridge_fdb_entry * f,bool swdev_notify)321161d82deSPetr Machata static void fdb_delete(struct net_bridge *br, struct net_bridge_fdb_entry *f,
322161d82deSPetr Machata 		       bool swdev_notify)
3231da177e4SLinus Torvalds {
324b74fd306SRoopa Prabhu 	trace_fdb_delete(br, f);
325b74fd306SRoopa Prabhu 
32629e63fffSNikolay Aleksandrov 	if (test_bit(BR_FDB_STATIC, &f->flags))
327eb793583SNikolay Aleksandrov 		fdb_del_hw_addr(br, f->key.addr.addr);
328145beee8SVlad Yasevich 
329eb793583SNikolay Aleksandrov 	hlist_del_init_rcu(&f->fdb_node);
330eb793583SNikolay Aleksandrov 	rhashtable_remove_fast(&br->fdb_hash_tbl, &f->rhnode,
331eb793583SNikolay Aleksandrov 			       br_fdb_rht_params);
332161d82deSPetr Machata 	fdb_notify(br, f, RTM_DELNEIGH, swdev_notify);
333da678292SMichał Mirosław 	call_rcu(&f->rcu, fdb_rcu_free);
3341da177e4SLinus Torvalds }
3351da177e4SLinus Torvalds 
336960b589fSToshiaki Makita /* Delete a local entry if no other port had the same address. */
fdb_delete_local(struct net_bridge * br,const struct net_bridge_port * p,struct net_bridge_fdb_entry * f)337960b589fSToshiaki Makita static void fdb_delete_local(struct net_bridge *br,
338960b589fSToshiaki Makita 			     const struct net_bridge_port *p,
339960b589fSToshiaki Makita 			     struct net_bridge_fdb_entry *f)
340960b589fSToshiaki Makita {
341eb793583SNikolay Aleksandrov 	const unsigned char *addr = f->key.addr.addr;
3422594e906SNikolay Aleksandrov 	struct net_bridge_vlan_group *vg;
3432594e906SNikolay Aleksandrov 	const struct net_bridge_vlan *v;
344960b589fSToshiaki Makita 	struct net_bridge_port *op;
345eb793583SNikolay Aleksandrov 	u16 vid = f->key.vlan_id;
346960b589fSToshiaki Makita 
347960b589fSToshiaki Makita 	/* Maybe another port has same hw addr? */
348960b589fSToshiaki Makita 	list_for_each_entry(op, &br->port_list, list) {
3492594e906SNikolay Aleksandrov 		vg = nbp_vlan_group(op);
350960b589fSToshiaki Makita 		if (op != p && ether_addr_equal(op->dev->dev_addr, addr) &&
3512594e906SNikolay Aleksandrov 		    (!vid || br_vlan_find(vg, vid))) {
352960b589fSToshiaki Makita 			f->dst = op;
353ac3ca6afSNikolay Aleksandrov 			clear_bit(BR_FDB_ADDED_BY_USER, &f->flags);
354960b589fSToshiaki Makita 			return;
355960b589fSToshiaki Makita 		}
356960b589fSToshiaki Makita 	}
357960b589fSToshiaki Makita 
3582594e906SNikolay Aleksandrov 	vg = br_vlan_group(br);
3592594e906SNikolay Aleksandrov 	v = br_vlan_find(vg, vid);
360960b589fSToshiaki Makita 	/* Maybe bridge device has same hw addr? */
361960b589fSToshiaki Makita 	if (p && ether_addr_equal(br->dev->dev_addr, addr) &&
3622594e906SNikolay Aleksandrov 	    (!vid || (v && br_vlan_should_use(v)))) {
363960b589fSToshiaki Makita 		f->dst = NULL;
364ac3ca6afSNikolay Aleksandrov 		clear_bit(BR_FDB_ADDED_BY_USER, &f->flags);
365960b589fSToshiaki Makita 		return;
366960b589fSToshiaki Makita 	}
367960b589fSToshiaki Makita 
368161d82deSPetr Machata 	fdb_delete(br, f, true);
369960b589fSToshiaki Makita }
370960b589fSToshiaki Makita 
br_fdb_find_delete_local(struct net_bridge * br,const struct net_bridge_port * p,const unsigned char * addr,u16 vid)371424bb9c9SToshiaki Makita void br_fdb_find_delete_local(struct net_bridge *br,
372424bb9c9SToshiaki Makita 			      const struct net_bridge_port *p,
373424bb9c9SToshiaki Makita 			      const unsigned char *addr, u16 vid)
374424bb9c9SToshiaki Makita {
375424bb9c9SToshiaki Makita 	struct net_bridge_fdb_entry *f;
376424bb9c9SToshiaki Makita 
377424bb9c9SToshiaki Makita 	spin_lock_bh(&br->hash_lock);
378bfd0aeacSNikolay Aleksandrov 	f = br_fdb_find(br, addr, vid);
3796869c3b0SNikolay Aleksandrov 	if (f && test_bit(BR_FDB_LOCAL, &f->flags) &&
380ac3ca6afSNikolay Aleksandrov 	    !test_bit(BR_FDB_ADDED_BY_USER, &f->flags) && f->dst == p)
381424bb9c9SToshiaki Makita 		fdb_delete_local(br, p, f);
382424bb9c9SToshiaki Makita 	spin_unlock_bh(&br->hash_lock);
383424bb9c9SToshiaki Makita }
384424bb9c9SToshiaki Makita 
fdb_create(struct net_bridge * br,struct net_bridge_port * source,const unsigned char * addr,__u16 vid,unsigned long flags)3855f94a5e2SVladimir Oltean static struct net_bridge_fdb_entry *fdb_create(struct net_bridge *br,
3865f94a5e2SVladimir Oltean 					       struct net_bridge_port *source,
3875f94a5e2SVladimir Oltean 					       const unsigned char *addr,
3885f94a5e2SVladimir Oltean 					       __u16 vid,
3895f94a5e2SVladimir Oltean 					       unsigned long flags)
3905f94a5e2SVladimir Oltean {
3915f94a5e2SVladimir Oltean 	struct net_bridge_fdb_entry *fdb;
3929574fb55SVladimir Oltean 	int err;
3935f94a5e2SVladimir Oltean 
3945f94a5e2SVladimir Oltean 	fdb = kmem_cache_alloc(br_fdb_cache, GFP_ATOMIC);
3959574fb55SVladimir Oltean 	if (!fdb)
3969574fb55SVladimir Oltean 		return NULL;
3979574fb55SVladimir Oltean 
3985f94a5e2SVladimir Oltean 	memcpy(fdb->key.addr.addr, addr, ETH_ALEN);
3995f94a5e2SVladimir Oltean 	WRITE_ONCE(fdb->dst, source);
4005f94a5e2SVladimir Oltean 	fdb->key.vlan_id = vid;
4015f94a5e2SVladimir Oltean 	fdb->flags = flags;
4025f94a5e2SVladimir Oltean 	fdb->updated = fdb->used = jiffies;
4039574fb55SVladimir Oltean 	err = rhashtable_lookup_insert_fast(&br->fdb_hash_tbl, &fdb->rhnode,
4049574fb55SVladimir Oltean 					    br_fdb_rht_params);
4059574fb55SVladimir Oltean 	if (err) {
4065f94a5e2SVladimir Oltean 		kmem_cache_free(br_fdb_cache, fdb);
4079574fb55SVladimir Oltean 		return NULL;
4089574fb55SVladimir Oltean 	}
4099574fb55SVladimir Oltean 
4105f94a5e2SVladimir Oltean 	hlist_add_head_rcu(&fdb->fdb_node, &br->fdb_list);
4119574fb55SVladimir Oltean 
4125f94a5e2SVladimir Oltean 	return fdb;
4135f94a5e2SVladimir Oltean }
4145f94a5e2SVladimir Oltean 
fdb_add_local(struct net_bridge * br,struct net_bridge_port * source,const unsigned char * addr,u16 vid)4154731b6d6SVladimir Oltean static int fdb_add_local(struct net_bridge *br, struct net_bridge_port *source,
4165f94a5e2SVladimir Oltean 			 const unsigned char *addr, u16 vid)
4175f94a5e2SVladimir Oltean {
4185f94a5e2SVladimir Oltean 	struct net_bridge_fdb_entry *fdb;
4195f94a5e2SVladimir Oltean 
4205f94a5e2SVladimir Oltean 	if (!is_valid_ether_addr(addr))
4215f94a5e2SVladimir Oltean 		return -EINVAL;
4225f94a5e2SVladimir Oltean 
4235f94a5e2SVladimir Oltean 	fdb = br_fdb_find(br, addr, vid);
4245f94a5e2SVladimir Oltean 	if (fdb) {
4255f94a5e2SVladimir Oltean 		/* it is okay to have multiple ports with same
4265f94a5e2SVladimir Oltean 		 * address, just use the first one.
4275f94a5e2SVladimir Oltean 		 */
4285f94a5e2SVladimir Oltean 		if (test_bit(BR_FDB_LOCAL, &fdb->flags))
4295f94a5e2SVladimir Oltean 			return 0;
4305f94a5e2SVladimir Oltean 		br_warn(br, "adding interface %s with same address as a received packet (addr:%pM, vlan:%u)\n",
4315f94a5e2SVladimir Oltean 			source ? source->dev->name : br->dev->name, addr, vid);
4325f94a5e2SVladimir Oltean 		fdb_delete(br, fdb, true);
4335f94a5e2SVladimir Oltean 	}
4345f94a5e2SVladimir Oltean 
4355f94a5e2SVladimir Oltean 	fdb = fdb_create(br, source, addr, vid,
4365f94a5e2SVladimir Oltean 			 BIT(BR_FDB_LOCAL) | BIT(BR_FDB_STATIC));
4375f94a5e2SVladimir Oltean 	if (!fdb)
4385f94a5e2SVladimir Oltean 		return -ENOMEM;
4395f94a5e2SVladimir Oltean 
4405f94a5e2SVladimir Oltean 	fdb_add_hw_addr(br, addr);
4415f94a5e2SVladimir Oltean 	fdb_notify(br, fdb, RTM_NEWNEIGH, true);
4425f94a5e2SVladimir Oltean 	return 0;
4435f94a5e2SVladimir Oltean }
4445f94a5e2SVladimir Oltean 
br_fdb_changeaddr(struct net_bridge_port * p,const unsigned char * newaddr)4451da177e4SLinus Torvalds void br_fdb_changeaddr(struct net_bridge_port *p, const unsigned char *newaddr)
4461da177e4SLinus Torvalds {
4472594e906SNikolay Aleksandrov 	struct net_bridge_vlan_group *vg;
448eb793583SNikolay Aleksandrov 	struct net_bridge_fdb_entry *f;
4491da177e4SLinus Torvalds 	struct net_bridge *br = p->br;
4502594e906SNikolay Aleksandrov 	struct net_bridge_vlan *v;
4511da177e4SLinus Torvalds 
4521da177e4SLinus Torvalds 	spin_lock_bh(&br->hash_lock);
4532594e906SNikolay Aleksandrov 	vg = nbp_vlan_group(p);
454eb793583SNikolay Aleksandrov 	hlist_for_each_entry(f, &br->fdb_list, fdb_node) {
4556869c3b0SNikolay Aleksandrov 		if (f->dst == p && test_bit(BR_FDB_LOCAL, &f->flags) &&
456ac3ca6afSNikolay Aleksandrov 		    !test_bit(BR_FDB_ADDED_BY_USER, &f->flags)) {
4571da177e4SLinus Torvalds 			/* delete old one */
458960b589fSToshiaki Makita 			fdb_delete_local(br, p, f);
459960b589fSToshiaki Makita 
460bc9a25d2SVlad Yasevich 			/* if this port has no vlan information
461bc9a25d2SVlad Yasevich 			 * configured, we can safely be done at
462bc9a25d2SVlad Yasevich 			 * this point.
463bc9a25d2SVlad Yasevich 			 */
4642594e906SNikolay Aleksandrov 			if (!vg || !vg->num_vlans)
4652836882fSToshiaki Makita 				goto insert;
4662836882fSToshiaki Makita 		}
4672836882fSToshiaki Makita 	}
4682836882fSToshiaki Makita 
4692836882fSToshiaki Makita insert:
4702836882fSToshiaki Makita 	/* insert new address,  may fail if invalid address or dup. */
4714731b6d6SVladimir Oltean 	fdb_add_local(br, p, newaddr, 0);
4722836882fSToshiaki Makita 
4732594e906SNikolay Aleksandrov 	if (!vg || !vg->num_vlans)
474bc9a25d2SVlad Yasevich 		goto done;
4752836882fSToshiaki Makita 
4762836882fSToshiaki Makita 	/* Now add entries for every VLAN configured on the port.
4772836882fSToshiaki Makita 	 * This function runs under RTNL so the bitmap will not change
4782836882fSToshiaki Makita 	 * from under us.
4792836882fSToshiaki Makita 	 */
4802594e906SNikolay Aleksandrov 	list_for_each_entry(v, &vg->vlan_list, vlist)
4814731b6d6SVladimir Oltean 		fdb_add_local(br, p, newaddr, v->vid);
482bc9a25d2SVlad Yasevich 
483bc9a25d2SVlad Yasevich done:
4841da177e4SLinus Torvalds 	spin_unlock_bh(&br->hash_lock);
4851da177e4SLinus Torvalds }
4861da177e4SLinus Torvalds 
br_fdb_change_mac_address(struct net_bridge * br,const u8 * newaddr)48743598813Sstephen hemminger void br_fdb_change_mac_address(struct net_bridge *br, const u8 *newaddr)
48843598813Sstephen hemminger {
4892594e906SNikolay Aleksandrov 	struct net_bridge_vlan_group *vg;
49043598813Sstephen hemminger 	struct net_bridge_fdb_entry *f;
4912594e906SNikolay Aleksandrov 	struct net_bridge_vlan *v;
49243598813Sstephen hemminger 
493ac4c8868SToshiaki Makita 	spin_lock_bh(&br->hash_lock);
494ac4c8868SToshiaki Makita 
49543598813Sstephen hemminger 	/* If old entry was unassociated with any port, then delete it. */
496bfd0aeacSNikolay Aleksandrov 	f = br_fdb_find(br, br->dev->dev_addr, 0);
4976869c3b0SNikolay Aleksandrov 	if (f && test_bit(BR_FDB_LOCAL, &f->flags) &&
498ac3ca6afSNikolay Aleksandrov 	    !f->dst && !test_bit(BR_FDB_ADDED_BY_USER, &f->flags))
499960b589fSToshiaki Makita 		fdb_delete_local(br, NULL, f);
50043598813Sstephen hemminger 
5014731b6d6SVladimir Oltean 	fdb_add_local(br, NULL, newaddr, 0);
5022594e906SNikolay Aleksandrov 	vg = br_vlan_group(br);
5032594e906SNikolay Aleksandrov 	if (!vg || !vg->num_vlans)
5042594e906SNikolay Aleksandrov 		goto out;
505bc9a25d2SVlad Yasevich 	/* Now remove and add entries for every VLAN configured on the
506bc9a25d2SVlad Yasevich 	 * bridge.  This function runs under RTNL so the bitmap will not
507bc9a25d2SVlad Yasevich 	 * change from under us.
508bc9a25d2SVlad Yasevich 	 */
5092594e906SNikolay Aleksandrov 	list_for_each_entry(v, &vg->vlan_list, vlist) {
5100b148defSToshiaki Makita 		if (!br_vlan_should_use(v))
5110b148defSToshiaki Makita 			continue;
512bfd0aeacSNikolay Aleksandrov 		f = br_fdb_find(br, br->dev->dev_addr, v->vid);
5136869c3b0SNikolay Aleksandrov 		if (f && test_bit(BR_FDB_LOCAL, &f->flags) &&
514ac3ca6afSNikolay Aleksandrov 		    !f->dst && !test_bit(BR_FDB_ADDED_BY_USER, &f->flags))
515960b589fSToshiaki Makita 			fdb_delete_local(br, NULL, f);
5164731b6d6SVladimir Oltean 		fdb_add_local(br, NULL, newaddr, v->vid);
517bc9a25d2SVlad Yasevich 	}
518ac4c8868SToshiaki Makita out:
519ac4c8868SToshiaki Makita 	spin_unlock_bh(&br->hash_lock);
52043598813Sstephen hemminger }
52143598813Sstephen hemminger 
br_fdb_cleanup(struct work_struct * work)522f7cdee8aSNikolay Aleksandrov void br_fdb_cleanup(struct work_struct *work)
5231da177e4SLinus Torvalds {
524f7cdee8aSNikolay Aleksandrov 	struct net_bridge *br = container_of(work, struct net_bridge,
525f7cdee8aSNikolay Aleksandrov 					     gc_work.work);
526eb793583SNikolay Aleksandrov 	struct net_bridge_fdb_entry *f = NULL;
5271da177e4SLinus Torvalds 	unsigned long delay = hold_time(br);
528f7cdee8aSNikolay Aleksandrov 	unsigned long work_delay = delay;
529f7cdee8aSNikolay Aleksandrov 	unsigned long now = jiffies;
5301da177e4SLinus Torvalds 
531eb793583SNikolay Aleksandrov 	/* this part is tricky, in order to avoid blocking learning and
532eb793583SNikolay Aleksandrov 	 * consequently forwarding, we rely on rcu to delete objects with
533eb793583SNikolay Aleksandrov 	 * delayed freeing allowing us to continue traversing
534eb793583SNikolay Aleksandrov 	 */
535eb793583SNikolay Aleksandrov 	rcu_read_lock();
536eb793583SNikolay Aleksandrov 	hlist_for_each_entry_rcu(f, &br->fdb_list, fdb_node) {
53731cbc39bSNikolay Aleksandrov 		unsigned long this_timer = f->updated + delay;
538f7cdee8aSNikolay Aleksandrov 
53929e63fffSNikolay Aleksandrov 		if (test_bit(BR_FDB_STATIC, &f->flags) ||
54031cbc39bSNikolay Aleksandrov 		    test_bit(BR_FDB_ADDED_BY_EXT_LEARN, &f->flags)) {
54131cbc39bSNikolay Aleksandrov 			if (test_bit(BR_FDB_NOTIFY, &f->flags)) {
54231cbc39bSNikolay Aleksandrov 				if (time_after(this_timer, now))
54331cbc39bSNikolay Aleksandrov 					work_delay = min(work_delay,
54431cbc39bSNikolay Aleksandrov 							 this_timer - now);
54531cbc39bSNikolay Aleksandrov 				else if (!test_and_set_bit(BR_FDB_NOTIFY_INACTIVE,
54631cbc39bSNikolay Aleksandrov 							   &f->flags))
54731cbc39bSNikolay Aleksandrov 					fdb_notify(br, f, RTM_NEWNEIGH, false);
54831cbc39bSNikolay Aleksandrov 			}
549dcd45e06SSiva Mannem 			continue;
55031cbc39bSNikolay Aleksandrov 		}
55131cbc39bSNikolay Aleksandrov 
552eb793583SNikolay Aleksandrov 		if (time_after(this_timer, now)) {
553f7cdee8aSNikolay Aleksandrov 			work_delay = min(work_delay, this_timer - now);
554eb793583SNikolay Aleksandrov 		} else {
555eb793583SNikolay Aleksandrov 			spin_lock_bh(&br->hash_lock);
556eb793583SNikolay Aleksandrov 			if (!hlist_unhashed(&f->fdb_node))
557161d82deSPetr Machata 				fdb_delete(br, f, true);
558f7cdee8aSNikolay Aleksandrov 			spin_unlock_bh(&br->hash_lock);
5591da177e4SLinus Torvalds 		}
560eb793583SNikolay Aleksandrov 	}
561eb793583SNikolay Aleksandrov 	rcu_read_unlock();
5621da177e4SLinus Torvalds 
563f7cdee8aSNikolay Aleksandrov 	/* Cleanup minimum 10 milliseconds apart */
564f7cdee8aSNikolay Aleksandrov 	work_delay = max_t(unsigned long, work_delay, msecs_to_jiffies(10));
565f7cdee8aSNikolay Aleksandrov 	mod_delayed_work(system_long_wq, &br->gc_work, work_delay);
5661da177e4SLinus Torvalds }
5671da177e4SLinus Torvalds 
__fdb_flush_matches(const struct net_bridge * br,const struct net_bridge_fdb_entry * f,const struct net_bridge_fdb_flush_desc * desc)5681f78ee14SNikolay Aleksandrov static bool __fdb_flush_matches(const struct net_bridge *br,
5691f78ee14SNikolay Aleksandrov 				const struct net_bridge_fdb_entry *f,
5701f78ee14SNikolay Aleksandrov 				const struct net_bridge_fdb_flush_desc *desc)
5711f78ee14SNikolay Aleksandrov {
5721f78ee14SNikolay Aleksandrov 	const struct net_bridge_port *dst = READ_ONCE(f->dst);
5731f78ee14SNikolay Aleksandrov 	int port_ifidx = dst ? dst->dev->ifindex : br->dev->ifindex;
5741f78ee14SNikolay Aleksandrov 
5751f78ee14SNikolay Aleksandrov 	if (desc->vlan_id && desc->vlan_id != f->key.vlan_id)
5761f78ee14SNikolay Aleksandrov 		return false;
5771f78ee14SNikolay Aleksandrov 	if (desc->port_ifindex && desc->port_ifindex != port_ifidx)
5781f78ee14SNikolay Aleksandrov 		return false;
5791f78ee14SNikolay Aleksandrov 	if (desc->flags_mask && (f->flags & desc->flags_mask) != desc->flags)
5801f78ee14SNikolay Aleksandrov 		return false;
5811f78ee14SNikolay Aleksandrov 
5821f78ee14SNikolay Aleksandrov 	return true;
5831f78ee14SNikolay Aleksandrov }
5841f78ee14SNikolay Aleksandrov 
5851f78ee14SNikolay Aleksandrov /* Flush forwarding database entries matching the description */
br_fdb_flush(struct net_bridge * br,const struct net_bridge_fdb_flush_desc * desc)5861f78ee14SNikolay Aleksandrov void br_fdb_flush(struct net_bridge *br,
5871f78ee14SNikolay Aleksandrov 		  const struct net_bridge_fdb_flush_desc *desc)
5889cf63747SStephen Hemminger {
589eb793583SNikolay Aleksandrov 	struct net_bridge_fdb_entry *f;
5901f78ee14SNikolay Aleksandrov 
5911f78ee14SNikolay Aleksandrov 	rcu_read_lock();
5921f78ee14SNikolay Aleksandrov 	hlist_for_each_entry_rcu(f, &br->fdb_list, fdb_node) {
5931f78ee14SNikolay Aleksandrov 		if (!__fdb_flush_matches(br, f, desc))
5941f78ee14SNikolay Aleksandrov 			continue;
5951a620698SStephen Hemminger 
5969cf63747SStephen Hemminger 		spin_lock_bh(&br->hash_lock);
5971f78ee14SNikolay Aleksandrov 		if (!hlist_unhashed(&f->fdb_node))
598161d82deSPetr Machata 			fdb_delete(br, f, true);
5999cf63747SStephen Hemminger 		spin_unlock_bh(&br->hash_lock);
6009cf63747SStephen Hemminger 	}
6011f78ee14SNikolay Aleksandrov 	rcu_read_unlock();
6021f78ee14SNikolay Aleksandrov }
6039cf63747SStephen Hemminger 
__ndm_state_to_fdb_flags(u16 ndm_state)604564445fbSNikolay Aleksandrov static unsigned long __ndm_state_to_fdb_flags(u16 ndm_state)
605564445fbSNikolay Aleksandrov {
606564445fbSNikolay Aleksandrov 	unsigned long flags = 0;
607564445fbSNikolay Aleksandrov 
608564445fbSNikolay Aleksandrov 	if (ndm_state & NUD_PERMANENT)
609564445fbSNikolay Aleksandrov 		__set_bit(BR_FDB_LOCAL, &flags);
610564445fbSNikolay Aleksandrov 	if (ndm_state & NUD_NOARP)
611564445fbSNikolay Aleksandrov 		__set_bit(BR_FDB_STATIC, &flags);
612564445fbSNikolay Aleksandrov 
613564445fbSNikolay Aleksandrov 	return flags;
614564445fbSNikolay Aleksandrov }
615564445fbSNikolay Aleksandrov 
__ndm_flags_to_fdb_flags(u8 ndm_flags)616564445fbSNikolay Aleksandrov static unsigned long __ndm_flags_to_fdb_flags(u8 ndm_flags)
617564445fbSNikolay Aleksandrov {
618564445fbSNikolay Aleksandrov 	unsigned long flags = 0;
619564445fbSNikolay Aleksandrov 
620564445fbSNikolay Aleksandrov 	if (ndm_flags & NTF_USE)
621564445fbSNikolay Aleksandrov 		__set_bit(BR_FDB_ADDED_BY_USER, &flags);
622564445fbSNikolay Aleksandrov 	if (ndm_flags & NTF_EXT_LEARNED)
623564445fbSNikolay Aleksandrov 		__set_bit(BR_FDB_ADDED_BY_EXT_LEARN, &flags);
624564445fbSNikolay Aleksandrov 	if (ndm_flags & NTF_OFFLOADED)
625564445fbSNikolay Aleksandrov 		__set_bit(BR_FDB_OFFLOADED, &flags);
626564445fbSNikolay Aleksandrov 	if (ndm_flags & NTF_STICKY)
627564445fbSNikolay Aleksandrov 		__set_bit(BR_FDB_STICKY, &flags);
628564445fbSNikolay Aleksandrov 
629564445fbSNikolay Aleksandrov 	return flags;
630564445fbSNikolay Aleksandrov }
631564445fbSNikolay Aleksandrov 
__fdb_flush_validate_ifindex(const struct net_bridge * br,int ifindex,struct netlink_ext_ack * extack)6320dbe886aSNikolay Aleksandrov static int __fdb_flush_validate_ifindex(const struct net_bridge *br,
6330dbe886aSNikolay Aleksandrov 					int ifindex,
6340dbe886aSNikolay Aleksandrov 					struct netlink_ext_ack *extack)
6350dbe886aSNikolay Aleksandrov {
6360dbe886aSNikolay Aleksandrov 	const struct net_device *dev;
6370dbe886aSNikolay Aleksandrov 
6380dbe886aSNikolay Aleksandrov 	dev = __dev_get_by_index(dev_net(br->dev), ifindex);
6390dbe886aSNikolay Aleksandrov 	if (!dev) {
6400dbe886aSNikolay Aleksandrov 		NL_SET_ERR_MSG_MOD(extack, "Unknown flush device ifindex");
6410dbe886aSNikolay Aleksandrov 		return -ENODEV;
6420dbe886aSNikolay Aleksandrov 	}
6430dbe886aSNikolay Aleksandrov 	if (!netif_is_bridge_master(dev) && !netif_is_bridge_port(dev)) {
6440dbe886aSNikolay Aleksandrov 		NL_SET_ERR_MSG_MOD(extack, "Flush device is not a bridge or bridge port");
6450dbe886aSNikolay Aleksandrov 		return -EINVAL;
6460dbe886aSNikolay Aleksandrov 	}
6470dbe886aSNikolay Aleksandrov 	if (netif_is_bridge_master(dev) && dev != br->dev) {
6480dbe886aSNikolay Aleksandrov 		NL_SET_ERR_MSG_MOD(extack,
6490dbe886aSNikolay Aleksandrov 				   "Flush bridge device does not match target bridge device");
6500dbe886aSNikolay Aleksandrov 		return -EINVAL;
6510dbe886aSNikolay Aleksandrov 	}
6520dbe886aSNikolay Aleksandrov 	if (netif_is_bridge_port(dev)) {
6530dbe886aSNikolay Aleksandrov 		struct net_bridge_port *p = br_port_get_rtnl(dev);
6540dbe886aSNikolay Aleksandrov 
6550dbe886aSNikolay Aleksandrov 		if (p->br != br) {
6560dbe886aSNikolay Aleksandrov 			NL_SET_ERR_MSG_MOD(extack, "Port belongs to a different bridge device");
6570dbe886aSNikolay Aleksandrov 			return -EINVAL;
6580dbe886aSNikolay Aleksandrov 		}
6590dbe886aSNikolay Aleksandrov 	}
6600dbe886aSNikolay Aleksandrov 
6610dbe886aSNikolay Aleksandrov 	return 0;
6620dbe886aSNikolay Aleksandrov }
6630dbe886aSNikolay Aleksandrov 
br_fdb_delete_bulk(struct ndmsg * ndm,struct nlattr * tb[],struct net_device * dev,u16 vid,struct netlink_ext_ack * extack)664edaef191SNikolay Aleksandrov int br_fdb_delete_bulk(struct ndmsg *ndm, struct nlattr *tb[],
665edaef191SNikolay Aleksandrov 		       struct net_device *dev, u16 vid,
666edaef191SNikolay Aleksandrov 		       struct netlink_ext_ack *extack)
667edaef191SNikolay Aleksandrov {
668564445fbSNikolay Aleksandrov 	u8 ndm_flags = ndm->ndm_flags & ~FDB_FLUSH_IGNORED_NDM_FLAGS;
6690dbe886aSNikolay Aleksandrov 	struct net_bridge_fdb_flush_desc desc = { .vlan_id = vid };
670edaef191SNikolay Aleksandrov 	struct net_bridge_port *p = NULL;
671edaef191SNikolay Aleksandrov 	struct net_bridge *br;
672edaef191SNikolay Aleksandrov 
673edaef191SNikolay Aleksandrov 	if (netif_is_bridge_master(dev)) {
674edaef191SNikolay Aleksandrov 		br = netdev_priv(dev);
675edaef191SNikolay Aleksandrov 	} else {
676edaef191SNikolay Aleksandrov 		p = br_port_get_rtnl(dev);
677edaef191SNikolay Aleksandrov 		if (!p) {
678edaef191SNikolay Aleksandrov 			NL_SET_ERR_MSG_MOD(extack, "Device is not a bridge port");
679edaef191SNikolay Aleksandrov 			return -EINVAL;
680edaef191SNikolay Aleksandrov 		}
681edaef191SNikolay Aleksandrov 		br = p->br;
682edaef191SNikolay Aleksandrov 	}
683edaef191SNikolay Aleksandrov 
684564445fbSNikolay Aleksandrov 	if (ndm_flags & ~FDB_FLUSH_ALLOWED_NDM_FLAGS) {
685564445fbSNikolay Aleksandrov 		NL_SET_ERR_MSG(extack, "Unsupported fdb flush ndm flag bits set");
686564445fbSNikolay Aleksandrov 		return -EINVAL;
687564445fbSNikolay Aleksandrov 	}
688564445fbSNikolay Aleksandrov 	if (ndm->ndm_state & ~FDB_FLUSH_ALLOWED_NDM_STATES) {
689564445fbSNikolay Aleksandrov 		NL_SET_ERR_MSG(extack, "Unsupported fdb flush ndm state bits set");
690564445fbSNikolay Aleksandrov 		return -EINVAL;
691564445fbSNikolay Aleksandrov 	}
692564445fbSNikolay Aleksandrov 
693564445fbSNikolay Aleksandrov 	desc.flags |= __ndm_state_to_fdb_flags(ndm->ndm_state);
694564445fbSNikolay Aleksandrov 	desc.flags |= __ndm_flags_to_fdb_flags(ndm_flags);
695564445fbSNikolay Aleksandrov 	if (tb[NDA_NDM_STATE_MASK]) {
696564445fbSNikolay Aleksandrov 		u16 ndm_state_mask = nla_get_u16(tb[NDA_NDM_STATE_MASK]);
697564445fbSNikolay Aleksandrov 
698564445fbSNikolay Aleksandrov 		desc.flags_mask |= __ndm_state_to_fdb_flags(ndm_state_mask);
699564445fbSNikolay Aleksandrov 	}
700564445fbSNikolay Aleksandrov 	if (tb[NDA_NDM_FLAGS_MASK]) {
701564445fbSNikolay Aleksandrov 		u8 ndm_flags_mask = nla_get_u8(tb[NDA_NDM_FLAGS_MASK]);
702564445fbSNikolay Aleksandrov 
703564445fbSNikolay Aleksandrov 		desc.flags_mask |= __ndm_flags_to_fdb_flags(ndm_flags_mask);
704564445fbSNikolay Aleksandrov 	}
7050dbe886aSNikolay Aleksandrov 	if (tb[NDA_IFINDEX]) {
7060dbe886aSNikolay Aleksandrov 		int err, ifidx = nla_get_s32(tb[NDA_IFINDEX]);
7070dbe886aSNikolay Aleksandrov 
7080dbe886aSNikolay Aleksandrov 		err = __fdb_flush_validate_ifindex(br, ifidx, extack);
7090dbe886aSNikolay Aleksandrov 		if (err)
7100dbe886aSNikolay Aleksandrov 			return err;
7110dbe886aSNikolay Aleksandrov 		desc.port_ifindex = ifidx;
7120dbe886aSNikolay Aleksandrov 	} else if (p) {
7130dbe886aSNikolay Aleksandrov 		/* flush was invoked with port device and NTF_MASTER */
7140dbe886aSNikolay Aleksandrov 		desc.port_ifindex = p->dev->ifindex;
7150dbe886aSNikolay Aleksandrov 	}
716564445fbSNikolay Aleksandrov 
717564445fbSNikolay Aleksandrov 	br_debug(br, "flushing port ifindex: %d vlan id: %u flags: 0x%lx flags mask: 0x%lx\n",
718564445fbSNikolay Aleksandrov 		 desc.port_ifindex, desc.vlan_id, desc.flags, desc.flags_mask);
719564445fbSNikolay Aleksandrov 
7201f78ee14SNikolay Aleksandrov 	br_fdb_flush(br, &desc);
721edaef191SNikolay Aleksandrov 
722edaef191SNikolay Aleksandrov 	return 0;
723edaef191SNikolay Aleksandrov }
724edaef191SNikolay Aleksandrov 
72525985edcSLucas De Marchi /* Flush all entries referring to a specific port.
7269cf63747SStephen Hemminger  * if do_all is set also flush static entries
7271ea2d020SNikolay Aleksandrov  * if vid is set delete all entries that match the vlan_id
7289cf63747SStephen Hemminger  */
br_fdb_delete_by_port(struct net_bridge * br,const struct net_bridge_port * p,u16 vid,int do_all)7291a620698SStephen Hemminger void br_fdb_delete_by_port(struct net_bridge *br,
7301a620698SStephen Hemminger 			   const struct net_bridge_port *p,
7311ea2d020SNikolay Aleksandrov 			   u16 vid,
7321a620698SStephen Hemminger 			   int do_all)
7331da177e4SLinus Torvalds {
734eb793583SNikolay Aleksandrov 	struct net_bridge_fdb_entry *f;
735eb793583SNikolay Aleksandrov 	struct hlist_node *tmp;
7361da177e4SLinus Torvalds 
7371da177e4SLinus Torvalds 	spin_lock_bh(&br->hash_lock);
738eb793583SNikolay Aleksandrov 	hlist_for_each_entry_safe(f, tmp, &br->fdb_list, fdb_node) {
7391da177e4SLinus Torvalds 		if (f->dst != p)
7401da177e4SLinus Torvalds 			continue;
7411da177e4SLinus Torvalds 
7421ea2d020SNikolay Aleksandrov 		if (!do_all)
74329e63fffSNikolay Aleksandrov 			if (test_bit(BR_FDB_STATIC, &f->flags) ||
744f2f3729fSNikolay Aleksandrov 			    (test_bit(BR_FDB_ADDED_BY_EXT_LEARN, &f->flags) &&
745f2f3729fSNikolay Aleksandrov 			     !test_bit(BR_FDB_OFFLOADED, &f->flags)) ||
74629e63fffSNikolay Aleksandrov 			    (vid && f->key.vlan_id != vid))
7471a620698SStephen Hemminger 				continue;
7481da177e4SLinus Torvalds 
7496869c3b0SNikolay Aleksandrov 		if (test_bit(BR_FDB_LOCAL, &f->flags))
750a778e6d1SToshiaki Makita 			fdb_delete_local(br, p, f);
751a778e6d1SToshiaki Makita 		else
752161d82deSPetr Machata 			fdb_delete(br, f, true);
7531da177e4SLinus Torvalds 	}
7541da177e4SLinus Torvalds 	spin_unlock_bh(&br->hash_lock);
7551da177e4SLinus Torvalds }
7561da177e4SLinus Torvalds 
757e6373c4cSIgor Maravić #if IS_ENABLED(CONFIG_ATM_LANE)
758da678292SMichał Mirosław /* Interface used by ATM LANE hook to test
759da678292SMichał Mirosław  * if an addr is on some other bridge port */
br_fdb_test_addr(struct net_device * dev,unsigned char * addr)760da678292SMichał Mirosław int br_fdb_test_addr(struct net_device *dev, unsigned char *addr)
7611da177e4SLinus Torvalds {
7621da177e4SLinus Torvalds 	struct net_bridge_fdb_entry *fdb;
763b5ed54e9Sstephen hemminger 	struct net_bridge_port *port;
764da678292SMichał Mirosław 	int ret;
765da678292SMichał Mirosław 
7661da177e4SLinus Torvalds 	rcu_read_lock();
767b5ed54e9Sstephen hemminger 	port = br_port_get_rcu(dev);
768b5ed54e9Sstephen hemminger 	if (!port)
769b5ed54e9Sstephen hemminger 		ret = 0;
770b5ed54e9Sstephen hemminger 	else {
7713e19ae7cSVladimir Oltean 		const struct net_bridge_port *dst = NULL;
7723e19ae7cSVladimir Oltean 
773bfd0aeacSNikolay Aleksandrov 		fdb = br_fdb_find_rcu(port->br, addr, 0);
7743e19ae7cSVladimir Oltean 		if (fdb)
7753e19ae7cSVladimir Oltean 			dst = READ_ONCE(fdb->dst);
7763e19ae7cSVladimir Oltean 
7773e19ae7cSVladimir Oltean 		ret = dst && dst->dev != dev &&
7783e19ae7cSVladimir Oltean 		      dst->state == BR_STATE_FORWARDING;
779b5ed54e9Sstephen hemminger 	}
7801da177e4SLinus Torvalds 	rcu_read_unlock();
7811da177e4SLinus Torvalds 
782da678292SMichał Mirosław 	return ret;
7831da177e4SLinus Torvalds }
784da678292SMichał Mirosław #endif /* CONFIG_ATM_LANE */
7851da177e4SLinus Torvalds 
7861da177e4SLinus Torvalds /*
7871da177e4SLinus Torvalds  * Fill buffer with forwarding table records in
7881da177e4SLinus Torvalds  * the API format.
7891da177e4SLinus Torvalds  */
br_fdb_fillbuf(struct net_bridge * br,void * buf,unsigned long maxnum,unsigned long skip)7901da177e4SLinus Torvalds int br_fdb_fillbuf(struct net_bridge *br, void *buf,
7911da177e4SLinus Torvalds 		   unsigned long maxnum, unsigned long skip)
7921da177e4SLinus Torvalds {
7931da177e4SLinus Torvalds 	struct net_bridge_fdb_entry *f;
794eb793583SNikolay Aleksandrov 	struct __fdb_entry *fe = buf;
795eb793583SNikolay Aleksandrov 	int num = 0;
7961da177e4SLinus Torvalds 
7971da177e4SLinus Torvalds 	memset(buf, 0, maxnum*sizeof(struct __fdb_entry));
7981da177e4SLinus Torvalds 
7991da177e4SLinus Torvalds 	rcu_read_lock();
800eb793583SNikolay Aleksandrov 	hlist_for_each_entry_rcu(f, &br->fdb_list, fdb_node) {
8011da177e4SLinus Torvalds 		if (num >= maxnum)
802eb793583SNikolay Aleksandrov 			break;
8031da177e4SLinus Torvalds 
8041da177e4SLinus Torvalds 		if (has_expired(br, f))
8051da177e4SLinus Torvalds 			continue;
8061da177e4SLinus Torvalds 
80743598813Sstephen hemminger 		/* ignore pseudo entry for local MAC address */
80843598813Sstephen hemminger 		if (!f->dst)
80943598813Sstephen hemminger 			continue;
81043598813Sstephen hemminger 
8111da177e4SLinus Torvalds 		if (skip) {
8121da177e4SLinus Torvalds 			--skip;
8131da177e4SLinus Torvalds 			continue;
8141da177e4SLinus Torvalds 		}
8151da177e4SLinus Torvalds 
8161da177e4SLinus Torvalds 		/* convert from internal format to API */
817eb793583SNikolay Aleksandrov 		memcpy(fe->mac_addr, f->key.addr.addr, ETH_ALEN);
818ae4f8fcaSStephen Hemminger 
819ae4f8fcaSStephen Hemminger 		/* due to ABI compat need to split into hi/lo */
8201da177e4SLinus Torvalds 		fe->port_no = f->dst->port_no;
821ae4f8fcaSStephen Hemminger 		fe->port_hi = f->dst->port_no >> 8;
822ae4f8fcaSStephen Hemminger 
8236869c3b0SNikolay Aleksandrov 		fe->is_local = test_bit(BR_FDB_LOCAL, &f->flags);
82429e63fffSNikolay Aleksandrov 		if (!test_bit(BR_FDB_STATIC, &f->flags))
825a399a805SEric Dumazet 			fe->ageing_timer_value = jiffies_delta_to_clock_t(jiffies - f->updated);
8261da177e4SLinus Torvalds 		++fe;
8271da177e4SLinus Torvalds 		++num;
8281da177e4SLinus Torvalds 	}
8291da177e4SLinus Torvalds 	rcu_read_unlock();
8301da177e4SLinus Torvalds 
8311da177e4SLinus Torvalds 	return num;
8321da177e4SLinus Torvalds }
8331da177e4SLinus Torvalds 
83403e9b64bSstephen hemminger /* Add entry for local address of interface */
br_fdb_add_local(struct net_bridge * br,struct net_bridge_port * source,const unsigned char * addr,u16 vid)835f6814fdcSVladimir Oltean int br_fdb_add_local(struct net_bridge *br, struct net_bridge_port *source,
836bc9a25d2SVlad Yasevich 		     const unsigned char *addr, u16 vid)
8371da177e4SLinus Torvalds {
8381da177e4SLinus Torvalds 	int ret;
8391da177e4SLinus Torvalds 
8401da177e4SLinus Torvalds 	spin_lock_bh(&br->hash_lock);
8414731b6d6SVladimir Oltean 	ret = fdb_add_local(br, source, addr, vid);
8421da177e4SLinus Torvalds 	spin_unlock_bh(&br->hash_lock);
8431da177e4SLinus Torvalds 	return ret;
8441da177e4SLinus Torvalds }
8451da177e4SLinus Torvalds 
84631cbc39bSNikolay Aleksandrov /* returns true if the fdb was modified */
__fdb_mark_active(struct net_bridge_fdb_entry * fdb)84731cbc39bSNikolay Aleksandrov static bool __fdb_mark_active(struct net_bridge_fdb_entry *fdb)
84831cbc39bSNikolay Aleksandrov {
84931cbc39bSNikolay Aleksandrov 	return !!(test_bit(BR_FDB_NOTIFY_INACTIVE, &fdb->flags) &&
85031cbc39bSNikolay Aleksandrov 		  test_and_clear_bit(BR_FDB_NOTIFY_INACTIVE, &fdb->flags));
85131cbc39bSNikolay Aleksandrov }
85231cbc39bSNikolay Aleksandrov 
br_fdb_update(struct net_bridge * br,struct net_bridge_port * source,const unsigned char * addr,u16 vid,unsigned long flags)8531da177e4SLinus Torvalds void br_fdb_update(struct net_bridge *br, struct net_bridge_port *source,
854be0c5677SNikolay Aleksandrov 		   const unsigned char *addr, u16 vid, unsigned long flags)
8551da177e4SLinus Torvalds {
8561da177e4SLinus Torvalds 	struct net_bridge_fdb_entry *fdb;
8571da177e4SLinus Torvalds 
8581da177e4SLinus Torvalds 	/* some users want to always flood. */
8591da177e4SLinus Torvalds 	if (hold_time(br) == 0)
8601da177e4SLinus Torvalds 		return;
8611da177e4SLinus Torvalds 
862eb793583SNikolay Aleksandrov 	fdb = fdb_find_rcu(&br->fdb_hash_tbl, addr, vid);
8631da177e4SLinus Torvalds 	if (likely(fdb)) {
8641da177e4SLinus Torvalds 		/* attempt to update an entry for a local interface */
8656869c3b0SNikolay Aleksandrov 		if (unlikely(test_bit(BR_FDB_LOCAL, &fdb->flags))) {
8661da177e4SLinus Torvalds 			if (net_ratelimit())
867de1dfeefSRoopa Prabhu 				br_warn(br, "received packet on %s with own address as source address (addr:%pM, vlan:%u)\n",
868de1dfeefSRoopa Prabhu 					source->dev->name, addr, vid);
8691da177e4SLinus Torvalds 		} else {
870ca6d4480Sstephen hemminger 			unsigned long now = jiffies;
87131cbc39bSNikolay Aleksandrov 			bool fdb_modified = false;
87231cbc39bSNikolay Aleksandrov 
87331cbc39bSNikolay Aleksandrov 			if (now != fdb->updated) {
87431cbc39bSNikolay Aleksandrov 				fdb->updated = now;
87531cbc39bSNikolay Aleksandrov 				fdb_modified = __fdb_mark_active(fdb);
87631cbc39bSNikolay Aleksandrov 			}
877ca6d4480Sstephen hemminger 
8781da177e4SLinus Torvalds 			/* fastpath: update of existing entry */
8793e19ae7cSVladimir Oltean 			if (unlikely(source != READ_ONCE(fdb->dst) &&
880e0458d9aSNikolay Aleksandrov 				     !test_bit(BR_FDB_STICKY, &fdb->flags))) {
8816eb38bf8STobias Waldekranz 				br_switchdev_fdb_notify(br, fdb, RTM_DELNEIGH);
8823e19ae7cSVladimir Oltean 				WRITE_ONCE(fdb->dst, source);
883c65c7a30SJon Maxwell 				fdb_modified = true;
88458073b32SArkadi Sharshevsky 				/* Take over HW learned entry */
88558ec1ea6SNikolay Aleksandrov 				if (unlikely(test_bit(BR_FDB_ADDED_BY_EXT_LEARN,
88658ec1ea6SNikolay Aleksandrov 						      &fdb->flags)))
88758ec1ea6SNikolay Aleksandrov 					clear_bit(BR_FDB_ADDED_BY_EXT_LEARN,
888b5cd9f7cSNikolay Aleksandrov 						  &fdb->flags);
889a35ec8e3SHans J. Schultz 				/* Clear locked flag when roaming to an
890a35ec8e3SHans J. Schultz 				 * unlocked port.
891a35ec8e3SHans J. Schultz 				 */
892a35ec8e3SHans J. Schultz 				if (unlikely(test_bit(BR_FDB_LOCKED, &fdb->flags)))
893a35ec8e3SHans J. Schultz 					clear_bit(BR_FDB_LOCKED, &fdb->flags);
894c65c7a30SJon Maxwell 			}
89531cbc39bSNikolay Aleksandrov 
896be0c5677SNikolay Aleksandrov 			if (unlikely(test_bit(BR_FDB_ADDED_BY_USER, &flags)))
897ac3ca6afSNikolay Aleksandrov 				set_bit(BR_FDB_ADDED_BY_USER, &fdb->flags);
898e3cfddd5SRoopa Prabhu 			if (unlikely(fdb_modified)) {
899be0c5677SNikolay Aleksandrov 				trace_br_fdb_update(br, source, addr, vid, flags);
900161d82deSPetr Machata 				fdb_notify(br, fdb, RTM_NEWNEIGH, true);
9011da177e4SLinus Torvalds 			}
902e3cfddd5SRoopa Prabhu 		}
9031da177e4SLinus Torvalds 	} else {
904f8ae737dSStephen Hemminger 		spin_lock(&br->hash_lock);
905be0c5677SNikolay Aleksandrov 		fdb = fdb_create(br, source, addr, vid, flags);
906a5642ab4SToshiaki Makita 		if (fdb) {
907be0c5677SNikolay Aleksandrov 			trace_br_fdb_update(br, source, addr, vid, flags);
908161d82deSPetr Machata 			fdb_notify(br, fdb, RTM_NEWNEIGH, true);
909f58ee4e1Sstephen hemminger 		}
9101da177e4SLinus Torvalds 		/* else  we lose race and someone else inserts
9111da177e4SLinus Torvalds 		 * it first, don't bother updating
9121da177e4SLinus Torvalds 		 */
913f8ae737dSStephen Hemminger 		spin_unlock(&br->hash_lock);
9141da177e4SLinus Torvalds 	}
9151da177e4SLinus Torvalds }
916b078f0dfSstephen hemminger 
917b078f0dfSstephen hemminger /* Dump information about entries, in response to GETNEIGH */
br_fdb_dump(struct sk_buff * skb,struct netlink_callback * cb,struct net_device * dev,struct net_device * filter_dev,int * idx)91877162022SJohn Fastabend int br_fdb_dump(struct sk_buff *skb,
91977162022SJohn Fastabend 		struct netlink_callback *cb,
92077162022SJohn Fastabend 		struct net_device *dev,
9215d5eacb3SJamal Hadi Salim 		struct net_device *filter_dev,
922d297653dSRoopa Prabhu 		int *idx)
923b078f0dfSstephen hemminger {
924b078f0dfSstephen hemminger 	struct net_bridge *br = netdev_priv(dev);
925eb793583SNikolay Aleksandrov 	struct net_bridge_fdb_entry *f;
926d297653dSRoopa Prabhu 	int err = 0;
927b078f0dfSstephen hemminger 
928254ec036SKyungrok Chung 	if (!netif_is_bridge_master(dev))
929eb793583SNikolay Aleksandrov 		return err;
930b078f0dfSstephen hemminger 
931d297653dSRoopa Prabhu 	if (!filter_dev) {
932d297653dSRoopa Prabhu 		err = ndo_dflt_fdb_dump(skb, cb, dev, NULL, idx);
933d297653dSRoopa Prabhu 		if (err < 0)
934eb793583SNikolay Aleksandrov 			return err;
935d297653dSRoopa Prabhu 	}
9366cb69742SHubert Sokolowski 
937eb793583SNikolay Aleksandrov 	rcu_read_lock();
938eb793583SNikolay Aleksandrov 	hlist_for_each_entry_rcu(f, &br->fdb_list, fdb_node) {
939d297653dSRoopa Prabhu 		if (*idx < cb->args[2])
940b078f0dfSstephen hemminger 			goto skip;
941eb793583SNikolay Aleksandrov 		if (filter_dev && (!f->dst || f->dst->dev != filter_dev)) {
9425e6d2435SJamal Hadi Salim 			if (filter_dev != dev)
9435d5eacb3SJamal Hadi Salim 				goto skip;
9446cb69742SHubert Sokolowski 			/* !f->dst is a special case for bridge
9455e6d2435SJamal Hadi Salim 			 * It means the MAC belongs to the bridge
9465e6d2435SJamal Hadi Salim 			 * Therefore need a little more filtering
9475e6d2435SJamal Hadi Salim 			 * we only want to dump the !f->dst case
9485e6d2435SJamal Hadi Salim 			 */
9495e6d2435SJamal Hadi Salim 			if (f->dst)
9505e6d2435SJamal Hadi Salim 				goto skip;
9515e6d2435SJamal Hadi Salim 		}
9526cb69742SHubert Sokolowski 		if (!filter_dev && f->dst)
9536cb69742SHubert Sokolowski 			goto skip;
9545d5eacb3SJamal Hadi Salim 
955472681d5SMINOURA Makoto / 箕浦 真 		err = fdb_fill_info(skb, br, f,
95615e47304SEric W. Biederman 				    NETLINK_CB(cb->skb).portid,
957b078f0dfSstephen hemminger 				    cb->nlh->nlmsg_seq,
958b078f0dfSstephen hemminger 				    RTM_NEWNEIGH,
959472681d5SMINOURA Makoto / 箕浦 真 				    NLM_F_MULTI);
960d297653dSRoopa Prabhu 		if (err < 0)
961eb793583SNikolay Aleksandrov 			break;
962b078f0dfSstephen hemminger skip:
963d297653dSRoopa Prabhu 		*idx += 1;
964b078f0dfSstephen hemminger 	}
965eb793583SNikolay Aleksandrov 	rcu_read_unlock();
966b078f0dfSstephen hemminger 
967d297653dSRoopa Prabhu 	return err;
968b078f0dfSstephen hemminger }
96936fd2b63Sstephen hemminger 
br_fdb_get(struct sk_buff * skb,struct nlattr * tb[],struct net_device * dev,const unsigned char * addr,u16 vid,u32 portid,u32 seq,struct netlink_ext_ack * extack)97047674562SRoopa Prabhu int br_fdb_get(struct sk_buff *skb,
97147674562SRoopa Prabhu 	       struct nlattr *tb[],
97247674562SRoopa Prabhu 	       struct net_device *dev,
97347674562SRoopa Prabhu 	       const unsigned char *addr,
97447674562SRoopa Prabhu 	       u16 vid, u32 portid, u32 seq,
97547674562SRoopa Prabhu 	       struct netlink_ext_ack *extack)
97647674562SRoopa Prabhu {
97747674562SRoopa Prabhu 	struct net_bridge *br = netdev_priv(dev);
97847674562SRoopa Prabhu 	struct net_bridge_fdb_entry *f;
97947674562SRoopa Prabhu 	int err = 0;
98047674562SRoopa Prabhu 
98147674562SRoopa Prabhu 	rcu_read_lock();
98247674562SRoopa Prabhu 	f = br_fdb_find_rcu(br, addr, vid);
98347674562SRoopa Prabhu 	if (!f) {
98447674562SRoopa Prabhu 		NL_SET_ERR_MSG(extack, "Fdb entry not found");
98547674562SRoopa Prabhu 		err = -ENOENT;
98647674562SRoopa Prabhu 		goto errout;
98747674562SRoopa Prabhu 	}
98847674562SRoopa Prabhu 
98947674562SRoopa Prabhu 	err = fdb_fill_info(skb, br, f, portid, seq,
99047674562SRoopa Prabhu 			    RTM_NEWNEIGH, 0);
99147674562SRoopa Prabhu errout:
99247674562SRoopa Prabhu 	rcu_read_unlock();
99347674562SRoopa Prabhu 	return err;
99447674562SRoopa Prabhu }
99547674562SRoopa Prabhu 
99631cbc39bSNikolay Aleksandrov /* returns true if the fdb is modified */
fdb_handle_notify(struct net_bridge_fdb_entry * fdb,u8 notify)99731cbc39bSNikolay Aleksandrov static bool fdb_handle_notify(struct net_bridge_fdb_entry *fdb, u8 notify)
99831cbc39bSNikolay Aleksandrov {
99931cbc39bSNikolay Aleksandrov 	bool modified = false;
100031cbc39bSNikolay Aleksandrov 
100131cbc39bSNikolay Aleksandrov 	/* allow to mark an entry as inactive, usually done on creation */
100231cbc39bSNikolay Aleksandrov 	if ((notify & FDB_NOTIFY_INACTIVE_BIT) &&
100331cbc39bSNikolay Aleksandrov 	    !test_and_set_bit(BR_FDB_NOTIFY_INACTIVE, &fdb->flags))
100431cbc39bSNikolay Aleksandrov 		modified = true;
100531cbc39bSNikolay Aleksandrov 
100631cbc39bSNikolay Aleksandrov 	if ((notify & FDB_NOTIFY_BIT) &&
100731cbc39bSNikolay Aleksandrov 	    !test_and_set_bit(BR_FDB_NOTIFY, &fdb->flags)) {
100831cbc39bSNikolay Aleksandrov 		/* enabled activity tracking */
100931cbc39bSNikolay Aleksandrov 		modified = true;
101031cbc39bSNikolay Aleksandrov 	} else if (!(notify & FDB_NOTIFY_BIT) &&
101131cbc39bSNikolay Aleksandrov 		   test_and_clear_bit(BR_FDB_NOTIFY, &fdb->flags)) {
101231cbc39bSNikolay Aleksandrov 		/* disabled activity tracking, clear notify state */
101331cbc39bSNikolay Aleksandrov 		clear_bit(BR_FDB_NOTIFY_INACTIVE, &fdb->flags);
101431cbc39bSNikolay Aleksandrov 		modified = true;
101531cbc39bSNikolay Aleksandrov 	}
101631cbc39bSNikolay Aleksandrov 
101731cbc39bSNikolay Aleksandrov 	return modified;
101831cbc39bSNikolay Aleksandrov }
101931cbc39bSNikolay Aleksandrov 
1020292d1398Sstephen hemminger /* Update (create or replace) forwarding database entry */
fdb_add_entry(struct net_bridge * br,struct net_bridge_port * source,const u8 * addr,struct ndmsg * ndm,u16 flags,u16 vid,struct nlattr * nfea_tb[])10217bb90c37SToshiaki Makita static int fdb_add_entry(struct net_bridge *br, struct net_bridge_port *source,
102231cbc39bSNikolay Aleksandrov 			 const u8 *addr, struct ndmsg *ndm, u16 flags, u16 vid,
102331cbc39bSNikolay Aleksandrov 			 struct nlattr *nfea_tb[])
102436fd2b63Sstephen hemminger {
10250592ff88SNikolay Aleksandrov 	bool is_sticky = !!(ndm->ndm_flags & NTF_STICKY);
1026b5f1d9ecSNikolay Aleksandrov 	bool refresh = !nfea_tb[NFEA_DONT_REFRESH];
102736fd2b63Sstephen hemminger 	struct net_bridge_fdb_entry *fdb;
10280592ff88SNikolay Aleksandrov 	u16 state = ndm->ndm_state;
1029b0a397fbSroopa 	bool modified = false;
103031cbc39bSNikolay Aleksandrov 	u8 notify = 0;
103136fd2b63Sstephen hemminger 
1032eb8d7baaSWilson Kok 	/* If the port cannot learn allow only local and static entries */
10337bb90c37SToshiaki Makita 	if (source && !(state & NUD_PERMANENT) && !(state & NUD_NOARP) &&
1034eb8d7baaSWilson Kok 	    !(source->state == BR_STATE_LEARNING ||
1035eb8d7baaSWilson Kok 	      source->state == BR_STATE_FORWARDING))
1036eb8d7baaSWilson Kok 		return -EPERM;
1037eb8d7baaSWilson Kok 
10387bb90c37SToshiaki Makita 	if (!source && !(state & NUD_PERMANENT)) {
10397bb90c37SToshiaki Makita 		pr_info("bridge: RTM_NEWNEIGH %s without NUD_PERMANENT\n",
10407bb90c37SToshiaki Makita 			br->dev->name);
10417bb90c37SToshiaki Makita 		return -EINVAL;
10427bb90c37SToshiaki Makita 	}
10437bb90c37SToshiaki Makita 
1044435f2e7cSNikolay Aleksandrov 	if (is_sticky && (state & NUD_PERMANENT))
1045435f2e7cSNikolay Aleksandrov 		return -EINVAL;
1046435f2e7cSNikolay Aleksandrov 
104731cbc39bSNikolay Aleksandrov 	if (nfea_tb[NFEA_ACTIVITY_NOTIFY]) {
104831cbc39bSNikolay Aleksandrov 		notify = nla_get_u8(nfea_tb[NFEA_ACTIVITY_NOTIFY]);
104931cbc39bSNikolay Aleksandrov 		if ((notify & ~BR_FDB_NOTIFY_SETTABLE_BITS) ||
105031cbc39bSNikolay Aleksandrov 		    (notify & BR_FDB_NOTIFY_SETTABLE_BITS) == FDB_NOTIFY_INACTIVE_BIT)
105131cbc39bSNikolay Aleksandrov 			return -EINVAL;
105231cbc39bSNikolay Aleksandrov 	}
105331cbc39bSNikolay Aleksandrov 
1054bfd0aeacSNikolay Aleksandrov 	fdb = br_fdb_find(br, addr, vid);
105564af1bacSstephen hemminger 	if (fdb == NULL) {
105664af1bacSstephen hemminger 		if (!(flags & NLM_F_CREATE))
105764af1bacSstephen hemminger 			return -ENOENT;
105836fd2b63Sstephen hemminger 
10593fb01a31SNikolay Aleksandrov 		fdb = fdb_create(br, source, addr, vid, 0);
106036fd2b63Sstephen hemminger 		if (!fdb)
106136fd2b63Sstephen hemminger 			return -ENOMEM;
1062b0a397fbSroopa 
1063b0a397fbSroopa 		modified = true;
106464af1bacSstephen hemminger 	} else {
106564af1bacSstephen hemminger 		if (flags & NLM_F_EXCL)
106664af1bacSstephen hemminger 			return -EEXIST;
1067b0a397fbSroopa 
10683e19ae7cSVladimir Oltean 		if (READ_ONCE(fdb->dst) != source) {
10693e19ae7cSVladimir Oltean 			WRITE_ONCE(fdb->dst, source);
1070b0a397fbSroopa 			modified = true;
1071b0a397fbSroopa 		}
107264af1bacSstephen hemminger 	}
107336fd2b63Sstephen hemminger 
10743741873bSRoopa Prabhu 	if (fdb_to_nud(br, fdb) != state) {
1075145beee8SVlad Yasevich 		if (state & NUD_PERMANENT) {
10766869c3b0SNikolay Aleksandrov 			set_bit(BR_FDB_LOCAL, &fdb->flags);
107729e63fffSNikolay Aleksandrov 			if (!test_and_set_bit(BR_FDB_STATIC, &fdb->flags))
1078020ec6baSJiri Pirko 				fdb_add_hw_addr(br, addr);
1079145beee8SVlad Yasevich 		} else if (state & NUD_NOARP) {
10806869c3b0SNikolay Aleksandrov 			clear_bit(BR_FDB_LOCAL, &fdb->flags);
108129e63fffSNikolay Aleksandrov 			if (!test_and_set_bit(BR_FDB_STATIC, &fdb->flags))
1082020ec6baSJiri Pirko 				fdb_add_hw_addr(br, addr);
1083145beee8SVlad Yasevich 		} else {
10846869c3b0SNikolay Aleksandrov 			clear_bit(BR_FDB_LOCAL, &fdb->flags);
108529e63fffSNikolay Aleksandrov 			if (test_and_clear_bit(BR_FDB_STATIC, &fdb->flags))
1086020ec6baSJiri Pirko 				fdb_del_hw_addr(br, addr);
1087145beee8SVlad Yasevich 		}
1088292d1398Sstephen hemminger 
1089b0a397fbSroopa 		modified = true;
1090b0a397fbSroopa 	}
1091435f2e7cSNikolay Aleksandrov 
1092e0458d9aSNikolay Aleksandrov 	if (is_sticky != test_bit(BR_FDB_STICKY, &fdb->flags)) {
1093e0458d9aSNikolay Aleksandrov 		change_bit(BR_FDB_STICKY, &fdb->flags);
1094435f2e7cSNikolay Aleksandrov 		modified = true;
1095435f2e7cSNikolay Aleksandrov 	}
1096435f2e7cSNikolay Aleksandrov 
1097a35ec8e3SHans J. Schultz 	if (test_and_clear_bit(BR_FDB_LOCKED, &fdb->flags))
1098a35ec8e3SHans J. Schultz 		modified = true;
1099a35ec8e3SHans J. Schultz 
110031cbc39bSNikolay Aleksandrov 	if (fdb_handle_notify(fdb, notify))
110131cbc39bSNikolay Aleksandrov 		modified = true;
110231cbc39bSNikolay Aleksandrov 
1103ac3ca6afSNikolay Aleksandrov 	set_bit(BR_FDB_ADDED_BY_USER, &fdb->flags);
1104b0a397fbSroopa 
1105b0a397fbSroopa 	fdb->used = jiffies;
1106b0a397fbSroopa 	if (modified) {
1107b5f1d9ecSNikolay Aleksandrov 		if (refresh)
1108b0a397fbSroopa 			fdb->updated = jiffies;
1109161d82deSPetr Machata 		fdb_notify(br, fdb, RTM_NEWNEIGH, true);
1110292d1398Sstephen hemminger 	}
1111292d1398Sstephen hemminger 
111236fd2b63Sstephen hemminger 	return 0;
111336fd2b63Sstephen hemminger }
111436fd2b63Sstephen hemminger 
__br_fdb_add(struct ndmsg * ndm,struct net_bridge * br,struct net_bridge_port * p,const unsigned char * addr,u16 nlh_flags,u16 vid,struct nlattr * nfea_tb[],struct netlink_ext_ack * extack)11157bb90c37SToshiaki Makita static int __br_fdb_add(struct ndmsg *ndm, struct net_bridge *br,
11167bb90c37SToshiaki Makita 			struct net_bridge_port *p, const unsigned char *addr,
11170541a629SVladimir Oltean 			u16 nlh_flags, u16 vid, struct nlattr *nfea_tb[],
11180541a629SVladimir Oltean 			struct netlink_ext_ack *extack)
11191690be63SVlad Yasevich {
11201690be63SVlad Yasevich 	int err = 0;
11211690be63SVlad Yasevich 
11221690be63SVlad Yasevich 	if (ndm->ndm_flags & NTF_USE) {
11237bb90c37SToshiaki Makita 		if (!p) {
11247bb90c37SToshiaki Makita 			pr_info("bridge: RTM_NEWNEIGH %s with NTF_USE is not supported\n",
11257bb90c37SToshiaki Makita 				br->dev->name);
11267bb90c37SToshiaki Makita 			return -EINVAL;
11277bb90c37SToshiaki Makita 		}
11285d1fcaf3SNikolay Aleksandrov 		if (!nbp_state_should_learn(p))
11295d1fcaf3SNikolay Aleksandrov 			return 0;
11305d1fcaf3SNikolay Aleksandrov 
1131c4c832f8SNikolay Aleksandrov 		local_bh_disable();
11321690be63SVlad Yasevich 		rcu_read_lock();
1133be0c5677SNikolay Aleksandrov 		br_fdb_update(br, p, addr, vid, BIT(BR_FDB_ADDED_BY_USER));
11341690be63SVlad Yasevich 		rcu_read_unlock();
1135c4c832f8SNikolay Aleksandrov 		local_bh_enable();
1136eb100e0eSNikolay Aleksandrov 	} else if (ndm->ndm_flags & NTF_EXT_LEARNED) {
11370541a629SVladimir Oltean 		if (!p && !(ndm->ndm_state & NUD_PERMANENT)) {
11380541a629SVladimir Oltean 			NL_SET_ERR_MSG_MOD(extack,
11390541a629SVladimir Oltean 					   "FDB entry towards bridge must be permanent");
11400541a629SVladimir Oltean 			return -EINVAL;
11410541a629SVladimir Oltean 		}
114227fabd02SHans J. Schultz 		err = br_fdb_external_learn_add(br, p, addr, vid, false, true);
11431690be63SVlad Yasevich 	} else {
11447bb90c37SToshiaki Makita 		spin_lock_bh(&br->hash_lock);
114531cbc39bSNikolay Aleksandrov 		err = fdb_add_entry(br, p, addr, ndm, nlh_flags, vid, nfea_tb);
11467bb90c37SToshiaki Makita 		spin_unlock_bh(&br->hash_lock);
11471690be63SVlad Yasevich 	}
11481690be63SVlad Yasevich 
11491690be63SVlad Yasevich 	return err;
11501690be63SVlad Yasevich }
11511690be63SVlad Yasevich 
115231cbc39bSNikolay Aleksandrov static const struct nla_policy br_nda_fdb_pol[NFEA_MAX + 1] = {
115331cbc39bSNikolay Aleksandrov 	[NFEA_ACTIVITY_NOTIFY]	= { .type = NLA_U8 },
1154b5f1d9ecSNikolay Aleksandrov 	[NFEA_DONT_REFRESH]	= { .type = NLA_FLAG },
115531cbc39bSNikolay Aleksandrov };
115631cbc39bSNikolay Aleksandrov 
115736fd2b63Sstephen hemminger /* Add new permanent fdb entry with RTM_NEWNEIGH */
br_fdb_add(struct ndmsg * ndm,struct nlattr * tb[],struct net_device * dev,const unsigned char * addr,u16 vid,u16 nlh_flags,struct netlink_ext_ack * extack)1158edc7d573Sstephen hemminger int br_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
1159edc7d573Sstephen hemminger 	       struct net_device *dev,
116087b0984eSPetr Machata 	       const unsigned char *addr, u16 vid, u16 nlh_flags,
116187b0984eSPetr Machata 	       struct netlink_ext_ack *extack)
116236fd2b63Sstephen hemminger {
116331cbc39bSNikolay Aleksandrov 	struct nlattr *nfea_tb[NFEA_MAX + 1], *attr;
11642594e906SNikolay Aleksandrov 	struct net_bridge_vlan_group *vg;
11653741873bSRoopa Prabhu 	struct net_bridge_port *p = NULL;
11662594e906SNikolay Aleksandrov 	struct net_bridge_vlan *v;
11673741873bSRoopa Prabhu 	struct net_bridge *br = NULL;
1168a35ec8e3SHans J. Schultz 	u32 ext_flags = 0;
116977162022SJohn Fastabend 	int err = 0;
117036fd2b63Sstephen hemminger 
1171b74fd306SRoopa Prabhu 	trace_br_fdb_add(ndm, dev, addr, vid, nlh_flags);
1172b74fd306SRoopa Prabhu 
1173292d1398Sstephen hemminger 	if (!(ndm->ndm_state & (NUD_PERMANENT|NUD_NOARP|NUD_REACHABLE))) {
1174292d1398Sstephen hemminger 		pr_info("bridge: RTM_NEWNEIGH with invalid state %#x\n", ndm->ndm_state);
1175292d1398Sstephen hemminger 		return -EINVAL;
1176292d1398Sstephen hemminger 	}
1177292d1398Sstephen hemminger 
1178537f7f84SStephen Hemminger 	if (is_zero_ether_addr(addr)) {
1179537f7f84SStephen Hemminger 		pr_info("bridge: RTM_NEWNEIGH with invalid ether address\n");
1180537f7f84SStephen Hemminger 		return -EINVAL;
1181537f7f84SStephen Hemminger 	}
1182537f7f84SStephen Hemminger 
1183254ec036SKyungrok Chung 	if (netif_is_bridge_master(dev)) {
11843741873bSRoopa Prabhu 		br = netdev_priv(dev);
11853741873bSRoopa Prabhu 		vg = br_vlan_group(br);
11863741873bSRoopa Prabhu 	} else {
118736fd2b63Sstephen hemminger 		p = br_port_get_rtnl(dev);
11883741873bSRoopa Prabhu 		if (!p) {
118936fd2b63Sstephen hemminger 			pr_info("bridge: RTM_NEWNEIGH %s not a bridge port\n",
119036fd2b63Sstephen hemminger 				dev->name);
119136fd2b63Sstephen hemminger 			return -EINVAL;
119236fd2b63Sstephen hemminger 		}
11937bb90c37SToshiaki Makita 		br = p->br;
11942594e906SNikolay Aleksandrov 		vg = nbp_vlan_group(p);
11953741873bSRoopa Prabhu 	}
11963741873bSRoopa Prabhu 
1197a35ec8e3SHans J. Schultz 	if (tb[NDA_FLAGS_EXT])
1198a35ec8e3SHans J. Schultz 		ext_flags = nla_get_u32(tb[NDA_FLAGS_EXT]);
1199a35ec8e3SHans J. Schultz 
1200a35ec8e3SHans J. Schultz 	if (ext_flags & NTF_EXT_LOCKED) {
1201a35ec8e3SHans J. Schultz 		NL_SET_ERR_MSG_MOD(extack, "Cannot add FDB entry with \"locked\" flag set");
1202a35ec8e3SHans J. Schultz 		return -EINVAL;
1203a35ec8e3SHans J. Schultz 	}
1204a35ec8e3SHans J. Schultz 
120531cbc39bSNikolay Aleksandrov 	if (tb[NDA_FDB_EXT_ATTRS]) {
120631cbc39bSNikolay Aleksandrov 		attr = tb[NDA_FDB_EXT_ATTRS];
120731cbc39bSNikolay Aleksandrov 		err = nla_parse_nested(nfea_tb, NFEA_MAX, attr,
120831cbc39bSNikolay Aleksandrov 				       br_nda_fdb_pol, extack);
120931cbc39bSNikolay Aleksandrov 		if (err)
121031cbc39bSNikolay Aleksandrov 			return err;
121131cbc39bSNikolay Aleksandrov 	} else {
121231cbc39bSNikolay Aleksandrov 		memset(nfea_tb, 0, sizeof(struct nlattr *) * (NFEA_MAX + 1));
121331cbc39bSNikolay Aleksandrov 	}
121431cbc39bSNikolay Aleksandrov 
1215f6f6424bSJiri Pirko 	if (vid) {
12162594e906SNikolay Aleksandrov 		v = br_vlan_find(vg, vid);
12173741873bSRoopa Prabhu 		if (!v || !br_vlan_should_use(v)) {
12183741873bSRoopa Prabhu 			pr_info("bridge: RTM_NEWNEIGH with unconfigured vlan %d on %s\n", vid, dev->name);
12191690be63SVlad Yasevich 			return -EINVAL;
1220292d1398Sstephen hemminger 		}
122136fd2b63Sstephen hemminger 
12221690be63SVlad Yasevich 		/* VID was specified, so use it. */
12230541a629SVladimir Oltean 		err = __br_fdb_add(ndm, br, p, addr, nlh_flags, vid, nfea_tb,
12240541a629SVladimir Oltean 				   extack);
12251690be63SVlad Yasevich 	} else {
12260541a629SVladimir Oltean 		err = __br_fdb_add(ndm, br, p, addr, nlh_flags, 0, nfea_tb,
12270541a629SVladimir Oltean 				   extack);
12282594e906SNikolay Aleksandrov 		if (err || !vg || !vg->num_vlans)
12291690be63SVlad Yasevich 			goto out;
12301690be63SVlad Yasevich 
12311690be63SVlad Yasevich 		/* We have vlans configured on this port and user didn't
12321690be63SVlad Yasevich 		 * specify a VLAN.  To be nice, add/update entry for every
12331690be63SVlad Yasevich 		 * vlan on this port.
12341690be63SVlad Yasevich 		 */
12352594e906SNikolay Aleksandrov 		list_for_each_entry(v, &vg->vlan_list, vlist) {
12363741873bSRoopa Prabhu 			if (!br_vlan_should_use(v))
12373741873bSRoopa Prabhu 				continue;
123831cbc39bSNikolay Aleksandrov 			err = __br_fdb_add(ndm, br, p, addr, nlh_flags, v->vid,
12390541a629SVladimir Oltean 					   nfea_tb, extack);
12401690be63SVlad Yasevich 			if (err)
12411690be63SVlad Yasevich 				goto out;
12421690be63SVlad Yasevich 		}
12431690be63SVlad Yasevich 	}
12441690be63SVlad Yasevich 
12451690be63SVlad Yasevich out:
12461690be63SVlad Yasevich 	return err;
12471690be63SVlad Yasevich }
12481690be63SVlad Yasevich 
fdb_delete_by_addr_and_port(struct net_bridge * br,const struct net_bridge_port * p,const u8 * addr,u16 vlan)12495019ab50SNikolay Aleksandrov static int fdb_delete_by_addr_and_port(struct net_bridge *br,
12505019ab50SNikolay Aleksandrov 				       const struct net_bridge_port *p,
12518c86f967SNikolay Aleksandrov 				       const u8 *addr, u16 vlan)
12521690be63SVlad Yasevich {
12531690be63SVlad Yasevich 	struct net_bridge_fdb_entry *fdb;
12541690be63SVlad Yasevich 
1255bfd0aeacSNikolay Aleksandrov 	fdb = br_fdb_find(br, addr, vlan);
12563e19ae7cSVladimir Oltean 	if (!fdb || READ_ONCE(fdb->dst) != p)
12571690be63SVlad Yasevich 		return -ENOENT;
12581690be63SVlad Yasevich 
1259161d82deSPetr Machata 	fdb_delete(br, fdb, true);
12605019ab50SNikolay Aleksandrov 
12611690be63SVlad Yasevich 	return 0;
12621690be63SVlad Yasevich }
12631690be63SVlad Yasevich 
__br_fdb_delete(struct net_bridge * br,const struct net_bridge_port * p,const unsigned char * addr,u16 vid)12645019ab50SNikolay Aleksandrov static int __br_fdb_delete(struct net_bridge *br,
12655019ab50SNikolay Aleksandrov 			   const struct net_bridge_port *p,
12661690be63SVlad Yasevich 			   const unsigned char *addr, u16 vid)
12671690be63SVlad Yasevich {
12681690be63SVlad Yasevich 	int err;
12691690be63SVlad Yasevich 
12705019ab50SNikolay Aleksandrov 	spin_lock_bh(&br->hash_lock);
12715019ab50SNikolay Aleksandrov 	err = fdb_delete_by_addr_and_port(br, p, addr, vid);
12725019ab50SNikolay Aleksandrov 	spin_unlock_bh(&br->hash_lock);
12731690be63SVlad Yasevich 
127436fd2b63Sstephen hemminger 	return err;
127536fd2b63Sstephen hemminger }
127636fd2b63Sstephen hemminger 
127736fd2b63Sstephen hemminger /* Remove neighbor entry with RTM_DELNEIGH */
br_fdb_delete(struct ndmsg * ndm,struct nlattr * tb[],struct net_device * dev,const unsigned char * addr,u16 vid,struct netlink_ext_ack * extack)12781690be63SVlad Yasevich int br_fdb_delete(struct ndmsg *ndm, struct nlattr *tb[],
12791690be63SVlad Yasevich 		  struct net_device *dev,
1280ca4567f1SAlaa Mohamed 		  const unsigned char *addr, u16 vid,
1281ca4567f1SAlaa Mohamed 		  struct netlink_ext_ack *extack)
128236fd2b63Sstephen hemminger {
12832594e906SNikolay Aleksandrov 	struct net_bridge_vlan_group *vg;
12843741873bSRoopa Prabhu 	struct net_bridge_port *p = NULL;
12852594e906SNikolay Aleksandrov 	struct net_bridge_vlan *v;
12865019ab50SNikolay Aleksandrov 	struct net_bridge *br;
128736fd2b63Sstephen hemminger 	int err;
128836fd2b63Sstephen hemminger 
1289254ec036SKyungrok Chung 	if (netif_is_bridge_master(dev)) {
12903741873bSRoopa Prabhu 		br = netdev_priv(dev);
12913741873bSRoopa Prabhu 		vg = br_vlan_group(br);
12923741873bSRoopa Prabhu 	} else {
129336fd2b63Sstephen hemminger 		p = br_port_get_rtnl(dev);
12943741873bSRoopa Prabhu 		if (!p) {
129536fd2b63Sstephen hemminger 			pr_info("bridge: RTM_DELNEIGH %s not a bridge port\n",
129636fd2b63Sstephen hemminger 				dev->name);
129736fd2b63Sstephen hemminger 			return -EINVAL;
129836fd2b63Sstephen hemminger 		}
12992594e906SNikolay Aleksandrov 		vg = nbp_vlan_group(p);
13005019ab50SNikolay Aleksandrov 		br = p->br;
13013741873bSRoopa Prabhu 	}
13023741873bSRoopa Prabhu 
1303f6f6424bSJiri Pirko 	if (vid) {
13042594e906SNikolay Aleksandrov 		v = br_vlan_find(vg, vid);
13052594e906SNikolay Aleksandrov 		if (!v) {
13063741873bSRoopa Prabhu 			pr_info("bridge: RTM_DELNEIGH with unconfigured vlan %d on %s\n", vid, dev->name);
13071690be63SVlad Yasevich 			return -EINVAL;
13081690be63SVlad Yasevich 		}
130936fd2b63Sstephen hemminger 
13105019ab50SNikolay Aleksandrov 		err = __br_fdb_delete(br, p, addr, vid);
13111690be63SVlad Yasevich 	} else {
131225d3b493SToshiaki Makita 		err = -ENOENT;
13135019ab50SNikolay Aleksandrov 		err &= __br_fdb_delete(br, p, addr, 0);
13142594e906SNikolay Aleksandrov 		if (!vg || !vg->num_vlans)
13155019ab50SNikolay Aleksandrov 			return err;
13161690be63SVlad Yasevich 
13173741873bSRoopa Prabhu 		list_for_each_entry(v, &vg->vlan_list, vlist) {
13183741873bSRoopa Prabhu 			if (!br_vlan_should_use(v))
13193741873bSRoopa Prabhu 				continue;
13205019ab50SNikolay Aleksandrov 			err &= __br_fdb_delete(br, p, addr, v->vid);
13211690be63SVlad Yasevich 		}
13223741873bSRoopa Prabhu 	}
13235019ab50SNikolay Aleksandrov 
132436fd2b63Sstephen hemminger 	return err;
132536fd2b63Sstephen hemminger }
13268db24af7SVlad Yasevich 
br_fdb_sync_static(struct net_bridge * br,struct net_bridge_port * p)13278db24af7SVlad Yasevich int br_fdb_sync_static(struct net_bridge *br, struct net_bridge_port *p)
13288db24af7SVlad Yasevich {
1329eb793583SNikolay Aleksandrov 	struct net_bridge_fdb_entry *f, *tmp;
1330367dc658SGeert Uytterhoeven 	int err = 0;
13318db24af7SVlad Yasevich 
13328db24af7SVlad Yasevich 	ASSERT_RTNL();
13338db24af7SVlad Yasevich 
1334eb793583SNikolay Aleksandrov 	/* the key here is that static entries change only under rtnl */
1335eb793583SNikolay Aleksandrov 	rcu_read_lock();
1336eb793583SNikolay Aleksandrov 	hlist_for_each_entry_rcu(f, &br->fdb_list, fdb_node) {
13378db24af7SVlad Yasevich 		/* We only care for static entries */
133829e63fffSNikolay Aleksandrov 		if (!test_bit(BR_FDB_STATIC, &f->flags))
13398db24af7SVlad Yasevich 			continue;
1340eb793583SNikolay Aleksandrov 		err = dev_uc_add(p->dev, f->key.addr.addr);
13418db24af7SVlad Yasevich 		if (err)
13428db24af7SVlad Yasevich 			goto rollback;
13438db24af7SVlad Yasevich 	}
1344eb793583SNikolay Aleksandrov done:
1345eb793583SNikolay Aleksandrov 	rcu_read_unlock();
1346eb793583SNikolay Aleksandrov 
1347eb793583SNikolay Aleksandrov 	return err;
13488db24af7SVlad Yasevich 
13498db24af7SVlad Yasevich rollback:
1350eb793583SNikolay Aleksandrov 	hlist_for_each_entry_rcu(tmp, &br->fdb_list, fdb_node) {
13518db24af7SVlad Yasevich 		/* We only care for static entries */
135229e63fffSNikolay Aleksandrov 		if (!test_bit(BR_FDB_STATIC, &tmp->flags))
13538db24af7SVlad Yasevich 			continue;
1354eb793583SNikolay Aleksandrov 		if (tmp == f)
1355eb793583SNikolay Aleksandrov 			break;
1356eb793583SNikolay Aleksandrov 		dev_uc_del(p->dev, tmp->key.addr.addr);
1357eb793583SNikolay Aleksandrov 	}
13588db24af7SVlad Yasevich 
1359eb793583SNikolay Aleksandrov 	goto done;
13608db24af7SVlad Yasevich }
13618db24af7SVlad Yasevich 
br_fdb_unsync_static(struct net_bridge * br,struct net_bridge_port * p)13628db24af7SVlad Yasevich void br_fdb_unsync_static(struct net_bridge *br, struct net_bridge_port *p)
13638db24af7SVlad Yasevich {
1364eb793583SNikolay Aleksandrov 	struct net_bridge_fdb_entry *f;
13658db24af7SVlad Yasevich 
13668db24af7SVlad Yasevich 	ASSERT_RTNL();
13678db24af7SVlad Yasevich 
1368eb793583SNikolay Aleksandrov 	rcu_read_lock();
1369eb793583SNikolay Aleksandrov 	hlist_for_each_entry_rcu(f, &br->fdb_list, fdb_node) {
13708db24af7SVlad Yasevich 		/* We only care for static entries */
137129e63fffSNikolay Aleksandrov 		if (!test_bit(BR_FDB_STATIC, &f->flags))
13728db24af7SVlad Yasevich 			continue;
13738db24af7SVlad Yasevich 
1374eb793583SNikolay Aleksandrov 		dev_uc_del(p->dev, f->key.addr.addr);
13758db24af7SVlad Yasevich 	}
1376eb793583SNikolay Aleksandrov 	rcu_read_unlock();
13778db24af7SVlad Yasevich }
1378cf6b8e1eSScott Feldman 
br_fdb_external_learn_add(struct net_bridge * br,struct net_bridge_port * p,const unsigned char * addr,u16 vid,bool locked,bool swdev_notify)13793aeb6617SJiri Pirko int br_fdb_external_learn_add(struct net_bridge *br, struct net_bridge_port *p,
138027fabd02SHans J. Schultz 			      const unsigned char *addr, u16 vid, bool locked,
1381161d82deSPetr Machata 			      bool swdev_notify)
1382cf6b8e1eSScott Feldman {
1383cf6b8e1eSScott Feldman 	struct net_bridge_fdb_entry *fdb;
13847597b266SNikolay Aleksandrov 	bool modified = false;
1385cf6b8e1eSScott Feldman 	int err = 0;
1386cf6b8e1eSScott Feldman 
1387b74fd306SRoopa Prabhu 	trace_br_fdb_external_learn_add(br, p, addr, vid);
1388b74fd306SRoopa Prabhu 
138927fabd02SHans J. Schultz 	if (locked && (!p || !(p->flags & BR_PORT_MAB)))
139027fabd02SHans J. Schultz 		return -EINVAL;
139127fabd02SHans J. Schultz 
1392cf6b8e1eSScott Feldman 	spin_lock_bh(&br->hash_lock);
1393cf6b8e1eSScott Feldman 
1394bfd0aeacSNikolay Aleksandrov 	fdb = br_fdb_find(br, addr, vid);
1395cf6b8e1eSScott Feldman 	if (!fdb) {
139631f1155bSNikolay Aleksandrov 		unsigned long flags = BIT(BR_FDB_ADDED_BY_EXT_LEARN);
139731f1155bSNikolay Aleksandrov 
139831f1155bSNikolay Aleksandrov 		if (swdev_notify)
139931f1155bSNikolay Aleksandrov 			flags |= BIT(BR_FDB_ADDED_BY_USER);
14000541a629SVladimir Oltean 
140145a68787SNikolay Aleksandrov 		if (!p)
14020541a629SVladimir Oltean 			flags |= BIT(BR_FDB_LOCAL);
14030541a629SVladimir Oltean 
140427fabd02SHans J. Schultz 		if (locked)
140527fabd02SHans J. Schultz 			flags |= BIT(BR_FDB_LOCKED);
140627fabd02SHans J. Schultz 
140731f1155bSNikolay Aleksandrov 		fdb = fdb_create(br, p, addr, vid, flags);
1408cf6b8e1eSScott Feldman 		if (!fdb) {
1409cf6b8e1eSScott Feldman 			err = -ENOMEM;
1410cf6b8e1eSScott Feldman 			goto err_unlock;
1411cf6b8e1eSScott Feldman 		}
1412161d82deSPetr Machata 		fdb_notify(br, fdb, RTM_NEWNEIGH, swdev_notify);
14137597b266SNikolay Aleksandrov 	} else {
141427fabd02SHans J. Schultz 		if (locked &&
141527fabd02SHans J. Schultz 		    (!test_bit(BR_FDB_LOCKED, &fdb->flags) ||
141627fabd02SHans J. Schultz 		     READ_ONCE(fdb->dst) != p)) {
141727fabd02SHans J. Schultz 			err = -EINVAL;
141827fabd02SHans J. Schultz 			goto err_unlock;
141927fabd02SHans J. Schultz 		}
142027fabd02SHans J. Schultz 
14217597b266SNikolay Aleksandrov 		fdb->updated = jiffies;
14227597b266SNikolay Aleksandrov 
14233e19ae7cSVladimir Oltean 		if (READ_ONCE(fdb->dst) != p) {
14243e19ae7cSVladimir Oltean 			WRITE_ONCE(fdb->dst, p);
14257597b266SNikolay Aleksandrov 			modified = true;
14267597b266SNikolay Aleksandrov 		}
14277597b266SNikolay Aleksandrov 
1428*c6c535a4SJonas Gorski 		if (test_and_set_bit(BR_FDB_ADDED_BY_EXT_LEARN, &fdb->flags)) {
1429cf6b8e1eSScott Feldman 			/* Refresh entry */
14307597b266SNikolay Aleksandrov 			fdb->used = jiffies;
1431*c6c535a4SJonas Gorski 		} else {
14327597b266SNikolay Aleksandrov 			modified = true;
14337597b266SNikolay Aleksandrov 		}
14347597b266SNikolay Aleksandrov 
143527fabd02SHans J. Schultz 		if (locked != test_bit(BR_FDB_LOCKED, &fdb->flags)) {
143627fabd02SHans J. Schultz 			change_bit(BR_FDB_LOCKED, &fdb->flags);
143727fabd02SHans J. Schultz 			modified = true;
143827fabd02SHans J. Schultz 		}
143927fabd02SHans J. Schultz 
1440710ae728SIdo Schimmel 		if (swdev_notify)
1441ac3ca6afSNikolay Aleksandrov 			set_bit(BR_FDB_ADDED_BY_USER, &fdb->flags);
1442710ae728SIdo Schimmel 
144345a68787SNikolay Aleksandrov 		if (!p)
14440541a629SVladimir Oltean 			set_bit(BR_FDB_LOCAL, &fdb->flags);
14450541a629SVladimir Oltean 
14467597b266SNikolay Aleksandrov 		if (modified)
1447161d82deSPetr Machata 			fdb_notify(br, fdb, RTM_NEWNEIGH, swdev_notify);
1448cf6b8e1eSScott Feldman 	}
1449cf6b8e1eSScott Feldman 
1450cf6b8e1eSScott Feldman err_unlock:
1451cf6b8e1eSScott Feldman 	spin_unlock_bh(&br->hash_lock);
1452cf6b8e1eSScott Feldman 
1453cf6b8e1eSScott Feldman 	return err;
1454cf6b8e1eSScott Feldman }
1455cf6b8e1eSScott Feldman 
br_fdb_external_learn_del(struct net_bridge * br,struct net_bridge_port * p,const unsigned char * addr,u16 vid,bool swdev_notify)14563aeb6617SJiri Pirko int br_fdb_external_learn_del(struct net_bridge *br, struct net_bridge_port *p,
1457161d82deSPetr Machata 			      const unsigned char *addr, u16 vid,
1458161d82deSPetr Machata 			      bool swdev_notify)
1459cf6b8e1eSScott Feldman {
1460cf6b8e1eSScott Feldman 	struct net_bridge_fdb_entry *fdb;
1461cf6b8e1eSScott Feldman 	int err = 0;
1462cf6b8e1eSScott Feldman 
1463cf6b8e1eSScott Feldman 	spin_lock_bh(&br->hash_lock);
1464cf6b8e1eSScott Feldman 
1465bfd0aeacSNikolay Aleksandrov 	fdb = br_fdb_find(br, addr, vid);
1466b5cd9f7cSNikolay Aleksandrov 	if (fdb && test_bit(BR_FDB_ADDED_BY_EXT_LEARN, &fdb->flags))
1467161d82deSPetr Machata 		fdb_delete(br, fdb, swdev_notify);
1468cf6b8e1eSScott Feldman 	else
1469cf6b8e1eSScott Feldman 		err = -ENOENT;
1470cf6b8e1eSScott Feldman 
1471cf6b8e1eSScott Feldman 	spin_unlock_bh(&br->hash_lock);
1472cf6b8e1eSScott Feldman 
1473cf6b8e1eSScott Feldman 	return err;
1474cf6b8e1eSScott Feldman }
14759fe8bcecSArkadi Sharshevsky 
br_fdb_offloaded_set(struct net_bridge * br,struct net_bridge_port * p,const unsigned char * addr,u16 vid,bool offloaded)14769fe8bcecSArkadi Sharshevsky void br_fdb_offloaded_set(struct net_bridge *br, struct net_bridge_port *p,
1477e9ba0fbcSIdo Schimmel 			  const unsigned char *addr, u16 vid, bool offloaded)
14789fe8bcecSArkadi Sharshevsky {
14799fe8bcecSArkadi Sharshevsky 	struct net_bridge_fdb_entry *fdb;
14809fe8bcecSArkadi Sharshevsky 
14819fe8bcecSArkadi Sharshevsky 	spin_lock_bh(&br->hash_lock);
14829fe8bcecSArkadi Sharshevsky 
14839fe8bcecSArkadi Sharshevsky 	fdb = br_fdb_find(br, addr, vid);
1484d38c6e3dSNikolay Aleksandrov 	if (fdb && offloaded != test_bit(BR_FDB_OFFLOADED, &fdb->flags))
1485d38c6e3dSNikolay Aleksandrov 		change_bit(BR_FDB_OFFLOADED, &fdb->flags);
14869fe8bcecSArkadi Sharshevsky 
14879fe8bcecSArkadi Sharshevsky 	spin_unlock_bh(&br->hash_lock);
14889fe8bcecSArkadi Sharshevsky }
148943920edfSPetr Machata 
br_fdb_clear_offload(const struct net_device * dev,u16 vid)149043920edfSPetr Machata void br_fdb_clear_offload(const struct net_device *dev, u16 vid)
149143920edfSPetr Machata {
149243920edfSPetr Machata 	struct net_bridge_fdb_entry *f;
149343920edfSPetr Machata 	struct net_bridge_port *p;
149443920edfSPetr Machata 
149543920edfSPetr Machata 	ASSERT_RTNL();
149643920edfSPetr Machata 
149743920edfSPetr Machata 	p = br_port_get_rtnl(dev);
149843920edfSPetr Machata 	if (!p)
149943920edfSPetr Machata 		return;
150043920edfSPetr Machata 
150143920edfSPetr Machata 	spin_lock_bh(&p->br->hash_lock);
150243920edfSPetr Machata 	hlist_for_each_entry(f, &p->br->fdb_list, fdb_node) {
150343920edfSPetr Machata 		if (f->dst == p && f->key.vlan_id == vid)
1504d38c6e3dSNikolay Aleksandrov 			clear_bit(BR_FDB_OFFLOADED, &f->flags);
150543920edfSPetr Machata 	}
150643920edfSPetr Machata 	spin_unlock_bh(&p->br->hash_lock);
150743920edfSPetr Machata }
150843920edfSPetr Machata EXPORT_SYMBOL_GPL(br_fdb_clear_offload);
1509