net: mscc: ocelot: offload redirect action to VCAP IS2
authorVladimir Oltean <vladimir.oltean@nxp.com>
Fri, 2 Oct 2020 12:02:27 +0000 (15:02 +0300)
committerDavid S. Miller <davem@davemloft.net>
Fri, 2 Oct 2020 22:40:30 +0000 (15:40 -0700)
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>
drivers/net/ethernet/mscc/ocelot_flower.c

index b26a5f8dc62d6280439fbd74c19ab3770abb0b2b..0ea6d4f411cbf840a503d77a85da6d7ddcce7e97 100644 (file)
@@ -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;