@@ -330,6 +330,9 @@ fc_flow_uninit(struct pmd_internals *p)
break;
TAILQ_REMOVE(&p->soft.fc.flow_list, flow, node);
+
+ free(flow->pattern);
+ free(flow->actions);
free(flow);
}
}
@@ -369,9 +372,309 @@ fc_free(struct pmd_internals *p)
rte_free(p->soft.fc.pkts);
}
+static struct rte_flow *
+fc_flow_search(struct pmd_internals *p,
+ const struct rte_flow_attr *attr,
+ const struct rte_flow_item pattern[],
+ const struct rte_flow_action actions[])
+{
+ struct fc_flow_list *fl = &p->soft.fc.flow_list;
+ struct rte_flow *f;
+ uint32_t n_item, n_act, n_match_params;
+
+ TAILQ_FOREACH(f, fl, node) {
+ n_item = 0;
+ n_act = 0;
+ n_match_params = 0;
+
+ /* Check: Flow attr */
+ if (memcmp(&f->attr,
+ (const void *)attr, sizeof(*attr)))
+ continue;
+ else
+ n_match_params += 1;
+
+ /* Check: Flow pattern */
+ while (pattern[n_item].type != RTE_FLOW_ITEM_TYPE_END) {
+ if (pattern[n_item].type != f->pattern[n_item].type)
+ n_match_params = 0;
+
+ n_item++;
+ }
+
+ if (n_match_params)
+ n_match_params += 1;
+ else
+ continue;
+
+ /* Check: Flow action */
+ while (actions[n_act].type != RTE_FLOW_ACTION_TYPE_END) {
+ if (actions[n_act].type != f->actions[n_act].type)
+ n_match_params = 0;
+
+ n_act++;
+ }
+
+ if (n_match_params)
+ n_match_params += 1;
+ else
+ continue;
+
+ if (n_match_params == 3)
+ return f;
+ }
+ return NULL;
+}
+
+static int rule_add_check(struct pmd_internals *p,
+ const struct rte_flow_attr *attr,
+ const struct rte_flow_item pattern[],
+ const struct rte_flow_action actions[],
+ struct rte_flow_error *error)
+{
+ struct rte_flow *flow;
+ uint32_t n_flow_rules;
+
+ /** Check: Number of rules */
+ n_flow_rules = p->soft.fc.n_flow_rules;
+ if (n_flow_rules >= p->params.soft.fc.nb_rules) {
+ rte_flow_error_set(error,
+ EINVAL,
+ RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
+ NULL,
+ "Number of Flow rule exceeds.");
+ return -EINVAL;
+ }
+
+ flow = fc_flow_search(p, attr, pattern, actions);
+ if (flow != NULL) {
+ rte_flow_error_set(error,
+ EEXIST,
+ RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
+ NULL,
+ "Flow rule exists.");
+ return -EEXIST;
+ }
+
+ return 0;
+}
+
+/* Flow rule validate */
+static int
+pmd_flow_validate(__rte_unused struct rte_eth_dev *dev,
+ const struct rte_flow_attr *attr,
+ const struct rte_flow_item pattern[],
+ const struct rte_flow_action actions[],
+ struct rte_flow_error *error)
+{
+ if (!pattern) {
+ rte_flow_error_set(error,
+ EINVAL,
+ RTE_FLOW_ERROR_TYPE_ITEM_NUM,
+ NULL,
+ "NULL pattern.");
+ return -rte_errno;
+ }
+
+ if (!actions) {
+ rte_flow_error_set(error,
+ EINVAL,
+ RTE_FLOW_ERROR_TYPE_ACTION_NUM,
+ NULL,
+ "NULL action.");
+ return -rte_errno;
+ }
+
+ if (!attr) {
+ rte_flow_error_set(error,
+ EINVAL,
+ RTE_FLOW_ERROR_TYPE_ATTR,
+ NULL,
+ "NULL attribute.");
+ return -rte_errno;
+ }
+
+ /* Add validate function */
+
+ return 0;
+}
+
+/* Create flow rule */
+static struct rte_flow *
+pmd_flow_create(struct rte_eth_dev *dev,
+ const struct rte_flow_attr *attr,
+ const struct rte_flow_item pattern[],
+ const struct rte_flow_action actions[],
+ struct rte_flow_error *error)
+{
+ struct pmd_internals *p = dev->data->dev_private;
+ struct fc_flow_list *fl = &p->soft.fc.flow_list;
+ struct rte_flow *f;
+ uint32_t n_item = 0, n_act = 0;
+ int status;
+
+ /** Check: Attributes */
+ if (!attr) {
+ rte_flow_error_set(error,
+ EINVAL,
+ RTE_FLOW_ERROR_TYPE_ATTR,
+ NULL,
+ "NULL attribute.");
+ return NULL;
+ }
+
+ /** Check: Pattern */
+ if (!pattern) {
+ rte_flow_error_set(error,
+ EINVAL,
+ RTE_FLOW_ERROR_TYPE_ITEM_NUM,
+ NULL,
+ "NULL pattern.");
+ return NULL;
+ }
+
+ /** Check: Actions */
+ if (!actions) {
+ rte_flow_error_set(error,
+ EINVAL,
+ RTE_FLOW_ERROR_TYPE_ACTION_NUM,
+ NULL,
+ "NULL action.");
+ return NULL;
+ }
+
+ /** Check: Rule */
+ status = rule_add_check(p, attr, pattern, actions, error);
+ if (status)
+ return NULL;
+
+ /** Add rule to the table */
+
+ /* Memory allocation */
+ f = calloc(1, sizeof(struct rte_flow));
+ if (f == NULL) {
+ rte_flow_error_set(error,
+ ENOMEM,
+ RTE_TM_ERROR_TYPE_UNSPECIFIED,
+ NULL,
+ "Failed to create flow.");
+ return NULL;
+ }
+
+ /** Add attr to list */
+ memcpy((void *)&f->attr, (const void *)attr, sizeof(*attr));
+
+ /** Allocate for pattern */
+ while ((pattern + n_item)->type != RTE_FLOW_ITEM_TYPE_END)
+ n_item++;
+
+ n_item++;
+
+ f->pattern = calloc(n_item, sizeof(struct rte_flow_item));
+ if (f->pattern) {
+ rte_flow_error_set(error,
+ ENOMEM,
+ RTE_TM_ERROR_TYPE_UNSPECIFIED,
+ NULL,
+ "Failed to create flow.");
+ return NULL;
+ }
+
+ /** Add pattern */
+ memcpy((void *)f->pattern, (const void *)pattern, sizeof(*f->pattern));
+
+ /** Allocate for action */
+ while ((actions + n_act)->type != RTE_FLOW_ACTION_TYPE_END)
+ n_act++;
+
+ n_act++;
+
+ f->actions = calloc(n_act, sizeof(struct rte_flow_action));
+ if (f->actions) {
+ rte_flow_error_set(error,
+ ENOMEM,
+ RTE_TM_ERROR_TYPE_UNSPECIFIED,
+ NULL,
+ "Failed to create flow.");
+ return NULL;
+ }
+
+ /** Add actions */
+ memcpy((void *)f->actions, (const void *)actions, sizeof(*f->actions));
+
+ TAILQ_INSERT_TAIL(fl, f, node);
+ p->soft.fc.n_flow_rules++;
+
+ return f;
+}
+
+/* Destroy flow rule */
+static int
+pmd_flow_destroy(struct rte_eth_dev *dev,
+ struct rte_flow *flow,
+ struct rte_flow_error *error)
+{
+ struct pmd_internals *p = dev->data->dev_private;
+ struct fc_flow_list *fl = &p->soft.fc.flow_list;
+ struct rte_flow *f;
+
+ /** Check: flow */
+ if (!flow) {
+ rte_flow_error_set(error,
+ EINVAL,
+ RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
+ NULL,
+ "NULL flow.");
+ return -EINVAL;
+ }
+ /* Check existing */
+ f = fc_flow_search(p, &flow->attr, flow->pattern, flow->actions);
+ if (f == NULL) {
+ rte_flow_error_set(error,
+ EINVAL,
+ RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
+ NULL,
+ "Flow not exist");
+ return -EINVAL;
+ }
+
+ /** Remove from Classifier table */
+
+ /** Remove from list */
+ TAILQ_REMOVE(fl, f, node);
+ p->soft.fc.n_flow_rules--;
+ free(f);
+
+ return 0;
+}
+
+/* Destroy flow rules */
+static int
+pmd_flow_flush(struct rte_eth_dev *dev,
+ __rte_unused struct rte_flow_error *error)
+{
+ struct pmd_internals *p = dev->data->dev_private;
+
+ for ( ; ; ) {
+ struct rte_flow *f;
+
+ f = TAILQ_FIRST(&p->soft.fc.flow_list);
+ if (f == NULL)
+ break;
+
+ /** Remove from Classifier table */
+
+ /** Remove from list */
+ TAILQ_REMOVE(&p->soft.fc.flow_list, f, node);
+ free(f);
+ }
+
+ return 0;
+}
+
const struct rte_flow_ops pmd_flow_ops = {
- .validate = NULL,
- .create = NULL,
- .destroy = NULL,
- .flush = NULL,
+ .validate = pmd_flow_validate,
+ .create = pmd_flow_create,
+ .destroy = pmd_flow_destroy,
+ .flush = pmd_flow_flush,
};