* [RFC PATCH net-next 0/6] add dsa cross-chip port mirroring
@ 2024-01-05 10:46 Ante Knezic
2024-01-05 10:46 ` [RFC PATCH net-next 1/6] net:dsa: drop mirror struct from port mirror functions Ante Knezic
` (5 more replies)
0 siblings, 6 replies; 7+ messages in thread
From: Ante Knezic @ 2024-01-05 10:46 UTC (permalink / raw)
To: netdev
Cc: andrew, f.fainelli, olteanv, davem, edumazet, kuba, pabeni,
ante.knezic
This patch is an attempt to add cross-chip port mirroring to dsa core and
mv88e6xxx switches but should apply similarly to other devices as well.
It is a work in progress so I am posting as RFC hopefully to get some
feedback on the general idea behind he problem rather than on the quality
of the code itself, though provided you have the time I would appreciate
any suggestions to code as well.
Cross-chip mirroring requires creating mirroring segments on each switch
that is acting as a part of the mirroring route, from source to destination
mirroring port. For example, configuration:
SW0 SW1 SW2 SW3
+-------+ +-------+ +-------+ +--------+
| P9|<--->|P10 P9|<--->|P10 |<--->|P10 |
| | | | | | | |
+-------+ +-------+ +----+--+ +--------+
^ |
| v
P2 P8
for which dsa tree devices need to be configured as follows:
----------------------------------------
| | source destination |
| SW | mirror port mirror port |
----------------------------------------
| 0 | P2 -> P9 |
| 1 | P10 -> P9 |
| 2 | P10 -> P8 |
| 3 | -> |
----------------------------------------
This basically means that request for adding port mirroring needs to be
propagated to the entire dsa switch tree as we can have a mirroring path
in which all switches need to be setup. This can be achieved through use
of switch event notifiers. First step is to create a mirroring route
which will contain source and destination ports for each switch in the
route. Then, this route is passed on to each switch where it is evaluated
for mirror settings for this particular switch. If a switch is contained
inside the route, its source and destination ports are passed on to
ds->ops->port_mirror_add().
Things get a bit more complicated when we need to remove port mirroring.
Again, we make use of the switch event notifiers to be able to inform
all switches that make a part of the route. Additionally, we must also
check if the source/destination mirror ports are being used by another
route and if so they should be kept active as we would interfere with
operation of another mirror action.
The critical part of the patch is getting the actual routing figured out,
which is done inside the dsa_route_create routine. It is a recursive
function that makes use of dsa_link and dst->rtable which is apparently
planned to be removed at some point (indicated by the TODO for dsa_link
struct in include/net/dsa.h). I'm not sure if this is a good way of getting
the routing done and what is the general opinion on using recursive functions
for this kind of work? In lack of real hardware, I isolated and tested
dsa_route_create routine on dummy switch topologies with up to three dsa
links. Even a sort of circular topology seems to work provided that the
requested to/from ports can actually be found in the dsa tree. Are there
any other variants that should be considered?
I decided to drop passing struct dsa_mall_mirror_tc_entry *mirror to
dsa drivers in favor of simpler from/to port and constraint the
dsa_mall_mirror_tc_entry to dsa core only. Member u8 to_local_port is
replaced with struct dsa_port *to_port as we are may no longer be addressing
the same switch for source/dest mirror. In this sense, passing the struct
dsa_port *to_port as a member of the dsa_mall_mirror_tc_entry to individual
switch devices seemed a bit off. This is addressed in patch no. 1
Patch no.5 sets destination mirroring ports to 0x1f when trying to disable
destination mirroring as suggested by the Switch Functional Specification
for 88E6390X/88E6390/88E6290/88E6190X/88E6190 and Switch Functional
Functional Specification for 88E6393X/88E6193X/88E6191X. If I see correctly
we have 3 variants of mv88e6xxx_ops->set_egress_port and they are:
- mv88e6390_g1_set_egress_port
- mv88e6393x_set_egress_port
- mv88e6095_g1_set_egress_port
I guess that we can assume that above mentioned documents apply to the first
two variants, and if someone can confirm the same for mv88e6095 than
MV88E6XXX_EGRESS_DEST_DISABLE should apply for the complete mv88e6xxx family.
Finally, patch is tested on a board consisting of two cascaded mv88e6390x
switches and seems to work fine, but this obviously is not sufficient and
would be great if someone can do a bit more testing on proper hardware
assuming there are no objections to the patch itself.
Any feedback is appreciated.
Thanks,
Ante
Ante Knezic (6):
net:dsa: drop mirror struct from port mirror functions
net: dsa: add groundwork for cross chip mirroring
net: dsa: implement cross chip port mirroring
net: dsa: check for busy mirror ports when removing mirroring action
net: dsa: mv88e6xxx: properly disable mirror destination
net: dsa: mv88e6xxx add cross-chip mirroring
drivers/net/dsa/b53/b53_common.c | 21 +++--
drivers/net/dsa/b53/b53_priv.h | 8 +-
drivers/net/dsa/microchip/ksz8.h | 10 +-
drivers/net/dsa/microchip/ksz8795.c | 36 +++----
drivers/net/dsa/microchip/ksz9477.c | 26 ++---
drivers/net/dsa/microchip/ksz9477.h | 10 +-
drivers/net/dsa/microchip/ksz_common.c | 15 +--
drivers/net/dsa/microchip/ksz_common.h | 7 +-
drivers/net/dsa/mt7530.c | 35 +++----
drivers/net/dsa/mv88e6xxx/chip.c | 91 +++++++++++-------
drivers/net/dsa/mv88e6xxx/chip.h | 5 +-
drivers/net/dsa/mv88e6xxx/port.c | 5 -
drivers/net/dsa/ocelot/felix.c | 15 +--
drivers/net/dsa/qca/qca8k-common.c | 39 ++++----
drivers/net/dsa/qca/qca8k.h | 11 ++-
drivers/net/dsa/sja1105/sja1105_main.c | 14 +--
include/net/dsa.h | 38 ++++++--
net/dsa/dsa.c | 14 +++
net/dsa/switch.c | 84 +++++++++++++++++
net/dsa/switch.h | 8 ++
net/dsa/user.c | 167 +++++++++++++++++++++++++++++++--
21 files changed, 480 insertions(+), 179 deletions(-)
--
2.11.0
^ permalink raw reply [flat|nested] 7+ messages in thread
* [RFC PATCH net-next 1/6] net:dsa: drop mirror struct from port mirror functions
2024-01-05 10:46 [RFC PATCH net-next 0/6] add dsa cross-chip port mirroring Ante Knezic
@ 2024-01-05 10:46 ` Ante Knezic
2024-01-05 10:46 ` [RFC PATCH net-next 2/6] net: dsa: add groundwork for cross chip mirroring Ante Knezic
` (4 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: Ante Knezic @ 2024-01-05 10:46 UTC (permalink / raw)
To: netdev
Cc: andrew, f.fainelli, olteanv, davem, edumazet, kuba, pabeni,
ante.knezic
dsa_mall_mirror_tc_entry struct assumes that the mirror
destination port must be on the same switch device as the
mirror source port. While this is true as far as particular
switch is concerned, it is not necessarily true for
dsa_mall_tc_entry struct entries. Therefore, replace port
index member of dsa_mall_mirror_tc_entry with dsa_port struct
and limit its scope to dsa core only.
Signed-off-by: Ante Knezic <ante.knezic@helmholz.de>
---
drivers/net/dsa/b53/b53_common.c | 20 +++++++++---------
drivers/net/dsa/b53/b53_priv.h | 8 +++----
drivers/net/dsa/microchip/ksz8.h | 10 ++++-----
drivers/net/dsa/microchip/ksz8795.c | 36 ++++++++++++++++----------------
drivers/net/dsa/microchip/ksz9477.c | 26 +++++++++++------------
drivers/net/dsa/microchip/ksz9477.h | 10 ++++-----
drivers/net/dsa/microchip/ksz_common.c | 14 ++++++-------
drivers/net/dsa/microchip/ksz_common.h | 7 +++----
drivers/net/dsa/mt7530.c | 34 +++++++++++++++---------------
drivers/net/dsa/mv88e6xxx/chip.c | 25 +++++++++++-----------
drivers/net/dsa/ocelot/felix.c | 14 ++++++-------
drivers/net/dsa/qca/qca8k-common.c | 38 +++++++++++++++++-----------------
drivers/net/dsa/qca/qca8k.h | 10 ++++-----
drivers/net/dsa/sja1105/sja1105_main.c | 13 ++++++------
include/net/dsa.h | 12 +++++------
net/dsa/user.c | 13 ++++++++----
16 files changed, 146 insertions(+), 144 deletions(-)
diff --git a/drivers/net/dsa/b53/b53_common.c b/drivers/net/dsa/b53/b53_common.c
index 0d628b35fd5c..993adbc81339 100644
--- a/drivers/net/dsa/b53/b53_common.c
+++ b/drivers/net/dsa/b53/b53_common.c
@@ -2128,8 +2128,8 @@ enum dsa_tag_protocol b53_get_tag_protocol(struct dsa_switch *ds, int port,
}
EXPORT_SYMBOL(b53_get_tag_protocol);
-int b53_mirror_add(struct dsa_switch *ds, int port,
- struct dsa_mall_mirror_tc_entry *mirror, bool ingress,
+int b53_mirror_add(struct dsa_switch *ds, int from_port,
+ int to_port, bool ingress,
struct netlink_ext_ack *extack)
{
struct b53_device *dev = ds->priv;
@@ -2141,12 +2141,12 @@ int b53_mirror_add(struct dsa_switch *ds, int port,
loc = B53_EG_MIR_CTL;
b53_read16(dev, B53_MGMT_PAGE, loc, ®);
- reg |= BIT(port);
+ reg |= BIT(from_port);
b53_write16(dev, B53_MGMT_PAGE, loc, reg);
b53_read16(dev, B53_MGMT_PAGE, B53_MIR_CAP_CTL, ®);
reg &= ~CAP_PORT_MASK;
- reg |= mirror->to_local_port;
+ reg |= to_port;
reg |= MIRROR_EN;
b53_write16(dev, B53_MGMT_PAGE, B53_MIR_CAP_CTL, reg);
@@ -2154,21 +2154,21 @@ int b53_mirror_add(struct dsa_switch *ds, int port,
}
EXPORT_SYMBOL(b53_mirror_add);
-void b53_mirror_del(struct dsa_switch *ds, int port,
- struct dsa_mall_mirror_tc_entry *mirror)
+void b53_mirror_del(struct dsa_switch *ds, int from_port,
+ int to_port, bool ingress)
{
struct b53_device *dev = ds->priv;
bool loc_disable = false, other_loc_disable = false;
u16 reg, loc;
- if (mirror->ingress)
+ if (ingress)
loc = B53_IG_MIR_CTL;
else
loc = B53_EG_MIR_CTL;
/* Update the desired ingress/egress register */
b53_read16(dev, B53_MGMT_PAGE, loc, ®);
- reg &= ~BIT(port);
+ reg &= ~BIT(from_port);
if (!(reg & MIRROR_MASK))
loc_disable = true;
b53_write16(dev, B53_MGMT_PAGE, loc, reg);
@@ -2176,7 +2176,7 @@ void b53_mirror_del(struct dsa_switch *ds, int port,
/* Now look at the other one to know if we can disable mirroring
* entirely
*/
- if (mirror->ingress)
+ if (ingress)
b53_read16(dev, B53_MGMT_PAGE, B53_EG_MIR_CTL, ®);
else
b53_read16(dev, B53_MGMT_PAGE, B53_IG_MIR_CTL, ®);
@@ -2187,7 +2187,7 @@ void b53_mirror_del(struct dsa_switch *ds, int port,
/* Both no longer have ports, let's disable mirroring */
if (loc_disable && other_loc_disable) {
reg &= ~MIRROR_EN;
- reg &= ~mirror->to_local_port;
+ reg &= ~to_port;
}
b53_write16(dev, B53_MGMT_PAGE, B53_MIR_CAP_CTL, reg);
}
diff --git a/drivers/net/dsa/b53/b53_priv.h b/drivers/net/dsa/b53/b53_priv.h
index fdcfd5081c28..625dafcd757b 100644
--- a/drivers/net/dsa/b53/b53_priv.h
+++ b/drivers/net/dsa/b53/b53_priv.h
@@ -385,13 +385,13 @@ int b53_mdb_add(struct dsa_switch *ds, int port,
int b53_mdb_del(struct dsa_switch *ds, int port,
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,
+int b53_mirror_add(struct dsa_switch *ds, int from_port,
+ int to_port, bool ingress,
struct netlink_ext_ack *extack);
enum dsa_tag_protocol b53_get_tag_protocol(struct dsa_switch *ds, int port,
enum dsa_tag_protocol mprot);
-void b53_mirror_del(struct dsa_switch *ds, int port,
- struct dsa_mall_mirror_tc_entry *mirror);
+void b53_mirror_del(struct dsa_switch *ds, int from_port, int to_port,
+ bool ingress);
int b53_enable_port(struct dsa_switch *ds, int port, struct phy_device *phy);
void b53_disable_port(struct dsa_switch *ds, int port);
void b53_brcm_hdr_setup(struct dsa_switch *ds, int port);
diff --git a/drivers/net/dsa/microchip/ksz8.h b/drivers/net/dsa/microchip/ksz8.h
index 1a5225264e6a..3fce8a9e99e7 100644
--- a/drivers/net/dsa/microchip/ksz8.h
+++ b/drivers/net/dsa/microchip/ksz8.h
@@ -43,11 +43,11 @@ int ksz8_port_vlan_add(struct ksz_device *dev, int port,
struct netlink_ext_ack *extack);
int ksz8_port_vlan_del(struct ksz_device *dev, int port,
const struct switchdev_obj_port_vlan *vlan);
-int ksz8_port_mirror_add(struct ksz_device *dev, int port,
- struct dsa_mall_mirror_tc_entry *mirror,
- bool ingress, struct netlink_ext_ack *extack);
-void ksz8_port_mirror_del(struct ksz_device *dev, int port,
- struct dsa_mall_mirror_tc_entry *mirror);
+int ksz8_port_mirror_add(struct ksz_device *dev, int from_port,
+ int to_port, bool ingress,
+ struct netlink_ext_ack *extack);
+void ksz8_port_mirror_del(struct ksz_device *dev, int from_port,
+ int to_port, bool ingress);
void ksz8_get_caps(struct ksz_device *dev, int port,
struct phylink_config *config);
void ksz8_config_cpu_port(struct dsa_switch *ds);
diff --git a/drivers/net/dsa/microchip/ksz8795.c b/drivers/net/dsa/microchip/ksz8795.c
index 61b71bcfe396..9f52137c3f38 100644
--- a/drivers/net/dsa/microchip/ksz8795.c
+++ b/drivers/net/dsa/microchip/ksz8795.c
@@ -1312,45 +1312,45 @@ int ksz8_port_vlan_del(struct ksz_device *dev, int port,
return 0;
}
-int ksz8_port_mirror_add(struct ksz_device *dev, int port,
- struct dsa_mall_mirror_tc_entry *mirror,
- bool ingress, struct netlink_ext_ack *extack)
+int ksz8_port_mirror_add(struct ksz_device *dev, int from_port,
+ int to_port, bool ingress,
+ struct netlink_ext_ack *extack)
{
if (ingress) {
- ksz_port_cfg(dev, port, P_MIRROR_CTRL, PORT_MIRROR_RX, true);
- dev->mirror_rx |= BIT(port);
+ ksz_port_cfg(dev, from_port, P_MIRROR_CTRL, PORT_MIRROR_RX, true);
+ dev->mirror_rx |= BIT(from_port);
} else {
- ksz_port_cfg(dev, port, P_MIRROR_CTRL, PORT_MIRROR_TX, true);
- dev->mirror_tx |= BIT(port);
+ ksz_port_cfg(dev, from_port, P_MIRROR_CTRL, PORT_MIRROR_TX, true);
+ dev->mirror_tx |= BIT(from_port);
}
- ksz_port_cfg(dev, port, P_MIRROR_CTRL, PORT_MIRROR_SNIFFER, false);
+ ksz_port_cfg(dev, from_port, P_MIRROR_CTRL, PORT_MIRROR_SNIFFER, false);
/* configure mirror port */
if (dev->mirror_rx || dev->mirror_tx)
- ksz_port_cfg(dev, mirror->to_local_port, P_MIRROR_CTRL,
+ ksz_port_cfg(dev, to_port, P_MIRROR_CTRL,
PORT_MIRROR_SNIFFER, true);
return 0;
}
-void ksz8_port_mirror_del(struct ksz_device *dev, int port,
- struct dsa_mall_mirror_tc_entry *mirror)
+void ksz8_port_mirror_del(struct ksz_device *dev, int from_port,
+ int to_port, bool ingress)
{
u8 data;
- if (mirror->ingress) {
- ksz_port_cfg(dev, port, P_MIRROR_CTRL, PORT_MIRROR_RX, false);
- dev->mirror_rx &= ~BIT(port);
+ if (ingress) {
+ ksz_port_cfg(dev, from_port, P_MIRROR_CTRL, PORT_MIRROR_RX, false);
+ dev->mirror_rx &= ~BIT(from_port);
} else {
- ksz_port_cfg(dev, port, P_MIRROR_CTRL, PORT_MIRROR_TX, false);
- dev->mirror_tx &= ~BIT(port);
+ ksz_port_cfg(dev, from_port, P_MIRROR_CTRL, PORT_MIRROR_TX, false);
+ dev->mirror_tx &= ~BIT(from_port);
}
- ksz_pread8(dev, port, P_MIRROR_CTRL, &data);
+ ksz_pread8(dev, from_port, P_MIRROR_CTRL, &data);
if (!dev->mirror_rx && !dev->mirror_tx)
- ksz_port_cfg(dev, mirror->to_local_port, P_MIRROR_CTRL,
+ ksz_port_cfg(dev, to_port, P_MIRROR_CTRL,
PORT_MIRROR_SNIFFER, false);
}
diff --git a/drivers/net/dsa/microchip/ksz9477.c b/drivers/net/dsa/microchip/ksz9477.c
index 7f745628c84d..a5c7e177e5d4 100644
--- a/drivers/net/dsa/microchip/ksz9477.c
+++ b/drivers/net/dsa/microchip/ksz9477.c
@@ -1003,9 +1003,9 @@ int ksz9477_mdb_del(struct ksz_device *dev, int port,
return ret;
}
-int ksz9477_port_mirror_add(struct ksz_device *dev, int port,
- struct dsa_mall_mirror_tc_entry *mirror,
- bool ingress, struct netlink_ext_ack *extack)
+int ksz9477_port_mirror_add(struct ksz_device *dev, int from_port,
+ int to_port, bool ingress,
+ struct netlink_ext_ack *extack)
{
u8 data;
int p;
@@ -1016,7 +1016,7 @@ int ksz9477_port_mirror_add(struct ksz_device *dev, int port,
*/
for (p = 0; p < dev->info->port_cnt; p++) {
/* Skip the current sniffing port */
- if (p == mirror->to_local_port)
+ if (p == to_port)
continue;
ksz_pread8(dev, p, P_MIRROR_CTRL, &data);
@@ -1029,12 +1029,12 @@ int ksz9477_port_mirror_add(struct ksz_device *dev, int port,
}
if (ingress)
- ksz_port_cfg(dev, port, P_MIRROR_CTRL, PORT_MIRROR_RX, true);
+ ksz_port_cfg(dev, from_port, P_MIRROR_CTRL, PORT_MIRROR_RX, true);
else
- ksz_port_cfg(dev, port, P_MIRROR_CTRL, PORT_MIRROR_TX, true);
+ ksz_port_cfg(dev, from_port, P_MIRROR_CTRL, PORT_MIRROR_TX, true);
/* configure mirror port */
- ksz_port_cfg(dev, mirror->to_local_port, P_MIRROR_CTRL,
+ ksz_port_cfg(dev, to_port, P_MIRROR_CTRL,
PORT_MIRROR_SNIFFER, true);
ksz_cfg(dev, S_MIRROR_CTRL, SW_MIRROR_RX_TX, false);
@@ -1042,17 +1042,17 @@ int ksz9477_port_mirror_add(struct ksz_device *dev, int port,
return 0;
}
-void ksz9477_port_mirror_del(struct ksz_device *dev, int port,
- struct dsa_mall_mirror_tc_entry *mirror)
+void ksz9477_port_mirror_del(struct ksz_device *dev, int from_port,
+ int to_port, bool ingress)
{
bool in_use = false;
u8 data;
int p;
- if (mirror->ingress)
- ksz_port_cfg(dev, port, P_MIRROR_CTRL, PORT_MIRROR_RX, false);
+ if (ingress)
+ ksz_port_cfg(dev, from_port, P_MIRROR_CTRL, PORT_MIRROR_RX, false);
else
- ksz_port_cfg(dev, port, P_MIRROR_CTRL, PORT_MIRROR_TX, false);
+ ksz_port_cfg(dev, from_port, P_MIRROR_CTRL, PORT_MIRROR_TX, false);
/* Check if any of the port is still referring to sniffer port */
@@ -1067,7 +1067,7 @@ void ksz9477_port_mirror_del(struct ksz_device *dev, int port,
/* delete sniffing if there are no other mirroring rules */
if (!in_use)
- ksz_port_cfg(dev, mirror->to_local_port, P_MIRROR_CTRL,
+ ksz_port_cfg(dev, to_port, P_MIRROR_CTRL,
PORT_MIRROR_SNIFFER, false);
}
diff --git a/drivers/net/dsa/microchip/ksz9477.h b/drivers/net/dsa/microchip/ksz9477.h
index ce1e656b800b..2d74b30482e0 100644
--- a/drivers/net/dsa/microchip/ksz9477.h
+++ b/drivers/net/dsa/microchip/ksz9477.h
@@ -31,11 +31,11 @@ int ksz9477_port_vlan_add(struct ksz_device *dev, int port,
struct netlink_ext_ack *extack);
int ksz9477_port_vlan_del(struct ksz_device *dev, int port,
const struct switchdev_obj_port_vlan *vlan);
-int ksz9477_port_mirror_add(struct ksz_device *dev, int port,
- struct dsa_mall_mirror_tc_entry *mirror,
- bool ingress, struct netlink_ext_ack *extack);
-void ksz9477_port_mirror_del(struct ksz_device *dev, int port,
- struct dsa_mall_mirror_tc_entry *mirror);
+int ksz9477_port_mirror_add(struct ksz_device *dev, int from_port,
+ int to_port, bool ingress,
+ struct netlink_ext_ack *extack);
+void ksz9477_port_mirror_del(struct ksz_device *dev, int from_port,
+ int to_port, bool ingress);
void ksz9477_get_caps(struct ksz_device *dev, int port,
struct phylink_config *config);
int ksz9477_fdb_dump(struct ksz_device *dev, int port,
diff --git a/drivers/net/dsa/microchip/ksz_common.c b/drivers/net/dsa/microchip/ksz_common.c
index 245dfb7a7a31..824bfb0ed0ad 100644
--- a/drivers/net/dsa/microchip/ksz_common.c
+++ b/drivers/net/dsa/microchip/ksz_common.c
@@ -2770,25 +2770,25 @@ static int ksz_port_vlan_del(struct dsa_switch *ds, int port,
return dev->dev_ops->vlan_del(dev, port, vlan);
}
-static int ksz_port_mirror_add(struct dsa_switch *ds, int port,
- struct dsa_mall_mirror_tc_entry *mirror,
- bool ingress, struct netlink_ext_ack *extack)
+static int ksz_port_mirror_add(struct dsa_switch *ds, int from_port,
+ int to_port, bool ingress,
+ struct netlink_ext_ack *extack)
{
struct ksz_device *dev = ds->priv;
if (!dev->dev_ops->mirror_add)
return -EOPNOTSUPP;
- return dev->dev_ops->mirror_add(dev, port, mirror, ingress, extack);
+ return dev->dev_ops->mirror_add(dev, from_port, to_port, ingress, extack);
}
-static void ksz_port_mirror_del(struct dsa_switch *ds, int port,
- struct dsa_mall_mirror_tc_entry *mirror)
+static void ksz_port_mirror_del(struct dsa_switch *ds, int from_port,
+ int to_port, bool ingress)
{
struct ksz_device *dev = ds->priv;
if (dev->dev_ops->mirror_del)
- dev->dev_ops->mirror_del(dev, port, mirror);
+ dev->dev_ops->mirror_del(dev, from_port, to_port, ingress);
}
static int ksz_change_mtu(struct dsa_switch *ds, int port, int mtu)
diff --git a/drivers/net/dsa/microchip/ksz_common.h b/drivers/net/dsa/microchip/ksz_common.h
index 15612101a155..295560eea10d 100644
--- a/drivers/net/dsa/microchip/ksz_common.h
+++ b/drivers/net/dsa/microchip/ksz_common.h
@@ -325,11 +325,10 @@ struct ksz_dev_ops {
struct netlink_ext_ack *extack);
int (*vlan_del)(struct ksz_device *dev, int port,
const struct switchdev_obj_port_vlan *vlan);
- int (*mirror_add)(struct ksz_device *dev, int port,
- struct dsa_mall_mirror_tc_entry *mirror,
+ int (*mirror_add)(struct ksz_device *dev, int from_port, int to_port,
bool ingress, struct netlink_ext_ack *extack);
- void (*mirror_del)(struct ksz_device *dev, int port,
- struct dsa_mall_mirror_tc_entry *mirror);
+ void (*mirror_del)(struct ksz_device *dev, int from_port,
+ int to_port, bool ingress);
int (*fdb_add)(struct ksz_device *dev, int port,
const unsigned char *addr, u16 vid, struct dsa_db db);
int (*fdb_del)(struct ksz_device *dev, int port,
diff --git a/drivers/net/dsa/mt7530.c b/drivers/net/dsa/mt7530.c
index 391c4dbdff42..9e284edfbd0e 100644
--- a/drivers/net/dsa/mt7530.c
+++ b/drivers/net/dsa/mt7530.c
@@ -1760,16 +1760,16 @@ static int mt753x_mirror_port_set(unsigned int id, u32 val)
MIRROR_PORT(val);
}
-static int mt753x_port_mirror_add(struct dsa_switch *ds, int port,
- struct dsa_mall_mirror_tc_entry *mirror,
- bool ingress, struct netlink_ext_ack *extack)
+static int mt753x_port_mirror_add(struct dsa_switch *ds, int from_port,
+ int to_port, bool ingress,
+ struct netlink_ext_ack *extack)
{
struct mt7530_priv *priv = ds->priv;
int monitor_port;
u32 val;
/* Check for existent entry */
- if ((ingress ? priv->mirror_rx : priv->mirror_tx) & BIT(port))
+ if ((ingress ? priv->mirror_rx : priv->mirror_tx) & BIT(from_port))
return -EEXIST;
val = mt7530_read(priv, MT753X_MIRROR_REG(priv->id));
@@ -1777,42 +1777,42 @@ static int mt753x_port_mirror_add(struct dsa_switch *ds, int port,
/* MT7530 only supports one monitor port */
monitor_port = mt753x_mirror_port_get(priv->id, val);
if (val & MT753X_MIRROR_EN(priv->id) &&
- monitor_port != mirror->to_local_port)
+ monitor_port != to_port)
return -EEXIST;
val |= MT753X_MIRROR_EN(priv->id);
val &= ~MT753X_MIRROR_MASK(priv->id);
- val |= mt753x_mirror_port_set(priv->id, mirror->to_local_port);
+ val |= mt753x_mirror_port_set(priv->id, to_port);
mt7530_write(priv, MT753X_MIRROR_REG(priv->id), val);
- val = mt7530_read(priv, MT7530_PCR_P(port));
+ val = mt7530_read(priv, MT7530_PCR_P(from_port));
if (ingress) {
val |= PORT_RX_MIR;
- priv->mirror_rx |= BIT(port);
+ priv->mirror_rx |= BIT(from_port);
} else {
val |= PORT_TX_MIR;
- priv->mirror_tx |= BIT(port);
+ priv->mirror_tx |= BIT(from_port);
}
- mt7530_write(priv, MT7530_PCR_P(port), val);
+ mt7530_write(priv, MT7530_PCR_P(from_port), val);
return 0;
}
-static void mt753x_port_mirror_del(struct dsa_switch *ds, int port,
- struct dsa_mall_mirror_tc_entry *mirror)
+static void mt753x_port_mirror_del(struct dsa_switch *ds, int from_port,
+ int to_port, bool ingress)
{
struct mt7530_priv *priv = ds->priv;
u32 val;
- val = mt7530_read(priv, MT7530_PCR_P(port));
- if (mirror->ingress) {
+ val = mt7530_read(priv, MT7530_PCR_P(from_port));
+ if (ingress) {
val &= ~PORT_RX_MIR;
- priv->mirror_rx &= ~BIT(port);
+ priv->mirror_rx &= ~BIT(from_port);
} else {
val &= ~PORT_TX_MIR;
- priv->mirror_tx &= ~BIT(port);
+ priv->mirror_tx &= ~BIT(from_port);
}
- mt7530_write(priv, MT7530_PCR_P(port), val);
+ mt7530_write(priv, MT7530_PCR_P(from_port), val);
if (!priv->mirror_rx && !priv->mirror_tx) {
val = mt7530_read(priv, MT753X_MIRROR_REG(priv->id));
diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index 383b3c4d6f59..b8820b31d05b 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -6480,9 +6480,8 @@ static int mv88e6xxx_port_mdb_del(struct dsa_switch *ds, int port,
return err;
}
-static int mv88e6xxx_port_mirror_add(struct dsa_switch *ds, int port,
- struct dsa_mall_mirror_tc_entry *mirror,
- bool ingress,
+static int mv88e6xxx_port_mirror_add(struct dsa_switch *ds, int from_port,
+ int to_port, bool ingress,
struct netlink_ext_ack *extack)
{
enum mv88e6xxx_egress_direction direction = ingress ?
@@ -6495,7 +6494,7 @@ static int mv88e6xxx_port_mirror_add(struct dsa_switch *ds, int port,
mutex_lock(&chip->reg_lock);
if ((ingress ? chip->ingress_dest_port : chip->egress_dest_port) !=
- mirror->to_local_port) {
+ to_port) {
for (i = 0; i < mv88e6xxx_num_ports(chip); i++)
other_mirrors |= ingress ?
chip->ports[i].mirror_ingress :
@@ -6508,22 +6507,22 @@ static int mv88e6xxx_port_mirror_add(struct dsa_switch *ds, int port,
}
err = mv88e6xxx_set_egress_port(chip, direction,
- mirror->to_local_port);
+ to_port);
if (err)
goto out;
}
- err = mv88e6xxx_port_set_mirror(chip, port, direction, true);
+ err = mv88e6xxx_port_set_mirror(chip, from_port, direction, true);
out:
mutex_unlock(&chip->reg_lock);
return err;
}
-static void mv88e6xxx_port_mirror_del(struct dsa_switch *ds, int port,
- struct dsa_mall_mirror_tc_entry *mirror)
+static void mv88e6xxx_port_mirror_del(struct dsa_switch *ds, int from_port,
+ int to_port, bool ingress)
{
- enum mv88e6xxx_egress_direction direction = mirror->ingress ?
+ enum mv88e6xxx_egress_direction direction = ingress ?
MV88E6XXX_EGRESS_DIR_INGRESS :
MV88E6XXX_EGRESS_DIR_EGRESS;
struct mv88e6xxx_chip *chip = ds->priv;
@@ -6531,18 +6530,18 @@ static void mv88e6xxx_port_mirror_del(struct dsa_switch *ds, int port,
int i;
mutex_lock(&chip->reg_lock);
- if (mv88e6xxx_port_set_mirror(chip, port, direction, false))
- dev_err(ds->dev, "p%d: failed to disable mirroring\n", port);
+ if (mv88e6xxx_port_set_mirror(chip, from_port, direction, false))
+ dev_err(ds->dev, "p%d: failed to disable mirroring\n", from_port);
for (i = 0; i < mv88e6xxx_num_ports(chip); i++)
- other_mirrors |= mirror->ingress ?
+ other_mirrors |= ingress ?
chip->ports[i].mirror_ingress :
chip->ports[i].mirror_egress;
/* Reset egress port when no other mirror is active */
if (!other_mirrors) {
if (mv88e6xxx_set_egress_port(chip, direction,
- dsa_upstream_port(ds, port)))
+ dsa_upstream_port(ds, from_port)))
dev_err(ds->dev, "failed to set egress port\n");
}
diff --git a/drivers/net/dsa/ocelot/felix.c b/drivers/net/dsa/ocelot/felix.c
index 61e95487732d..c3d21e06bde3 100644
--- a/drivers/net/dsa/ocelot/felix.c
+++ b/drivers/net/dsa/ocelot/felix.c
@@ -1853,22 +1853,22 @@ static void felix_port_policer_del(struct dsa_switch *ds, int port)
ocelot_port_policer_del(ocelot, port);
}
-static int felix_port_mirror_add(struct dsa_switch *ds, int port,
- struct dsa_mall_mirror_tc_entry *mirror,
- bool ingress, struct netlink_ext_ack *extack)
+static int felix_port_mirror_add(struct dsa_switch *ds, int from_port,
+ int to_port, bool ingress,
+ struct netlink_ext_ack *extack)
{
struct ocelot *ocelot = ds->priv;
- return ocelot_port_mirror_add(ocelot, port, mirror->to_local_port,
+ return ocelot_port_mirror_add(ocelot, from_port, to_port,
ingress, extack);
}
-static void felix_port_mirror_del(struct dsa_switch *ds, int port,
- struct dsa_mall_mirror_tc_entry *mirror)
+static void felix_port_mirror_del(struct dsa_switch *ds, int from_port,
+ int to_port, bool ingress)
{
struct ocelot *ocelot = ds->priv;
- ocelot_port_mirror_del(ocelot, port, mirror->ingress);
+ ocelot_port_mirror_del(ocelot, from_port, ingress);
}
static int felix_port_setup_tc(struct dsa_switch *ds, int port,
diff --git a/drivers/net/dsa/qca/qca8k-common.c b/drivers/net/dsa/qca/qca8k-common.c
index 2358cd399c7e..4ff6763a81ce 100644
--- a/drivers/net/dsa/qca/qca8k-common.c
+++ b/drivers/net/dsa/qca/qca8k-common.c
@@ -884,16 +884,16 @@ int qca8k_port_mdb_del(struct dsa_switch *ds, int port,
return qca8k_fdb_search_and_del(priv, BIT(port), addr, vid);
}
-int qca8k_port_mirror_add(struct dsa_switch *ds, int port,
- struct dsa_mall_mirror_tc_entry *mirror,
- bool ingress, struct netlink_ext_ack *extack)
+int qca8k_port_mirror_add(struct dsa_switch *ds, int from_port,
+ int to_port, bool ingress,
+ struct netlink_ext_ack *extack)
{
struct qca8k_priv *priv = ds->priv;
int monitor_port, ret;
u32 reg, val;
/* Check for existent entry */
- if ((ingress ? priv->mirror_rx : priv->mirror_tx) & BIT(port))
+ if ((ingress ? priv->mirror_rx : priv->mirror_tx) & BIT(from_port))
return -EEXIST;
ret = regmap_read(priv->regmap, QCA8K_REG_GLOBAL_FW_CTRL0, &val);
@@ -905,22 +905,22 @@ int qca8k_port_mirror_add(struct dsa_switch *ds, int port,
* When no mirror port is set, the values is set to 0xF
*/
monitor_port = FIELD_GET(QCA8K_GLOBAL_FW_CTRL0_MIRROR_PORT_NUM, val);
- if (monitor_port != 0xF && monitor_port != mirror->to_local_port)
+ if (monitor_port != 0xF && monitor_port != to_port)
return -EEXIST;
/* Set the monitor port */
val = FIELD_PREP(QCA8K_GLOBAL_FW_CTRL0_MIRROR_PORT_NUM,
- mirror->to_local_port);
+ to_port);
ret = regmap_update_bits(priv->regmap, QCA8K_REG_GLOBAL_FW_CTRL0,
QCA8K_GLOBAL_FW_CTRL0_MIRROR_PORT_NUM, val);
if (ret)
return ret;
if (ingress) {
- reg = QCA8K_PORT_LOOKUP_CTRL(port);
+ reg = QCA8K_PORT_LOOKUP_CTRL(from_port);
val = QCA8K_PORT_LOOKUP_ING_MIRROR_EN;
} else {
- reg = QCA8K_REG_PORT_HOL_CTRL1(port);
+ reg = QCA8K_REG_PORT_HOL_CTRL1(from_port);
val = QCA8K_PORT_HOL_CTRL1_EG_MIRROR_EN;
}
@@ -932,25 +932,25 @@ int qca8k_port_mirror_add(struct dsa_switch *ds, int port,
* mirror port has to be disabled.
*/
if (ingress)
- priv->mirror_rx |= BIT(port);
+ priv->mirror_rx |= BIT(from_port);
else
- priv->mirror_tx |= BIT(port);
+ priv->mirror_tx |= BIT(from_port);
return 0;
}
-void qca8k_port_mirror_del(struct dsa_switch *ds, int port,
- struct dsa_mall_mirror_tc_entry *mirror)
+void qca8k_port_mirror_del(struct dsa_switch *ds, int from_port,
+ int to_port, bool ingress)
{
struct qca8k_priv *priv = ds->priv;
u32 reg, val;
int ret;
- if (mirror->ingress) {
- reg = QCA8K_PORT_LOOKUP_CTRL(port);
+ if (ingress) {
+ reg = QCA8K_PORT_LOOKUP_CTRL(from_port);
val = QCA8K_PORT_LOOKUP_ING_MIRROR_EN;
} else {
- reg = QCA8K_REG_PORT_HOL_CTRL1(port);
+ reg = QCA8K_REG_PORT_HOL_CTRL1(from_port);
val = QCA8K_PORT_HOL_CTRL1_EG_MIRROR_EN;
}
@@ -958,10 +958,10 @@ void qca8k_port_mirror_del(struct dsa_switch *ds, int port,
if (ret)
goto err;
- if (mirror->ingress)
- priv->mirror_rx &= ~BIT(port);
+ if (ingress)
+ priv->mirror_rx &= ~BIT(from_port);
else
- priv->mirror_tx &= ~BIT(port);
+ priv->mirror_tx &= ~BIT(from_port);
/* No port set to send packet to mirror port. Disable mirror port */
if (!priv->mirror_rx && !priv->mirror_tx) {
@@ -972,7 +972,7 @@ void qca8k_port_mirror_del(struct dsa_switch *ds, int port,
goto err;
}
err:
- dev_err(priv->dev, "Failed to del mirror port from %d", port);
+ dev_err(priv->dev, "Failed to del mirror port from %d", from_port);
}
int qca8k_port_vlan_filtering(struct dsa_switch *ds, int port,
diff --git a/drivers/net/dsa/qca/qca8k.h b/drivers/net/dsa/qca/qca8k.h
index 2ac7e88f8da5..7c6e75a37e13 100644
--- a/drivers/net/dsa/qca/qca8k.h
+++ b/drivers/net/dsa/qca/qca8k.h
@@ -569,11 +569,11 @@ int qca8k_port_mdb_del(struct dsa_switch *ds, int port,
struct dsa_db db);
/* Common port mirror function */
-int qca8k_port_mirror_add(struct dsa_switch *ds, int port,
- struct dsa_mall_mirror_tc_entry *mirror,
- bool ingress, struct netlink_ext_ack *extack);
-void qca8k_port_mirror_del(struct dsa_switch *ds, int port,
- struct dsa_mall_mirror_tc_entry *mirror);
+int qca8k_port_mirror_add(struct dsa_switch *ds, int from_port,
+ int to_port, bool ingress,
+ struct netlink_ext_ack *extack);
+void qca8k_port_mirror_del(struct dsa_switch *ds, int from_port,
+ int to_port, bool ingress);
/* Common port VLAN function */
int qca8k_port_vlan_filtering(struct dsa_switch *ds, int port, bool vlan_filtering,
diff --git a/drivers/net/dsa/sja1105/sja1105_main.c b/drivers/net/dsa/sja1105/sja1105_main.c
index 6646f7fb0f90..7f4cb3a1f39d 100644
--- a/drivers/net/dsa/sja1105/sja1105_main.c
+++ b/drivers/net/dsa/sja1105/sja1105_main.c
@@ -2895,19 +2895,18 @@ static int sja1105_mirror_apply(struct sja1105_private *priv, int from, int to,
&mac[from], true);
}
-static int sja1105_mirror_add(struct dsa_switch *ds, int port,
- struct dsa_mall_mirror_tc_entry *mirror,
+static int sja1105_mirror_add(struct dsa_switch *ds, int from_port, int to_port,
bool ingress, struct netlink_ext_ack *extack)
{
- return sja1105_mirror_apply(ds->priv, port, mirror->to_local_port,
+ return sja1105_mirror_apply(ds->priv, from_port, to_port,
ingress, true);
}
-static void sja1105_mirror_del(struct dsa_switch *ds, int port,
- struct dsa_mall_mirror_tc_entry *mirror)
+static void sja1105_mirror_del(struct dsa_switch *ds, int from_port,
+ int to_port, bool ingress)
{
- sja1105_mirror_apply(ds->priv, port, mirror->to_local_port,
- mirror->ingress, false);
+ sja1105_mirror_apply(ds->priv, from_port, to_port,
+ ingress, false);
}
static int sja1105_port_policer_add(struct dsa_switch *ds, int port,
diff --git a/include/net/dsa.h b/include/net/dsa.h
index 82135fbdb1e6..c1fbe89f8f81 100644
--- a/include/net/dsa.h
+++ b/include/net/dsa.h
@@ -207,7 +207,7 @@ enum dsa_port_mall_action_type {
/* TC mirroring entry */
struct dsa_mall_mirror_tc_entry {
- u8 to_local_port;
+ struct dsa_port *to_port;
bool ingress;
};
@@ -1098,11 +1098,11 @@ struct dsa_switch_ops {
struct flow_cls_offload *cls, bool ingress);
int (*cls_flower_stats)(struct dsa_switch *ds, int port,
struct flow_cls_offload *cls, bool ingress);
- int (*port_mirror_add)(struct dsa_switch *ds, int port,
- struct dsa_mall_mirror_tc_entry *mirror,
- bool ingress, struct netlink_ext_ack *extack);
- void (*port_mirror_del)(struct dsa_switch *ds, int port,
- struct dsa_mall_mirror_tc_entry *mirror);
+ int (*port_mirror_add)(struct dsa_switch *ds, int from_port,
+ int to_port, bool ingress,
+ struct netlink_ext_ack *extack);
+ void (*port_mirror_del)(struct dsa_switch *ds, int from_port,
+ int to_port, bool ingress);
int (*port_policer_add)(struct dsa_switch *ds, int port,
struct dsa_mall_policer_tc_entry *policer);
void (*port_policer_del)(struct dsa_switch *ds, int port);
diff --git a/net/dsa/user.c b/net/dsa/user.c
index b738a466e2dc..ce73d0a5140d 100644
--- a/net/dsa/user.c
+++ b/net/dsa/user.c
@@ -1399,10 +1399,10 @@ dsa_user_add_cls_matchall_mirred(struct net_device *dev,
to_dp = dsa_user_to_port(act->dev);
- mirror->to_local_port = to_dp->index;
+ mirror->to_port = to_dp;
mirror->ingress = ingress;
- err = ds->ops->port_mirror_add(ds, dp->index, mirror, ingress, extack);
+ err = ds->ops->port_mirror_add(ds, dp->index, to_dp->index, ingress, extack);
if (err) {
kfree(mall_tc_entry);
return err;
@@ -1506,9 +1506,14 @@ static void dsa_user_del_cls_matchall(struct net_device *dev,
switch (mall_tc_entry->type) {
case DSA_PORT_MALL_MIRROR:
- if (ds->ops->port_mirror_del)
+ if (ds->ops->port_mirror_del) {
+ struct dsa_mall_mirror_tc_entry *mirror;
+
+ mirror = &mall_tc_entry->mirror;
ds->ops->port_mirror_del(ds, dp->index,
- &mall_tc_entry->mirror);
+ mirror->to_port->index,
+ mirror->ingress);
+ }
break;
case DSA_PORT_MALL_POLICER:
if (ds->ops->port_policer_del)
--
2.11.0
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [RFC PATCH net-next 2/6] net: dsa: add groundwork for cross chip mirroring
2024-01-05 10:46 [RFC PATCH net-next 0/6] add dsa cross-chip port mirroring Ante Knezic
2024-01-05 10:46 ` [RFC PATCH net-next 1/6] net:dsa: drop mirror struct from port mirror functions Ante Knezic
@ 2024-01-05 10:46 ` Ante Knezic
2024-01-05 10:46 ` [RFC PATCH net-next 3/6] net: dsa: implement cross chip port mirroring Ante Knezic
` (3 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: Ante Knezic @ 2024-01-05 10:46 UTC (permalink / raw)
To: netdev
Cc: andrew, f.fainelli, olteanv, davem, edumazet, kuba, pabeni,
ante.knezic
cross chip mirroring require routing mirrored data
from source to destination switch. Add the necessary
groundwork.
Signed-off-by: Ante Knezic <ante.knezic@helmholz.de>
---
include/net/dsa.h | 18 ++++++++++++++++++
net/dsa/dsa.c | 14 ++++++++++++++
2 files changed, 32 insertions(+)
diff --git a/include/net/dsa.h b/include/net/dsa.h
index c1fbe89f8f81..aa0e97150bc3 100644
--- a/include/net/dsa.h
+++ b/include/net/dsa.h
@@ -162,6 +162,9 @@ struct dsa_switch_tree {
/* Track the largest switch index within a tree */
unsigned int last_switch;
+
+ /* List of port mirror routes */
+ struct list_head mirrors;
};
/* LAG IDs are one-based, the dst->lags array is zero-based */
@@ -368,6 +371,21 @@ struct dsa_vlan {
struct list_head list;
};
+struct dsa_mirror {
+ struct list_head list;
+ const struct dsa_port *from_dp;
+ const struct dsa_port *to_dp;
+ bool ingress;
+ struct list_head route;
+};
+
+struct dsa_route {
+ struct list_head list;
+ int sw_index;
+ int from_local_p;
+ int to_local_p;
+};
+
struct dsa_switch {
struct device *dev;
diff --git a/net/dsa/dsa.c b/net/dsa/dsa.c
index ac7be864e80d..304c7100cf55 100644
--- a/net/dsa/dsa.c
+++ b/net/dsa/dsa.c
@@ -228,6 +228,8 @@ static struct dsa_switch_tree *dsa_tree_alloc(int index)
kref_init(&dst->refcount);
+ INIT_LIST_HEAD(&dst->mirrors);
+
return dst;
}
@@ -923,6 +925,8 @@ static int dsa_tree_setup(struct dsa_switch_tree *dst)
static void dsa_tree_teardown(struct dsa_switch_tree *dst)
{
struct dsa_link *dl, *next;
+ struct dsa_mirror *dm, *m;
+ struct dsa_route *dr, *r;
if (!dst->setup)
return;
@@ -942,6 +946,16 @@ static void dsa_tree_teardown(struct dsa_switch_tree *dst)
kfree(dl);
}
+ list_for_each_entry_safe(dm, m, &dst->mirrors, list) {
+ list_for_each_entry_safe(dr, r, &dm->route, list) {
+ list_del(&dr->list);
+ kfree(dr);
+ }
+
+ list_del(&dm->list);
+ kfree(dm);
+ }
+
pr_info("DSA: tree %d torn down\n", dst->index);
dst->setup = false;
--
2.11.0
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [RFC PATCH net-next 3/6] net: dsa: implement cross chip port mirroring
2024-01-05 10:46 [RFC PATCH net-next 0/6] add dsa cross-chip port mirroring Ante Knezic
2024-01-05 10:46 ` [RFC PATCH net-next 1/6] net:dsa: drop mirror struct from port mirror functions Ante Knezic
2024-01-05 10:46 ` [RFC PATCH net-next 2/6] net: dsa: add groundwork for cross chip mirroring Ante Knezic
@ 2024-01-05 10:46 ` Ante Knezic
2024-01-05 10:46 ` [RFC PATCH net-next 4/6] net: dsa: check for busy mirror ports when removing mirroring action Ante Knezic
` (2 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: Ante Knezic @ 2024-01-05 10:46 UTC (permalink / raw)
To: netdev
Cc: andrew, f.fainelli, olteanv, davem, edumazet, kuba, pabeni,
ante.knezic
Cross-chip port mirroring requires creating mirroring
segments on each switch that is acting as a part of the
mirroring route, from source to destination mirroring port.
For example, following configuration:
SW0 SW1 SW2 SW3
+-------+ +-------+ +-------+ +--------+
| P9|<--->|P10 P9|<--->|P10 P9|<--->|P10 |
| | | | | | | |
+-------+ +-------+ +----+--+ +--------+
^ |
| v
P2 P8
needs dsa tree devices to be configured as follows:
----------------------------------------
| | source destination |
| SW | mirror port mirror port |
----------------------------------------
| 0 | P2 -> P9 |
| 1 | P10 -> P9 |
| 2 | P10 -> P8 |
| 3 | -> |
----------------------------------------
This means that request for adding port mirroring needs to
be propagated to the entire dsa switch tree as we can have
mirroring path in which all switches need to be setup.
This is achieved through use of switch event notifiers.
When adding port mirroring, first step is to create a mirroring
route which will contain source and destination ports for each
switch in the route. Then, this route is passed on to each switch
where it is evaluated for mirror settings for this particular
switch. If a switch is contained inside the route, its source
and destination ports are passed on to ds->ops->port_mirror_add()
normally.
Similar principle applies when removing port mirroring, where
complete mirroring route needs to be extracted from dsa_tree
mirrors list.
Signed-off-by: Ante Knezic <ante.knezic@helmholz.de>
---
net/dsa/switch.c | 52 +++++++++++++++++
net/dsa/switch.h | 8 +++
net/dsa/user.c | 174 ++++++++++++++++++++++++++++++++++++++++++++++++++-----
3 files changed, 219 insertions(+), 15 deletions(-)
diff --git a/net/dsa/switch.c b/net/dsa/switch.c
index 3d2feeea897b..5a81742cb139 100644
--- a/net/dsa/switch.c
+++ b/net/dsa/switch.c
@@ -125,6 +125,52 @@ static int dsa_switch_bridge_leave(struct dsa_switch *ds,
return 0;
}
+static int dsa_switch_mirror_add(struct dsa_switch *ds,
+ struct dsa_notifier_mirror_info *info)
+{
+ struct dsa_route *dr;
+ struct dsa_port *dp;
+ bool ingress;
+ int to_port;
+
+ list_for_each_entry(dr, &info->mirror->route, list) {
+ if (ds->index == dr->sw_index) {
+ ingress = info->mirror->ingress;
+ dp = dsa_to_port(ds, dr->to_local_p);
+ to_port = dp->index;
+
+ return ds->ops->port_mirror_add(ds, dr->from_local_p,
+ to_port, ingress,
+ info->extack);
+ }
+ }
+
+ return 0;
+}
+
+static int dsa_switch_mirror_del(struct dsa_switch *ds,
+ struct dsa_notifier_mirror_info *info)
+{
+ struct dsa_route *dr;
+ struct dsa_port *dp;
+ bool ingress;
+ int to_port;
+
+ /* check if switch is a part of the route we are trying to delete */
+ list_for_each_entry(dr, &info->mirror->route, list) {
+ if (ds->index == dr->sw_index) {
+ ingress = info->mirror->ingress;
+ dp = dsa_to_port(ds, dr->to_local_p);
+ to_port = dp->index;
+
+ ds->ops->port_mirror_del(ds, dr->from_local_p,
+ to_port, ingress);
+ }
+ }
+
+ return 0;
+}
+
/* Matches for all upstream-facing ports (the CPU port and all upstream-facing
* DSA links) that sit between the targeted port on which the notifier was
* emitted and its dedicated CPU port.
@@ -1059,6 +1105,12 @@ static int dsa_switch_event(struct notifier_block *nb,
case DSA_NOTIFIER_CONDUIT_STATE_CHANGE:
err = dsa_switch_conduit_state_change(ds, info);
break;
+ case DSA_NOTIFIER_MIRROR_ADD:
+ err = dsa_switch_mirror_add(ds, info);
+ break;
+ case DSA_NOTIFIER_MIRROR_DEL:
+ err = dsa_switch_mirror_del(ds, info);
+ break;
default:
err = -EOPNOTSUPP;
break;
diff --git a/net/dsa/switch.h b/net/dsa/switch.h
index be0a2749cd97..9fa52f5bc11d 100644
--- a/net/dsa/switch.h
+++ b/net/dsa/switch.h
@@ -35,6 +35,8 @@ enum {
DSA_NOTIFIER_TAG_8021Q_VLAN_ADD,
DSA_NOTIFIER_TAG_8021Q_VLAN_DEL,
DSA_NOTIFIER_CONDUIT_STATE_CHANGE,
+ DSA_NOTIFIER_MIRROR_ADD,
+ DSA_NOTIFIER_MIRROR_DEL,
};
/* DSA_NOTIFIER_AGEING_TIME */
@@ -111,6 +113,12 @@ struct dsa_notifier_conduit_state_info {
bool operational;
};
+/* DSA_NOTIFIER_MIRROR_ADD */
+struct dsa_notifier_mirror_info {
+ const struct dsa_mirror *mirror;
+ struct netlink_ext_ack *extack;
+};
+
struct dsa_vlan *dsa_vlan_find(struct list_head *vlan_list,
const struct switchdev_obj_port_vlan *vlan);
diff --git a/net/dsa/user.c b/net/dsa/user.c
index ce73d0a5140d..7f705ae8633b 100644
--- a/net/dsa/user.c
+++ b/net/dsa/user.c
@@ -1359,6 +1359,89 @@ dsa_user_mall_tc_entry_find(struct net_device *dev, unsigned long cookie)
return NULL;
}
+static int dsa_route_add_segment(int sw_index, int from_port,
+ int to_port, struct list_head *route)
+{
+ struct dsa_route *nr;
+
+ nr = kzalloc(sizeof(*nr), GFP_KERNEL);
+ if (!nr)
+ return -ENOMEM;
+
+ nr->sw_index = sw_index;
+ nr->from_local_p = from_port;
+ nr->to_local_p = to_port;
+ list_add(&nr->list, route);
+ return 0;
+}
+
+static int dsa_route_create(struct dsa_port *from_dp, struct dsa_port *to_dp,
+ struct dsa_port *iter, struct list_head *route)
+{
+ struct dsa_switch_tree *dst = from_dp->ds->dst;
+ struct dsa_route *dr;
+ struct dsa_link *dl;
+ int err;
+
+ if (from_dp->ds == to_dp->ds)
+ return dsa_route_add_segment(from_dp->ds->index, from_dp->index,
+ to_dp->index, route);
+
+ /* Assign iter to final "to port" on first entry */
+ if (!iter)
+ iter = to_dp;
+
+ list_for_each_entry(dl, &dst->rtable, list) {
+ if (dl->dp->ds != iter->ds)
+ continue;
+
+ dr = list_first_entry_or_null(route, struct dsa_route, list);
+
+ if (!dr || dr->sw_index != dl->link_dp->ds->index) {
+ err = dsa_route_add_segment(dl->dp->ds->index, dl->dp->index,
+ dr ? iter->index : to_dp->index,
+ route);
+ if (err)
+ return err;
+
+ /* have we reached the final "from" device */
+ if (dl->link_dp->ds == from_dp->ds)
+ return dsa_route_add_segment(dl->link_dp->ds->index,
+ from_dp->index,
+ dl->link_dp->index, route);
+
+ err = dsa_route_create(from_dp, to_dp, dl->link_dp, route);
+ if (err <= 0)
+ return err;
+ }
+ }
+
+ dr = list_first_entry_or_null(route, struct dsa_route, list);
+ if (dr) {
+ list_del(&dr->list);
+ kfree(dr);
+ }
+
+ return 1;
+}
+
+static struct dsa_mirror *dsa_tree_find_mirror(struct dsa_switch_tree *dst,
+ struct dsa_port *from_dp,
+ struct dsa_mall_mirror_tc_entry *mirror)
+{
+ struct dsa_mirror *dm;
+
+ list_for_each_entry(dm, &dst->mirrors, list) {
+ if (dm->ingress != mirror->ingress)
+ continue;
+
+ if (dm->from_dp == from_dp && dm->to_dp == mirror->to_port)
+ return dm;
+ }
+
+ return NULL;
+}
+
static int
dsa_user_add_cls_matchall_mirred(struct net_device *dev,
struct tc_cls_matchall_offload *cls,
@@ -1369,9 +1452,12 @@ dsa_user_add_cls_matchall_mirred(struct net_device *dev,
struct dsa_user_priv *p = netdev_priv(dev);
struct dsa_mall_mirror_tc_entry *mirror;
struct dsa_mall_tc_entry *mall_tc_entry;
+ struct dsa_notifier_mirror_info info;
struct dsa_switch *ds = dp->ds;
struct flow_action_entry *act;
+ struct dsa_route *dr, *n;
struct dsa_port *to_dp;
+ struct dsa_mirror *dm;
int err;
if (!ds->ops->port_mirror_add)
@@ -1389,6 +1475,10 @@ dsa_user_add_cls_matchall_mirred(struct net_device *dev,
if (!dsa_user_dev_check(act->dev))
return -EOPNOTSUPP;
+ to_dp = dsa_user_to_port(act->dev);
+ if (ds->dst != to_dp->ds->dst)
+ return -EINVAL;
+
mall_tc_entry = kzalloc(sizeof(*mall_tc_entry), GFP_KERNEL);
if (!mall_tc_entry)
return -ENOMEM;
@@ -1396,20 +1486,53 @@ dsa_user_add_cls_matchall_mirred(struct net_device *dev,
mall_tc_entry->cookie = cls->cookie;
mall_tc_entry->type = DSA_PORT_MALL_MIRROR;
mirror = &mall_tc_entry->mirror;
-
- to_dp = dsa_user_to_port(act->dev);
-
mirror->to_port = to_dp;
mirror->ingress = ingress;
- err = ds->ops->port_mirror_add(ds, dp->index, to_dp->index, ingress, extack);
- if (err) {
- kfree(mall_tc_entry);
- return err;
+ if (dsa_tree_find_mirror(ds->dst, dp, mirror)) {
+ err = -EINVAL;
+ goto err_mirror;
+ }
+
+ dm = kzalloc(sizeof(*dm), GFP_KERNEL);
+ if (!dm) {
+ err = -ENOMEM;
+ goto err_mirror;
}
+ INIT_LIST_HEAD(&dm->route);
+ dm->from_dp = dp;
+ dm->to_dp = to_dp;
+ dm->ingress = ingress;
+
+ if (dsa_route_create(dp, to_dp, NULL, &dm->route)) {
+ err = -EINVAL;
+ goto err_route;
+ }
+
+ info.mirror = dm;
+ info.extack = extack;
+
+ err = dsa_tree_notify(ds->dst, DSA_NOTIFIER_MIRROR_ADD, &info);
+ if (err)
+ goto err_route;
+
+ list_add(&dm->list, &ds->dst->mirrors);
list_add_tail(&mall_tc_entry->list, &p->mall_tc_list);
+ return 0;
+
+err_route:
+ dsa_tree_notify(ds->dst, DSA_NOTIFIER_MIRROR_DEL, &info);
+
+ list_for_each_entry_safe(dr, n, &dm->route, list) {
+ list_del(&dr->list);
+ kfree(dr);
+ }
+ kfree(dm);
+err_mirror:
+ kfree(mall_tc_entry);
+
return err;
}
@@ -1491,6 +1614,33 @@ static int dsa_user_add_cls_matchall(struct net_device *dev,
return err;
}
+static void dsa_user_mirror_del(struct dsa_switch *ds, struct dsa_port *dp,
+ struct dsa_mall_mirror_tc_entry *mirror)
+{
+ struct dsa_notifier_mirror_info info;
+ struct dsa_route *dr, *n;
+ struct dsa_mirror *dm;
+
+ dm = dsa_tree_find_mirror(ds->dst, dp, mirror);
+
+ if (!dm) {
+ netdev_err(dp->user, "failed to delete mirror\n");
+ return;
+ }
+
+ info.mirror = dm;
+
+ dsa_tree_notify(ds->dst, DSA_NOTIFIER_MIRROR_DEL, &info);
+
+ list_for_each_entry_safe(dr, n, &dm->route, list) {
+ list_del(&dr->list);
+ kfree(dr);
+ }
+
+ list_del(&dm->list);
+ kfree(dm);
+}
+
static void dsa_user_del_cls_matchall(struct net_device *dev,
struct tc_cls_matchall_offload *cls)
{
@@ -1506,14 +1656,8 @@ static void dsa_user_del_cls_matchall(struct net_device *dev,
switch (mall_tc_entry->type) {
case DSA_PORT_MALL_MIRROR:
- if (ds->ops->port_mirror_del) {
- struct dsa_mall_mirror_tc_entry *mirror;
-
- mirror = &mall_tc_entry->mirror;
- ds->ops->port_mirror_del(ds, dp->index,
- mirror->to_port->index,
- mirror->ingress);
- }
+ if (ds->ops->port_mirror_del)
+ dsa_user_mirror_del(ds, dp, &mall_tc_entry->mirror);
break;
case DSA_PORT_MALL_POLICER:
if (ds->ops->port_policer_del)
--
2.11.0
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [RFC PATCH net-next 4/6] net: dsa: check for busy mirror ports when removing mirroring action
2024-01-05 10:46 [RFC PATCH net-next 0/6] add dsa cross-chip port mirroring Ante Knezic
` (2 preceding siblings ...)
2024-01-05 10:46 ` [RFC PATCH net-next 3/6] net: dsa: implement cross chip port mirroring Ante Knezic
@ 2024-01-05 10:46 ` Ante Knezic
2024-01-05 10:46 ` [RFC PATCH net-next 5/6] net: dsa: mv88e6xxx: properly disable mirror destination Ante Knezic
2024-01-05 10:46 ` [RFC PATCH net-next 6/6] net: dsa: mv88e6xxx add cross-chip mirroring Ante Knezic
5 siblings, 0 replies; 7+ messages in thread
From: Ante Knezic @ 2024-01-05 10:46 UTC (permalink / raw)
To: netdev
Cc: andrew, f.fainelli, olteanv, davem, edumazet, kuba, pabeni,
ante.knezic
Check if the source/destination mirror ports are being used by
another mirroring route. This is necessary as otherwise we
might be interfering with mirroring operation of another mirror
route.
Signed-off-by: Ante Knezic <ante.knezic@helmholz.de>
---
drivers/net/dsa/b53/b53_common.c | 3 ++-
drivers/net/dsa/b53/b53_priv.h | 2 +-
drivers/net/dsa/microchip/ksz_common.c | 3 ++-
drivers/net/dsa/mt7530.c | 3 ++-
drivers/net/dsa/mv88e6xxx/chip.c | 3 ++-
drivers/net/dsa/ocelot/felix.c | 3 ++-
drivers/net/dsa/qca/qca8k-common.c | 3 ++-
drivers/net/dsa/qca/qca8k.h | 3 ++-
drivers/net/dsa/sja1105/sja1105_main.c | 3 ++-
include/net/dsa.h | 10 +++++++++-
net/dsa/switch.c | 34 +++++++++++++++++++++++++++++++++-
11 files changed, 59 insertions(+), 11 deletions(-)
diff --git a/drivers/net/dsa/b53/b53_common.c b/drivers/net/dsa/b53/b53_common.c
index 993adbc81339..79b2c9dab77d 100644
--- a/drivers/net/dsa/b53/b53_common.c
+++ b/drivers/net/dsa/b53/b53_common.c
@@ -2155,7 +2155,8 @@ int b53_mirror_add(struct dsa_switch *ds, int from_port,
EXPORT_SYMBOL(b53_mirror_add);
void b53_mirror_del(struct dsa_switch *ds, int from_port,
- int to_port, bool ingress)
+ int to_port, bool ingress,
+ enum dsa_route_status route_status)
{
struct b53_device *dev = ds->priv;
bool loc_disable = false, other_loc_disable = false;
diff --git a/drivers/net/dsa/b53/b53_priv.h b/drivers/net/dsa/b53/b53_priv.h
index 625dafcd757b..d78b3d04ffe0 100644
--- a/drivers/net/dsa/b53/b53_priv.h
+++ b/drivers/net/dsa/b53/b53_priv.h
@@ -391,7 +391,7 @@ int b53_mirror_add(struct dsa_switch *ds, int from_port,
enum dsa_tag_protocol b53_get_tag_protocol(struct dsa_switch *ds, int port,
enum dsa_tag_protocol mprot);
void b53_mirror_del(struct dsa_switch *ds, int from_port, int to_port,
- bool ingress);
+ bool ingress, enum dsa_route_status route_status);
int b53_enable_port(struct dsa_switch *ds, int port, struct phy_device *phy);
void b53_disable_port(struct dsa_switch *ds, int port);
void b53_brcm_hdr_setup(struct dsa_switch *ds, int port);
diff --git a/drivers/net/dsa/microchip/ksz_common.c b/drivers/net/dsa/microchip/ksz_common.c
index 824bfb0ed0ad..ab2a65ba498c 100644
--- a/drivers/net/dsa/microchip/ksz_common.c
+++ b/drivers/net/dsa/microchip/ksz_common.c
@@ -2783,7 +2783,8 @@ static int ksz_port_mirror_add(struct dsa_switch *ds, int from_port,
}
static void ksz_port_mirror_del(struct dsa_switch *ds, int from_port,
- int to_port, bool ingress)
+ int to_port, bool ingress,
+ enum dsa_route_status route_status)
{
struct ksz_device *dev = ds->priv;
diff --git a/drivers/net/dsa/mt7530.c b/drivers/net/dsa/mt7530.c
index 9e284edfbd0e..aba020687427 100644
--- a/drivers/net/dsa/mt7530.c
+++ b/drivers/net/dsa/mt7530.c
@@ -1799,7 +1799,8 @@ static int mt753x_port_mirror_add(struct dsa_switch *ds, int from_port,
}
static void mt753x_port_mirror_del(struct dsa_switch *ds, int from_port,
- int to_port, bool ingress)
+ int to_port, bool ingress,
+ enum dsa_route_status route_status)
{
struct mt7530_priv *priv = ds->priv;
u32 val;
diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index b8820b31d05b..1938f0b1644f 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -6520,7 +6520,8 @@ static int mv88e6xxx_port_mirror_add(struct dsa_switch *ds, int from_port,
}
static void mv88e6xxx_port_mirror_del(struct dsa_switch *ds, int from_port,
- int to_port, bool ingress)
+ int to_port, bool ingress,
+ enum dsa_route_status route_status)
{
enum mv88e6xxx_egress_direction direction = ingress ?
MV88E6XXX_EGRESS_DIR_INGRESS :
diff --git a/drivers/net/dsa/ocelot/felix.c b/drivers/net/dsa/ocelot/felix.c
index c3d21e06bde3..0ba9a79316d3 100644
--- a/drivers/net/dsa/ocelot/felix.c
+++ b/drivers/net/dsa/ocelot/felix.c
@@ -1864,7 +1864,8 @@ static int felix_port_mirror_add(struct dsa_switch *ds, int from_port,
}
static void felix_port_mirror_del(struct dsa_switch *ds, int from_port,
- int to_port, bool ingress)
+ int to_port, bool ingress,
+ enum dsa_route_status route_status)
{
struct ocelot *ocelot = ds->priv;
diff --git a/drivers/net/dsa/qca/qca8k-common.c b/drivers/net/dsa/qca/qca8k-common.c
index 4ff6763a81ce..fc009f3c460a 100644
--- a/drivers/net/dsa/qca/qca8k-common.c
+++ b/drivers/net/dsa/qca/qca8k-common.c
@@ -940,7 +940,8 @@ int qca8k_port_mirror_add(struct dsa_switch *ds, int from_port,
}
void qca8k_port_mirror_del(struct dsa_switch *ds, int from_port,
- int to_port, bool ingress)
+ int to_port, bool ingress,
+ enum dsa_route_status route_status)
{
struct qca8k_priv *priv = ds->priv;
u32 reg, val;
diff --git a/drivers/net/dsa/qca/qca8k.h b/drivers/net/dsa/qca/qca8k.h
index 7c6e75a37e13..7a4ac5d4a505 100644
--- a/drivers/net/dsa/qca/qca8k.h
+++ b/drivers/net/dsa/qca/qca8k.h
@@ -573,7 +573,8 @@ int qca8k_port_mirror_add(struct dsa_switch *ds, int from_port,
int to_port, bool ingress,
struct netlink_ext_ack *extack);
void qca8k_port_mirror_del(struct dsa_switch *ds, int from_port,
- int to_port, bool ingress);
+ int to_port, bool ingress,
+ enum dsa_route_status route_status);
/* Common port VLAN function */
int qca8k_port_vlan_filtering(struct dsa_switch *ds, int port, bool vlan_filtering,
diff --git a/drivers/net/dsa/sja1105/sja1105_main.c b/drivers/net/dsa/sja1105/sja1105_main.c
index 7f4cb3a1f39d..bb4a703174c5 100644
--- a/drivers/net/dsa/sja1105/sja1105_main.c
+++ b/drivers/net/dsa/sja1105/sja1105_main.c
@@ -2903,7 +2903,8 @@ static int sja1105_mirror_add(struct dsa_switch *ds, int from_port, int to_port,
}
static void sja1105_mirror_del(struct dsa_switch *ds, int from_port,
- int to_port, bool ingress)
+ int to_port, bool ingress,
+ enum dsa_route_status route_status)
{
sja1105_mirror_apply(ds->priv, from_port, to_port,
ingress, false);
diff --git a/include/net/dsa.h b/include/net/dsa.h
index aa0e97150bc3..f17da56d138d 100644
--- a/include/net/dsa.h
+++ b/include/net/dsa.h
@@ -88,6 +88,13 @@ enum dsa_tag_protocol {
DSA_TAG_PROTO_LAN937X = DSA_TAG_PROTO_LAN937X_VALUE,
};
+enum dsa_route_status {
+ DSA_ROUTE_UNUSED = 0,
+ DSA_ROUTE_SRC_PORT_BUSY = BIT(0),
+ DSA_ROUTE_DEST_PORT_BUSY = BIT(1),
+ DSA_ROUTE_BUSY = (BIT(0) | BIT(1))
+};
+
struct dsa_switch;
struct dsa_device_ops {
@@ -1120,7 +1127,8 @@ struct dsa_switch_ops {
int to_port, bool ingress,
struct netlink_ext_ack *extack);
void (*port_mirror_del)(struct dsa_switch *ds, int from_port,
- int to_port, bool ingress);
+ int to_port, bool ingress,
+ enum dsa_route_status route_status);
int (*port_policer_add)(struct dsa_switch *ds, int port,
struct dsa_mall_policer_tc_entry *policer);
void (*port_policer_del)(struct dsa_switch *ds, int port);
diff --git a/net/dsa/switch.c b/net/dsa/switch.c
index 5a81742cb139..17d71bde5df5 100644
--- a/net/dsa/switch.c
+++ b/net/dsa/switch.c
@@ -148,9 +148,38 @@ static int dsa_switch_mirror_add(struct dsa_switch *ds,
return 0;
}
+static enum dsa_route_status dsa_route_get_status(struct dsa_switch *ds,
+ const struct dsa_mirror *dm,
+ int from_port, int to_port)
+{
+ enum dsa_route_status ret;
+ struct dsa_mirror *m;
+ struct dsa_route *r;
+
+ ret = DSA_ROUTE_UNUSED;
+ list_for_each_entry(m, &ds->dst->mirrors, list) {
+ if (m == dm)
+ continue;
+ if (m->ingress != dm->ingress)
+ continue;
+
+ list_for_each_entry(r, &m->route, list) {
+ if (r->sw_index == ds->index) {
+ if (r->from_local_p == from_port)
+ ret |= DSA_ROUTE_SRC_PORT_BUSY;
+ if (r->to_local_p == to_port)
+ ret |= DSA_ROUTE_DEST_PORT_BUSY;
+ }
+ }
+ }
+
+ return ret;
+}
+
static int dsa_switch_mirror_del(struct dsa_switch *ds,
struct dsa_notifier_mirror_info *info)
{
+ enum dsa_route_status status;
struct dsa_route *dr;
struct dsa_port *dp;
bool ingress;
@@ -162,9 +191,12 @@ static int dsa_switch_mirror_del(struct dsa_switch *ds,
ingress = info->mirror->ingress;
dp = dsa_to_port(ds, dr->to_local_p);
to_port = dp->index;
+ status = dsa_route_get_status(ds, info->mirror,
+ dr->from_local_p,
+ dr->to_local_p);
ds->ops->port_mirror_del(ds, dr->from_local_p,
- to_port, ingress);
+ to_port, ingress, status);
}
}
--
2.11.0
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [RFC PATCH net-next 5/6] net: dsa: mv88e6xxx: properly disable mirror destination
2024-01-05 10:46 [RFC PATCH net-next 0/6] add dsa cross-chip port mirroring Ante Knezic
` (3 preceding siblings ...)
2024-01-05 10:46 ` [RFC PATCH net-next 4/6] net: dsa: check for busy mirror ports when removing mirroring action Ante Knezic
@ 2024-01-05 10:46 ` Ante Knezic
2024-01-05 10:46 ` [RFC PATCH net-next 6/6] net: dsa: mv88e6xxx add cross-chip mirroring Ante Knezic
5 siblings, 0 replies; 7+ messages in thread
From: Ante Knezic @ 2024-01-05 10:46 UTC (permalink / raw)
To: netdev
Cc: andrew, f.fainelli, olteanv, davem, edumazet, kuba, pabeni,
ante.knezic
According to Switch Functional Specification in order to
disable policy mirroring we need to set mirror destination
to 0x1F.
Signed-off-by: Ante Knezic <ante.knezic@helmholz.de>
---
drivers/net/dsa/mv88e6xxx/chip.c | 2 +-
drivers/net/dsa/mv88e6xxx/chip.h | 3 +++
2 files changed, 4 insertions(+), 1 deletion(-)
diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index 1938f0b1644f..ce3a5d61edb4 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -6542,7 +6542,7 @@ static void mv88e6xxx_port_mirror_del(struct dsa_switch *ds, int from_port,
/* Reset egress port when no other mirror is active */
if (!other_mirrors) {
if (mv88e6xxx_set_egress_port(chip, direction,
- dsa_upstream_port(ds, from_port)))
+ MV88E6XXX_EGRESS_DEST_DISABLE))
dev_err(ds->dev, "failed to set egress port\n");
}
diff --git a/drivers/net/dsa/mv88e6xxx/chip.h b/drivers/net/dsa/mv88e6xxx/chip.h
index 85eb293381a7..a73da4e965ec 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.h
+++ b/drivers/net/dsa/mv88e6xxx/chip.h
@@ -589,6 +589,9 @@ struct mv88e6xxx_ops {
const struct mv88e6xxx_hw_stat *stat,
uint64_t *data);
int (*set_cpu_port)(struct mv88e6xxx_chip *chip, int port);
+
+#define MV88E6XXX_EGRESS_DEST_DISABLE 0x1f
+
int (*set_egress_port)(struct mv88e6xxx_chip *chip,
enum mv88e6xxx_egress_direction direction,
int port);
--
2.11.0
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [RFC PATCH net-next 6/6] net: dsa: mv88e6xxx add cross-chip mirroring
2024-01-05 10:46 [RFC PATCH net-next 0/6] add dsa cross-chip port mirroring Ante Knezic
` (4 preceding siblings ...)
2024-01-05 10:46 ` [RFC PATCH net-next 5/6] net: dsa: mv88e6xxx: properly disable mirror destination Ante Knezic
@ 2024-01-05 10:46 ` Ante Knezic
5 siblings, 0 replies; 7+ messages in thread
From: Ante Knezic @ 2024-01-05 10:46 UTC (permalink / raw)
To: netdev
Cc: andrew, f.fainelli, olteanv, davem, edumazet, kuba, pabeni,
ante.knezic
modify mv88e6xxx port mirroring to support cross-chip mirroring.
Remove mirror_ingress and mirror_egress as they are no longer
needed.
Do not allow setting dsa ports as mirror source port as
recommended by the Switch Functional Specification.
Signed-off-by: Ante Knezic <ante.knezic@helmholz.de>
---
drivers/net/dsa/mv88e6xxx/chip.c | 77 +++++++++++++++++++++++++---------------
drivers/net/dsa/mv88e6xxx/chip.h | 2 --
drivers/net/dsa/mv88e6xxx/port.c | 5 ---
3 files changed, 48 insertions(+), 36 deletions(-)
diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index ce3a5d61edb4..fab92c3cb511 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -3568,6 +3568,28 @@ static int mv88e6xxx_stats_setup(struct mv88e6xxx_chip *chip)
return mv88e6xxx_g1_stats_clear(chip);
}
+static int mv88e6xxx_mirror_setup(struct mv88e6xxx_chip *chip)
+{
+ int err, port, i;
+ const enum mv88e6xxx_egress_direction direction[] = {
+ MV88E6XXX_EGRESS_DIR_INGRESS, MV88E6XXX_EGRESS_DIR_EGRESS};
+
+ for (i = 0; i < ARRAY_SIZE(direction); i++) {
+ err = mv88e6xxx_set_egress_port(chip, i,
+ MV88E6XXX_EGRESS_DEST_DISABLE);
+ if (err)
+ return err;
+
+ for (port = 0; port < mv88e6xxx_num_ports(chip); port++) {
+ err = mv88e6xxx_port_set_mirror(chip, port, i, false);
+ if (err)
+ return err;
+ }
+ }
+
+ return 0;
+}
+
/* Check if the errata has already been applied. */
static bool mv88e6390_setup_errata_applied(struct mv88e6xxx_chip *chip)
{
@@ -3966,6 +3988,10 @@ static int mv88e6xxx_setup(struct dsa_switch *ds)
if (err)
goto unlock;
+ err = mv88e6xxx_mirror_setup(chip);
+ if (err)
+ goto unlock;
+
unlock:
mv88e6xxx_reg_unlock(chip);
@@ -6488,31 +6514,26 @@ static int mv88e6xxx_port_mirror_add(struct dsa_switch *ds, int from_port,
MV88E6XXX_EGRESS_DIR_INGRESS :
MV88E6XXX_EGRESS_DIR_EGRESS;
struct mv88e6xxx_chip *chip = ds->priv;
- bool other_mirrors = false;
- int i;
+ int *dest_port;
int err;
mutex_lock(&chip->reg_lock);
- if ((ingress ? chip->ingress_dest_port : chip->egress_dest_port) !=
- to_port) {
- for (i = 0; i < mv88e6xxx_num_ports(chip); i++)
- other_mirrors |= ingress ?
- chip->ports[i].mirror_ingress :
- chip->ports[i].mirror_egress;
-
- /* Can't change egress port when other mirror is active */
- if (other_mirrors) {
- err = -EBUSY;
- goto out;
- }
+ dest_port = ingress ? &chip->ingress_dest_port : &chip->egress_dest_port;
- err = mv88e6xxx_set_egress_port(chip, direction,
- to_port);
- if (err)
- goto out;
+ /* Can't change egress port when mirroring is active */
+ if (*dest_port != MV88E6XXX_EGRESS_DEST_DISABLE &&
+ *dest_port != to_port) {
+ err = -EBUSY;
+ goto out;
}
- err = mv88e6xxx_port_set_mirror(chip, from_port, direction, true);
+ err = mv88e6xxx_set_egress_port(chip, direction, to_port);
+ if (err)
+ goto out;
+
+ if (dsa_port_is_user(dsa_to_port(ds, from_port)))
+ err = mv88e6xxx_port_set_mirror(chip, from_port, direction, true);
+
out:
mutex_unlock(&chip->reg_lock);
@@ -6527,20 +6548,18 @@ static void mv88e6xxx_port_mirror_del(struct dsa_switch *ds, int from_port,
MV88E6XXX_EGRESS_DIR_INGRESS :
MV88E6XXX_EGRESS_DIR_EGRESS;
struct mv88e6xxx_chip *chip = ds->priv;
- bool other_mirrors = false;
- int i;
+ int *dest_port;
mutex_lock(&chip->reg_lock);
- if (mv88e6xxx_port_set_mirror(chip, from_port, direction, false))
- dev_err(ds->dev, "p%d: failed to disable mirroring\n", from_port);
+ dest_port = ingress ? &chip->ingress_dest_port : &chip->egress_dest_port;
- for (i = 0; i < mv88e6xxx_num_ports(chip); i++)
- other_mirrors |= ingress ?
- chip->ports[i].mirror_ingress :
- chip->ports[i].mirror_egress;
+ if (!(route_status & DSA_ROUTE_SRC_PORT_BUSY)) {
+ if (mv88e6xxx_port_set_mirror(chip, from_port, direction, false))
+ dev_err(ds->dev, "p%d: failed to disable mirroring\n", from_port);
+ }
- /* Reset egress port when no other mirror is active */
- if (!other_mirrors) {
+ if (!(route_status & DSA_ROUTE_DEST_PORT_BUSY) &&
+ *dest_port == to_port) {
if (mv88e6xxx_set_egress_port(chip, direction,
MV88E6XXX_EGRESS_DEST_DISABLE))
dev_err(ds->dev, "failed to set egress port\n");
diff --git a/drivers/net/dsa/mv88e6xxx/chip.h b/drivers/net/dsa/mv88e6xxx/chip.h
index a73da4e965ec..0000a7aa3fbc 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.h
+++ b/drivers/net/dsa/mv88e6xxx/chip.h
@@ -284,8 +284,6 @@ struct mv88e6xxx_port {
u64 vtu_miss_violation;
phy_interface_t interface;
u8 cmode;
- bool mirror_ingress;
- bool mirror_egress;
struct devlink_region *region;
void *pcs_private;
diff --git a/drivers/net/dsa/mv88e6xxx/port.c b/drivers/net/dsa/mv88e6xxx/port.c
index 5394a8cf7bf1..777515ee722b 100644
--- a/drivers/net/dsa/mv88e6xxx/port.c
+++ b/drivers/net/dsa/mv88e6xxx/port.c
@@ -1183,7 +1183,6 @@ int mv88e6xxx_port_set_mirror(struct mv88e6xxx_chip *chip, int port,
enum mv88e6xxx_egress_direction direction,
bool mirror)
{
- bool *mirror_port;
u16 reg;
u16 bit;
int err;
@@ -1195,11 +1194,9 @@ int mv88e6xxx_port_set_mirror(struct mv88e6xxx_chip *chip, int port,
switch (direction) {
case MV88E6XXX_EGRESS_DIR_INGRESS:
bit = MV88E6XXX_PORT_CTL2_INGRESS_MONITOR;
- mirror_port = &chip->ports[port].mirror_ingress;
break;
case MV88E6XXX_EGRESS_DIR_EGRESS:
bit = MV88E6XXX_PORT_CTL2_EGRESS_MONITOR;
- mirror_port = &chip->ports[port].mirror_egress;
break;
default:
return -EINVAL;
@@ -1210,8 +1207,6 @@ int mv88e6xxx_port_set_mirror(struct mv88e6xxx_chip *chip, int port,
reg |= bit;
err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL2, reg);
- if (!err)
- *mirror_port = mirror;
return err;
}
--
2.11.0
^ permalink raw reply related [flat|nested] 7+ messages in thread
end of thread, other threads:[~2024-01-05 10:49 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-01-05 10:46 [RFC PATCH net-next 0/6] add dsa cross-chip port mirroring Ante Knezic
2024-01-05 10:46 ` [RFC PATCH net-next 1/6] net:dsa: drop mirror struct from port mirror functions Ante Knezic
2024-01-05 10:46 ` [RFC PATCH net-next 2/6] net: dsa: add groundwork for cross chip mirroring Ante Knezic
2024-01-05 10:46 ` [RFC PATCH net-next 3/6] net: dsa: implement cross chip port mirroring Ante Knezic
2024-01-05 10:46 ` [RFC PATCH net-next 4/6] net: dsa: check for busy mirror ports when removing mirroring action Ante Knezic
2024-01-05 10:46 ` [RFC PATCH net-next 5/6] net: dsa: mv88e6xxx: properly disable mirror destination Ante Knezic
2024-01-05 10:46 ` [RFC PATCH net-next 6/6] net: dsa: mv88e6xxx add cross-chip mirroring Ante Knezic
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).