Commit 219827ef authored by Vladimir Oltean's avatar Vladimir Oltean Committed by David S. Miller

net: dsa: sja1105: enforce FDB isolation

For sja1105, to enforce FDB isolation simply means to turn on
Independent VLAN Learning unconditionally, and to remap VLAN-unaware FDB
and MDB entries towards the private VLAN allocated by tag_8021q for each
bridge.

Standalone ports each have their own standalone tag_8021q VLAN. No
learning happens in that VLAN due to:
- learning being disabled on standalone user ports
- learning being disabled on the CPU port (we use
  assisted_learning_on_cpu_port which only installs bridge FDBs)

VLAN-aware ports learn FDB entries with the bridge VLANs.

VLAN-unaware bridge ports learn with the tag_8021q VLAN for bridging.
Signed-off-by: default avatarVladimir Oltean <vladimir.oltean@nxp.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 06b9cce4
...@@ -393,10 +393,8 @@ static int sja1105_init_l2_lookup_params(struct sja1105_private *priv) ...@@ -393,10 +393,8 @@ static int sja1105_init_l2_lookup_params(struct sja1105_private *priv)
.start_dynspc = 0, .start_dynspc = 0,
/* 2^8 + 2^5 + 2^3 + 2^2 + 2^1 + 1 in Koopman notation */ /* 2^8 + 2^5 + 2^3 + 2^2 + 2^1 + 1 in Koopman notation */
.poly = 0x97, .poly = 0x97,
/* This selects between Independent VLAN Learning (IVL) and /* Always use Independent VLAN Learning (IVL) */
* Shared VLAN Learning (SVL) .shared_learn = false,
*/
.shared_learn = true,
/* Don't discard management traffic based on ENFPORT - /* Don't discard management traffic based on ENFPORT -
* we don't perform SMAC port enforcement anyway, so * we don't perform SMAC port enforcement anyway, so
* what we are setting here doesn't matter. * what we are setting here doesn't matter.
...@@ -1808,6 +1806,19 @@ static int sja1105_fdb_add(struct dsa_switch *ds, int port, ...@@ -1808,6 +1806,19 @@ static int sja1105_fdb_add(struct dsa_switch *ds, int port,
{ {
struct sja1105_private *priv = ds->priv; 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); return priv->info->fdb_add_cmd(ds, port, addr, vid);
} }
...@@ -1817,13 +1828,25 @@ static int sja1105_fdb_del(struct dsa_switch *ds, int port, ...@@ -1817,13 +1828,25 @@ static int sja1105_fdb_del(struct dsa_switch *ds, int port,
{ {
struct sja1105_private *priv = ds->priv; 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); return priv->info->fdb_del_cmd(ds, port, addr, vid);
} }
static int sja1105_fdb_dump(struct dsa_switch *ds, int port, static int sja1105_fdb_dump(struct dsa_switch *ds, int port,
dsa_fdb_dump_cb_t *cb, void *data) dsa_fdb_dump_cb_t *cb, void *data)
{ {
struct dsa_port *dp = dsa_to_port(ds, port);
struct sja1105_private *priv = ds->priv; struct sja1105_private *priv = ds->priv;
struct device *dev = ds->dev; struct device *dev = ds->dev;
int i; int i;
...@@ -1860,7 +1883,7 @@ static int sja1105_fdb_dump(struct dsa_switch *ds, int port, ...@@ -1860,7 +1883,7 @@ static int sja1105_fdb_dump(struct dsa_switch *ds, int port,
u64_to_ether_addr(l2_lookup.macaddr, macaddr); u64_to_ether_addr(l2_lookup.macaddr, macaddr);
/* We need to hide the dsa_8021q VLANs from the user. */ /* 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; l2_lookup.vlanid = 0;
rc = cb(macaddr, l2_lookup.vlanid, l2_lookup.lockeds, data); rc = cb(macaddr, l2_lookup.vlanid, l2_lookup.lockeds, data);
if (rc) if (rc)
...@@ -2354,7 +2377,6 @@ sja1105_get_tag_protocol(struct dsa_switch *ds, int port, ...@@ -2354,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, int sja1105_vlan_filtering(struct dsa_switch *ds, int port, bool enabled,
struct netlink_ext_ack *extack) struct netlink_ext_ack *extack)
{ {
struct sja1105_l2_lookup_params_entry *l2_lookup_params;
struct sja1105_general_params_entry *general_params; struct sja1105_general_params_entry *general_params;
struct sja1105_private *priv = ds->priv; struct sja1105_private *priv = ds->priv;
struct sja1105_table *table; struct sja1105_table *table;
...@@ -2392,28 +2414,6 @@ int sja1105_vlan_filtering(struct dsa_switch *ds, int port, bool enabled, ...@@ -2392,28 +2414,6 @@ int sja1105_vlan_filtering(struct dsa_switch *ds, int port, bool enabled,
general_params->incl_srcpt1 = enabled; general_params->incl_srcpt1 = enabled;
general_params->incl_srcpt0 = 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++) { for (port = 0; port < ds->num_ports; port++) {
if (dsa_is_unused_port(ds, port)) if (dsa_is_unused_port(ds, port))
continue; continue;
...@@ -3099,6 +3099,7 @@ static int sja1105_setup(struct dsa_switch *ds) ...@@ -3099,6 +3099,7 @@ static int sja1105_setup(struct dsa_switch *ds)
*/ */
ds->vlan_filtering_is_global = true; ds->vlan_filtering_is_global = true;
ds->untag_bridge_pvid = true; ds->untag_bridge_pvid = true;
ds->fdb_isolation = true;
/* tag_8021q has 3 bits for the VBID, and the value 0 is reserved */ /* tag_8021q has 3 bits for the VBID, and the value 0 is reserved */
ds->max_num_bridges = 7; ds->max_num_bridges = 7;
......
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