From 9530dd3ff2debbd535016f7c9723ca90aa903bef Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Fri, 2 Oct 2020 15:02:27 +0300 Subject: [PATCH] net: mscc: ocelot: offload redirect action to VCAP IS2 Via the OCELOT_MASK_MODE_REDIRECT flag put in the IS2 action vector, it is possible to replace previous forwarding decisions with the port mask installed in this rule. I have studied Table 54 "MASK_MODE and PORT_MASK Combinations" from the VSC7514 documentation and it appears to behave sanely when this rule is installed in either lookup 0 or 1. Namely, a redirect in lookup 1 will overwrite the forwarding decision taken by any entry in lookup 0. Signed-off-by: Vladimir Oltean Signed-off-by: David S. Miller --- drivers/net/ethernet/mscc/ocelot_flower.c | 28 ++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/mscc/ocelot_flower.c b/drivers/net/ethernet/mscc/ocelot_flower.c index b26a5f8dc62d6..0ea6d4f411cbf 100644 --- a/drivers/net/ethernet/mscc/ocelot_flower.c +++ b/drivers/net/ethernet/mscc/ocelot_flower.c @@ -142,14 +142,15 @@ ocelot_find_vcap_filter_that_points_at(struct ocelot *ocelot, int chain) return NULL; } -static int ocelot_flower_parse_action(struct flow_cls_offload *f, bool ingress, +static int ocelot_flower_parse_action(struct ocelot *ocelot, bool ingress, + struct flow_cls_offload *f, struct ocelot_vcap_filter *filter) { struct netlink_ext_ack *extack = f->common.extack; bool allow_missing_goto_target = false; const struct flow_action_entry *a; enum ocelot_tag_tpid_sel tpid; - int i, chain; + int i, chain, egress_port; u64 rate; if (!flow_action_basic_hw_stats_check(&f->rule->action, @@ -224,6 +225,27 @@ static int ocelot_flower_parse_action(struct flow_cls_offload *f, bool ingress, filter->action.pol.burst = a->police.burst; filter->type = OCELOT_VCAP_FILTER_OFFLOAD; break; + case FLOW_ACTION_REDIRECT: + if (filter->block_id != VCAP_IS2) { + NL_SET_ERR_MSG_MOD(extack, + "Redirect 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->action.mask_mode = OCELOT_MASK_MODE_REDIRECT; + filter->action.port_mask = BIT(egress_port); + filter->type = OCELOT_VCAP_FILTER_OFFLOAD; + break; case FLOW_ACTION_VLAN_POP: if (filter->block_id != VCAP_IS1) { NL_SET_ERR_MSG_MOD(extack, @@ -579,7 +601,7 @@ static int ocelot_flower_parse(struct ocelot *ocelot, int port, bool ingress, filter->prio = f->common.prio; filter->id = f->cookie; - ret = ocelot_flower_parse_action(f, ingress, filter); + ret = ocelot_flower_parse_action(ocelot, ingress, f, filter); if (ret) return ret; -- 2.39.5