Implement meter enablement through flow rules.

Signed-off-by: Jasvinder Singh <jasvinder.si...@intel.com>
---
 drivers/net/softnic/rte_eth_softnic_flow.c | 170 +++++++++++++++++++++++++++++
 1 file changed, 170 insertions(+)

diff --git a/drivers/net/softnic/rte_eth_softnic_flow.c 
b/drivers/net/softnic/rte_eth_softnic_flow.c
index 6562004..0f33381 100644
--- a/drivers/net/softnic/rte_eth_softnic_flow.c
+++ b/drivers/net/softnic/rte_eth_softnic_flow.c
@@ -1459,6 +1459,117 @@ flow_rule_action_get(struct pmd_internals *softnic,
                        break;
                } /* RTE_FLOW_ACTION_TYPE_COUNT */
 
+               case RTE_FLOW_ACTION_TYPE_METER:
+               {
+                       struct rte_table_action_mtr_tc_params mtr_tc_params;
+                       const struct rte_flow_action_meter *conf = action->conf;
+                       struct softnic_mtr *m;
+                       struct softnic_mtr_meter_profile *mp;
+                       uint32_t meter_profile_id;
+
+                       if (conf == NULL)
+                               return rte_flow_error_set(error,
+                                       EINVAL,
+                                       RTE_FLOW_ERROR_TYPE_ACTION,
+                                       action,
+                                       "COUNT: Null configuration");
+
+                       if ((params->action_mask & (1LLU << 
RTE_TABLE_ACTION_MTR)) == 0)
+                               return rte_flow_error_set(error,
+                                       EINVAL,
+                                       RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
+                                       NULL,
+                                       "METER action not supported by this 
table");
+
+                       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,
+                                       rte_strerror(EINVAL));
+
+                       if (params->mtr.n_tc != 1)
+                               return -rte_flow_error_set(error,
+                                       EINVAL,
+                                       RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
+                                       NULL,
+                                       rte_strerror(EINVAL));
+
+                       meter_profile_id = m->params.meter_profile_id;
+
+                       mp = softnic_table_meter_profile_find(table, 
meter_profile_id);
+                       if (mp == NULL) {
+                               struct softnic_mtr_meter_profile 
*mtr_meter_profile;
+                               struct rte_table_action_meter_profile profile;
+                               int status;
+
+                               mp = calloc(1, sizeof(struct 
softnic_mtr_meter_profile));
+                               if (mp == NULL) {
+                                       rte_flow_error_set(error,
+                                               ENOMEM,
+                                               RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
+                                               NULL,
+                                               "Not enough table memory for 
meter profile");
+                                       return -1;
+                               }
+
+                               mtr_meter_profile = 
softnic_mtr_meter_profile_find(softnic,
+                                       meter_profile_id);
+                               if (mtr_meter_profile == NULL) {
+                                       free(mp);
+
+                                       rte_flow_error_set(error,
+                                               EINVAL,
+                                               RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
+                                               NULL,
+                                               rte_strerror(EINVAL));
+                                       return -1;
+                               }
+
+                               mp->meter_profile_id = meter_profile_id;
+                               mp->n_users = mtr_meter_profile->n_users;
+                               memcpy(&mp->params, &mtr_meter_profile->params,
+                                       sizeof(mp->params));
+
+                               profile.alg = RTE_TABLE_ACTION_METER_TRTCM;
+                               memcpy(&profile.trtcm, 
&mp->params.trtcm_rfc2698,
+                                       sizeof(profile.trtcm));
+
+                               status = 
rte_table_action_meter_profile_add(table->a,
+                                       meter_profile_id,
+                                       &profile);
+                               if (status) {
+                                               free(mp);
+
+                                       rte_flow_error_set(error,
+                                               EINVAL,
+                                               RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
+                                               NULL,
+                                               rte_strerror(EINVAL));
+                                       return -1;
+                               }
+
+                               /* Add to table meter profile list */
+                               TAILQ_INSERT_TAIL(&table->meter_profiles, mp, 
node);
+                       }
+
+                       mtr_tc_params.meter_profile_id = meter_profile_id;
+                       mtr_tc_params.policer[e_RTE_METER_GREEN] =
+                               (enum 
rte_table_action_policer)m->params.action[RTE_MTR_GREEN];
+                       mtr_tc_params.policer[e_RTE_METER_YELLOW] =
+                               (enum 
rte_table_action_policer)m->params.action[RTE_MTR_YELLOW];
+                       mtr_tc_params.policer[e_RTE_METER_RED] =
+                               (enum 
rte_table_action_policer)m->params.action[RTE_MTR_RED];
+
+                       /* RTE_TABLE_ACTION_METER */
+                       memcpy(&rule_action->mtr.mtr[0], &mtr_tc_params,
+                               sizeof(rule_action->mtr.mtr[0]));
+                       rule_action->mtr.tc_mask = 1 << 0;
+                       rule_action->action_mask |= 1 << RTE_TABLE_ACTION_MTR;
+                       break;
+               } /* RTE_FLOW_ACTION_TYPE_METER */
+
                default:
                        return -ENOTSUP;
                }
@@ -1562,6 +1673,35 @@ pmd_flow_validate(struct rte_eth_dev *dev,
        return 0;
 }
 
+static void set_meter_owner_to_flow(struct pmd_internals *softnic,
+       struct rte_flow *flow,
+       const struct rte_flow_action *action)
+{
+       for ( ; action->type != RTE_FLOW_ACTION_TYPE_END; action++) {
+
+               if (action->type == RTE_FLOW_ACTION_TYPE_VOID)
+                       continue;
+
+               if (action->type == RTE_FLOW_ACTION_TYPE_METER) {
+                       const struct rte_flow_action_meter *conf = action->conf;
+                       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;
+                               }
+                       }
+
+                       m = softnic_mtr_find(softnic, conf->mtr_id);
+                       m->flow = flow;
+
+                       break;
+               }
+       }
+}
+
 static struct rte_flow *
 pmd_flow_create(struct rte_eth_dev *dev,
        const struct rte_flow_attr *attr,
@@ -1702,6 +1842,8 @@ pmd_flow_create(struct rte_eth_dev *dev,
        flow->pipeline = pipeline;
        flow->table_id = table_id;
 
+       set_meter_owner_to_flow(softnic, flow, action);
+
        /* Flow add to list. */
        if (new_flow)
                TAILQ_INSERT_TAIL(&table->flows, flow, node);
@@ -1709,6 +1851,31 @@ pmd_flow_create(struct rte_eth_dev *dev,
        return flow;
 }
 
+static void reset_meter_owner(struct pmd_internals *softnic,
+       struct softnic_table *table,
+       struct rte_flow *flow)
+{
+       struct softnic_table_action_profile *profile;
+       struct softnic_table_action_profile_params *params;
+
+       profile = softnic_table_action_profile_find(softnic,
+               table->params.action_profile_name);
+
+       params = &profile->params;
+
+       if ((params->action_mask & (1LLU << RTE_TABLE_ACTION_MTR)) == 0) {
+               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 int
 pmd_flow_destroy(struct rte_eth_dev *dev,
        struct rte_flow *flow,
@@ -1744,6 +1911,9 @@ pmd_flow_destroy(struct rte_eth_dev *dev,
        TAILQ_REMOVE(&table->flows, flow, node);
        free(flow);
 
+       /* Update dependencies */
+       reset_meter_owner(softnic, table, flow);
+
        return 0;
 }
 
-- 
2.9.3

Reply via email to