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