net/sfc: allow ports without MAE privilege
[dpdk.git] / drivers / net / sfc / sfc_flow.c
index 1294dbd..d57235f 100644 (file)
@@ -22,6 +22,7 @@
 #include "sfc_rx.h"
 #include "sfc_filter.h"
 #include "sfc_flow.h"
+#include "sfc_flow_tunnel.h"
 #include "sfc_log.h"
 #include "sfc_dp_rx.h"
 #include "sfc_mae_counter.h"
@@ -32,6 +33,7 @@ struct sfc_flow_ops_by_spec {
        sfc_flow_cleanup_cb_t   *cleanup;
        sfc_flow_insert_cb_t    *insert;
        sfc_flow_remove_cb_t    *remove;
+       sfc_flow_query_cb_t     *query;
 };
 
 static sfc_flow_parse_cb_t sfc_flow_parse_rte_to_filter;
@@ -45,6 +47,7 @@ static const struct sfc_flow_ops_by_spec sfc_flow_ops_filter = {
        .cleanup = NULL,
        .insert = sfc_flow_filter_insert,
        .remove = sfc_flow_filter_remove,
+       .query = NULL,
 };
 
 static const struct sfc_flow_ops_by_spec sfc_flow_ops_mae = {
@@ -53,6 +56,7 @@ static const struct sfc_flow_ops_by_spec sfc_flow_ops_mae = {
        .cleanup = sfc_mae_flow_cleanup,
        .insert = sfc_mae_flow_insert,
        .remove = sfc_mae_flow_remove,
+       .query = sfc_mae_flow_query,
 };
 
 static const struct sfc_flow_ops_by_spec *
@@ -1125,6 +1129,7 @@ sfc_flow_parse_pppoex(const struct rte_flow_item *item,
 static const struct sfc_flow_item sfc_flow_items[] = {
        {
                .type = RTE_FLOW_ITEM_TYPE_VOID,
+               .name = "VOID",
                .prev_layer = SFC_FLOW_ITEM_ANY_LAYER,
                .layer = SFC_FLOW_ITEM_ANY_LAYER,
                .ctx_type = SFC_FLOW_PARSE_CTX_FILTER,
@@ -1132,6 +1137,7 @@ static const struct sfc_flow_item sfc_flow_items[] = {
        },
        {
                .type = RTE_FLOW_ITEM_TYPE_ETH,
+               .name = "ETH",
                .prev_layer = SFC_FLOW_ITEM_START_LAYER,
                .layer = SFC_FLOW_ITEM_L2,
                .ctx_type = SFC_FLOW_PARSE_CTX_FILTER,
@@ -1139,6 +1145,7 @@ static const struct sfc_flow_item sfc_flow_items[] = {
        },
        {
                .type = RTE_FLOW_ITEM_TYPE_VLAN,
+               .name = "VLAN",
                .prev_layer = SFC_FLOW_ITEM_L2,
                .layer = SFC_FLOW_ITEM_L2,
                .ctx_type = SFC_FLOW_PARSE_CTX_FILTER,
@@ -1146,6 +1153,7 @@ static const struct sfc_flow_item sfc_flow_items[] = {
        },
        {
                .type = RTE_FLOW_ITEM_TYPE_PPPOED,
+               .name = "PPPOED",
                .prev_layer = SFC_FLOW_ITEM_L2,
                .layer = SFC_FLOW_ITEM_L2,
                .ctx_type = SFC_FLOW_PARSE_CTX_FILTER,
@@ -1153,6 +1161,7 @@ static const struct sfc_flow_item sfc_flow_items[] = {
        },
        {
                .type = RTE_FLOW_ITEM_TYPE_PPPOES,
+               .name = "PPPOES",
                .prev_layer = SFC_FLOW_ITEM_L2,
                .layer = SFC_FLOW_ITEM_L2,
                .ctx_type = SFC_FLOW_PARSE_CTX_FILTER,
@@ -1160,6 +1169,7 @@ static const struct sfc_flow_item sfc_flow_items[] = {
        },
        {
                .type = RTE_FLOW_ITEM_TYPE_IPV4,
+               .name = "IPV4",
                .prev_layer = SFC_FLOW_ITEM_L2,
                .layer = SFC_FLOW_ITEM_L3,
                .ctx_type = SFC_FLOW_PARSE_CTX_FILTER,
@@ -1167,6 +1177,7 @@ static const struct sfc_flow_item sfc_flow_items[] = {
        },
        {
                .type = RTE_FLOW_ITEM_TYPE_IPV6,
+               .name = "IPV6",
                .prev_layer = SFC_FLOW_ITEM_L2,
                .layer = SFC_FLOW_ITEM_L3,
                .ctx_type = SFC_FLOW_PARSE_CTX_FILTER,
@@ -1174,6 +1185,7 @@ static const struct sfc_flow_item sfc_flow_items[] = {
        },
        {
                .type = RTE_FLOW_ITEM_TYPE_TCP,
+               .name = "TCP",
                .prev_layer = SFC_FLOW_ITEM_L3,
                .layer = SFC_FLOW_ITEM_L4,
                .ctx_type = SFC_FLOW_PARSE_CTX_FILTER,
@@ -1181,6 +1193,7 @@ static const struct sfc_flow_item sfc_flow_items[] = {
        },
        {
                .type = RTE_FLOW_ITEM_TYPE_UDP,
+               .name = "UDP",
                .prev_layer = SFC_FLOW_ITEM_L3,
                .layer = SFC_FLOW_ITEM_L4,
                .ctx_type = SFC_FLOW_PARSE_CTX_FILTER,
@@ -1188,6 +1201,7 @@ static const struct sfc_flow_item sfc_flow_items[] = {
        },
        {
                .type = RTE_FLOW_ITEM_TYPE_VXLAN,
+               .name = "VXLAN",
                .prev_layer = SFC_FLOW_ITEM_L4,
                .layer = SFC_FLOW_ITEM_START_LAYER,
                .ctx_type = SFC_FLOW_PARSE_CTX_FILTER,
@@ -1195,6 +1209,7 @@ static const struct sfc_flow_item sfc_flow_items[] = {
        },
        {
                .type = RTE_FLOW_ITEM_TYPE_GENEVE,
+               .name = "GENEVE",
                .prev_layer = SFC_FLOW_ITEM_L4,
                .layer = SFC_FLOW_ITEM_START_LAYER,
                .ctx_type = SFC_FLOW_PARSE_CTX_FILTER,
@@ -1202,6 +1217,7 @@ static const struct sfc_flow_item sfc_flow_items[] = {
        },
        {
                .type = RTE_FLOW_ITEM_TYPE_NVGRE,
+               .name = "NVGRE",
                .prev_layer = SFC_FLOW_ITEM_L3,
                .layer = SFC_FLOW_ITEM_START_LAYER,
                .ctx_type = SFC_FLOW_PARSE_CTX_FILTER,
@@ -1259,7 +1275,7 @@ sfc_flow_parse_attr(struct sfc_adapter *sa,
                spec_filter->template.efs_rss_context = EFX_RSS_CONTEXT_DEFAULT;
                spec_filter->template.efs_priority = EFX_FILTER_PRI_MANUAL;
        } else {
-               if (mae->status != SFC_MAE_STATUS_SUPPORTED) {
+               if (mae->status != SFC_MAE_STATUS_ADMIN) {
                        rte_flow_error_set(error, ENOTSUP,
                                           RTE_FLOW_ERROR_TYPE_ATTR_TRANSFER,
                                           attr, "Transfer is not supported");
@@ -1297,7 +1313,8 @@ sfc_flow_get_item(const struct sfc_flow_item *items,
 }
 
 int
-sfc_flow_parse_pattern(const struct sfc_flow_item *flow_items,
+sfc_flow_parse_pattern(struct sfc_adapter *sa,
+                      const struct sfc_flow_item *flow_items,
                       unsigned int nb_flow_items,
                       const struct rte_flow_item pattern[],
                       struct sfc_flow_parse_ctx *parse_ctx,
@@ -1381,8 +1398,11 @@ sfc_flow_parse_pattern(const struct sfc_flow_item *flow_items,
                }
 
                rc = item->parse(pattern, parse_ctx, error);
-               if (rc != 0)
+               if (rc != 0) {
+                       sfc_err(sa, "failed to parse item %s: %s",
+                               item->name, strerror(-rc));
                        return rc;
+               }
 
                if (item->layer != SFC_FLOW_ITEM_ANY_LAYER)
                        prev_layer = item->layer;
@@ -1721,8 +1741,13 @@ sfc_flow_parse_mark(struct sfc_adapter *sa,
        struct sfc_flow_spec *spec = &flow->spec;
        struct sfc_flow_spec_filter *spec_filter = &spec->filter;
        const efx_nic_cfg_t *encp = efx_nic_cfg_get(sa->nic);
+       uint32_t mark_max;
 
-       if (mark == NULL || mark->id > encp->enc_filter_action_mark_max)
+       mark_max = encp->enc_filter_action_mark_max;
+       if (sfc_flow_tunnel_is_active(sa))
+               mark_max = RTE_MIN(mark_max, SFC_FT_USER_MARK_MASK);
+
+       if (mark == NULL || mark->id > mark_max)
                return EINVAL;
 
        spec_filter->template.efs_flags |= EFX_FILTER_FLAG_ACTION_MARK;
@@ -1741,6 +1766,7 @@ sfc_flow_parse_actions(struct sfc_adapter *sa,
        struct sfc_flow_spec *spec = &flow->spec;
        struct sfc_flow_spec_filter *spec_filter = &spec->filter;
        const unsigned int dp_rx_features = sa->priv.dp_rx->features;
+       const uint64_t rx_metadata = sa->negotiated_rx_metadata;
        uint32_t actions_set = 0;
        const uint32_t fate_actions_mask = (1UL << RTE_FLOW_ACTION_TYPE_QUEUE) |
                                           (1UL << RTE_FLOW_ACTION_TYPE_RSS) |
@@ -1813,6 +1839,12 @@ sfc_flow_parse_actions(struct sfc_adapter *sa,
                                        RTE_FLOW_ERROR_TYPE_ACTION, NULL,
                                        "FLAG action is not supported on the current Rx datapath");
                                return -rte_errno;
+                       } else if ((rx_metadata &
+                                   RTE_ETH_RX_METADATA_USER_FLAG) == 0) {
+                               rte_flow_error_set(error, ENOTSUP,
+                                       RTE_FLOW_ERROR_TYPE_ACTION, NULL,
+                                       "flag delivery has not been negotiated");
+                               return -rte_errno;
                        }
 
                        spec_filter->template.efs_flags |=
@@ -1830,6 +1862,12 @@ sfc_flow_parse_actions(struct sfc_adapter *sa,
                                        RTE_FLOW_ERROR_TYPE_ACTION, NULL,
                                        "MARK action is not supported on the current Rx datapath");
                                return -rte_errno;
+                       } else if ((rx_metadata &
+                                   RTE_ETH_RX_METADATA_USER_MARK) == 0) {
+                               rte_flow_error_set(error, ENOTSUP,
+                                       RTE_FLOW_ERROR_TYPE_ACTION, NULL,
+                                       "mark delivery has not been negotiated");
+                               return -rte_errno;
                        }
 
                        rc = sfc_flow_parse_mark(sa, actions->conf, flow);
@@ -2480,7 +2518,7 @@ sfc_flow_parse_rte_to_filter(struct rte_eth_dev *dev,
        ctx.type = SFC_FLOW_PARSE_CTX_FILTER;
        ctx.filter = &spec_filter->template;
 
-       rc = sfc_flow_parse_pattern(sfc_flow_items, RTE_DIM(sfc_flow_items),
+       rc = sfc_flow_parse_pattern(sa, sfc_flow_items, RTE_DIM(sfc_flow_items),
                                    pattern, &ctx, error);
        if (rc != 0)
                goto fail_bad_value;
@@ -2511,15 +2549,49 @@ sfc_flow_parse_rte_to_mae(struct rte_eth_dev *dev,
        struct sfc_flow_spec_mae *spec_mae = &spec->mae;
        int rc;
 
+       /*
+        * If the flow is meant to be a JUMP rule in tunnel offload,
+        * preparse its actions and save its properties in spec_mae.
+        */
+       rc = sfc_flow_tunnel_detect_jump_rule(sa, actions, spec_mae, error);
+       if (rc != 0)
+               goto fail;
+
        rc = sfc_mae_rule_parse_pattern(sa, pattern, spec_mae, error);
        if (rc != 0)
-               return rc;
+               goto fail;
+
+       if (spec_mae->ft_rule_type == SFC_FT_RULE_JUMP) {
+               /*
+                * By design, this flow should be represented solely by the
+                * outer rule. But the HW/FW hasn't got support for setting
+                * Rx mark from RECIRC_ID on outer rule lookup yet. Neither
+                * does it support outer rule counters. As a workaround, an
+                * action rule of lower priority is used to do the job.
+                *
+                * So don't skip sfc_mae_rule_parse_actions() below.
+                */
+       }
 
        rc = sfc_mae_rule_parse_actions(sa, actions, spec_mae, error);
        if (rc != 0)
-               return rc;
+               goto fail;
+
+       if (spec_mae->ft != NULL) {
+               if (spec_mae->ft_rule_type == SFC_FT_RULE_JUMP)
+                       spec_mae->ft->jump_rule_is_set = B_TRUE;
+
+               ++(spec_mae->ft->refcnt);
+       }
 
        return 0;
+
+fail:
+       /* Reset these values to avoid confusing sfc_mae_flow_cleanup(). */
+       spec_mae->ft_rule_type = SFC_FT_RULE_NONE;
+       spec_mae->ft = NULL;
+
+       return rc;
 }
 
 static int
@@ -2705,7 +2777,7 @@ sfc_flow_create(struct rte_eth_dev *dev,
 
        TAILQ_INSERT_TAIL(&sa->flow_list, flow, entries);
 
-       if (sa->state == SFC_ADAPTER_STARTED) {
+       if (sa->state == SFC_ETHDEV_STARTED) {
                rc = sfc_flow_insert(sa, flow, error);
                if (rc != 0)
                        goto fail_flow_insert;
@@ -2748,7 +2820,7 @@ sfc_flow_destroy(struct rte_eth_dev *dev,
                goto fail_bad_value;
        }
 
-       if (sa->state == SFC_ADAPTER_STARTED)
+       if (sa->state == SFC_ETHDEV_STARTED)
                rc = sfc_flow_remove(sa, flow, error);
 
        TAILQ_REMOVE(&sa->flow_list, flow, entries);
@@ -2771,7 +2843,7 @@ sfc_flow_flush(struct rte_eth_dev *dev,
        sfc_adapter_lock(sa);
 
        while ((flow = TAILQ_FIRST(&sa->flow_list)) != NULL) {
-               if (sa->state == SFC_ADAPTER_STARTED) {
+               if (sa->state == SFC_ETHDEV_STARTED) {
                        int rc;
 
                        rc = sfc_flow_remove(sa, flow, error);
@@ -2788,6 +2860,49 @@ sfc_flow_flush(struct rte_eth_dev *dev,
        return -ret;
 }
 
+static int
+sfc_flow_query(struct rte_eth_dev *dev,
+              struct rte_flow *flow,
+              const struct rte_flow_action *action,
+              void *data,
+              struct rte_flow_error *error)
+{
+       struct sfc_adapter *sa = sfc_adapter_by_eth_dev(dev);
+       const struct sfc_flow_ops_by_spec *ops;
+       int ret;
+
+       sfc_adapter_lock(sa);
+
+       ops = sfc_flow_get_ops_by_spec(flow);
+       if (ops == NULL || ops->query == NULL) {
+               ret = rte_flow_error_set(error, ENOTSUP,
+                       RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+                       "No backend to handle this flow");
+               goto fail_no_backend;
+       }
+
+       if (sa->state != SFC_ETHDEV_STARTED) {
+               ret = rte_flow_error_set(error, EINVAL,
+                       RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+                       "Can't query the flow: the adapter is not started");
+               goto fail_not_started;
+       }
+
+       ret = ops->query(dev, flow, action, data, error);
+       if (ret != 0)
+               goto fail_query;
+
+       sfc_adapter_unlock(sa);
+
+       return 0;
+
+fail_query:
+fail_not_started:
+fail_no_backend:
+       sfc_adapter_unlock(sa);
+       return ret;
+}
+
 static int
 sfc_flow_isolate(struct rte_eth_dev *dev, int enable,
                 struct rte_flow_error *error)
@@ -2796,7 +2911,7 @@ sfc_flow_isolate(struct rte_eth_dev *dev, int enable,
        int ret = 0;
 
        sfc_adapter_lock(sa);
-       if (sa->state != SFC_ADAPTER_INITIALIZED) {
+       if (sa->state != SFC_ETHDEV_INITIALIZED) {
                rte_flow_error_set(error, EBUSY,
                                   RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
                                   NULL, "please close the port first");
@@ -2814,8 +2929,13 @@ const struct rte_flow_ops sfc_flow_ops = {
        .create = sfc_flow_create,
        .destroy = sfc_flow_destroy,
        .flush = sfc_flow_flush,
-       .query = NULL,
+       .query = sfc_flow_query,
        .isolate = sfc_flow_isolate,
+       .tunnel_decap_set = sfc_flow_tunnel_decap_set,
+       .tunnel_match = sfc_flow_tunnel_match,
+       .tunnel_action_decap_release = sfc_flow_tunnel_action_decap_release,
+       .tunnel_item_release = sfc_flow_tunnel_item_release,
+       .get_restore_info = sfc_flow_tunnel_get_restore_info,
 };
 
 void
@@ -2873,6 +2993,8 @@ sfc_flow_start(struct sfc_adapter *sa)
 
        SFC_ASSERT(sfc_adapter_is_locked(sa));
 
+       sfc_flow_tunnel_reset_hit_counters(sa);
+
        TAILQ_FOREACH(flow, &sa->flow_list, entries) {
                rc = sfc_flow_insert(sa, flow, NULL);
                if (rc != 0)