get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 95088,
    "url": "http://patches.dpdk.org/api/patches/95088/?format=api",
    "web_url": "http://patches.dpdk.org/project/dts/patch/20210701135738.18513-2-zhiminx.huang@intel.com/",
    "project": {
        "id": 3,
        "url": "http://patches.dpdk.org/api/projects/3/?format=api",
        "name": "DTS",
        "link_name": "dts",
        "list_id": "dts.dpdk.org",
        "list_email": "dts@dpdk.org",
        "web_url": "",
        "scm_url": "git://dpdk.org/tools/dts",
        "webscm_url": "http://git.dpdk.org/tools/dts/",
        "list_archive_url": "https://inbox.dpdk.org/dts",
        "list_archive_url_format": "https://inbox.dpdk.org/dts/{}",
        "commit_url_format": ""
    },
    "msgid": "<20210701135738.18513-2-zhiminx.huang@intel.com>",
    "list_archive_url": "https://inbox.dpdk.org/dts/20210701135738.18513-2-zhiminx.huang@intel.com",
    "date": "2021-07-01T13:57:36",
    "name": "[V2,1/3] tests/rte_flow_common:add common to process fdir",
    "commit_ref": null,
    "pull_url": null,
    "state": "accepted",
    "archived": false,
    "hash": "220f5c3d08568cb2886d9691ad65bd9c86bbf700",
    "submitter": {
        "id": 1685,
        "url": "http://patches.dpdk.org/api/people/1685/?format=api",
        "name": "Huang, ZhiminX",
        "email": "zhiminx.huang@intel.com"
    },
    "delegate": null,
    "mbox": "http://patches.dpdk.org/project/dts/patch/20210701135738.18513-2-zhiminx.huang@intel.com/mbox/",
    "series": [
        {
            "id": 17556,
            "url": "http://patches.dpdk.org/api/series/17556/?format=api",
            "web_url": "http://patches.dpdk.org/project/dts/list/?series=17556",
            "date": "2021-07-01T13:57:35",
            "name": "add new feature suite",
            "version": 2,
            "mbox": "http://patches.dpdk.org/series/17556/mbox/"
        }
    ],
    "comments": "http://patches.dpdk.org/api/patches/95088/comments/",
    "check": "pending",
    "checks": "http://patches.dpdk.org/api/patches/95088/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<dts-bounces@dpdk.org>",
        "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])\n\tby inbox.dpdk.org (Postfix) with ESMTP id 2E14FA0A0F;\n\tThu,  1 Jul 2021 07:23:47 +0200 (CEST)",
            "from [217.70.189.124] (localhost [127.0.0.1])\n\tby mails.dpdk.org (Postfix) with ESMTP id 200F641296;\n\tThu,  1 Jul 2021 07:23:47 +0200 (CEST)",
            "from mga14.intel.com (mga14.intel.com [192.55.52.115])\n by mails.dpdk.org (Postfix) with ESMTP id 00A6B40040\n for <dts@dpdk.org>; Thu,  1 Jul 2021 07:23:44 +0200 (CEST)",
            "from orsmga007.jf.intel.com ([10.7.209.58])\n by fmsmga103.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384;\n 30 Jun 2021 22:23:43 -0700",
            "from unknown (HELO localhost.localdomain) ([10.240.183.103])\n by orsmga007-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384;\n 30 Jun 2021 22:23:41 -0700"
        ],
        "X-IronPort-AV": [
            "E=McAfee;i=\"6200,9189,10031\"; a=\"208294847\"",
            "E=Sophos;i=\"5.83,313,1616482800\"; d=\"scan'208\";a=\"208294847\"",
            "E=Sophos;i=\"5.83,313,1616482800\"; d=\"scan'208\";a=\"447746841\""
        ],
        "From": "Zhimin Huang <zhiminx.huang@intel.com>",
        "To": "dts@dpdk.org",
        "Cc": "qi.fu@intel.com,\n\tZhimin Huang <zhiminx.huang@intel.com>",
        "Date": "Thu,  1 Jul 2021 21:57:36 +0800",
        "Message-Id": "<20210701135738.18513-2-zhiminx.huang@intel.com>",
        "X-Mailer": "git-send-email 2.17.1",
        "In-Reply-To": "<20210701135738.18513-1-zhiminx.huang@intel.com>",
        "References": "<20210701135738.18513-1-zhiminx.huang@intel.com>",
        "Subject": "[dts] [PATCH V2 1/3] tests/rte_flow_common:add common to process\n fdir",
        "X-BeenThere": "dts@dpdk.org",
        "X-Mailman-Version": "2.1.29",
        "Precedence": "list",
        "List-Id": "test suite reviews and discussions <dts.dpdk.org>",
        "List-Unsubscribe": "<https://mails.dpdk.org/options/dts>,\n <mailto:dts-request@dpdk.org?subject=unsubscribe>",
        "List-Archive": "<http://mails.dpdk.org/archives/dts/>",
        "List-Post": "<mailto:dts@dpdk.org>",
        "List-Help": "<mailto:dts-request@dpdk.org?subject=help>",
        "List-Subscribe": "<https://mails.dpdk.org/listinfo/dts>,\n <mailto:dts-request@dpdk.org?subject=subscribe>",
        "Errors-To": "dts-bounces@dpdk.org",
        "Sender": "\"dts\" <dts-bounces@dpdk.org>"
    },
    "content": "*.add common class to test fdir\n\nSigned-off-by: Zhimin Huang <zhiminx.huang@intel.com>\n---\n tests/rte_flow_common.py | 219 ++++++++++++++++++++++++++++++++++++++-\n 1 file changed, 216 insertions(+), 3 deletions(-)",
    "diff": "diff --git a/tests/rte_flow_common.py b/tests/rte_flow_common.py\nindex c9f556f7..42afbfd1 100644\n--- a/tests/rte_flow_common.py\n+++ b/tests/rte_flow_common.py\n@@ -674,9 +674,23 @@ def check_pf_rss_queue(out, count):\n     else:\n         return False\n \n+def send_ipfragment_pkt(test_case, pkts, tx_port):\n+    if isinstance(pkts, str):\n+        pkts = [pkts]\n+    for i in range(len(pkts)):\n+        test_case.tester.scapy_session.send_expect(\n+            'p=eval(\"{}\")'.format(pkts[i]), '>>> ')\n+        if 'IPv6ExtHdrFragment' in pkts[i]:\n+            test_case.tester.scapy_session.send_expect(\n+                'pkts=fragment6(p, 500)', '>>> ')\n+        else:\n+            test_case.tester.scapy_session.send_expect(\n+                'pkts=fragment(p, fragsize=500)', '>>> ')\n+        test_case.tester.scapy_session.send_expect(\n+            'sendp(pkts, iface=\"{}\")'.format(tx_port), '>>> ')\n \n class RssProcessing(object):\n-    def __init__(self, test_case, pmd_output, tester_ifaces, rxq):\n+    def __init__(self, test_case, pmd_output, tester_ifaces, rxq, ipfrag_flag=False):\n         self.test_case = test_case\n         self.pmd_output = pmd_output\n         self.tester_ifaces = tester_ifaces\n@@ -697,6 +711,7 @@ class RssProcessing(object):\n             'check_no_hash': self.check_no_hash,\n         }\n         self.error_msgs = []\n+        self.ipfrag_flag = ipfrag_flag\n \n     def save_hash(self, out, key='', port_id=0):\n         hashes, rss_distribute = self.get_hash_verify_rss_distribute(out, port_id)\n@@ -858,11 +873,15 @@ class RssProcessing(object):\n         return hashes, queues\n \n     def send_pkt_get_output(self, pkts, port_id=0, count=1, interval=0):\n-        self.pkt.update_pkt(pkts)\n         tx_port = self.tester_ifaces[0] if port_id == 0 else self.tester_ifaces[1]\n         self.logger.info('----------send packet-------------')\n         self.logger.info('{}'.format(pkts))\n-        self.pkt.send_pkt(crb=self.test_case.tester, tx_port=tx_port, count=count, interval=interval)\n+        if self.ipfrag_flag == True:\n+            count = 2\n+            send_ipfragment_pkt(self.test_case, pkts, tx_port)\n+        else:\n+            self.pkt.update_pkt(pkts)\n+            self.pkt.send_pkt(crb=self.test_case.tester, tx_port=tx_port, count=count, interval=interval)\n         out = self.pmd_output.get_output(timeout=1)\n         pkt_pattern = 'port\\s%d/queue\\s\\d+:\\sreceived\\s(\\d+)\\spackets.+?\\n.*length=\\d{2,}\\s' % port_id\n         reveived_data = re.findall(pkt_pattern, out)\n@@ -1074,3 +1093,197 @@ class RssProcessing(object):\n                               .replace('IP(proto=0x2F)/GRE(proto=0x0800)/IP()', 'IPv6(nh=0x2F)/GRE(proto=0x86DD)/IPv6()').replace('mac_ipv4', 'mac_ipv6'))\n                          for element in template]\n         return ipv6_template\n+\n+\n+class FdirProcessing(object):\n+    def __init__(self, test_case, pmd_output, tester_ifaces, rxq, ipfrag_flag=False):\n+        self.test_case = test_case\n+        self.pmd_output = pmd_output\n+        self.tester_ifaces = tester_ifaces\n+        self.logger = test_case.logger\n+        self.pkt = Packet()\n+        self.rxq = rxq\n+        self.verify = self.test_case.verify\n+        self.ipfrag_flag = ipfrag_flag\n+\n+    def send_pkt_get_output(self, pkts, port_id=0, count=1, interval=0, drop=False):\n+        tx_port = self.tester_ifaces[0] if port_id == 0 else self.tester_ifaces[1]\n+        self.logger.info('----------send packet-------------')\n+        self.logger.info('{}'.format(pkts))\n+        if drop:\n+            self.pmd_output.execute_cmd(\"clear port stats all\")\n+            time.sleep(1)\n+            if self.ipfrag_flag == True:\n+                send_ipfragment_pkt(self.test_case, pkts, tx_port)\n+            else:\n+                self.pkt.update_pkt(pkts)\n+                self.pkt.send_pkt(crb=self.test_case.tester, tx_port=tx_port, count=count, interval=interval)\n+            out = self.pmd_output.execute_cmd(\"stop\")\n+            self.pmd_output.execute_cmd(\"start\")\n+            return out\n+        else:\n+            if self.ipfrag_flag == True:\n+                count = 2\n+                send_ipfragment_pkt(self.test_case, pkts, tx_port)\n+            else:\n+                self.pkt.update_pkt(pkts)\n+                self.pkt.send_pkt(crb=self.test_case.tester, tx_port=tx_port, count=count, interval=interval)\n+            out = self.pmd_output.get_output(timeout=1)\n+        pkt_pattern = 'port\\s%d/queue\\s\\d+:\\sreceived\\s(\\d+)\\spackets.+?\\n.*length=\\d{2,}\\s' % port_id\n+        reveived_data = re.findall(pkt_pattern, out)\n+        reveived_pkts = sum(map(int, [i[0] for i in reveived_data]))\n+        if isinstance(pkts, list):\n+            self.verify(reveived_pkts == len(pkts) * count,\n+                        'expect received %d pkts, but get %d instead' % (len(pkts) * count, reveived_pkts))\n+        else:\n+            self.verify(reveived_pkts == 1 * count,\n+                        'expect received %d pkts, but get %d instead' % (1 * count, reveived_pkts))\n+        return out\n+\n+    def check_rule(self, port_id=0, stats=True, rule_list=None):\n+        out = self.pmd_output.execute_cmd(\"flow list %s\" % port_id)\n+        p = re.compile(r\"ID\\s+Group\\s+Prio\\s+Attr\\s+Rule\")\n+        matched = p.search(out)\n+        if stats:\n+            self.verify(matched, \"flow rule on port %s is not existed\" % port_id)\n+            if rule_list:\n+                p2 = re.compile(\"^(\\d+)\\s\")\n+                li = out.splitlines()\n+                res = list(filter(bool, list(map(p2.match, li))))\n+                result = [i.group(1) for i in res]\n+                self.verify(set(rule_list).issubset(set(result)),\n+                            \"check rule list failed. expect %s, result %s\" % (rule_list, result))\n+        else:\n+            if matched:\n+                if rule_list:\n+                    res_li = [i.split()[0].strip() for i in out.splitlines() if re.match('\\d', i)]\n+                    self.verify(not set(rule_list).issubset(res_li), 'rule specified should not in result.')\n+                else:\n+                    raise Exception('expect no rule listed')\n+            else:\n+                self.verify(not matched, \"flow rule on port %s is existed\" % port_id)\n+\n+    def destroy_rule(self, port_id=0, rule_id=None):\n+        if rule_id is None:\n+            rule_id = 0\n+        if isinstance(rule_id, list):\n+            for i in rule_id:\n+                out = self.test_case.dut.send_command(\"flow destroy %s rule %s\" % (port_id, i), timeout=1)\n+                p = re.compile(r\"Flow rule #(\\d+) destroyed\")\n+                m = p.search(out)\n+                self.verify(m, \"flow rule %s delete failed\" % rule_id)\n+        else:\n+            out = self.test_case.dut.send_command(\"flow destroy %s rule %s\" % (port_id, rule_id), timeout=1)\n+            p = re.compile(r\"Flow rule #(\\d+) destroyed\")\n+            m = p.search(out)\n+            self.verify(m, \"flow rule %s delete failed\" % rule_id)\n+\n+    def create_rule(self, rule: (list, str), check_stats=True, msg=None):\n+        p = re.compile(r\"Flow rule #(\\d+) created\")\n+        rule_list = list()\n+        if isinstance(rule, list):\n+            for i in rule:\n+                out = self.pmd_output.execute_cmd(i, timeout=1)\n+                if msg:\n+                    self.verify(msg in out, \"failed: expect %s in %s\" % (msg, out))\n+                m = p.search(out)\n+                if m:\n+                    rule_list.append(m.group(1))\n+                else:\n+                    rule_list.append(False)\n+        elif isinstance(rule, str):\n+            out = self.pmd_output.execute_cmd(rule, timeout=1)\n+            if msg:\n+                self.verify(msg in out, \"failed: expect %s in %s\" % (msg, out))\n+            m = p.search(out)\n+            if m:\n+                rule_list.append(m.group(1))\n+            else:\n+                rule_list.append(False)\n+        else:\n+            raise Exception(\"unsupported rule type, only accept list or str\")\n+        if check_stats:\n+            self.verify(all(rule_list), \"some rules create failed, result %s\" % rule_list)\n+        elif not check_stats:\n+            self.verify(not any(rule_list), \"all rules should create failed, result %s\" % rule_list)\n+        return rule_list\n+\n+    def validate_rule(self, rule, check_stats=True, check_msg=None):\n+        flag = 'Flow rule validated'\n+        if isinstance(rule, str):\n+            if 'create' in rule:\n+                rule = rule.replace('create', 'validate')\n+            out = self.pmd_output.execute_cmd(rule, timeout=1)\n+            if check_stats:\n+                self.verify(flag in out.strip(), \"rule %s validated failed, result %s\" % (rule, out))\n+            else:\n+                if check_msg:\n+                    self.verify(flag not in out.strip() and check_msg in out.strip(),\n+                                \"rule %s validate should failed with msg: %s, but result %s\" % (rule, check_msg, out))\n+                else:\n+                    self.verify(flag not in out.strip(), \"rule %s validate should failed, result %s\" % (rule, out))\n+        elif isinstance(rule, list):\n+            for r in rule:\n+                if 'create' in r:\n+                    r = r.replace('create', 'validate')\n+                out = self.pmd_output.execute_cmd(r, timeout=1)\n+                if check_stats:\n+                    self.verify(flag in out.strip(), \"rule %s validated failed, result %s\" % (r, out))\n+                else:\n+                    if not check_msg:\n+                        self.verify(flag not in out.strip(), \"rule %s validate should failed, result %s\" % (r, out))\n+                    else:\n+                        self.verify(flag not in out.strip() and check_msg in out.strip(),\n+                                    \"rule %s should validate failed with msg: %s, but result %s\" % (\n+                                        r, check_msg, out))\n+\n+    def flow_director_validate(self, vectors):\n+        \"\"\"\n+        FDIR test: validate/create rule, check match pkts and unmatched pkts, destroy rule...\n+\n+        :param vectors: test vectors\n+        \"\"\"\n+        test_results = dict()\n+        for tv in vectors:\n+            try:\n+                self.logger.info(\"====================sub_case: {}=========================\".format(tv[\"name\"]))\n+                port_id = tv[\"check_param\"][\"port_id\"] if tv[\"check_param\"].get(\"port_id\") is not None else 0\n+                drop = tv[\"check_param\"].get(\"drop\")\n+                # create rule\n+                self.test_case.dut.send_expect(\"flow flush %d\" % port_id, \"testpmd> \", 120)\n+                rule_li = self.create_rule(tv[\"rule\"])\n+                # send and check match packets\n+                out1 = self.send_pkt_get_output(pkts=tv[\"scapy_str\"][\"matched\"], port_id=port_id, drop=drop)\n+                matched_queue = check_mark(out1, pkt_num=len(tv[\"scapy_str\"][\"matched\"]) * 2 if self.ipfrag_flag else\n+                    len(tv[\"scapy_str\"][\"matched\"]), check_param=tv[\"check_param\"])\n+\n+                # send and check unmatched packets\n+                out2 = self.send_pkt_get_output(pkts=tv[\"scapy_str\"][\"unmatched\"], port_id=port_id, drop=drop)\n+                check_mark(out2, pkt_num=len(tv[\"scapy_str\"][\"unmatched\"]) * 2 if self.ipfrag_flag else len(\n+                    tv[\"scapy_str\"][\"unmatched\"]), check_param=tv[\"check_param\"], stats=False)\n+\n+                # list and destroy rule\n+                self.check_rule(port_id=tv[\"check_param\"][\"port_id\"], rule_list=rule_li)\n+                self.destroy_rule(rule_id=rule_li, port_id=port_id)\n+                # send matched packet\n+                out3 = self.send_pkt_get_output(pkts=tv[\"scapy_str\"][\"matched\"], port_id=port_id, drop=drop)\n+                matched_queue2 = check_mark(out3, pkt_num=len(tv[\"scapy_str\"][\"matched\"]) * 2 if self.ipfrag_flag else len(\n+                    tv[\"scapy_str\"][\"matched\"]), check_param=tv[\"check_param\"], stats=False)\n+                if tv[\"check_param\"].get(\"rss\"):\n+                    self.verify(matched_queue == matched_queue2 and None not in matched_queue,\n+                                     \"send twice matched packet, received in deferent queues\")\n+                # check not rule exists\n+                self.check_rule(port_id=port_id, stats=False)\n+                test_results[tv[\"name\"]] = True\n+                self.logger.info((GREEN(\"case passed: %s\" % tv[\"name\"])))\n+            except Exception as e:\n+                self.logger.warning((RED(e)))\n+                self.test_case.dut.send_command(\"flow flush 0\", timeout=1)\n+                test_results[tv[\"name\"]] = False\n+                self.logger.info((GREEN(\"case failed: %s\" % tv[\"name\"])))\n+                continue\n+        failed_cases = []\n+        for k, v in list(test_results.items()):\n+            if not v:\n+                failed_cases.append(k)\n+        self.verify(all(test_results.values()), \"{} failed\".format(failed_cases))\n",
    "prefixes": [
        "V2",
        "1/3"
    ]
}