Commit b42a738e authored by David S. Miller's avatar David S. Miller

Merge branch 'dsa-fdb-isolation'

Vladimir Oltean says:

====================
DSA FDB isolation

There are use cases which need FDB isolation between standalone ports
and bridged ports, as well as isolation between ports of different
bridges. Most of these use cases are a result of the fact that packets
can now be partially forwarded by the software bridge, so one port might
need to send a packet to the CPU but its FDB lookup will see that it can
forward it directly to a bridge port where that packet was autonomously
learned. So the source port will attempt to shortcircuit the CPU and
forward autonomously, which it can't due to the forwarding isolation we
have in place. So we will have packet drops instead of proper operation.

Additionally, before DSA can implement IFF_UNICAST_FLT for standalone
ports, we must have control over which database we install FDB entries
corresponding to port MAC addresses in. We don't want to hinder the
operation of the bridging layer.

DSA does not have a driver API that encourages FDB isolation, so this
needs to be created. The basis for this is a new struct dsa_db which
annotates each FDB and MDB entry with the database it belongs to.

The sja1105 and felix drivers are modified to observe the dsa_db
argument, and therefore, enforce the FDB isolation.

Compared to the previous RFC patch series from August:
https://patchwork.kernel.org/project/netdevbpf/cover/20210818120150.892647-1-vladimir.oltean@nxp.com/

what is different is that I stopped trying to make SWITCHDEV_FDB_{ADD,DEL}_TO_DEVICE
blocking, instead I'm making use of the fact that DSA waits for switchdev FDB work
items to finish before a port leaves the bridge. This is possible since:
https://patchwork.kernel.org/project/netdevbpf/patch/20211024171757.3753288-7-vladimir.oltean@nxp.com/

