get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 1558034,
    "url": "http://patchwork.ozlabs.org/api/patches/1558034/?format=api",
    "web_url": "http://patchwork.ozlabs.org/project/openvswitch/patch/20211122112256.2011194-18-amorenoz@redhat.com/",
    "project": {
        "id": 47,
        "url": "http://patchwork.ozlabs.org/api/projects/47/?format=api",
        "name": "Open vSwitch",
        "link_name": "openvswitch",
        "list_id": "ovs-dev.openvswitch.org",
        "list_email": "ovs-dev@openvswitch.org",
        "web_url": "http://openvswitch.org/",
        "scm_url": "git@github.com:openvswitch/ovs.git",
        "webscm_url": "https://github.com/openvswitch/ovs",
        "list_archive_url": "",
        "list_archive_url_format": "",
        "commit_url_format": ""
    },
    "msgid": "<20211122112256.2011194-18-amorenoz@redhat.com>",
    "list_archive_url": null,
    "date": "2021-11-22T11:22:55",
    "name": "[ovs-dev,v1,17/18] python: add unit tests to datapath parsing",
    "commit_ref": null,
    "pull_url": null,
    "state": "changes-requested",
    "archived": false,
    "hash": "406048d711f896bf5e85f252b488ffc4d7e61df0",
    "submitter": {
        "id": 77477,
        "url": "http://patchwork.ozlabs.org/api/people/77477/?format=api",
        "name": "Adrian Moreno",
        "email": "amorenoz@redhat.com"
    },
    "delegate": null,
    "mbox": "http://patchwork.ozlabs.org/project/openvswitch/patch/20211122112256.2011194-18-amorenoz@redhat.com/mbox/",
    "series": [
        {
            "id": 273222,
            "url": "http://patchwork.ozlabs.org/api/series/273222/?format=api",
            "web_url": "http://patchwork.ozlabs.org/project/openvswitch/list/?series=273222",
            "date": "2021-11-22T11:22:39",
            "name": "python: add flow parsing library",
            "version": 1,
            "mbox": "http://patchwork.ozlabs.org/series/273222/mbox/"
        }
    ],
    "comments": "http://patchwork.ozlabs.org/api/patches/1558034/comments/",
    "check": "fail",
    "checks": "http://patchwork.ozlabs.org/api/patches/1558034/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<ovs-dev-bounces@openvswitch.org>",
        "X-Original-To": [
            "incoming@patchwork.ozlabs.org",
            "dev@openvswitch.org"
        ],
        "Delivered-To": [
            "patchwork-incoming@bilbo.ozlabs.org",
            "ovs-dev@lists.linuxfoundation.org"
        ],
        "Authentication-Results": [
            "bilbo.ozlabs.org;\n\tdkim=fail reason=\"signature verification failed\" (1024-bit key;\n unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256\n header.s=mimecast20190719 header.b=jKHbGyyA;\n\tdkim-atps=neutral",
            "ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org\n (client-ip=140.211.166.133; helo=smtp2.osuosl.org;\n envelope-from=ovs-dev-bounces@openvswitch.org; receiver=<UNKNOWN>)",
            "relay.mimecast.com;\n auth=pass smtp.auth=CUSA124A263 smtp.mailfrom=amorenoz@redhat.com"
        ],
        "Received": [
            "from smtp2.osuosl.org (smtp2.osuosl.org [140.211.166.133])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest\n SHA256)\n\t(No client certificate requested)\n\tby bilbo.ozlabs.org (Postfix) with ESMTPS id 4HyQ0x6STHz9sRR\n\tfor <incoming@patchwork.ozlabs.org>; Mon, 22 Nov 2021 22:25:05 +1100 (AEDT)",
            "from localhost (localhost [127.0.0.1])\n\tby smtp2.osuosl.org (Postfix) with ESMTP id 471B4403BB;\n\tMon, 22 Nov 2021 11:25:03 +0000 (UTC)",
            "from smtp2.osuosl.org ([127.0.0.1])\n\tby localhost (smtp2.osuosl.org [127.0.0.1]) (amavisd-new, port 10024)\n\twith ESMTP id OPAYIlJ6DTYk; Mon, 22 Nov 2021 11:24:59 +0000 (UTC)",
            "from lists.linuxfoundation.org (lf-lists.osuosl.org\n [IPv6:2605:bc80:3010:104::8cd3:938])\n\tby smtp2.osuosl.org (Postfix) with ESMTPS id 3FDA0409C6;\n\tMon, 22 Nov 2021 11:24:53 +0000 (UTC)",
            "from lf-lists.osuosl.org (localhost [127.0.0.1])\n\tby lists.linuxfoundation.org (Postfix) with ESMTP id 05E35C0036;\n\tMon, 22 Nov 2021 11:24:52 +0000 (UTC)",
            "from smtp2.osuosl.org (smtp2.osuosl.org [140.211.166.133])\n by lists.linuxfoundation.org (Postfix) with ESMTP id 2209AC003C\n for <dev@openvswitch.org>; Mon, 22 Nov 2021 11:24:51 +0000 (UTC)",
            "from localhost (localhost [127.0.0.1])\n by smtp2.osuosl.org (Postfix) with ESMTP id 02CB3401B9\n for <dev@openvswitch.org>; Mon, 22 Nov 2021 11:23:52 +0000 (UTC)",
            "from smtp2.osuosl.org ([127.0.0.1])\n by localhost (smtp2.osuosl.org [127.0.0.1]) (amavisd-new, port 10024)\n with ESMTP id MCot0Nz13h7s for <dev@openvswitch.org>;\n Mon, 22 Nov 2021 11:23:50 +0000 (UTC)",
            "from us-smtp-delivery-124.mimecast.com\n (us-smtp-delivery-124.mimecast.com [170.10.129.124])\n by smtp2.osuosl.org (Postfix) with ESMTPS id 6BD7840405\n for <dev@openvswitch.org>; Mon, 22 Nov 2021 11:23:50 +0000 (UTC)",
            "from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com\n [209.132.183.4]) by relay.mimecast.com with ESMTP with STARTTLS\n (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id\n us-mta-13-TcQpDoTSNYyYNvUooay-dA-1; Mon, 22 Nov 2021 06:23:47 -0500",
            "from smtp.corp.redhat.com (int-mx03.intmail.prod.int.phx2.redhat.com\n [10.5.11.13])\n (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits))\n (No client certificate requested)\n by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 011F51966323\n for <dev@openvswitch.org>; Mon, 22 Nov 2021 11:23:47 +0000 (UTC)",
            "from amorenoz.users.ipa.redhat.com (unknown [10.2.16.196])\n by smtp.corp.redhat.com (Postfix) with ESMTP id 1A7E860862;\n Mon, 22 Nov 2021 11:23:45 +0000 (UTC)"
        ],
        "X-Virus-Scanned": [
            "amavisd-new at osuosl.org",
            "amavisd-new at osuosl.org"
        ],
        "X-Greylist": "domain auto-whitelisted by SQLgrey-1.8.0",
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com;\n s=mimecast20190719; t=1637580229;\n h=from:from:reply-to:subject:subject:date:date:message-id:message-id:\n to:to:cc:cc:mime-version:mime-version:content-type:content-type:\n content-transfer-encoding:content-transfer-encoding:\n in-reply-to:in-reply-to:references:references;\n bh=j0NP3kYH804SG4Z/9X0OTg1EJEUYLV+pZEMiD4/oilQ=;\n b=jKHbGyyAl2CBSFZEVfC7KM8syliIsGl748om29bZ8SQIGP0dtHFSlNe4iOEQ7u5kAdd3Xs\n qkFvTFemJvuTvc1FdyrYqj3O4z3VyOIfaI38Nena1LpMKPQFvIml+O+eu9ztRn24OtidP2\n kUnP5wttsxnhFrvejWvfetj7BgaGhdk=",
        "X-MC-Unique": "TcQpDoTSNYyYNvUooay-dA-1",
        "From": "Adrian Moreno <amorenoz@redhat.com>",
        "To": "dev@openvswitch.org",
        "Date": "Mon, 22 Nov 2021 12:22:55 +0100",
        "Message-Id": "<20211122112256.2011194-18-amorenoz@redhat.com>",
        "In-Reply-To": "<20211122112256.2011194-1-amorenoz@redhat.com>",
        "References": "<20211122112256.2011194-1-amorenoz@redhat.com>",
        "MIME-Version": "1.0",
        "X-Scanned-By": "MIMEDefang 2.79 on 10.5.11.13",
        "X-Mimecast-Spam-Score": "0",
        "X-Mimecast-Originator": "redhat.com",
        "Subject": "[ovs-dev] [PATCH v1 17/18] python: add unit tests to datapath\n\tparsing",
        "X-BeenThere": "ovs-dev@openvswitch.org",
        "X-Mailman-Version": "2.1.15",
        "Precedence": "list",
        "List-Id": "<ovs-dev.openvswitch.org>",
        "List-Unsubscribe": "<https://mail.openvswitch.org/mailman/options/ovs-dev>,\n <mailto:ovs-dev-request@openvswitch.org?subject=unsubscribe>",
        "List-Archive": "<http://mail.openvswitch.org/pipermail/ovs-dev/>",
        "List-Post": "<mailto:ovs-dev@openvswitch.org>",
        "List-Help": "<mailto:ovs-dev-request@openvswitch.org?subject=help>",
        "List-Subscribe": "<https://mail.openvswitch.org/mailman/listinfo/ovs-dev>,\n <mailto:ovs-dev-request@openvswitch.org?subject=subscribe>",
        "Content-Type": "text/plain; charset=\"us-ascii\"",
        "Content-Transfer-Encoding": "7bit",
        "Errors-To": "ovs-dev-bounces@openvswitch.org",
        "Sender": "\"dev\" <ovs-dev-bounces@openvswitch.org>"
    },
    "content": "Signed-off-by: Adrian Moreno <amorenoz@redhat.com>\n---\n python/automake.mk           |   3 +-\n python/ovs/tests/test_odp.py | 527 +++++++++++++++++++++++++++++++++++\n 2 files changed, 529 insertions(+), 1 deletion(-)\n create mode 100644 python/ovs/tests/test_odp.py",
    "diff": "diff --git a/python/automake.mk b/python/automake.mk\nindex 713f1d1a4..cb8697b12 100644\n--- a/python/automake.mk\n+++ b/python/automake.mk\n@@ -56,7 +56,8 @@ ovs_pyfiles = \\\n ovs_tests = \\\n \tpython/ovs/tests/test_kv.py \\\n \tpython/ovs/tests/test_list.py \\\n-\tpython/ovs/tests/test_ofp.py\n+\tpython/ovs/tests/test_ofp.py \\\n+\tpython/ovs/tests/test_odp.py\n \n \n # These python files are used at build time but not runtime,\ndiff --git a/python/ovs/tests/test_odp.py b/python/ovs/tests/test_odp.py\nnew file mode 100644\nindex 000000000..3690d85a7\n--- /dev/null\n+++ b/python/ovs/tests/test_odp.py\n@@ -0,0 +1,527 @@\n+import netaddr\n+import pytest\n+\n+from ovs.flows.odp import ODPFlowFactory\n+from ovs.flows.kv import KeyValue\n+from ovs.flows.decoders import (\n+    EthMask,\n+    IPMask,\n+    Mask32,\n+    Mask16,\n+    Mask8,\n+    Mask128,\n+)\n+\n+\n+@pytest.mark.parametrize(\n+    \"input_string,expected\",\n+    [\n+        (\n+            \"skb_priority(0x123),skb_mark(0x123),recirc_id(0x123),dp_hash(0x123),ct_zone(0x123), actions:\",   # noqa: E501\n+            [\n+                KeyValue(\"skb_priority\", Mask32(\"0x123\")),\n+                KeyValue(\"skb_mark\", Mask32(\"0x123\")),\n+                KeyValue(\"recirc_id\", 0x123),\n+                KeyValue(\"dp_hash\", Mask32(\"0x123\")),\n+                KeyValue(\"ct_zone\", Mask16(\"0x123\")),\n+            ],\n+        ),\n+        (\n+            \"tunnel(tun_id=0x7f10354,src=10.10.10.10,dst=20.20.20.20,ttl=64,flags(csum|key)) actions:\",   # noqa: E501\n+            [\n+                KeyValue(\n+                    \"tunnel\",\n+                    {\n+                        \"tun_id\": 0x7F10354,\n+                        \"src\": IPMask(\"10.10.10.10\"),\n+                        \"dst\": IPMask(\"20.20.20.20\"),\n+                        \"ttl\": 64,\n+                        \"flags\": \"csum|key\",\n+                    },\n+                )\n+            ],\n+        ),\n+        (\n+            \"tunnel(geneve({class=0,type=0,len=4,0xa/0xff}),vxlan(flags=0x800000,vni=0x1c7),erspan(ver=2,dir=1,hwid=0x1)), actions:\",   # noqa: E501\n+            [\n+                KeyValue(\n+                    \"tunnel\",\n+                    {\n+                        \"geneve\": [\n+                            {\n+                                \"class\": Mask16(\"0\"),\n+                                \"type\": Mask8(\"0\"),\n+                                \"len\": Mask8(\"4\"),\n+                                \"data\": Mask128(\"0xa/0xff\"),\n+                            }\n+                        ],\n+                        \"vxlan\": {\"flags\": 0x800000, \"vni\": 0x1C7},\n+                        \"erspan\": {\"ver\": 2, \"dir\": 1, \"hwid\": 0x1},\n+                    },\n+                )\n+            ],\n+        ),\n+        (\n+            \"in_port(2),eth(src=11:22:33:44:55:66,dst=66:55:44:33:22:11) actions:\",   # noqa: E501\n+            [\n+                KeyValue(\"in_port\", 2),\n+                KeyValue(\n+                    \"eth\",\n+                    {\n+                        \"src\": EthMask(\"11:22:33:44:55:66\"),\n+                        \"dst\": EthMask(\"66:55:44:33:22:11\"),\n+                    },\n+                ),\n+            ],\n+        ),\n+        (\n+            \"eth_type(0x800/0x006),ipv4(src=192.168.1.1/24,dst=192.168.0.0/16,proto=0x1,tos=0x2/0xf0) actions:\",  # noqa: E501\n+            [\n+                KeyValue(\"eth_type\", Mask16(\"0x800/0x006\")),\n+                KeyValue(\n+                    \"ipv4\",\n+                    {\n+                        \"src\": IPMask(\"192.168.1.1/24\"),\n+                        \"dst\": IPMask(\"192.168.0.0/16\"),\n+                        \"proto\": Mask8(\"0x1/0xFF\"),\n+                        \"tos\": Mask8(\"0x2/0xF0\"),\n+                    },\n+                ),\n+            ],\n+        ),\n+        (\n+            \"encap(eth_type(0x800/0x006),ipv4(src=192.168.1.1/24,dst=192.168.0.0/16,proto=0x1,tos=0x2/0xf0)) actions:\",   # noqa: E501\n+            [\n+                KeyValue(\n+                    \"encap\",\n+                    {\n+                        \"eth_type\": Mask16(\"0x800/0x006\"),\n+                        \"ipv4\": {\n+                            \"src\": IPMask(\"192.168.1.1/24\"),\n+                            \"dst\": IPMask(\"192.168.0.0/16\"),\n+                            \"proto\": Mask8(\"0x1/0xff\"),\n+                            \"tos\": Mask8(\"0x2/0xf0\"),\n+                        },\n+                    },\n+                ),\n+            ],\n+        ),\n+    ],\n+)\n+def test_odp_fields(input_string, expected):\n+    odp = ODPFlowFactory().from_string(input_string)\n+    match = odp.match_kv\n+    for i in range(len(expected)):\n+        assert expected[i].key == match[i].key\n+        assert expected[i].value == match[i].value\n+\n+        # Assert positions relative to action string are OK\n+        mpos = odp.section(\"match\").pos\n+        mstring = odp.section(\"match\").string\n+\n+        kpos = match[i].meta.kpos\n+        kstr = match[i].meta.kstring\n+        vpos = match[i].meta.vpos\n+        vstr = match[i].meta.vstring\n+        assert mstring[kpos : kpos + len(kstr)] == kstr\n+        if vpos != -1:\n+            assert mstring[vpos : vpos + len(vstr)] == vstr\n+\n+        # assert mstring meta is correct\n+        assert input_string[mpos : mpos + len(mstring)] == mstring\n+\n+\n+@pytest.mark.parametrize(\n+    \"input_string,expected\",\n+    [\n+        (\n+            \"actions:ct\"\n+            \",ct(commit)\"\n+            \",ct(commit,zone=5)\"\n+            \",ct(commit,mark=0xa0a0a0a0/0xfefefefe)\"\n+            \",ct(commit,label=0x1234567890abcdef1234567890abcdef/0xf1f2f3f4f5f6f7f8f9f0fafbfcfdfeff)\"   # noqa: E501\n+            \",ct(commit,helper=ftp)\"\n+            \",ct(commit,helper=tftp)\"\n+            \",ct(commit,timeout=ovs_tp_1_tcp4)\"\n+            \",ct(nat)\",\n+            [\n+                KeyValue(\"ct\", True),\n+                KeyValue(\"ct\", {\"commit\": True}),\n+                KeyValue(\"ct\", {\"commit\": True, \"zone\": 5}),\n+                KeyValue(\n+                    \"ct\",\n+                    {\"commit\": True, \"mark\": Mask32(\"0xA0A0A0A0/0xFEFEFEFE\")},\n+                ),\n+                KeyValue(\n+                    \"ct\",\n+                    {\n+                        \"commit\": True,\n+                        \"label\": Mask128(\n+                            \"0x1234567890ABCDEF1234567890ABCDEF/0xF1F2F3F4F5F6F7F8F9F0FAFBFCFDFEFF\"   # noqa: E501\n+                        ),\n+                    },\n+                ),\n+                KeyValue(\"ct\", {\"commit\": True, \"helper\": \"ftp\"}),\n+                KeyValue(\"ct\", {\"commit\": True, \"helper\": \"tftp\"}),\n+                KeyValue(\"ct\", {\"commit\": True, \"timeout\": \"ovs_tp_1_tcp4\"}),\n+                KeyValue(\"ct\", {\"nat\": True}),\n+            ],\n+        ),\n+        (\n+            \"actions:ct(nat)\"\n+            \",ct(commit,nat(src))\"\n+            \",ct(commit,nat(dst))\"\n+            \",ct(commit,nat(src=10.0.0.240,random))\"\n+            \",ct(commit,nat(src=10.0.0.240:32768-65535,random))\"\n+            \",ct(commit,nat(dst=10.0.0.128-10.0.0.254,hash))\"\n+            \",ct(commit,nat(src=10.0.0.240-10.0.0.254:32768-65535,persistent))\"\n+            \",ct(commit,nat(src=fe80::20c:29ff:fe88:a18b,random))\"\n+            \",ct(commit,nat(src=fe80::20c:29ff:fe88:1-fe80::20c:29ff:fe88:a18b,random))\"   # noqa: E501\n+            \",ct(commit,nat(src=[[fe80::20c:29ff:fe88:1]]-[[fe80::20c:29ff:fe88:a18b]]:255-4096,random))\"   # noqa: E501\n+            \",ct(commit,helper=ftp,nat(src=10.1.1.240-10.1.1.255))\"\n+            \",ct(force_commit)\",\n+            [\n+                KeyValue(\"ct\", {\"nat\": True}),\n+                KeyValue(\"ct\", {\"commit\": True, \"nat\": {\"type\": \"src\"}}),\n+                KeyValue(\"ct\", {\"commit\": True, \"nat\": {\"type\": \"dst\"}}),\n+                KeyValue(\n+                    \"ct\",\n+                    {\n+                        \"commit\": True,\n+                        \"nat\": {\n+                            \"type\": \"src\",\n+                            \"addrs\": {\n+                                \"start\": netaddr.IPAddress(\"10.0.0.240\"),\n+                                \"end\": netaddr.IPAddress(\"10.0.0.240\"),\n+                            },\n+                            \"random\": True,\n+                        },\n+                    },\n+                ),\n+                KeyValue(\n+                    \"ct\",\n+                    {\n+                        \"commit\": True,\n+                        \"nat\": {\n+                            \"type\": \"src\",\n+                            \"addrs\": {\n+                                \"start\": netaddr.IPAddress(\"10.0.0.240\"),\n+                                \"end\": netaddr.IPAddress(\"10.0.0.240\"),\n+                            },\n+                            \"ports\": {\n+                                \"start\": 32768,\n+                                \"end\": 65535,\n+                            },\n+                            \"random\": True,\n+                        },\n+                    },\n+                ),\n+                KeyValue(\n+                    \"ct\",\n+                    {\n+                        \"commit\": True,\n+                        \"nat\": {\n+                            \"type\": \"dst\",\n+                            \"addrs\": {\n+                                \"start\": netaddr.IPAddress(\"10.0.0.128\"),\n+                                \"end\": netaddr.IPAddress(\"10.0.0.254\"),\n+                            },\n+                            \"hash\": True,\n+                        },\n+                    },\n+                ),\n+                KeyValue(\n+                    \"ct\",\n+                    {\n+                        \"commit\": True,\n+                        \"nat\": {\n+                            \"type\": \"src\",\n+                            \"addrs\": {\n+                                \"start\": netaddr.IPAddress(\"10.0.0.240\"),\n+                                \"end\": netaddr.IPAddress(\"10.0.0.254\"),\n+                            },\n+                            \"ports\": {\n+                                \"start\": 32768,\n+                                \"end\": 65535,\n+                            },\n+                            \"persistent\": True,\n+                        },\n+                    },\n+                ),\n+                KeyValue(\n+                    \"ct\",\n+                    {\n+                        \"commit\": True,\n+                        \"nat\": {\n+                            \"type\": \"src\",\n+                            \"addrs\": {\n+                                \"start\": netaddr.IPAddress(\n+                                    \"fe80::20c:29ff:fe88:a18b\"\n+                                ),\n+                                \"end\": netaddr.IPAddress(\n+                                    \"fe80::20c:29ff:fe88:a18b\"\n+                                ),\n+                            },\n+                            \"random\": True,\n+                        },\n+                    },\n+                ),\n+                KeyValue(\n+                    \"ct\",\n+                    {\n+                        \"commit\": True,\n+                        \"nat\": {\n+                            \"type\": \"src\",\n+                            \"addrs\": {\n+                                \"start\": netaddr.IPAddress(\n+                                    \"fe80::20c:29ff:fe88:1\"\n+                                ),\n+                                \"end\": netaddr.IPAddress(\n+                                    \"fe80::20c:29ff:fe88:a18b\"\n+                                ),\n+                            },\n+                            \"random\": True,\n+                        },\n+                    },\n+                ),\n+                KeyValue(\n+                    \"ct\",\n+                    {\n+                        \"commit\": True,\n+                        \"nat\": {\n+                            \"type\": \"src\",\n+                            \"addrs\": {\n+                                \"start\": netaddr.IPAddress(\n+                                    \"fe80::20c:29ff:fe88:1\"\n+                                ),\n+                                \"end\": netaddr.IPAddress(\n+                                    \"fe80::20c:29ff:fe88:a18b\"\n+                                ),\n+                            },\n+                            \"ports\": {\n+                                \"start\": 255,\n+                                \"end\": 4096,\n+                            },\n+                            \"random\": True,\n+                        },\n+                    },\n+                ),\n+                KeyValue(\n+                    \"ct\",\n+                    {\n+                        \"commit\": True,\n+                        \"nat\": {\n+                            \"type\": \"src\",\n+                            \"addrs\": {\n+                                \"start\": netaddr.IPAddress(\"10.1.1.240\"),\n+                                \"end\": netaddr.IPAddress(\"10.1.1.255\"),\n+                            },\n+                        },\n+                        \"helper\": \"ftp\",\n+                    },\n+                ),\n+                KeyValue(\"ct\", {\"force_commit\": True}),\n+            ],\n+        ),\n+        (\n+            \"actions:set(tunnel(tun_id=0xabcdef1234567890,src=1.1.1.1,dst=2.2.2.2,ttl=64,flags(df|csum|key)))\"   # noqa: E501\n+            \",tnl_pop(4)\"\n+            \",tnl_push(tnl_port(6),header(size=50,type=4,eth(dst=f8:bc:12:44:34:b6,src=f8:bc:12:46:58:e0,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.92,proto=17,tos=0,ttl=64,frag=0x4000),udp(src=0,dst=4789,csum=0x0),vxlan(flags=0x8000000,vni=0x1c7)),out_port(1))\"   # noqa: E501\n+            \",tnl_push(tnl_port(6),header(size=70,type=4,eth(dst=f8:bc:12:44:34:b6,src=f8:bc:12:46:58:e0,dl_type=0x86dd),ipv6(src=2001:cafe::88,dst=2001:cafe::92,label=0,proto=17,tclass=0x0,hlimit=64),udp(src=0,dst=4789,csum=0x0),vxlan(flags=0x8000000,vni=0x1c7)),out_port(1))\",   # noqa: E501\n+            [\n+                KeyValue(\n+                    \"set\",\n+                    {\n+                        \"tunnel\": {\n+                            \"tun_id\": 0xABCDEF1234567890,\n+                            \"src\": IPMask(\"1.1.1.1\"),\n+                            \"dst\": IPMask(\"2.2.2.2\"),\n+                            \"ttl\": 64,\n+                            \"flags\": \"df|csum|key\",\n+                        }\n+                    },\n+                ),\n+                KeyValue(\"tnl_pop\", 4),\n+                KeyValue(\n+                    \"tnl_push\",\n+                    {\n+                        \"tnl_port\": 6,\n+                        \"header\": {\n+                            \"size\": 50,\n+                            \"type\": 4,\n+                            \"eth\": {\n+                                \"dst\": EthMask(\"f8:bc:12:44:34:b6\"),\n+                                \"src\": EthMask(\"f8:bc:12:46:58:e0\"),\n+                                \"dl_type\": 0x800,\n+                            },\n+                            \"ipv4\": {\n+                                \"src\": IPMask(\"1.1.2.88\"),\n+                                \"dst\": IPMask(\"1.1.2.92\"),\n+                                \"proto\": 17,\n+                                \"tos\": 0,\n+                                \"ttl\": 64,\n+                                \"frag\": 0x4000,\n+                            },\n+                            \"udp\": {\"src\": 0, \"dst\": 4789, \"csum\": 0x0},\n+                            \"vxlan\": {\n+                                \"flags\": 0x8000000,\n+                                \"vni\": 0x1C7,\n+                            },\n+                        },\n+                        \"out_port\": 1,\n+                    },\n+                ),\n+                KeyValue(\n+                    \"tnl_push\",\n+                    {\n+                        \"tnl_port\": 6,\n+                        \"header\": {\n+                            \"size\": 70,\n+                            \"type\": 4,\n+                            \"eth\": {\n+                                \"dst\": EthMask(\"f8:bc:12:44:34:b6\"),\n+                                \"src\": EthMask(\"f8:bc:12:46:58:e0\"),\n+                                \"dl_type\": 0x86DD,\n+                            },\n+                            \"ipv6\": {\n+                                \"src\": IPMask(\"2001:cafe::88\"),\n+                                \"dst\": IPMask(\"2001:cafe::92\"),\n+                                \"label\": 0,\n+                                \"proto\": 17,\n+                                \"tclass\": 0x0,\n+                                \"hlimit\": 64,\n+                            },\n+                            \"udp\": {\"src\": 0, \"dst\": 4789, \"csum\": 0x0},\n+                            \"vxlan\": {\n+                                \"flags\": 0x8000000,\n+                                \"vni\": 0x1C7,\n+                            },\n+                        },\n+                        \"out_port\": 1,\n+                    },\n+                ),\n+            ],\n+        ),\n+        (\n+            \"actions:tnl_push(header(geneve(oam,vni=0x1c7)))\"\n+            \",tnl_push(header(geneve(crit,vni=0x1c7,options({class=0xffff,type=0x80,len=4,0xa}))))\"   # noqa: E501\n+            \",tnl_push(header(gre((flags=0xa000,proto=0x6558),csum=0x0,key=0x1e241)))\",   # noqa: E501\n+            [\n+                KeyValue(\n+                    \"tnl_push\",\n+                    {\n+                        \"header\": {\n+                            \"geneve\": {\n+                                \"oam\": True,\n+                                \"vni\": 0x1C7,\n+                            }\n+                        }\n+                    },\n+                ),\n+                KeyValue(\n+                    \"tnl_push\",\n+                    {\n+                        \"header\": {\n+                            \"geneve\": {\n+                                \"crit\": True,\n+                                \"vni\": 0x1C7,\n+                                \"options\": [\n+                                    {\n+                                        \"class\": 0xFFFF,\n+                                        \"type\": 0x80,\n+                                        \"len\": 4,\n+                                        \"data\": 0xA,\n+                                    }\n+                                ],\n+                            }\n+                        }\n+                    },\n+                ),\n+                KeyValue(\n+                    \"tnl_push\",\n+                    {\n+                        \"header\": {\n+                            \"gre\": {\n+                                \"flags\": 0xA000,\n+                                \"proto\": 0x6558,\n+                                \"key\": 0x1E241,\n+                                \"csum\": 0x0,\n+                            }\n+                        }\n+                    },\n+                ),\n+            ],\n+        ),\n+        (\n+            \"actions:clone(1)\" \",clone(clone(push_vlan(vid=12,pcp=0),2),1)\",\n+            [\n+                KeyValue(\"clone\", {\"output\": {\"port\": 1}}),\n+                KeyValue(\n+                    \"clone\",\n+                    {\n+                        \"output\": {\"port\": 1},\n+                        \"clone\": {\n+                            \"push_vlan\": {\n+                                \"vid\": 12,\n+                                \"pcp\": 0,\n+                            },\n+                            \"output\": {\"port\": 2},\n+                        },\n+                    },\n+                ),\n+            ],\n+        ),\n+        (\n+            \"actions: check_pkt_len(size=200,gt(4),le(5))\"\n+            \",check_pkt_len(size=200,gt(drop),le(5))\"\n+            \",check_pkt_len(size=200,gt(ct(nat)),le(drop))\",\n+            [\n+                KeyValue(\n+                    \"check_pkt_len\",\n+                    {\n+                        \"size\": 200,\n+                        \"gt\": {\"output\": {\"port\": 4}},\n+                        \"le\": {\"output\": {\"port\": 5}},\n+                    },\n+                ),\n+                KeyValue(\n+                    \"check_pkt_len\",\n+                    {\n+                        \"size\": 200,\n+                        \"gt\": {\"drop\": True},\n+                        \"le\": {\"output\": {\"port\": 5}},\n+                    },\n+                ),\n+                KeyValue(\n+                    \"check_pkt_len\",\n+                    {\n+                        \"size\": 200,\n+                        \"gt\": {\"ct\": {\"nat\": True}},\n+                        \"le\": {\"drop\": True},\n+                    },\n+                ),\n+            ],\n+        ),\n+    ],\n+)\n+def test_odp_actions(input_string, expected):\n+    odp = ODPFlowFactory().from_string(input_string)\n+    actions = odp.actions_kv\n+    for i in range(len(expected)):\n+        assert expected[i].key == actions[i].key\n+        assert expected[i].value == actions[i].value\n+\n+        # Assert positions relative to action string are OK\n+        apos = odp.section(\"actions\").pos\n+        astring = odp.section(\"actions\").string\n+\n+        kpos = actions[i].meta.kpos\n+        kstr = actions[i].meta.kstring\n+        vpos = actions[i].meta.vpos\n+        vstr = actions[i].meta.vstring\n+        assert astring[kpos : kpos + len(kstr)] == kstr\n+        if vpos != -1:\n+            assert astring[vpos : vpos + len(vstr)] == vstr\n+\n+        # assert astring meta is correct\n+        assert input_string[apos : apos + len(astring)] == astring\n",
    "prefixes": [
        "ovs-dev",
        "v1",
        "17/18"
    ]
}