eal: add function to query device status
[dpdk.git] / drivers / net / softnic / rte_eth_softnic_flow.c
index 90387b3..23ef329 100644 (file)
@@ -11,6 +11,7 @@
 #include <rte_string_fns.h>
 #include <rte_flow.h>
 #include <rte_flow_driver.h>
+#include <rte_tailq.h>
 
 #include "rte_eth_softnic_internals.h"
 #include "rte_eth_softnic.h"
@@ -297,6 +298,106 @@ flow_item_is_proto(enum rte_flow_item_type type,
        }
 }
 
+static int
+flow_item_raw_preprocess(const struct rte_flow_item *item,
+       union flow_item *item_spec,
+       union flow_item *item_mask,
+       size_t *item_size,
+       int *item_disabled,
+       struct rte_flow_error *error)
+{
+       const struct rte_flow_item_raw *item_raw_spec = item->spec;
+       const struct rte_flow_item_raw *item_raw_mask = item->mask;
+       const uint8_t *pattern;
+       const uint8_t *pattern_mask;
+       uint8_t *spec = (uint8_t *)item_spec;
+       uint8_t *mask = (uint8_t *)item_mask;
+       size_t pattern_length, pattern_offset, i;
+       int disabled;
+
+       if (!item->spec)
+               return rte_flow_error_set(error,
+                       ENOTSUP,
+                       RTE_FLOW_ERROR_TYPE_ITEM,
+                       item,
+                       "RAW: Null specification");
+
+       if (item->last)
+               return rte_flow_error_set(error,
+                       ENOTSUP,
+                       RTE_FLOW_ERROR_TYPE_ITEM,
+                       item,
+                       "RAW: Range not allowed (last must be NULL)");
+
+       if (item_raw_spec->relative == 0)
+               return rte_flow_error_set(error,
+                       ENOTSUP,
+                       RTE_FLOW_ERROR_TYPE_ITEM,
+                       item,
+                       "RAW: Absolute offset not supported");
+
+       if (item_raw_spec->search)
+               return rte_flow_error_set(error,
+                       ENOTSUP,
+                       RTE_FLOW_ERROR_TYPE_ITEM,
+                       item,
+                       "RAW: Search not supported");
+
+       if (item_raw_spec->offset < 0)
+               return rte_flow_error_set(error,
+                       ENOTSUP, RTE_FLOW_ERROR_TYPE_ITEM,
+                       item,
+                       "RAW: Negative offset not supported");
+
+       if (item_raw_spec->length == 0)
+               return rte_flow_error_set(error,
+                       ENOTSUP,
+                       RTE_FLOW_ERROR_TYPE_ITEM,
+                       item,
+                       "RAW: Zero pattern length");
+
+       if (item_raw_spec->offset + item_raw_spec->length >
+               TABLE_RULE_MATCH_SIZE_MAX)
+               return rte_flow_error_set(error,
+                       ENOTSUP,
+                       RTE_FLOW_ERROR_TYPE_ITEM,
+                       item,
+                       "RAW: Item too big");
+
+       if (!item_raw_spec->pattern && item_raw_mask && item_raw_mask->pattern)
+               return rte_flow_error_set(error,
+                       ENOTSUP,
+                       RTE_FLOW_ERROR_TYPE_ITEM,
+                       item,
+                       "RAW: Non-NULL pattern mask not allowed with NULL pattern");
+
+       pattern = item_raw_spec->pattern;
+       pattern_mask = (item_raw_mask) ? item_raw_mask->pattern : NULL;
+       pattern_length = (size_t)item_raw_spec->length;
+       pattern_offset = (size_t)item_raw_spec->offset;
+
+       disabled = 0;
+       if (pattern_mask == NULL)
+               disabled = 1;
+       else
+               for (i = 0; i < pattern_length; i++)
+                       if ((pattern)[i])
+                               disabled = 1;
+
+       memset(spec, 0, TABLE_RULE_MATCH_SIZE_MAX);
+       if (pattern)
+               memcpy(&spec[pattern_offset], pattern, pattern_length);
+
+       memset(mask, 0, TABLE_RULE_MATCH_SIZE_MAX);
+       if (pattern_mask)
+               memcpy(&mask[pattern_offset], pattern_mask, pattern_length);
+
+       *item_size = pattern_offset + pattern_length;
+       *item_disabled = disabled;
+
+       return 0;
+}
+
 static int
 flow_item_proto_preprocess(const struct rte_flow_item *item,
        union flow_item *item_spec,
@@ -317,6 +418,14 @@ flow_item_proto_preprocess(const struct rte_flow_item *item,
                        item,
                        "Item type not supported");
 
+       if (item->type == RTE_FLOW_ITEM_TYPE_RAW)
+               return flow_item_raw_preprocess(item,
+                       item_spec,
+                       item_mask,
+                       item_size,
+                       item_disabled,
+                       error);
+
        /* spec */
        if (!item->spec) {
                /* If spec is NULL, then last and mask also have to be NULL. */
@@ -1053,12 +1162,14 @@ flow_rule_action_get(struct pmd_internals *softnic,
        const struct rte_flow_attr *attr,
        const struct rte_flow_action *action,
        struct softnic_table_rule_action *rule_action,
-       struct rte_flow_error *error __rte_unused)
+       struct rte_flow_error *error)
 {
        struct softnic_table_action_profile *profile;
        struct softnic_table_action_profile_params *params;
        int n_jump_queue_rss_drop = 0;
        int n_count = 0;
+       int n_mark = 0;
+       int n_vxlan_decap = 0;
 
        profile = softnic_table_action_profile_find(softnic,
                table->params.action_profile_name);
@@ -1366,6 +1477,163 @@ flow_rule_action_get(struct pmd_internals *softnic,
                        break;
                } /* RTE_FLOW_ACTION_TYPE_COUNT */
 
+               case RTE_FLOW_ACTION_TYPE_MARK:
+               {
+                       const struct rte_flow_action_mark *conf = action->conf;
+
+                       if (conf == NULL)
+                               return rte_flow_error_set(error,
+                                       EINVAL,
+                                       RTE_FLOW_ERROR_TYPE_ACTION,
+                                       action,
+                                       "MARK: Null configuration");
+
+                       if (n_mark)
+                               return rte_flow_error_set(error,
+                                       ENOTSUP,
+                                       RTE_FLOW_ERROR_TYPE_ACTION,
+                                       action,
+                                       "Only one MARK action per flow");
+
+                       if ((params->action_mask &
+                               (1LLU << RTE_TABLE_ACTION_TAG)) == 0)
+                               return rte_flow_error_set(error,
+                                       ENOTSUP,
+                                       RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
+                                       NULL,
+                                       "MARK action not supported by this table");
+
+                       n_mark = 1;
+
+                       /* RTE_TABLE_ACTION_TAG */
+                       rule_action->tag.tag = conf->id;
+                       rule_action->action_mask |= 1 << RTE_TABLE_ACTION_TAG;
+                       break;
+               } /* RTE_FLOW_ACTION_TYPE_MARK */
+
+               case RTE_FLOW_ACTION_TYPE_VXLAN_DECAP:
+               {
+                       const struct rte_flow_action_mark *conf = action->conf;
+
+                       if (conf)
+                               return rte_flow_error_set(error,
+                                       EINVAL,
+                                       RTE_FLOW_ERROR_TYPE_ACTION,
+                                       action,
+                                       "VXLAN DECAP: Non-null configuration");
+
+                       if (n_vxlan_decap)
+                               return rte_flow_error_set(error,
+                                       ENOTSUP,
+                                       RTE_FLOW_ERROR_TYPE_ACTION,
+                                       action,
+                                       "Only one VXLAN DECAP action per flow");
+
+                       if ((params->action_mask &
+                               (1LLU << RTE_TABLE_ACTION_DECAP)) == 0)
+                               return rte_flow_error_set(error,
+                                       ENOTSUP,
+                                       RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
+                                       NULL,
+                                       "VXLAN DECAP action not supported by this table");
+
+                       n_vxlan_decap = 1;
+
+                       /* RTE_TABLE_ACTION_DECAP */
+                       rule_action->decap.n = 50; /* Ether/IPv4/UDP/VXLAN */
+                       rule_action->action_mask |= 1 << RTE_TABLE_ACTION_DECAP;
+                       break;
+               } /* RTE_FLOW_ACTION_TYPE_VXLAN_DECAP */
+
+               case RTE_FLOW_ACTION_TYPE_METER:
+               {
+                       const struct rte_flow_action_meter *conf = action->conf;
+                       struct softnic_mtr_meter_profile *mp;
+                       struct softnic_mtr *m;
+                       uint32_t table_id = table - pipeline->table;
+                       uint32_t meter_profile_id;
+                       int status;
+
+                       if ((params->action_mask & (1LLU << RTE_TABLE_ACTION_MTR)) == 0)
+                               return rte_flow_error_set(error,
+                                       EINVAL,
+                                       RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
+                                       NULL,
+                                       "METER: Table action not supported");
+
+                       if (params->mtr.n_tc != 1)
+                               return rte_flow_error_set(error,
+                                       EINVAL,
+                                       RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
+                                       NULL,
+                                       "METER: Multiple TCs not supported");
+
+                       if (conf == NULL)
+                               return rte_flow_error_set(error,
+                                       EINVAL,
+                                       RTE_FLOW_ERROR_TYPE_ACTION,
+                                       action,
+                                       "METER: Null configuration");
+
+                       m = softnic_mtr_find(softnic, conf->mtr_id);
+
+                       if (m == NULL)
+                               return rte_flow_error_set(error,
+                                       EINVAL,
+                                       RTE_FLOW_ERROR_TYPE_ACTION_CONF,
+                                       NULL,
+                                       "METER: Invalid meter ID");
+
+                       if (m->flow)
+                               return rte_flow_error_set(error,
+                                       EINVAL,
+                                       RTE_FLOW_ERROR_TYPE_ACTION_CONF,
+                                       NULL,
+                                       "METER: Meter already attached to a flow");
+
+                       meter_profile_id = m->params.meter_profile_id;
+                       mp = softnic_mtr_meter_profile_find(softnic, meter_profile_id);
+
+                       /* Add meter profile to pipeline table */
+                       if (!softnic_pipeline_table_meter_profile_find(table,
+                                       meter_profile_id)) {
+                               struct rte_table_action_meter_profile profile;
+
+                               memset(&profile, 0, sizeof(profile));
+                               profile.alg = RTE_TABLE_ACTION_METER_TRTCM;
+                               profile.trtcm.cir = mp->params.trtcm_rfc2698.cir;
+                               profile.trtcm.pir = mp->params.trtcm_rfc2698.pir;
+                               profile.trtcm.cbs = mp->params.trtcm_rfc2698.cbs;
+                               profile.trtcm.pbs = mp->params.trtcm_rfc2698.pbs;
+
+                               status = softnic_pipeline_table_mtr_profile_add(softnic,
+                                               pipeline->name,
+                                               table_id,
+                                               meter_profile_id,
+                                               &profile);
+                               if (status) {
+                                       rte_flow_error_set(error,
+                                               EINVAL,
+                                               RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
+                                               NULL,
+                                               "METER: Table meter profile add failed");
+                                       return -1;
+                               }
+                       }
+
+                       /* RTE_TABLE_ACTION_METER */
+                       rule_action->mtr.mtr[0].meter_profile_id = meter_profile_id;
+                       rule_action->mtr.mtr[0].policer[e_RTE_METER_GREEN] =
+                               (enum rte_table_action_policer)m->params.action[RTE_MTR_GREEN];
+                       rule_action->mtr.mtr[0].policer[e_RTE_METER_YELLOW] =
+                               (enum rte_table_action_policer)m->params.action[RTE_MTR_YELLOW];
+                       rule_action->mtr.mtr[0].policer[e_RTE_METER_RED] =
+                               (enum rte_table_action_policer)m->params.action[RTE_MTR_RED];
+                       rule_action->mtr.tc_mask = 1;
+                       rule_action->action_mask |= 1 << RTE_TABLE_ACTION_MTR;
+                       break;
+               } /* RTE_FLOW_ACTION_TYPE_METER */
+
                default:
                        return -ENOTSUP;
                }
@@ -1469,6 +1737,61 @@ pmd_flow_validate(struct rte_eth_dev *dev,
        return 0;
 }
 
+static struct softnic_mtr *
+flow_action_meter_get(struct pmd_internals *softnic,
+       const struct rte_flow_action *action)
+{
+       for ( ; action->type != RTE_FLOW_ACTION_TYPE_END; action++)
+               if (action->type == RTE_FLOW_ACTION_TYPE_METER) {
+                       const struct rte_flow_action_meter *conf = action->conf;
+
+                       if (conf == NULL)
+                               return NULL;
+
+                       return softnic_mtr_find(softnic, conf->mtr_id);
+               }
+
+       return NULL;
+}
+
+static void
+flow_meter_owner_reset(struct pmd_internals *softnic,
+       struct rte_flow *flow)
+{
+       struct softnic_mtr_list *ml = &softnic->mtr.mtrs;
+       struct softnic_mtr *m;
+
+       TAILQ_FOREACH(m, ml, node)
+               if (m->flow == flow) {
+                       m->flow = NULL;
+                       break;
+               }
+}
+
+static void
+flow_meter_owner_set(struct pmd_internals *softnic,
+       struct rte_flow *flow,
+       struct softnic_mtr *mtr)
+{
+       /* Reset current flow meter  */
+       flow_meter_owner_reset(softnic, flow);
+
+       /* Set new flow meter */
+       mtr->flow = flow;
+}
+
+static int
+is_meter_action_enable(struct pmd_internals *softnic,
+       struct softnic_table *table)
+{
+       struct softnic_table_action_profile *profile =
+               softnic_table_action_profile_find(softnic,
+                       table->params.action_profile_name);
+       struct softnic_table_action_profile_params *params = &profile->params;
+
+       return (params->action_mask & (1LLU << RTE_TABLE_ACTION_MTR)) ? 1 : 0;
+}
+
 static struct rte_flow *
 pmd_flow_create(struct rte_eth_dev *dev,
        const struct rte_flow_attr *attr,
@@ -1484,6 +1807,7 @@ pmd_flow_create(struct rte_eth_dev *dev,
        struct pipeline *pipeline;
        struct softnic_table *table;
        struct rte_flow *flow;
+       struct softnic_mtr *mtr;
        const char *pipeline_name = NULL;
        uint32_t table_id = 0;
        int new_flow, status;
@@ -1609,6 +1933,10 @@ pmd_flow_create(struct rte_eth_dev *dev,
        flow->pipeline = pipeline;
        flow->table_id = table_id;
 
+       mtr = flow_action_meter_get(softnic, action);
+       if (mtr)
+               flow_meter_owner_set(softnic, flow, mtr);
+
        /* Flow add to list. */
        if (new_flow)
                TAILQ_INSERT_TAIL(&table->flows, flow, node);
@@ -1647,6 +1975,10 @@ pmd_flow_destroy(struct rte_eth_dev *dev,
                        NULL,
                        "Pipeline table rule delete failed");
 
+       /* Update dependencies */
+       if (is_meter_action_enable(softnic, table))
+               flow_meter_owner_reset(softnic, flow);
+
        /* Flow delete. */
        TAILQ_REMOVE(&table->flows, flow, node);
        free(flow);
@@ -1654,8 +1986,110 @@ pmd_flow_destroy(struct rte_eth_dev *dev,
        return 0;
 }
 
+static int
+pmd_flow_flush(struct rte_eth_dev *dev,
+       struct rte_flow_error *error)
+{
+       struct pmd_internals *softnic = dev->data->dev_private;
+       struct pipeline *pipeline;
+       int fail_to_del_rule = 0;
+       uint32_t i;
+
+       TAILQ_FOREACH(pipeline, &softnic->pipeline_list, node) {
+               /* Remove all the flows added to the tables. */
+               for (i = 0; i < pipeline->n_tables; i++) {
+                       struct softnic_table *table = &pipeline->table[i];
+                       struct rte_flow *flow;
+                       void *temp;
+                       int status;
+
+                       TAILQ_FOREACH_SAFE(flow, &table->flows, node, temp) {
+                               /* Rule delete. */
+                               status = softnic_pipeline_table_rule_delete
+                                               (softnic,
+                                               pipeline->name,
+                                               i,
+                                               &flow->match);
+                               if (status)
+                                       fail_to_del_rule = 1;
+                               /* Update dependencies */
+                               if (is_meter_action_enable(softnic, table))
+                                       flow_meter_owner_reset(softnic, flow);
+
+                               /* Flow delete. */
+                               TAILQ_REMOVE(&table->flows, flow, node);
+                               free(flow);
+                       }
+               }
+       }
+
+       if (fail_to_del_rule)
+               return rte_flow_error_set(error,
+                       EINVAL,
+                       RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
+                       NULL,
+                       "Some of the rules could not be deleted");
+
+       return 0;
+}
+
+static int
+pmd_flow_query(struct rte_eth_dev *dev __rte_unused,
+       struct rte_flow *flow,
+       const struct rte_flow_action *action __rte_unused,
+       void *data,
+       struct rte_flow_error *error)
+{
+       struct rte_table_action_stats_counters stats;
+       struct softnic_table *table;
+       struct rte_flow_query_count *flow_stats = data;
+       int status;
+
+       /* Check input parameters. */
+       if (flow == NULL)
+               return rte_flow_error_set(error,
+                       EINVAL,
+                       RTE_FLOW_ERROR_TYPE_HANDLE,
+                       NULL,
+                       "Null flow");
+
+       if (data == NULL)
+               return rte_flow_error_set(error,
+                       EINVAL,
+                       RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
+                       NULL,
+                       "Null data");
+
+       table = &flow->pipeline->table[flow->table_id];
+
+       /* Rule stats read. */
+       status = rte_table_action_stats_read(table->a,
+               flow->data,
+               &stats,
+               flow_stats->reset);
+       if (status)
+               return rte_flow_error_set(error,
+                       EINVAL,
+                       RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
+                       NULL,
+                       "Pipeline table rule stats read failed");
+
+       /* Fill in flow stats. */
+       flow_stats->hits_set =
+               (table->ap->params.stats.n_packets_enabled) ? 1 : 0;
+       flow_stats->bytes_set =
+               (table->ap->params.stats.n_bytes_enabled) ? 1 : 0;
+       flow_stats->hits = stats.n_packets;
+       flow_stats->bytes = stats.n_bytes;
+
+       return 0;
+}
+
 const struct rte_flow_ops pmd_flow_ops = {
        .validate = pmd_flow_validate,
        .create = pmd_flow_create,
        .destroy = pmd_flow_destroy,
+       .flush = pmd_flow_flush,
+       .query = pmd_flow_query,
+       .isolate = NULL,
 };