summaryrefslogtreecommitdiffstats
path: root/drivers/net/ethernet/mscc/ocelot_flower.c
diff options
context:
space:
mode:
authorVladimir Oltean <vladimir.oltean@nxp.com>2020-10-02 15:02:27 +0300
committerDavid S. Miller <davem@davemloft.net>2020-10-02 15:40:30 -0700
commit16a7a15f4b14c4e188d153786f433f1c8f103ebb (patch)
tree037ca386c29b0098ab23883675b847ef51c2281c /drivers/net/ethernet/mscc/ocelot_flower.c
parentf854e6f6f450c988cf2531e9551431de300a8719 (diff)
downloadlinux-16a7a15f4b14c4e188d153786f433f1c8f103ebb.tar.bz2
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 <vladimir.oltean@nxp.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/ethernet/mscc/ocelot_flower.c')
-rw-r--r--drivers/net/ethernet/mscc/ocelot_flower.c28
1 files changed, 25 insertions, 3 deletions
diff --git a/drivers/net/ethernet/mscc/ocelot_flower.c b/drivers/net/ethernet/mscc/ocelot_flower.c
index b26a5f8dc62d..0ea6d4f411cb 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;