diff options
| author | Vladimir Oltean <vladimir.oltean@nxp.com> | 2024-10-23 16:52:51 +0300 |
|---|---|---|
| committer | Jakub Kicinski <kuba@kernel.org> | 2024-10-30 17:33:55 -0700 |
| commit | 49a09073cb23e02f57aa53cf6b9da3c888ab4713 (patch) | |
| tree | 999ab1127043ae5436b1aca1bc829b3f56438df2 | |
| parent | 3535d70df9c80b382a202baa430aa8fbb2433bfa (diff) | |
| download | linux-49a09073cb23e02f57aa53cf6b9da3c888ab4713.tar.gz linux-49a09073cb23e02f57aa53cf6b9da3c888ab4713.zip | |
net: mscc: ocelot: allow tc-flower mirred action towards foreign interfaces
Debugging certain flows in the offloaded switch data path can be done by
installing two tc-mirred filters for mirroring: one in the hardware data
path, which copies the frames to the CPU, and one which takes the frame
from there and mirrors it to a virtual interface like a dummy device,
where it can be seen with tcpdump.
The effect of having 2 filters run on the same packet can be obtained by
default using tc, by not specifying either the 'skip_sw' or 'skip_hw'
keywords.
Instead of refusing to offload mirroring/redirecting packets towards
interfaces that aren't switch ports, just treat every other destination
for what it is: something that is handled in software, behind the CPU
port.
Usage:
$ ip link add dummy0 type dummy; ip link set dummy0 up
$ tc qdisc add dev swp0 clsact
$ tc filter add dev swp0 ingress protocol ip flower action mirred ingress mirror dev dummy0
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Link: https://patch.msgid.link/20241023135251.1752488-7-vladimir.oltean@nxp.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
| -rw-r--r-- | drivers/net/ethernet/mscc/ocelot_flower.c | 54 |
1 files changed, 42 insertions, 12 deletions
diff --git a/drivers/net/ethernet/mscc/ocelot_flower.c b/drivers/net/ethernet/mscc/ocelot_flower.c index a057ec3dab97..986b1f150e3b 100644 --- a/drivers/net/ethernet/mscc/ocelot_flower.c +++ b/drivers/net/ethernet/mscc/ocelot_flower.c @@ -228,6 +228,32 @@ ocelot_flower_parse_egress_vlan_modify(struct ocelot_vcap_filter *filter, return 0; } +static int +ocelot_flower_parse_egress_port(struct ocelot *ocelot, struct flow_cls_offload *f, + const struct flow_action_entry *a, bool mirror, + struct netlink_ext_ack *extack) +{ + const char *act_string = mirror ? "mirror" : "redirect"; + int egress_port = ocelot->ops->netdev_to_port(a->dev); + enum flow_action_id offloadable_act_id; + + offloadable_act_id = mirror ? FLOW_ACTION_MIRRED : FLOW_ACTION_REDIRECT; + + /* Mirroring towards foreign interfaces is handled in software */ + if (egress_port < 0 || a->id != offloadable_act_id) { + if (f->common.skip_sw) { + NL_SET_ERR_MSG_FMT(extack, + "Can only %s to %s if filter also runs in software", + act_string, egress_port < 0 ? + "CPU" : "ingress of ocelot port"); + return -EOPNOTSUPP; + } + egress_port = ocelot->num_phys_ports; + } + + return egress_port; +} + static int ocelot_flower_parse_action(struct ocelot *ocelot, int port, bool ingress, struct flow_cls_offload *f, struct ocelot_vcap_filter *filter) @@ -356,6 +382,7 @@ static int ocelot_flower_parse_action(struct ocelot *ocelot, int port, filter->type = OCELOT_VCAP_FILTER_OFFLOAD; break; case FLOW_ACTION_REDIRECT: + case FLOW_ACTION_REDIRECT_INGRESS: if (filter->block_id != VCAP_IS2) { NL_SET_ERR_MSG_MOD(extack, "Redirect action can only be offloaded to VCAP IS2"); @@ -366,17 +393,19 @@ static int ocelot_flower_parse_action(struct ocelot *ocelot, int port, "Last action must be GOTO"); return -EOPNOTSUPP; } - egress_port = ocelot->ops->netdev_to_port(a->dev); - if (egress_port < 0) { - NL_SET_ERR_MSG_MOD(extack, - "Destination not an ocelot port"); - return -EOPNOTSUPP; - } + + egress_port = ocelot_flower_parse_egress_port(ocelot, f, + a, false, + extack); + if (egress_port < 0) + return egress_port; + filter->action.mask_mode = OCELOT_MASK_MODE_REDIRECT; filter->action.port_mask = BIT(egress_port); filter->type = OCELOT_VCAP_FILTER_OFFLOAD; break; case FLOW_ACTION_MIRRED: + case FLOW_ACTION_MIRRED_INGRESS: if (filter->block_id != VCAP_IS2) { NL_SET_ERR_MSG_MOD(extack, "Mirror action can only be offloaded to VCAP IS2"); @@ -387,12 +416,13 @@ static int ocelot_flower_parse_action(struct ocelot *ocelot, int port, "Last action must be GOTO"); return -EOPNOTSUPP; } - egress_port = ocelot->ops->netdev_to_port(a->dev); - if (egress_port < 0) { - NL_SET_ERR_MSG_MOD(extack, - "Destination not an ocelot port"); - return -EOPNOTSUPP; - } + + egress_port = ocelot_flower_parse_egress_port(ocelot, f, + a, true, + extack); + if (egress_port < 0) + return egress_port; + filter->egress_port.value = egress_port; filter->action.mirror_ena = true; filter->type = OCELOT_VCAP_FILTER_OFFLOAD; |
