From patchwork Tue Aug 15 16:50:42 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Zhang, Yuying" X-Patchwork-Id: 131458 X-Patchwork-Delegate: ferruh.yigit@amd.com Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id A5DA5425A3; Fri, 15 Sep 2023 10:47:27 +0200 (CEST) Received: from mails.dpdk.org (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 923F94067E; Fri, 15 Sep 2023 10:47:27 +0200 (CEST) Received: from mgamail.intel.com (mgamail.intel.com [134.134.136.31]) by mails.dpdk.org (Postfix) with ESMTP id 2A70F4067A for ; Fri, 15 Sep 2023 10:47:24 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1694767644; x=1726303644; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=1QwCy6PV79G9Zm/O+jBCY/Rin42OczZo85azITZV/ew=; b=VXv6TqjfJuZElsjQCt7BkDcQuBRnAVQVtQFes+RsLr4LLaeWh6CPTOLu w78Okac3QEEduopNphDevpllSLe2MsL2qo+7B8Aw73D0XgC9mETMaKPZD qzGVP1gztgKqCst6kJjOjMW0Wiotp8aCGiW4fBWQQltTq/j9Gf3TBwfGW TKP3krP52oZq4C1Ksl5aHtMKc3ZeNO6qZ/BM77kmLsWKV2YQsBjOBQwv9 9cRSw4AcaoeiG7hW6ouft5BsQG53f3u4Lpx7UuJl5/4wZx1MugRMB8OqI jzelBNccg7YMf3UU8IiSmgp2a/13xFOpI6oWjwftP8qS+lG4dUntkxTzP Q==; X-IronPort-AV: E=McAfee;i="6600,9927,10833"; a="443264997" X-IronPort-AV: E=Sophos;i="6.02,148,1688454000"; d="scan'208";a="443264997" Received: from orsmga007.jf.intel.com ([10.7.209.58]) by orsmga104.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 15 Sep 2023 01:47:23 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6600,9927,10833"; a="738254361" X-IronPort-AV: E=Sophos;i="6.02,148,1688454000"; d="scan'208";a="738254361" Received: from dpdk-pengyuan-mev.sh.intel.com ([10.67.119.128]) by orsmga007.jf.intel.com with ESMTP; 15 Sep 2023 01:47:21 -0700 From: "Zhang, Yuying" To: yuying.zhang@intel.com, dev@dpdk.org, qi.z.zhang@intel.com, beilei.xing@intel.com, jingjing.wu@intel.com Cc: mingxia.liu@intel.com, Wenjing Qiao Subject: [PATCH v4 1/9] net/cpfl: add json parser for rte flow pattern rules Date: Tue, 15 Aug 2023 16:50:42 +0000 Message-Id: <20230815165050.86595-2-yuying.zhang@intel.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20230815165050.86595-1-yuying.zhang@intel.com> References: <20230906093407.3635038-1-wenjing.qiao@intel.com> <20230815165050.86595-1-yuying.zhang@intel.com> MIME-Version: 1.0 X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org From: Wenjing Qiao Add devargs "flow_parser" for rte flow json parser which depends on json-c library. Example: -a ca:00.0,flow_parser="refpkg.json" Add json parser for rte flow pattern rules.The cpfl PMD supports utilizing a JSON config file to translate rte flow tokens into low level hardware resources. Signed-off-by: Wenjing Qiao --- doc/guides/nics/cpfl.rst | 30 + drivers/net/cpfl/cpfl_ethdev.c | 38 +- drivers/net/cpfl/cpfl_ethdev.h | 76 ++ drivers/net/cpfl/cpfl_flow_parser.c | 1302 +++++++++++++++++++++++++++ drivers/net/cpfl/cpfl_flow_parser.h | 167 ++++ drivers/net/cpfl/meson.build | 13 + 6 files changed, 1625 insertions(+), 1 deletion(-) create mode 100644 drivers/net/cpfl/cpfl_flow_parser.c create mode 100644 drivers/net/cpfl/cpfl_flow_parser.h diff --git a/doc/guides/nics/cpfl.rst b/doc/guides/nics/cpfl.rst index 83a18c3f2e..aae157f0df 100644 --- a/doc/guides/nics/cpfl.rst +++ b/doc/guides/nics/cpfl.rst @@ -128,12 +128,24 @@ Runtime Configuration -a BDF,representor=vf[0-3],representor=c1pf1 +- ``flow_parser`` (default ``not enabled``) + + The cpfl PMD supports utilizing a JSON config file to translate rte_flow tokens into + low-level hardware resources. + Using the ``devargs`` option ``flow_parser`` the user can specify the path + of a json file, for example:: + + -a ca:00.0,flow_parser="refpkg.json" + + Then the PMD will load json file for device ``ca:00.0``. + The parameter is optional. Driver compilation and testing ------------------------------ Refer to the document :doc:`build_and_test` for details. +The json-c library must be installed to use rte_flow. Features -------- @@ -164,3 +176,21 @@ Hairpin queue E2100 Series can loopback packets from RX port to TX port. This feature is called port-to-port or hairpin. Currently, the PMD only supports single port hairpin. + +Rte_flow +~~~~~~~~~~~~~ + +PMD uses a json file to direct CPF PMD to parse rte_flow tokens into +low level hardware resources. + +- Required Libraries + + * json-c (version 0.14+) + + * For Ubuntu, it can be installed using `apt install libjson-c-dev` + +- run testpmd with the json file + + .. code-block:: console + + dpdk-testpmd -c 0x3 -n 4 -a 0000:af:00.6,vport=[0],flow_parser="refpkg.json" -- -i diff --git a/drivers/net/cpfl/cpfl_ethdev.c b/drivers/net/cpfl/cpfl_ethdev.c index 189072ab33..54ae127cc3 100644 --- a/drivers/net/cpfl/cpfl_ethdev.c +++ b/drivers/net/cpfl/cpfl_ethdev.c @@ -21,6 +21,10 @@ #define CPFL_RX_SINGLE_Q "rx_single" #define CPFL_VPORT "vport" +#ifdef CPFL_FLOW_JSON_SUPPORT +#define CPFL_FLOW_PARSER "flow_parser" +#endif + rte_spinlock_t cpfl_adapter_lock; /* A list for all adapters, one adapter matches one PCI device */ struct cpfl_adapter_list cpfl_adapter_list; @@ -31,6 +35,9 @@ static const char * const cpfl_valid_args_first[] = { CPFL_TX_SINGLE_Q, CPFL_RX_SINGLE_Q, CPFL_VPORT, +#ifdef CPFL_FLOW_JSON_SUPPORT + CPFL_FLOW_PARSER, +#endif NULL }; @@ -1537,6 +1544,24 @@ parse_repr(const char *key __rte_unused, const char *value, void *args) return 0; } +#ifdef CPFL_FLOW_JSON_SUPPORT +static int +parse_file(const char *key, const char *value, void *args) +{ + char *name = args; + + if (strlen(value) > CPFL_FLOW_FILE_LEN - 1) { + PMD_DRV_LOG(ERR, "file path(%s) is too long.", value); + return -1; + } + + PMD_DRV_LOG(DEBUG, "value:\"%s\" for key:\"%s\"", value, key); + strlcpy(name, value, CPFL_FLOW_FILE_LEN); + + return 0; +} +#endif + static int cpfl_parse_devargs(struct rte_pci_device *pci_dev, struct cpfl_adapter_ext *adapter, bool first) { @@ -1585,7 +1610,18 @@ cpfl_parse_devargs(struct rte_pci_device *pci_dev, struct cpfl_adapter_ext *adap &adapter->base.is_rx_singleq); if (ret != 0) goto fail; - +#ifdef CPFL_FLOW_JSON_SUPPORT + if (rte_kvargs_get(kvlist, CPFL_FLOW_PARSER)) { + ret = rte_kvargs_process(kvlist, CPFL_FLOW_PARSER, + &parse_file, cpfl_args->flow_parser); + if (ret) { + PMD_DRV_LOG(ERR, "Failed to parser flow_parser, ret: %d", ret); + goto fail; + } + } else { + cpfl_args->flow_parser[0] = '\0'; + } +#endif fail: rte_kvargs_free(kvlist); return ret; diff --git a/drivers/net/cpfl/cpfl_ethdev.h b/drivers/net/cpfl/cpfl_ethdev.h index d0dcc0cc05..383dbd14c6 100644 --- a/drivers/net/cpfl/cpfl_ethdev.h +++ b/drivers/net/cpfl/cpfl_ethdev.h @@ -77,6 +77,11 @@ #define CPFL_VPORT_LAN_PF 0 #define CPFL_VPORT_LAN_VF 1 +#define CPFL_FLOW_FILE_LEN 100 +#define CPFL_INVALID_HW_ID UINT16_MAX +#define CPFL_META_CHUNK_LENGTH 1024 +#define CPFL_META_LENGTH 32 + /* bit[15:14] type * bit[13] host/accelerator core * bit[12] apf/cpf @@ -99,6 +104,7 @@ struct cpfl_devargs { uint16_t req_vport_nb; uint8_t repr_args_num; struct rte_eth_devargs repr_args[CPFL_REPR_ARG_NUM_MAX]; + char flow_parser[CPFL_FLOW_FILE_LEN]; }; struct p2p_queue_chunks_info { @@ -165,6 +171,20 @@ struct cpfl_repr { bool func_up; /* If the represented function is up */ }; +struct cpfl_metadata_chunk { + int type; + uint8_t data[CPFL_META_CHUNK_LENGTH]; +}; + +/** + * It is driver's responsibility to simlulate a metadata buffer which + * can be used as data source to fill the key of a flow rule. + */ +struct cpfl_metadata { + int length; + struct cpfl_metadata_chunk chunks[CPFL_META_LENGTH]; +}; + struct cpfl_adapter_ext { TAILQ_ENTRY(cpfl_adapter_ext) next; struct idpf_adapter base; @@ -185,6 +205,8 @@ struct cpfl_adapter_ext { rte_spinlock_t repr_lock; struct rte_hash *repr_allowlist_hash; + + struct cpfl_metadata meta; }; TAILQ_HEAD(cpfl_adapter_list, cpfl_adapter_ext); @@ -211,4 +233,58 @@ int cpfl_cc_vport_info_get(struct cpfl_adapter_ext *adapter, #define CPFL_DEV_TO_ITF(dev) \ ((struct cpfl_itf *)((dev)->data->dev_private)) +static inline uint16_t +cpfl_get_port_id(struct cpfl_itf *itf) +{ + if (!itf) + return CPFL_INVALID_HW_ID; + + if (itf->type == CPFL_ITF_TYPE_VPORT) { + struct cpfl_vport *vport = (void *)itf; + + return vport->base.devarg_id; + } + + return CPFL_INVALID_HW_ID; +} + +static inline uint16_t +cpfl_get_vsi_id(struct cpfl_itf *itf) +{ + struct cpfl_adapter_ext *adapter = itf->adapter; + struct cpfl_vport_info *info; + uint32_t vport_id; + int ret; + struct cpfl_vport_id vport_identity; + + if (!itf) + return CPFL_INVALID_HW_ID; + + if (itf->type == CPFL_ITF_TYPE_REPRESENTOR) { + struct cpfl_repr *repr = (void *)itf; + + return repr->vport_info->vport.info.vsi_id; + } else if (itf->type == CPFL_ITF_TYPE_VPORT) { + vport_id = ((struct cpfl_vport *)itf)->base.vport_id; + + vport_identity.func_type = CPCHNL2_FUNC_TYPE_PF; + /* host: CPFL_HOST0_CPF_ID, acc: CPFL_ACC_CPF_ID */ + vport_identity.pf_id = CPFL_ACC_CPF_ID; + vport_identity.vf_id = 0; + vport_identity.vport_id = vport_id; + ret = rte_hash_lookup_data(adapter->vport_map_hash, + &vport_identity, + (void **)&info); + if (ret < 0) { + PMD_DRV_LOG(ERR, "vport id not exist"); + goto err; + } + + return info->vport.info.vsi_id; + } + +err: + return CPFL_INVALID_HW_ID; +} + #endif /* _CPFL_ETHDEV_H_ */ diff --git a/drivers/net/cpfl/cpfl_flow_parser.c b/drivers/net/cpfl/cpfl_flow_parser.c new file mode 100644 index 0000000000..630ce8a227 --- /dev/null +++ b/drivers/net/cpfl/cpfl_flow_parser.c @@ -0,0 +1,1302 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2023 Intel Corporation + */ + +#include +#include +#include + +#include "cpfl_flow_parser.h" +#include "cpfl_ethdev.h" +#include "rte_malloc.h" + +static enum rte_flow_item_type +cpfl_get_item_type_by_str(const char *type) +{ + if (strcmp(type, "eth") == 0) + return RTE_FLOW_ITEM_TYPE_ETH; + else if (strcmp(type, "ipv4") == 0) + return RTE_FLOW_ITEM_TYPE_IPV4; + else if (strcmp(type, "tcp") == 0) + return RTE_FLOW_ITEM_TYPE_TCP; + else if (strcmp(type, "udp") == 0) + return RTE_FLOW_ITEM_TYPE_UDP; + else if (strcmp(type, "vxlan") == 0) + return RTE_FLOW_ITEM_TYPE_VXLAN; + else if (strcmp(type, "icmp") == 0) + return RTE_FLOW_ITEM_TYPE_ICMP; + else if (strcmp(type, "vlan") == 0) + return RTE_FLOW_ITEM_TYPE_VLAN; + + PMD_DRV_LOG(ERR, "Not support this type: %s.", type); + return RTE_FLOW_ITEM_TYPE_VOID; +} + +static const char * +cpfl_json_object_to_string(json_object *object, const char *name) +{ + json_object *subobject; + + if (!object) { + PMD_DRV_LOG(ERR, "object doesn't exist."); + return NULL; + } + subobject = json_object_object_get(object, name); + if (!subobject) { + PMD_DRV_LOG(ERR, "%s doesn't exist.", name); + return NULL; + } + + return json_object_get_string(subobject); +} + +static int +cpfl_json_object_to_uint16(json_object *object, const char *name, uint16_t *value) +{ + json_object *subobject; + + if (!object) { + PMD_DRV_LOG(ERR, "object doesn't exist."); + return -EINVAL; + } + subobject = json_object_object_get(object, name); + if (!subobject) { + PMD_DRV_LOG(ERR, "%s doesn't exist.", name); + return -EINVAL; + } + *value = json_object_get_int(subobject); + + return 0; +} + +static int +cpfl_json_object_to_uint32(json_object *object, const char *name, uint32_t *value) +{ + json_object *subobject; + + if (!object) { + PMD_DRV_LOG(ERR, "object doesn't exist."); + return -EINVAL; + } + subobject = json_object_object_get(object, name); + if (!subobject) { + PMD_DRV_LOG(ERR, "%s doesn't exist.", name); + return -EINVAL; + } + *value = json_object_get_int64(subobject); + + return 0; +} + +static int +cpfl_flow_js_pattern_key_attr(json_object *ob_pr_key_attrs, struct cpfl_flow_js_pr *js_pr) +{ + int i, len; + struct cpfl_flow_js_pr_key_attr *attr; + + len = json_object_array_length(ob_pr_key_attrs); + js_pr->key.attributes = rte_malloc(NULL, sizeof(struct cpfl_flow_js_pr_key_attr), 0); + if (!js_pr->key.attributes) { + PMD_DRV_LOG(ERR, "Failed to alloc memory."); + return -ENOMEM; + } + js_pr->key.attr_size = len; + attr = js_pr->key.attributes; + for (i = 0; i < len; i++) { + json_object *object; + const char *name; + uint16_t value = 0; + int ret; + + object = json_object_array_get_idx(ob_pr_key_attrs, i); + name = cpfl_json_object_to_string(object, "Name"); + if (!name) { + PMD_DRV_LOG(ERR, "Can not parse string 'Name'."); + goto err; + } + ret = cpfl_json_object_to_uint16(object, "Value", &value); + if (ret < 0) { + PMD_DRV_LOG(ERR, "Can not parse 'value'."); + goto err; + } + if (strcmp(name, "ingress") == 0) { + attr->ingress = value; + } else if (strcmp(name, "egress") == 0) { + attr->egress = value; + } else { + /* TODO: more... */ + PMD_DRV_LOG(ERR, "Not support attr name: %s.", name); + goto err; + } + } + + return 0; +err: + rte_free(js_pr->key.attributes); + return -EINVAL; +} + +static int +cpfl_flow_js_pattern_key_proto_field(json_object *ob_fields, + struct cpfl_flow_js_pr_key_proto *js_field) +{ + int len, i; + + if (!ob_fields) + return 0; + len = json_object_array_length(ob_fields); + if (len == 0) + return 0; + js_field->fields_size = len; + js_field->fields = + rte_malloc(NULL, sizeof(struct cpfl_flow_js_pr_key_proto_field) * len, 0); + if (!js_field->fields) { + PMD_DRV_LOG(ERR, "Failed to alloc memory."); + return -ENOMEM; + } + for (i = 0; i < len; i++) { + json_object *object; + const char *name, *mask; + + object = json_object_array_get_idx(ob_fields, i); + name = cpfl_json_object_to_string(object, "name"); + if (!name) { + PMD_DRV_LOG(ERR, "Can not parse string 'name'."); + goto err; + } + if (strlen(name) > CPFL_FLOW_JSON_STR_SIZE_MAX) { + PMD_DRV_LOG(ERR, "The 'name' is too long."); + goto err; + } + memcpy(js_field->fields[i].name, name, strlen(name)); + + if (js_field->type == RTE_FLOW_ITEM_TYPE_ETH || + js_field->type == RTE_FLOW_ITEM_TYPE_IPV4) { + mask = cpfl_json_object_to_string(object, "mask"); + if (!mask) { + PMD_DRV_LOG(ERR, "Can not parse string 'mask'."); + goto err; + } + if (strlen(mask) > CPFL_FLOW_JSON_STR_SIZE_MAX) { + PMD_DRV_LOG(ERR, "The 'mask' is too long."); + goto err; + } + memcpy(js_field->fields[i].mask, mask, strlen(mask)); + } else { + uint32_t mask_32b; + int ret; + + ret = cpfl_json_object_to_uint32(object, "mask", &mask_32b); + if (ret < 0) { + PMD_DRV_LOG(ERR, "Can not parse uint32 'mask'."); + goto err; + } + js_field->fields[i].mask_32b = mask_32b; + } + } + + return 0; + +err: + rte_free(js_field->fields); + return -EINVAL; +} + +static int +cpfl_flow_js_pattern_key_proto(json_object *ob_pr_key_protos, struct cpfl_flow_js_pr *js_pr) +{ + int len, i, ret; + + len = json_object_array_length(ob_pr_key_protos); + if (len == 0) + return 0; + js_pr->key.proto_size = len; + js_pr->key.protocols = rte_malloc(NULL, sizeof(struct cpfl_flow_js_pr_key_proto) * len, 0); + if (!js_pr->key.protocols) { + PMD_DRV_LOG(ERR, "Failed to alloc memory."); + return -ENOMEM; + } + + for (i = 0; i < len; i++) { + json_object *object, *ob_fields; + const char *type; + enum rte_flow_item_type item_type; + + object = json_object_array_get_idx(ob_pr_key_protos, i); + /* pr->key->proto->type */ + type = cpfl_json_object_to_string(object, "type"); + if (!type) { + PMD_DRV_LOG(ERR, "Can not parse string 'type'."); + goto err; + } + item_type = cpfl_get_item_type_by_str(type); + if (item_type == RTE_FLOW_ITEM_TYPE_VOID) + goto err; + js_pr->key.protocols[i].type = item_type; + /* pr->key->proto->fields */ + ob_fields = json_object_object_get(object, "fields"); + ret = cpfl_flow_js_pattern_key_proto_field(ob_fields, + &js_pr->key.protocols[i]); + if (ret < 0) + goto err; + } + + return 0; + +err: + rte_free(js_pr->key.protocols); + return -EINVAL; +} + +static int +cpfl_flow_js_pattern_act_fv_proto(json_object *ob_value, struct cpfl_flow_js_fv *js_fv) +{ + uint16_t layer = 0, offset = 0, mask = 0; + const char *header; + enum rte_flow_item_type type; + int ret; + + ret = cpfl_json_object_to_uint16(ob_value, "layer", &layer); + if (ret < 0) { + PMD_DRV_LOG(ERR, "Can not parse 'value'."); + return -EINVAL; + } + + header = cpfl_json_object_to_string(ob_value, "header"); + if (!header) { + PMD_DRV_LOG(ERR, "Can not parse string 'header'."); + return -EINVAL; + } + ret = cpfl_json_object_to_uint16(ob_value, "offset", &offset); + if (ret < 0) { + PMD_DRV_LOG(ERR, "Can not parse 'offset'."); + return -EINVAL; + } + ret = cpfl_json_object_to_uint16(ob_value, "mask", &mask); + if (ret < 0) { + PMD_DRV_LOG(ERR, "Can not parse 'mask'."); + return -EINVAL; + } + type = cpfl_get_item_type_by_str(header); + if (type == RTE_FLOW_ITEM_TYPE_VOID) + return -EINVAL; + js_fv->proto.layer = layer; + js_fv->proto.offset = offset; + js_fv->proto.mask = mask; + js_fv->proto.header = type; + + return 0; +} + +static int +cpfl_flow_js_pattern_act_fv_metadata(json_object *ob_value, struct cpfl_flow_js_fv *js_fv) +{ + int ret; + + ret = cpfl_json_object_to_uint16(ob_value, "type", &js_fv->meta.type); + if (ret < 0) { + PMD_DRV_LOG(ERR, "Can not parse 'size'."); + return ret; + } + ret = cpfl_json_object_to_uint16(ob_value, "offset", &js_fv->meta.offset); + if (ret < 0) { + PMD_DRV_LOG(ERR, "Can not parse 'size'."); + return ret; + } + ret = cpfl_json_object_to_uint16(ob_value, "mask", &js_fv->meta.mask); + if (ret < 0) { + PMD_DRV_LOG(ERR, "Can not parse 'size'."); + return ret; + } + + return 0; +} + +static int +cpfl_flow_js_pattern_act_fv(json_object *ob_fvs, struct cpfl_flow_js_pr_action *js_act) +{ + int len, i; + + len = json_object_array_length(ob_fvs); + if (len == 0) + return 0; + js_act->sem.fv = rte_malloc(NULL, sizeof(struct cpfl_flow_js_fv) * len, 0); + if (!js_act->sem.fv) { + PMD_DRV_LOG(ERR, "Failed to alloc memory."); + return -ENOMEM; + } + js_act->sem.fv_size = len; + for (i = 0; i < len; i++) { + struct cpfl_flow_js_fv *js_fv; + json_object *object, *ob_value; + uint16_t offset = 0; + const char *type; + int ret; + + js_fv = &js_act->sem.fv[i]; + object = json_object_array_get_idx(ob_fvs, i); + ret = cpfl_json_object_to_uint16(object, "offset", &offset); + if (ret < 0) { + PMD_DRV_LOG(ERR, "Can not parse 'offset'."); + goto err; + } + js_fv->offset = offset; + + type = cpfl_json_object_to_string(object, "type"); + if (!type) { + PMD_DRV_LOG(ERR, "Can not parse string 'type'."); + goto err; + } + ob_value = json_object_object_get(object, "value"); + if (strcmp(type, "immediate") == 0) { + js_fv->type = CPFL_FV_TYPE_IMMEDIATE; + js_fv->immediate = json_object_get_int(ob_value); + } else if (strcmp(type, "metadata") == 0) { + js_fv->type = CPFL_FV_TYPE_METADATA; + cpfl_flow_js_pattern_act_fv_metadata(ob_value, js_fv); + } else if (strcmp(type, "protocol") == 0) { + js_fv->type = CPFL_FV_TYPE_PROTOCOL; + cpfl_flow_js_pattern_act_fv_proto(ob_value, js_fv); + } else { + PMD_DRV_LOG(ERR, "Not support this type: %s.", type); + goto err; + } + } + + return 0; + +err: + rte_free(js_act->sem.fv); + return -EINVAL; +} + +static int +cpfl_flow_js_pattern_per_act(json_object *ob_per_act, struct cpfl_flow_js_pr_action *js_act) +{ + const char *type; + int ret; + + /* pr->actions->type */ + type = cpfl_json_object_to_string(ob_per_act, "type"); + if (!type) { + PMD_DRV_LOG(ERR, "Can not parse string 'type'."); + return -EINVAL; + } + /* pr->actions->data */ + if (strcmp(type, "sem") == 0) { + json_object *ob_fvs, *ob_sem; + + js_act->type = CPFL_JS_PR_ACTION_TYPE_SEM; + ob_sem = json_object_object_get(ob_per_act, "data"); + ret = cpfl_json_object_to_uint16(ob_sem, "profile", + &js_act->sem.prof); + if (ret < 0) { + PMD_DRV_LOG(ERR, "Can not parse 'profile'."); + return -EINVAL; + } + ret = cpfl_json_object_to_uint16(ob_sem, "subprofile", + &js_act->sem.subprof); + if (ret < 0) { + PMD_DRV_LOG(ERR, "Can not parse 'subprofile'."); + return -EINVAL; + } + ret = cpfl_json_object_to_uint16(ob_sem, "keysize", + &js_act->sem.keysize); + if (ret < 0) { + PMD_DRV_LOG(ERR, "Can not parse 'keysize'."); + return -EINVAL; + } + ob_fvs = json_object_object_get(ob_sem, "fieldvectors"); + ret = cpfl_flow_js_pattern_act_fv(ob_fvs, js_act); + if (ret < 0) + return ret; + } else { + PMD_DRV_LOG(ERR, "Not support this type: %s.", type); + return -EINVAL; + } + + return 0; +} + +static int +cpfl_flow_js_pattern_act(json_object *ob_pr_acts, struct cpfl_flow_js_pr *js_pr) +{ + int i, len, ret; + + len = json_object_array_length(ob_pr_acts); + if (len == 0) + return 0; + js_pr->actions = rte_malloc(NULL, sizeof(struct cpfl_flow_js_pr_action) * len, 0); + if (!js_pr->actions) { + PMD_DRV_LOG(ERR, "Failed to alloc memory."); + return -ENOMEM; + } + js_pr->actions_size = len; + for (i = 0; i < len; i++) { + struct cpfl_flow_js_pr_action *js_act; + json_object *object; + + object = json_object_array_get_idx(ob_pr_acts, i); + js_act = &js_pr->actions[i]; + ret = cpfl_flow_js_pattern_per_act(object, js_act); + if (ret < 0) { + rte_free(js_pr->actions); + PMD_DRV_LOG(ERR, "Can not parse pattern action."); + return -EINVAL; + } + } + + return 0; +} + +/** + * The patterns object array defines a set of rules directing the PMD to match sequences of + * rte_flow protocol headers and translate them into profile/field vectors for each pipeline + * stage. This object is mandatory. + */ +static int +cpfl_flow_js_pattern_rule(json_object *ob_root, struct cpfl_flow_js_parser *parser) +{ + json_object *ob_prs; + int i, len; + + /* Pattern Rules */ + ob_prs = json_object_object_get(ob_root, "patterns"); + if (!ob_prs) { + PMD_DRV_LOG(ERR, "The patterns is mandatory."); + return -EINVAL; + } + + len = json_object_array_length(ob_prs); + if (len == 0) + return 0; + parser->patterns = rte_malloc(NULL, sizeof(struct cpfl_flow_js_pr) * len, 0); + if (!parser->patterns) { + PMD_DRV_LOG(ERR, "Failed to alloc memory."); + return -ENOMEM; + } + parser->pr_size = len; + for (i = 0; i < len; i++) { + json_object *object; + json_object *ob_pr_actions; + json_object *ob_pr_key; + json_object *ob_pr_key_protos; + json_object *ob_pr_key_attrs; + int ret; + + object = json_object_array_get_idx(ob_prs, i); + /* pr->key */ + ob_pr_key = json_object_object_get(object, "key"); + /* pr->key->protocols */ + ob_pr_key_protos = json_object_object_get(ob_pr_key, "protocols"); + ret = cpfl_flow_js_pattern_key_proto(ob_pr_key_protos, &parser->patterns[i]); + if (ret < 0) { + PMD_DRV_LOG(ERR, "Can not parse key->protocols."); + goto err; + } + /* pr->key->attributes */ + ob_pr_key_attrs = json_object_object_get(ob_pr_key, "attributes"); + ret = cpfl_flow_js_pattern_key_attr(ob_pr_key_attrs, &parser->patterns[i]); + if (ret < 0) { + PMD_DRV_LOG(ERR, "Can not parse key->attributes."); + goto err; + } + /* pr->actions */ + ob_pr_actions = json_object_object_get(object, "actions"); + ret = cpfl_flow_js_pattern_act(ob_pr_actions, &parser->patterns[i]); + if (ret < 0) { + PMD_DRV_LOG(ERR, "Can not parse pattern action."); + goto err; + } + } + + return 0; + +err: + rte_free(parser->patterns); + return -EINVAL; +} + +static int +cpfl_parser_init(json_object *ob_root, struct cpfl_flow_js_parser *parser) +{ + int ret = 0; + + ret = cpfl_flow_js_pattern_rule(ob_root, parser); + if (ret < 0) { + PMD_DRV_LOG(ERR, "parse pattern_rule failed."); + return ret; + } + + return 0; +} + +int +cpfl_parser_create(struct cpfl_flow_js_parser **flow_parser, const char *filename) +{ + struct cpfl_flow_js_parser *parser; + json_object *root; + int ret; + + parser = rte_zmalloc("flow_parser", sizeof(struct cpfl_flow_js_parser), 0); + if (!parser) { + PMD_DRV_LOG(ERR, "Not enough memory to create flow parser."); + return -ENOMEM; + } + root = json_object_from_file(filename); + if (!root) { + PMD_DRV_LOG(ERR, "Can not load JSON file: %s.", filename); + rte_free(parser); + return -EINVAL; + } + ret = cpfl_parser_init(root, parser); + if (ret < 0) { + PMD_DRV_LOG(ERR, "parser init failed."); + goto free_parser; + } + *flow_parser = parser; + ret = json_object_put(root); + if (ret != 1) { + PMD_DRV_LOG(ERR, "Free json_object failed."); + return -EINVAL; + } + + return 0; +free_parser: + rte_free(parser); + return -EINVAL; +} + +static void +cpfl_parser_free_pr_action(struct cpfl_flow_js_pr_action *pr_act) +{ + if (pr_act->type == CPFL_JS_PR_ACTION_TYPE_SEM) + rte_free(pr_act->sem.fv); +} + +int +cpfl_parser_destroy(struct cpfl_flow_js_parser *parser) +{ + int i, j; + + if (!parser) + return 0; + + for (i = 0; i < parser->pr_size; i++) { + struct cpfl_flow_js_pr *pattern = &parser->patterns[i]; + + if (!pattern) + continue; + for (j = 0; j < pattern->key.proto_size; j++) + rte_free(pattern->key.protocols[j].fields); + rte_free(pattern->key.protocols); + rte_free(pattern->key.attributes); + + for (j = 0; j < pattern->actions_size; j++) { + struct cpfl_flow_js_pr_action *pr_act; + + pr_act = &pattern->actions[j]; + cpfl_parser_free_pr_action(pr_act); + } + rte_free(pattern->actions); + } + rte_free(parser->patterns); + rte_free(parser); + + return 0; +} + +static int +cpfl_get_items_length(const struct rte_flow_item *items) +{ + int length = 0; + const struct rte_flow_item *item = items; + + while ((item + length++)->type != RTE_FLOW_ITEM_TYPE_END) + continue; + return length; +} + +static int +cpfl_parse_fv_protocol(struct cpfl_flow_js_fv *js_fv, const struct rte_flow_item *items, + uint16_t offset, uint8_t *fv) +{ + uint16_t v_layer, v_offset, v_mask; + enum rte_flow_item_type v_header; + int j, layer, length; + uint16_t temp_fv; + + length = cpfl_get_items_length(items); + v_layer = js_fv->proto.layer; + v_header = js_fv->proto.header; + v_offset = js_fv->proto.offset; + v_mask = js_fv->proto.mask; + layer = 0; + for (j = 0; j < length - 1; j++) { + if (items[j].type == v_header) { + if (layer == v_layer) { + /* copy out 16 bits from offset */ + const uint8_t *pointer; + + pointer = &(((const uint8_t *)(items[j].spec))[v_offset]); + temp_fv = ntohs((*((const uint16_t *)pointer)) & v_mask); + fv[2 * offset] = (uint8_t)(temp_fv >> 8); + fv[2 * offset + 1] = (uint8_t)(temp_fv & 0x00ff); + break; + } + layer++; + } /* TODO: more type... */ + } + + return 0; +} + +static int +cpfl_parse_fieldvectors(struct cpfl_itf *itf, struct cpfl_flow_js_fv *js_fvs, int size, + uint8_t *fv, const struct rte_flow_item *items) +{ + int i, ret; + + for (i = 0; i < size; i++) { + uint16_t offset, temp_fv, value_int; + enum cpfl_flow_js_fv_type type; + struct cpfl_flow_js_fv *js_fv; + + js_fv = &js_fvs[i]; + offset = js_fv->offset; + type = js_fv->type; + if (type == CPFL_FV_TYPE_IMMEDIATE) { + value_int = js_fv->immediate; + temp_fv = (value_int << 8) & 0xff00; + fv[2 * offset] = (uint8_t)(temp_fv >> 8); + fv[2 * offset + 1] = (uint8_t)(temp_fv & 0x00ff); + } else if (type == CPFL_FV_TYPE_METADATA) { + uint16_t type, v_offset, mask; + + type = js_fv->meta.type; + v_offset = js_fv->meta.offset; + mask = js_fv->meta.mask; + temp_fv = cpfl_metadata_read16(&itf->adapter->meta, type, v_offset) & mask; + fv[2 * offset] = (uint8_t)(temp_fv & 0x00ff); + fv[2 * offset + 1] = (uint8_t)(temp_fv >> 8); + } else if (type == CPFL_FV_TYPE_PROTOCOL) { + ret = cpfl_parse_fv_protocol(js_fv, items, offset, fv); + if (ret) + return ret; + } else { + PMD_DRV_LOG(DEBUG, "not support this type: %d.", type); + return -EINVAL; + } + } + + return 0; +} + +static int +cpfl_parse_pr_actions(struct cpfl_itf *itf, + struct cpfl_flow_js_pr_action *actions, + int size, + const struct rte_flow_item *items, + const struct rte_flow_attr *attr, + struct cpfl_flow_pr_action *pr_action) +{ + int i, ret; + + for (i = 0; i < size; i++) { + struct cpfl_flow_js_pr_action *pr_act; + enum cpfl_flow_pr_action_type type; + + pr_act = &actions[i]; + /* pr->actions->type */ + type = pr_act->type; + /* pr->actions->data */ + if (attr->group == 1 && type == CPFL_JS_PR_ACTION_TYPE_SEM) { + struct cpfl_flow_js_pr_action_sem *sem = &pr_act->sem; + + pr_action->type = CPFL_JS_PR_ACTION_TYPE_SEM; + pr_action->sem.prof = sem->prof; + pr_action->sem.subprof = sem->subprof; + pr_action->sem.keysize = sem->keysize; + memset(pr_action->sem.cpfl_flow_pr_fv, 0, + sizeof(pr_action->sem.cpfl_flow_pr_fv)); + ret = cpfl_parse_fieldvectors(itf, sem->fv, sem->fv_size, + pr_action->sem.cpfl_flow_pr_fv, items); + return ret; + } else if (attr->group > 4 || attr->group == 0) { + return -EPERM; + } + } + + return 0; +} + +static int +cpfl_check_eth_mask(const char *mask, struct rte_ether_addr addr) +{ + int i, ret; + struct rte_ether_addr mask_bytes; + + ret = rte_ether_unformat_addr(mask, &mask_bytes); + if (ret < 0) { + PMD_DRV_LOG(ERR, "translate mac address from string to rte_ether_addr failed."); + return -EINVAL; + } + /* validate eth mask addr if match */ + for (i = 0; i < RTE_ETHER_ADDR_LEN; i++) { + if (mask_bytes.addr_bytes[i] != addr.addr_bytes[i]) + return -EINVAL; + } + + return 0; +} + +static int +cpfl_check_ipv4_mask(const char *mask, rte_be32_t addr) +{ + uint32_t out_addr; + + /* 0: success; -EINVAL: invalid; -ENOTSUP: fail */ + int ret = inet_pton(AF_INET, mask, &out_addr); + + if (ret < 0) + return -EINVAL; + /* validate ipv4 mask addr if match */ + if (out_addr != addr) + return -EINVAL; + + return 0; +} + +static int +cpfl_check_eth(struct cpfl_flow_js_pr_key_proto *proto, const struct rte_flow_item_eth *eth_mask) +{ + int field_size, j; + int flag_dst_addr, flag_src_addr, flag_ether_type; + struct cpfl_flow_js_pr_key_proto_field *field; + + if (!proto) + return 0; + field_size = proto->fields_size; + if (field_size != 0 && !eth_mask) + return -EINVAL; + + if (field_size == 0 && eth_mask) + return -EINVAL; + + if (field_size == 0 && !eth_mask) + return 0; + + flag_dst_addr = false; + flag_src_addr = false; + flag_ether_type = false; + for (j = 0; j < field_size; j++) { + const char *name, *s_mask; + + field = &proto->fields[j]; + /* match: rte_flow_item_eth.dst, more see Field Mapping + */ + name = field->name; + /* match: rte_flow_item->mask */ + if (strcmp(name, "src_addr") == 0) { + s_mask = field->mask; + if (cpfl_check_eth_mask(s_mask, eth_mask->src) < 0) + return -EINVAL; + flag_src_addr = true; + } else if (strcmp(name, "dst_addr") == 0) { + s_mask = field->mask; + if (cpfl_check_eth_mask(s_mask, eth_mask->dst) < 0) + return -EINVAL; + flag_dst_addr = true; + } else if (strcmp(name, "ether_type") == 0) { + uint16_t mask = (uint16_t)field->mask_32b; + + if (mask != eth_mask->type) + return -EINVAL; + flag_ether_type = true; + } else { + /* TODO: more type... */ + PMD_DRV_LOG(ERR, "not support this name."); + return -EINVAL; + } + } + if (!flag_src_addr) { + if (strcmp((const char *)eth_mask->src.addr_bytes, "\x00\x00\x00\x00\x00\x00") != 0) + return -EINVAL; + } + if (!flag_dst_addr) { + if (strcmp((const char *)eth_mask->dst.addr_bytes, "\x00\x00\x00\x00\x00\x00") != 0) + return -EINVAL; + } + if (!flag_ether_type) { + if (eth_mask->hdr.ether_type != (rte_be16_t)0) + return -EINVAL; + } + + return 0; +} + +static int +cpfl_check_ipv4(struct cpfl_flow_js_pr_key_proto *proto, const struct rte_flow_item_ipv4 *ipv4_mask) +{ + int field_size, j; + int flag_next_proto_id, flag_src_addr, flag_dst_addr; + struct cpfl_flow_js_pr_key_proto_field *field; + + if (!proto) + return 0; + + field_size = proto->fields_size; + if (field_size != 0 && !ipv4_mask) + return -EINVAL; + + if (field_size == 0 && ipv4_mask) + return -EINVAL; + + if (field_size == 0 && !ipv4_mask) + return 0; + + flag_dst_addr = false; + flag_src_addr = false; + flag_next_proto_id = false; + for (j = 0; j < field_size; j++) { + const char *name; + + field = &proto->fields[j]; + name = field->name; + if (strcmp(name, "src_addr") == 0) { + const char *mask; + + mask = field->mask; + if (cpfl_check_ipv4_mask(mask, ipv4_mask->hdr.src_addr) < 0) + return -EINVAL; + flag_src_addr = true; + } else if (strcmp(name, "dst_addr") == 0) { + const char *mask; + + mask = field->mask; + if (cpfl_check_ipv4_mask(mask, ipv4_mask->hdr.dst_addr) < 0) + return -EINVAL; + flag_dst_addr = true; + } else if (strcmp(name, "next_proto_id") == 0) { + uint8_t mask; + + mask = (uint8_t)field->mask_32b; + if (mask != ipv4_mask->hdr.next_proto_id) + return -EINVAL; + flag_next_proto_id = true; + } else { + PMD_DRV_LOG(ERR, "not support this name."); + return -EINVAL; + } + } + if (!flag_src_addr) { + if (ipv4_mask->hdr.src_addr != (rte_be32_t)0) + return -EINVAL; + } + if (!flag_dst_addr) { + if (ipv4_mask->hdr.dst_addr != (rte_be32_t)0) + return -EINVAL; + } + if (!flag_next_proto_id) { + if (ipv4_mask->hdr.next_proto_id != (uint8_t)0) + return -EINVAL; + } + + return 0; +} + +static int +cpfl_check_tcp(struct cpfl_flow_js_pr_key_proto *proto, const struct rte_flow_item_tcp *tcp_mask) +{ + int field_size, j; + int flag_src_port, flag_dst_port; + struct cpfl_flow_js_pr_key_proto_field *field; + + if (!proto) + return 0; + + field_size = proto->fields_size; + if (field_size != 0 && !tcp_mask) + return -EINVAL; + + if (field_size == 0 && tcp_mask) + return -EINVAL; + + if (field_size == 0 && !tcp_mask) + return 0; + + flag_src_port = false; + flag_dst_port = false; + for (j = 0; j < field_size; j++) { + const char *name; + uint16_t mask; + + field = &proto->fields[j]; + name = field->name; + mask = (uint16_t)field->mask_32b; + if (strcmp(name, "src_port") == 0) { + if (tcp_mask->hdr.src_port != mask) + return -EINVAL; + flag_src_port = true; + } else if (strcmp(name, "dst_port") == 0) { + if (tcp_mask->hdr.dst_port != mask) + return -EINVAL; + flag_dst_port = true; + } else { + PMD_DRV_LOG(ERR, "not support this name."); + return -EINVAL; + } + } + if (!flag_src_port) { + if (tcp_mask->hdr.src_port != (rte_be16_t)0) + return -EINVAL; + } + if (!flag_dst_port) { + if (tcp_mask->hdr.dst_port != (rte_be16_t)0) + return -EINVAL; + } + + return 0; +} + +static int +cpfl_check_udp(struct cpfl_flow_js_pr_key_proto *proto, const struct rte_flow_item_udp *udp_mask) +{ + int field_size, j; + bool flag_src_port, flag_dst_port; + struct cpfl_flow_js_pr_key_proto_field *field; + + if (!proto) + return 0; + field_size = proto->fields_size; + if (field_size != 0 && !udp_mask) + return -EINVAL; + if (field_size == 0 && udp_mask) + return -EINVAL; + if (field_size == 0 && !udp_mask) + return 0; + flag_src_port = false; + flag_dst_port = false; + for (j = 0; j < field_size; j++) { + const char *name; + uint16_t mask; + + field = &proto->fields[j]; + /* match: rte_flow_item_eth.dst */ + name = field->name; /* match: rte_flow_item->mask */ + mask = (uint16_t)field->mask_32b; + if (strcmp(name, "src_port") == 0) { + if (udp_mask->hdr.src_port != mask) + return -EINVAL; + flag_src_port = true; + } else if (strcmp(name, "dst_port") == 0) { + if (udp_mask->hdr.dst_port != mask) + return -EINVAL; + flag_dst_port = true; + } else { + PMD_DRV_LOG(ERR, "not support this name: %s.", name); + return -EINVAL; + } + } + if (!flag_src_port) { + if (udp_mask->hdr.src_port != (rte_be16_t)0) + return -EINVAL; + } + if (!flag_dst_port) { + if (udp_mask->hdr.dst_port != (rte_be16_t)0) + return -EINVAL; + } + + return 0; +} + +static int +cpfl_check_vxlan(struct cpfl_flow_js_pr_key_proto *proto, + const struct rte_flow_item_vxlan *vxlan_mask) +{ + int field_size, j; + struct cpfl_flow_js_pr_key_proto_field *field; + + if (!proto) + return 0; + field_size = proto->fields_size; + if (field_size != 0 && !vxlan_mask) + return -EINVAL; + if (field_size == 0 && vxlan_mask) + return -EINVAL; + if (field_size == 0 && !vxlan_mask) + return 0; + for (j = 0; j < field_size; j++) { + const char *name; + int64_t mask; + + field = &proto->fields[j]; + name = field->name; + /* match: rte_flow_item->mask */ + mask = (int64_t)field->mask_32b; + if (strcmp(name, "vx_vni") == 0) { + if ((int64_t)RTE_BE32(vxlan_mask->hdr.vx_vni) != mask) + return -EINVAL; + } else { + PMD_DRV_LOG(ERR, "not support this name."); + return -EINVAL; + } + } + + return 0; +} + +static int +cpfl_check_icmp(struct cpfl_flow_js_pr_key_proto *proto, const struct rte_flow_item_icmp *icmp_mask) +{ + int field_size; + + if (!proto) + return 0; + field_size = proto->fields_size; + if ((field_size != 0 && !icmp_mask) || (field_size == 0 && icmp_mask)) + return -EINVAL; + + return 0; +} + +static int +cpfl_check_pattern_key_proto(struct cpfl_flow_js_pr_key_proto *protocols, + int proto_size, + const struct rte_flow_item *items) +{ + int i, length; + int j = 0; + + length = cpfl_get_items_length(items); + if (proto_size > length - 1) + return -EINVAL; + for (i = 0; i < proto_size; i++) { + struct cpfl_flow_js_pr_key_proto *key_proto; + enum rte_flow_item_type type; + + key_proto = &protocols[i]; + /* pr->key->proto->type */ + type = key_proto->type; + /* pr->key->proto->fields */ + switch (type) { + case RTE_FLOW_ITEM_TYPE_ETH: + if (items[j++].type == RTE_FLOW_ITEM_TYPE_ETH) { + const struct rte_flow_item_eth *eth_mask; + int ret; + + eth_mask = (const struct rte_flow_item_eth *)items[i].mask; + ret = cpfl_check_eth(key_proto, eth_mask); + if (ret < 0) + return ret; + } else { + return -EINVAL; + } + break; + case RTE_FLOW_ITEM_TYPE_IPV4: + if (items[j++].type == RTE_FLOW_ITEM_TYPE_IPV4) { + const struct rte_flow_item_ipv4 *ipv4_mask; + int ret; + + ipv4_mask = (const struct rte_flow_item_ipv4 *)items[i].mask; + ret = cpfl_check_ipv4(key_proto, ipv4_mask); + if (ret < 0) + return ret; + } else { + return -EINVAL; + } + break; + case RTE_FLOW_ITEM_TYPE_TCP: + if (items[j++].type == RTE_FLOW_ITEM_TYPE_TCP) { + const struct rte_flow_item_tcp *tcp_mask; + int ret; + + tcp_mask = (const struct rte_flow_item_tcp *)items[i].mask; + ret = cpfl_check_tcp(key_proto, tcp_mask); + if (ret < 0) + return ret; + } else { + return -EINVAL; + } + break; + case RTE_FLOW_ITEM_TYPE_UDP: + if (items[j++].type == RTE_FLOW_ITEM_TYPE_UDP) { + const struct rte_flow_item_udp *udp_mask; + int ret; + + udp_mask = (const struct rte_flow_item_udp *)items[i].mask; + ret = cpfl_check_udp(key_proto, udp_mask); + if (ret < 0) + return ret; + } else { + return -EINVAL; + } + break; + case RTE_FLOW_ITEM_TYPE_VXLAN: + if (items[j++].type == RTE_FLOW_ITEM_TYPE_VXLAN) { + const struct rte_flow_item_vxlan *vxlan_mask; + int ret; + + vxlan_mask = (const struct rte_flow_item_vxlan *)items[i].mask; + ret = cpfl_check_vxlan(key_proto, vxlan_mask); + if (ret < 0) + return ret; + } else { + return -EINVAL; + } + break; + case RTE_FLOW_ITEM_TYPE_ICMP: + if (items[j++].type == RTE_FLOW_ITEM_TYPE_ICMP) { + const struct rte_flow_item_icmp *icmp_mask; + int ret; + + icmp_mask = (const struct rte_flow_item_icmp *)items[i].mask; + ret = cpfl_check_icmp(key_proto, icmp_mask); + if (ret < 0) + return ret; + } else { + return -EINVAL; + } + break; + default: + PMD_DRV_LOG(ERR, "Not support this type: %d.", type); + return -EPERM; + } + } + if (items[j].type != RTE_FLOW_ITEM_TYPE_END) + return -EINVAL; + + return 0; +} + +static int +cpfl_check_pattern_key_attr(struct cpfl_flow_js_pr_key_attr *key_attr, + const struct rte_flow_attr *attr) +{ + if (key_attr->ingress != attr->ingress) { + PMD_DRV_LOG(DEBUG, "ingress not match."); + return -EINVAL; + } + if (key_attr->egress != attr->egress) { + PMD_DRV_LOG(DEBUG, "egress not match."); + return -EINVAL; + } + + return 0; +} + +static int +cpfl_check_pattern_key(struct cpfl_flow_js_pr *pattern, + const struct rte_flow_item *items, + const struct rte_flow_attr *attr) +{ + int ret; + + /* pr->key */ + /* pr->key->protocols */ + ret = cpfl_check_pattern_key_proto(pattern->key.protocols, + pattern->key.proto_size, items); + if (ret < 0) + return -EINVAL; + /* pr->key->attributes */ + ret = cpfl_check_pattern_key_attr(pattern->key.attributes, attr); + if (ret < 0) + return -EINVAL; + + return 0; +} + +/* output: struct cpfl_flow_pr_action* pr_action */ +int +cpfl_flow_parse_items(struct cpfl_itf *itf, + struct cpfl_flow_js_parser *parser, + const struct rte_flow_item *items, + const struct rte_flow_attr *attr, + struct cpfl_flow_pr_action *pr_action) +{ + int i, size; + struct cpfl_flow_js_pr *pattern; + + size = parser->pr_size; + for (i = 0; i < size; i++) { + int ret; + + pattern = &parser->patterns[i]; + ret = cpfl_check_pattern_key(pattern, items, attr); + if (ret < 0) + continue; + /* pr->actions */ + ret = cpfl_parse_pr_actions(itf, pattern->actions, pattern->actions_size, + items, attr, pr_action); + return ret; + } + + return -EINVAL; +} + +bool +cpfl_metadata_write_port_id(struct cpfl_itf *itf) +{ + uint16_t dev_id; + const int type = 0; + const int offset = 5; + + dev_id = cpfl_get_port_id(itf); + if (dev_id == CPFL_INVALID_HW_ID) { + PMD_DRV_LOG(ERR, "fail to get hw ID\n"); + return false; + } + cpfl_metadata_write16(&itf->adapter->meta, type, offset, dev_id << 3); + + return true; +} + +bool +cpfl_metadata_write_targetvsi(struct cpfl_itf *itf) +{ + uint16_t dev_id; + const int type = 6; + const int offset = 2; + + dev_id = cpfl_get_vsi_id(itf); + if (dev_id == CPFL_INVALID_HW_ID) { + PMD_DRV_LOG(ERR, "fail to get hw ID"); + return false; + } + cpfl_metadata_write16(&itf->adapter->meta, type, offset, dev_id << 1); + + return true; +} + +bool +cpfl_metadata_write_sourcevsi(struct cpfl_itf *itf) +{ + uint16_t dev_id; + const int type = 6; + const int offset = 0; + + dev_id = cpfl_get_vsi_id(itf); + if (dev_id == CPFL_INVALID_HW_ID) { + PMD_DRV_LOG(ERR, "fail to get hw ID"); + return false; + } + cpfl_metadata_write16(&itf->adapter->meta, type, offset, dev_id); + + return true; +} + +bool cpfl_metadata_write_vsi(struct cpfl_itf *itf) +{ + uint16_t dev_id; + const int type = 0; + const int offset = 24; + + dev_id = cpfl_get_vsi_id(itf); + if (dev_id == CPFL_INVALID_HW_ID) { + PMD_DRV_LOG(ERR, "fail to get hw ID"); + return false; + } + cpfl_metadata_write16(&itf->adapter->meta, type, offset, dev_id); + + return true; +} diff --git a/drivers/net/cpfl/cpfl_flow_parser.h b/drivers/net/cpfl/cpfl_flow_parser.h new file mode 100644 index 0000000000..af64a158a8 --- /dev/null +++ b/drivers/net/cpfl/cpfl_flow_parser.h @@ -0,0 +1,167 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2023 Intel Corporation + */ +#include +#include +#include "cpfl_ethdev.h" + +#ifndef _CPFL_FLOW_PARSER_H_ +#define _CPFL_FLOW_PARSER_H_ + +#define CPFL_FLOW_JSON_STR_SIZE_MAX 100 +#define CPFL_MAX_SEM_FV_KEY_SIZE 64 +#define CPFL_FLOW_JS_PROTO_SIZE 16 +#define CPFL_MOD_KEY_NUM_MAX 8 + +/* Pattern Rules Storage */ +enum cpfl_flow_pr_action_type { + CPFL_JS_PR_ACTION_TYPE_SEM, + CPFL_JS_PR_ACTION_TYPE_UNKNOWN = -1, +}; + +/* This structure matches a sequence of fields in struct rte_flow_attr */ +struct cpfl_flow_js_pr_key_attr { + uint16_t ingress; + uint16_t egress; +}; + +struct cpfl_flow_js_pr_key_proto_field { + char name[CPFL_FLOW_JSON_STR_SIZE_MAX]; + union { + char mask[CPFL_FLOW_JSON_STR_SIZE_MAX]; + uint32_t mask_32b; + }; +}; + +/* This structure matches a sequence of "struct rte_flow_item" */ +struct cpfl_flow_js_pr_key_proto { + enum rte_flow_item_type type; + struct cpfl_flow_js_pr_key_proto_field *fields; + int fields_size; +}; + +enum cpfl_flow_js_fv_type { + CPFL_FV_TYPE_PROTOCOL, + CPFL_FV_TYPE_IMMEDIATE, + CPFL_FV_TYPE_METADATA, + CPFL_FV_TYPE_UNKNOWN = -1, +}; + +struct cpfl_flow_js_fv { + uint16_t offset; + enum cpfl_flow_js_fv_type type; + union { + /* a 16 bits value */ + uint16_t immediate; + /* a reference to a protocol header with a tuple */ + struct { + enum rte_flow_item_type header; + uint16_t layer; + uint16_t offset; + uint16_t mask; + } proto; + /* a reference to a metadata */ + struct { + uint16_t type; + uint16_t offset; + uint16_t mask; + } meta; + }; +}; + +/** + * This structure defines the message be used to composite the + * profile / key of a SEM control packet + */ +struct cpfl_flow_js_pr_action_sem { + uint16_t prof; /* SEM profile ID */ + uint16_t subprof; /* SEM subprofile ID */ + uint16_t keysize; /* extract key size in bytes */ + struct cpfl_flow_js_fv *fv; /* A SEM field vector array */ + int fv_size; +}; + +/* define how to map current key to low level pipeline configuration */ +struct cpfl_flow_js_pr_action { + enum cpfl_flow_pr_action_type type; + union { + struct cpfl_flow_js_pr_action_sem sem; + }; +}; + +/** + * This structure defines a set of rules that direct PMD how to parse rte_flow + * protocol headers. Each rule be described by a key object and a action array. + */ +struct cpfl_flow_js_pr { + struct { + struct cpfl_flow_js_pr_key_proto *protocols; + uint16_t proto_size; + struct cpfl_flow_js_pr_key_attr *attributes; + uint16_t attr_size; + } key; + /* An array to define how to map current key to low level pipeline configuration. */ + struct cpfl_flow_js_pr_action *actions; + uint16_t actions_size; +}; + +struct cpfl_flow_js_parser { + struct cpfl_flow_js_pr *patterns; + int pr_size; +}; + +/* Pattern Rules */ +struct cpfl_flow_pr_action_sem { + uint16_t prof; + uint16_t subprof; + uint16_t keysize; + uint8_t cpfl_flow_pr_fv[CPFL_MAX_SEM_FV_KEY_SIZE]; +}; + +struct cpfl_flow_pr_action { + enum cpfl_flow_pr_action_type type; + union { + struct cpfl_flow_pr_action_sem sem; + }; +}; + +int cpfl_parser_create(struct cpfl_flow_js_parser **parser, const char *filename); +int cpfl_parser_destroy(struct cpfl_flow_js_parser *parser); +int cpfl_flow_parse_items(struct cpfl_itf *itf, + struct cpfl_flow_js_parser *parser, + const struct rte_flow_item *items, + const struct rte_flow_attr *attr, + struct cpfl_flow_pr_action *pr_action); +bool cpfl_metadata_write_port_id(struct cpfl_itf *itf); +bool cpfl_metadata_write_vsi(struct cpfl_itf *itf); +bool cpfl_metadata_write_targetvsi(struct cpfl_itf *itf); +bool cpfl_metadata_write_sourcevsi(struct cpfl_itf *itf); + +static inline void +cpfl_metadata_init(struct cpfl_metadata *meta) +{ + int i; + + for (i = 0; i < CPFL_META_LENGTH; i++) + meta->chunks[i].type = i; +} + +static inline void +cpfl_metadata_write16(struct cpfl_metadata *meta, int type, int offset, uint16_t data) +{ + rte_memcpy(&meta->chunks[type].data[offset], &data, sizeof(uint16_t)); +} + +static inline void +cpfl_metadata_write32(struct cpfl_metadata *meta, int type, int offset, uint32_t data) +{ + rte_memcpy(&meta->chunks[type].data[offset], &data, sizeof(uint32_t)); +} + +static inline uint16_t +cpfl_metadata_read16(struct cpfl_metadata *meta, int type, int offset) +{ + return *((uint16_t *)(&meta->chunks[type].data[offset])); +} + +#endif diff --git a/drivers/net/cpfl/meson.build b/drivers/net/cpfl/meson.build index d8b92ae16a..1e0a1b0290 100644 --- a/drivers/net/cpfl/meson.build +++ b/drivers/net/cpfl/meson.build @@ -38,3 +38,16 @@ if arch_subdir == 'x86' cflags += ['-DCC_AVX512_SUPPORT'] endif endif + +js_dep = dependency('json-c', required: false, method : 'pkg-config') +if js_dep.found() + if js_dep.version().version_compare('<0.14') + message('json-c lib version is too low') + else + sources += files( + 'cpfl_flow_parser.c', + ) + dpdk_conf.set('CPFL_FLOW_JSON_SUPPORT', true) + ext_deps += js_dep + endif +endif