Commit f2a0e216 authored by Vladimir Oltean's avatar Vladimir Oltean Committed by Jakub Kicinski

net: mscc: ocelot: offload per-flow mirroring using tc-mirred and VCAP IS2

Per-flow mirroring with the VCAP IS2 TCAM (in itself handled as an
offload for tc-flower) is done by setting the MIRROR_ENA bit from the
action vector of the filter. The packet is mirrored to the port mask
configured in the ANA:ANA:MIRRORPORTS register (the same port mask as
the destinations for port-based mirroring).

Functionality was tested with:

tc qdisc add dev swp3 clsact
tc filter add dev swp3 ingress protocol ip \
	flower skip_sw ip_proto icmp \
	action mirred egress mirror dev swp1

and pinging through swp3, while seeing that the ICMP replies are
mirrored towards swp1.
Signed-off-by: default avatarVladimir Oltean <vladimir.oltean@nxp.com>
Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent c3d427ea
...@@ -3023,7 +3023,7 @@ int ocelot_port_del_dscp_prio(struct ocelot *ocelot, int port, u8 dscp, u8 prio) ...@@ -3023,7 +3023,7 @@ int ocelot_port_del_dscp_prio(struct ocelot *ocelot, int port, u8 dscp, u8 prio)
} }
EXPORT_SYMBOL_GPL(ocelot_port_del_dscp_prio); EXPORT_SYMBOL_GPL(ocelot_port_del_dscp_prio);
static struct ocelot_mirror *ocelot_mirror_get(struct ocelot *ocelot, int to, struct ocelot_mirror *ocelot_mirror_get(struct ocelot *ocelot, int to,
struct netlink_ext_ack *extack) struct netlink_ext_ack *extack)
{ {
struct ocelot_mirror *m = ocelot->mirror; struct ocelot_mirror *m = ocelot->mirror;
...@@ -3053,7 +3053,7 @@ static struct ocelot_mirror *ocelot_mirror_get(struct ocelot *ocelot, int to, ...@@ -3053,7 +3053,7 @@ static struct ocelot_mirror *ocelot_mirror_get(struct ocelot *ocelot, int to,
return m; return m;
} }
static void ocelot_mirror_put(struct ocelot *ocelot) void ocelot_mirror_put(struct ocelot *ocelot)
{ {
struct ocelot_mirror *m = ocelot->mirror; struct ocelot_mirror *m = ocelot->mirror;
......
...@@ -112,6 +112,10 @@ int ocelot_trap_add(struct ocelot *ocelot, int port, ...@@ -112,6 +112,10 @@ int ocelot_trap_add(struct ocelot *ocelot, int port,
void (*populate)(struct ocelot_vcap_filter *f)); void (*populate)(struct ocelot_vcap_filter *f));
int ocelot_trap_del(struct ocelot *ocelot, int port, unsigned long cookie); int ocelot_trap_del(struct ocelot *ocelot, int port, unsigned long cookie);
struct ocelot_mirror *ocelot_mirror_get(struct ocelot *ocelot, int to,
struct netlink_ext_ack *extack);
void ocelot_mirror_put(struct ocelot *ocelot);
extern struct notifier_block ocelot_netdevice_nb; extern struct notifier_block ocelot_netdevice_nb;
extern struct notifier_block ocelot_switchdev_nb; extern struct notifier_block ocelot_switchdev_nb;
extern struct notifier_block ocelot_switchdev_blocking_nb; extern struct notifier_block ocelot_switchdev_blocking_nb;
......
...@@ -359,6 +359,27 @@ static int ocelot_flower_parse_action(struct ocelot *ocelot, int port, ...@@ -359,6 +359,27 @@ static int ocelot_flower_parse_action(struct ocelot *ocelot, int port,
filter->action.port_mask = BIT(egress_port); filter->action.port_mask = BIT(egress_port);
filter->type = OCELOT_VCAP_FILTER_OFFLOAD; filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
break; break;
case FLOW_ACTION_MIRRED:
if (filter->block_id != VCAP_IS2) {
NL_SET_ERR_MSG_MOD(extack,
"Mirror action can only be offloaded to VCAP IS2");
return -EOPNOTSUPP;
}
if (filter->goto_target != -1) {
NL_SET_ERR_MSG_MOD(extack,
"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;
}
filter->egress_port.value = egress_port;
filter->action.mirror_ena = true;
filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
break;
case FLOW_ACTION_VLAN_POP: case FLOW_ACTION_VLAN_POP:
if (filter->block_id != VCAP_IS1) { if (filter->block_id != VCAP_IS1) {
NL_SET_ERR_MSG_MOD(extack, NL_SET_ERR_MSG_MOD(extack,
......
...@@ -335,6 +335,7 @@ static void is2_action_set(struct ocelot *ocelot, struct vcap_data *data, ...@@ -335,6 +335,7 @@ static void is2_action_set(struct ocelot *ocelot, struct vcap_data *data,
vcap_action_set(vcap, data, VCAP_IS2_ACT_MASK_MODE, a->mask_mode); vcap_action_set(vcap, data, VCAP_IS2_ACT_MASK_MODE, a->mask_mode);
vcap_action_set(vcap, data, VCAP_IS2_ACT_PORT_MASK, a->port_mask); vcap_action_set(vcap, data, VCAP_IS2_ACT_PORT_MASK, a->port_mask);
vcap_action_set(vcap, data, VCAP_IS2_ACT_MIRROR_ENA, a->mirror_ena);
vcap_action_set(vcap, data, VCAP_IS2_ACT_POLICE_ENA, a->police_ena); vcap_action_set(vcap, data, VCAP_IS2_ACT_POLICE_ENA, a->police_ena);
vcap_action_set(vcap, data, VCAP_IS2_ACT_POLICE_IDX, a->pol_ix); vcap_action_set(vcap, data, VCAP_IS2_ACT_POLICE_IDX, a->pol_ix);
vcap_action_set(vcap, data, VCAP_IS2_ACT_CPU_QU_NUM, a->cpu_qu_num); vcap_action_set(vcap, data, VCAP_IS2_ACT_CPU_QU_NUM, a->cpu_qu_num);
...@@ -960,8 +961,16 @@ ocelot_vcap_filter_add_aux_resources(struct ocelot *ocelot, ...@@ -960,8 +961,16 @@ ocelot_vcap_filter_add_aux_resources(struct ocelot *ocelot,
struct ocelot_vcap_filter *filter, struct ocelot_vcap_filter *filter,
struct netlink_ext_ack *extack) struct netlink_ext_ack *extack)
{ {
struct ocelot_mirror *m;
int ret; int ret;
if (filter->block_id == VCAP_IS2 && filter->action.mirror_ena) {
m = ocelot_mirror_get(ocelot, filter->egress_port.value,
extack);
if (IS_ERR(m))
return PTR_ERR(m);
}
if (filter->block_id == VCAP_IS2 && filter->action.police_ena) { if (filter->block_id == VCAP_IS2 && filter->action.police_ena) {
ret = ocelot_vcap_policer_add(ocelot, filter->action.pol_ix, ret = ocelot_vcap_policer_add(ocelot, filter->action.pol_ix,
&filter->action.pol); &filter->action.pol);
...@@ -978,6 +987,9 @@ ocelot_vcap_filter_del_aux_resources(struct ocelot *ocelot, ...@@ -978,6 +987,9 @@ ocelot_vcap_filter_del_aux_resources(struct ocelot *ocelot,
{ {
if (filter->block_id == VCAP_IS2 && filter->action.police_ena) if (filter->block_id == VCAP_IS2 && filter->action.police_ena)
ocelot_vcap_policer_del(ocelot, filter->action.pol_ix); ocelot_vcap_policer_del(ocelot, filter->action.pol_ix);
if (filter->block_id == VCAP_IS2 && filter->action.mirror_ena)
ocelot_mirror_put(ocelot);
} }
static int ocelot_vcap_filter_add_to_block(struct ocelot *ocelot, static int ocelot_vcap_filter_add_to_block(struct ocelot *ocelot,
......
...@@ -654,6 +654,7 @@ struct ocelot_vcap_action { ...@@ -654,6 +654,7 @@ struct ocelot_vcap_action {
enum ocelot_mask_mode mask_mode; enum ocelot_mask_mode mask_mode;
unsigned long port_mask; unsigned long port_mask;
bool police_ena; bool police_ena;
bool mirror_ena;
struct ocelot_policer pol; struct ocelot_policer pol;
u32 pol_ix; u32 pol_ix;
}; };
...@@ -697,6 +698,7 @@ struct ocelot_vcap_filter { ...@@ -697,6 +698,7 @@ struct ocelot_vcap_filter {
unsigned long ingress_port_mask; unsigned long ingress_port_mask;
/* For VCAP ES0 */ /* For VCAP ES0 */
struct ocelot_vcap_port ingress_port; struct ocelot_vcap_port ingress_port;
/* For VCAP IS2 mirrors and ES0 */
struct ocelot_vcap_port egress_port; struct ocelot_vcap_port egress_port;
enum ocelot_vcap_bit dmac_mc; enum ocelot_vcap_bit dmac_mc;
......
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