Commit 6487c819 authored by David S. Miller's avatar David S. Miller

Merge branch 'br-fdb-refactoring'

Vladimir Oltean says:

====================
Bridge FDB refactoring

This series refactors the br_fdb.c, br_switchdev.c and switchdev.c files
to offer the same level of functionality with a bit less code, and to
clarify the purpose of some functions.

No functional change intended.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents e334df1d 716a30a9
...@@ -299,28 +299,16 @@ void switchdev_port_fwd_mark_set(struct net_device *dev, ...@@ -299,28 +299,16 @@ void switchdev_port_fwd_mark_set(struct net_device *dev,
struct net_device *group_dev, struct net_device *group_dev,
bool joining); bool joining);
int switchdev_handle_fdb_add_to_device(struct net_device *dev, int switchdev_handle_fdb_event_to_device(struct net_device *dev, unsigned long event,
const struct switchdev_notifier_fdb_info *fdb_info, const struct switchdev_notifier_fdb_info *fdb_info,
bool (*check_cb)(const struct net_device *dev), bool (*check_cb)(const struct net_device *dev),
bool (*foreign_dev_check_cb)(const struct net_device *dev, bool (*foreign_dev_check_cb)(const struct net_device *dev,
const struct net_device *foreign_dev), const struct net_device *foreign_dev),
int (*add_cb)(struct net_device *dev, int (*mod_cb)(struct net_device *dev, struct net_device *orig_dev,
const struct net_device *orig_dev, const void *ctx, unsigned long event, const void *ctx,
const struct switchdev_notifier_fdb_info *fdb_info), const struct switchdev_notifier_fdb_info *fdb_info),
int (*lag_add_cb)(struct net_device *dev, int (*lag_mod_cb)(struct net_device *dev, struct net_device *orig_dev,
const struct net_device *orig_dev, const void *ctx, unsigned long event, const void *ctx,
const struct switchdev_notifier_fdb_info *fdb_info));
int switchdev_handle_fdb_del_to_device(struct net_device *dev,
const struct switchdev_notifier_fdb_info *fdb_info,
bool (*check_cb)(const struct net_device *dev),
bool (*foreign_dev_check_cb)(const struct net_device *dev,
const struct net_device *foreign_dev),
int (*del_cb)(struct net_device *dev,
const struct net_device *orig_dev, const void *ctx,
const struct switchdev_notifier_fdb_info *fdb_info),
int (*lag_del_cb)(struct net_device *dev,
const struct net_device *orig_dev, const void *ctx,
const struct switchdev_notifier_fdb_info *fdb_info)); const struct switchdev_notifier_fdb_info *fdb_info));
int switchdev_handle_port_obj_add(struct net_device *dev, int switchdev_handle_port_obj_add(struct net_device *dev,
...@@ -426,32 +414,16 @@ call_switchdev_blocking_notifiers(unsigned long val, ...@@ -426,32 +414,16 @@ call_switchdev_blocking_notifiers(unsigned long val,
} }
static inline int static inline int
switchdev_handle_fdb_add_to_device(struct net_device *dev, switchdev_handle_fdb_event_to_device(struct net_device *dev, unsigned long event,
const struct switchdev_notifier_fdb_info *fdb_info,
bool (*check_cb)(const struct net_device *dev),
bool (*foreign_dev_check_cb)(const struct net_device *dev,
const struct net_device *foreign_dev),
int (*add_cb)(struct net_device *dev,
const struct net_device *orig_dev, const void *ctx,
const struct switchdev_notifier_fdb_info *fdb_info),
int (*lag_add_cb)(struct net_device *dev,
const struct net_device *orig_dev, const void *ctx,
const struct switchdev_notifier_fdb_info *fdb_info))
{
return 0;
}
static inline int
switchdev_handle_fdb_del_to_device(struct net_device *dev,
const struct switchdev_notifier_fdb_info *fdb_info, const struct switchdev_notifier_fdb_info *fdb_info,
bool (*check_cb)(const struct net_device *dev), bool (*check_cb)(const struct net_device *dev),
bool (*foreign_dev_check_cb)(const struct net_device *dev, bool (*foreign_dev_check_cb)(const struct net_device *dev,
const struct net_device *foreign_dev), const struct net_device *foreign_dev),
int (*del_cb)(struct net_device *dev, int (*mod_cb)(struct net_device *dev, struct net_device *orig_dev,
const struct net_device *orig_dev, const void *ctx, unsigned long event, const void *ctx,
const struct switchdev_notifier_fdb_info *fdb_info), const struct switchdev_notifier_fdb_info *fdb_info),
int (*lag_del_cb)(struct net_device *dev, int (*lag_mod_cb)(struct net_device *dev, struct net_device *orig_dev,
const struct net_device *orig_dev, const void *ctx, unsigned long event, const void *ctx,
const struct switchdev_notifier_fdb_info *fdb_info)) const struct switchdev_notifier_fdb_info *fdb_info))
{ {
return 0; return 0;
......
This diff is collapsed.
...@@ -670,7 +670,7 @@ int br_add_if(struct net_bridge *br, struct net_device *dev, ...@@ -670,7 +670,7 @@ int br_add_if(struct net_bridge *br, struct net_device *dev,
else else
netdev_set_rx_headroom(dev, br_hr); netdev_set_rx_headroom(dev, br_hr);
if (br_fdb_insert(br, p, dev->dev_addr, 0)) if (br_fdb_add_local(br, p, dev->dev_addr, 0))
netdev_err(dev, "failed insert local address bridge forwarding table\n"); netdev_err(dev, "failed insert local address bridge forwarding table\n");
if (br->dev->addr_assign_type != NET_ADDR_SET) { if (br->dev->addr_assign_type != NET_ADDR_SET) {
......
...@@ -767,8 +767,8 @@ struct net_bridge_fdb_entry *br_fdb_find_rcu(struct net_bridge *br, ...@@ -767,8 +767,8 @@ struct net_bridge_fdb_entry *br_fdb_find_rcu(struct net_bridge *br,
int br_fdb_test_addr(struct net_device *dev, unsigned char *addr); int br_fdb_test_addr(struct net_device *dev, unsigned char *addr);
int br_fdb_fillbuf(struct net_bridge *br, void *buf, unsigned long count, int br_fdb_fillbuf(struct net_bridge *br, void *buf, unsigned long count,
unsigned long off); unsigned long off);
int br_fdb_insert(struct net_bridge *br, struct net_bridge_port *source, int br_fdb_add_local(struct net_bridge *br, struct net_bridge_port *source,
const unsigned char *addr, u16 vid); const unsigned char *addr, u16 vid);
void br_fdb_update(struct net_bridge *br, struct net_bridge_port *source, void br_fdb_update(struct net_bridge *br, struct net_bridge_port *source,
const unsigned char *addr, u16 vid, unsigned long flags); const unsigned char *addr, u16 vid, unsigned long flags);
...@@ -792,8 +792,6 @@ int br_fdb_external_learn_del(struct net_bridge *br, struct net_bridge_port *p, ...@@ -792,8 +792,6 @@ int br_fdb_external_learn_del(struct net_bridge *br, struct net_bridge_port *p,
bool swdev_notify); bool swdev_notify);
void br_fdb_offloaded_set(struct net_bridge *br, struct net_bridge_port *p, void br_fdb_offloaded_set(struct net_bridge *br, struct net_bridge_port *p,
const unsigned char *addr, u16 vid, bool offloaded); const unsigned char *addr, u16 vid, bool offloaded);
int br_fdb_replay(const struct net_device *br_dev, const void *ctx, bool adding,
struct notifier_block *nb);
/* br_forward.c */ /* br_forward.c */
enum br_pkt_type { enum br_pkt_type {
......
...@@ -122,28 +122,38 @@ int br_switchdev_set_port_flag(struct net_bridge_port *p, ...@@ -122,28 +122,38 @@ int br_switchdev_set_port_flag(struct net_bridge_port *p,
return 0; return 0;
} }
static void br_switchdev_fdb_populate(struct net_bridge *br,
struct switchdev_notifier_fdb_info *item,
const struct net_bridge_fdb_entry *fdb,
const void *ctx)
{
const struct net_bridge_port *p = READ_ONCE(fdb->dst);
item->addr = fdb->key.addr.addr;
item->vid = fdb->key.vlan_id;
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->info.dev = (!p || item->is_local) ? br->dev : p->dev;
item->info.ctx = ctx;
}
void void
br_switchdev_fdb_notify(struct net_bridge *br, br_switchdev_fdb_notify(struct net_bridge *br,
const struct net_bridge_fdb_entry *fdb, int type) const struct net_bridge_fdb_entry *fdb, int type)
{ {
const struct net_bridge_port *dst = READ_ONCE(fdb->dst); struct switchdev_notifier_fdb_info item;
struct switchdev_notifier_fdb_info info = {
.addr = fdb->key.addr.addr, br_switchdev_fdb_populate(br, &item, fdb, NULL);
.vid = fdb->key.vlan_id,
.added_by_user = test_bit(BR_FDB_ADDED_BY_USER, &fdb->flags),
.is_local = test_bit(BR_FDB_LOCAL, &fdb->flags),
.offloaded = test_bit(BR_FDB_OFFLOADED, &fdb->flags),
};
struct net_device *dev = (!dst || info.is_local) ? br->dev : dst->dev;
switch (type) { switch (type) {
case RTM_DELNEIGH: case RTM_DELNEIGH:
call_switchdev_notifiers(SWITCHDEV_FDB_DEL_TO_DEVICE, call_switchdev_notifiers(SWITCHDEV_FDB_DEL_TO_DEVICE,
dev, &info.info, NULL); item.info.dev, &item.info, NULL);
break; break;
case RTM_NEWNEIGH: case RTM_NEWNEIGH:
call_switchdev_notifiers(SWITCHDEV_FDB_ADD_TO_DEVICE, call_switchdev_notifiers(SWITCHDEV_FDB_ADD_TO_DEVICE,
dev, &info.info, NULL); item.info.dev, &item.info, NULL);
break; break;
} }
} }
...@@ -270,6 +280,53 @@ static void nbp_switchdev_del(struct net_bridge_port *p) ...@@ -270,6 +280,53 @@ static void nbp_switchdev_del(struct net_bridge_port *p)
} }
} }
static int br_fdb_replay_one(struct net_bridge *br, struct notifier_block *nb,
const struct net_bridge_fdb_entry *fdb,
unsigned long action, const void *ctx)
{
struct switchdev_notifier_fdb_info item;
int err;
br_switchdev_fdb_populate(br, &item, fdb, ctx);
err = nb->notifier_call(nb, action, &item);
return notifier_to_errno(err);
}
static int br_fdb_replay(const struct net_device *br_dev, const void *ctx,
bool adding, struct notifier_block *nb)
{
struct net_bridge_fdb_entry *fdb;
struct net_bridge *br;
unsigned long action;
int err = 0;
if (!nb)
return 0;
if (!netif_is_bridge_master(br_dev))
return -EINVAL;
br = netdev_priv(br_dev);
if (adding)
action = SWITCHDEV_FDB_ADD_TO_DEVICE;
else
action = SWITCHDEV_FDB_DEL_TO_DEVICE;
rcu_read_lock();
hlist_for_each_entry_rcu(fdb, &br->fdb_list, fdb_node) {
err = br_fdb_replay_one(br, nb, fdb, action, ctx);
if (err)
break;
}
rcu_read_unlock();
return err;
}
static int nbp_switchdev_sync_objs(struct net_bridge_port *p, const void *ctx, static int nbp_switchdev_sync_objs(struct net_bridge_port *p, const void *ctx,
struct notifier_block *atomic_nb, struct notifier_block *atomic_nb,
struct notifier_block *blocking_nb, struct notifier_block *blocking_nb,
......
...@@ -293,7 +293,7 @@ static int __vlan_add(struct net_bridge_vlan *v, u16 flags, ...@@ -293,7 +293,7 @@ static int __vlan_add(struct net_bridge_vlan *v, u16 flags,
/* Add the dev mac and count the vlan only if it's usable */ /* Add the dev mac and count the vlan only if it's usable */
if (br_vlan_should_use(v)) { if (br_vlan_should_use(v)) {
err = br_fdb_insert(br, p, dev->dev_addr, v->vid); err = br_fdb_add_local(br, p, dev->dev_addr, v->vid);
if (err) { if (err) {
br_err(br, "failed insert local address into bridge forwarding table\n"); br_err(br, "failed insert local address into bridge forwarding table\n");
goto out_filt; goto out_filt;
...@@ -683,8 +683,7 @@ static int br_vlan_add_existing(struct net_bridge *br, ...@@ -683,8 +683,7 @@ static int br_vlan_add_existing(struct net_bridge *br,
goto err_flags; goto err_flags;
} }
/* It was only kept for port vlans, now make it real */ /* It was only kept for port vlans, now make it real */
err = br_fdb_insert(br, NULL, br->dev->dev_addr, err = br_fdb_add_local(br, NULL, br->dev->dev_addr, vlan->vid);
vlan->vid);
if (err) { if (err) {
br_err(br, "failed to insert local address into bridge forwarding table\n"); br_err(br, "failed to insert local address into bridge forwarding table\n");
goto err_fdb_insert; goto err_fdb_insert;
......
...@@ -2468,10 +2468,9 @@ static bool dsa_foreign_dev_check(const struct net_device *dev, ...@@ -2468,10 +2468,9 @@ static bool dsa_foreign_dev_check(const struct net_device *dev,
} }
static int dsa_slave_fdb_event(struct net_device *dev, static int dsa_slave_fdb_event(struct net_device *dev,
const struct net_device *orig_dev, struct net_device *orig_dev,
const void *ctx, unsigned long event, const void *ctx,
const struct switchdev_notifier_fdb_info *fdb_info, const struct switchdev_notifier_fdb_info *fdb_info)
unsigned long event)
{ {
struct dsa_switchdev_event_work *switchdev_work; struct dsa_switchdev_event_work *switchdev_work;
struct dsa_port *dp = dsa_slave_to_port(dev); struct dsa_port *dp = dsa_slave_to_port(dev);
...@@ -2525,24 +2524,6 @@ static int dsa_slave_fdb_event(struct net_device *dev, ...@@ -2525,24 +2524,6 @@ static int dsa_slave_fdb_event(struct net_device *dev,
return 0; return 0;
} }
static int
dsa_slave_fdb_add_to_device(struct net_device *dev,
const struct net_device *orig_dev, const void *ctx,
const struct switchdev_notifier_fdb_info *fdb_info)
{
return dsa_slave_fdb_event(dev, orig_dev, ctx, fdb_info,
SWITCHDEV_FDB_ADD_TO_DEVICE);
}
static int
dsa_slave_fdb_del_to_device(struct net_device *dev,
const struct net_device *orig_dev, const void *ctx,
const struct switchdev_notifier_fdb_info *fdb_info)
{
return dsa_slave_fdb_event(dev, orig_dev, ctx, fdb_info,
SWITCHDEV_FDB_DEL_TO_DEVICE);
}
/* Called under rcu_read_lock() */ /* Called under rcu_read_lock() */
static int dsa_slave_switchdev_event(struct notifier_block *unused, static int dsa_slave_switchdev_event(struct notifier_block *unused,
unsigned long event, void *ptr) unsigned long event, void *ptr)
...@@ -2557,18 +2538,12 @@ static int dsa_slave_switchdev_event(struct notifier_block *unused, ...@@ -2557,18 +2538,12 @@ static int dsa_slave_switchdev_event(struct notifier_block *unused,
dsa_slave_port_attr_set); dsa_slave_port_attr_set);
return notifier_from_errno(err); return notifier_from_errno(err);
case SWITCHDEV_FDB_ADD_TO_DEVICE: case SWITCHDEV_FDB_ADD_TO_DEVICE:
err = switchdev_handle_fdb_add_to_device(dev, ptr,
dsa_slave_dev_check,
dsa_foreign_dev_check,
dsa_slave_fdb_add_to_device,
NULL);
return notifier_from_errno(err);
case SWITCHDEV_FDB_DEL_TO_DEVICE: case SWITCHDEV_FDB_DEL_TO_DEVICE:
err = switchdev_handle_fdb_del_to_device(dev, ptr, err = switchdev_handle_fdb_event_to_device(dev, event, ptr,
dsa_slave_dev_check, dsa_slave_dev_check,
dsa_foreign_dev_check, dsa_foreign_dev_check,
dsa_slave_fdb_del_to_device, dsa_slave_fdb_event,
NULL); NULL);
return notifier_from_errno(err); return notifier_from_errno(err);
default: default:
return NOTIFY_DONE; return NOTIFY_DONE;
......
...@@ -428,17 +428,17 @@ switchdev_lower_dev_find(struct net_device *dev, ...@@ -428,17 +428,17 @@ switchdev_lower_dev_find(struct net_device *dev,
return switchdev_priv.lower_dev; return switchdev_priv.lower_dev;
} }
static int __switchdev_handle_fdb_add_to_device(struct net_device *dev, static int __switchdev_handle_fdb_event_to_device(struct net_device *dev,
const struct net_device *orig_dev, struct net_device *orig_dev, unsigned long event,
const struct switchdev_notifier_fdb_info *fdb_info, const struct switchdev_notifier_fdb_info *fdb_info,
bool (*check_cb)(const struct net_device *dev), bool (*check_cb)(const struct net_device *dev),
bool (*foreign_dev_check_cb)(const struct net_device *dev, bool (*foreign_dev_check_cb)(const struct net_device *dev,
const struct net_device *foreign_dev), const struct net_device *foreign_dev),
int (*add_cb)(struct net_device *dev, int (*mod_cb)(struct net_device *dev, struct net_device *orig_dev,
const struct net_device *orig_dev, const void *ctx, unsigned long event, const void *ctx,
const struct switchdev_notifier_fdb_info *fdb_info), const struct switchdev_notifier_fdb_info *fdb_info),
int (*lag_add_cb)(struct net_device *dev, int (*lag_mod_cb)(struct net_device *dev, struct net_device *orig_dev,
const struct net_device *orig_dev, const void *ctx, unsigned long event, const void *ctx,
const struct switchdev_notifier_fdb_info *fdb_info)) const struct switchdev_notifier_fdb_info *fdb_info))
{ {
const struct switchdev_notifier_info *info = &fdb_info->info; const struct switchdev_notifier_info *info = &fdb_info->info;
...@@ -447,17 +447,17 @@ static int __switchdev_handle_fdb_add_to_device(struct net_device *dev, ...@@ -447,17 +447,17 @@ static int __switchdev_handle_fdb_add_to_device(struct net_device *dev,
int err = -EOPNOTSUPP; int err = -EOPNOTSUPP;
if (check_cb(dev)) if (check_cb(dev))
return add_cb(dev, orig_dev, info->ctx, fdb_info); return mod_cb(dev, orig_dev, event, info->ctx, fdb_info);
if (netif_is_lag_master(dev)) { if (netif_is_lag_master(dev)) {
if (!switchdev_lower_dev_find(dev, check_cb, foreign_dev_check_cb)) if (!switchdev_lower_dev_find(dev, check_cb, foreign_dev_check_cb))
goto maybe_bridged_with_us; goto maybe_bridged_with_us;
/* This is a LAG interface that we offload */ /* This is a LAG interface that we offload */
if (!lag_add_cb) if (!lag_mod_cb)
return -EOPNOTSUPP; return -EOPNOTSUPP;
return lag_add_cb(dev, orig_dev, info->ctx, fdb_info); return lag_mod_cb(dev, orig_dev, event, info->ctx, fdb_info);
} }
/* Recurse through lower interfaces in case the FDB entry is pointing /* Recurse through lower interfaces in case the FDB entry is pointing
...@@ -481,10 +481,10 @@ static int __switchdev_handle_fdb_add_to_device(struct net_device *dev, ...@@ -481,10 +481,10 @@ static int __switchdev_handle_fdb_add_to_device(struct net_device *dev,
foreign_dev_check_cb)) foreign_dev_check_cb))
continue; continue;
err = __switchdev_handle_fdb_add_to_device(lower_dev, orig_dev, err = __switchdev_handle_fdb_event_to_device(lower_dev, orig_dev,
fdb_info, check_cb, event, fdb_info, check_cb,
foreign_dev_check_cb, foreign_dev_check_cb,
add_cb, lag_add_cb); mod_cb, lag_mod_cb);
if (err && err != -EOPNOTSUPP) if (err && err != -EOPNOTSUPP)
return err; return err;
} }
...@@ -503,140 +503,34 @@ static int __switchdev_handle_fdb_add_to_device(struct net_device *dev, ...@@ -503,140 +503,34 @@ static int __switchdev_handle_fdb_add_to_device(struct net_device *dev,
if (!switchdev_lower_dev_find(br, check_cb, foreign_dev_check_cb)) if (!switchdev_lower_dev_find(br, check_cb, foreign_dev_check_cb))
return 0; return 0;
return __switchdev_handle_fdb_add_to_device(br, orig_dev, fdb_info, return __switchdev_handle_fdb_event_to_device(br, orig_dev, event, fdb_info,
check_cb, foreign_dev_check_cb, check_cb, foreign_dev_check_cb,
add_cb, lag_add_cb); mod_cb, lag_mod_cb);
} }
int switchdev_handle_fdb_add_to_device(struct net_device *dev, int switchdev_handle_fdb_event_to_device(struct net_device *dev, unsigned long event,
const struct switchdev_notifier_fdb_info *fdb_info, const struct switchdev_notifier_fdb_info *fdb_info,
bool (*check_cb)(const struct net_device *dev), bool (*check_cb)(const struct net_device *dev),
bool (*foreign_dev_check_cb)(const struct net_device *dev, bool (*foreign_dev_check_cb)(const struct net_device *dev,
const struct net_device *foreign_dev), const struct net_device *foreign_dev),
int (*add_cb)(struct net_device *dev, int (*mod_cb)(struct net_device *dev, struct net_device *orig_dev,
const struct net_device *orig_dev, const void *ctx, unsigned long event, const void *ctx,
const struct switchdev_notifier_fdb_info *fdb_info), const struct switchdev_notifier_fdb_info *fdb_info),
int (*lag_add_cb)(struct net_device *dev, int (*lag_mod_cb)(struct net_device *dev, struct net_device *orig_dev,
const struct net_device *orig_dev, const void *ctx, unsigned long event, const void *ctx,
const struct switchdev_notifier_fdb_info *fdb_info)) const struct switchdev_notifier_fdb_info *fdb_info))
{ {
int err; int err;
err = __switchdev_handle_fdb_add_to_device(dev, dev, fdb_info, err = __switchdev_handle_fdb_event_to_device(dev, dev, event, fdb_info,
check_cb, check_cb, foreign_dev_check_cb,
foreign_dev_check_cb, mod_cb, lag_mod_cb);
add_cb, lag_add_cb);
if (err == -EOPNOTSUPP) if (err == -EOPNOTSUPP)
err = 0; err = 0;
return err; return err;
} }
EXPORT_SYMBOL_GPL(switchdev_handle_fdb_add_to_device); EXPORT_SYMBOL_GPL(switchdev_handle_fdb_event_to_device);
static int __switchdev_handle_fdb_del_to_device(struct net_device *dev,
const struct net_device *orig_dev,
const struct switchdev_notifier_fdb_info *fdb_info,
bool (*check_cb)(const struct net_device *dev),
bool (*foreign_dev_check_cb)(const struct net_device *dev,
const struct net_device *foreign_dev),
int (*del_cb)(struct net_device *dev,
const struct net_device *orig_dev, const void *ctx,
const struct switchdev_notifier_fdb_info *fdb_info),
int (*lag_del_cb)(struct net_device *dev,
const struct net_device *orig_dev, const void *ctx,
const struct switchdev_notifier_fdb_info *fdb_info))
{
const struct switchdev_notifier_info *info = &fdb_info->info;
struct net_device *br, *lower_dev;
struct list_head *iter;
int err = -EOPNOTSUPP;
if (check_cb(dev))
return del_cb(dev, orig_dev, info->ctx, fdb_info);
if (netif_is_lag_master(dev)) {
if (!switchdev_lower_dev_find(dev, check_cb, foreign_dev_check_cb))
goto maybe_bridged_with_us;
/* This is a LAG interface that we offload */
if (!lag_del_cb)
return -EOPNOTSUPP;
return lag_del_cb(dev, orig_dev, info->ctx, fdb_info);
}
/* Recurse through lower interfaces in case the FDB entry is pointing
* towards a bridge device.
*/
if (netif_is_bridge_master(dev)) {
if (!switchdev_lower_dev_find(dev, check_cb, foreign_dev_check_cb))
return 0;
/* This is a bridge interface that we offload */
netdev_for_each_lower_dev(dev, lower_dev, iter) {
/* Do not propagate FDB entries across bridges */
if (netif_is_bridge_master(lower_dev))
continue;
/* Bridge ports might be either us, or LAG interfaces
* that we offload.
*/
if (!check_cb(lower_dev) &&
!switchdev_lower_dev_find(lower_dev, check_cb,
foreign_dev_check_cb))
continue;
err = __switchdev_handle_fdb_del_to_device(lower_dev, orig_dev,
fdb_info, check_cb,
foreign_dev_check_cb,
del_cb, lag_del_cb);
if (err && err != -EOPNOTSUPP)
return err;
}
return 0;
}
maybe_bridged_with_us:
/* Event is neither on a bridge nor a LAG. Check whether it is on an
* interface that is in a bridge with us.
*/
br = netdev_master_upper_dev_get_rcu(dev);
if (!br || !netif_is_bridge_master(br))
return 0;
if (!switchdev_lower_dev_find(br, check_cb, foreign_dev_check_cb))
return 0;
return __switchdev_handle_fdb_del_to_device(br, orig_dev, fdb_info,
check_cb, foreign_dev_check_cb,
del_cb, lag_del_cb);
}
int switchdev_handle_fdb_del_to_device(struct net_device *dev,
const struct switchdev_notifier_fdb_info *fdb_info,
bool (*check_cb)(const struct net_device *dev),
bool (*foreign_dev_check_cb)(const struct net_device *dev,
const struct net_device *foreign_dev),
int (*del_cb)(struct net_device *dev,
const struct net_device *orig_dev, const void *ctx,
const struct switchdev_notifier_fdb_info *fdb_info),
int (*lag_del_cb)(struct net_device *dev,
const struct net_device *orig_dev, const void *ctx,
const struct switchdev_notifier_fdb_info *fdb_info))
{
int err;
err = __switchdev_handle_fdb_del_to_device(dev, dev, fdb_info,
check_cb,
foreign_dev_check_cb,
del_cb, lag_del_cb);
if (err == -EOPNOTSUPP)
err = 0;
return err;
}
EXPORT_SYMBOL_GPL(switchdev_handle_fdb_del_to_device);
static int __switchdev_handle_port_obj_add(struct net_device *dev, static int __switchdev_handle_port_obj_add(struct net_device *dev,
struct switchdev_notifier_port_obj_info *port_obj_info, struct switchdev_notifier_port_obj_info *port_obj_info,
......
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