examples/ipsec-secgw: replace strncpy with strlcpy
[dpdk.git] / drivers / net / sfc / sfc_flow.c
index 9c09cdb..e6b2ecf 100644 (file)
@@ -23,6 +23,7 @@
 #include "sfc_filter.h"
 #include "sfc_flow.h"
 #include "sfc_log.h"
+#include "sfc_dp_rx.h"
 
 /*
  * At now flow API is implemented in such a manner that each
@@ -120,7 +121,6 @@ sfc_flow_parse_init(const struct rte_flow_item *item,
        const uint8_t *spec;
        const uint8_t *mask;
        const uint8_t *last;
-       uint8_t match;
        uint8_t supp;
        unsigned int i;
 
@@ -181,12 +181,11 @@ sfc_flow_parse_init(const struct rte_flow_item *item,
                return -rte_errno;
        }
 
-       /* Check that mask and spec not asks for more match than supp_mask */
+       /* Check that mask does not ask for more match than supp_mask */
        for (i = 0; i < size; i++) {
-               match = spec[i] | mask[i];
                supp = ((const uint8_t *)supp_mask)[i];
 
-               if ((match | supp) != supp) {
+               if (~supp & mask[i]) {
                        rte_flow_error_set(error, ENOTSUP,
                                           RTE_FLOW_ERROR_TYPE_ITEM, item,
                                           "Item's field is not supported");
@@ -1250,18 +1249,20 @@ sfc_flow_parse_queue(struct sfc_adapter *sa,
 
 static int
 sfc_flow_parse_rss(struct sfc_adapter *sa,
-                  const struct rte_flow_action_rss *rss,
+                  const struct rte_flow_action_rss *action_rss,
                   struct rte_flow *flow)
 {
+       struct sfc_rss *rss = &sa->rss;
        unsigned int rxq_sw_index;
        struct sfc_rxq *rxq;
        unsigned int rxq_hw_index_min;
        unsigned int rxq_hw_index_max;
+       efx_rx_hash_type_t efx_hash_types;
        const uint8_t *rss_key;
        struct sfc_flow_rss *sfc_rss_conf = &flow->rss_conf;
        unsigned int i;
 
-       if (rss->queue_num == 0)
+       if (action_rss->queue_num == 0)
                return -EINVAL;
 
        rxq_sw_index = sa->rxq_count - 1;
@@ -1269,8 +1270,8 @@ sfc_flow_parse_rss(struct sfc_adapter *sa,
        rxq_hw_index_min = rxq->hw_index;
        rxq_hw_index_max = 0;
 
-       for (i = 0; i < rss->queue_num; ++i) {
-               rxq_sw_index = rss->queue[i];
+       for (i = 0; i < action_rss->queue_num; ++i) {
+               rxq_sw_index = action_rss->queue[i];
 
                if (rxq_sw_index >= sa->rxq_count)
                        return -EINVAL;
@@ -1284,7 +1285,7 @@ sfc_flow_parse_rss(struct sfc_adapter *sa,
                        rxq_hw_index_max = rxq->hw_index;
        }
 
-       switch (rss->func) {
+       switch (action_rss->func) {
        case RTE_ETH_HASH_FUNCTION_DEFAULT:
        case RTE_ETH_HASH_FUNCTION_TOEPLITZ:
                break;
@@ -1292,30 +1293,54 @@ sfc_flow_parse_rss(struct sfc_adapter *sa,
                return -EINVAL;
        }
 
-       if (rss->level)
+       if (action_rss->level)
                return -EINVAL;
 
-       if ((rss->types & ~SFC_RSS_OFFLOADS) != 0)
-               return -EINVAL;
+       /*
+        * Dummy RSS action with only one queue and no specific settings
+        * for hash types and key does not require dedicated RSS context
+        * and may be simplified to single queue action.
+        */
+       if (action_rss->queue_num == 1 && action_rss->types == 0 &&
+           action_rss->key_len == 0) {
+               flow->spec.template.efs_dmaq_id = rxq_hw_index_min;
+               return 0;
+       }
+
+       if (action_rss->types) {
+               int rc;
 
-       if (rss->key_len) {
-               if (rss->key_len != sizeof(sa->rss_key))
+               rc = sfc_rx_hf_rte_to_efx(sa, action_rss->types,
+                                         &efx_hash_types);
+               if (rc != 0)
+                       return -rc;
+       } else {
+               unsigned int i;
+
+               efx_hash_types = 0;
+               for (i = 0; i < rss->hf_map_nb_entries; ++i)
+                       efx_hash_types |= rss->hf_map[i].efx;
+       }
+
+       if (action_rss->key_len) {
+               if (action_rss->key_len != sizeof(rss->key))
                        return -EINVAL;
 
-               rss_key = rss->key;
+               rss_key = action_rss->key;
        } else {
-               rss_key = sa->rss_key;
+               rss_key = rss->key;
        }
 
        flow->rss = B_TRUE;
 
        sfc_rss_conf->rxq_hw_index_min = rxq_hw_index_min;
        sfc_rss_conf->rxq_hw_index_max = rxq_hw_index_max;
-       sfc_rss_conf->rss_hash_types = sfc_rte_to_efx_hash_type(rss->types);
-       rte_memcpy(sfc_rss_conf->rss_key, rss_key, sizeof(sa->rss_key));
+       sfc_rss_conf->rss_hash_types = efx_hash_types;
+       rte_memcpy(sfc_rss_conf->rss_key, rss_key, sizeof(rss->key));
 
        for (i = 0; i < RTE_DIM(sfc_rss_conf->rss_tbl); ++i) {
-               unsigned int rxq_sw_index = rss->queue[i % rss->queue_num];
+               unsigned int nb_queues = action_rss->queue_num;
+               unsigned int rxq_sw_index = action_rss->queue[i % nb_queues];
                struct sfc_rxq *rxq = sa->rxq_info[rxq_sw_index].rxq;
 
                sfc_rss_conf->rss_tbl[i] = rxq->hw_index - rxq_hw_index_min;
@@ -1372,14 +1397,15 @@ static int
 sfc_flow_filter_insert(struct sfc_adapter *sa,
                       struct rte_flow *flow)
 {
-       struct sfc_flow_rss *rss = &flow->rss_conf;
+       struct sfc_rss *rss = &sa->rss;
+       struct sfc_flow_rss *flow_rss = &flow->rss_conf;
        uint32_t efs_rss_context = EFX_RSS_CONTEXT_DEFAULT;
        unsigned int i;
        int rc = 0;
 
        if (flow->rss) {
-               unsigned int rss_spread = MIN(rss->rxq_hw_index_max -
-                                             rss->rxq_hw_index_min + 1,
+               unsigned int rss_spread = MIN(flow_rss->rxq_hw_index_max -
+                                             flow_rss->rxq_hw_index_min + 1,
                                              EFX_MAXRSS);
 
                rc = efx_rx_scale_context_alloc(sa->nic,
@@ -1390,14 +1416,14 @@ sfc_flow_filter_insert(struct sfc_adapter *sa,
                        goto fail_scale_context_alloc;
 
                rc = efx_rx_scale_mode_set(sa->nic, efs_rss_context,
-                                          EFX_RX_HASHALG_TOEPLITZ,
-                                          rss->rss_hash_types, B_TRUE);
+                                          rss->hash_alg,
+                                          flow_rss->rss_hash_types, B_TRUE);
                if (rc != 0)
                        goto fail_scale_mode_set;
 
                rc = efx_rx_scale_key_set(sa->nic, efs_rss_context,
-                                         rss->rss_key,
-                                         sizeof(sa->rss_key));
+                                         flow_rss->rss_key,
+                                         sizeof(rss->key));
                if (rc != 0)
                        goto fail_scale_key_set;
 
@@ -1411,7 +1437,7 @@ sfc_flow_filter_insert(struct sfc_adapter *sa,
                        efx_filter_spec_t *spec = &flow->spec.filters[i];
 
                        spec->efs_rss_context = efs_rss_context;
-                       spec->efs_dmaq_id = rss->rxq_hw_index_min;
+                       spec->efs_dmaq_id = flow_rss->rxq_hw_index_min;
                        spec->efs_flags |= EFX_FILTER_FLAG_RX_RSS;
                }
        }
@@ -1430,7 +1456,8 @@ sfc_flow_filter_insert(struct sfc_adapter *sa,
                 * the table entries, and the operation will succeed
                 */
                rc = efx_rx_scale_tbl_set(sa->nic, efs_rss_context,
-                                         rss->rss_tbl, RTE_DIM(rss->rss_tbl));
+                                         flow_rss->rss_tbl,
+                                         RTE_DIM(flow_rss->rss_tbl));
                if (rc != 0)
                        goto fail_scale_tbl_set;
        }
@@ -1474,6 +1501,22 @@ sfc_flow_filter_remove(struct sfc_adapter *sa,
        return rc;
 }
 
+static int
+sfc_flow_parse_mark(struct sfc_adapter *sa,
+                   const struct rte_flow_action_mark *mark,
+                   struct rte_flow *flow)
+{
+       const efx_nic_cfg_t *encp = efx_nic_cfg_get(sa->nic);
+
+       if (mark == NULL || mark->id > encp->enc_filter_action_mark_max)
+               return EINVAL;
+
+       flow->spec.template.efs_flags |= EFX_FILTER_FLAG_ACTION_MARK;
+       flow->spec.template.efs_mark = mark->id;
+
+       return 0;
+}
+
 static int
 sfc_flow_parse_actions(struct sfc_adapter *sa,
                       const struct rte_flow_action actions[],
@@ -1481,7 +1524,13 @@ sfc_flow_parse_actions(struct sfc_adapter *sa,
                       struct rte_flow_error *error)
 {
        int rc;
-       boolean_t is_specified = B_FALSE;
+       const unsigned int dp_rx_features = sa->dp_rx->features;
+       uint32_t actions_set = 0;
+       const uint32_t fate_actions_mask = (1UL << RTE_FLOW_ACTION_TYPE_QUEUE) |
+                                          (1UL << RTE_FLOW_ACTION_TYPE_RSS) |
+                                          (1UL << RTE_FLOW_ACTION_TYPE_DROP);
+       const uint32_t mark_actions_mask = (1UL << RTE_FLOW_ACTION_TYPE_MARK) |
+                                          (1UL << RTE_FLOW_ACTION_TYPE_FLAG);
 
        if (actions == NULL) {
                rte_flow_error_set(error, EINVAL,
@@ -1490,21 +1539,22 @@ sfc_flow_parse_actions(struct sfc_adapter *sa,
                return -rte_errno;
        }
 
+#define SFC_BUILD_SET_OVERFLOW(_action, _set) \
+       RTE_BUILD_BUG_ON(_action >= sizeof(_set) * CHAR_BIT)
+
        for (; actions->type != RTE_FLOW_ACTION_TYPE_END; actions++) {
-               /* This one may appear anywhere multiple times. */
-               if (actions->type == RTE_FLOW_ACTION_TYPE_VOID)
-                       continue;
-               /* Fate-deciding actions may appear exactly once. */
-               if (is_specified) {
-                       rte_flow_error_set
-                               (error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ACTION,
-                                actions,
-                                "Cannot combine several fate-deciding actions,"
-                                "choose between QUEUE, RSS or DROP");
-                       return -rte_errno;
-               }
                switch (actions->type) {
+               case RTE_FLOW_ACTION_TYPE_VOID:
+                       SFC_BUILD_SET_OVERFLOW(RTE_FLOW_ACTION_TYPE_VOID,
+                                              actions_set);
+                       break;
+
                case RTE_FLOW_ACTION_TYPE_QUEUE:
+                       SFC_BUILD_SET_OVERFLOW(RTE_FLOW_ACTION_TYPE_QUEUE,
+                                              actions_set);
+                       if ((actions_set & fate_actions_mask) != 0)
+                               goto fail_fate_actions;
+
                        rc = sfc_flow_parse_queue(sa, actions->conf, flow);
                        if (rc != 0) {
                                rte_flow_error_set(error, EINVAL,
@@ -1512,11 +1562,14 @@ sfc_flow_parse_actions(struct sfc_adapter *sa,
                                        "Bad QUEUE action");
                                return -rte_errno;
                        }
-
-                       is_specified = B_TRUE;
                        break;
 
                case RTE_FLOW_ACTION_TYPE_RSS:
+                       SFC_BUILD_SET_OVERFLOW(RTE_FLOW_ACTION_TYPE_RSS,
+                                              actions_set);
+                       if ((actions_set & fate_actions_mask) != 0)
+                               goto fail_fate_actions;
+
                        rc = sfc_flow_parse_rss(sa, actions->conf, flow);
                        if (rc != 0) {
                                rte_flow_error_set(error, rc,
@@ -1524,15 +1577,55 @@ sfc_flow_parse_actions(struct sfc_adapter *sa,
                                        "Bad RSS action");
                                return -rte_errno;
                        }
-
-                       is_specified = B_TRUE;
                        break;
 
                case RTE_FLOW_ACTION_TYPE_DROP:
+                       SFC_BUILD_SET_OVERFLOW(RTE_FLOW_ACTION_TYPE_DROP,
+                                              actions_set);
+                       if ((actions_set & fate_actions_mask) != 0)
+                               goto fail_fate_actions;
+
                        flow->spec.template.efs_dmaq_id =
                                EFX_FILTER_SPEC_RX_DMAQ_ID_DROP;
+                       break;
+
+               case RTE_FLOW_ACTION_TYPE_FLAG:
+                       SFC_BUILD_SET_OVERFLOW(RTE_FLOW_ACTION_TYPE_FLAG,
+                                              actions_set);
+                       if ((actions_set & mark_actions_mask) != 0)
+                               goto fail_actions_overlap;
+
+                       if ((dp_rx_features & SFC_DP_RX_FEAT_FLOW_FLAG) == 0) {
+                               rte_flow_error_set(error, ENOTSUP,
+                                       RTE_FLOW_ERROR_TYPE_ACTION, NULL,
+                                       "FLAG action is not supported on the current Rx datapath");
+                               return -rte_errno;
+                       }
+
+                       flow->spec.template.efs_flags |=
+                               EFX_FILTER_FLAG_ACTION_FLAG;
+                       break;
+
+               case RTE_FLOW_ACTION_TYPE_MARK:
+                       SFC_BUILD_SET_OVERFLOW(RTE_FLOW_ACTION_TYPE_MARK,
+                                              actions_set);
+                       if ((actions_set & mark_actions_mask) != 0)
+                               goto fail_actions_overlap;
 
-                       is_specified = B_TRUE;
+                       if ((dp_rx_features & SFC_DP_RX_FEAT_FLOW_MARK) == 0) {
+                               rte_flow_error_set(error, ENOTSUP,
+                                       RTE_FLOW_ERROR_TYPE_ACTION, NULL,
+                                       "MARK action is not supported on the current Rx datapath");
+                               return -rte_errno;
+                       }
+
+                       rc = sfc_flow_parse_mark(sa, actions->conf, flow);
+                       if (rc != 0) {
+                               rte_flow_error_set(error, rc,
+                                       RTE_FLOW_ERROR_TYPE_ACTION, actions,
+                                       "Bad MARK action");
+                               return -rte_errno;
+                       }
                        break;
 
                default:
@@ -1541,15 +1634,29 @@ sfc_flow_parse_actions(struct sfc_adapter *sa,
                                           "Action is not supported");
                        return -rte_errno;
                }
+
+               actions_set |= (1UL << actions->type);
        }
+#undef SFC_BUILD_SET_OVERFLOW
 
        /* When fate is unknown, drop traffic. */
-       if (!is_specified) {
+       if ((actions_set & fate_actions_mask) == 0) {
                flow->spec.template.efs_dmaq_id =
                        EFX_FILTER_SPEC_RX_DMAQ_ID_DROP;
        }
 
        return 0;
+
+fail_fate_actions:
+       rte_flow_error_set(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ACTION, actions,
+                          "Cannot combine several fate-deciding actions, "
+                          "choose between QUEUE, RSS or DROP");
+       return -rte_errno;
+
+fail_actions_overlap:
+       rte_flow_error_set(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ACTION, actions,
+                          "Overlapping actions are not supported");
+       return -rte_errno;
 }
 
 /**