mirror of
https://github.com/torvalds/linux.git
synced 2026-05-28 00:53:34 +02:00
Merge branch 'dsa-cross-chip-notifier-cleanup'
Vladimir Oltean says: ==================== DSA cross-chip notifier cleanups This patch set makes the following improvements: - Cross-chip notifiers pass a switch index, port index, sometimes tree index, all as integers. Sometimes we need to recover the struct dsa_port based on those integers. That recovery involves traversing a list. By passing directly a pointer to the struct dsa_port we can avoid that, and the indices passed previously can still be obtained from the passed struct dsa_port. - Resetting VLAN filtering on a switch has explicit code to make it run on a single switch, so it has no place to stay in the cross-chip notifier code. Move it out. - Changing the MTU on a user port affects only that single port, yet the code passes through the cross-chip notifier layer where all switches are notified. Avoid that. - Other related cosmetic changes in the MTU changing procedure. Apart from the slight improvement in performance given by (a) doing less work in cross-chip notifiers (b) emitting less cross-chip notifiers we also end up with about 100 less lines of code. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
8ab38ed779
|
|
@ -54,18 +54,15 @@ struct dsa_notifier_ageing_time_info {
|
|||
|
||||
/* DSA_NOTIFIER_BRIDGE_* */
|
||||
struct dsa_notifier_bridge_info {
|
||||
const struct dsa_port *dp;
|
||||
struct dsa_bridge bridge;
|
||||
int tree_index;
|
||||
int sw_index;
|
||||
int port;
|
||||
bool tx_fwd_offload;
|
||||
struct netlink_ext_ack *extack;
|
||||
};
|
||||
|
||||
/* DSA_NOTIFIER_FDB_* */
|
||||
struct dsa_notifier_fdb_info {
|
||||
int sw_index;
|
||||
int port;
|
||||
const struct dsa_port *dp;
|
||||
const unsigned char *addr;
|
||||
u16 vid;
|
||||
struct dsa_db db;
|
||||
|
|
@ -81,34 +78,28 @@ struct dsa_notifier_lag_fdb_info {
|
|||
|
||||
/* DSA_NOTIFIER_MDB_* */
|
||||
struct dsa_notifier_mdb_info {
|
||||
const struct dsa_port *dp;
|
||||
const struct switchdev_obj_port_mdb *mdb;
|
||||
int sw_index;
|
||||
int port;
|
||||
struct dsa_db db;
|
||||
};
|
||||
|
||||
/* DSA_NOTIFIER_LAG_* */
|
||||
struct dsa_notifier_lag_info {
|
||||
const struct dsa_port *dp;
|
||||
struct dsa_lag lag;
|
||||
int sw_index;
|
||||
int port;
|
||||
|
||||
struct netdev_lag_upper_info *info;
|
||||
};
|
||||
|
||||
/* DSA_NOTIFIER_VLAN_* */
|
||||
struct dsa_notifier_vlan_info {
|
||||
const struct dsa_port *dp;
|
||||
const struct switchdev_obj_port_vlan *vlan;
|
||||
int sw_index;
|
||||
int port;
|
||||
struct netlink_ext_ack *extack;
|
||||
};
|
||||
|
||||
/* DSA_NOTIFIER_MTU */
|
||||
struct dsa_notifier_mtu_info {
|
||||
bool targeted_match;
|
||||
int sw_index;
|
||||
int port;
|
||||
const struct dsa_port *dp;
|
||||
int mtu;
|
||||
};
|
||||
|
||||
|
|
@ -119,9 +110,7 @@ struct dsa_notifier_tag_proto_info {
|
|||
|
||||
/* DSA_NOTIFIER_TAG_8021Q_VLAN_* */
|
||||
struct dsa_notifier_tag_8021q_vlan_info {
|
||||
int tree_index;
|
||||
int sw_index;
|
||||
int port;
|
||||
const struct dsa_port *dp;
|
||||
u16 vid;
|
||||
};
|
||||
|
||||
|
|
@ -241,8 +230,7 @@ int dsa_port_mst_enable(struct dsa_port *dp, bool on,
|
|||
struct netlink_ext_ack *extack);
|
||||
int dsa_port_vlan_msti(struct dsa_port *dp,
|
||||
const struct switchdev_vlan_msti *msti);
|
||||
int dsa_port_mtu_change(struct dsa_port *dp, int new_mtu,
|
||||
bool targeted_match);
|
||||
int dsa_port_mtu_change(struct dsa_port *dp, int new_mtu);
|
||||
int dsa_port_fdb_add(struct dsa_port *dp, const unsigned char *addr,
|
||||
u16 vid);
|
||||
int dsa_port_fdb_del(struct dsa_port *dp, const unsigned char *addr,
|
||||
|
|
|
|||
128
net/dsa/port.c
128
net/dsa/port.c
|
|
@ -242,6 +242,59 @@ void dsa_port_disable(struct dsa_port *dp)
|
|||
rtnl_unlock();
|
||||
}
|
||||
|
||||
static void dsa_port_reset_vlan_filtering(struct dsa_port *dp,
|
||||
struct dsa_bridge bridge)
|
||||
{
|
||||
struct netlink_ext_ack extack = {0};
|
||||
bool change_vlan_filtering = false;
|
||||
struct dsa_switch *ds = dp->ds;
|
||||
bool vlan_filtering;
|
||||
int err;
|
||||
|
||||
if (ds->needs_standalone_vlan_filtering &&
|
||||
!br_vlan_enabled(bridge.dev)) {
|
||||
change_vlan_filtering = true;
|
||||
vlan_filtering = true;
|
||||
} else if (!ds->needs_standalone_vlan_filtering &&
|
||||
br_vlan_enabled(bridge.dev)) {
|
||||
change_vlan_filtering = true;
|
||||
vlan_filtering = false;
|
||||
}
|
||||
|
||||
/* If the bridge was vlan_filtering, the bridge core doesn't trigger an
|
||||
* event for changing vlan_filtering setting upon slave ports leaving
|
||||
* it. That is a good thing, because that lets us handle it and also
|
||||
* handle the case where the switch's vlan_filtering setting is global
|
||||
* (not per port). When that happens, the correct moment to trigger the
|
||||
* vlan_filtering callback is only when the last port leaves the last
|
||||
* VLAN-aware bridge.
|
||||
*/
|
||||
if (change_vlan_filtering && ds->vlan_filtering_is_global) {
|
||||
dsa_switch_for_each_port(dp, ds) {
|
||||
struct net_device *br = dsa_port_bridge_dev_get(dp);
|
||||
|
||||
if (br && br_vlan_enabled(br)) {
|
||||
change_vlan_filtering = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!change_vlan_filtering)
|
||||
return;
|
||||
|
||||
err = dsa_port_vlan_filtering(dp, vlan_filtering, &extack);
|
||||
if (extack._msg) {
|
||||
dev_err(ds->dev, "port %d: %s\n", dp->index,
|
||||
extack._msg);
|
||||
}
|
||||
if (err && err != -EOPNOTSUPP) {
|
||||
dev_err(ds->dev,
|
||||
"port %d failed to reset VLAN filtering to %d: %pe\n",
|
||||
dp->index, vlan_filtering, ERR_PTR(err));
|
||||
}
|
||||
}
|
||||
|
||||
static int dsa_port_inherit_brport_flags(struct dsa_port *dp,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
|
|
@ -313,7 +366,8 @@ static int dsa_port_switchdev_sync_attrs(struct dsa_port *dp,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void dsa_port_switchdev_unsync_attrs(struct dsa_port *dp)
|
||||
static void dsa_port_switchdev_unsync_attrs(struct dsa_port *dp,
|
||||
struct dsa_bridge bridge)
|
||||
{
|
||||
/* Configure the port for standalone mode (no address learning,
|
||||
* flood everything).
|
||||
|
|
@ -333,7 +387,7 @@ static void dsa_port_switchdev_unsync_attrs(struct dsa_port *dp)
|
|||
*/
|
||||
dsa_port_set_state_now(dp, BR_STATE_FORWARDING, true);
|
||||
|
||||
/* VLAN filtering is handled by dsa_switch_bridge_leave */
|
||||
dsa_port_reset_vlan_filtering(dp, bridge);
|
||||
|
||||
/* Ageing time may be global to the switch chip, so don't change it
|
||||
* here because we have no good reason (or value) to change it to.
|
||||
|
|
@ -405,9 +459,7 @@ int dsa_port_bridge_join(struct dsa_port *dp, struct net_device *br,
|
|||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct dsa_notifier_bridge_info info = {
|
||||
.tree_index = dp->ds->dst->index,
|
||||
.sw_index = dp->ds->index,
|
||||
.port = dp->index,
|
||||
.dp = dp,
|
||||
.extack = extack,
|
||||
};
|
||||
struct net_device *dev = dp->slave;
|
||||
|
|
@ -476,9 +528,7 @@ void dsa_port_pre_bridge_leave(struct dsa_port *dp, struct net_device *br)
|
|||
void dsa_port_bridge_leave(struct dsa_port *dp, struct net_device *br)
|
||||
{
|
||||
struct dsa_notifier_bridge_info info = {
|
||||
.tree_index = dp->ds->dst->index,
|
||||
.sw_index = dp->ds->index,
|
||||
.port = dp->index,
|
||||
.dp = dp,
|
||||
};
|
||||
int err;
|
||||
|
||||
|
|
@ -501,15 +551,14 @@ void dsa_port_bridge_leave(struct dsa_port *dp, struct net_device *br)
|
|||
"port %d failed to notify DSA_NOTIFIER_BRIDGE_LEAVE: %pe\n",
|
||||
dp->index, ERR_PTR(err));
|
||||
|
||||
dsa_port_switchdev_unsync_attrs(dp);
|
||||
dsa_port_switchdev_unsync_attrs(dp, info.bridge);
|
||||
}
|
||||
|
||||
int dsa_port_lag_change(struct dsa_port *dp,
|
||||
struct netdev_lag_lower_state_info *linfo)
|
||||
{
|
||||
struct dsa_notifier_lag_info info = {
|
||||
.sw_index = dp->ds->index,
|
||||
.port = dp->index,
|
||||
.dp = dp,
|
||||
};
|
||||
bool tx_enabled;
|
||||
|
||||
|
|
@ -578,8 +627,7 @@ int dsa_port_lag_join(struct dsa_port *dp, struct net_device *lag_dev,
|
|||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct dsa_notifier_lag_info info = {
|
||||
.sw_index = dp->ds->index,
|
||||
.port = dp->index,
|
||||
.dp = dp,
|
||||
.info = uinfo,
|
||||
};
|
||||
struct net_device *bridge_dev;
|
||||
|
|
@ -624,8 +672,7 @@ void dsa_port_lag_leave(struct dsa_port *dp, struct net_device *lag_dev)
|
|||
{
|
||||
struct net_device *br = dsa_port_bridge_dev_get(dp);
|
||||
struct dsa_notifier_lag_info info = {
|
||||
.sw_index = dp->ds->index,
|
||||
.port = dp->index,
|
||||
.dp = dp,
|
||||
};
|
||||
int err;
|
||||
|
||||
|
|
@ -883,13 +930,10 @@ int dsa_port_vlan_msti(struct dsa_port *dp,
|
|||
return ds->ops->vlan_msti_set(ds, *dp->bridge, msti);
|
||||
}
|
||||
|
||||
int dsa_port_mtu_change(struct dsa_port *dp, int new_mtu,
|
||||
bool targeted_match)
|
||||
int dsa_port_mtu_change(struct dsa_port *dp, int new_mtu)
|
||||
{
|
||||
struct dsa_notifier_mtu_info info = {
|
||||
.sw_index = dp->ds->index,
|
||||
.targeted_match = targeted_match,
|
||||
.port = dp->index,
|
||||
.dp = dp,
|
||||
.mtu = new_mtu,
|
||||
};
|
||||
|
||||
|
|
@ -900,8 +944,7 @@ int dsa_port_fdb_add(struct dsa_port *dp, const unsigned char *addr,
|
|||
u16 vid)
|
||||
{
|
||||
struct dsa_notifier_fdb_info info = {
|
||||
.sw_index = dp->ds->index,
|
||||
.port = dp->index,
|
||||
.dp = dp,
|
||||
.addr = addr,
|
||||
.vid = vid,
|
||||
.db = {
|
||||
|
|
@ -924,8 +967,7 @@ int dsa_port_fdb_del(struct dsa_port *dp, const unsigned char *addr,
|
|||
u16 vid)
|
||||
{
|
||||
struct dsa_notifier_fdb_info info = {
|
||||
.sw_index = dp->ds->index,
|
||||
.port = dp->index,
|
||||
.dp = dp,
|
||||
.addr = addr,
|
||||
.vid = vid,
|
||||
.db = {
|
||||
|
|
@ -945,8 +987,7 @@ static int dsa_port_host_fdb_add(struct dsa_port *dp,
|
|||
struct dsa_db db)
|
||||
{
|
||||
struct dsa_notifier_fdb_info info = {
|
||||
.sw_index = dp->ds->index,
|
||||
.port = dp->index,
|
||||
.dp = dp,
|
||||
.addr = addr,
|
||||
.vid = vid,
|
||||
.db = db,
|
||||
|
|
@ -997,8 +1038,7 @@ static int dsa_port_host_fdb_del(struct dsa_port *dp,
|
|||
struct dsa_db db)
|
||||
{
|
||||
struct dsa_notifier_fdb_info info = {
|
||||
.sw_index = dp->ds->index,
|
||||
.port = dp->index,
|
||||
.dp = dp,
|
||||
.addr = addr,
|
||||
.vid = vid,
|
||||
.db = db,
|
||||
|
|
@ -1093,8 +1133,7 @@ int dsa_port_mdb_add(const struct dsa_port *dp,
|
|||
const struct switchdev_obj_port_mdb *mdb)
|
||||
{
|
||||
struct dsa_notifier_mdb_info info = {
|
||||
.sw_index = dp->ds->index,
|
||||
.port = dp->index,
|
||||
.dp = dp,
|
||||
.mdb = mdb,
|
||||
.db = {
|
||||
.type = DSA_DB_BRIDGE,
|
||||
|
|
@ -1112,8 +1151,7 @@ int dsa_port_mdb_del(const struct dsa_port *dp,
|
|||
const struct switchdev_obj_port_mdb *mdb)
|
||||
{
|
||||
struct dsa_notifier_mdb_info info = {
|
||||
.sw_index = dp->ds->index,
|
||||
.port = dp->index,
|
||||
.dp = dp,
|
||||
.mdb = mdb,
|
||||
.db = {
|
||||
.type = DSA_DB_BRIDGE,
|
||||
|
|
@ -1132,8 +1170,7 @@ static int dsa_port_host_mdb_add(const struct dsa_port *dp,
|
|||
struct dsa_db db)
|
||||
{
|
||||
struct dsa_notifier_mdb_info info = {
|
||||
.sw_index = dp->ds->index,
|
||||
.port = dp->index,
|
||||
.dp = dp,
|
||||
.mdb = mdb,
|
||||
.db = db,
|
||||
};
|
||||
|
|
@ -1177,8 +1214,7 @@ static int dsa_port_host_mdb_del(const struct dsa_port *dp,
|
|||
struct dsa_db db)
|
||||
{
|
||||
struct dsa_notifier_mdb_info info = {
|
||||
.sw_index = dp->ds->index,
|
||||
.port = dp->index,
|
||||
.dp = dp,
|
||||
.mdb = mdb,
|
||||
.db = db,
|
||||
};
|
||||
|
|
@ -1222,8 +1258,7 @@ int dsa_port_vlan_add(struct dsa_port *dp,
|
|||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct dsa_notifier_vlan_info info = {
|
||||
.sw_index = dp->ds->index,
|
||||
.port = dp->index,
|
||||
.dp = dp,
|
||||
.vlan = vlan,
|
||||
.extack = extack,
|
||||
};
|
||||
|
|
@ -1235,8 +1270,7 @@ int dsa_port_vlan_del(struct dsa_port *dp,
|
|||
const struct switchdev_obj_port_vlan *vlan)
|
||||
{
|
||||
struct dsa_notifier_vlan_info info = {
|
||||
.sw_index = dp->ds->index,
|
||||
.port = dp->index,
|
||||
.dp = dp,
|
||||
.vlan = vlan,
|
||||
};
|
||||
|
||||
|
|
@ -1248,8 +1282,7 @@ int dsa_port_host_vlan_add(struct dsa_port *dp,
|
|||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct dsa_notifier_vlan_info info = {
|
||||
.sw_index = dp->ds->index,
|
||||
.port = dp->index,
|
||||
.dp = dp,
|
||||
.vlan = vlan,
|
||||
.extack = extack,
|
||||
};
|
||||
|
|
@ -1269,8 +1302,7 @@ int dsa_port_host_vlan_del(struct dsa_port *dp,
|
|||
const struct switchdev_obj_port_vlan *vlan)
|
||||
{
|
||||
struct dsa_notifier_vlan_info info = {
|
||||
.sw_index = dp->ds->index,
|
||||
.port = dp->index,
|
||||
.dp = dp,
|
||||
.vlan = vlan,
|
||||
};
|
||||
struct dsa_port *cpu_dp = dp->cpu_dp;
|
||||
|
|
@ -1689,9 +1721,7 @@ void dsa_port_hsr_leave(struct dsa_port *dp, struct net_device *hsr)
|
|||
int dsa_port_tag_8021q_vlan_add(struct dsa_port *dp, u16 vid, bool broadcast)
|
||||
{
|
||||
struct dsa_notifier_tag_8021q_vlan_info info = {
|
||||
.tree_index = dp->ds->dst->index,
|
||||
.sw_index = dp->ds->index,
|
||||
.port = dp->index,
|
||||
.dp = dp,
|
||||
.vid = vid,
|
||||
};
|
||||
|
||||
|
|
@ -1704,9 +1734,7 @@ int dsa_port_tag_8021q_vlan_add(struct dsa_port *dp, u16 vid, bool broadcast)
|
|||
void dsa_port_tag_8021q_vlan_del(struct dsa_port *dp, u16 vid, bool broadcast)
|
||||
{
|
||||
struct dsa_notifier_tag_8021q_vlan_info info = {
|
||||
.tree_index = dp->ds->dst->index,
|
||||
.sw_index = dp->ds->index,
|
||||
.port = dp->index,
|
||||
.dp = dp,
|
||||
.vid = vid,
|
||||
};
|
||||
int err;
|
||||
|
|
|
|||
|
|
@ -1806,11 +1806,9 @@ int dsa_slave_change_mtu(struct net_device *dev, int new_mtu)
|
|||
{
|
||||
struct net_device *master = dsa_slave_to_master(dev);
|
||||
struct dsa_port *dp = dsa_slave_to_port(dev);
|
||||
struct dsa_slave_priv *p = netdev_priv(dev);
|
||||
struct dsa_switch *ds = p->dp->ds;
|
||||
struct dsa_port *dp_iter;
|
||||
struct dsa_port *cpu_dp;
|
||||
int port = p->dp->index;
|
||||
struct dsa_port *cpu_dp = dp->cpu_dp;
|
||||
struct dsa_switch *ds = dp->ds;
|
||||
struct dsa_port *other_dp;
|
||||
int largest_mtu = 0;
|
||||
int new_master_mtu;
|
||||
int old_master_mtu;
|
||||
|
|
@ -1821,33 +1819,28 @@ int dsa_slave_change_mtu(struct net_device *dev, int new_mtu)
|
|||
if (!ds->ops->port_change_mtu)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
list_for_each_entry(dp_iter, &ds->dst->ports, list) {
|
||||
dsa_tree_for_each_user_port(other_dp, ds->dst) {
|
||||
int slave_mtu;
|
||||
|
||||
if (!dsa_port_is_user(dp_iter))
|
||||
continue;
|
||||
|
||||
/* During probe, this function will be called for each slave
|
||||
* device, while not all of them have been allocated. That's
|
||||
* ok, it doesn't change what the maximum is, so ignore it.
|
||||
*/
|
||||
if (!dp_iter->slave)
|
||||
if (!other_dp->slave)
|
||||
continue;
|
||||
|
||||
/* Pretend that we already applied the setting, which we
|
||||
* actually haven't (still haven't done all integrity checks)
|
||||
*/
|
||||
if (dp_iter == dp)
|
||||
if (dp == other_dp)
|
||||
slave_mtu = new_mtu;
|
||||
else
|
||||
slave_mtu = dp_iter->slave->mtu;
|
||||
slave_mtu = other_dp->slave->mtu;
|
||||
|
||||
if (largest_mtu < slave_mtu)
|
||||
largest_mtu = slave_mtu;
|
||||
}
|
||||
|
||||
cpu_dp = dsa_to_port(ds, port)->cpu_dp;
|
||||
|
||||
mtu_limit = min_t(int, master->max_mtu, dev->max_mtu);
|
||||
old_master_mtu = master->mtu;
|
||||
new_master_mtu = largest_mtu + dsa_tag_protocol_overhead(cpu_dp->tag_ops);
|
||||
|
|
@ -1866,15 +1859,14 @@ int dsa_slave_change_mtu(struct net_device *dev, int new_mtu)
|
|||
goto out_master_failed;
|
||||
|
||||
/* We only need to propagate the MTU of the CPU port to
|
||||
* upstream switches, so create a non-targeted notifier which
|
||||
* updates all switches.
|
||||
* upstream switches, so emit a notifier which updates them.
|
||||
*/
|
||||
err = dsa_port_mtu_change(cpu_dp, cpu_mtu, false);
|
||||
err = dsa_port_mtu_change(cpu_dp, cpu_mtu);
|
||||
if (err)
|
||||
goto out_cpu_failed;
|
||||
}
|
||||
|
||||
err = dsa_port_mtu_change(dp, new_mtu, true);
|
||||
err = ds->ops->port_change_mtu(ds, dp->index, new_mtu);
|
||||
if (err)
|
||||
goto out_port_failed;
|
||||
|
||||
|
|
@ -1887,8 +1879,7 @@ int dsa_slave_change_mtu(struct net_device *dev, int new_mtu)
|
|||
out_port_failed:
|
||||
if (new_master_mtu != old_master_mtu)
|
||||
dsa_port_mtu_change(cpu_dp, old_master_mtu -
|
||||
dsa_tag_protocol_overhead(cpu_dp->tag_ops),
|
||||
false);
|
||||
dsa_tag_protocol_overhead(cpu_dp->tag_ops));
|
||||
out_cpu_failed:
|
||||
if (new_master_mtu != old_master_mtu)
|
||||
dev_set_mtu(master, old_master_mtu);
|
||||
|
|
|
|||
188
net/dsa/switch.c
188
net/dsa/switch.c
|
|
@ -49,19 +49,7 @@ static int dsa_switch_ageing_time(struct dsa_switch *ds,
|
|||
static bool dsa_port_mtu_match(struct dsa_port *dp,
|
||||
struct dsa_notifier_mtu_info *info)
|
||||
{
|
||||
if (dp->ds->index == info->sw_index && dp->index == info->port)
|
||||
return true;
|
||||
|
||||
/* Do not propagate to other switches in the tree if the notifier was
|
||||
* targeted for a single switch.
|
||||
*/
|
||||
if (info->targeted_match)
|
||||
return false;
|
||||
|
||||
if (dsa_port_is_dsa(dp) || dsa_port_is_cpu(dp))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
return dp == info->dp || dsa_port_is_dsa(dp) || dsa_port_is_cpu(dp);
|
||||
}
|
||||
|
||||
static int dsa_switch_mtu(struct dsa_switch *ds,
|
||||
|
|
@ -88,25 +76,26 @@ static int dsa_switch_mtu(struct dsa_switch *ds,
|
|||
static int dsa_switch_bridge_join(struct dsa_switch *ds,
|
||||
struct dsa_notifier_bridge_info *info)
|
||||
{
|
||||
struct dsa_switch_tree *dst = ds->dst;
|
||||
int err;
|
||||
|
||||
if (dst->index == info->tree_index && ds->index == info->sw_index) {
|
||||
if (info->dp->ds == ds) {
|
||||
if (!ds->ops->port_bridge_join)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
err = ds->ops->port_bridge_join(ds, info->port, info->bridge,
|
||||
err = ds->ops->port_bridge_join(ds, info->dp->index,
|
||||
info->bridge,
|
||||
&info->tx_fwd_offload,
|
||||
info->extack);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
if ((dst->index != info->tree_index || ds->index != info->sw_index) &&
|
||||
ds->ops->crosschip_bridge_join) {
|
||||
err = ds->ops->crosschip_bridge_join(ds, info->tree_index,
|
||||
info->sw_index,
|
||||
info->port, info->bridge,
|
||||
if (info->dp->ds != ds && ds->ops->crosschip_bridge_join) {
|
||||
err = ds->ops->crosschip_bridge_join(ds,
|
||||
info->dp->ds->dst->index,
|
||||
info->dp->ds->index,
|
||||
info->dp->index,
|
||||
info->bridge,
|
||||
info->extack);
|
||||
if (err)
|
||||
return err;
|
||||
|
|
@ -115,79 +104,18 @@ static int dsa_switch_bridge_join(struct dsa_switch *ds,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int dsa_switch_sync_vlan_filtering(struct dsa_switch *ds,
|
||||
struct dsa_notifier_bridge_info *info)
|
||||
{
|
||||
struct netlink_ext_ack extack = {0};
|
||||
bool change_vlan_filtering = false;
|
||||
bool vlan_filtering;
|
||||
struct dsa_port *dp;
|
||||
int err;
|
||||
|
||||
if (ds->needs_standalone_vlan_filtering &&
|
||||
!br_vlan_enabled(info->bridge.dev)) {
|
||||
change_vlan_filtering = true;
|
||||
vlan_filtering = true;
|
||||
} else if (!ds->needs_standalone_vlan_filtering &&
|
||||
br_vlan_enabled(info->bridge.dev)) {
|
||||
change_vlan_filtering = true;
|
||||
vlan_filtering = false;
|
||||
}
|
||||
|
||||
/* If the bridge was vlan_filtering, the bridge core doesn't trigger an
|
||||
* event for changing vlan_filtering setting upon slave ports leaving
|
||||
* it. That is a good thing, because that lets us handle it and also
|
||||
* handle the case where the switch's vlan_filtering setting is global
|
||||
* (not per port). When that happens, the correct moment to trigger the
|
||||
* vlan_filtering callback is only when the last port leaves the last
|
||||
* VLAN-aware bridge.
|
||||
*/
|
||||
if (change_vlan_filtering && ds->vlan_filtering_is_global) {
|
||||
dsa_switch_for_each_port(dp, ds) {
|
||||
struct net_device *br = dsa_port_bridge_dev_get(dp);
|
||||
|
||||
if (br && br_vlan_enabled(br)) {
|
||||
change_vlan_filtering = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (change_vlan_filtering) {
|
||||
err = dsa_port_vlan_filtering(dsa_to_port(ds, info->port),
|
||||
vlan_filtering, &extack);
|
||||
if (extack._msg)
|
||||
dev_err(ds->dev, "port %d: %s\n", info->port,
|
||||
extack._msg);
|
||||
if (err && err != -EOPNOTSUPP)
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dsa_switch_bridge_leave(struct dsa_switch *ds,
|
||||
struct dsa_notifier_bridge_info *info)
|
||||
{
|
||||
struct dsa_switch_tree *dst = ds->dst;
|
||||
int err;
|
||||
if (info->dp->ds == ds && ds->ops->port_bridge_leave)
|
||||
ds->ops->port_bridge_leave(ds, info->dp->index, info->bridge);
|
||||
|
||||
if (dst->index == info->tree_index && ds->index == info->sw_index &&
|
||||
ds->ops->port_bridge_leave)
|
||||
ds->ops->port_bridge_leave(ds, info->port, info->bridge);
|
||||
|
||||
if ((dst->index != info->tree_index || ds->index != info->sw_index) &&
|
||||
ds->ops->crosschip_bridge_leave)
|
||||
ds->ops->crosschip_bridge_leave(ds, info->tree_index,
|
||||
info->sw_index, info->port,
|
||||
if (info->dp->ds != ds && ds->ops->crosschip_bridge_leave)
|
||||
ds->ops->crosschip_bridge_leave(ds, info->dp->ds->dst->index,
|
||||
info->dp->ds->index,
|
||||
info->dp->index,
|
||||
info->bridge);
|
||||
|
||||
if (ds->dst->index == info->tree_index && ds->index == info->sw_index) {
|
||||
err = dsa_switch_sync_vlan_filtering(ds, info);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -196,16 +124,11 @@ static int dsa_switch_bridge_leave(struct dsa_switch *ds,
|
|||
* emitted and its dedicated CPU port.
|
||||
*/
|
||||
static bool dsa_port_host_address_match(struct dsa_port *dp,
|
||||
int info_sw_index, int info_port)
|
||||
const struct dsa_port *targeted_dp)
|
||||
{
|
||||
struct dsa_port *targeted_dp, *cpu_dp;
|
||||
struct dsa_switch *targeted_ds;
|
||||
struct dsa_port *cpu_dp = targeted_dp->cpu_dp;
|
||||
|
||||
targeted_ds = dsa_switch_find(dp->ds->dst->index, info_sw_index);
|
||||
targeted_dp = dsa_to_port(targeted_ds, info_port);
|
||||
cpu_dp = targeted_dp->cpu_dp;
|
||||
|
||||
if (dsa_switch_is_upstream_of(dp->ds, targeted_ds))
|
||||
if (dsa_switch_is_upstream_of(dp->ds, targeted_dp->ds))
|
||||
return dp->index == dsa_towards_port(dp->ds, cpu_dp->ds->index,
|
||||
cpu_dp->index);
|
||||
|
||||
|
|
@ -473,8 +396,7 @@ static int dsa_switch_host_fdb_add(struct dsa_switch *ds,
|
|||
return -EOPNOTSUPP;
|
||||
|
||||
dsa_switch_for_each_port(dp, ds) {
|
||||
if (dsa_port_host_address_match(dp, info->sw_index,
|
||||
info->port)) {
|
||||
if (dsa_port_host_address_match(dp, info->dp)) {
|
||||
err = dsa_port_do_fdb_add(dp, info->addr, info->vid,
|
||||
info->db);
|
||||
if (err)
|
||||
|
|
@ -495,8 +417,7 @@ static int dsa_switch_host_fdb_del(struct dsa_switch *ds,
|
|||
return -EOPNOTSUPP;
|
||||
|
||||
dsa_switch_for_each_port(dp, ds) {
|
||||
if (dsa_port_host_address_match(dp, info->sw_index,
|
||||
info->port)) {
|
||||
if (dsa_port_host_address_match(dp, info->dp)) {
|
||||
err = dsa_port_do_fdb_del(dp, info->addr, info->vid,
|
||||
info->db);
|
||||
if (err)
|
||||
|
|
@ -510,7 +431,7 @@ static int dsa_switch_host_fdb_del(struct dsa_switch *ds,
|
|||
static int dsa_switch_fdb_add(struct dsa_switch *ds,
|
||||
struct dsa_notifier_fdb_info *info)
|
||||
{
|
||||
int port = dsa_towards_port(ds, info->sw_index, info->port);
|
||||
int port = dsa_towards_port(ds, info->dp->ds->index, info->dp->index);
|
||||
struct dsa_port *dp = dsa_to_port(ds, port);
|
||||
|
||||
if (!ds->ops->port_fdb_add)
|
||||
|
|
@ -522,7 +443,7 @@ static int dsa_switch_fdb_add(struct dsa_switch *ds,
|
|||
static int dsa_switch_fdb_del(struct dsa_switch *ds,
|
||||
struct dsa_notifier_fdb_info *info)
|
||||
{
|
||||
int port = dsa_towards_port(ds, info->sw_index, info->port);
|
||||
int port = dsa_towards_port(ds, info->dp->ds->index, info->dp->index);
|
||||
struct dsa_port *dp = dsa_to_port(ds, port);
|
||||
|
||||
if (!ds->ops->port_fdb_del)
|
||||
|
|
@ -570,12 +491,12 @@ static int dsa_switch_lag_fdb_del(struct dsa_switch *ds,
|
|||
static int dsa_switch_lag_change(struct dsa_switch *ds,
|
||||
struct dsa_notifier_lag_info *info)
|
||||
{
|
||||
if (ds->index == info->sw_index && ds->ops->port_lag_change)
|
||||
return ds->ops->port_lag_change(ds, info->port);
|
||||
if (info->dp->ds == ds && ds->ops->port_lag_change)
|
||||
return ds->ops->port_lag_change(ds, info->dp->index);
|
||||
|
||||
if (ds->index != info->sw_index && ds->ops->crosschip_lag_change)
|
||||
return ds->ops->crosschip_lag_change(ds, info->sw_index,
|
||||
info->port);
|
||||
if (info->dp->ds != ds && ds->ops->crosschip_lag_change)
|
||||
return ds->ops->crosschip_lag_change(ds, info->dp->ds->index,
|
||||
info->dp->index);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -583,13 +504,13 @@ static int dsa_switch_lag_change(struct dsa_switch *ds,
|
|||
static int dsa_switch_lag_join(struct dsa_switch *ds,
|
||||
struct dsa_notifier_lag_info *info)
|
||||
{
|
||||
if (ds->index == info->sw_index && ds->ops->port_lag_join)
|
||||
return ds->ops->port_lag_join(ds, info->port, info->lag,
|
||||
if (info->dp->ds == ds && ds->ops->port_lag_join)
|
||||
return ds->ops->port_lag_join(ds, info->dp->index, info->lag,
|
||||
info->info);
|
||||
|
||||
if (ds->index != info->sw_index && ds->ops->crosschip_lag_join)
|
||||
return ds->ops->crosschip_lag_join(ds, info->sw_index,
|
||||
info->port, info->lag,
|
||||
if (info->dp->ds != ds && ds->ops->crosschip_lag_join)
|
||||
return ds->ops->crosschip_lag_join(ds, info->dp->ds->index,
|
||||
info->dp->index, info->lag,
|
||||
info->info);
|
||||
|
||||
return -EOPNOTSUPP;
|
||||
|
|
@ -598,12 +519,12 @@ static int dsa_switch_lag_join(struct dsa_switch *ds,
|
|||
static int dsa_switch_lag_leave(struct dsa_switch *ds,
|
||||
struct dsa_notifier_lag_info *info)
|
||||
{
|
||||
if (ds->index == info->sw_index && ds->ops->port_lag_leave)
|
||||
return ds->ops->port_lag_leave(ds, info->port, info->lag);
|
||||
if (info->dp->ds == ds && ds->ops->port_lag_leave)
|
||||
return ds->ops->port_lag_leave(ds, info->dp->index, info->lag);
|
||||
|
||||
if (ds->index != info->sw_index && ds->ops->crosschip_lag_leave)
|
||||
return ds->ops->crosschip_lag_leave(ds, info->sw_index,
|
||||
info->port, info->lag);
|
||||
if (info->dp->ds != ds && ds->ops->crosschip_lag_leave)
|
||||
return ds->ops->crosschip_lag_leave(ds, info->dp->ds->index,
|
||||
info->dp->index, info->lag);
|
||||
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
|
@ -611,7 +532,7 @@ static int dsa_switch_lag_leave(struct dsa_switch *ds,
|
|||
static int dsa_switch_mdb_add(struct dsa_switch *ds,
|
||||
struct dsa_notifier_mdb_info *info)
|
||||
{
|
||||
int port = dsa_towards_port(ds, info->sw_index, info->port);
|
||||
int port = dsa_towards_port(ds, info->dp->ds->index, info->dp->index);
|
||||
struct dsa_port *dp = dsa_to_port(ds, port);
|
||||
|
||||
if (!ds->ops->port_mdb_add)
|
||||
|
|
@ -623,7 +544,7 @@ static int dsa_switch_mdb_add(struct dsa_switch *ds,
|
|||
static int dsa_switch_mdb_del(struct dsa_switch *ds,
|
||||
struct dsa_notifier_mdb_info *info)
|
||||
{
|
||||
int port = dsa_towards_port(ds, info->sw_index, info->port);
|
||||
int port = dsa_towards_port(ds, info->dp->ds->index, info->dp->index);
|
||||
struct dsa_port *dp = dsa_to_port(ds, port);
|
||||
|
||||
if (!ds->ops->port_mdb_del)
|
||||
|
|
@ -642,8 +563,7 @@ static int dsa_switch_host_mdb_add(struct dsa_switch *ds,
|
|||
return -EOPNOTSUPP;
|
||||
|
||||
dsa_switch_for_each_port(dp, ds) {
|
||||
if (dsa_port_host_address_match(dp, info->sw_index,
|
||||
info->port)) {
|
||||
if (dsa_port_host_address_match(dp, info->dp)) {
|
||||
err = dsa_port_do_mdb_add(dp, info->mdb, info->db);
|
||||
if (err)
|
||||
break;
|
||||
|
|
@ -663,8 +583,7 @@ static int dsa_switch_host_mdb_del(struct dsa_switch *ds,
|
|||
return -EOPNOTSUPP;
|
||||
|
||||
dsa_switch_for_each_port(dp, ds) {
|
||||
if (dsa_port_host_address_match(dp, info->sw_index,
|
||||
info->port)) {
|
||||
if (dsa_port_host_address_match(dp, info->dp)) {
|
||||
err = dsa_port_do_mdb_del(dp, info->mdb, info->db);
|
||||
if (err)
|
||||
break;
|
||||
|
|
@ -678,29 +597,18 @@ static int dsa_switch_host_mdb_del(struct dsa_switch *ds,
|
|||
static bool dsa_port_vlan_match(struct dsa_port *dp,
|
||||
struct dsa_notifier_vlan_info *info)
|
||||
{
|
||||
if (dp->ds->index == info->sw_index && dp->index == info->port)
|
||||
return true;
|
||||
|
||||
if (dsa_port_is_dsa(dp))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
return dsa_port_is_dsa(dp) || dp == info->dp;
|
||||
}
|
||||
|
||||
/* Host VLANs match on the targeted port's CPU port, and on all DSA ports
|
||||
* (upstream and downstream) of that switch and its upstream switches.
|
||||
*/
|
||||
static bool dsa_port_host_vlan_match(struct dsa_port *dp,
|
||||
struct dsa_notifier_vlan_info *info)
|
||||
const struct dsa_port *targeted_dp)
|
||||
{
|
||||
struct dsa_port *targeted_dp, *cpu_dp;
|
||||
struct dsa_switch *targeted_ds;
|
||||
struct dsa_port *cpu_dp = targeted_dp->cpu_dp;
|
||||
|
||||
targeted_ds = dsa_switch_find(dp->ds->dst->index, info->sw_index);
|
||||
targeted_dp = dsa_to_port(targeted_ds, info->port);
|
||||
cpu_dp = targeted_dp->cpu_dp;
|
||||
|
||||
if (dsa_switch_is_upstream_of(dp->ds, targeted_ds))
|
||||
if (dsa_switch_is_upstream_of(dp->ds, targeted_dp->ds))
|
||||
return dsa_port_is_dsa(dp) || dp == cpu_dp;
|
||||
|
||||
return false;
|
||||
|
|
@ -858,7 +766,7 @@ static int dsa_switch_host_vlan_add(struct dsa_switch *ds,
|
|||
return -EOPNOTSUPP;
|
||||
|
||||
dsa_switch_for_each_port(dp, ds) {
|
||||
if (dsa_port_host_vlan_match(dp, info)) {
|
||||
if (dsa_port_host_vlan_match(dp, info->dp)) {
|
||||
err = dsa_port_do_vlan_add(dp, info->vlan,
|
||||
info->extack);
|
||||
if (err)
|
||||
|
|
@ -879,7 +787,7 @@ static int dsa_switch_host_vlan_del(struct dsa_switch *ds,
|
|||
return -EOPNOTSUPP;
|
||||
|
||||
dsa_switch_for_each_port(dp, ds) {
|
||||
if (dsa_port_host_vlan_match(dp, info)) {
|
||||
if (dsa_port_host_vlan_match(dp, info->dp)) {
|
||||
err = dsa_port_do_vlan_del(dp, info->vlan);
|
||||
if (err)
|
||||
return err;
|
||||
|
|
|
|||
|
|
@ -196,15 +196,7 @@ static bool
|
|||
dsa_port_tag_8021q_vlan_match(struct dsa_port *dp,
|
||||
struct dsa_notifier_tag_8021q_vlan_info *info)
|
||||
{
|
||||
struct dsa_switch *ds = dp->ds;
|
||||
|
||||
if (dsa_port_is_dsa(dp) || dsa_port_is_cpu(dp))
|
||||
return true;
|
||||
|
||||
if (ds->dst->index == info->tree_index && ds->index == info->sw_index)
|
||||
return dp->index == info->port;
|
||||
|
||||
return false;
|
||||
return dsa_port_is_dsa(dp) || dsa_port_is_cpu(dp) || dp == info->dp;
|
||||
}
|
||||
|
||||
int dsa_switch_tag_8021q_vlan_add(struct dsa_switch *ds,
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user