Additionally, v2 is also rebased over the DSA LAG FDB work.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 1bb1c5bc 54c31984
......@@ -293,6 +293,33 @@ of dropped frames, which is a sum of frames dropped due to timing violations,
lack of destination ports and MTU enforcement checks). Byte-level counters are
not available.
Limitations
===========
The SJA1105 switch family always performs VLAN processing. When configured as
VLAN-unaware, frames carry a different VLAN tag internally, depending on
whether the port is standalone or under a VLAN-unaware bridge.
The virtual link keys are always fixed at {MAC DA, VLAN ID, VLAN PCP}, but the
driver asks for the VLAN ID and VLAN PCP when the port is under a VLAN-aware
bridge. Otherwise, it fills in the VLAN ID and PCP automatically, based on
whether the port is standalone or in a VLAN-unaware bridge, and accepts only
"VLAN-unaware" tc-flower keys (MAC DA).
The existing tc-flower keys that are offloaded using virtual links are no
longer operational after one of the following happens:
- port was standalone and joins a bridge (VLAN-aware or VLAN-unaware)
- port is part of a bridge whose VLAN awareness state changes
- port was part of a bridge and becomes standalone
- port was standalone, but another port joins a VLAN-aware bridge and this
changes the global VLAN awareness state of the bridge
The driver cannot veto all these operations, and it cannot update/remove the
existing tc-flower filters either. So for proper operation, the tc-flower
filters should be installed only after the forwarding configuration of the port
has been made, and removed by user space before making any changes to it.
Device Tree bindings and board design
=====================================
......
......@@ -1708,7 +1708,8 @@ static int b53_arl_op(struct b53_device *dev, int op, int port,
}
int b53_fdb_add(struct dsa_switch *ds, int port,
const unsigned char *addr, u16 vid)
const unsigned char *addr, u16 vid,
struct dsa_db db)
{
struct b53_device *priv = ds->priv;
int ret;
......@@ -1728,7 +1729,8 @@ int b53_fdb_add(struct dsa_switch *ds, int port,
EXPORT_SYMBOL(b53_fdb_add);
int b53_fdb_del(struct dsa_switch *ds, int port,
const unsigned char *addr, u16 vid)
const unsigned char *addr, u16 vid,
struct dsa_db db)
{
struct b53_device *priv = ds->priv;
int ret;
......@@ -1829,7 +1831,8 @@ int b53_fdb_dump(struct dsa_switch *ds, int port,
EXPORT_SYMBOL(b53_fdb_dump);
int b53_mdb_add(struct dsa_switch *ds, int port,
const struct switchdev_obj_port_mdb *mdb)
const struct switchdev_obj_port_mdb *mdb,
struct dsa_db db)
{
struct b53_device *priv = ds->priv;
int ret;
......@@ -1849,7 +1852,8 @@ int b53_mdb_add(struct dsa_switch *ds, int port,
EXPORT_SYMBOL(b53_mdb_add);
int b53_mdb_del(struct dsa_switch *ds, int port,
const struct switchdev_obj_port_mdb *mdb)
const struct switchdev_obj_port_mdb *mdb,
struct dsa_db db)
{
struct b53_device *priv = ds->priv;
int ret;
......@@ -1865,7 +1869,7 @@ int b53_mdb_del(struct dsa_switch *ds, int port,
EXPORT_SYMBOL(b53_mdb_del);
int b53_br_join(struct dsa_switch *ds, int port, struct dsa_bridge bridge,
bool *tx_fwd_offload)
bool *tx_fwd_offload, struct netlink_ext_ack *extack)
{
struct b53_device *dev = ds->priv;
s8 cpu_port = dsa_to_port(ds, port)->cpu_dp->index;
......
......@@ -324,7 +324,7 @@ void b53_get_ethtool_stats(struct dsa_switch *ds, int port, uint64_t *data);
int b53_get_sset_count(struct dsa_switch *ds, int port, int sset);
void b53_get_ethtool_phy_stats(struct dsa_switch *ds, int port, uint64_t *data);
int b53_br_join(struct dsa_switch *ds, int port, struct dsa_bridge bridge,
bool *tx_fwd_offload);
bool *tx_fwd_offload, struct netlink_ext_ack *extack);
void b53_br_leave(struct dsa_switch *ds, int port, struct dsa_bridge bridge);
void b53_br_set_stp_state(struct dsa_switch *ds, int port, u8 state);
void b53_br_fast_age(struct dsa_switch *ds, int port);
......@@ -359,15 +359,19 @@ int b53_vlan_add(struct dsa_switch *ds, int port,
int b53_vlan_del(struct dsa_switch *ds, int port,
const struct switchdev_obj_port_vlan *vlan);
int b53_fdb_add(struct dsa_switch *ds, int port,
const unsigned char *addr, u16 vid);
const unsigned char *addr, u16 vid,
struct dsa_db db);
int b53_fdb_del(struct dsa_switch *ds, int port,
const unsigned char *addr, u16 vid);
const unsigned char *addr, u16 vid,
struct dsa_db db);
int b53_fdb_dump(struct dsa_switch *ds, int port,
dsa_fdb_dump_cb_t *cb, void *data);
int b53_mdb_add(struct dsa_switch *ds, int port,
const struct switchdev_obj_port_mdb *mdb);
const struct switchdev_obj_port_mdb *mdb,
struct dsa_db db);
int b53_mdb_del(struct dsa_switch *ds, int port,
const struct switchdev_obj_port_mdb *mdb);
const struct switchdev_obj_port_mdb *mdb,
struct dsa_db db);
int b53_mirror_add(struct dsa_switch *ds, int port,
struct dsa_mall_mirror_tc_entry *mirror, bool ingress);
enum dsa_tag_protocol b53_get_tag_protocol(struct dsa_switch *ds, int port,
......
......@@ -168,7 +168,8 @@ static int dsa_loop_phy_write(struct dsa_switch *ds, int port,
static int dsa_loop_port_bridge_join(struct dsa_switch *ds, int port,
struct dsa_bridge bridge,
bool *tx_fwd_offload)
bool *tx_fwd_offload,
struct netlink_ext_ack *extack)
{
dev_dbg(ds->dev, "%s: port: %d, bridge: %s\n",
__func__, port, bridge.dev->name);
......
......@@ -675,7 +675,8 @@ static int hellcreek_bridge_flags(struct dsa_switch *ds, int port,
static int hellcreek_port_bridge_join(struct dsa_switch *ds, int port,
struct dsa_bridge bridge,
bool *tx_fwd_offload)
bool *tx_fwd_offload,
struct netlink_ext_ack *extack)
{
struct hellcreek *hellcreek = ds->priv;
......@@ -827,7 +828,8 @@ static int hellcreek_fdb_get(struct hellcreek *hellcreek,
}
static int hellcreek_fdb_add(struct dsa_switch *ds, int port,
const unsigned char *addr, u16 vid)
const unsigned char *addr, u16 vid,
struct dsa_db db)
{
struct hellcreek_fdb_entry entry = { 0 };
struct hellcreek *hellcreek = ds->priv;
......@@ -872,7 +874,8 @@ static int hellcreek_fdb_add(struct dsa_switch *ds, int port,
}
static int hellcreek_fdb_del(struct dsa_switch *ds, int port,
const unsigned char *addr, u16 vid)
const unsigned char *addr, u16 vid,
struct dsa_db db)
{
struct hellcreek_fdb_entry entry = { 0 };
struct hellcreek *hellcreek = ds->priv;
......
......@@ -1111,7 +1111,8 @@ static void lan9303_port_disable(struct dsa_switch *ds, int port)
static int lan9303_port_bridge_join(struct dsa_switch *ds, int port,
struct dsa_bridge bridge,
bool *tx_fwd_offload)
bool *tx_fwd_offload,
struct netlink_ext_ack *extack)
{
struct lan9303 *chip = ds->priv;
......@@ -1188,7 +1189,8 @@ static void lan9303_port_fast_age(struct dsa_switch *ds, int port)
}
static int lan9303_port_fdb_add(struct dsa_switch *ds, int port,
const unsigned char *addr, u16 vid)
const unsigned char *addr, u16 vid,
struct dsa_db db)
{
struct lan9303 *chip = ds->priv;
......@@ -1200,8 +1202,8 @@ static int lan9303_port_fdb_add(struct dsa_switch *ds, int port,
}
static int lan9303_port_fdb_del(struct dsa_switch *ds, int port,
const unsigned char *addr, u16 vid)
const unsigned char *addr, u16 vid,
struct dsa_db db)
{
struct lan9303 *chip = ds->priv;
......@@ -1245,7 +1247,8 @@ static int lan9303_port_mdb_prepare(struct dsa_switch *ds, int port,
}
static int lan9303_port_mdb_add(struct dsa_switch *ds, int port,
const struct switchdev_obj_port_mdb *mdb)
const struct switchdev_obj_port_mdb *mdb,
struct dsa_db db)
{
struct lan9303 *chip = ds->priv;
int err;
......@@ -1260,7 +1263,8 @@ static int lan9303_port_mdb_add(struct dsa_switch *ds, int port,
}
static int lan9303_port_mdb_del(struct dsa_switch *ds, int port,
const struct switchdev_obj_port_mdb *mdb)
const struct switchdev_obj_port_mdb *mdb,
struct dsa_db db)
{
struct lan9303 *chip = ds->priv;
......
......@@ -1152,7 +1152,8 @@ static int gswip_vlan_remove(struct gswip_priv *priv,
static int gswip_port_bridge_join(struct dsa_switch *ds, int port,
struct dsa_bridge bridge,
bool *tx_fwd_offload)
bool *tx_fwd_offload,
struct netlink_ext_ack *extack)
{
struct net_device *br = bridge.dev;
struct gswip_priv *priv = ds->priv;
......@@ -1389,13 +1390,15 @@ static int gswip_port_fdb(struct dsa_switch *ds, int port,
}
static int gswip_port_fdb_add(struct dsa_switch *ds, int port,
const unsigned char *addr, u16 vid)
const unsigned char *addr, u16 vid,
struct dsa_db db)
{
return gswip_port_fdb(ds, port, addr, vid, true);
}
static int gswip_port_fdb_del(struct dsa_switch *ds, int port,
const unsigned char *addr, u16 vid)
const unsigned char *addr, u16 vid,
struct dsa_db db)
{
return gswip_port_fdb(ds, port, addr, vid, false);
}
......
......@@ -640,7 +640,8 @@ static int ksz9477_port_vlan_del(struct dsa_switch *ds, int port,
}
static int ksz9477_port_fdb_add(struct dsa_switch *ds, int port,
const unsigned char *addr, u16 vid)
const unsigned char *addr, u16 vid,
struct dsa_db db)
{
struct ksz_device *dev = ds->priv;
u32 alu_table[4];
......@@ -697,7 +698,8 @@ static int ksz9477_port_fdb_add(struct dsa_switch *ds, int port,
}
static int ksz9477_port_fdb_del(struct dsa_switch *ds, int port,
const unsigned char *addr, u16 vid)
const unsigned char *addr, u16 vid,
struct dsa_db db)
{
struct ksz_device *dev = ds->priv;
u32 alu_table[4];
......@@ -839,7 +841,8 @@ static int ksz9477_port_fdb_dump(struct dsa_switch *ds, int port,
}
static int ksz9477_port_mdb_add(struct dsa_switch *ds, int port,
const struct switchdev_obj_port_mdb *mdb)
const struct switchdev_obj_port_mdb *mdb,
struct dsa_db db)
{
struct ksz_device *dev = ds->priv;
u32 static_table[4];
......@@ -914,7 +917,8 @@ static int ksz9477_port_mdb_add(struct dsa_switch *ds, int port,
}
static int ksz9477_port_mdb_del(struct dsa_switch *ds, int port,
const struct switchdev_obj_port_mdb *mdb)
const struct switchdev_obj_port_mdb *mdb,
struct dsa_db db)
{
struct ksz_device *dev = ds->priv;
u32 static_table[4];
......
......@@ -217,7 +217,8 @@ EXPORT_SYMBOL_GPL(ksz_get_ethtool_stats);
int ksz_port_bridge_join(struct dsa_switch *ds, int port,
struct dsa_bridge bridge,
bool *tx_fwd_offload)
bool *tx_fwd_offload,
struct netlink_ext_ack *extack)
{
/* port_stp_state_set() will be called after to put the port in
* appropriate state so there is no need to do anything.
......@@ -276,7 +277,8 @@ int ksz_port_fdb_dump(struct dsa_switch *ds, int port, dsa_fdb_dump_cb_t *cb,
EXPORT_SYMBOL_GPL(ksz_port_fdb_dump);
int ksz_port_mdb_add(struct dsa_switch *ds, int port,
const struct switchdev_obj_port_mdb *mdb)
const struct switchdev_obj_port_mdb *mdb,
struct dsa_db db)
{
struct ksz_device *dev = ds->priv;
struct alu_struct alu;
......@@ -321,7 +323,8 @@ int ksz_port_mdb_add(struct dsa_switch *ds, int port,
EXPORT_SYMBOL_GPL(ksz_port_mdb_add);
int ksz_port_mdb_del(struct dsa_switch *ds, int port,
const struct switchdev_obj_port_mdb *mdb)
const struct switchdev_obj_port_mdb *mdb,
struct dsa_db db)
{
struct ksz_device *dev = ds->priv;
struct alu_struct alu;
......
......@@ -159,16 +159,19 @@ void ksz_mac_link_down(struct dsa_switch *ds, int port, unsigned int mode,
int ksz_sset_count(struct dsa_switch *ds, int port, int sset);
void ksz_get_ethtool_stats(struct dsa_switch *ds, int port, uint64_t *buf);
int ksz_port_bridge_join(struct dsa_switch *ds, int port,
struct dsa_bridge bridge, bool *tx_fwd_offload);
struct dsa_bridge bridge, bool *tx_fwd_offload,
struct netlink_ext_ack *extack);
void ksz_port_bridge_leave(struct dsa_switch *ds, int port,
struct dsa_bridge bridge);
void ksz_port_fast_age(struct dsa_switch *ds, int port);
int ksz_port_fdb_dump(struct dsa_switch *ds, int port, dsa_fdb_dump_cb_t *cb,
void *data);
int ksz_port_mdb_add(struct dsa_switch *ds, int port,
const struct switchdev_obj_port_mdb *mdb);
const struct switchdev_obj_port_mdb *mdb,
struct dsa_db db);
int ksz_port_mdb_del(struct dsa_switch *ds, int port,
const struct switchdev_obj_port_mdb *mdb);
const struct switchdev_obj_port_mdb *mdb,
struct dsa_db db);
int ksz_enable_port(struct dsa_switch *ds, int port, struct phy_device *phy);
/* Common register access functions */
......
......@@ -1186,7 +1186,8 @@ mt7530_port_bridge_flags(struct dsa_switch *ds, int port,
static int
mt7530_port_bridge_join(struct dsa_switch *ds, int port,
struct dsa_bridge bridge, bool *tx_fwd_offload)
struct dsa_bridge bridge, bool *tx_fwd_offload,
struct netlink_ext_ack *extack)
{
struct dsa_port *dp = dsa_to_port(ds, port), *other_dp;
u32 port_bitmap = BIT(MT7530_CPU_PORT);
......@@ -1349,7 +1350,8 @@ mt7530_port_bridge_leave(struct dsa_switch *ds, int port,
static int
mt7530_port_fdb_add(struct dsa_switch *ds, int port,
const unsigned char *addr, u16 vid)
const unsigned char *addr, u16 vid,
struct dsa_db db)
{
struct mt7530_priv *priv = ds->priv;
int ret;
......@@ -1365,7 +1367,8 @@ mt7530_port_fdb_add(struct dsa_switch *ds, int port,
static int
mt7530_port_fdb_del(struct dsa_switch *ds, int port,
const unsigned char *addr, u16 vid)
const unsigned char *addr, u16 vid,
struct dsa_db db)
{
struct mt7530_priv *priv = ds->priv;
int ret;
......@@ -1416,7 +1419,8 @@ mt7530_port_fdb_dump(struct dsa_switch *ds, int port,
static int
mt7530_port_mdb_add(struct dsa_switch *ds, int port,
const struct switchdev_obj_port_mdb *mdb)
const struct switchdev_obj_port_mdb *mdb,
struct dsa_db db)
{
struct mt7530_priv *priv = ds->priv;
const u8 *addr = mdb->addr;
......@@ -1442,7 +1446,8 @@ mt7530_port_mdb_add(struct dsa_switch *ds, int port,
static int
mt7530_port_mdb_del(struct dsa_switch *ds, int port,
const struct switchdev_obj_port_mdb *mdb)
const struct switchdev_obj_port_mdb *mdb,
struct dsa_db db)
{
struct mt7530_priv *priv = ds->priv;
const u8 *addr = mdb->addr;
......
......@@ -2456,7 +2456,8 @@ static int mv88e6xxx_port_vlan_del(struct dsa_switch *ds, int port,
}
static int mv88e6xxx_port_fdb_add(struct dsa_switch *ds, int port,
const unsigned char *addr, u16 vid)
const unsigned char *addr, u16 vid,
struct dsa_db db)
{
struct mv88e6xxx_chip *chip = ds->priv;
int err;
......@@ -2470,7 +2471,8 @@ static int mv88e6xxx_port_fdb_add(struct dsa_switch *ds, int port,
}
static int mv88e6xxx_port_fdb_del(struct dsa_switch *ds, int port,
const unsigned char *addr, u16 vid)
const unsigned char *addr, u16 vid,
struct dsa_db db)
{
struct mv88e6xxx_chip *chip = ds->priv;
int err;
......@@ -2616,7 +2618,8 @@ static int mv88e6xxx_map_virtual_bridge_to_pvt(struct dsa_switch *ds,
static int mv88e6xxx_port_bridge_join(struct dsa_switch *ds, int port,
struct dsa_bridge bridge,
bool *tx_fwd_offload)
bool *tx_fwd_offload,
struct netlink_ext_ack *extack)
{
struct mv88e6xxx_chip *chip = ds->priv;
int err;
......@@ -2682,7 +2685,8 @@ static void mv88e6xxx_port_bridge_leave(struct dsa_switch *ds, int port,
static int mv88e6xxx_crosschip_bridge_join(struct dsa_switch *ds,
int tree_index, int sw_index,
int port, struct dsa_bridge bridge)
int port, struct dsa_bridge bridge,
struct netlink_ext_ack *extack)
{
struct mv88e6xxx_chip *chip = ds->priv;
int err;
......@@ -6002,7 +6006,8 @@ static int mv88e6xxx_change_tag_protocol(struct dsa_switch *ds, int port,
}
static int mv88e6xxx_port_mdb_add(struct dsa_switch *ds, int port,
const struct switchdev_obj_port_mdb *mdb)
const struct switchdev_obj_port_mdb *mdb,
struct dsa_db db)
{
struct mv88e6xxx_chip *chip = ds->priv;
int err;
......@@ -6016,7 +6021,8 @@ static int mv88e6xxx_port_mdb_add(struct dsa_switch *ds, int port,
}
static int mv88e6xxx_port_mdb_del(struct dsa_switch *ds, int port,
const struct switchdev_obj_port_mdb *mdb)
const struct switchdev_obj_port_mdb *mdb,
struct dsa_db db)
{
struct mv88e6xxx_chip *chip = ds->priv;
int err;
......
This diff is collapsed.
......@@ -2247,7 +2247,8 @@ qca8k_port_stp_state_set(struct dsa_switch *ds, int port, u8 state)
static int qca8k_port_bridge_join(struct dsa_switch *ds, int port,
struct dsa_bridge bridge,
bool *tx_fwd_offload)
bool *tx_fwd_offload,
struct netlink_ext_ack *extack)
{
struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv;
int port_mask, cpu_port;
......@@ -2398,7 +2399,8 @@ qca8k_port_fdb_insert(struct qca8k_priv *priv, const u8 *addr,
static int
qca8k_port_fdb_add(struct dsa_switch *ds, int port,
const unsigned char *addr, u16 vid)
const unsigned char *addr, u16 vid,
struct dsa_db db)
{
struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv;
u16 port_mask = BIT(port);
......@@ -2408,7 +2410,8 @@ qca8k_port_fdb_add(struct dsa_switch *ds, int port,
static int
qca8k_port_fdb_del(struct dsa_switch *ds, int port,
const unsigned char *addr, u16 vid)
const unsigned char *addr, u16 vid,
struct dsa_db db)
{
struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv;
u16 port_mask = BIT(port);
......@@ -2445,7 +2448,8 @@ qca8k_port_fdb_dump(struct dsa_switch *ds, int port,
static int
qca8k_port_mdb_add(struct dsa_switch *ds, int port,
const struct switchdev_obj_port_mdb *mdb)
const struct switchdev_obj_port_mdb *mdb,
struct dsa_db db)
{
struct qca8k_priv *priv = ds->priv;
const u8 *addr = mdb->addr;
......@@ -2456,7 +2460,8 @@ qca8k_port_mdb_add(struct dsa_switch *ds, int port,
static int
qca8k_port_mdb_del(struct dsa_switch *ds, int port,
const struct switchdev_obj_port_mdb *mdb)
const struct switchdev_obj_port_mdb *mdb,
struct dsa_db db)
{
struct qca8k_priv *priv = ds->priv;
const u8 *addr = mdb->addr;
......
......@@ -1189,7 +1189,8 @@ rtl8366rb_port_disable(struct dsa_switch *ds, int port)
static int
rtl8366rb_port_bridge_join(struct dsa_switch *ds, int port,
struct dsa_bridge bridge,
bool *tx_fwd_offload)
bool *tx_fwd_offload,
struct netlink_ext_ack *extack)
{
struct realtek_priv *priv = ds->priv;
unsigned int port_bitmap = 0;
......
......@@ -393,10 +393,8 @@ static int sja1105_init_l2_lookup_params(struct sja1105_private *priv)
.start_dynspc = 0,
/* 2^8 + 2^5 + 2^3 + 2^2 + 2^1 + 1 in Koopman notation */
.poly = 0x97,
/* This selects between Independent VLAN Learning (IVL) and
* Shared VLAN Learning (SVL)
*/
.shared_learn = true,
/* Always use Independent VLAN Learning (IVL) */
.shared_learn = false,
/* Don't discard management traffic based on ENFPORT -
* we don't perform SMAC port enforcement anyway, so
* what we are setting here doesn't matter.
......@@ -1803,25 +1801,52 @@ int sja1105pqrs_fdb_del(struct dsa_switch *ds, int port,
}
static int sja1105_fdb_add(struct dsa_switch *ds, int port,
const unsigned char *addr, u16 vid)
const unsigned char *addr, u16 vid,
struct dsa_db db)
{
struct sja1105_private *priv = ds->priv;
if (!vid) {
switch (db.type) {
case DSA_DB_PORT:
vid = dsa_tag_8021q_standalone_vid(db.dp);
break;
case DSA_DB_BRIDGE:
vid = dsa_tag_8021q_bridge_vid(db.bridge.num);
break;
default:
return -EOPNOTSUPP;
}
}
return priv->info->fdb_add_cmd(ds, port, addr, vid);
}
static int sja1105_fdb_del(struct dsa_switch *ds, int port,
const unsigned char *addr, u16 vid)
const unsigned char *addr, u16 vid,
struct dsa_db db)
{
struct sja1105_private *priv = ds->priv;
if (!vid) {
switch (db.type) {
case DSA_DB_PORT:
vid = dsa_tag_8021q_standalone_vid(db.dp);
break;
case DSA_DB_BRIDGE:
vid = dsa_tag_8021q_bridge_vid(db.bridge.num);
break;
default:
return -EOPNOTSUPP;
}
}
return priv->info->fdb_del_cmd(ds, port, addr, vid);
}
static int sja1105_fdb_dump(struct dsa_switch *ds, int port,
dsa_fdb_dump_cb_t *cb, void *data)
{
struct dsa_port *dp = dsa_to_port(ds, port);
struct sja1105_private *priv = ds->priv;
struct device *dev = ds->dev;
int i;
......@@ -1858,7 +1883,7 @@ static int sja1105_fdb_dump(struct dsa_switch *ds, int port,
u64_to_ether_addr(l2_lookup.macaddr, macaddr);
/* We need to hide the dsa_8021q VLANs from the user. */
if (!dsa_port_is_vlan_filtering(dp))
if (vid_is_dsa_8021q(l2_lookup.vlanid))
l2_lookup.vlanid = 0;
rc = cb(macaddr, l2_lookup.vlanid, l2_lookup.lockeds, data);
if (rc)
......@@ -1869,7 +1894,15 @@ static int sja1105_fdb_dump(struct dsa_switch *ds, int port,
static void sja1105_fast_age(struct dsa_switch *ds, int port)
{
struct dsa_port *dp = dsa_to_port(ds, port);
struct sja1105_private *priv = ds->priv;
struct dsa_db db = {
.type = DSA_DB_BRIDGE,
.bridge = {
.dev = dsa_port_bridge_dev_get(dp),
.num = dsa_port_bridge_num_get(dp),
},
};
int i;
for (i = 0; i < SJA1105_MAX_L2_LOOKUP_COUNT; i++) {
......@@ -1897,7 +1930,7 @@ static void sja1105_fast_age(struct dsa_switch *ds, int port)
u64_to_ether_addr(l2_lookup.macaddr, macaddr);
rc = sja1105_fdb_del(ds, port, macaddr, l2_lookup.vlanid);
rc = sja1105_fdb_del(ds, port, macaddr, l2_lookup.vlanid, db);
if (rc) {
dev_err(ds->dev,
"Failed to delete FDB entry %pM vid %lld: %pe\n",
......@@ -1908,15 +1941,17 @@ static void sja1105_fast_age(struct dsa_switch *ds, int port)
}
static int sja1105_mdb_add(struct dsa_switch *ds, int port,
const struct switchdev_obj_port_mdb *mdb)
const struct switchdev_obj_port_mdb *mdb,
struct dsa_db db)
{
return sja1105_fdb_add(ds, port, mdb->addr, mdb->vid);
return sja1105_fdb_add(ds, port, mdb->addr, mdb->vid, db);
}
static int sja1105_mdb_del(struct dsa_switch *ds, int port,
const struct switchdev_obj_port_mdb *mdb)
const struct switchdev_obj_port_mdb *mdb,
struct dsa_db db)
{
return sja1105_fdb_del(ds, port, mdb->addr, mdb->vid);
return sja1105_fdb_del(ds, port, mdb->addr, mdb->vid, db);
}
/* Common function for unicast and broadcast flood configuration.
......@@ -2059,7 +2094,8 @@ static void sja1105_bridge_stp_state_set(struct dsa_switch *ds, int port,
static int sja1105_bridge_join(struct dsa_switch *ds, int port,
struct dsa_bridge bridge,
bool *tx_fwd_offload)
bool *tx_fwd_offload,
struct netlink_ext_ack *extack)
{
int rc;
......@@ -2067,7 +2103,7 @@ static int sja1105_bridge_join(struct dsa_switch *ds, int port,
if (rc)
return rc;
rc = dsa_tag_8021q_bridge_tx_fwd_offload(ds, port, bridge);
rc = dsa_tag_8021q_bridge_join(ds, port, bridge);
if (rc) {
sja1105_bridge_member(ds, port, bridge, false);
return rc;
......@@ -2081,7 +2117,7 @@ static int sja1105_bridge_join(struct dsa_switch *ds, int port,
static void sja1105_bridge_leave(struct dsa_switch *ds, int port,
struct dsa_bridge bridge)
{
dsa_tag_8021q_bridge_tx_fwd_unoffload(ds, port, bridge);
dsa_tag_8021q_bridge_leave(ds, port, bridge);
sja1105_bridge_member(ds, port, bridge, false);
}
......@@ -2341,7 +2377,6 @@ sja1105_get_tag_protocol(struct dsa_switch *ds, int port,
int sja1105_vlan_filtering(struct dsa_switch *ds, int port, bool enabled,
struct netlink_ext_ack *extack)
{
struct sja1105_l2_lookup_params_entry *l2_lookup_params;
struct sja1105_general_params_entry *general_params;
struct sja1105_private *priv = ds->priv;
struct sja1105_table *table;
......@@ -2379,28 +2414,6 @@ int sja1105_vlan_filtering(struct dsa_switch *ds, int port, bool enabled,
general_params->incl_srcpt1 = enabled;
general_params->incl_srcpt0 = enabled;
/* VLAN filtering => independent VLAN learning.
* No VLAN filtering (or best effort) => shared VLAN learning.
*
* In shared VLAN learning mode, untagged traffic still gets
* pvid-tagged, and the FDB table gets populated with entries
* containing the "real" (pvid or from VLAN tag) VLAN ID.
* However the switch performs a masked L2 lookup in the FDB,
* effectively only looking up a frame's DMAC (and not VID) for the
* forwarding decision.
*
* This is extremely convenient for us, because in modes with
* vlan_filtering=0, dsa_8021q actually installs unique pvid's into
* each front panel port. This is good for identification but breaks
* learning badly - the VID of the learnt FDB entry is unique, aka
* no frames coming from any other port are going to have it. So
* for forwarding purposes, this is as though learning was broken
* (all frames get flooded).
*/
table = &priv->static_config.tables[BLK_IDX_L2_LOOKUP_PARAMS];
l2_lookup_params = table->entries;
l2_lookup_params->shared_learn = !enabled;
for (port = 0; port < ds->num_ports; port++) {
if (dsa_is_unused_port(ds, port))
continue;
......@@ -2509,7 +2522,7 @@ static int sja1105_bridge_vlan_add(struct dsa_switch *ds, int port,
*/
if (vid_is_dsa_8021q(vlan->vid)) {
NL_SET_ERR_MSG_MOD(extack,
"Range 1024-3071 reserved for dsa_8021q operation");
"Range 3072-4095 reserved for dsa_8021q operation");
return -EBUSY;
}
......@@ -3086,6 +3099,7 @@ static int sja1105_setup(struct dsa_switch *ds)
*/
ds->vlan_filtering_is_global = true;
ds->untag_bridge_pvid = true;
ds->fdb_isolation = true;
/* tag_8021q has 3 bits for the VBID, and the value 0 is reserved */
ds->max_num_bridges = 7;
......
......@@ -296,6 +296,19 @@ static bool sja1105_vl_key_lower(struct sja1105_vl_lookup_entry *a,
return false;
}
/* FIXME: this should change when the bridge upper of the port changes. */
static u16 sja1105_port_get_tag_8021q_vid(struct dsa_port *dp)
{
unsigned long bridge_num;
if (!dp->bridge)
return dsa_tag_8021q_standalone_vid(dp);
bridge_num = dsa_port_bridge_num_get(dp);
return dsa_tag_8021q_bridge_vid(bridge_num);
}
static int sja1105_init_virtual_links(struct sja1105_private *priv,
struct netlink_ext_ack *extack)
{
......@@ -394,8 +407,9 @@ static int sja1105_init_virtual_links(struct sja1105_private *priv,
vl_lookup[k].vlanid = rule->key.vl.vid;
vl_lookup[k].vlanprior = rule->key.vl.pcp;
} else {
/* FIXME */
struct dsa_port *dp = dsa_to_port(priv->ds, port);
u16 vid = dsa_tag_8021q_rx_vid(dp);
u16 vid = sja1105_port_get_tag_8021q_vid(dp);
vl_lookup[k].vlanid = vid;
vl_lookup[k].vlanprior = 0;
......
......@@ -534,7 +534,8 @@ static int xrs700x_bridge_common(struct dsa_switch *ds, int port,
}
static int xrs700x_bridge_join(struct dsa_switch *ds, int port,
struct dsa_bridge bridge, bool *tx_fwd_offload)
struct dsa_bridge bridge, bool *tx_fwd_offload,
struct netlink_ext_ack *extack)
{
return xrs700x_bridge_common(ds, port, bridge, true);
}
......
This diff is collapsed.
......@@ -26,7 +26,7 @@
#include "ocelot_rew.h"
#include "ocelot_qs.h"
#define OCELOT_VLAN_UNAWARE_PVID 0
#define OCELOT_STANDALONE_PVID 0
#define OCELOT_BUFFER_CELL_SZ 60
#define OCELOT_STATS_CHECK_DELAY (2 * HZ)
......@@ -81,6 +81,9 @@ struct ocelot_multicast {
struct ocelot_pgid *pgid;
};
int ocelot_bridge_num_find(struct ocelot *ocelot,
const struct net_device *bridge);
int ocelot_port_fdb_do_dump(const unsigned char *addr, u16 vid,
bool is_static, void *data);
int ocelot_mact_learn(struct ocelot *ocelot, int port,
......
......@@ -107,16 +107,16 @@ static void ocelot_mrp_save_mac(struct ocelot *ocelot,
struct ocelot_port *port)
{
ocelot_mact_learn(ocelot, PGID_BLACKHOLE, mrp_test_dmac,
OCELOT_VLAN_UNAWARE_PVID, ENTRYTYPE_LOCKED);
OCELOT_STANDALONE_PVID, ENTRYTYPE_LOCKED);
ocelot_mact_learn(ocelot, PGID_BLACKHOLE, mrp_control_dmac,
OCELOT_VLAN_UNAWARE_PVID, ENTRYTYPE_LOCKED);
OCELOT_STANDALONE_PVID, ENTRYTYPE_LOCKED);
}
static void ocelot_mrp_del_mac(struct ocelot *ocelot,
struct ocelot_port *port)
{
ocelot_mact_forget(ocelot, mrp_test_dmac, OCELOT_VLAN_UNAWARE_PVID);
ocelot_mact_forget(ocelot, mrp_control_dmac, OCELOT_VLAN_UNAWARE_PVID);
ocelot_mact_forget(ocelot, mrp_test_dmac, OCELOT_STANDALONE_PVID);
ocelot_mact_forget(ocelot, mrp_control_dmac, OCELOT_STANDALONE_PVID);
}
int ocelot_mrp_add(struct ocelot *ocelot, int port,
......
......@@ -419,7 +419,7 @@ static int ocelot_vlan_vid_del(struct net_device *dev, u16 vid)
* with VLAN filtering feature. We need to keep it to receive
* untagged traffic.
*/
if (vid == OCELOT_VLAN_UNAWARE_PVID)
if (vid == OCELOT_STANDALONE_PVID)
return 0;
ret = ocelot_vlan_del(ocelot, port, vid);
......@@ -559,7 +559,7 @@ static int ocelot_mc_unsync(struct net_device *dev, const unsigned char *addr)
struct ocelot_mact_work_ctx w;
ether_addr_copy(w.forget.addr, addr);
w.forget.vid = OCELOT_VLAN_UNAWARE_PVID;
w.forget.vid = OCELOT_STANDALONE_PVID;
w.type = OCELOT_MACT_FORGET;
return ocelot_enqueue_mact_action(ocelot, &w);
......@@ -573,7 +573,7 @@ static int ocelot_mc_sync(struct net_device *dev, const unsigned char *addr)
struct ocelot_mact_work_ctx w;
ether_addr_copy(w.learn.addr, addr);
w.learn.vid = OCELOT_VLAN_UNAWARE_PVID;
w.learn.vid = OCELOT_STANDALONE_PVID;
w.learn.pgid = PGID_CPU;
w.learn.entry_type = ENTRYTYPE_LOCKED;
w.type = OCELOT_MACT_LEARN;
......@@ -608,9 +608,9 @@ static int ocelot_port_set_mac_address(struct net_device *dev, void *p)
/* Learn the new net device MAC address in the mac table. */
ocelot_mact_learn(ocelot, PGID_CPU, addr->sa_data,
OCELOT_VLAN_UNAWARE_PVID, ENTRYTYPE_LOCKED);
OCELOT_STANDALONE_PVID, ENTRYTYPE_LOCKED);
/* Then forget the previous one. */
ocelot_mact_forget(ocelot, dev->dev_addr, OCELOT_VLAN_UNAWARE_PVID);
ocelot_mact_forget(ocelot, dev->dev_addr, OCELOT_STANDALONE_PVID);
eth_hw_addr_set(dev, addr->sa_data);
return 0;
......@@ -662,10 +662,11 @@ static int ocelot_port_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
struct netlink_ext_ack *extack)
{
struct ocelot_port_private *priv = netdev_priv(dev);
struct ocelot *ocelot = priv->port.ocelot;
struct ocelot_port *ocelot_port = &priv->port;
struct ocelot *ocelot = ocelot_port->ocelot;
int port = priv->chip_port;
return ocelot_fdb_add(ocelot, port, addr, vid);
return ocelot_fdb_add(ocelot, port, addr, vid, ocelot_port->bridge);
}
static int ocelot_port_fdb_del(struct ndmsg *ndm, struct nlattr *tb[],
......@@ -673,10 +674,11 @@ static int ocelot_port_fdb_del(struct ndmsg *ndm, struct nlattr *tb[],
const unsigned char *addr, u16 vid)
{
struct ocelot_port_private *priv = netdev_priv(dev);
struct ocelot *ocelot = priv->port.ocelot;
struct ocelot_port *ocelot_port = &priv->port;
struct ocelot *ocelot = ocelot_port->ocelot;
int port = priv->chip_port;
return ocelot_fdb_del(ocelot, port, addr, vid);
return ocelot_fdb_del(ocelot, port, addr, vid, ocelot_port->bridge);
}
static int ocelot_port_fdb_dump(struct sk_buff *skb,
......@@ -988,7 +990,7 @@ static int ocelot_port_obj_add_mdb(struct net_device *dev,
struct ocelot *ocelot = ocelot_port->ocelot;
int port = priv->chip_port;
return ocelot_port_mdb_add(ocelot, port, mdb);
return ocelot_port_mdb_add(ocelot, port, mdb, ocelot_port->bridge);
}
static int ocelot_port_obj_del_mdb(struct net_device *dev,
......@@ -999,7 +1001,7 @@ static int ocelot_port_obj_del_mdb(struct net_device *dev,
struct ocelot *ocelot = ocelot_port->ocelot;
int port = priv->chip_port;
return ocelot_port_mdb_del(ocelot, port, mdb);
return ocelot_port_mdb_del(ocelot, port, mdb, ocelot_port->bridge);
}
static int ocelot_port_obj_mrp_add(struct net_device *dev,
......@@ -1173,6 +1175,33 @@ static int ocelot_switchdev_unsync(struct ocelot *ocelot, int port)
return 0;
}
static int ocelot_bridge_num_get(struct ocelot *ocelot,
const struct net_device *bridge_dev)
{
int bridge_num = ocelot_bridge_num_find(ocelot, bridge_dev);
if (bridge_num < 0) {
/* First port that offloads this bridge */
bridge_num = find_first_zero_bit(&ocelot->bridges,
ocelot->num_phys_ports);
set_bit(bridge_num, &ocelot->bridges);
}
return bridge_num;
}
static void ocelot_bridge_num_put(struct ocelot *ocelot,
const struct net_device *bridge_dev,
int bridge_num)
{
/* Check if the bridge is still in use, otherwise it is time
* to clean it up so we can reuse this bridge_num later.
*/
if (!ocelot_bridge_num_find(ocelot, bridge_dev))
clear_bit(bridge_num, &ocelot->bridges);
}
static int ocelot_netdevice_bridge_join(struct net_device *dev,
struct net_device *brport_dev,
struct net_device *bridge,
......@@ -1182,9 +1211,14 @@ static int ocelot_netdevice_bridge_join(struct net_device *dev,
struct ocelot_port *ocelot_port = &priv->port;
struct ocelot *ocelot = ocelot_port->ocelot;
int port = priv->chip_port;
int err;
int bridge_num, err;
ocelot_port_bridge_join(ocelot, port, bridge);
bridge_num = ocelot_bridge_num_get(ocelot, bridge);
err = ocelot_port_bridge_join(ocelot, port, bridge, bridge_num,
extack);
if (err)
goto err_join;
err = switchdev_bridge_port_offload(brport_dev, dev, priv,
&ocelot_switchdev_nb,
......@@ -1205,6 +1239,8 @@ static int ocelot_netdevice_bridge_join(struct net_device *dev,
&ocelot_switchdev_blocking_nb);
err_switchdev_offload:
ocelot_port_bridge_leave(ocelot, port, bridge);
err_join:
ocelot_bridge_num_put(ocelot, bridge, bridge_num);
return err;
}
......@@ -1225,6 +1261,7 @@ static int ocelot_netdevice_bridge_leave(struct net_device *dev,
struct ocelot_port_private *priv = netdev_priv(dev);
struct ocelot_port *ocelot_port = &priv->port;
struct ocelot *ocelot = ocelot_port->ocelot;
int bridge_num = ocelot_port->bridge_num;
int port = priv->chip_port;
int err;
......@@ -1233,6 +1270,7 @@ static int ocelot_netdevice_bridge_leave(struct net_device *dev,
return err;
ocelot_port_bridge_leave(ocelot, port, bridge);
ocelot_bridge_num_put(ocelot, bridge, bridge_num);
return 0;
}
......@@ -1700,7 +1738,7 @@ int ocelot_probe_port(struct ocelot *ocelot, int port, struct regmap *target,
eth_hw_addr_gen(dev, ocelot->base_mac, port);
ocelot_mact_learn(ocelot, PGID_CPU, dev->dev_addr,
OCELOT_VLAN_UNAWARE_PVID, ENTRYTYPE_LOCKED);
OCELOT_STANDALONE_PVID, ENTRYTYPE_LOCKED);
ocelot_init_port(ocelot, port);
......
......@@ -32,31 +32,29 @@ int dsa_tag_8021q_register(struct dsa_switch *ds, __be16 proto);
void dsa_tag_8021q_unregister(struct dsa_switch *ds);
struct sk_buff *dsa_8021q_xmit(struct sk_buff *skb, struct net_device *netdev,
u16 tpid, u16 tci);
int dsa_tag_8021q_bridge_join(struct dsa_switch *ds, int port,
struct dsa_bridge bridge);
void dsa_8021q_rcv(struct sk_buff *skb, int *source_port, int *switch_id);
void dsa_tag_8021q_bridge_leave(struct dsa_switch *ds, int port,
struct dsa_bridge bridge);
int dsa_tag_8021q_bridge_tx_fwd_offload(struct dsa_switch *ds, int port,
struct dsa_bridge bridge);
struct sk_buff *dsa_8021q_xmit(struct sk_buff *skb, struct net_device *netdev,
u16 tpid, u16 tci);
void dsa_tag_8021q_bridge_tx_fwd_unoffload(struct dsa_switch *ds, int port,
struct dsa_bridge bridge);
void dsa_8021q_rcv(struct sk_buff *skb, int *source_port, int *switch_id,
int *vbid);
u16 dsa_8021q_bridge_tx_fwd_offload_vid(unsigned int bridge_num);
struct net_device *dsa_tag_8021q_find_port_by_vbid(struct net_device *master,
int vbid);
u16 dsa_tag_8021q_tx_vid(const struct dsa_port *dp);
u16 dsa_tag_8021q_bridge_vid(unsigned int bridge_num);
u16 dsa_tag_8021q_rx_vid(const struct dsa_port *dp);
u16 dsa_tag_8021q_standalone_vid(const struct dsa_port *dp);
int dsa_8021q_rx_switch_id(u16 vid);
int dsa_8021q_rx_source_port(u16 vid);
bool vid_is_dsa_8021q_rxvlan(u16 vid);
bool vid_is_dsa_8021q_txvlan(u16 vid);
bool vid_is_dsa_8021q(u16 vid);
#endif /* _NET_DSA_8021Q_H */
......@@ -341,11 +341,28 @@ struct dsa_link {
struct list_head list;
};
enum dsa_db_type {
DSA_DB_PORT,
DSA_DB_LAG,
DSA_DB_BRIDGE,
};
struct dsa_db {
enum dsa_db_type type;
union {
const struct dsa_port *dp;
struct dsa_lag lag;
struct dsa_bridge bridge;
};
};
struct dsa_mac_addr {
unsigned char addr[ETH_ALEN];
u16 vid;
refcount_t refcount;
struct list_head list;
struct dsa_db db;
};
struct dsa_vlan {
......@@ -409,6 +426,13 @@ struct dsa_switch {
*/
u32 mtu_enforcement_ingress:1;
/* Drivers that isolate the FDBs of multiple bridges must set this
* to true to receive the bridge as an argument in .port_fdb_{add,del}
* and .port_mdb_{add,del}. Otherwise, the bridge.num will always be
* passed as zero.
*/
u32 fdb_isolation:1;
/* Listener for switch fabric events */
struct notifier_block nb;
......@@ -913,7 +937,8 @@ struct dsa_switch_ops {
int (*set_ageing_time)(struct dsa_switch *ds, unsigned int msecs);
int (*port_bridge_join)(struct dsa_switch *ds, int port,
struct dsa_bridge bridge,
bool *tx_fwd_offload);
bool *tx_fwd_offload,
struct netlink_ext_ack *extack);
void (*port_bridge_leave)(struct dsa_switch *ds, int port,
struct dsa_bridge bridge);
void (*port_stp_state_set)(struct dsa_switch *ds, int port,
......@@ -941,23 +966,29 @@ struct dsa_switch_ops {
* Forwarding database
*/
int (*port_fdb_add)(struct dsa_switch *ds, int port,
const unsigned char *addr, u16 vid);
const unsigned char *addr, u16 vid,
struct dsa_db db);
int (*port_fdb_del)(struct dsa_switch *ds, int port,
const unsigned char *addr, u16 vid);
const unsigned char *addr, u16 vid,
struct dsa_db db);
int (*port_fdb_dump)(struct dsa_switch *ds, int port,
dsa_fdb_dump_cb_t *cb, void *data);
int (*lag_fdb_add)(struct dsa_switch *ds, struct dsa_lag lag,
const unsigned char *addr, u16 vid);
const unsigned char *addr, u16 vid,
struct dsa_db db);
int (*lag_fdb_del)(struct dsa_switch *ds, struct dsa_lag lag,
const unsigned char *addr, u16 vid);
const unsigned char *addr, u16 vid,
struct dsa_db db);
/*
* Multicast database
*/
int (*port_mdb_add)(struct dsa_switch *ds, int port,
const struct switchdev_obj_port_mdb *mdb);
const struct switchdev_obj_port_mdb *mdb,
struct dsa_db db);
int (*port_mdb_del)(struct dsa_switch *ds, int port,
const struct switchdev_obj_port_mdb *mdb);
const struct switchdev_obj_port_mdb *mdb,
struct dsa_db db);
/*
* RXNFC
*/
......@@ -991,7 +1022,8 @@ struct dsa_switch_ops {
*/
int (*crosschip_bridge_join)(struct dsa_switch *ds, int tree_index,
int sw_index, int port,
struct dsa_bridge bridge);
struct dsa_bridge bridge,
struct netlink_ext_ack *extack);
void (*crosschip_bridge_leave)(struct dsa_switch *ds, int tree_index,
int sw_index, int port,
struct dsa_bridge bridge);
......
......@@ -668,6 +668,7 @@ struct ocelot_port {
u16 mrp_ring_id;
struct net_device *bridge;
int bridge_num;
u8 stp_state;
int speed;
......@@ -713,6 +714,8 @@ struct ocelot {
enum ocelot_tag_prefix npi_inj_prefix;
enum ocelot_tag_prefix npi_xtr_prefix;
unsigned long bridges;
struct list_head multicast;
struct list_head pgids;
......@@ -846,6 +849,9 @@ void ocelot_deinit(struct ocelot *ocelot);
void ocelot_init_port(struct ocelot *ocelot, int port);
void ocelot_deinit_port(struct ocelot *ocelot, int port);
void ocelot_port_set_dsa_8021q_cpu(struct ocelot *ocelot, int port);
void ocelot_port_unset_dsa_8021q_cpu(struct ocelot *ocelot, int port);
/* DSA callbacks */
void ocelot_get_strings(struct ocelot *ocelot, int port, u32 sset, u8 *data);
void ocelot_get_ethtool_stats(struct ocelot *ocelot, int port, u64 *data);
......@@ -863,21 +869,24 @@ int ocelot_port_pre_bridge_flags(struct ocelot *ocelot, int port,
struct switchdev_brport_flags val);
void ocelot_port_bridge_flags(struct ocelot *ocelot, int port,
struct switchdev_brport_flags val);
void ocelot_port_bridge_join(struct ocelot *ocelot, int port,
struct net_device *bridge);
int ocelot_port_bridge_join(struct ocelot *ocelot, int port,
struct net_device *bridge, int bridge_num,
struct netlink_ext_ack *extack);
void ocelot_port_bridge_leave(struct ocelot *ocelot, int port,
struct net_device *bridge);
int ocelot_mact_flush(struct ocelot *ocelot, int port);
int ocelot_fdb_dump(struct ocelot *ocelot, int port,
dsa_fdb_dump_cb_t *cb, void *data);
int ocelot_fdb_add(struct ocelot *ocelot, int port,
const unsigned char *addr, u16 vid);
int ocelot_fdb_del(struct ocelot *ocelot, int port,
const unsigned char *addr, u16 vid);
int ocelot_fdb_add(struct ocelot *ocelot, int port, const unsigned char *addr,
u16 vid, const struct net_device *bridge);
int ocelot_fdb_del(struct ocelot *ocelot, int port, const unsigned char *addr,
u16 vid, const struct net_device *bridge);
int ocelot_lag_fdb_add(struct ocelot *ocelot, struct net_device *bond,
const unsigned char *addr, u16 vid);
const unsigned char *addr, u16 vid,
const struct net_device *bridge);
int ocelot_lag_fdb_del(struct ocelot *ocelot, struct net_device *bond,
const unsigned char *addr, u16 vid);
const unsigned char *addr, u16 vid,
const struct net_device *bridge);
int ocelot_vlan_prepare(struct ocelot *ocelot, int port, u16 vid, bool pvid,
bool untagged, struct netlink_ext_ack *extack);
int ocelot_vlan_add(struct ocelot *ocelot, int port, u16 vid, bool pvid,
......@@ -901,9 +910,11 @@ int ocelot_cls_flower_destroy(struct ocelot *ocelot, int port,
int ocelot_cls_flower_stats(struct ocelot *ocelot, int port,
struct flow_cls_offload *f, bool ingress);
int ocelot_port_mdb_add(struct ocelot *ocelot, int port,
const struct switchdev_obj_port_mdb *mdb);
const struct switchdev_obj_port_mdb *mdb,
const struct net_device *bridge);
int ocelot_port_mdb_del(struct ocelot *ocelot, int port,
const struct switchdev_obj_port_mdb *mdb);
const struct switchdev_obj_port_mdb *mdb,
const struct net_device *bridge);
int ocelot_port_lag_join(struct ocelot *ocelot, int port,
struct net_device *bond,
struct netdev_lag_upper_info *info);
......
......@@ -59,6 +59,7 @@ struct dsa_notifier_bridge_info {
int sw_index;
int port;
bool tx_fwd_offload;
struct netlink_ext_ack *extack;
};
/* DSA_NOTIFIER_FDB_* */
......@@ -67,6 +68,7 @@ struct dsa_notifier_fdb_info {
int port;
const unsigned char *addr;
u16 vid;
struct dsa_db db;
};
/* DSA_NOTIFIER_LAG_FDB_* */
......@@ -74,6 +76,7 @@ struct dsa_notifier_lag_fdb_info {
struct dsa_lag *lag;
const unsigned char *addr;
u16 vid;
struct dsa_db db;
};
/* DSA_NOTIFIER_MDB_* */
......@@ -81,6 +84,7 @@ struct dsa_notifier_mdb_info {
const struct switchdev_obj_port_mdb *mdb;
int sw_index;
int port;
struct dsa_db db;
};
/* DSA_NOTIFIER_LAG_* */
......@@ -522,10 +526,6 @@ struct dsa_bridge *dsa_tree_bridge_find(struct dsa_switch_tree *dst,
const struct net_device *br);
/* tag_8021q.c */
int dsa_tag_8021q_bridge_join(struct dsa_switch *ds,
struct dsa_notifier_bridge_info *info);
int dsa_tag_8021q_bridge_leave(struct dsa_switch *ds,
struct dsa_notifier_bridge_info *info);
int dsa_switch_tag_8021q_vlan_add(struct dsa_switch *ds,
struct dsa_notifier_tag_8021q_vlan_info *info);
int dsa_switch_tag_8021q_vlan_del(struct dsa_switch *ds,
......
......@@ -328,6 +328,7 @@ int dsa_port_bridge_join(struct dsa_port *dp, struct net_device *br,
.tree_index = dp->ds->dst->index,
.sw_index = dp->ds->index,
.port = dp->index,
.extack = extack,
};
struct net_device *dev = dp->slave;
struct net_device *brport_dev;
......@@ -798,8 +799,19 @@ int dsa_port_fdb_add(struct dsa_port *dp, const unsigned char *addr,
.port = dp->index,
.addr = addr,
.vid = vid,
.db = {
.type = DSA_DB_BRIDGE,
.bridge = *dp->bridge,
},
};
/* Refcounting takes bridge.num as a key, and should be global for all
* bridges in the absence of FDB isolation, and per bridge otherwise.
* Force the bridge.num to zero here in the absence of FDB isolation.
*/
if (!dp->ds->fdb_isolation)
info.db.bridge.num = 0;
return dsa_port_notify(dp, DSA_NOTIFIER_FDB_ADD, &info);
}
......@@ -811,9 +823,15 @@ int dsa_port_fdb_del(struct dsa_port *dp, const unsigned char *addr,
.port = dp->index,
.addr = addr,
.vid = vid,
.db = {
.type = DSA_DB_BRIDGE,
.bridge = *dp->bridge,
},
};
if (!dp->ds->fdb_isolation)
info.db.bridge.num = 0;
return dsa_port_notify(dp, DSA_NOTIFIER_FDB_DEL, &info);
}
......@@ -825,6 +843,10 @@ int dsa_port_host_fdb_add(struct dsa_port *dp, const unsigned char *addr,
.port = dp->index,
.addr = addr,
.vid = vid,
.db = {
.type = DSA_DB_BRIDGE,
.bridge = *dp->bridge,
},
};
struct dsa_port *cpu_dp = dp->cpu_dp;
int err;
......@@ -839,6 +861,9 @@ int dsa_port_host_fdb_add(struct dsa_port *dp, const unsigned char *addr,
return err;
}
if (!dp->ds->fdb_isolation)
info.db.bridge.num = 0;
return dsa_port_notify(dp, DSA_NOTIFIER_HOST_FDB_ADD, &info);
}
......@@ -850,6 +875,10 @@ int dsa_port_host_fdb_del(struct dsa_port *dp, const unsigned char *addr,
.port = dp->index,
.addr = addr,
.vid = vid,
.db = {
.type = DSA_DB_BRIDGE,
.bridge = *dp->bridge,
},
};
struct dsa_port *cpu_dp = dp->cpu_dp;
int err;
......@@ -860,6 +889,9 @@ int dsa_port_host_fdb_del(struct dsa_port *dp, const unsigned char *addr,
return err;
}
if (!dp->ds->fdb_isolation)
info.db.bridge.num = 0;
return dsa_port_notify(dp, DSA_NOTIFIER_HOST_FDB_DEL, &info);
}
......@@ -870,8 +902,15 @@ int dsa_port_lag_fdb_add(struct dsa_port *dp, const unsigned char *addr,
.lag = dp->lag,
.addr = addr,
.vid = vid,
.db = {
.type = DSA_DB_BRIDGE,
.bridge = *dp->bridge,
},
};
if (!dp->ds->fdb_isolation)
info.db.bridge.num = 0;
return dsa_port_notify(dp, DSA_NOTIFIER_LAG_FDB_ADD, &info);
}
......@@ -882,8 +921,15 @@ int dsa_port_lag_fdb_del(struct dsa_port *dp, const unsigned char *addr,
.lag = dp->lag,
.addr = addr,
.vid = vid,
.db = {
.type = DSA_DB_BRIDGE,
.bridge = *dp->bridge,
},
};
if (!dp->ds->fdb_isolation)
info.db.bridge.num = 0;
return dsa_port_notify(dp, DSA_NOTIFIER_LAG_FDB_DEL, &info);
}
......@@ -905,8 +951,15 @@ int dsa_port_mdb_add(const struct dsa_port *dp,
.sw_index = dp->ds->index,
.port = dp->index,
.mdb = mdb,
.db = {
.type = DSA_DB_BRIDGE,
.bridge = *dp->bridge,
},
};
if (!dp->ds->fdb_isolation)
info.db.bridge.num = 0;
return dsa_port_notify(dp, DSA_NOTIFIER_MDB_ADD, &info);
}
......@@ -917,8 +970,15 @@ int dsa_port_mdb_del(const struct dsa_port *dp,
.sw_index = dp->ds->index,
.port = dp->index,
.mdb = mdb,
.db = {
.type = DSA_DB_BRIDGE,
.bridge = *dp->bridge,
},
};
if (!dp->ds->fdb_isolation)
info.db.bridge.num = 0;
return dsa_port_notify(dp, DSA_NOTIFIER_MDB_DEL, &info);
}
......@@ -929,6 +989,10 @@ int dsa_port_host_mdb_add(const struct dsa_port *dp,
.sw_index = dp->ds->index,
.port = dp->index,
.mdb = mdb,
.db = {
.type = DSA_DB_BRIDGE,
.bridge = *dp->bridge,
},
};
struct dsa_port *cpu_dp = dp->cpu_dp;
int err;
......@@ -937,6 +1001,9 @@ int dsa_port_host_mdb_add(const struct dsa_port *dp,
if (err)
return err;
if (!dp->ds->fdb_isolation)
info.db.bridge.num = 0;
return dsa_port_notify(dp, DSA_NOTIFIER_HOST_MDB_ADD, &info);
}
......@@ -947,6 +1014,10 @@ int dsa_port_host_mdb_del(const struct dsa_port *dp,
.sw_index = dp->ds->index,
.port = dp->index,
.mdb = mdb,
.db = {
.type = DSA_DB_BRIDGE,
.bridge = *dp->bridge,
},
};
struct dsa_port *cpu_dp = dp->cpu_dp;
int err;
......@@ -955,6 +1026,9 @@ int dsa_port_host_mdb_del(const struct dsa_port *dp,
if (err)
return err;
if (!dp->ds->fdb_isolation)
info.db.bridge.num = 0;
return dsa_port_notify(dp, DSA_NOTIFIER_HOST_MDB_DEL, &info);
}
......
This diff is collapsed.
This diff is collapsed.
......@@ -62,7 +62,7 @@ static struct sk_buff *ocelot_xmit(struct sk_buff *skb,
struct dsa_port *dp = dsa_slave_to_port(netdev);
u16 queue_mapping = skb_get_queue_mapping(skb);
u8 pcp = netdev_txq_to_tc(netdev, queue_mapping);
u16 tx_vid = dsa_tag_8021q_tx_vid(dp);
u16 tx_vid = dsa_tag_8021q_standalone_vid(dp);
struct ethhdr *hdr = eth_hdr(skb);
if (ocelot_ptp_rew_op(skb) || is_link_local_ether_addr(hdr->h_dest))
......@@ -77,7 +77,7 @@ static struct sk_buff *ocelot_rcv(struct sk_buff *skb,
{
int src_port, switch_id;
dsa_8021q_rcv(skb, &src_port, &switch_id);
dsa_8021q_rcv(skb, &src_port, &switch_id, NULL);
skb->dev = dsa_master_find_slave(netdev, switch_id, src_port);
if (!skb->dev)
......
......@@ -226,7 +226,7 @@ static struct sk_buff *sja1105_imprecise_xmit(struct sk_buff *skb,
* TX VLAN that targets the bridge's entire broadcast domain,
* instead of just the specific port.
*/
tx_vid = dsa_8021q_bridge_tx_fwd_offload_vid(bridge_num);
tx_vid = dsa_tag_8021q_bridge_vid(bridge_num);
return dsa_8021q_xmit(skb, netdev, sja1105_xmit_tpid(dp), tx_vid);
}
......@@ -267,7 +267,7 @@ static struct sk_buff *sja1105_xmit(struct sk_buff *skb,
struct dsa_port *dp = dsa_slave_to_port(netdev);
u16 queue_mapping = skb_get_queue_mapping(skb);
u8 pcp = netdev_txq_to_tc(netdev, queue_mapping);
u16 tx_vid = dsa_tag_8021q_tx_vid(dp);
u16 tx_vid = dsa_tag_8021q_standalone_vid(dp);
if (skb->offload_fwd_mark)
return sja1105_imprecise_xmit(skb, netdev);
......@@ -295,7 +295,7 @@ static struct sk_buff *sja1110_xmit(struct sk_buff *skb,
struct dsa_port *dp = dsa_slave_to_port(netdev);
u16 queue_mapping = skb_get_queue_mapping(skb);
u8 pcp = netdev_txq_to_tc(netdev, queue_mapping);
u16 tx_vid = dsa_tag_8021q_tx_vid(dp);
u16 tx_vid = dsa_tag_8021q_standalone_vid(dp);
__be32 *tx_trailer;
__be16 *tx_header;
int trailer_pos;
......@@ -509,7 +509,7 @@ static bool sja1110_skb_has_inband_control_extension(const struct sk_buff *skb)
* packet.
*/
static void sja1105_vlan_rcv(struct sk_buff *skb, int *source_port,
int *switch_id, u16 *vid)
int *switch_id, int *vbid, u16 *vid)
{
struct vlan_ethhdr *hdr = (struct vlan_ethhdr *)skb_mac_header(skb);
u16 vlan_tci;
......@@ -519,8 +519,8 @@ static void sja1105_vlan_rcv(struct sk_buff *skb, int *source_port,
else
vlan_tci = ntohs(hdr->h_vlan_TCI);
if (vid_is_dsa_8021q_rxvlan(vlan_tci & VLAN_VID_MASK))
return dsa_8021q_rcv(skb, source_port, switch_id);
if (vid_is_dsa_8021q(vlan_tci & VLAN_VID_MASK))
return dsa_8021q_rcv(skb, source_port, switch_id, vbid);
/* Try our best with imprecise RX */
*vid = vlan_tci & VLAN_VID_MASK;
......@@ -529,7 +529,7 @@ static void sja1105_vlan_rcv(struct sk_buff *skb, int *source_port,
static struct sk_buff *sja1105_rcv(struct sk_buff *skb,
struct net_device *netdev)
{
int source_port = -1, switch_id = -1;
int source_port = -1, switch_id = -1, vbid = -1;
struct sja1105_meta meta = {0};
struct ethhdr *hdr;
bool is_link_local;
......@@ -542,7 +542,7 @@ static struct sk_buff *sja1105_rcv(struct sk_buff *skb,
if (sja1105_skb_has_tag_8021q(skb)) {
/* Normal traffic path. */
sja1105_vlan_rcv(skb, &source_port, &switch_id, &vid);
sja1105_vlan_rcv(skb, &source_port, &switch_id, &vbid, &vid);
} else if (is_link_local) {
/* Management traffic path. Switch embeds the switch ID and
* port ID into bytes of the destination MAC, courtesy of
......@@ -561,7 +561,9 @@ static struct sk_buff *sja1105_rcv(struct sk_buff *skb,
return NULL;
}
if (source_port == -1 || switch_id == -1)
if (vbid >= 1)
skb->dev = dsa_tag_8021q_find_port_by_vbid(netdev, vbid);
else if (source_port == -1 || switch_id == -1)
skb->dev = dsa_find_designated_bridge_port_by_vid(netdev, vid);
else
skb->dev = dsa_master_find_slave(netdev, switch_id, source_port);
......@@ -686,7 +688,7 @@ static struct sk_buff *sja1110_rcv_inband_control_extension(struct sk_buff *skb,
static struct sk_buff *sja1110_rcv(struct sk_buff *skb,
struct net_device *netdev)
{
int source_port = -1, switch_id = -1;
int source_port = -1, switch_id = -1, vbid = -1;
bool host_only = false;
u16 vid = 0;
......@@ -700,9 +702,11 @@ static struct sk_buff *sja1110_rcv(struct sk_buff *skb,
/* Packets with in-band control extensions might still have RX VLANs */
if (likely(sja1105_skb_has_tag_8021q(skb)))
sja1105_vlan_rcv(skb, &source_port, &switch_id, &vid);
sja1105_vlan_rcv(skb, &source_port, &switch_id, &vbid, &vid);
if (source_port == -1 || switch_id == -1)
if (vbid >= 1)
skb->dev = dsa_tag_8021q_find_port_by_vbid(netdev, vbid);
else if (source_port == -1 || switch_id == -1)
skb->dev = dsa_find_designated_bridge_port_by_vid(netdev, vid);
else
skb->dev = dsa_master_find_slave(netdev, switch_id, source_port);
......
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