Commit 45a68787 authored by Nikolay Aleksandrov's avatar Nikolay Aleksandrov Committed by Jakub Kicinski

net: bridge: fix flags interpretation for extern learn fdb entries

Ignore fdb flags when adding port extern learn entries and always set
BR_FDB_LOCAL flag when adding bridge extern learn entries. This is
closest to the behaviour we had before and avoids breaking any use cases
which were allowed.

This patch fixes iproute2 calls which assume NUD_PERMANENT and were
allowed before, example:
$ bridge fdb add 00:11:22:33:44:55 dev swp1 extern_learn

Extern learn entries are allowed to roam, but do not expire, so static
or dynamic flags make no sense for them.

Also add a comment for future reference.

Fixes: eb100e0e ("net: bridge: allow to add externally learned entries from user-space")
Fixes: 0541a629 ("net: bridge: validate the NUD_PERMANENT bit when adding an extern_learn FDB entry")
Reviewed-by: default avatarIdo Schimmel <idosch@nvidia.com>
Tested-by: default avatarIdo Schimmel <idosch@nvidia.com>
Signed-off-by: default avatarNikolay Aleksandrov <nikolay@nvidia.com>
Reviewed-by: default avatarVladimir Oltean <vladimir.oltean@nxp.com>
Link: https://lore.kernel.org/r/20210810110010.43859-1-razor@blackwall.orgSigned-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent 2e273b09
...@@ -66,8 +66,11 @@ enum { ...@@ -66,8 +66,11 @@ enum {
#define NUD_NONE 0x00 #define NUD_NONE 0x00
/* NUD_NOARP & NUD_PERMANENT are pseudostates, they never change /* NUD_NOARP & NUD_PERMANENT are pseudostates, they never change
and make no address resolution or NUD. * and make no address resolution or NUD.
NUD_PERMANENT also cannot be deleted by garbage collectors. * NUD_PERMANENT also cannot be deleted by garbage collectors.
* When NTF_EXT_LEARNED is set for a bridge fdb entry the different cache entry
* states don't make sense and thus are ignored. Such entries don't age and
* can roam.
*/ */
struct nda_cacheinfo { struct nda_cacheinfo {
......
...@@ -166,8 +166,7 @@ static int br_switchdev_event(struct notifier_block *unused, ...@@ -166,8 +166,7 @@ static int br_switchdev_event(struct notifier_block *unused,
case SWITCHDEV_FDB_ADD_TO_BRIDGE: case SWITCHDEV_FDB_ADD_TO_BRIDGE:
fdb_info = ptr; fdb_info = ptr;
err = br_fdb_external_learn_add(br, p, fdb_info->addr, err = br_fdb_external_learn_add(br, p, fdb_info->addr,
fdb_info->vid, fdb_info->vid, false);
fdb_info->is_local, false);
if (err) { if (err) {
err = notifier_from_errno(err); err = notifier_from_errno(err);
break; break;
......
...@@ -1044,10 +1044,7 @@ static int __br_fdb_add(struct ndmsg *ndm, struct net_bridge *br, ...@@ -1044,10 +1044,7 @@ static int __br_fdb_add(struct ndmsg *ndm, struct net_bridge *br,
"FDB entry towards bridge must be permanent"); "FDB entry towards bridge must be permanent");
return -EINVAL; return -EINVAL;
} }
err = br_fdb_external_learn_add(br, p, addr, vid, true);
err = br_fdb_external_learn_add(br, p, addr, vid,
ndm->ndm_state & NUD_PERMANENT,
true);
} else { } else {
spin_lock_bh(&br->hash_lock); spin_lock_bh(&br->hash_lock);
err = fdb_add_entry(br, p, addr, ndm, nlh_flags, vid, nfea_tb); err = fdb_add_entry(br, p, addr, ndm, nlh_flags, vid, nfea_tb);
...@@ -1275,7 +1272,7 @@ void br_fdb_unsync_static(struct net_bridge *br, struct net_bridge_port *p) ...@@ -1275,7 +1272,7 @@ void br_fdb_unsync_static(struct net_bridge *br, struct net_bridge_port *p)
} }
int br_fdb_external_learn_add(struct net_bridge *br, struct net_bridge_port *p, int br_fdb_external_learn_add(struct net_bridge *br, struct net_bridge_port *p,
const unsigned char *addr, u16 vid, bool is_local, const unsigned char *addr, u16 vid,
bool swdev_notify) bool swdev_notify)
{ {
struct net_bridge_fdb_entry *fdb; struct net_bridge_fdb_entry *fdb;
...@@ -1293,7 +1290,7 @@ int br_fdb_external_learn_add(struct net_bridge *br, struct net_bridge_port *p, ...@@ -1293,7 +1290,7 @@ int br_fdb_external_learn_add(struct net_bridge *br, struct net_bridge_port *p,
if (swdev_notify) if (swdev_notify)
flags |= BIT(BR_FDB_ADDED_BY_USER); flags |= BIT(BR_FDB_ADDED_BY_USER);
if (is_local) if (!p)
flags |= BIT(BR_FDB_LOCAL); flags |= BIT(BR_FDB_LOCAL);
fdb = fdb_create(br, p, addr, vid, flags); fdb = fdb_create(br, p, addr, vid, flags);
...@@ -1322,7 +1319,7 @@ int br_fdb_external_learn_add(struct net_bridge *br, struct net_bridge_port *p, ...@@ -1322,7 +1319,7 @@ int br_fdb_external_learn_add(struct net_bridge *br, struct net_bridge_port *p,
if (swdev_notify) if (swdev_notify)
set_bit(BR_FDB_ADDED_BY_USER, &fdb->flags); set_bit(BR_FDB_ADDED_BY_USER, &fdb->flags);
if (is_local) if (!p)
set_bit(BR_FDB_LOCAL, &fdb->flags); set_bit(BR_FDB_LOCAL, &fdb->flags);
if (modified) if (modified)
......
...@@ -711,7 +711,7 @@ int br_fdb_get(struct sk_buff *skb, struct nlattr *tb[], struct net_device *dev, ...@@ -711,7 +711,7 @@ int br_fdb_get(struct sk_buff *skb, struct nlattr *tb[], struct net_device *dev,
int br_fdb_sync_static(struct net_bridge *br, struct net_bridge_port *p); int br_fdb_sync_static(struct net_bridge *br, struct net_bridge_port *p);
void br_fdb_unsync_static(struct net_bridge *br, struct net_bridge_port *p); void br_fdb_unsync_static(struct net_bridge *br, struct net_bridge_port *p);
int br_fdb_external_learn_add(struct net_bridge *br, struct net_bridge_port *p, int br_fdb_external_learn_add(struct net_bridge *br, struct net_bridge_port *p,
const unsigned char *addr, u16 vid, bool is_local, const unsigned char *addr, u16 vid,
bool swdev_notify); bool swdev_notify);
int br_fdb_external_learn_del(struct net_bridge *br, struct net_bridge_port *p, int br_fdb_external_learn_del(struct net_bridge *br, struct net_bridge_port *p,
const unsigned char *addr, u16 vid, const unsigned char *addr, u16 vid,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment