Skip to content

Commit 511e6ca

Browse files
vladimirolteandavem330
authored andcommitted
net: dsa: sja1105: Add support for port mirroring
Amazingly, of all features, this does not require a switch reset. Tested with: tc qdisc add dev swp2 clsact tc filter add dev swp2 ingress matchall skip_sw \ action mirred egress mirror dev swp3 tc filter show dev swp2 ingress tc filter del dev swp2 ingress pref 49152 Signed-off-by: Vladimir Oltean <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 5a43f69 commit 511e6ca

File tree

1 file changed

+84
-4
lines changed

1 file changed

+84
-4
lines changed

drivers/net/dsa/sja1105/sja1105_main.c

Lines changed: 84 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -382,8 +382,8 @@ static int sja1105_init_l2_forwarding_params(struct sja1105_private *priv)
382382
static int sja1105_init_general_params(struct sja1105_private *priv)
383383
{
384384
struct sja1105_general_params_entry default_general_params = {
385-
/* Disallow dynamic changing of the mirror port */
386-
.mirr_ptacu = 0,
385+
/* Allow dynamic changing of the mirror port */
386+
.mirr_ptacu = true,
387387
.switchid = priv->ds->index,
388388
/* Priority queue for link-local management frames
389389
* (both ingress to and egress from CPU - PTP, STP etc)
@@ -403,8 +403,8 @@ static int sja1105_init_general_params(struct sja1105_private *priv)
403403
* by installing a temporary 'management route'
404404
*/
405405
.host_port = dsa_upstream_port(priv->ds, 0),
406-
/* Same as host port */
407-
.mirr_port = dsa_upstream_port(priv->ds, 0),
406+
/* Default to an invalid value */
407+
.mirr_port = SJA1105_NUM_PORTS,
408408
/* Link-local traffic received on casc_port will be forwarded
409409
* to host_port without embedding the source port and device ID
410410
* info in the destination MAC address (presumably because it
@@ -2069,6 +2069,84 @@ static int sja1105_port_setup_tc(struct dsa_switch *ds, int port,
20692069
}
20702070
}
20712071

2072+
/* We have a single mirror (@to) port, but can configure ingress and egress
2073+
* mirroring on all other (@from) ports.
2074+
* We need to allow mirroring rules only as long as the @to port is always the
2075+
* same, and we need to unset the @to port from mirr_port only when there is no
2076+
* mirroring rule that references it.
2077+
*/
2078+
static int sja1105_mirror_apply(struct sja1105_private *priv, int from, int to,
2079+
bool ingress, bool enabled)
2080+
{
2081+
struct sja1105_general_params_entry *general_params;
2082+
struct sja1105_mac_config_entry *mac;
2083+
struct sja1105_table *table;
2084+
bool already_enabled;
2085+
u64 new_mirr_port;
2086+
int rc;
2087+
2088+
table = &priv->static_config.tables[BLK_IDX_GENERAL_PARAMS];
2089+
general_params = table->entries;
2090+
2091+
mac = priv->static_config.tables[BLK_IDX_MAC_CONFIG].entries;
2092+
2093+
already_enabled = (general_params->mirr_port != SJA1105_NUM_PORTS);
2094+
if (already_enabled && enabled && general_params->mirr_port != to) {
2095+
dev_err(priv->ds->dev,
2096+
"Delete mirroring rules towards port %llu first\n",
2097+
general_params->mirr_port);
2098+
return -EBUSY;
2099+
}
2100+
2101+
new_mirr_port = to;
2102+
if (!enabled) {
2103+
bool keep = false;
2104+
int port;
2105+
2106+
/* Anybody still referencing mirr_port? */
2107+
for (port = 0; port < SJA1105_NUM_PORTS; port++) {
2108+
if (mac[port].ing_mirr || mac[port].egr_mirr) {
2109+
keep = true;
2110+
break;
2111+
}
2112+
}
2113+
/* Unset already_enabled for next time */
2114+
if (!keep)
2115+
new_mirr_port = SJA1105_NUM_PORTS;
2116+
}
2117+
if (new_mirr_port != general_params->mirr_port) {
2118+
general_params->mirr_port = new_mirr_port;
2119+
2120+
rc = sja1105_dynamic_config_write(priv, BLK_IDX_GENERAL_PARAMS,
2121+
0, general_params, true);
2122+
if (rc < 0)
2123+
return rc;
2124+
}
2125+
2126+
if (ingress)
2127+
mac[from].ing_mirr = enabled;
2128+
else
2129+
mac[from].egr_mirr = enabled;
2130+
2131+
return sja1105_dynamic_config_write(priv, BLK_IDX_MAC_CONFIG, from,
2132+
&mac[from], true);
2133+
}
2134+
2135+
static int sja1105_mirror_add(struct dsa_switch *ds, int port,
2136+
struct dsa_mall_mirror_tc_entry *mirror,
2137+
bool ingress)
2138+
{
2139+
return sja1105_mirror_apply(ds->priv, port, mirror->to_local_port,
2140+
ingress, true);
2141+
}
2142+
2143+
static void sja1105_mirror_del(struct dsa_switch *ds, int port,
2144+
struct dsa_mall_mirror_tc_entry *mirror)
2145+
{
2146+
sja1105_mirror_apply(ds->priv, port, mirror->to_local_port,
2147+
mirror->ingress, false);
2148+
}
2149+
20722150
static const struct dsa_switch_ops sja1105_switch_ops = {
20732151
.get_tag_protocol = sja1105_get_tag_protocol,
20742152
.setup = sja1105_setup,
@@ -2102,6 +2180,8 @@ static const struct dsa_switch_ops sja1105_switch_ops = {
21022180
.port_rxtstamp = sja1105_port_rxtstamp,
21032181
.port_txtstamp = sja1105_port_txtstamp,
21042182
.port_setup_tc = sja1105_port_setup_tc,
2183+
.port_mirror_add = sja1105_mirror_add,
2184+
.port_mirror_del = sja1105_mirror_del,
21052185
};
21062186

21072187
static int sja1105_check_device_id(struct sja1105_private *priv)

0 commit comments

Comments
 (0)