From: Yasufumi Ogawa <yasufum.o@gmail.com>
To: x-fn-spp-ml@ntt-tx.co.jp
Cc: ferruh.yigit@intel.com, spp@dpdk.org
Subject: Re: [spp] [PATCH 06/17] spp_primary: add support of rte_flow
Date: Wed, 19 Feb 2020 11:24:35 +0900 [thread overview]
Message-ID: <d614780b-4d66-1bcc-5f7a-e47434e3028e@gmail.com> (raw)
In-Reply-To: <20200218063720.6597-7-x-fn-spp-ml@ntt-tx.co.jp>
> From: Hideyuki Yamashita <yamashita.hideyuki@ntt-tx.co.jp>
>
> To support rte_flow in SPP, this patch provides main functions which
> defines validate, create, delete and flush flow
This patch has several issues from checkpatches.sh. Please fix bellow.
WARNING:RETURN_VOID: void function return statements are not generally
useful
#604: FILE: src/primary/flow/flow.c:581:
+ return;
+}
ERROR:SWITCH_CASE_INDENT_LEVEL: switch and case should be at the same indent
#700: FILE: src/primary/flow/flow.c:677:
+ switch(input->command) {
+ case VALIDATE:
[...]
+ case CREATE:
[...]
+ case DESTROY:
[...]
+ case FLUSH:
ERROR:SPACING: space required before the open parenthesis '('
#700: FILE: src/primary/flow/flow.c:677:
+ switch(input->command) {
WARNING:RETURN_VOID: void function return statements are not generally
useful
#729: FILE: src/primary/flow/flow.c:706:
+ return;
+}
Regards,
Yasufumi
>
> Signed-off-by: Hideyuki Yamashita <yamashita.hideyuki@ntt-tx.co.jp>
> Signed-off-by: Yasufumi Ogawa <yasufum.o@gmail.com>
> ---
> src/primary/flow/flow.c | 1048 +++++++++++++++++++++++++++++++++++++++
> src/primary/flow/flow.h | 94 ++++
> 2 files changed, 1142 insertions(+)
> create mode 100644 src/primary/flow/flow.c
> create mode 100644 src/primary/flow/flow.h
>
> diff --git a/src/primary/flow/flow.c b/src/primary/flow/flow.c
> new file mode 100644
> index 0000000..52a3e59
> --- /dev/null
> +++ b/src/primary/flow/flow.c
> @@ -0,0 +1,1048 @@
> +/* SPDX-License-Identifier: BSD-3-Clause
> + * Copyright(c) 2019 Nippon Telegraph and Telephone Corporation
> + */
> +
> +#include <rte_flow.h>
> +#include <rte_common.h>
> +#include <rte_ether.h>
> +#include <rte_byteorder.h>
> +
> +#include "shared/common.h"
> +#include "shared/secondary/utils.h"
> +#include "shared/secondary/spp_worker_th/data_types.h"
> +#include "primary/primary.h"
> +#include "flow.h"
> +#include "attr.h"
> +#include "common.h"
> +
> +#include "primary/flow/pattern/eth.h"
> +#include "primary/flow/pattern/vlan.h"
> +
> +#include "primary/flow/action/jump.h"
> +#include "primary/flow/action/queue.h"
> +#include "primary/flow/action/of_push_vlan.h"
> +#include "primary/flow/action/of_set_vlan_vid.h"
> +#include "primary/flow/action/of_set_vlan_pcp.h"
> +
> +
> +/* Flow list for each port */
> +static struct port_flow port_list[RTE_MAX_ETHPORTS] = { 0 };
> +
> +/* Define item operations */
> +static struct flow_item_ops flow_item_ops_list[] = {
> + {
> + .str_type = "end",
> + .type = RTE_FLOW_ITEM_TYPE_END,
> + .parse = NULL,
> + .detail_list = NULL
> + },
> + {
> + .str_type = "eth",
> + .type = RTE_FLOW_ITEM_TYPE_ETH,
> + .size = sizeof(struct rte_flow_item_eth),
> + .parse = parse_item_common,
> + .detail_list = eth_ops_list,
> + .status = append_item_eth_json,
> + },
> + {
> + .str_type = "vlan",
> + .type = RTE_FLOW_ITEM_TYPE_VLAN,
> + .size = sizeof(struct rte_flow_item_vlan),
> + .parse = parse_item_common,
> + .detail_list = vlan_ops_list,
> + .status = append_item_vlan_json,
> + },
> +};
> +
> +/* Define action operations */
> +static struct flow_action_ops flow_action_ops_list[] = {
> + {
> + .str_type = "end",
> + .type = RTE_FLOW_ACTION_TYPE_END,
> + .size = 0,
> + .parse = NULL,
> + .detail_list = NULL,
> + .status = NULL,
> + },
> + {
> + .str_type = "jump",
> + .type = RTE_FLOW_ACTION_TYPE_JUMP,
> + .size = sizeof(struct rte_flow_action_jump),
> + .parse = parse_action_common,
> + .detail_list = jump_ops_list,
> + .status = append_action_jump_json,
> + },
> + {
> + .str_type = "queue",
> + .type = RTE_FLOW_ACTION_TYPE_QUEUE,
> + .size = sizeof(struct rte_flow_action_queue),
> + .parse = parse_action_common,
> + .detail_list = queue_ops_list,
> + .status = append_action_queue_json,
> + },
> + {
> + .str_type = "of_pop_vlan",
> + .type = RTE_FLOW_ACTION_TYPE_OF_POP_VLAN,
> + .size = 0,
> + .parse = NULL,
> + .detail_list = NULL,
> + .status = append_action_null_json,
> + },
> + {
> + .str_type = "of_push_vlan",
> + .type = RTE_FLOW_ACTION_TYPE_OF_PUSH_VLAN,
> + .size = sizeof(struct rte_flow_action_of_push_vlan),
> + .parse = parse_action_common,
> + .detail_list = of_push_vlan_ops_list,
> + .status = append_action_of_push_vlan_json,
> + },
> + {
> + .str_type = "of_set_vlan_vid",
> + .type = RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_VID,
> + .size = sizeof(struct rte_flow_action_of_set_vlan_vid),
> + .parse = parse_action_common,
> + .detail_list = of_set_vlan_vid_ops_list,
> + .status = append_action_of_set_vlan_vid_json,
> + },
> + {
> + .str_type = "of_set_vlan_pcp",
> + .type = RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_PCP,
> + .size = sizeof(struct rte_flow_action_of_set_vlan_pcp),
> + .parse = parse_action_common,
> + .detail_list = of_set_vlan_pcp_ops_list,
> + .status = append_action_of_set_vlan_pcp_json,
> + },
> +};
> +
> +/* Free memory of "flow_args". */
> +static void
> +free_flow_args(struct flow_args *input)
> +{
> + int i;
> + struct rte_flow_item *pattern;
> + struct rte_flow_action *actions;
> + char **target;
> +
> + if ((input->command != VALIDATE) &&
> + (input->command != CREATE))
> + return;
> +
> + pattern = input->args.rule.pattern;
> + if (pattern != NULL) {
> + for (i = 0; pattern[i].type != RTE_FLOW_ITEM_TYPE_END; i++) {
> + target = (char **)((char *)(&pattern[i]) +
> + offsetof(struct rte_flow_item, spec));
> + if (*target != NULL)
> + free(*target);
> +
> + target = (char **)((char *)(&pattern[i]) +
> + offsetof(struct rte_flow_item, last));
> + if (*target != NULL)
> + free(*target);
> +
> + target = (char **)((char *)(&pattern[i]) +
> + offsetof(struct rte_flow_item, mask));
> + if (*target != NULL)
> + free(*target);
> + }
> +
> + free(pattern);
> + }
> +
> + actions = input->args.rule.actions;
> + if (actions != NULL) {
> + for (i = 0; actions[i].type != RTE_FLOW_ACTION_TYPE_END; i++) {
> + target = (char **)((char *)(&actions[i]) +
> + offsetof(struct rte_flow_action, conf));
> + if (*target != NULL)
> + free(*target);
> + }
> +
> + free(actions);
> + }
> +}
> +
> +/*
> + * Create response in JSON format.
> + * `rule_id` must be empty if flow create is failed.
> + */
> +static void
> +make_response(char *response, const char *result, const char *message,
> + char *rule_id)
> +{
> + if (rule_id == NULL)
> + snprintf(response, MSG_SIZE,
> + "{\"result\": \"%s\", \"message\": \"%s\"}",
> + result, message);
> + else
> + snprintf(response, MSG_SIZE,
> + "{\"result\": \"%s\", \"message\": \"%s\", "
> + "\"rule_id\": \"%s\"}",
> + result, message, rule_id);
> +}
> +
> +/* Create error response from rte_flow_error */
> +static void
> +make_error_response(char *response, const char *message,
> + struct rte_flow_error error, char *rule_id)
> +{
> + /* Define description for each error type */
> + static const char *const errstr_list[] = {
> + [RTE_FLOW_ERROR_TYPE_NONE] = "No error",
> + [RTE_FLOW_ERROR_TYPE_UNSPECIFIED] = "Cause unspecified",
> + [RTE_FLOW_ERROR_TYPE_HANDLE] = "Flow rule (handle)",
> + [RTE_FLOW_ERROR_TYPE_ATTR_GROUP] = "Group field",
> + [RTE_FLOW_ERROR_TYPE_ATTR_PRIORITY] = "Priority field",
> + [RTE_FLOW_ERROR_TYPE_ATTR_INGRESS] = "Ingress field",
> + [RTE_FLOW_ERROR_TYPE_ATTR_EGRESS] = "Egress field",
> + [RTE_FLOW_ERROR_TYPE_ATTR_TRANSFER] = "Transfer field",
> + [RTE_FLOW_ERROR_TYPE_ATTR] = "Attributes structure",
> + [RTE_FLOW_ERROR_TYPE_ITEM_NUM] = "Pattern length",
> + [RTE_FLOW_ERROR_TYPE_ITEM_SPEC] = "Item specification",
> + [RTE_FLOW_ERROR_TYPE_ITEM_LAST] = "Item specification range",
> + [RTE_FLOW_ERROR_TYPE_ITEM_MASK] = "Item specification mask",
> + [RTE_FLOW_ERROR_TYPE_ITEM] = "Specific pattern item",
> + [RTE_FLOW_ERROR_TYPE_ACTION_NUM] = "Number of actions",
> + [RTE_FLOW_ERROR_TYPE_ACTION_CONF] = "Action configuration",
> + [RTE_FLOW_ERROR_TYPE_ACTION] = "Specific action",
> + };
> + int err = rte_errno;
> + char msg[512] = "";
> + char cause[32] = "";
> + const char *errstr;
> +
> + if ((unsigned int)error.type >= RTE_DIM(errstr_list) ||
> + !errstr_list[error.type])
> + errstr = "Unknown type";
> + else
> + errstr = errstr_list[error.type];
> +
> +
> + if (error.cause != NULL)
> + snprintf(cause, sizeof(cause), "cause: %p\\n", error.cause);
> +
> + snprintf(msg, sizeof(msg),
> + "%s\\nerror type: %d (%s)\\n"
> + "%serror message: %s\\nrte_errno: %s",
> + message, error.type, errstr, cause,
> + error.message ? error.message : "(no stated reason)",
> + rte_strerror(err));
> + make_response(response, "error", msg, rule_id);
> +}
> +
> +/* Add to array, redeclare memory. */
> +static int
> +append_object_list(void **list, void *add, size_t obj_size, int num)
> +{
> + char *new_list;
> +
> + new_list = malloc(obj_size * num);
> + if (new_list == NULL)
> + return -1;
> +
> + /* Copy original list*/
> + if (*list != NULL) {
> + memcpy(new_list, *list, obj_size * (num - 1));
> + free(*list);
> + }
> +
> + /* Add to list */
> + memcpy(new_list + (obj_size * (num - 1)), add, obj_size);
> +
> + *list = (void *)new_list;
> + return 0;
> +}
> +
> +static int
> +parse_flow_actions(char *token_list[], int *index,
> + struct rte_flow_action **actions)
> +{
> + int ret;
> + int action_count = 0;
> + uint16_t i;
> + char *token;
> + struct flow_action_ops *ops;
> + struct rte_flow_action action;
> +
> + if (strcmp(token_list[*index], "actions")) {
> + RTE_LOG(ERR, SPP_FLOW,
> + "Invalid parameter is %s(%s:%d)\n",
> + token_list[*index], __func__, __LINE__);
> + return -1;
> + }
> +
> + /* Next to word */
> + (*index)++;
> +
> + while (token_list[*index] != NULL) {
> + token = token_list[*index];
> +
> + for (i = 0; i < RTE_DIM(flow_action_ops_list); i++) {
> + ops = &flow_action_ops_list[i];
> + if (strcmp(token, ops->str_type))
> + continue;
> +
> + memset(&action, 0, sizeof(struct rte_flow_action));
> + action.type = ops->type;
> + if (ops->parse != NULL) {
> + ret = ops->parse(token_list, index, &action,
> + ops);
> + if (ret < 0)
> + return -1;
> + } else {
> + (*index)++;
> + }
> + break;
> + }
> +
> + /*
> + * Error occurs if a action string that is not defined in
> + * str_type of flow_action_ops_list is specified
> + */
> + if (i == RTE_DIM(flow_action_ops_list)) {
> + RTE_LOG(ERR, SPP_FLOW,
> + "Invalid parameter "
> + "is %s action(%s:%d)\n",
> + token, __func__, __LINE__);
> + return -1;
> + }
> +
> + /* Add to "actions" list */
> + action_count++;
> + ret = append_object_list((void **)actions, &action,
> + sizeof(struct rte_flow_action), action_count);
> +
> + if (!strcmp(token, "end"))
> + break;
> +
> + (*index)++;
> + }
> +
> + return 0;
> +}
> +
> +static int
> +parse_flow_pattern(char *token_list[], int *index,
> + struct rte_flow_item **pattern)
> +{
> + int ret;
> + int item_count = 0;
> + uint32_t i;
> + char *token;
> + struct flow_item_ops *ops;
> + struct rte_flow_item item;
> +
> + while (token_list[*index] != NULL) {
> + token = token_list[*index];
> +
> + for (i = 0; i < RTE_DIM(flow_item_ops_list); i++) {
> + ops = &flow_item_ops_list[i];
> + if (strcmp(token, ops->str_type))
> + continue;
> +
> + memset(&item, 0, sizeof(struct rte_flow_item));
> + item.type = ops->type;
> + if (ops->parse != NULL) {
> + ret = ops->parse(token_list, index, &item,
> + ops);
> + if (ret < 0)
> + return -1;
> + }
> + break;
> + }
> +
> + /*
> + * Error occurs if a pattern string that is not defined in
> + * str_type of flow_item_ops_list is specified
> + */
> + if (i == RTE_DIM(flow_item_ops_list)) {
> + RTE_LOG(ERR, SPP_FLOW,
> + "Invalid parameter "
> + "is %s pattern(%s:%d)\n",
> + token, __func__, __LINE__);
> + return -1;
> + }
> +
> + /* Add to "pattern" list */
> + item_count++;
> + ret = append_object_list((void **)pattern, &item,
> + sizeof(struct rte_flow_item), item_count);
> +
> + if (!strcmp(token, "end"))
> + break;
> +
> + (*index)++;
> + }
> +
> + return 0;
> +}
> +
> +static int
> +parse_flow_rule(char *token_list[], struct flow_args *input)
> +{
> + int ret = 0;
> + int index;
> +
> + ret = parse_phy_port_id(token_list[2], &input->port_id);
> + if (ret < 0)
> + return -1;
> +
> + /* The next index of the port */
> + index = 3;
> +
> + /* Attribute parse */
> + ret = parse_flow_attr(token_list, &index, &input->args.rule.attr);
> + if (ret < 0) {
> + RTE_LOG(ERR, SPP_FLOW,
> + "Failed to parse Attribute(%s:%d)\n",
> + __func__, __LINE__);
> + return -1;
> + }
> +
> + /* The next index of the pattern */
> + index++;
> +
> + /* Pattern parse */
> + ret = parse_flow_pattern(token_list, &index,
> + &input->args.rule.pattern);
> + if (ret < 0) {
> + RTE_LOG(ERR, SPP_FLOW,
> + "Failed to parse Pattern(%s:%d)\n",
> + __func__, __LINE__);
> + return -1;
> + }
> +
> + /* The next index of the actions */
> + index++;
> +
> + /* Actions parse */
> + ret = parse_flow_actions(token_list, &index,
> + &input->args.rule.actions);
> + if (ret < 0) {
> + RTE_LOG(ERR, SPP_FLOW,
> + "Failed to parse Actions(%s:%d)\n",
> + __func__, __LINE__);
> + return -1;
> + }
> +
> + return 0;
> +}
> +
> +static int
> +parse_flow_destroy(char *token_list[], struct flow_args *input)
> +{
> + int ret;
> + char *end;
> +
> + ret = parse_phy_port_id(token_list[2], &input->port_id);
> + if (ret < 0)
> + return -1;
> +
> + if (token_list[3] == NULL) {
> + RTE_LOG(ERR, SPP_FLOW,
> + "rule_id is not specified(%s:%d)\n",
> + __func__, __LINE__);
> + return -1;
> + }
> +
> + if (!strcmp(token_list[3], "ALL")) {
> + input->command = FLUSH;
> +
> + } else {
> + input->command = DESTROY;
> + input->args.destroy.rule_id = strtoul(token_list[3],
> + &end, 10);
> + }
> +
> + return 0;
> +}
> +
> +/** Generate a flow_rule entry from attributes/pattern/actions. */
> +static struct flow_rule *
> +create_flow_rule(struct rte_flow_attr *attr,
> + struct rte_flow_item *pattern,
> + struct rte_flow_action *actions,
> + struct rte_flow_error *error)
> +{
> + const struct rte_flow_conv_rule conv_rule = {
> + .attr_ro = attr,
> + .pattern_ro = pattern,
> + .actions_ro = actions,
> + };
> + struct flow_rule *rule;
> + int ret;
> +
> + ret = rte_flow_conv(RTE_FLOW_CONV_OP_RULE, NULL, 0, &conv_rule,
> + error);
> + if (ret < 0)
> + return NULL;
> +
> + rule = calloc(1, offsetof(struct flow_rule, rule) + ret);
> + if (!rule) {
> + rte_flow_error_set
> + (error, errno, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
> + "calloc() failed");
> + return NULL;
> + }
> +
> + ret = rte_flow_conv(RTE_FLOW_CONV_OP_RULE, &rule->rule, ret, &conv_rule,
> + error);
> + if (ret >= 0)
> + return rule;
> +
> + free(rule);
> + return NULL;
> +}
> +
> +/* Execute rte_flow_validate().*/
> +static void
> +exec_flow_validate(int port_id,
> + struct rte_flow_attr *attr,
> + struct rte_flow_item *pattern,
> + struct rte_flow_action *actions,
> + char *response)
> +{
> + int ret;
> + struct rte_flow_error error;
> +
> + memset(&error, 0, sizeof(error));
> +
> + ret = rte_flow_validate(port_id, attr, pattern, actions, &error);
> + if (ret != 0)
> + make_error_response(response, "Flow validate error", error,
> + NULL);
> + else
> + make_response(response, "success", "Flow rule validated",
> + NULL);
> +}
> +
> +/* Execute rte_flow_create(). Save flow rules globally */
> +static void
> +exec_flow_create(int port_id,
> + struct rte_flow_attr *attr,
> + struct rte_flow_item *pattern,
> + struct rte_flow_action *actions,
> + char *response)
> +{
> + uint32_t rule_id;
> + char mes[32];
> + char rule_id_str[11] = {0};
> + struct rte_flow_error error;
> + struct rte_flow *flow;
> + struct flow_rule *rule;
> + struct port_flow *port;
> +
> + memset(&error, 0, sizeof(error));
> +
> + flow = rte_flow_create(port_id, attr, pattern, actions, &error);
> + if (flow == NULL) {
> + make_error_response(response, "Flow create error", error,
> + rule_id_str);
> + return;
> + }
> +
> + port = &port_list[port_id];
> + if (port->flow_list != NULL) {
> + if (port->flow_list->rule_id >= UINT32_MAX) {
> + make_response(response, "error",
> + "Rule ID must be less than %"PRIu32,
> + rule_id_str);
> + rte_flow_destroy(port_id, flow, NULL);
> + return;
> + }
> + rule_id = port->flow_list->rule_id + 1;
> + } else {
> + rule_id = 0;
> + }
> +
> + rule = create_flow_rule(attr, pattern, actions, &error);
> + if (rule == NULL) {
> + rte_flow_destroy(port_id, flow, NULL);
> + make_error_response(response, "Flow create error", error,
> + rule_id_str);
> + return;
> + }
> +
> + /* Keep it globally as a list */
> + rule->rule_id = rule_id;
> + rule->flow_handle = flow;
> +
> + if (port->flow_list == NULL)
> + rule->prev = NULL;
> + else
> + rule->prev = port->flow_list;
> +
> + port->flow_list = rule;
> +
> + sprintf(mes, "Flow rule #%d created", rule_id);
> + sprintf(rule_id_str, "%d", rule_id);
> + make_response(response, "success", mes, rule_id_str);
> + return;
> +}
> +
> +/* Execute rte_flow_destroy(). Destroying a globally saved flow rule */
> +static void
> +exec_flow_destroy(int port_id, uint32_t rule_id, char *response)
> +{
> + int ret;
> + int found_flg = 0;
> + char mes[64];
> + struct flow_rule *rule, **next_ptr;
> + struct rte_flow_error error;
> +
> + memset(&error, 0, sizeof(error));
> +
> + ret = is_portid_used(port_id);
> + if (ret != 0) {
> + sprintf(mes, "Invalid port %d", port_id);
> + make_response(response, "error", mes, NULL);
> + return;
> + }
> +
> + next_ptr = &(port_list[port_id].flow_list);
> + rule = port_list[port_id].flow_list;
> +
> + while (rule != NULL) {
> + if (rule->rule_id != rule_id) {
> + next_ptr = &(rule->prev);
> + rule = rule->prev;
> + continue;
> + }
> +
> + ret = rte_flow_destroy(port_id, rule->flow_handle, &error);
> + if (ret != 0) {
> + make_error_response(response, "Flow destroy error",
> + error, NULL);
> + return;
> + }
> +
> + /* Remove flow from global list */
> + *next_ptr = rule->prev;
> + free(rule);
> + found_flg = 1;
> +
> + sprintf(mes, "Flow rule #%d destroyed", rule_id);
> + make_response(response, "success", mes, NULL);
> + break;
> + }
> +
> + /* Rule_id not found */
> + if (found_flg == 0) {
> + sprintf(mes, "Flow rule #%d not found", rule_id);
> + make_response(response, "error", mes, NULL);
> + }
> +}
> +
> +/* Delete all globally saved flow rules */
> +static void
> +exec_flow_flush(int port_id, char *response)
> +{
> + int ret;
> + char mes[64];
> + struct flow_rule *rule;
> + struct rte_flow_error error;
> +
> + memset(&error, 0, sizeof(error));
> +
> + ret = is_portid_used(port_id);
> + if (ret != 0) {
> + sprintf(mes, "Invalid port %d", port_id);
> + make_response(response, "error", mes, NULL);
> + return;
> + }
> +
> + ret = rte_flow_flush(port_id, &error);
> + if (ret != 0)
> + make_error_response(response, "Flow destroy error",
> + error, NULL);
> + else
> + make_response(response, "success", "Flow rule all destroyed",
> + NULL);
> +
> + /*
> + * Even if a failure occurs, flow handle is invalidated,
> + * so delete flow_list.
> + */
> +
> + while (port_list[port_id].flow_list != NULL) {
> + rule = port_list[port_id].flow_list->prev;
> + free(port_list[port_id].flow_list);
> + port_list[port_id].flow_list = rule;
> + }
> +}
> +
> +static void
> +exec_flow(struct flow_args *input, char *response)
> +{
> + switch(input->command) {
> + case VALIDATE:
> + exec_flow_validate(input->port_id,
> + &input->args.rule.attr,
> + input->args.rule.pattern,
> + input->args.rule.actions,
> + response);
> + break;
> + case CREATE:
> + exec_flow_create(input->port_id,
> + &input->args.rule.attr,
> + input->args.rule.pattern,
> + input->args.rule.actions,
> + response);
> + break;
> + case DESTROY:
> + exec_flow_destroy(input->port_id,
> + input->args.destroy.rule_id,
> + response);
> + break;
> + case FLUSH:
> + exec_flow_flush(input->port_id, response);
> + break;
> + }
> +
> + /* Argument data is no longer needed and freed */
> + free_flow_args(input);
> +
> + return;
> +}
> +
> +int
> +parse_flow(char *token_list[], char *response)
> +{
> + int ret = 0;
> + struct flow_args input = { 0 };
> +
> + if (token_list[1] == NULL) {
> + ret = -1;
> + } else if (!strcmp(token_list[1], "validate")) {
> + input.command = VALIDATE;
> + ret = parse_flow_rule(token_list, &input);
> +
> + } else if (!strcmp(token_list[1], "create")) {
> + input.command = CREATE;
> + ret = parse_flow_rule(token_list, &input);
> +
> + } else if (!strcmp(token_list[1], "destroy")) {
> + ret = parse_flow_destroy(token_list, &input);
> +
> + } else {
> + ret = -1;
> + }
> +
> + if (ret != 0) {
> + free_flow_args(&input);
> + make_response(response, "error",
> + "Flow command invalid argument", NULL);
> + return 0;
> + }
> +
> + exec_flow(&input, response);
> +
> + return 0;
> +}
> +
> +static int
> +append_flow_pattern_json(const struct rte_flow_item *pattern, int buf_size,
> + char *pattern_str)
> +{
> + uint32_t i, j;
> + uint32_t nof_elems = 3;
> + int ret = 0;
> + char *tmp_str;
> + const char element_str[][5] = { "spec", "last", "mask" };
> + const struct rte_flow_item *ptn = pattern;
> + struct flow_item_ops *ops;
> + const void *tmp_ptr[nof_elems];
> +
> + tmp_str = malloc(buf_size);
> + if (tmp_str == NULL) {
> + RTE_LOG(ERR, SPP_FLOW,
> + "Memory allocation failure(%s:%d)\n",
> + __func__, __LINE__);
> + return -1;
> + }
> +
> + while (ptn->type != RTE_FLOW_ITEM_TYPE_END) {
> + memset(tmp_str, 0, buf_size);
> +
> + tmp_ptr[0] = ptn->spec;
> + tmp_ptr[1] = ptn->last;
> + tmp_ptr[2] = ptn->mask;
> +
> + for (i = 0; i < RTE_DIM(flow_item_ops_list); i++) {
> + ops = &flow_item_ops_list[i];
> + if (ptn->type != ops->type)
> + continue;
> +
> + snprintf(tmp_str, buf_size,
> + "{\"type\":\"%s\",",
> + ops->str_type);
> +
> + for (j = 0; j < nof_elems; j++) {
> + snprintf(tmp_str + strlen(tmp_str), buf_size,
> + "\"%s\":",
> + element_str[j]);
> +
> + if (tmp_ptr[j] != NULL)
> + ret = ops->status(tmp_ptr[j],
> + buf_size - (int)strlen(tmp_str),
> + tmp_str + strlen(tmp_str));
> + else
> + snprintf(tmp_str + strlen(tmp_str),
> + buf_size,
> + "null");
> +
> + if (ret != 0)
> + break;
> +
> + if (j < nof_elems - 1)
> + tmp_str[strlen(tmp_str)] = ',';
> + }
> +
> + tmp_str[strlen(tmp_str)] = '}';
> +
> + break;
> + }
> +
> + if (ret != 0)
> + break;
> +
> + if ((int)strlen(pattern_str) + (int)strlen(tmp_str)
> + > buf_size - 1) {
> + ret = -1;
> + break;
> + }
> + strncat(pattern_str, tmp_str, strlen(tmp_str));
> +
> + /*
> + * If there is the following pattern, add ',' to
> + * pattern_str
> + */
> + ptn++;
> + if (ptn->type != RTE_FLOW_ITEM_TYPE_END) {
> + if ((int)strlen(pattern_str) + 1 > buf_size - 1) {
> + ret = -1;
> + break;
> + }
> + pattern_str[strlen(pattern_str)] = ',';
> + }
> + }
> +
> + if (tmp_str != NULL)
> + free(tmp_str);
> +
> + return ret;
> +}
> +
> +static int
> +append_flow_action_json(const struct rte_flow_action *actions, int buf_size,
> + char *actions_str)
> +{
> + uint32_t i;
> + int ret = 0;
> + char *tmp_str;
> + const struct rte_flow_action *act = actions;
> + struct flow_action_ops *ops;
> +
> + tmp_str = malloc(buf_size);
> + if (tmp_str == NULL) {
> + RTE_LOG(ERR, SPP_FLOW,
> + "Memory allocation failure(%s:%d)\n",
> + __func__, __LINE__);
> + return -1;
> + }
> +
> + while (act->type != RTE_FLOW_ACTION_TYPE_END) {
> + memset(tmp_str, 0, buf_size);
> +
> + for (i = 0; i < RTE_DIM(flow_action_ops_list); i++) {
> + ops = &flow_action_ops_list[i];
> + if (act->type != ops->type)
> + continue;
> +
> + snprintf(tmp_str, buf_size,
> + "{\"type\":\"%s\",\"conf\":",
> + ops->str_type);
> +
> + ret = ops->status(act->conf,
> + buf_size - (int)strlen(tmp_str),
> + tmp_str + strlen(tmp_str));
> + tmp_str[strlen(tmp_str)] = '}';
> + break;
> + }
> +
> + if (ret != 0)
> + break;
> +
> + if ((int)strlen(actions_str) + (int)strlen(tmp_str)
> + > buf_size - 1) {
> + ret = -1;
> + break;
> + }
> + strncat(actions_str, tmp_str, strlen(tmp_str));
> +
> + /*
> + * If there is the following pattern, add ',' to
> + * actions_str
> + */
> + act++;
> + if (act->type != RTE_FLOW_ACTION_TYPE_END) {
> + if ((int)strlen(actions_str) + 1 > buf_size - 1) {
> + ret = -1;
> + break;
> + }
> + actions_str[strlen(actions_str)] = ',';
> + }
> + }
> +
> + if (tmp_str != NULL)
> + free(tmp_str);
> +
> + return ret;
> +}
> +
> +static int
> +append_flow_rule_json(struct flow_rule *flow, int buf_size, char *flow_str)
> +{
> + int ret = 0;
> + struct rte_flow_conv_rule rule;
> + char *tmp_str, *attr_str, *pattern_str, *actions_str;
> +
> + while (1) {
> + tmp_str = malloc(buf_size);
> + attr_str = malloc(buf_size);
> + pattern_str = malloc(buf_size);
> + actions_str = malloc(buf_size);
> + if (tmp_str == NULL || attr_str == NULL
> + || pattern_str == NULL || actions_str == NULL) {
> + RTE_LOG(ERR, SPP_FLOW,
> + "Memory allocation failure(%s:%d)\n",
> + __func__, __LINE__);
> + ret = -1;
> + break;
> + }
> + memset(tmp_str, 0, buf_size);
> + memset(attr_str, 0, buf_size);
> + memset(pattern_str, 0, buf_size);
> + memset(actions_str, 0, buf_size);
> +
> + rule = flow->rule;
> +
> + ret = append_flow_attr_json(rule.attr_ro, buf_size, attr_str);
> + if (ret != 0)
> + break;
> +
> + ret = append_flow_pattern_json(rule.pattern_ro, buf_size,
> + pattern_str);
> + if (ret != 0)
> + break;
> +
> + ret = append_flow_action_json(rule.actions_ro, buf_size,
> + actions_str);
> + if (ret != 0)
> + break;
> +
> + snprintf(tmp_str, buf_size,
> + "{\"rule_id\":%d,"
> + "\"attr\":%s,"
> + "\"patterns\":[%s],"
> + "\"actions\":[%s]}",
> + flow->rule_id, attr_str, pattern_str, actions_str);
> +
> + if ((int)strlen(tmp_str) > buf_size - 1) {
> + ret = -1;
> + break;
> + }
> +
> + snprintf(flow_str, buf_size, "%s", tmp_str);
> + break;
> + }
> +
> + if (tmp_str != NULL)
> + free(tmp_str);
> + if (attr_str != NULL)
> + free(attr_str);
> + if (pattern_str != NULL)
> + free(pattern_str);
> + if (actions_str != NULL)
> + free(actions_str);
> +
> + return ret;
> +}
> +
> +int
> +append_flow_json(int port_id, int buf_size, char *output)
> +{
> + int ret = 0;
> + int str_size = 0;
> + char *flow_str, *tmp_str;
> + struct flow_rule *flow;
> +
> + flow_str = malloc(buf_size);
> + tmp_str = malloc(buf_size);
> + if (flow_str == NULL || tmp_str == NULL) {
> + RTE_LOG(ERR, SPP_FLOW,
> + "Memory allocation failure(%s:%d)\n",
> + __func__, __LINE__);
> + return -1;
> + }
> +
> + flow = port_list[port_id].flow_list;
> +
> + while (flow != NULL) {
> + memset(flow_str, 0, buf_size);
> +
> + ret = append_flow_rule_json(flow, buf_size, flow_str);
> + if (ret != 0)
> + break;
> +
> + if (str_size == 0) {
> + snprintf(output, buf_size, "%s", flow_str);
> + str_size += (int)strlen(flow_str);
> +
> + } else {
> + str_size += ((int)strlen(flow_str) + 1);
> + if (str_size > buf_size - 1) {
> + ret = -1;
> + break;
> + }
> +
> + /*
> + * Since flow_list is in descending order,
> + * concatenate the strings in front.
> + */
> + memset(tmp_str, 0, buf_size);
> + strncpy(tmp_str, output, buf_size);
> + memset(output, 0, buf_size);
> +
> + snprintf(output, buf_size, "%s,%s",
> + flow_str, tmp_str);
> + }
> +
> + flow = flow->prev;
> + }
> +
> + if (ret == 0) {
> + if ((int)strlen("[]") + (int)strlen(flow_str)
> + > buf_size - 1)
> + ret = -1;
> + else {
> + memset(tmp_str, 0, buf_size);
> + strncpy(tmp_str, output, buf_size);
> + memset(output, 0, buf_size);
> +
> + snprintf(output, buf_size, "[%s]", tmp_str);
> + }
> + }
> +
> + if (ret != 0)
> + RTE_LOG(ERR, SPP_FLOW,
> + "Cannot send all of flow stats(%s:%d)\n",
> + __func__, __LINE__);
> +
> + if (flow_str != NULL)
> + free(flow_str);
> + if (tmp_str != NULL)
> + free(tmp_str);
> +
> + return ret;
> +}
> diff --git a/src/primary/flow/flow.h b/src/primary/flow/flow.h
> new file mode 100644
> index 0000000..ecd4eb3
> --- /dev/null
> +++ b/src/primary/flow/flow.h
> @@ -0,0 +1,94 @@
> +/* SPDX-License-Identifier: BSD-3-Clause
> + * Copyright(c) 2019 Nippon Telegraph and Telephone Corporation
> + */
> +
> +#ifndef _PRIMARY_FLOW_H_
> +#define _PRIMARY_FLOW_H_
> +
> +#include <rte_log.h>
> +
> +#define RTE_LOGTYPE_SPP_FLOW RTE_LOGTYPE_USER1
> +
> +enum flow_command {
> + VALIDATE = 0,
> + CREATE,
> + DESTROY,
> + FLUSH
> +};
> +
> +/* Parser result of flow command arguments */
> +struct flow_args {
> + enum flow_command command;
> + int port_id;
> + union {
> + struct {
> + struct rte_flow_attr attr;
> + struct rte_flow_item *pattern;
> + struct rte_flow_action *actions;
> + } rule; /* validate or create arguments. */
> + struct {
> + uint32_t rule_id;
> + } destroy; /* destroy arguments. */
> + } args;
> +};
> +
> +/* Descriptor for a single flow. */
> +struct flow_rule {
> + /* Flow rule ID */
> + uint32_t rule_id;
> +
> + /* Previous flow in list. */
> + struct flow_rule *prev;
> +
> + /* Opaque flow object returned by PMD. */
> + struct rte_flow *flow_handle;
> +
> + /* Saved flow rule description. */
> + struct rte_flow_conv_rule rule;
> +};
> +
> +/* Flow rule list of the port */
> +struct port_flow {
> + /* Associated flows */
> + struct flow_rule *flow_list;
> +};
> +
> +/* Detail parse operation for a specific item or action */
> +struct flow_detail_ops {
> + const char *token;
> + const size_t offset;
> + const size_t size;
> + int flg_value;
> + int (*parse_detail)(char *str, void *output);
> +};
> +
> +/* Operation for each item type */
> +struct flow_item_ops {
> + const char *str_type;
> + enum rte_flow_item_type type;
> + size_t size;
> + int (*parse)(char *token_list[], int *index,
> + struct rte_flow_item *pattern,
> + struct flow_item_ops *ops);
> + struct flow_detail_ops *detail_list;
> + int (*status)(const void *element,
> + int buf_size, char *pattern_str);
> +};
> +
> +/* Operation for each action type */
> +struct flow_action_ops {
> + const char *str_type;
> + enum rte_flow_action_type type;
> + size_t size;
> + int (*parse)(char *token_list[], int *index,
> + struct rte_flow_action *action,
> + struct flow_action_ops *ops);
> + struct flow_detail_ops *detail_list;
> + int (*status)(const void *conf,
> + int buf_size, char *action_str);
> +};
> +
> +int parse_flow(char *token_list[], char *response);
> +int append_flow_json(int port_id, int buf_size, char *output);
> +
> +#endif
>
next prev parent reply other threads:[~2020-02-19 2:23 UTC|newest]
Thread overview: 40+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-02-18 6:37 [spp] [PATCH 00/17] Adding Hardware offload capability x-fn-spp-ml
2020-02-18 6:37 ` [spp] [PATCH 01/17] shared: add support of multi-queue x-fn-spp-ml
2020-02-18 6:37 ` [spp] [PATCH 02/17] spp_vf: " x-fn-spp-ml
2020-02-18 6:37 ` [spp] [PATCH 03/17] spp_mirror: " x-fn-spp-ml
2020-02-18 6:37 ` [spp] [PATCH 04/17] spp_pcap: " x-fn-spp-ml
2020-02-18 6:37 ` [spp] [PATCH 05/17] spp_primary: " x-fn-spp-ml
2020-02-18 6:37 ` [spp] [PATCH 06/17] spp_primary: add support of rte_flow x-fn-spp-ml
2020-02-19 2:24 ` Yasufumi Ogawa [this message]
2020-02-19 11:57 ` [spp] (x-fn-spp-ml 118) " Hideyuki Yamashita
2020-02-18 6:37 ` [spp] [PATCH 07/17] spp_primary: add common function " x-fn-spp-ml
2020-02-18 6:37 ` [spp] [PATCH 08/17] spp_primary: add attribute " x-fn-spp-ml
2020-02-18 6:37 ` [spp] [PATCH 09/17] spp_primary: add patterns " x-fn-spp-ml
2020-02-18 6:37 ` [spp] [PATCH 10/17] spp_primary: add actions " x-fn-spp-ml
2020-02-18 6:37 ` [spp] [PATCH 11/17] bin: add parameter for hardrare offload x-fn-spp-ml
2020-02-18 6:37 ` [spp] [PATCH 12/17] cli: add support of hardware offload x-fn-spp-ml
2020-02-18 6:37 ` [spp] [PATCH 13/17] cli: add support of rte_flow in vf x-fn-spp-ml
2020-02-18 6:37 ` [spp] [PATCH 14/17] cli: add support of rte_flow in mirror x-fn-spp-ml
2020-02-18 6:37 ` [spp] [PATCH 15/17] cli: add support of rte_flow in nfv x-fn-spp-ml
2020-02-18 6:37 ` [spp] [PATCH 16/17] spp-ctl: add APIs for flow rules x-fn-spp-ml
2020-02-18 6:37 ` [spp] [PATCH 17/17] spp_nfv: add support of multi-queue x-fn-spp-ml
2020-02-19 11:49 ` [spp] [PATCH v2 00/17] Adding Hardware offload capability x-fn-spp-ml
2020-02-21 8:17 ` Yasufumi Ogawa
2020-02-25 5:49 ` [spp] (x-fn-spp-ml 177) " Hideyuki Yamashita
2020-02-19 11:49 ` [spp] [PATCH v2 01/17] shared: add support of multi-queue x-fn-spp-ml
2020-02-19 11:49 ` [spp] [PATCH v2 02/17] spp_vf: " x-fn-spp-ml
2020-02-19 11:49 ` [spp] [PATCH v2 03/17] spp_mirror: " x-fn-spp-ml
2020-02-19 11:49 ` [spp] [PATCH v2 04/17] spp_pcap: " x-fn-spp-ml
2020-02-19 11:49 ` [spp] [PATCH v2 05/17] spp_primary: " x-fn-spp-ml
2020-02-19 11:49 ` [spp] [PATCH v2 06/17] spp_primary: add support of rte_flow x-fn-spp-ml
2020-02-19 11:49 ` [spp] [PATCH v2 07/17] spp_primary: add common function " x-fn-spp-ml
2020-02-19 11:49 ` [spp] [PATCH v2 08/17] spp_primary: add attribute " x-fn-spp-ml
2020-02-19 11:49 ` [spp] [PATCH v2 09/17] spp_primary: add patterns " x-fn-spp-ml
2020-02-19 11:49 ` [spp] [PATCH v2 10/17] spp_primary: add actions " x-fn-spp-ml
2020-02-19 11:49 ` [spp] [PATCH v2 11/17] bin: add parameter for hardrare offload x-fn-spp-ml
2020-02-19 11:49 ` [spp] [PATCH v2 12/17] cli: add support of hardware offload x-fn-spp-ml
2020-02-19 11:49 ` [spp] [PATCH v2 13/17] cli: add support of rte_flow in vf x-fn-spp-ml
2020-02-19 11:49 ` [spp] [PATCH v2 14/17] cli: add support of rte_flow in mirror x-fn-spp-ml
2020-02-19 11:49 ` [spp] [PATCH v2 15/17] cli: add support of rte_flow in nfv x-fn-spp-ml
2020-02-19 11:49 ` [spp] [PATCH v2 16/17] spp-ctl: add APIs for flow rules x-fn-spp-ml
2020-02-19 11:49 ` [spp] [PATCH v2 17/17] spp_nfv: add support of multi-queue x-fn-spp-ml
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=d614780b-4d66-1bcc-5f7a-e47434e3028e@gmail.com \
--to=yasufum.o@gmail.com \
--cc=ferruh.yigit@intel.com \
--cc=spp@dpdk.org \
--cc=x-fn-spp-ml@ntt-tx.co.jp \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).