@@ -455,6 +455,7 @@ struct softnic_table {
struct softnic_table_action_profile *ap;
struct rte_table_action *a;
struct flow_list flows;
+ struct softnic_mtr_meter_profile_list meter_profiles;
};
struct pipeline {
@@ -620,6 +621,10 @@ struct softnic_mtr_meter_profile *
softnic_mtr_meter_profile_find(struct pmd_internals *p,
uint32_t meter_profile_id);
+struct softnic_mtr_meter_profile *
+softnic_table_meter_profile_find(struct softnic_table *table,
+ uint32_t meter_profile_id);
+
extern const struct rte_mtr_ops pmd_mtr_ops;
/**
@@ -316,6 +316,143 @@ pmd_mtr_destroy(struct rte_eth_dev *dev,
return 0;
}
+struct softnic_mtr_meter_profile *
+softnic_table_meter_profile_find(struct softnic_table *table,
+ uint32_t meter_profile_id)
+{
+ struct softnic_mtr_meter_profile *mp;
+
+ TAILQ_FOREACH(mp, &table->meter_profiles, node)
+ if (mp->meter_profile_id == meter_profile_id)
+ return mp;
+
+ return NULL;
+}
+
+static int
+softnic_table_meter_profile_update(struct pmd_internals *p,
+ struct softnic_mtr *mtr,
+ uint32_t meter_profile_id,
+ struct rte_mtr_meter_profile *params,
+ struct rte_mtr_error *error)
+{
+ struct rte_flow *mflow = mtr->flow;
+ struct softnic_table *table = &mflow->pipeline->table[mflow->table_id];
+ struct softnic_mtr_meter_profile *mp;
+ int status, mp_mem_alloc = 0;
+
+ /* Find/allocate meter profile for table */
+ if (!softnic_table_meter_profile_find(table, meter_profile_id)) {
+ mp = calloc(1, sizeof(struct softnic_mtr_meter_profile));
+ if (mp == NULL) {
+ rte_mtr_error_set(error,
+ ENOMEM,
+ RTE_MTR_ERROR_TYPE_UNSPECIFIED,
+ NULL,
+ "Not enough table memory for meter profile");
+ return -1;
+ }
+ mp_mem_alloc = 1;
+
+ /* Fill in */
+ mp->meter_profile_id = meter_profile_id;
+ memcpy(&mp->params, params, sizeof(mp->params));
+
+ /* Add to list */
+ TAILQ_INSERT_TAIL(&table->meter_profiles, mp, node);
+ }
+
+ /* Update meter action */
+ mflow->action.mtr.mtr[0].meter_profile_id = meter_profile_id;
+
+ /* Re-add new rule */
+ status = softnic_pipeline_table_rule_add(p,
+ mflow->pipeline->name,
+ mflow->table_id,
+ &mflow->match,
+ &mflow->action,
+ &mflow->data);
+ if (status) {
+ if (mp_mem_alloc)
+ free(mp);
+
+ rte_mtr_error_set(error,
+ EINVAL,
+ RTE_MTR_ERROR_TYPE_UNSPECIFIED,
+ NULL,
+ "Pipeline table rule add failed");
+ return -1;
+ }
+
+ return 0;
+}
+
+/* MTR object meter profile update */
+static int
+pmd_mtr_meter_profile_update(struct rte_eth_dev *dev,
+ uint32_t mtr_id,
+ uint32_t meter_profile_id,
+ struct rte_mtr_error *error)
+{
+ struct pmd_internals *p = dev->data->dev_private;
+ struct softnic_mtr_meter_profile *mp, *mp_old;
+ struct softnic_mtr *m;
+ int status;
+
+ /* MTR object id must be valid */
+ m = softnic_mtr_find(p, mtr_id);
+ if (m == NULL)
+ return -rte_mtr_error_set(error,
+ EEXIST,
+ RTE_MTR_ERROR_TYPE_MTR_ID,
+ NULL,
+ rte_strerror(EEXIST));
+
+ /* Meter profile id must be valid */
+ mp = softnic_mtr_meter_profile_find(p, meter_profile_id);
+ if (mp == NULL)
+ return -rte_mtr_error_set(error,
+ EINVAL,
+ RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
+ NULL,
+ rte_strerror(EINVAL));
+
+ /* MTR object already set to meter profile id */
+ if (m->params.meter_profile_id == meter_profile_id)
+ return 0;
+
+ m->params.meter_profile_id = meter_profile_id;
+
+ /* Update dependencies */
+ mp_old = softnic_mtr_meter_profile_find(p, m->params.meter_profile_id);
+ if (mp_old == NULL)
+ return -rte_mtr_error_set(error,
+ EINVAL,
+ RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
+ NULL,
+ rte_strerror(EINVAL));
+
+ mp_old->n_users--;
+ mp->n_users++;
+
+ /* MTR object owner table update */
+ if (m->flow) {
+ status = softnic_table_meter_profile_update(p,
+ m,
+ meter_profile_id,
+ &mp->params,
+ error);
+ if (status)
+ return -rte_mtr_error_set(error,
+ EINVAL,
+ RTE_MTR_ERROR_TYPE_UNSPECIFIED,
+ NULL,
+ rte_strerror(EINVAL));
+ }
+
+ return 0;
+}
+
const struct rte_mtr_ops pmd_mtr_ops = {
.capabilities_get = NULL,
@@ -327,7 +464,7 @@ const struct rte_mtr_ops pmd_mtr_ops = {
.meter_enable = NULL,
.meter_disable = NULL,
- .meter_profile_update = NULL,
+ .meter_profile_update = pmd_mtr_meter_profile_update,
.meter_dscp_table_update = NULL,
.policer_actions_update = NULL,
.stats_update = NULL,
@@ -56,6 +56,17 @@ softnic_pipeline_table_free(struct softnic_table *table)
TAILQ_REMOVE(&table->flows, flow, node);
free(flow);
}
+
+ for ( ; ; ) {
+ struct softnic_mtr_meter_profile *mp;
+
+ mp = TAILQ_FIRST(&table->meter_profiles);
+ if (mp == NULL)
+ break;
+
+ TAILQ_REMOVE(&table->meter_profiles, mp, node);
+ free(mp);
+ }
}
void
@@ -989,6 +1000,7 @@ softnic_pipeline_table_create(struct pmd_internals *softnic,
table->ap = ap;
table->a = action;
TAILQ_INIT(&table->flows);
+ TAILQ_INIT(&table->meter_profiles);
pipeline->n_tables++;
return 0;