bridge: switchdev: Allow device drivers to install locked FDB entries

Bugzilla: https://bugzilla.redhat.com/2184372

commit 27fabd02abf30a9df9899f92d467591c7eabb1ba
Author: Hans J. Schultz <netdev@kapio-technology.com>
Date:   Tue Nov 8 11:47:08 2022 +0100

    bridge: switchdev: Allow device drivers to install locked FDB entries
    
    When the bridge is offloaded to hardware, FDB entries are learned and
    aged-out by the hardware. Some device drivers synchronize the hardware
    and software FDBs by generating switchdev events towards the bridge.
    
    When a port is locked, the hardware must not learn autonomously, as
    otherwise any host will blindly gain authorization. Instead, the
    hardware should generate events regarding hosts that are trying to gain
    authorization and their MAC addresses should be notified by the device
    driver as locked FDB entries towards the bridge driver.
    
    Allow device drivers to notify the bridge driver about such entries by
    extending the 'switchdev_notifier_fdb_info' structure with the 'locked'
    bit. The bit can only be set by device drivers and not by the bridge
    driver.
    
    Prevent a locked entry from being installed if MAB is not enabled on the
    bridge port.
    
    If an entry already exists in the bridge driver, reject the locked entry
    if the current entry does not have the "locked" flag set or if it points
    to a different port. The same semantics are implemented in the software
    data path.
    
    Signed-off-by: Hans J. Schultz <netdev@kapio-technology.com>
    Signed-off-by: Ido Schimmel <idosch@nvidia.com>
    Reviewed-by: Petr Machata <petrm@nvidia.com>
    Signed-off-by: Petr Machata <petrm@nvidia.com>
    Reviewed-by: Vladimir Oltean <vladimir.oltean@nxp.com>
    Acked-by: Nikolay Aleksandrov <razor@blackwall.org>
    Signed-off-by: Jakub Kicinski <kuba@kernel.org>

Signed-off-by: Íñigo Huguet <ihuguet@redhat.com>
This commit is contained in:
Íñigo Huguet 2023-05-11 09:20:12 +02:00
parent 2888f76d0e
commit ab6e9c38e4
5 changed files with 28 additions and 4 deletions

View File

@ -248,6 +248,7 @@ struct switchdev_notifier_fdb_info {
u16 vid;
u8 added_by_user:1,
is_local:1,
locked:1,
offloaded:1;
};

View File

@ -166,7 +166,8 @@ static int br_switchdev_event(struct notifier_block *unused,
case SWITCHDEV_FDB_ADD_TO_BRIDGE:
fdb_info = ptr;
err = br_fdb_external_learn_add(br, p, fdb_info->addr,
fdb_info->vid, false);
fdb_info->vid,
fdb_info->locked, false);
if (err) {
err = notifier_from_errno(err);
break;

View File

@ -1139,7 +1139,7 @@ static int __br_fdb_add(struct ndmsg *ndm, struct net_bridge *br,
"FDB entry towards bridge must be permanent");
return -EINVAL;
}
err = br_fdb_external_learn_add(br, p, addr, vid, true);
err = br_fdb_external_learn_add(br, p, addr, vid, false, true);
} else {
spin_lock_bh(&br->hash_lock);
err = fdb_add_entry(br, p, addr, ndm, nlh_flags, vid, nfea_tb);
@ -1376,7 +1376,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,
const unsigned char *addr, u16 vid,
const unsigned char *addr, u16 vid, bool locked,
bool swdev_notify)
{
struct net_bridge_fdb_entry *fdb;
@ -1385,6 +1385,9 @@ int br_fdb_external_learn_add(struct net_bridge *br, struct net_bridge_port *p,
trace_br_fdb_external_learn_add(br, p, addr, vid);
if (locked && (!p || !(p->flags & BR_PORT_MAB)))
return -EINVAL;
spin_lock_bh(&br->hash_lock);
fdb = br_fdb_find(br, addr, vid);
@ -1397,6 +1400,9 @@ int br_fdb_external_learn_add(struct net_bridge *br, struct net_bridge_port *p,
if (!p)
flags |= BIT(BR_FDB_LOCAL);
if (locked)
flags |= BIT(BR_FDB_LOCKED);
fdb = fdb_create(br, p, addr, vid, flags);
if (!fdb) {
err = -ENOMEM;
@ -1404,6 +1410,13 @@ int br_fdb_external_learn_add(struct net_bridge *br, struct net_bridge_port *p,
}
fdb_notify(br, fdb, RTM_NEWNEIGH, swdev_notify);
} else {
if (locked &&
(!test_bit(BR_FDB_LOCKED, &fdb->flags) ||
READ_ONCE(fdb->dst) != p)) {
err = -EINVAL;
goto err_unlock;
}
fdb->updated = jiffies;
if (READ_ONCE(fdb->dst) != p) {
@ -1420,6 +1433,11 @@ int br_fdb_external_learn_add(struct net_bridge *br, struct net_bridge_port *p,
modified = true;
}
if (locked != test_bit(BR_FDB_LOCKED, &fdb->flags)) {
change_bit(BR_FDB_LOCKED, &fdb->flags);
modified = true;
}
if (swdev_notify)
set_bit(BR_FDB_ADDED_BY_USER, &fdb->flags);

View File

@ -810,7 +810,7 @@ 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);
int br_fdb_external_learn_add(struct net_bridge *br, struct net_bridge_port *p,
const unsigned char *addr, u16 vid,
bool swdev_notify);
bool locked, bool swdev_notify);
int br_fdb_external_learn_del(struct net_bridge *br, struct net_bridge_port *p,
const unsigned char *addr, u16 vid,
bool swdev_notify);

View File

@ -136,6 +136,7 @@ static void br_switchdev_fdb_populate(struct net_bridge *br,
item->added_by_user = test_bit(BR_FDB_ADDED_BY_USER, &fdb->flags);
item->offloaded = test_bit(BR_FDB_OFFLOADED, &fdb->flags);
item->is_local = test_bit(BR_FDB_LOCAL, &fdb->flags);
item->locked = false;
item->info.dev = (!p || item->is_local) ? br->dev : p->dev;
item->info.ctx = ctx;
}
@ -146,6 +147,9 @@ br_switchdev_fdb_notify(struct net_bridge *br,
{
struct switchdev_notifier_fdb_info item;
if (test_bit(BR_FDB_LOCKED, &fdb->flags))
return;
br_switchdev_fdb_populate(br, &item, fdb, NULL);
switch (type) {