get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

GET /api/patches/1411/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 1411,
    "url": "http://patches.dpdk.org/api/patches/1411/?format=api",
    "web_url": "http://patches.dpdk.org/project/dpdk/patch/1416530816-2159-7-git-send-email-jingjing.wu@intel.com/",
    "project": {
        "id": 1,
        "url": "http://patches.dpdk.org/api/projects/1/?format=api",
        "name": "DPDK",
        "link_name": "dpdk",
        "list_id": "dev.dpdk.org",
        "list_email": "dev@dpdk.org",
        "web_url": "http://core.dpdk.org",
        "scm_url": "git://dpdk.org/dpdk",
        "webscm_url": "http://git.dpdk.org/dpdk",
        "list_archive_url": "https://inbox.dpdk.org/dev",
        "list_archive_url_format": "https://inbox.dpdk.org/dev/{}",
        "commit_url_format": ""
    },
    "msgid": "<1416530816-2159-7-git-send-email-jingjing.wu@intel.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/1416530816-2159-7-git-send-email-jingjing.wu@intel.com",
    "date": "2014-11-21T00:46:40",
    "name": "[dpdk-dev,v6,06/22] i40e: implement operations to add/delete flow director",
    "commit_ref": null,
    "pull_url": null,
    "state": "accepted",
    "archived": true,
    "hash": "9c284c03263d2b037179b89d96a7e3ac85cc5954",
    "submitter": {
        "id": 47,
        "url": "http://patches.dpdk.org/api/people/47/?format=api",
        "name": "Jingjing Wu",
        "email": "jingjing.wu@intel.com"
    },
    "delegate": null,
    "mbox": "http://patches.dpdk.org/project/dpdk/patch/1416530816-2159-7-git-send-email-jingjing.wu@intel.com/mbox/",
    "series": [],
    "comments": "http://patches.dpdk.org/api/patches/1411/comments/",
    "check": "pending",
    "checks": "http://patches.dpdk.org/api/patches/1411/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<dev-bounces@dpdk.org>",
        "X-Original-To": "patchwork@dpdk.org",
        "Delivered-To": "patchwork@dpdk.org",
        "Received": [
            "from [92.243.14.124] (localhost [IPv6:::1])\n\tby dpdk.org (Postfix) with ESMTP id 18AE47FA5;\n\tFri, 21 Nov 2014 01:36:48 +0100 (CET)",
            "from mga01.intel.com (mga01.intel.com [192.55.52.88])\n\tby dpdk.org (Postfix) with ESMTP id 1008C7F7D\n\tfor <dev@dpdk.org>; Fri, 21 Nov 2014 01:36:44 +0100 (CET)",
            "from fmsmga003.fm.intel.com ([10.253.24.29])\n\tby fmsmga101.fm.intel.com with ESMTP; 20 Nov 2014 16:47:16 -0800",
            "from shvmail01.sh.intel.com ([10.239.29.42])\n\tby FMSMGA003.fm.intel.com with ESMTP; 20 Nov 2014 16:37:47 -0800",
            "from shecgisg004.sh.intel.com (shecgisg004.sh.intel.com\n\t[10.239.29.89])\n\tby shvmail01.sh.intel.com with ESMTP id sAL0lDAN003143;\n\tFri, 21 Nov 2014 08:47:13 +0800",
            "from shecgisg004.sh.intel.com (localhost [127.0.0.1])\n\tby shecgisg004.sh.intel.com (8.13.6/8.13.6/SuSE Linux 0.8) with ESMTP\n\tid sAL0lBEe002236; Fri, 21 Nov 2014 08:47:13 +0800",
            "(from wujingji@localhost)\n\tby shecgisg004.sh.intel.com (8.13.6/8.13.6/Submit) id sAL0lBoD002232; \n\tFri, 21 Nov 2014 08:47:11 +0800"
        ],
        "X-ExtLoop1": "1",
        "X-IronPort-AV": "E=Sophos;i=\"4.97,862,1389772800\"; d=\"scan'208\";a=\"419585352\"",
        "From": "Jingjing Wu <jingjing.wu@intel.com>",
        "To": "dev@dpdk.org",
        "Date": "Fri, 21 Nov 2014 08:46:40 +0800",
        "Message-Id": "<1416530816-2159-7-git-send-email-jingjing.wu@intel.com>",
        "X-Mailer": "git-send-email 1.7.4.1",
        "In-Reply-To": "<1416530816-2159-1-git-send-email-jingjing.wu@intel.com>",
        "References": "<1414654006-7472-1-git-send-email-jingjing.wu@intel.com>\n\t<1416530816-2159-1-git-send-email-jingjing.wu@intel.com>",
        "Subject": "[dpdk-dev] [PATCH v6 06/22] i40e: implement operations to\n\tadd/delete flow director",
        "X-BeenThere": "dev@dpdk.org",
        "X-Mailman-Version": "2.1.15",
        "Precedence": "list",
        "List-Id": "patches and discussions about DPDK <dev.dpdk.org>",
        "List-Unsubscribe": "<http://dpdk.org/ml/options/dev>,\n\t<mailto:dev-request@dpdk.org?subject=unsubscribe>",
        "List-Archive": "<http://dpdk.org/ml/archives/dev/>",
        "List-Post": "<mailto:dev@dpdk.org>",
        "List-Help": "<mailto:dev-request@dpdk.org?subject=help>",
        "List-Subscribe": "<http://dpdk.org/ml/listinfo/dev>,\n\t<mailto:dev-request@dpdk.org?subject=subscribe>",
        "Errors-To": "dev-bounces@dpdk.org",
        "Sender": "\"dev\" <dev-bounces@dpdk.org>"
    },
    "content": "deal with two operations for flow director\n - RTE_ETH_FILTER_ADD\n - RTE_ETH_FILTER_DELETE\nencode the flow inputs to programming packet\nsent the packet to filter programming queue and check status on the status report queue\n\nSigned-off-by: jingjing.wu <jingjing.wu@intel.com>\n---\n lib/librte_pmd_i40e/i40e_ethdev.c |   3 +\n lib/librte_pmd_i40e/i40e_ethdev.h |   3 +\n lib/librte_pmd_i40e/i40e_fdir.c   | 518 +++++++++++++++++++++++++++++++++++++-\n 3 files changed, 523 insertions(+), 1 deletion(-)",
    "diff": "diff --git a/lib/librte_pmd_i40e/i40e_ethdev.c b/lib/librte_pmd_i40e/i40e_ethdev.c\nindex 29b971c..66286ee 100644\n--- a/lib/librte_pmd_i40e/i40e_ethdev.c\n+++ b/lib/librte_pmd_i40e/i40e_ethdev.c\n@@ -5111,6 +5111,9 @@ i40e_dev_filter_ctrl(struct rte_eth_dev *dev,\n \tcase RTE_ETH_FILTER_TUNNEL:\n \t\tret = i40e_tunnel_filter_handle(dev, filter_op, arg);\n \t\tbreak;\n+\tcase RTE_ETH_FILTER_FDIR:\n+\t\tret = i40e_fdir_ctrl_func(dev, filter_op, arg);\n+\t\tbreak;\n \tdefault:\n \t\tPMD_DRV_LOG(WARNING, \"Filter type (%d) not supported\",\n \t\t\t\t\t\t\tfilter_type);\ndiff --git a/lib/librte_pmd_i40e/i40e_ethdev.h b/lib/librte_pmd_i40e/i40e_ethdev.h\nindex cda309a..fbce86a 100644\n--- a/lib/librte_pmd_i40e/i40e_ethdev.h\n+++ b/lib/librte_pmd_i40e/i40e_ethdev.h\n@@ -441,6 +441,9 @@ enum i40e_filter_pctype i40e_flowtype_to_pctype(\n \t\t\t\tenum rte_eth_flow_type flow_type);\n enum rte_eth_flow_type i40e_pctype_to_flowtype(\n \t\t\t\tenum i40e_filter_pctype pctype);\n+int i40e_fdir_ctrl_func(struct rte_eth_dev *dev,\n+\t\t\t  enum rte_filter_op filter_op,\n+\t\t\t  void *arg);\n \n /* I40E_DEV_PRIVATE_TO */\n #define I40E_DEV_PRIVATE_TO_PF(adapter) \\\ndiff --git a/lib/librte_pmd_i40e/i40e_fdir.c b/lib/librte_pmd_i40e/i40e_fdir.c\nindex ed61f2a..5205530 100644\n--- a/lib/librte_pmd_i40e/i40e_fdir.c\n+++ b/lib/librte_pmd_i40e/i40e_fdir.c\n@@ -44,6 +44,10 @@\n #include <rte_log.h>\n #include <rte_memzone.h>\n #include <rte_malloc.h>\n+#include <rte_ip.h>\n+#include <rte_udp.h>\n+#include <rte_tcp.h>\n+#include <rte_sctp.h>\n \n #include \"i40e_logs.h\"\n #include \"i40e/i40e_type.h\"\n@@ -51,8 +55,23 @@\n #include \"i40e_rxtx.h\"\n \n #define I40E_FDIR_MZ_NAME          \"FDIR_MEMZONE\"\n-#define I40E_FDIR_PKT_LEN                   512\n+#ifndef IPV6_ADDR_LEN\n+#define IPV6_ADDR_LEN              16\n+#endif\n \n+#define I40E_FDIR_PKT_LEN                   512\n+#define I40E_FDIR_IP_DEFAULT_LEN            420\n+#define I40E_FDIR_IP_DEFAULT_TTL            0x40\n+#define I40E_FDIR_IP_DEFAULT_VERSION_IHL    0x45\n+#define I40E_FDIR_TCP_DEFAULT_DATAOFF       0x50\n+#define I40E_FDIR_IPv6_DEFAULT_VTC_FLOW     0x60300000\n+#define I40E_FDIR_IPv6_DEFAULT_HOP_LIMITS   0xFF\n+#define I40E_FDIR_IPv6_PAYLOAD_LEN          380\n+#define I40E_FDIR_UDP_DEFAULT_LEN           400\n+\n+/* Wait count and interval for fdir filter programming */\n+#define I40E_FDIR_WAIT_COUNT       10\n+#define I40E_FDIR_WAIT_INTERVAL_US 1000\n \n /* Wait count and interval for fdir filter flush */\n #define I40E_FDIR_FLUSH_RETRY       50\n@@ -64,6 +83,16 @@\n #define I40E_FLX_OFFSET_IN_FIELD_VECTOR   50\n \n static int i40e_fdir_rx_queue_init(struct i40e_rx_queue *rxq);\n+static int i40e_fdir_construct_pkt(struct i40e_pf *pf,\n+\t\t\t\t     const struct rte_eth_fdir_input *fdir_input,\n+\t\t\t\t     unsigned char *raw_pkt);\n+static int i40e_add_del_fdir_filter(struct rte_eth_dev *dev,\n+\t\t\t    const struct rte_eth_fdir_filter *filter,\n+\t\t\t    bool add);\n+static int i40e_fdir_filter_programming(struct i40e_pf *pf,\n+\t\t\tenum i40e_filter_pctype pctype,\n+\t\t\tconst struct rte_eth_fdir_filter *filter,\n+\t\t\tbool add);\n static int i40e_fdir_flush(struct rte_eth_dev *dev);\n \n static int\n@@ -347,6 +376,451 @@ i40e_fdir_configure(struct rte_eth_dev *dev)\n \treturn ret;\n }\n \n+static inline void\n+i40e_fdir_fill_eth_ip_head(const struct rte_eth_fdir_input *fdir_input,\n+\t\t\t       unsigned char *raw_pkt)\n+{\n+\tstruct ether_hdr *ether = (struct ether_hdr *)raw_pkt;\n+\tstruct ipv4_hdr *ip;\n+\tstruct ipv6_hdr *ip6;\n+\tstatic const uint8_t next_proto[] = {\n+\t\t[RTE_ETH_FLOW_TYPE_UDPV4] = IPPROTO_UDP,\n+\t\t[RTE_ETH_FLOW_TYPE_TCPV4] = IPPROTO_TCP,\n+\t\t[RTE_ETH_FLOW_TYPE_SCTPV4] = IPPROTO_SCTP,\n+\t\t[RTE_ETH_FLOW_TYPE_IPV4_OTHER] = IPPROTO_IP,\n+\t\t[RTE_ETH_FLOW_TYPE_FRAG_IPV4] = IPPROTO_IP,\n+\t\t[RTE_ETH_FLOW_TYPE_UDPV6] = IPPROTO_UDP,\n+\t\t[RTE_ETH_FLOW_TYPE_TCPV6] = IPPROTO_TCP,\n+\t\t[RTE_ETH_FLOW_TYPE_SCTPV6] = IPPROTO_SCTP,\n+\t\t[RTE_ETH_FLOW_TYPE_IPV6_OTHER] = IPPROTO_NONE,\n+\t\t[RTE_ETH_FLOW_TYPE_FRAG_IPV6] = IPPROTO_NONE,\n+\t};\n+\n+\tswitch (fdir_input->flow_type) {\n+\tcase RTE_ETH_FLOW_TYPE_UDPV4:\n+\tcase RTE_ETH_FLOW_TYPE_TCPV4:\n+\tcase RTE_ETH_FLOW_TYPE_SCTPV4:\n+\tcase RTE_ETH_FLOW_TYPE_IPV4_OTHER:\n+\tcase RTE_ETH_FLOW_TYPE_FRAG_IPV4:\n+\t\tip = (struct ipv4_hdr *)(raw_pkt + sizeof(struct ether_hdr));\n+\n+\t\tether->ether_type = rte_cpu_to_be_16(ETHER_TYPE_IPv4);\n+\t\tip->version_ihl = I40E_FDIR_IP_DEFAULT_VERSION_IHL;\n+\t\t/* set len to by default */\n+\t\tip->total_length = rte_cpu_to_be_16(I40E_FDIR_IP_DEFAULT_LEN);\n+\t\tip->time_to_live = I40E_FDIR_IP_DEFAULT_TTL;\n+\t\t/*\n+\t\t * The source and destination fields in the transmitted packet\n+\t\t * need to be presented in a reversed order with respect\n+\t\t * to the expected received packets.\n+\t\t */\n+\t\tip->src_addr = fdir_input->flow.ip4_flow.dst_ip;\n+\t\tip->dst_addr = fdir_input->flow.ip4_flow.src_ip;\n+\t\tip->next_proto_id = next_proto[fdir_input->flow_type];\n+\t\tbreak;\n+\tcase RTE_ETH_FLOW_TYPE_UDPV6:\n+\tcase RTE_ETH_FLOW_TYPE_TCPV6:\n+\tcase RTE_ETH_FLOW_TYPE_SCTPV6:\n+\tcase RTE_ETH_FLOW_TYPE_IPV6_OTHER:\n+\tcase RTE_ETH_FLOW_TYPE_FRAG_IPV6:\n+\t\tip6 = (struct ipv6_hdr *)(raw_pkt + sizeof(struct ether_hdr));\n+\n+\t\tether->ether_type = rte_cpu_to_be_16(ETHER_TYPE_IPv6);\n+\t\tip6->vtc_flow =\n+\t\t\trte_cpu_to_be_32(I40E_FDIR_IPv6_DEFAULT_VTC_FLOW);\n+\t\tip6->payload_len =\n+\t\t\trte_cpu_to_be_16(I40E_FDIR_IPv6_PAYLOAD_LEN);\n+\t\tip6->hop_limits = I40E_FDIR_IPv6_DEFAULT_HOP_LIMITS;\n+\n+\t\t/*\n+\t\t * The source and destination fields in the transmitted packet\n+\t\t * need to be presented in a reversed order with respect\n+\t\t * to the expected received packets.\n+\t\t */\n+\t\trte_memcpy(&(ip6->src_addr),\n+\t\t\t   &(fdir_input->flow.ip6_flow.dst_ip),\n+\t\t\t   IPV6_ADDR_LEN);\n+\t\trte_memcpy(&(ip6->dst_addr),\n+\t\t\t   &(fdir_input->flow.ip6_flow.src_ip),\n+\t\t\t   IPV6_ADDR_LEN);\n+\t\tip6->proto = next_proto[fdir_input->flow_type];\n+\t\tbreak;\n+\tdefault:\n+\t\tPMD_DRV_LOG(ERR, \"unknown flow type %u.\",\n+\t\t\t    fdir_input->flow_type);\n+\t\tbreak;\n+\t}\n+}\n+\n+\n+/*\n+ * i40e_fdir_construct_pkt - construct packet based on fields in input\n+ * @pf: board private structure\n+ * @fdir_input: input set of the flow director entry\n+ * @raw_pkt: a packet to be constructed\n+ */\n+static int\n+i40e_fdir_construct_pkt(struct i40e_pf *pf,\n+\t\t\t     const struct rte_eth_fdir_input *fdir_input,\n+\t\t\t     unsigned char *raw_pkt)\n+{\n+\tunsigned char *payload, *ptr;\n+\tstruct udp_hdr *udp;\n+\tstruct tcp_hdr *tcp;\n+\tstruct sctp_hdr *sctp;\n+\tuint8_t size, dst = 0;\n+\tuint8_t i, pit_idx, set_idx = I40E_FLXPLD_L4_IDX; /* use l4 by default*/\n+\n+\t/* fill the ethernet and IP head */\n+\ti40e_fdir_fill_eth_ip_head(fdir_input, raw_pkt);\n+\n+\t/* fill the L4 head */\n+\tswitch (fdir_input->flow_type) {\n+\tcase RTE_ETH_FLOW_TYPE_UDPV4:\n+\t\tudp = (struct udp_hdr *)(raw_pkt + sizeof(struct ether_hdr) +\n+\t\t\t\tsizeof(struct ipv4_hdr));\n+\t\tpayload = (unsigned char *)udp + sizeof(struct udp_hdr);\n+\t\t/*\n+\t\t * The source and destination fields in the transmitted packet\n+\t\t * need to be presented in a reversed order with respect\n+\t\t * to the expected received packets.\n+\t\t */\n+\t\tudp->src_port = fdir_input->flow.udp4_flow.dst_port;\n+\t\tudp->dst_port = fdir_input->flow.udp4_flow.src_port;\n+\t\tudp->dgram_len = rte_cpu_to_be_16(I40E_FDIR_UDP_DEFAULT_LEN);\n+\t\tbreak;\n+\n+\tcase RTE_ETH_FLOW_TYPE_TCPV4:\n+\t\ttcp = (struct tcp_hdr *)(raw_pkt + sizeof(struct ether_hdr) +\n+\t\t\t\t\t sizeof(struct ipv4_hdr));\n+\t\tpayload = (unsigned char *)tcp + sizeof(struct tcp_hdr);\n+\t\t/*\n+\t\t * The source and destination fields in the transmitted packet\n+\t\t * need to be presented in a reversed order with respect\n+\t\t * to the expected received packets.\n+\t\t */\n+\t\ttcp->src_port = fdir_input->flow.tcp4_flow.dst_port;\n+\t\ttcp->dst_port = fdir_input->flow.tcp4_flow.src_port;\n+\t\ttcp->data_off = I40E_FDIR_TCP_DEFAULT_DATAOFF;\n+\t\tbreak;\n+\n+\tcase RTE_ETH_FLOW_TYPE_SCTPV4:\n+\t\tsctp = (struct sctp_hdr *)(raw_pkt + sizeof(struct ether_hdr) +\n+\t\t\t\t\t   sizeof(struct ipv4_hdr));\n+\t\tpayload = (unsigned char *)sctp + sizeof(struct sctp_hdr);\n+\t\tsctp->tag = fdir_input->flow.sctp4_flow.verify_tag;\n+\t\tbreak;\n+\n+\tcase RTE_ETH_FLOW_TYPE_IPV4_OTHER:\n+\tcase RTE_ETH_FLOW_TYPE_FRAG_IPV4:\n+\t\tpayload = raw_pkt + sizeof(struct ether_hdr) +\n+\t\t\t  sizeof(struct ipv4_hdr);\n+\t\tset_idx = I40E_FLXPLD_L3_IDX;\n+\t\tbreak;\n+\n+\tcase RTE_ETH_FLOW_TYPE_UDPV6:\n+\t\tudp = (struct udp_hdr *)(raw_pkt + sizeof(struct ether_hdr) +\n+\t\t\t\t\t sizeof(struct ipv6_hdr));\n+\t\tpayload = (unsigned char *)udp + sizeof(struct udp_hdr);\n+\t\t/*\n+\t\t * The source and destination fields in the transmitted packet\n+\t\t * need to be presented in a reversed order with respect\n+\t\t * to the expected received packets.\n+\t\t */\n+\t\tudp->src_port = fdir_input->flow.udp6_flow.dst_port;\n+\t\tudp->dst_port = fdir_input->flow.udp6_flow.src_port;\n+\t\tudp->dgram_len = rte_cpu_to_be_16(I40E_FDIR_IPv6_PAYLOAD_LEN);\n+\t\tbreak;\n+\n+\tcase RTE_ETH_FLOW_TYPE_TCPV6:\n+\t\ttcp = (struct tcp_hdr *)(raw_pkt + sizeof(struct ether_hdr) +\n+\t\t\t\t\t sizeof(struct ipv6_hdr));\n+\t\tpayload = (unsigned char *)tcp + sizeof(struct tcp_hdr);\n+\t\t/*\n+\t\t * The source and destination fields in the transmitted packet\n+\t\t * need to be presented in a reversed order with respect\n+\t\t * to the expected received packets.\n+\t\t */\n+\t\ttcp->data_off = I40E_FDIR_TCP_DEFAULT_DATAOFF;\n+\t\ttcp->src_port = fdir_input->flow.udp6_flow.dst_port;\n+\t\ttcp->dst_port = fdir_input->flow.udp6_flow.src_port;\n+\t\tbreak;\n+\n+\tcase RTE_ETH_FLOW_TYPE_SCTPV6:\n+\t\tsctp = (struct sctp_hdr *)(raw_pkt + sizeof(struct ether_hdr) +\n+\t\t\t\t\t   sizeof(struct ipv6_hdr));\n+\t\tpayload = (unsigned char *)sctp + sizeof(struct sctp_hdr);\n+\t\tsctp->tag = fdir_input->flow.sctp6_flow.verify_tag;\n+\t\tbreak;\n+\n+\tcase RTE_ETH_FLOW_TYPE_IPV6_OTHER:\n+\tcase RTE_ETH_FLOW_TYPE_FRAG_IPV6:\n+\t\tpayload = raw_pkt + sizeof(struct ether_hdr) +\n+\t\t\t  sizeof(struct ipv6_hdr);\n+\t\tset_idx = I40E_FLXPLD_L3_IDX;\n+\t\tbreak;\n+\tdefault:\n+\t\tPMD_DRV_LOG(ERR, \"unknown flow type %u.\", fdir_input->flow_type);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\t/* fill the flexbytes to payload */\n+\tfor (i = 0; i < I40E_MAX_FLXPLD_FIED; i++) {\n+\t\tpit_idx = set_idx * I40E_MAX_FLXPLD_FIED + i;\n+\t\tsize = pf->fdir.flex_set[pit_idx].size;\n+\t\tif (size == 0)\n+\t\t\tcontinue;\n+\t\tdst = pf->fdir.flex_set[pit_idx].dst_offset * sizeof(uint16_t);\n+\t\tptr = payload +\n+\t\t\tpf->fdir.flex_set[pit_idx].src_offset * sizeof(uint16_t);\n+\t\t(void)rte_memcpy(ptr,\n+\t\t\t\t &fdir_input->flow_ext.flexbytes[dst],\n+\t\t\t\t size * sizeof(uint16_t));\n+\t}\n+\n+\treturn 0;\n+}\n+\n+/* Construct the tx flags */\n+static inline uint64_t\n+i40e_build_ctob(uint32_t td_cmd,\n+\t\tuint32_t td_offset,\n+\t\tunsigned int size,\n+\t\tuint32_t td_tag)\n+{\n+\treturn rte_cpu_to_le_64(I40E_TX_DESC_DTYPE_DATA |\n+\t\t\t((uint64_t)td_cmd  << I40E_TXD_QW1_CMD_SHIFT) |\n+\t\t\t((uint64_t)td_offset << I40E_TXD_QW1_OFFSET_SHIFT) |\n+\t\t\t((uint64_t)size  << I40E_TXD_QW1_TX_BUF_SZ_SHIFT) |\n+\t\t\t((uint64_t)td_tag  << I40E_TXD_QW1_L2TAG1_SHIFT));\n+}\n+\n+/*\n+ * check the programming status descriptor in rx queue.\n+ * done after Programming Flow Director is programmed on\n+ * tx queue\n+ */\n+static inline int\n+i40e_check_fdir_programming_status(struct i40e_rx_queue *rxq)\n+{\n+\tvolatile union i40e_rx_desc *rxdp;\n+\tuint64_t qword1;\n+\tuint32_t rx_status;\n+\tuint32_t len, id;\n+\tuint32_t error;\n+\tint ret = 0;\n+\n+\trxdp = &rxq->rx_ring[rxq->rx_tail];\n+\tqword1 = rte_le_to_cpu_64(rxdp->wb.qword1.status_error_len);\n+\trx_status = (qword1 & I40E_RXD_QW1_STATUS_MASK)\n+\t\t\t>> I40E_RXD_QW1_STATUS_SHIFT;\n+\n+\tif (rx_status & (1 << I40E_RX_DESC_STATUS_DD_SHIFT)) {\n+\t\tlen = qword1 >> I40E_RX_PROG_STATUS_DESC_LENGTH_SHIFT;\n+\t\tid = (qword1 & I40E_RX_PROG_STATUS_DESC_QW1_PROGID_MASK) >>\n+\t\t\t    I40E_RX_PROG_STATUS_DESC_QW1_PROGID_SHIFT;\n+\n+\t\tif (len  == I40E_RX_PROG_STATUS_DESC_LENGTH &&\n+\t\t    id == I40E_RX_PROG_STATUS_DESC_FD_FILTER_STATUS) {\n+\t\t\terror = (qword1 &\n+\t\t\t\tI40E_RX_PROG_STATUS_DESC_QW1_ERROR_MASK) >>\n+\t\t\t\tI40E_RX_PROG_STATUS_DESC_QW1_ERROR_SHIFT;\n+\t\t\tif (error == (0x1 <<\n+\t\t\t\tI40E_RX_PROG_STATUS_DESC_FD_TBL_FULL_SHIFT)) {\n+\t\t\t\tPMD_DRV_LOG(ERR, \"Failed to add FDIR filter\"\n+\t\t\t\t\t    \" (FD_ID %u): programming status\"\n+\t\t\t\t\t    \" reported.\",\n+\t\t\t\t\t    rxdp->wb.qword0.hi_dword.fd_id);\n+\t\t\t\tret = -1;\n+\t\t\t} else if (error == (0x1 <<\n+\t\t\t\tI40E_RX_PROG_STATUS_DESC_NO_FD_ENTRY_SHIFT)) {\n+\t\t\t\tPMD_DRV_LOG(ERR, \"Failed to delete FDIR filter\"\n+\t\t\t\t\t    \" (FD_ID %u): programming status\"\n+\t\t\t\t\t    \" reported.\",\n+\t\t\t\t\t    rxdp->wb.qword0.hi_dword.fd_id);\n+\t\t\t\tret = -1;\n+\t\t\t} else\n+\t\t\t\tPMD_DRV_LOG(ERR, \"invalid programming status\"\n+\t\t\t\t\t    \" reported, error = %u.\", error);\n+\t\t} else\n+\t\t\tPMD_DRV_LOG(ERR, \"unknown programming status\"\n+\t\t\t\t    \" reported, len = %d, id = %u.\", len, id);\n+\t\trxdp->wb.qword1.status_error_len = 0;\n+\t\trxq->rx_tail++;\n+\t\tif (unlikely(rxq->rx_tail == rxq->nb_rx_desc))\n+\t\t\trxq->rx_tail = 0;\n+\t}\n+\treturn ret;\n+}\n+\n+/*\n+ * i40e_add_del_fdir_filter - add or remove a flow director filter.\n+ * @pf: board private structure\n+ * @filter: fdir filter entry\n+ * @add: 0 - delete, 1 - add\n+ */\n+static int\n+i40e_add_del_fdir_filter(struct rte_eth_dev *dev,\n+\t\t\t    const struct rte_eth_fdir_filter *filter,\n+\t\t\t    bool add)\n+{\n+\tstruct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);\n+\tunsigned char *pkt = (unsigned char *)pf->fdir.prg_pkt;\n+\tenum i40e_filter_pctype pctype;\n+\tint ret = 0;\n+\n+\tif (!(pf->flags & I40E_FLAG_FDIR)) {\n+\t\tPMD_DRV_LOG(ERR, \"FDIR is not enabled.\");\n+\t\treturn -ENOTSUP;\n+\t}\n+\tif (!I40E_VALID_FLOW_TYPE(filter->input.flow_type)) {\n+\t\tPMD_DRV_LOG(ERR, \"invalid flow_type input.\");\n+\t\treturn -EINVAL;\n+\t}\n+\tif (filter->action.rx_queue >= pf->dev_data->nb_rx_queues) {\n+\t\tPMD_DRV_LOG(ERR, \"Invalid queue ID\");\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tmemset(pkt, 0, I40E_FDIR_PKT_LEN);\n+\n+\tret = i40e_fdir_construct_pkt(pf, &filter->input, pkt);\n+\tif (ret < 0) {\n+\t\tPMD_DRV_LOG(ERR, \"construct packet for fdir fails.\");\n+\t\treturn ret;\n+\t}\n+\tpctype = i40e_flowtype_to_pctype(filter->input.flow_type);\n+\tret = i40e_fdir_filter_programming(pf, pctype, filter, add);\n+\tif (ret < 0) {\n+\t\tPMD_DRV_LOG(ERR, \"fdir programming fails for PCTYPE(%u).\",\n+\t\t\t    pctype);\n+\t\treturn ret;\n+\t}\n+\treturn ret;\n+}\n+\n+/*\n+ * i40e_fdir_filter_programming - Program a flow director filter rule.\n+ * Is done by Flow Director Programming Descriptor followed by packet\n+ * structure that contains the filter fields need to match.\n+ * @pf: board private structure\n+ * @pctype: pctype\n+ * @filter: fdir filter entry\n+ * @add: 0 - delelet, 1 - add\n+ */\n+static int\n+i40e_fdir_filter_programming(struct i40e_pf *pf,\n+\t\t\tenum i40e_filter_pctype pctype,\n+\t\t\tconst struct rte_eth_fdir_filter *filter,\n+\t\t\tbool add)\n+{\n+\tstruct i40e_tx_queue *txq = pf->fdir.txq;\n+\tstruct i40e_rx_queue *rxq = pf->fdir.rxq;\n+\tconst struct rte_eth_fdir_action *fdir_action = &filter->action;\n+\tvolatile struct i40e_tx_desc *txdp;\n+\tvolatile struct i40e_filter_program_desc *fdirdp;\n+\tuint32_t td_cmd;\n+\tuint16_t i;\n+\tuint8_t dest;\n+\n+\tPMD_DRV_LOG(INFO, \"filling filter programming descriptor.\");\n+\tfdirdp = (volatile struct i40e_filter_program_desc *)\n+\t\t\t(&(txq->tx_ring[txq->tx_tail]));\n+\n+\tfdirdp->qindex_flex_ptype_vsi =\n+\t\t\trte_cpu_to_le_32((fdir_action->rx_queue <<\n+\t\t\t\t\t  I40E_TXD_FLTR_QW0_QINDEX_SHIFT) &\n+\t\t\t\t\t  I40E_TXD_FLTR_QW0_QINDEX_MASK);\n+\n+\tfdirdp->qindex_flex_ptype_vsi |=\n+\t\t\trte_cpu_to_le_32((fdir_action->flex_off <<\n+\t\t\t\t\t  I40E_TXD_FLTR_QW0_FLEXOFF_SHIFT) &\n+\t\t\t\t\t  I40E_TXD_FLTR_QW0_FLEXOFF_MASK);\n+\n+\tfdirdp->qindex_flex_ptype_vsi |=\n+\t\t\trte_cpu_to_le_32((pctype <<\n+\t\t\t\t\t  I40E_TXD_FLTR_QW0_PCTYPE_SHIFT) &\n+\t\t\t\t\t  I40E_TXD_FLTR_QW0_PCTYPE_MASK);\n+\n+\t/* Use LAN VSI Id by default */\n+\tfdirdp->qindex_flex_ptype_vsi |=\n+\t\trte_cpu_to_le_32((pf->main_vsi->vsi_id <<\n+\t\t\t\t  I40E_TXD_FLTR_QW0_DEST_VSI_SHIFT) &\n+\t\t\t\t  I40E_TXD_FLTR_QW0_DEST_VSI_MASK);\n+\n+\tfdirdp->dtype_cmd_cntindex =\n+\t\t\trte_cpu_to_le_32(I40E_TX_DESC_DTYPE_FILTER_PROG);\n+\n+\tif (add)\n+\t\tfdirdp->dtype_cmd_cntindex |= rte_cpu_to_le_32(\n+\t\t\t\tI40E_FILTER_PROGRAM_DESC_PCMD_ADD_UPDATE <<\n+\t\t\t\tI40E_TXD_FLTR_QW1_PCMD_SHIFT);\n+\telse\n+\t\tfdirdp->dtype_cmd_cntindex |= rte_cpu_to_le_32(\n+\t\t\t\tI40E_FILTER_PROGRAM_DESC_PCMD_REMOVE <<\n+\t\t\t\tI40E_TXD_FLTR_QW1_PCMD_SHIFT);\n+\n+\tif (fdir_action->behavior == RTE_ETH_FDIR_REJECT)\n+\t\tdest = I40E_FILTER_PROGRAM_DESC_DEST_DROP_PACKET;\n+\telse\n+\t\tdest = I40E_FILTER_PROGRAM_DESC_DEST_DIRECT_PACKET_QINDEX;\n+\tfdirdp->dtype_cmd_cntindex |= rte_cpu_to_le_32((dest <<\n+\t\t\t\tI40E_TXD_FLTR_QW1_DEST_SHIFT) &\n+\t\t\t\tI40E_TXD_FLTR_QW1_DEST_MASK);\n+\n+\tfdirdp->dtype_cmd_cntindex |=\n+\t\trte_cpu_to_le_32((fdir_action->report_status<<\n+\t\t\t\tI40E_TXD_FLTR_QW1_FD_STATUS_SHIFT) &\n+\t\t\t\tI40E_TXD_FLTR_QW1_FD_STATUS_MASK);\n+\n+\tfdirdp->dtype_cmd_cntindex |=\n+\t\t\trte_cpu_to_le_32(I40E_TXD_FLTR_QW1_CNT_ENA_MASK);\n+\tfdirdp->dtype_cmd_cntindex |=\n+\t\t\trte_cpu_to_le_32((pf->fdir.match_counter_index <<\n+\t\t\tI40E_TXD_FLTR_QW1_CNTINDEX_SHIFT) &\n+\t\t\tI40E_TXD_FLTR_QW1_CNTINDEX_MASK);\n+\n+\tfdirdp->fd_id = rte_cpu_to_le_32(filter->soft_id);\n+\n+\tPMD_DRV_LOG(INFO, \"filling transmit descriptor.\");\n+\ttxdp = &(txq->tx_ring[txq->tx_tail + 1]);\n+\ttxdp->buffer_addr = rte_cpu_to_le_64(pf->fdir.dma_addr);\n+\ttd_cmd = I40E_TX_DESC_CMD_EOP |\n+\t\t I40E_TX_DESC_CMD_RS  |\n+\t\t I40E_TX_DESC_CMD_DUMMY;\n+\n+\ttxdp->cmd_type_offset_bsz =\n+\t\ti40e_build_ctob(td_cmd, 0, I40E_FDIR_PKT_LEN, 0);\n+\n+\ttxq->tx_tail += 2; /* set 2 descriptors above, fdirdp and txdp */\n+\tif (txq->tx_tail >= txq->nb_tx_desc)\n+\t\ttxq->tx_tail = 0;\n+\t/* Update the tx tail register */\n+\trte_wmb();\n+\tI40E_PCI_REG_WRITE(txq->qtx_tail, txq->tx_tail);\n+\n+\tfor (i = 0; i < I40E_FDIR_WAIT_COUNT; i++) {\n+\t\trte_delay_us(I40E_FDIR_WAIT_INTERVAL_US);\n+\t\tif (txdp->cmd_type_offset_bsz &\n+\t\t\t\trte_cpu_to_le_64(I40E_TX_DESC_DTYPE_DESC_DONE))\n+\t\t\tbreak;\n+\t}\n+\tif (i >= I40E_FDIR_WAIT_COUNT) {\n+\t\tPMD_DRV_LOG(ERR, \"Failed to program FDIR filter:\"\n+\t\t\t    \" time out to get DD on tx queue.\");\n+\t\treturn -ETIMEDOUT;\n+\t}\n+\t/* totally delay 10 ms to check programming status*/\n+\trte_delay_us((I40E_FDIR_WAIT_COUNT - i) * I40E_FDIR_WAIT_INTERVAL_US);\n+\tif (i40e_check_fdir_programming_status(rxq) < 0) {\n+\t\tPMD_DRV_LOG(ERR, \"Failed to program FDIR filter:\"\n+\t\t\t    \" programming status reported.\");\n+\t\treturn -ENOSYS;\n+\t}\n+\n+\treturn 0;\n+}\n+\n /*\n  * i40e_fdir_flush - clear all filters of Flow Director table\n  * @pf: board private structure\n@@ -386,3 +860,45 @@ i40e_fdir_flush(struct rte_eth_dev *dev)\n \t\tPMD_DRV_LOG(INFO, \"FD table Flush success.\");\n \treturn 0;\n }\n+\n+/*\n+ * i40e_fdir_ctrl_func - deal with all operations on flow director.\n+ * @pf: board private structure\n+ * @filter_op:operation will be taken.\n+ * @arg: a pointer to specific structure corresponding to the filter_op\n+ */\n+int\n+i40e_fdir_ctrl_func(struct rte_eth_dev *dev,\n+\t\t       enum rte_filter_op filter_op,\n+\t\t       void *arg)\n+{\n+\tstruct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);\n+\tint ret = 0;\n+\n+\tif (filter_op == RTE_ETH_FILTER_NOP) {\n+\t\tif (!(pf->flags & I40E_FLAG_FDIR))\n+\t\t\tret = -ENOTSUP;\n+\t\treturn ret;\n+\t}\n+\n+\tif (arg == NULL)\n+\t\treturn -EINVAL;\n+\n+\tswitch (filter_op) {\n+\tcase RTE_ETH_FILTER_ADD:\n+\t\tret = i40e_add_del_fdir_filter(dev,\n+\t\t\t(struct rte_eth_fdir_filter *)arg,\n+\t\t\tTRUE);\n+\t\tbreak;\n+\tcase RTE_ETH_FILTER_DELETE:\n+\t\tret = i40e_add_del_fdir_filter(dev,\n+\t\t\t(struct rte_eth_fdir_filter *)arg,\n+\t\t\tFALSE);\n+\t\tbreak;\n+\tdefault:\n+\t\tPMD_DRV_LOG(ERR, \"unknown operation %u.\", filter_op);\n+\t\tret = -EINVAL;\n+\t\tbreak;\n+\t}\n+\treturn ret;\n+}\n",
    "prefixes": [
        "dpdk-dev",
        "v6",
        "06/22"
    ]
}