get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 1561024,
    "url": "http://patchwork.ozlabs.org/api/patches/1561024/",
    "web_url": "http://patchwork.ozlabs.org/project/openvswitch/patch/20211129062205.2120-1-martinvarghesenokia@gmail.com/",
    "project": {
        "id": 47,
        "url": "http://patchwork.ozlabs.org/api/projects/47/",
        "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": "<20211129062205.2120-1-martinvarghesenokia@gmail.com>",
    "list_archive_url": null,
    "date": "2021-11-29T06:22:05",
    "name": "[ovs-dev,v8] Encap & Decap actions for MPLS packet type.",
    "commit_ref": "1917ace89364d366777b34467e952358d2d85b41",
    "pull_url": null,
    "state": "accepted",
    "archived": false,
    "hash": "ec6d642a77c104692df43df931a7fc70c9bb8167",
    "submitter": {
        "id": 77614,
        "url": "http://patchwork.ozlabs.org/api/people/77614/",
        "name": "Martin Varghese",
        "email": "martinvarghesenokia@gmail.com"
    },
    "delegate": null,
    "mbox": "http://patchwork.ozlabs.org/project/openvswitch/patch/20211129062205.2120-1-martinvarghesenokia@gmail.com/mbox/",
    "series": [
        {
            "id": 274153,
            "url": "http://patchwork.ozlabs.org/api/series/274153/",
            "web_url": "http://patchwork.ozlabs.org/project/openvswitch/list/?series=274153",
            "date": "2021-11-29T06:22:05",
            "name": "[ovs-dev,v8] Encap & Decap actions for MPLS packet type.",
            "version": 8,
            "mbox": "http://patchwork.ozlabs.org/series/274153/mbox/"
        }
    ],
    "comments": "http://patchwork.ozlabs.org/api/patches/1561024/comments/",
    "check": "warning",
    "checks": "http://patchwork.ozlabs.org/api/patches/1561024/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\" (2048-bit key;\n unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256\n header.s=20210112 header.b=MjW1sXru;\n\tdkim-atps=neutral",
            "ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org\n (client-ip=2605:bc80:3010::133; helo=smtp2.osuosl.org;\n envelope-from=ovs-dev-bounces@openvswitch.org; receiver=<UNKNOWN>)",
            "smtp1.osuosl.org (amavisd-new);\n dkim=pass (2048-bit key) header.d=gmail.com"
        ],
        "Received": [
            "from smtp2.osuosl.org (smtp2.osuosl.org [IPv6:2605:bc80:3010::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 4J2ZyW2v6Yz9t0T\n\tfor <incoming@patchwork.ozlabs.org>; Mon, 29 Nov 2021 17:22:26 +1100 (AEDT)",
            "from localhost (localhost [127.0.0.1])\n\tby smtp2.osuosl.org (Postfix) with ESMTP id 62D4C40254;\n\tMon, 29 Nov 2021 06:22:20 +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 zW0Q_yI6jthp; Mon, 29 Nov 2021 06:22:17 +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 2238C400A6;\n\tMon, 29 Nov 2021 06:22:16 +0000 (UTC)",
            "from lf-lists.osuosl.org (localhost [127.0.0.1])\n\tby lists.linuxfoundation.org (Postfix) with ESMTP id EE989C001C;\n\tMon, 29 Nov 2021 06:22:15 +0000 (UTC)",
            "from smtp1.osuosl.org (smtp1.osuosl.org [140.211.166.138])\n by lists.linuxfoundation.org (Postfix) with ESMTP id 6F147C000A\n for <dev@openvswitch.org>; Mon, 29 Nov 2021 06:22:14 +0000 (UTC)",
            "from localhost (localhost [127.0.0.1])\n by smtp1.osuosl.org (Postfix) with ESMTP id 482A682F87\n for <dev@openvswitch.org>; Mon, 29 Nov 2021 06:22:14 +0000 (UTC)",
            "from smtp1.osuosl.org ([127.0.0.1])\n by localhost (smtp1.osuosl.org [127.0.0.1]) (amavisd-new, port 10024)\n with ESMTP id FiCTBuTlf9rh for <dev@openvswitch.org>;\n Mon, 29 Nov 2021 06:22:11 +0000 (UTC)",
            "from mail-pf1-x429.google.com (mail-pf1-x429.google.com\n [IPv6:2607:f8b0:4864:20::429])\n by smtp1.osuosl.org (Postfix) with ESMTPS id B70C182F80\n for <dev@openvswitch.org>; Mon, 29 Nov 2021 06:22:11 +0000 (UTC)",
            "by mail-pf1-x429.google.com with SMTP id x5so15829854pfr.0\n for <dev@openvswitch.org>; Sun, 28 Nov 2021 22:22:11 -0800 (PST)",
            "from martin-ubuntu ([106.201.126.71])\n by smtp.gmail.com with ESMTPSA id a23sm11137720pgl.37.2021.11.28.22.22.09\n (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);\n Sun, 28 Nov 2021 22:22:10 -0800 (PST)"
        ],
        "X-Virus-Scanned": [
            "amavisd-new at osuosl.org",
            "amavisd-new at osuosl.org"
        ],
        "X-Greylist": "whitelisted by SQLgrey-1.8.0",
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112;\n h=from:to:cc:subject:date:message-id:mime-version\n :content-transfer-encoding;\n bh=Z/o3HX+7lHSrpbzA5RZ4CFIXPu7/r4feMIQQP7UYJLA=;\n b=MjW1sXruyxP5gn9mmWpMca1jE6ezuBC1XSX8vUiuTKBuA5GR9lzk9TLT4MarS8fSvx\n 2T3GoUakWDd7kFW0kXsHh39GPq9ZzFNGtV7ueEF2oXehz7ivZAo7JHTYhn4lFGpdRxLb\n Wh9FQ/6GfCdYgKqqRNCZvV6zlBToAySMCOjO6gvWKoQtm262QwO/4duuX+KmPjdCXRUM\n Dk4+aQ91dOQkVV685ifKsklRGQg6biaKTVUjZ5zS3z+IgbBrLbE+UOlSsR6bB46FIg2Z\n f4lbYspgok591zV+gi+54Plw69mqBlu/smMQxvKiSLn/i2Kzir4rtyzbfpUvnRp/4Vhz\n JGYQ==",
        "X-Google-DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=1e100.net; s=20210112;\n h=x-gm-message-state:from:to:cc:subject:date:message-id:mime-version\n :content-transfer-encoding;\n bh=Z/o3HX+7lHSrpbzA5RZ4CFIXPu7/r4feMIQQP7UYJLA=;\n b=fkYOG4G5MEdfDDKgjMjo89AVCuro3PDRlPL0guRMqRHYyYUBB20im+w+FQbU5KFX8f\n YkD1lrURdfYhXptWKrJ52TdM8ki7RKwaYki5OqwUcmNF7Qa54DmQs3LoEoxiSbotNz+6\n 9psUqcBv6LlwcEu+mKzoVyk3WQj0bzmKAUVnhtmY26RplfmS/x7erqBLddmKUHgyI+Wk\n LhQIX6amMjxhOpsni8J4VuCmuD6eKoPx3dPrCLQ+kkJLNmThYgiAxuLa6d02ByCDPmRf\n BIrKYnE3hFHdBF4rhFi+b1tbZkhV6LZGYp/lgq890rl/xpyhhBSO7wcDdAW/NJkWqutF\n jIDg==",
        "X-Gm-Message-State": "AOAM533ZuZ7DMvhYunU8ndYCHkFBsl5OCE0jmGvh+5RtS6aAVIonfh0a\n iOzSaQrgi+FYzYyrUZWaAV8=",
        "X-Google-Smtp-Source": "\n ABdhPJz3iITTcALMgO1BLldfo9omoONtsjfAF7Il/6iywTOLiSOqOEXF97v+NoUtZAS2AJ8ec5gU/g==",
        "X-Received": "by 2002:a63:1c66:: with SMTP id\n c38mr20410684pgm.622.1638166930705;\n Sun, 28 Nov 2021 22:22:10 -0800 (PST)",
        "From": "Martin Varghese <martinvarghesenokia@gmail.com>",
        "To": "dev@openvswitch.org, i.maximets@ovn.org, echaudro@redhat.com,\n jan.scheurich@ericsson.com",
        "Date": "Mon, 29 Nov 2021 11:52:05 +0530",
        "Message-Id": "<20211129062205.2120-1-martinvarghesenokia@gmail.com>",
        "X-Mailer": "git-send-email 2.27.0",
        "MIME-Version": "1.0",
        "Cc": "Martin Varghese <martin.varghese@nokia.com>",
        "Subject": "[ovs-dev] [PATCH v8] Encap & Decap actions for MPLS packet type.",
        "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": "From: Martin Varghese <martin.varghese@nokia.com>\n\nThe encap & decap actions are extended to support MPLS packet type.\nEncap & decap actions adds and removes MPLS header at start of the\npacket.\n\nThe existing PUSH MPLS & POP MPLS actions inserts & removes MPLS\nheader between ethernet header and the IP header. Though this behaviour\nis fine for L3 VPN where an IP packet is encapsulated inside a MPLS\ntunnel, it does not suffice the L2 VPN requirements. In L2 VPN the\nethernet packets must be encapsulated inside MPLS tunnel.\n\nIn this change the encap & decap actions are extended to support MPLS\npacket type. The encap & decap adds and removes MPLS header at the\nstart of packet as depicted below.\n\nEncapsulation:\n\nActions - encap(mpls(ether_type=0x8847)),encap(ethernet)\n\nIncoming packet -> | ETH | IP | Payload |\n\n1 Actions -  encap(mpls(ether_type=0x8847)) [Datapath action - ADD_MPLS:0x8847]\n\n        Outgoing packet -> | MPLS | ETH | Payload|\n\n2 Actions - encap(ethernet) [ Datapath action - push_eth ]\n\n        Outgoing packet -> | ETH | MPLS | ETH | Payload|\n\nDecapsulation:\n\nIncoming packet -> | ETH | MPLS | ETH | IP | Payload |\n\nActions - decap(),decap(packet_type(ns=0,type=0)\n\n1 Actions -  decap() [Datapath action - pop_eth)\n\n        Outgoing packet -> | MPLS | ETH | IP | Payload|\n\n2 Actions - decap(packet_type(ns=0,type=0) [Datapath action - POP_MPLS:0x6558]\n\n        Outgoing packet -> | ETH  | IP | Payload|\n\nSigned-off-by: Martin Varghese <martin.varghese@nokia.com>\nAcked-by: Eelco Chaudron <echaudro@redhat.com>\n---\nChanges in v2:\n   - Fixed the compilation error reported by bot.\n\nChanges in v3:\n   - Adapted the changes to allign with the kernel implementaion\n\nChanges in v4:\n   - Fixed the compilation error reported by bot.\n   - Added SLOW_ACTION support for no datapath support.\n\nChanges in v5:\n   -  Code styling fixed.\n   -  Given reference for packet_type field in documentation.\n   -  Modified code to do recirc only for the last label.\n   -  Cleaed l2,l3,l4 fields with encap.\n   -  Fixed existing encap & decap tests to do set eth to outer header\n   -  Added tests to verify Encap & Decap with legacy Push & Pop.\n   -  Added xlate tests.\n   -  Added seperate tests to inspect packet after encap & decap.\n   -  Added tests for multiple mpls test cases.\n\nChanges in v6:\n   - Styling and variable naming fixed.\n   - Tests added for slow path support.\n   - Added comments in code.\n   - Added odp test for add_mpls action.\n   - Documentation added in ovs-actions.7.rst\n\nChanges in v7:\n   - Fixed Documentation.\n   - Initialized variables in odp test.\n   - Add test skip for no dp support.\n\nChanges in v8:\n   - Changed the encap action format from encap(mpls(ethertype=0x884*)\n     to encap(mpls) & encap(mpls_mc). MPLS multicast & unicast are \n     2 different packet_types and have 2 different ethertype values.\n     Hence the new format is more consistent with other encap types.\n   - Fixed Documentation errors.\n   - Added check for MAX labels.\n   - Added tests for Max label check.\n   - Added tcpdump check in tests. \n   - structures rearranged in openvswitch.h.\n   - Cosmetics changes.\n   - Added Ack by echaudro@redhat.com\n\n Documentation/ref/ovs-actions.7.rst           |  28 +-\n NEWS                                          |   1 +\n .../linux/compat/include/linux/openvswitch.h  |  30 ++\n lib/dpif-netdev.c                             |   1 +\n lib/dpif.c                                    |   1 +\n lib/odp-execute.c                             |  12 +\n lib/odp-util.c                                |  74 +++-\n lib/ofp-actions.c                             |  10 +\n lib/ofp-ed-props.c                            |   2 +\n lib/packets.c                                 |  46 +++\n lib/packets.h                                 |   2 +\n ofproto/ofproto-dpif-ipfix.c                  |   1 +\n ofproto/ofproto-dpif-sflow.c                  |   1 +\n ofproto/ofproto-dpif-xlate.c                  |  85 ++++\n ofproto/ofproto-dpif.c                        |  38 ++\n ofproto/ofproto-dpif.h                        |   4 +-\n tests/mpls-xlate.at                           | 119 ++++++\n tests/odp.at                                  |   1 +\n tests/ofp-actions.at                          |   8 +\n tests/system-traffic.at                       | 376 ++++++++++++++++++\n 20 files changed, 826 insertions(+), 14 deletions(-)",
    "diff": "diff --git a/Documentation/ref/ovs-actions.7.rst b/Documentation/ref/ovs-actions.7.rst\nindex 7224896df..936f32f4e 100644\n--- a/Documentation/ref/ovs-actions.7.rst\n+++ b/Documentation/ref/ovs-actions.7.rst\n@@ -212,12 +212,13 @@ Unsupported packet type\n   is not an L3 packet, and ``encap(nsh)`` raises this error if the current\n   packet is not Ethernet, IPv4, IPv6, or NSH.\n \n+  The ``decap`` action is supported only for packet types ethernet, NSH and\n+  MPLS.  Openvswitch raises this error for other packet types.\n   When a ``decap`` action decapsulates a packet, Open vSwitch raises this error\n   if it does not support the type of inner packet.  ``decap`` of an Ethernet\n   header raises this error if a VLAN header is present, ``decap`` of a NSH\n   packet raises this error if the NSH inner packet is not Ethernet, IPv4, IPv6,\n-  or NSH, and ``decap`` of other types of packets is unsupported and also\n-  raises this error.\n+  or NSH.\n \n   This error terminates packet processing, retaining any previous side effects\n   (e.g. output actions).  When this error arises within the execution of a\n@@ -995,6 +996,8 @@ The ``encap`` action\n   | ``encap(nsh([md_type=``\\ *md_type*\\\n                  ``], [tlv(``\\ *class*,\\ *type*,\\ *value*\\ ``)]...))``\n   | ``encap(ethernet)``\n+  | ``encap(mpls)``\n+  | ``encap(mpls_mc)``\n \n The ``encap`` action encapsulates a packet with a specified header.  It has\n variants for different kinds of encapsulation.\n@@ -1018,10 +1021,20 @@ frame.  The Ethernet type is initialized to the L3 packet's type, e.g. 0x0800\n if the L3 packet is IPv4.  The Ethernet source and destination are initially\n zeroed.\n \n+The ``encap(mpls)`` variant adds a MPLS header at the start of the packet.\n+When encap(ethernet) is applied after this action, the ethertype of ethernet\n+header will be populated with MPLS unicast ethertype (``0x8847``).\n+\n+The ``encap(mpls_mc)`` variant adds a MPLS header at the start of the packet.\n+When encap(ethernet) is applied after this action, the ethertype of ethernet\n+header will be populated with MPLS multicast ethertype (``0x8848``).\n+\n **Conformance**\n   This action is an Open vSwitch extension to OpenFlow 1.3 and later,\n   introduced in Open vSwitch 2.8.\n \n+  The MPLS support for this action is added in Open vSwitch 2.17.\n+\n \n The ``decap`` action\n --------------------\n@@ -1030,6 +1043,7 @@ The ``decap`` action\n \n **Syntax**:\n   | ``decap``\n+  | ``decap(packet_type(ns=``\\*namespace,*\\ ``type=``\\*type*\\ ``))``\n \n Removes an outermost encapsulation from the packet:\n \n@@ -1042,12 +1056,22 @@ Removes an outermost encapsulation from the packet:\n     and NSH inner packet types.  Other types raise unsupported packet type\n     errors.\n \n+  - Otherwise, if the packet is encapsulated inside a MPLS header, removes\n+    the MPLS header and classifies the inner packet as mentioned in the packet\n+    type argument of the decap.  The packet_type field specifies the type of\n+    the packet in the format specified in OpenFlow 1.5 chapter\n+    `7.2.3.11 Packet Type Match Field`.  The inner packet will be incorrectly\n+    classified, if the inner packet is different from mentioned in the\n+    packet_type field.\n+\n   - Otherwise, raises an unsupported packet type error.\n \n **Conformance**\n   This action is an Open vSwitch extension to OpenFlow 1.3 and later,\n   introduced in Open vSwitch 2.8.\n \n+  The MPLS support for this action is added in Open vSwitch 2.17.\n+\n \n Field Modification Actions\n ==========================\ndiff --git a/NEWS b/NEWS\nindex 434ee570f..c9ab310c0 100644\n--- a/NEWS\n+++ b/NEWS\n@@ -16,6 +16,7 @@ Post-v2.16.0\n    - ovs-dpctl and 'ovs-appctl dpctl/':\n      * New commands 'cache-get-size' and 'cache-set-size' that allows to\n        get or configure linux kernel datapath cache sizes.\n+   - Encap & Decap action support for MPLS packet type.\n \n \n v2.16.0 - 16 Aug 2021\ndiff --git a/datapath/linux/compat/include/linux/openvswitch.h b/datapath/linux/compat/include/linux/openvswitch.h\nindex 936644192..31966fcf0 100644\n--- a/datapath/linux/compat/include/linux/openvswitch.h\n+++ b/datapath/linux/compat/include/linux/openvswitch.h\n@@ -754,6 +754,31 @@ struct ovs_action_push_mpls {\n \t__be16 mpls_ethertype; /* Either %ETH_P_MPLS_UC or %ETH_P_MPLS_MC */\n };\n \n+/* struct ovs_action_add_mpls - %OVS_ACTION_ATTR_ADD_MPLS action\n+ * argument.\n+ * @mpls_lse: MPLS label stack entry to push.\n+ * @mpls_ethertype: Ethertype to set in the encapsulating ethernet frame.\n+ * @tun_flags: MPLS tunnel attributes.\n+ *\n+ * The only values @mpls_ethertype should ever be given are %ETH_P_MPLS_UC and\n+ * %ETH_P_MPLS_MC, indicating MPLS unicast or multicast. Other are rejected.\n+ */\n+struct ovs_action_add_mpls {\n+\t__be32 mpls_lse;\n+\t__be16 mpls_ethertype; /* Either %ETH_P_MPLS_UC or %ETH_P_MPLS_MC */\n+\t__u16 tun_flags;\n+};\n+\n+#define OVS_MPLS_L3_TUNNEL_FLAG_MASK  (1 << 0) /* Flag to specify the place of\n+\t\t\t\t\t\t* insertion of MPLS header.\n+\t\t\t\t\t\t* When false, the MPLS header\n+\t\t\t\t\t\t* will be inserted at the start\n+\t\t\t\t\t\t* of the packet.\n+\t\t\t\t\t\t* When true, the MPLS header\n+\t\t\t\t\t\t* will be inserted at the start\n+\t\t\t\t\t\t* of the l3 header.\n+\t\t\t\t\t\t*/\n+\n /**\n  * struct ovs_action_push_vlan - %OVS_ACTION_ATTR_PUSH_VLAN action argument.\n  * @vlan_tpid: Tag protocol identifier (TPID) to push.\n@@ -1008,6 +1033,10 @@ struct check_pkt_len_arg {\n  * @OVS_ACTION_ATTR_CHECK_PKT_LEN: Check the packet length and execute a set\n  * of actions if greater than the specified packet length, else execute\n  * another set of actions.\n+ * @OVS_ACTION_ATTR_ADD_MPLS: Push a new MPLS label stack entry at the\n+ * start of the packet or at the start of the l3 header depending on the value\n+ * of l3 tunnel flag in the tun_flags field of OVS_ACTION_ATTR_ADD_MPLS\n+ * argument.\n  * @OVS_ACTION_ATTR_DROP: Explicit drop action.\n  */\n \n@@ -1037,6 +1066,7 @@ enum ovs_action_attr {\n \tOVS_ACTION_ATTR_METER,        /* u32 meter number. */\n \tOVS_ACTION_ATTR_CLONE,        /* Nested OVS_CLONE_ATTR_*.  */\n \tOVS_ACTION_ATTR_CHECK_PKT_LEN, /* Nested OVS_CHECK_PKT_LEN_ATTR_*. */\n+\tOVS_ACTION_ATTR_ADD_MPLS,     /* struct ovs_action_add_mpls. */\n \n #ifndef __KERNEL__\n \tOVS_ACTION_ATTR_TUNNEL_PUSH,   /* struct ovs_action_push_tnl*/\ndiff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c\nindex 98453a206..b80573ad1 100644\n--- a/lib/dpif-netdev.c\n+++ b/lib/dpif-netdev.c\n@@ -8315,6 +8315,7 @@ dp_execute_cb(void *aux_, struct dp_packet_batch *packets_,\n     case OVS_ACTION_ATTR_CT_CLEAR:\n     case OVS_ACTION_ATTR_CHECK_PKT_LEN:\n     case OVS_ACTION_ATTR_DROP:\n+    case OVS_ACTION_ATTR_ADD_MPLS:\n     case __OVS_ACTION_ATTR_MAX:\n         OVS_NOT_REACHED();\n     }\ndiff --git a/lib/dpif.c b/lib/dpif.c\nindex 38bcb47cb..0cfae1553 100644\n--- a/lib/dpif.c\n+++ b/lib/dpif.c\n@@ -1274,6 +1274,7 @@ dpif_execute_helper_cb(void *aux_, struct dp_packet_batch *packets_,\n     case OVS_ACTION_ATTR_UNSPEC:\n     case OVS_ACTION_ATTR_CHECK_PKT_LEN:\n     case OVS_ACTION_ATTR_DROP:\n+    case OVS_ACTION_ATTR_ADD_MPLS:\n     case __OVS_ACTION_ATTR_MAX:\n         OVS_NOT_REACHED();\n     }\ndiff --git a/lib/odp-execute.c b/lib/odp-execute.c\nindex 6eeda2a61..2f4cdd92c 100644\n--- a/lib/odp-execute.c\n+++ b/lib/odp-execute.c\n@@ -819,6 +819,7 @@ requires_datapath_assistance(const struct nlattr *a)\n     case OVS_ACTION_ATTR_POP_NSH:\n     case OVS_ACTION_ATTR_CT_CLEAR:\n     case OVS_ACTION_ATTR_CHECK_PKT_LEN:\n+    case OVS_ACTION_ATTR_ADD_MPLS:\n     case OVS_ACTION_ATTR_DROP:\n         return false;\n \n@@ -1061,6 +1062,17 @@ odp_execute_actions(void *dp, struct dp_packet_batch *batch, bool steal,\n             }\n             break;\n \n+        case OVS_ACTION_ATTR_ADD_MPLS: {\n+            const struct ovs_action_add_mpls *mpls = nl_attr_get(a);\n+            bool l3_flag =  mpls->tun_flags & OVS_MPLS_L3_TUNNEL_FLAG_MASK;\n+\n+            DP_PACKET_BATCH_FOR_EACH (i, packet, batch) {\n+                add_mpls(packet, mpls->mpls_ethertype, mpls->mpls_lse,\n+                         l3_flag);\n+            }\n+            break;\n+        }\n+\n         case OVS_ACTION_ATTR_DROP:{\n             const enum xlate_error *drop_reason = nl_attr_get(a);\n \ndiff --git a/lib/odp-util.c b/lib/odp-util.c\nindex fbdfc7ad8..5d8cea0dc 100644\n--- a/lib/odp-util.c\n+++ b/lib/odp-util.c\n@@ -142,6 +142,7 @@ odp_action_len(uint16_t type)\n     case OVS_ACTION_ATTR_PUSH_NSH: return ATTR_LEN_VARIABLE;\n     case OVS_ACTION_ATTR_POP_NSH: return 0;\n     case OVS_ACTION_ATTR_CHECK_PKT_LEN: return ATTR_LEN_VARIABLE;\n+    case OVS_ACTION_ATTR_ADD_MPLS: return sizeof(struct ovs_action_add_mpls);\n     case OVS_ACTION_ATTR_DROP: return sizeof(uint32_t);\n \n     case OVS_ACTION_ATTR_UNSPEC:\n@@ -1254,6 +1255,14 @@ format_odp_action(struct ds *ds, const struct nlattr *a,\n     case OVS_ACTION_ATTR_CHECK_PKT_LEN:\n         format_odp_check_pkt_len_action(ds, a, portno_names);\n         break;\n+    case OVS_ACTION_ATTR_ADD_MPLS: {\n+        const struct ovs_action_add_mpls *mpls = nl_attr_get(a);\n+        ds_put_cstr(ds, \"add_mpls(\");\n+        format_mpls_lse(ds, mpls->mpls_lse);\n+        ds_put_format(ds, \",eth_type=0x%\"PRIx16\")\",\n+                      ntohs(mpls->mpls_ethertype));\n+        break;\n+    }\n     case OVS_ACTION_ATTR_DROP:\n         ds_put_cstr(ds, \"drop\");\n         break;\n@@ -2595,6 +2604,29 @@ parse_odp_action__(struct parse_odp_context *context, const char *s,\n             return retval;\n         }\n     }\n+    {\n+        struct ovs_action_add_mpls mpls;\n+        uint32_t lse;\n+        uint8_t ttl, tc, bos;\n+        int n = -1;\n+        uint16_t eth_type;\n+\n+        if (ovs_scan(s,\n+                     \"add_mpls(label=%\"SCNi32\",tc=%\"SCNd8\",ttl=%\"SCNd8\",bos=%\"SCNd8\",eth_type=0x%\"SCNx16\")%n\",\n+                     &lse, &tc, &ttl, &bos, &eth_type, &n)) {\n+\n+            mpls.mpls_ethertype = htons(eth_type);\n+            mpls.mpls_lse = htonl(lse << MPLS_LABEL_SHIFT |\n+                                  tc  << MPLS_TC_SHIFT |\n+                                  ttl << MPLS_TTL_SHIFT |\n+                                  bos << MPLS_BOS_SHIFT);\n+            mpls.tun_flags = 0;\n+            nl_msg_put_unspec(actions, OVS_ACTION_ATTR_ADD_MPLS,\n+                              &mpls, sizeof mpls);\n+\n+            return n;\n+        }\n+    }\n \n     {\n         struct ovs_action_push_tnl data;\n@@ -7890,7 +7922,7 @@ commit_vlan_action(const struct flow* flow, struct flow *base,\n /* Wildcarding already done at action translation time. */\n static void\n commit_mpls_action(const struct flow *flow, struct flow *base,\n-                   struct ofpbuf *odp_actions)\n+                   struct ofpbuf *odp_actions, bool pending_encap)\n {\n     int base_n = flow_count_mpls_labels(base, NULL);\n     int flow_n = flow_count_mpls_labels(flow, NULL);\n@@ -7938,18 +7970,29 @@ commit_mpls_action(const struct flow *flow, struct flow *base,\n     /* If, after the above popping and setting, there are more LSEs in flow\n      * than base then some LSEs need to be pushed. */\n     while (base_n < flow_n) {\n-        struct ovs_action_push_mpls *mpls;\n \n-        mpls = nl_msg_put_unspec_zero(odp_actions,\n-                                      OVS_ACTION_ATTR_PUSH_MPLS,\n-                                      sizeof *mpls);\n-        mpls->mpls_ethertype = flow->dl_type;\n-        mpls->mpls_lse = flow->mpls_lse[flow_n - base_n - 1];\n+        if (pending_encap) {\n+             struct ovs_action_add_mpls *mpls;\n+\n+             mpls = nl_msg_put_unspec_zero(odp_actions,\n+                                           OVS_ACTION_ATTR_ADD_MPLS,\n+                                           sizeof *mpls);\n+             mpls->mpls_ethertype = flow->dl_type;\n+             mpls->mpls_lse = flow->mpls_lse[flow_n - base_n - 1];\n+        } else {\n+             struct ovs_action_push_mpls *mpls;\n+\n+             mpls = nl_msg_put_unspec_zero(odp_actions,\n+                                           OVS_ACTION_ATTR_PUSH_MPLS,\n+                                           sizeof *mpls);\n+             mpls->mpls_ethertype = flow->dl_type;\n+             mpls->mpls_lse = flow->mpls_lse[flow_n - base_n - 1];\n+        }\n         /* Update base flow's MPLS stack, but do not clear L3.  We need the L3\n          * headers if the flow is restored later due to returning from a patch\n          * port or group bucket. */\n-        flow_push_mpls(base, base_n, mpls->mpls_ethertype, NULL, false);\n-        flow_set_mpls_lse(base, 0, mpls->mpls_lse);\n+        flow_push_mpls(base, base_n, flow->dl_type, NULL, false);\n+        flow_set_mpls_lse(base, 0, flow->mpls_lse[flow_n - base_n - 1]);\n         base_n++;\n     }\n }\n@@ -8600,6 +8643,11 @@ commit_encap_decap_action(const struct flow *flow,\n             memcpy(&base_flow->dl_dst, &flow->dl_dst,\n                    sizeof(*flow) - offsetof(struct flow, dl_dst));\n             break;\n+        case PT_MPLS:\n+        case PT_MPLS_MC:\n+            commit_mpls_action(flow, base_flow, odp_actions,\n+                               pending_encap);\n+            break;\n         default:\n             /* Only the above protocols are supported for encap.\n              * The check is done at action translation. */\n@@ -8622,6 +8670,10 @@ commit_encap_decap_action(const struct flow *flow,\n                 /* pop_nsh. */\n                 odp_put_pop_nsh_action(odp_actions);\n                 break;\n+            case PT_MPLS:\n+                commit_mpls_action(flow, base_flow, odp_actions,\n+                                   pending_encap);\n+                break;\n             default:\n                 /* Checks are done during translation. */\n                 OVS_NOT_REACHED();\n@@ -8667,7 +8719,7 @@ commit_odp_actions(const struct flow *flow, struct flow *base,\n     /* Make packet a non-MPLS packet before committing L3/4 actions,\n      * which would otherwise do nothing. */\n     if (eth_type_mpls(base->dl_type) && !eth_type_mpls(flow->dl_type)) {\n-        commit_mpls_action(flow, base, odp_actions);\n+        commit_mpls_action(flow, base, odp_actions, false);\n         mpls_done = true;\n     }\n     commit_set_nsh_action(flow, base, odp_actions, wc, use_masked);\n@@ -8675,7 +8727,7 @@ commit_odp_actions(const struct flow *flow, struct flow *base,\n     commit_set_port_action(flow, base, odp_actions, wc, use_masked);\n     slow2 = commit_set_icmp_action(flow, base, odp_actions, wc);\n     if (!mpls_done) {\n-        commit_mpls_action(flow, base, odp_actions);\n+        commit_mpls_action(flow, base, odp_actions, false);\n     }\n     commit_vlan_action(flow, base, odp_actions, wc);\n     commit_set_priority_action(flow, base, odp_actions, wc, use_masked);\ndiff --git a/lib/ofp-actions.c b/lib/ofp-actions.c\nindex ecf914eac..68a846a24 100644\n--- a/lib/ofp-actions.c\n+++ b/lib/ofp-actions.c\n@@ -4468,6 +4468,8 @@ decode_NXAST_RAW_ENCAP(const struct nx_action_encap *nae,\n     switch (ntohl(nae->new_pkt_type)) {\n     case PT_ETH:\n     case PT_NSH:\n+    case PT_MPLS:\n+    case PT_MPLS_MC:\n         /* Add supported encap header types here. */\n         break;\n     default:\n@@ -4519,6 +4521,10 @@ parse_encap_header(const char *hdr, ovs_be32 *packet_type)\n         *packet_type = htonl(PT_ETH);\n     } else if (strcmp(hdr, \"nsh\") == 0) {\n         *packet_type = htonl(PT_NSH);\n+    } else if (strcmp(hdr, \"mpls\") == 0) {\n+        *packet_type = htonl(PT_MPLS);\n+    } else if (strcmp(hdr, \"mpls_mc\") == 0) {\n+        *packet_type = htonl(PT_MPLS_MC);\n     } else {\n         return false;\n     }\n@@ -4600,6 +4606,10 @@ format_encap_pkt_type(const ovs_be32 pkt_type)\n         return \"ethernet\";\n     case PT_NSH:\n         return \"nsh\";\n+    case PT_MPLS:\n+        return \"mpls\";\n+    case PT_MPLS_MC:\n+        return \"mpls_mc\";\n     default:\n         return \"UNKNOWN\";\n     }\ndiff --git a/lib/ofp-ed-props.c b/lib/ofp-ed-props.c\nindex 02a9235d5..d0649da02 100644\n--- a/lib/ofp-ed-props.c\n+++ b/lib/ofp-ed-props.c\n@@ -153,6 +153,8 @@ parse_ed_prop_class(const char *str OVS_UNUSED,\n         *prop_class = OFPPPC_BASIC;\n     } else if (!strcmp(str,\"mpls\")) {\n         *prop_class = OFPPPC_MPLS;\n+    } else if (!strcmp(str,\"mpls_mc\")) {\n+        *prop_class = OFPPPC_MPLS;\n     } else if (!strcmp(str,\"gre\")) {\n         *prop_class = OFPPPC_GRE;\n     } else if (!strcmp(str,\"gtp\")) {\ndiff --git a/lib/packets.c b/lib/packets.c\nindex 4a7643c5d..7ea50ffb2 100644\n--- a/lib/packets.c\n+++ b/lib/packets.c\n@@ -418,6 +418,40 @@ push_mpls(struct dp_packet *packet, ovs_be16 ethtype, ovs_be32 lse)\n     pkt_metadata_init_conn(&packet->md);\n }\n \n+void\n+add_mpls(struct dp_packet *packet, ovs_be16 ethtype, ovs_be32 lse,\n+         bool l3_encap)\n+{\n+    if (!eth_type_mpls(ethtype)) {\n+        return;\n+    }\n+\n+    if (!l3_encap) {\n+        ovs_be32 *header = dp_packet_push_uninit(packet, MPLS_HLEN);\n+\n+        *header = lse;\n+        packet->l2_5_ofs = 0;\n+        packet->packet_type = PACKET_TYPE_BE(OFPHTN_ETHERTYPE,\n+                                             ntohs(ethtype));\n+    } else {\n+        size_t len;\n+        char *header;\n+\n+        if (!is_mpls(packet)) {\n+            /* Set MPLS label stack offset. */\n+            packet->l2_5_ofs = packet->l3_ofs;\n+        }\n+        set_ethertype(packet, ethtype);\n+\n+        /* Push new MPLS shim header onto packet. */\n+        len = packet->l2_5_ofs;\n+        header = dp_packet_resize_l2_5(packet, MPLS_HLEN);\n+        memmove(header, header + MPLS_HLEN, len);\n+        memcpy(header + len, &lse, sizeof lse);\n+    }\n+    pkt_metadata_init_conn(&packet->md);\n+}\n+\n /* If 'packet' is an MPLS packet, removes its outermost MPLS label stack entry.\n  * If the label that was removed was the only MPLS label, changes 'packet''s\n  * Ethertype to 'ethtype' (which ordinarily should not be an MPLS\n@@ -440,6 +474,18 @@ pop_mpls(struct dp_packet *packet, ovs_be16 ethtype)\n         /* Invalidate offload flags as they are not valid after\n          * decapsulation of MPLS header. */\n         dp_packet_reset_offload(packet);\n+\n+        /* packet_type must be reset for the MPLS packets with no l2 header */\n+        if (!len) {\n+            if (ethtype == htons(ETH_TYPE_TEB)) {\n+                /* The inner packet must be classsified as ethernet if the\n+                 * ethtype is ETH_TYPE_TEB. */\n+                packet->packet_type = htonl(PT_ETH);\n+            } else {\n+                packet->packet_type = PACKET_TYPE_BE(OFPHTN_ETHERTYPE,\n+                                                     ntohs(ethtype));\n+            }\n+        }\n     }\n }\n \ndiff --git a/lib/packets.h b/lib/packets.h\nindex e8bdf08a0..5bdf6e4bb 100644\n--- a/lib/packets.h\n+++ b/lib/packets.h\n@@ -356,6 +356,8 @@ void set_mpls_lse_label(ovs_be32 *lse, ovs_be32 label);\n void set_mpls_lse_bos(ovs_be32 *lse, uint8_t bos);\n ovs_be32 set_mpls_lse_values(uint8_t ttl, uint8_t tc, uint8_t bos,\n                              ovs_be32 label);\n+void add_mpls(struct dp_packet *packet, ovs_be16 ethtype, ovs_be32 lse,\n+              bool l3_encap);\n \n /* Example:\n  *\ndiff --git a/ofproto/ofproto-dpif-ipfix.c b/ofproto/ofproto-dpif-ipfix.c\nindex 796eb6f88..9280e008e 100644\n--- a/ofproto/ofproto-dpif-ipfix.c\n+++ b/ofproto/ofproto-dpif-ipfix.c\n@@ -3018,6 +3018,7 @@ dpif_ipfix_read_actions(const struct flow *flow,\n         case OVS_ACTION_ATTR_CHECK_PKT_LEN:\n         case OVS_ACTION_ATTR_UNSPEC:\n         case OVS_ACTION_ATTR_DROP:\n+        case OVS_ACTION_ATTR_ADD_MPLS:\n         case __OVS_ACTION_ATTR_MAX:\n         default:\n             break;\ndiff --git a/ofproto/ofproto-dpif-sflow.c b/ofproto/ofproto-dpif-sflow.c\nindex 864c136b5..30e7caf54 100644\n--- a/ofproto/ofproto-dpif-sflow.c\n+++ b/ofproto/ofproto-dpif-sflow.c\n@@ -1226,6 +1226,7 @@ dpif_sflow_read_actions(const struct flow *flow,\n         case OVS_ACTION_ATTR_UNSPEC:\n         case OVS_ACTION_ATTR_CHECK_PKT_LEN:\n         case OVS_ACTION_ATTR_DROP:\n+        case OVS_ACTION_ATTR_ADD_MPLS:\n         case __OVS_ACTION_ATTR_MAX:\n         default:\n             break;\ndiff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c\nindex 9d336bc6a..cf35f5c68 100644\n--- a/ofproto/ofproto-dpif-xlate.c\n+++ b/ofproto/ofproto-dpif-xlate.c\n@@ -6420,6 +6420,47 @@ rewrite_flow_encap_ethernet(struct xlate_ctx *ctx,\n     }\n }\n \n+static void\n+rewrite_flow_encap_mpls(struct xlate_ctx *ctx,\n+                        const struct ofpact_encap *encap,\n+                        struct flow *flow,\n+                        struct flow_wildcards *wc)\n+{\n+    ovs_be16 ether_type = pt_ns_type_be(encap->new_pkt_type);\n+    int n;\n+\n+    n = flow_count_mpls_labels(flow, ctx->wc);\n+    if (n < FLOW_MAX_MPLS_LABELS) {\n+        wc->masks.packet_type = OVS_BE32_MAX;\n+\n+       /* If the current packet is already a MPLS packet with ethernet header\n+        * the existing MPLS states must be cleared before the encap MPLS action\n+        * is applied. */\n+       if (flow->packet_type == htonl(PT_ETH) &&\n+           flow->dl_type == htons(ETH_TYPE_MPLS)) {\n+           memset(&ctx->wc->masks.mpls_lse, 0x0,\n+                  sizeof *wc->masks.mpls_lse * FLOW_MAX_MPLS_LABELS);\n+           memset(&flow->mpls_lse, 0x0, sizeof *flow->mpls_lse *\n+                  FLOW_MAX_MPLS_LABELS);\n+           memset(&ctx->base_flow.mpls_lse, 0x0,\n+                  sizeof *ctx->base_flow.mpls_lse * FLOW_MAX_MPLS_LABELS);\n+       }\n+       flow->packet_type = encap->new_pkt_type;\n+       flow_push_mpls(flow, n, ether_type, ctx->wc, true);\n+       flow->dl_src = eth_addr_zero;\n+       flow->dl_dst = eth_addr_zero;\n+    } else {\n+        if (ctx->xin->packet != NULL) {\n+            xlate_report_error(ctx, \"dropping packet on which an encap MPLS \"\n+                               \"action can't be performed as it would have \"\n+                               \"more MPLS LSEs than the %d supported.\",\n+                               FLOW_MAX_MPLS_LABELS);\n+        }\n+        ctx->error = XLATE_TOO_MANY_MPLS_LABELS;\n+        return;\n+    }\n+}\n+\n /* For an MD2 NSH header returns a pointer to an ofpbuf with the encoded\n  * MD2 TLVs provided as encap properties to the encap operation. This\n  * will be stored as encap_data in the ctx and copied into the push_nsh\n@@ -6551,6 +6592,13 @@ xlate_generic_encap_action(struct xlate_ctx *ctx,\n         case PT_NSH:\n             encap_data = rewrite_flow_push_nsh(ctx, encap, flow, wc);\n             break;\n+        case PT_MPLS:\n+        case PT_MPLS_MC:\n+            rewrite_flow_encap_mpls(ctx, encap, flow, wc);\n+            if (!ctx->xbridge->support.add_mpls) {\n+                ctx->xout->slow |= SLOW_ACTION;\n+            }\n+            break;\n         default:\n             /* New packet type was checked during decoding. */\n             OVS_NOT_REACHED();\n@@ -6622,6 +6670,43 @@ xlate_generic_decap_action(struct xlate_ctx *ctx,\n             ctx->pending_decap = true;\n             /* Trigger recirculation. */\n             return true;\n+        case PT_MPLS: {\n+            int n;\n+            ovs_be16 ethertype;\n+\n+            flow->packet_type = decap->new_pkt_type;\n+            ethertype = pt_ns_type_be(flow->packet_type);\n+\n+            n = flow_count_mpls_labels(flow, ctx->wc);\n+            if (!ethertype) {\n+                ethertype = htons(ETH_TYPE_TEB);\n+            }\n+            if (flow_pop_mpls(flow, n, ethertype, ctx->wc)) {\n+                if (!ctx->xbridge->support.add_mpls) {\n+                   ctx->xout->slow |= SLOW_ACTION;\n+                }\n+                ctx->pending_decap = true;\n+                if (n == 1) {\n+                    /* Trigger recirculation. */\n+                    return true;\n+                } else {\n+                    return false;\n+                }\n+            } else if (n >= FLOW_MAX_MPLS_LABELS) {\n+                if (ctx->xin->packet != NULL) {\n+                    xlate_report_error(ctx, \"dropping packet on which an \"\n+                                       \"MPLS decap can't be performed as \"\n+                                       \"it has more MPLS LSEs than the %d \"\n+                                       \"supported.\",\n+                                       FLOW_MAX_MPLS_LABELS);\n+                }\n+                ctx->error = XLATE_TOO_MANY_MPLS_LABELS;\n+                ofpbuf_clear(ctx->odp_actions);\n+                return false;\n+            } else {\n+                return false;\n+            }\n+        }\n         default:\n             /* Error handling: drop packet. */\n             xlate_report_debug(\ndiff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c\nindex cba49a99e..c65b992a7 100644\n--- a/ofproto/ofproto-dpif.c\n+++ b/ofproto/ofproto-dpif.c\n@@ -1538,6 +1538,42 @@ check_nd_extensions(struct dpif_backer *backer)\n \n     return !error;\n }\n+/* Tests whether 'backer''s datapath supports the\n+ * OVS_ACTION_ATTR_ADD_MPLS action. */\n+static bool\n+check_add_mpls(struct dpif_backer *backer)\n+{\n+    struct odputil_keybuf keybuf;\n+    struct ofpbuf actions;\n+    struct ofpbuf key;\n+    struct flow flow;\n+    bool supported;\n+\n+    struct odp_flow_key_parms odp_parms = {\n+        .flow = &flow,\n+        .probe = true,\n+    };\n+\n+    memset(&flow, 0, sizeof flow);\n+    ofpbuf_use_stack(&key, &keybuf, sizeof keybuf);\n+    odp_flow_key_from_flow(&odp_parms, &key);\n+    ofpbuf_init(&actions, 64);\n+\n+    struct ovs_action_add_mpls *mpls;\n+\n+    mpls = nl_msg_put_unspec_zero(&actions,\n+                                  OVS_ACTION_ATTR_ADD_MPLS,\n+                                  sizeof *mpls);\n+    mpls->mpls_ethertype = htons(ETH_TYPE_MPLS);\n+\n+    supported = dpif_probe_feature(backer->dpif, \"add_mpls\", &key,\n+                                   &actions, NULL);\n+    ofpbuf_uninit(&actions);\n+    VLOG_INFO(\"%s: Datapath %s add_mpls action\",\n+              dpif_name(backer->dpif),\n+              supported ? \"supports\" : \"does not support\");\n+    return supported;\n+}\n \n #define CHECK_FEATURE__(NAME, SUPPORT, FIELD, VALUE, ETHTYPE)               \\\n static bool                                                                 \\\n@@ -1609,6 +1645,7 @@ check_support(struct dpif_backer *backer)\n     backer->rt_support.lb_output_action =\n         dpif_supports_lb_output_action(backer->dpif);\n     backer->rt_support.ct_zero_snat = dpif_supports_ct_zero_snat(backer);\n+    backer->rt_support.add_mpls = check_add_mpls(backer);\n \n     /* Flow fields. */\n     backer->rt_support.odp.ct_state = check_ct_state(backer);\n@@ -5625,6 +5662,7 @@ get_datapath_cap(const char *datapath_type, struct smap *cap)\n              s.explicit_drop_action ? \"true\" :\"false\");\n     smap_add(cap, \"lb_output_action\", s.lb_output_action ? \"true\" : \"false\");\n     smap_add(cap, \"ct_zero_snat\", s.ct_zero_snat ? \"true\" : \"false\");\n+    smap_add(cap, \"add_mpls\", s.add_mpls ? \"true\" : \"false\");\n }\n \n /* Gets timeout policy name in 'backer' based on 'zone', 'dl_type' and\ndiff --git a/ofproto/ofproto-dpif.h b/ofproto/ofproto-dpif.h\nindex 191cfcb0d..a83cc42a9 100644\n--- a/ofproto/ofproto-dpif.h\n+++ b/ofproto/ofproto-dpif.h\n@@ -207,7 +207,9 @@ struct group_dpif *group_dpif_lookup(struct ofproto_dpif *,\n     DPIF_SUPPORT_FIELD(bool, lb_output_action, \"Optimized Balance TCP mode\")\\\n                                                                             \\\n     /* True if the datapath supports all-zero IP SNAT. */                   \\\n-    DPIF_SUPPORT_FIELD(bool, ct_zero_snat, \"Conntrack all-zero IP SNAT\")\n+    DPIF_SUPPORT_FIELD(bool, ct_zero_snat, \"Conntrack all-zero IP SNAT\")    \\\n+    /* True if the datapath supports add_mpls action   */                   \\\n+    DPIF_SUPPORT_FIELD(bool, add_mpls, \"MPLS Label add\")\n \n \n /* Stores the various features which the corresponding backer supports. */\ndiff --git a/tests/mpls-xlate.at b/tests/mpls-xlate.at\nindex aafa89ba6..7474becc8 100644\n--- a/tests/mpls-xlate.at\n+++ b/tests/mpls-xlate.at\n@@ -207,3 +207,122 @@ AT_CHECK([tail -1 stdout], [0],\n \n OVS_VSWITCHD_STOP\n AT_CLEANUP\n+\n+AT_SETUP([Encap Decap MPLS xlate action])\n+\n+OVS_VSWITCHD_START(\n+  [add-port br0 p1 -- set Interface p1 type=dummy ofport_request=1 -- \\\n+   add-port br0 p2 -- set Interface p2 type=patch \\\n+                                       options:peer=p3 ofport_request=2 -- \\\n+   add-br br1 -- \\\n+   set bridge br1 other-config:hwaddr=aa:66:aa:66:00:00 -- \\\n+   set bridge br1 datapath-type=dummy other-config:datapath-id=1234 \\\n+                  fail-mode=secure -- \\\n+   add-port br1 p3 -- set Interface p3 type=patch \\\n+                                       options:peer=p2 ofport_request=3 -- \\\n+   add-port br1 p4 -- set Interface p4 type=dummy ofport_request=4])\n+\n+AT_CHECK([ovs-appctl dpif/show], [0], [dnl\n+dummy@ovs-dummy: hit:0 missed:0\n+  br0:\n+    br0 65534/100: (dummy-internal)\n+    p1 1/1: (dummy)\n+    p2 2/none: (patch: peer=p3)\n+  br1:\n+    br1 65534/101: (dummy-internal)\n+    p3 3/none: (patch: peer=p2)\n+    p4 4/4: (dummy)\n+])\n+\n+AT_CHECK([ovs-ofctl del-flows br0])\n+AT_CHECK([ovs-ofctl -O OpenFlow13 add-flow br0 \"in_port=p1,actions=encap(mpls),encap(ethernet),set_field:00:00:00:00:00:02->dl_dst,set_field:00:00:00:00:00:01->dl_src,output:p2\"])\n+AT_CHECK([ovs-ofctl -O OpenFlow13 add-flow br1 \"in_port=p3,dl_type=0x8847 actions=decap(),decap(packet_type(ns=0,type=0)),output:p4\"])\n+\n+# Now send two real ICMP echo request packets in on port p1\n+\n+AT_CHECK([ovs-appctl netdev-dummy/receive p1 1e2ce92a669e3a6dd2099cab0800450000548a53400040011addc0a80a0ac0a80a1e08006f200a4d0001fc509a58000000002715020000000000101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f3031323334353637] ,[0], [ignore])\n+\n+AT_CHECK([ovs-appctl netdev-dummy/receive p1 1e2ce92a669e3a6dd2099cab0800450000548a53400040011addc0a80a0ac0a80a1e08006f200a4d0001fc509a58000000002715020000000000101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f3031323334353637] ,[0], [ignore])\n+\n+AT_CHECK([ovs-appctl dpctl/dump-flows dummy@ovs-dummy | strip_used | grep -v ipv6 |sort], [0],\n+[flow-dump from the main thread:\n+recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth(src=3a:6d:d2:09:9c:ab,dst=1e:2c:e9:2a:66:9e),eth_type(0x0800),ipv4(frag=no), packets:1, bytes:98, used:0.0s, actions:add_mpls(label=0,tc=0,ttl=64,bos=1,eth_type=0x8847),push_eth(src=00:00:00:00:00:01,dst=00:00:00:00:00:02),pop_eth,pop_mpls(eth_type=0x6558),recirc(0x1)\n+recirc_id(0x1),in_port(1),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(frag=no), packets:1, bytes:98, used:0.0s, actions:4\n+])\n+\n+AT_CHECK(ovs-appctl dpif/set-dp-features br0 add_mpls false)\n+\n+AT_CHECK([ovs-appctl netdev-dummy/receive p1 1e2ce92a669e3a6dd2099cab0800450000548a53400040011addc0a80a0ac0a80a1e08006f200a4d0001fc509a58000000002715020000000000101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f3031323334353637] ,[0], [ignore])\n+\n+AT_CHECK([ovs-appctl netdev-dummy/receive p1 1e2ce92a669e3a6dd2099cab0800450000548a53400040011addc0a80a0ac0a80a1e08006f200a4d0001fc509a58000000002715020000000000101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f3031323334353637] ,[0], [ignore])\n+\n+AT_CHECK([ovs-appctl dpctl/dump-flows dummy@ovs-dummy | strip_used | grep -v ipv6 |sort], [0],\n+[flow-dump from the main thread:\n+recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth(src=3a:6d:d2:09:9c:ab,dst=1e:2c:e9:2a:66:9e),eth_type(0x0800),ipv4(frag=no), packets:1, bytes:98, used:0.0s, actions:userspace(pid=0,slow_path(action))\n+recirc_id(0x2),in_port(1),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(frag=no), packets:1, bytes:98, used:0.0s, actions:4\n+])\n+\n+OVS_VSWITCHD_STOP\n+AT_CLEANUP\n+\n+AT_SETUP([Encap MPLS xlate action - max labels])\n+\n+OVS_VSWITCHD_START([dnl\n+    set bridge br0 datapath_type=dummy \\\n+        protocols=OpenFlow10,OpenFlow13,OpenFlow14,OpenFlow15 -- \\\n+    add-port br0 p1 -- set Interface p1 type=dummy ofport_request=1 -- \\\n+    add-port br0 p2 -- set Interface p2 type=dummy ofport_request=2])\n+\n+AT_CHECK([ovs-appctl dpif/show], [0], [dnl\n+dummy@ovs-dummy: hit:0 missed:0\n+  br0:\n+    br0 65534/100: (dummy-internal)\n+    p1 1/1: (dummy)\n+    p2 2/2: (dummy)\n+])\n+\n+AT_CHECK([ovs-ofctl del-flows br0])\n+AT_CHECK([ovs-ofctl -O OpenFlow13 add-flow br0 \"in_port=p1,actions=encap(mpls),set_field:1->mpls_label,encap(mpls),set_field:2->mpls_label,encap(mpls),set_field:3->mpls_label,encap(mpls),set_field:4->mpls_label,encap(ethernet),set_field:00:00:00:00:00:02->dl_dst,set_field:00:00:00:00:00:01->dl_src,output:p2\"])\n+\n+AT_CHECK([ovs-appctl netdev-dummy/receive p1 1e2ce92a669e3a6dd2099cab0800450000548a53400040011addc0a80a0ac0a80a1e08006f200a4d0001fc509a58000000002715020000000000101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f3031323334353637] ,[0], [ignore])\n+\n+AT_CHECK([ovs-appctl netdev-dummy/receive p1 1e2ce92a669e3a6dd2099cab0800450000548a53400040011addc0a80a0ac0a80a1e08006f200a4d0001fc509a58000000002715020000000000101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f3031323334353637] ,[0], [ignore])\n+\n+AT_CHECK([ovs-appctl dpctl/dump-flows dummy@ovs-dummy | strip_used | grep -v ipv6 |sort], [0],\n+[flow-dump from the main thread:\n+recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(frag=no), packets:1, bytes:98, used:0.0s, actions:drop\n+])\n+\n+OVS_VSWITCHD_STOP([\"/ofproto_dpif_xlate|WARN|dropping packet on which an encap MPLS action can't be performed as it would have more MPLS LSEs than the 3 supported. on bridge br0 while processing mpls,in_port=1,vlan_tci=0x0000,dl_src=3a:6d:d2:09:9c:ab,dl_dst=1e:2c:e9:2a:66:9e,mpls_label=3,mpls_tc=0,mpls_ttl=64,mpls_bos=0,mpls_lse1=8256,mpls_lse2=4416/d\"])\n+AT_CLEANUP\n+\n+AT_SETUP([Decap MPLS xlate action - max labels])\n+\n+OVS_VSWITCHD_START([dnl\n+    set bridge br0 datapath_type=dummy \\\n+        protocols=OpenFlow10,OpenFlow13,OpenFlow14,OpenFlow15 -- \\\n+    add-port br0 p1 -- set Interface p1 type=dummy ofport_request=1 -- \\\n+    add-port br0 p2 -- set Interface p2 type=dummy ofport_request=2])\n+\n+AT_CHECK([ovs-appctl dpif/show], [0], [dnl\n+dummy@ovs-dummy: hit:0 missed:0\n+  br0:\n+    br0 65534/100: (dummy-internal)\n+    p1 1/1: (dummy)\n+    p2 2/2: (dummy)\n+])\n+\n+AT_CHECK([ovs-ofctl del-flows br0])\n+AT_CHECK([ovs-ofctl -Oopenflow13 add-flow br0 \"table=0,priority=100,dl_type=0x8847 actions=decap(),decap(packet_type(ns=0,type=0)),output:p2\"])\n+\n+AT_CHECK([ovs-appctl netdev-dummy/receive p1 00000000000200000000000188470000204000002040000020400000204036b1ee7c010236b1ee7c010308004500005403444000400121610a0101010a0101020800efac7ce400035b2c1f6100000000500b020000000000101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f3031323334353637] ,[0], [ignore])\n+\n+AT_CHECK([ovs-appctl netdev-dummy/receive p1 00000000000200000000000188470000204000002040000020400000204036b1ee7c010236b1ee7c010308004500005403444000400121610a0101010a0101020800efac7ce400035b2c1f6100000000500b020000000000101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f3031323334353637] ,[0], [ignore])\n+\n+AT_CHECK([ovs-appctl dpctl/dump-flows dummy@ovs-dummy | strip_used | grep -v ipv6 |sort], [0],\n+[flow-dump from the main thread:\n+recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x8847),mpls(label=2/0x0,tc=0/0,ttl=64/0x0,bos=0/1,label=2/0x0,tc=0/0,ttl=64/0x0,bos=0/1,label=2/0x0,tc=0/0,ttl=64/0x0,bos=0/1), packets:1, bytes:128, used:0.0s, actions:drop\n+])\n+\n+OVS_VSWITCHD_STOP([\"/ofproto_dpif_xlate|WARN|dropping packet on which an MPLS decap can't be performed as it has more MPLS LSEs than the 3 supported. on bridge br0 while processing packet_type=(1,0x8847),in_port=1,mpls_label=2,mpls_tc=0,mpls_ttl=64,mpls_bos=0,mpls_lse1=8256,mpls_lse2=8256/d\"])\n+AT_CLEANUP\ndiff --git a/tests/odp.at b/tests/odp.at\nindex 07a5cfe39..4d08c59ca 100644\n--- a/tests/odp.at\n+++ b/tests/odp.at\n@@ -384,6 +384,7 @@ check_pkt_len(size=200,gt(drop),le(5))\n check_pkt_len(size=200,gt(ct(nat)),le(drop))\n check_pkt_len(size=200,gt(set(eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15))),le(set(eth(src=00:01:02:03:04:06,dst=10:11:12:13:14:16))))\n lb_output(1)\n+add_mpls(label=200,tc=7,ttl=64,bos=1,eth_type=0x8847)\n ])\n AT_CHECK_UNQUOTED([ovstest test-odp parse-actions < actions.txt], [0],\n   [`cat actions.txt`\ndiff --git a/tests/ofp-actions.at b/tests/ofp-actions.at\nindex ef4898abb..9d820eba6 100644\n--- a/tests/ofp-actions.at\n+++ b/tests/ofp-actions.at\n@@ -780,6 +780,14 @@ dnl NSH encap with non-zero padding.\n # 23: 56 -> 00\n ffff 0018 00002320 002e 0000 0001894f 0004 01 05 01 123456\n \n+dnl Check mpls encap\n+# actions=encap(mpls)\n+ffff 0010 00002320 002e 0000 00018847\n+\n+dnl Check mpls encap\n+# actions=encap(mpls_mc)\n+ffff 0010 00002320 002e 0000 00018848\n+\n ])\n sed '/^[[#&]]/d' < test-data > input.txt\n sed -n 's/^# //p; /^$/p' < test-data > expout\ndiff --git a/tests/system-traffic.at b/tests/system-traffic.at\nindex a69896d33..b96425d1e 100644\n--- a/tests/system-traffic.at\n+++ b/tests/system-traffic.at\n@@ -1087,6 +1087,382 @@ NS_CHECK_EXEC([at_ns1], [ping -q -c 3 -i 0.3 -w 2 10.1.1.1 | FORMAT_PING], [0],\n OVS_TRAFFIC_VSWITCHD_STOP\n AT_CLEANUP\n \n+AT_SETUP([mpls - encap header dp-support])\n+AT_SKIP_IF([test $HAVE_TCPDUMP = no])\n+OVS_TRAFFIC_VSWITCHD_START()\n+\n+AT_SKIP_IF([! ovs-appctl dpif/show-dp-features br0 2>&1 | grep \"MPLS Label add: Yes\" >/dev/null])\n+\n+ADD_NAMESPACES(at_ns0, at_ns1)\n+\n+ADD_VETH(p0, at_ns0, br0, \"10.1.1.1/24\", 36:b1:ee:7c:01:03)\n+ADD_VETH(p1, at_ns1, br0, \"10.1.1.2/24\", 36:b1:ee:7c:01:02)\n+\n+dnl The flow will encap a mpls header to the ip packet\n+dnl eth/ip/icmp --> OVS --> eth/mpls/eth/ip/icmp\n+AT_CHECK([ovs-ofctl -Oopenflow13 add-flow br0 \"table=0,priority=100,dl_type=0x0800 actions=encap(mpls),set_mpls_label:2,encap(ethernet),set_field:00:00:00:00:00:02->dl_dst,set_field:00:00:00:00:00:01->dl_src,ovs-p1\"])\n+\n+rm -rf p1.pcap\n+NS_CHECK_EXEC([at_ns1], [tcpdump -l -n -xx -U -i p1 > p1.pcap &])\n+sleep 1\n+\n+dnl The hex dump is a icmp packet. pkt=eth/ip/icmp\n+dnl The packet is sent from p0(at_ns0) interface directed to\n+dnl p1(at_ns1) interface\n+NS_CHECK_EXEC([at_ns0], [$PYTHON3 $srcdir/sendpkt.py p0 36 b1 ee 7c 01 02 36 b1 ee 7c 01 03 08 00 45 00 00 54 03 44 40 00 40 01 21 61 0a 01 01 01 0a 01 01 02 08 00 ef ac 7c e4 00 03 5b 2c 1f 61 00 00 00 00 50 0b 02 00 00 00 00 00 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37  > /dev/null])\n+\n+dnl Check the expected mpls encapsulated packet on the egress interface\n+OVS_WAIT_UNTIL([cat p1.pcap | egrep \"0x0000:  *0000 *0000 *0002 *0000 *0000 *0001 *8847 *0000\" 2>&1 1>/dev/null])\n+OVS_WAIT_UNTIL([cat p1.pcap | egrep \"0x0010:  *2140 *36b1 *ee7c *0102 *36b1 *ee7c *0103 *0800\" 2>&1 1>/dev/null])\n+OVS_WAIT_UNTIL([cat p1.pcap | egrep \"0x0020:  *4500 *0054 *0344 *4000 *4001 *2161 *0a01 *0101\" 2>&1 1>/dev/null])\n+OVS_WAIT_UNTIL([cat p1.pcap | egrep \"0x0030:  *0a01 *0102 *0800 *efac *7ce4 *0003 *5b2c *1f61\" 2>&1 1>/dev/null])\n+\n+OVS_TRAFFIC_VSWITCHD_STOP\n+AT_CLEANUP\n+\n+AT_SETUP([mpls - encap header slow-path])\n+AT_SKIP_IF([test $HAVE_TCPDUMP = no])\n+OVS_TRAFFIC_VSWITCHD_START()\n+\n+AT_CHECK(ovs-appctl dpif/set-dp-features br0 add_mpls false)\n+ADD_NAMESPACES(at_ns0, at_ns1)\n+\n+ADD_VETH(p0, at_ns0, br0, \"10.1.1.1/24\", 36:b1:ee:7c:01:03)\n+ADD_VETH(p1, at_ns1, br0, \"10.1.1.2/24\", 36:b1:ee:7c:01:02)\n+\n+dnl The flow will encap a mpls header to the ip packet\n+dnl eth/ip/icmp --> OVS --> eth/mpls/eth/ip/icmp\n+AT_CHECK([ovs-ofctl -Oopenflow13 add-flow br0 \"table=0,priority=100,dl_type=0x0800 actions=encap(mpls),set_mpls_label:2,encap(ethernet),set_field:00:00:00:00:00:02->dl_dst,set_field:00:00:00:00:00:01->dl_src,ovs-p1\"])\n+\n+rm -rf p1.pcap\n+NS_CHECK_EXEC([at_ns1], [tcpdump -l -n -xx -U -i p1 > p1.pcap &])\n+sleep 1\n+\n+dnl The hex dump is a icmp packet. pkt=eth/ip/icmp\n+dnl The packet is sent from p0(at_ns0) interface directed to\n+dnl p1(at_ns1) interface\n+NS_CHECK_EXEC([at_ns0], [$PYTHON3 $srcdir/sendpkt.py p0 36 b1 ee 7c 01 02 36 b1 ee 7c 01 03 08 00 45 00 00 54 03 44 40 00 40 01 21 61 0a 01 01 01 0a 01 01 02 08 00 ef ac 7c e4 00 03 5b 2c 1f 61 00 00 00 00 50 0b 02 00 00 00 00 00 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37  > /dev/null])\n+\n+dnl Check the expected mpls encapsulated packet on the egress interface\n+OVS_WAIT_UNTIL([cat p1.pcap | egrep \"0x0000:  *0000 *0000 *0002 *0000 *0000 *0001 *8847 *0000\" 2>&1 1>/dev/null])\n+OVS_WAIT_UNTIL([cat p1.pcap | egrep \"0x0010:  *2140 *36b1 *ee7c *0102 *36b1 *ee7c *0103 *0800\" 2>&1 1>/dev/null])\n+OVS_WAIT_UNTIL([cat p1.pcap | egrep \"0x0020:  *4500 *0054 *0344 *4000 *4001 *2161 *0a01 *0101\" 2>&1 1>/dev/null])\n+OVS_WAIT_UNTIL([cat p1.pcap | egrep \"0x0030:  *0a01 *0102 *0800 *efac *7ce4 *0003 *5b2c *1f61\" 2>&1 1>/dev/null])\n+\n+OVS_TRAFFIC_VSWITCHD_STOP\n+AT_CLEANUP\n+\n+AT_SETUP([mpls_mc - encap header dp-support])\n+AT_SKIP_IF([test $HAVE_TCPDUMP = no])\n+OVS_TRAFFIC_VSWITCHD_START()\n+\n+AT_SKIP_IF([! ovs-appctl dpif/show-dp-features br0 2>&1 | grep \"MPLS Label add: Yes\" >/dev/null])\n+\n+ADD_NAMESPACES(at_ns0, at_ns1)\n+\n+ADD_VETH(p0, at_ns0, br0, \"10.1.1.1/24\", 36:b1:ee:7c:01:03)\n+ADD_VETH(p1, at_ns1, br0, \"10.1.1.2/24\", 36:b1:ee:7c:01:02)\n+\n+dnl The flow will encap a mpls header to the ip packet\n+dnl eth/ip/icmp --> OVS --> eth/mpls/eth/ip/icmp\n+AT_CHECK([ovs-ofctl -Oopenflow13 add-flow br0 \"table=0,priority=100,dl_type=0x0800 actions=encap(mpls_mc),set_mpls_label:2,encap(ethernet),set_field:00:00:00:00:00:02->dl_dst,set_field:00:00:00:00:00:01->dl_src,ovs-p1\"])\n+\n+rm -rf p1.pcap\n+NS_CHECK_EXEC([at_ns1], [tcpdump -l -n -xx -U -i p1 > p1.pcap &])\n+sleep 1\n+\n+dnl The hex dump is a icmp packet. pkt=eth/ip/icmp\n+dnl The packet is sent from p0(at_ns0) interface directed to\n+dnl p1(at_ns1) interface\n+NS_CHECK_EXEC([at_ns0], [$PYTHON3 $srcdir/sendpkt.py p0 36 b1 ee 7c 01 02 36 b1 ee 7c 01 03 08 00 45 00 00 54 03 44 40 00 40 01 21 61 0a 01 01 01 0a 01 01 02 08 00 ef ac 7c e4 00 03 5b 2c 1f 61 00 00 00 00 50 0b 02 00 00 00 00 00 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37  > /dev/null])\n+\n+dnl Check the expected mpls encapsulated packet on the egress interface\n+OVS_WAIT_UNTIL([cat p1.pcap | egrep \"0x0000:  *0000 *0000 *0002 *0000 *0000 *0001 *8848 *0000\" 2>&1 1>/dev/null])\n+OVS_WAIT_UNTIL([cat p1.pcap | egrep \"0x0010:  *2140 *36b1 *ee7c *0102 *36b1 *ee7c *0103 *0800\" 2>&1 1>/dev/null])\n+OVS_WAIT_UNTIL([cat p1.pcap | egrep \"0x0020:  *4500 *0054 *0344 *4000 *4001 *2161 *0a01 *0101\" 2>&1 1>/dev/null])\n+OVS_WAIT_UNTIL([cat p1.pcap | egrep \"0x0030:  *0a01 *0102 *0800 *efac *7ce4 *0003 *5b2c *1f61\" 2>&1 1>/dev/null])\n+\n+OVS_TRAFFIC_VSWITCHD_STOP\n+AT_CLEANUP\n+\n+AT_SETUP([mpls_mc - encap header slow-path])\n+AT_SKIP_IF([test $HAVE_TCPDUMP = no])\n+OVS_TRAFFIC_VSWITCHD_START()\n+\n+AT_CHECK(ovs-appctl dpif/set-dp-features br0 add_mpls false)\n+ADD_NAMESPACES(at_ns0, at_ns1)\n+\n+ADD_VETH(p0, at_ns0, br0, \"10.1.1.1/24\", 36:b1:ee:7c:01:03)\n+ADD_VETH(p1, at_ns1, br0, \"10.1.1.2/24\", 36:b1:ee:7c:01:02)\n+\n+dnl The flow will encap a mpls header to the ip packet\n+dnl eth/ip/icmp --> OVS --> eth/mpls/eth/ip/icmp\n+AT_CHECK([ovs-ofctl -Oopenflow13 add-flow br0 \"table=0,priority=100,dl_type=0x0800 actions=encap(mpls_mc),set_mpls_label:2,encap(ethernet),set_field:00:00:00:00:00:02->dl_dst,set_field:00:00:00:00:00:01->dl_src,ovs-p1\"])\n+\n+rm -rf p1.pcap\n+NS_CHECK_EXEC([at_ns1], [tcpdump -l -n -xx -U -i p1 > p1.pcap &])\n+sleep 1\n+\n+dnl The hex dump is a icmp packet. pkt=eth/ip/icmp\n+dnl The packet is sent from p0(at_ns0) interface directed to\n+dnl p1(at_ns1) interface\n+NS_CHECK_EXEC([at_ns0], [$PYTHON3 $srcdir/sendpkt.py p0 36 b1 ee 7c 01 02 36 b1 ee 7c 01 03 08 00 45 00 00 54 03 44 40 00 40 01 21 61 0a 01 01 01 0a 01 01 02 08 00 ef ac 7c e4 00 03 5b 2c 1f 61 00 00 00 00 50 0b 02 00 00 00 00 00 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37  > /dev/null])\n+\n+dnl Check the expected mpls encapsulated packet on the egress interface\n+OVS_WAIT_UNTIL([cat p1.pcap | egrep \"0x0000:  *0000 *0000 *0002 *0000 *0000 *0001 *8848 *0000\" 2>&1 1>/dev/null])\n+OVS_WAIT_UNTIL([cat p1.pcap | egrep \"0x0010:  *2140 *36b1 *ee7c *0102 *36b1 *ee7c *0103 *0800\" 2>&1 1>/dev/null])\n+OVS_WAIT_UNTIL([cat p1.pcap | egrep \"0x0020:  *4500 *0054 *0344 *4000 *4001 *2161 *0a01 *0101\" 2>&1 1>/dev/null])\n+OVS_WAIT_UNTIL([cat p1.pcap | egrep \"0x0030:  *0a01 *0102 *0800 *efac *7ce4 *0003 *5b2c *1f61\" 2>&1 1>/dev/null])\n+\n+OVS_TRAFFIC_VSWITCHD_STOP\n+AT_CLEANUP\n+\n+AT_SETUP([mpls - decap header dp-support])\n+AT_SKIP_IF([test $HAVE_TCPDUMP = no])\n+OVS_TRAFFIC_VSWITCHD_START()\n+\n+AT_SKIP_IF([! ovs-appctl dpif/show-dp-features br0 2>&1 | grep \"MPLS Label add: Yes\" >/dev/null])\n+\n+ADD_NAMESPACES(at_ns0, at_ns1)\n+\n+ADD_VETH(p0, at_ns0, br0, \"10.1.1.1/24\", 36:b1:ee:7c:01:03)\n+ADD_VETH(p1, at_ns1, br0, \"10.1.1.2/24\", 36:b1:ee:7c:01:02)\n+\n+dnl The flow will decap a mpls header which in turn carries a icmp packet\n+dnl eth/mpls/eth/ip/icmp --> OVS --> eth/ip/icmp\n+\n+AT_CHECK([ovs-ofctl -Oopenflow13 add-flow br0 \"table=0,priority=100,dl_type=0x8847,mpls_label=2 actions=decap(),decap(packet_type(ns=0,type=0)),ovs-p1\"])\n+\n+rm -rf p1.pcap\n+NS_CHECK_EXEC([at_ns1], [tcpdump -l -n -xx -U -i p1 > p1.pcap &])\n+sleep 1\n+\n+dnl The hex dump is an mpls packet encapsulating ethernet packet. pkt=eth/mpls/eth/ip/icmp\n+dnl The packet is sent from p0(at_ns0) interface directed to\n+dnl p1(at_ns1) interface\n+NS_CHECK_EXEC([at_ns0], [$PYTHON3 $srcdir/sendpkt.py p0 00 00 00 00 00 02 00 00 00 00 00 01 88 47 00 00 21 40 36 b1 ee 7c 01 02 36 b1 ee 7c 01 03 08 00 45 00 00 54 03 44 40 00 40 01 21 61 0a 01 01 01 0a 01 01 02 08 00 ef ac 7c e4 00 03 5b 2c 1f 61 00 00 00 00 50 0b 02 00 00 00 00 00 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37  > /dev/null])\n+\n+dnl Check the expected decapsulated on the egress interface\n+OVS_WAIT_UNTIL([cat p1.pcap | egrep \"0x0000:  *36b1 *ee7c *0102 *36b1 *ee7c *0103 *0800 *4500\" 2>&1 1>/dev/null])\n+OVS_WAIT_UNTIL([cat p1.pcap | egrep \"0x0010:  *0054 *0344 *4000 *4001 *2161 *0a01 *0101 *0a01\" 2>&1 1>/dev/null])\n+OVS_WAIT_UNTIL([cat p1.pcap | egrep \"0x0020:  *0102 *0800 *efac *7ce4 *0003 *5b2c *1f61 *0000\" 2>&1 1>/dev/null])\n+OVS_WAIT_UNTIL([cat p1.pcap | egrep \"0x0030:  *0000 *500b *0200 *0000 *0000 *1011 *1213 *1415\" 2>&1 1>/dev/null])\n+OVS_WAIT_UNTIL([cat p1.pcap | egrep \"0x0040:  *1617 *1819 *1a1b *1c1d *1e1f *2021 *2223 *2425\" 2>&1 1>/dev/null])\n+OVS_WAIT_UNTIL([cat p1.pcap | egrep \"0x0050:  *2627 *2829 *2a2b *2c2d *2e2f *3031 *3233 *3435\" 2>&1 1>/dev/null])\n+OVS_WAIT_UNTIL([cat p1.pcap | egrep \"0x0060:  *3637\" 2>&1 1>/dev/null])\n+\n+\n+OVS_TRAFFIC_VSWITCHD_STOP\n+AT_CLEANUP\n+\n+AT_SETUP([mpls - decap header slow-path])\n+AT_SKIP_IF([test $HAVE_TCPDUMP = no])\n+OVS_TRAFFIC_VSWITCHD_START()\n+\n+AT_CHECK(ovs-appctl dpif/set-dp-features br0 add_mpls false)\n+ADD_NAMESPACES(at_ns0, at_ns1)\n+\n+ADD_VETH(p0, at_ns0, br0, \"10.1.1.1/24\", 36:b1:ee:7c:01:03)\n+ADD_VETH(p1, at_ns1, br0, \"10.1.1.2/24\", 36:b1:ee:7c:01:02)\n+\n+dnl The flow will decap a mpls header which in turn carries a icmp packet\n+dnl eth/mpls/eth/ip/icmp --> OVS --> eth/ip/icmp\n+\n+AT_CHECK([ovs-ofctl -Oopenflow13 add-flow br0 \"table=0,priority=100,dl_type=0x8847,mpls_label=2 actions=decap(),decap(packet_type(ns=0,type=0)),ovs-p1\"])\n+\n+rm -rf p1.pcap\n+NS_CHECK_EXEC([at_ns1], [tcpdump -l -n -xx -U -i p1 > p1.pcap &])\n+sleep 1\n+\n+dnl The hex dump is an mpls packet encapsulating ethernet packet. pkt=eth/mpls/eth/ip/icmp\n+dnl The packet is sent from p0(at_ns0) interface directed to\n+dnl p1(at_ns1) interface\n+NS_CHECK_EXEC([at_ns0], [$PYTHON3 $srcdir/sendpkt.py p0 00 00 00 00 00 02 00 00 00 00 00 01 88 47 00 00 21 40 36 b1 ee 7c 01 02 36 b1 ee 7c 01 03 08 00 45 00 00 54 03 44 40 00 40 01 21 61 0a 01 01 01 0a 01 01 02 08 00 ef ac 7c e4 00 03 5b 2c 1f 61 00 00 00 00 50 0b 02 00 00 00 00 00 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37  > /dev/null])\n+\n+dnl Check the expected decapsulated on the egress interface\n+OVS_WAIT_UNTIL([cat p1.pcap | egrep \"0x0000:  *36b1 *ee7c *0102 *36b1 *ee7c *0103 *0800 *4500\" 2>&1 1>/dev/null])\n+OVS_WAIT_UNTIL([cat p1.pcap | egrep \"0x0010:  *0054 *0344 *4000 *4001 *2161 *0a01 *0101 *0a01\" 2>&1 1>/dev/null])\n+OVS_WAIT_UNTIL([cat p1.pcap | egrep \"0x0020:  *0102 *0800 *efac *7ce4 *0003 *5b2c *1f61 *0000\" 2>&1 1>/dev/null])\n+OVS_WAIT_UNTIL([cat p1.pcap | egrep \"0x0030:  *0000 *500b *0200 *0000 *0000 *1011 *1213 *1415\" 2>&1 1>/dev/null])\n+OVS_WAIT_UNTIL([cat p1.pcap | egrep \"0x0040:  *1617 *1819 *1a1b *1c1d *1e1f *2021 *2223 *2425\" 2>&1 1>/dev/null])\n+OVS_WAIT_UNTIL([cat p1.pcap | egrep \"0x0050:  *2627 *2829 *2a2b *2c2d *2e2f *3031 *3233 *3435\" 2>&1 1>/dev/null])\n+OVS_WAIT_UNTIL([cat p1.pcap | egrep \"0x0060:  *3637\" 2>&1 1>/dev/null])\n+\n+\n+OVS_TRAFFIC_VSWITCHD_STOP\n+AT_CLEANUP\n+\n+\n+AT_SETUP([datapath - Encap Decap mpls actions])\n+OVS_TRAFFIC_VSWITCHD_START([_ADD_BR([br1])])\n+\n+ADD_NAMESPACES(at_ns0, at_ns1)\n+\n+ADD_VETH(p0, at_ns0, br0, \"10.1.1.1/24\")\n+ADD_VETH(p1, at_ns1, br1, \"10.1.1.2/24\")\n+\n+AT_CHECK([ip link add patch0 type veth peer name patch1])\n+on_exit 'ip link del patch0'\n+\n+AT_CHECK([ip link set dev patch0 up])\n+AT_CHECK([ip link set dev patch1 up])\n+AT_CHECK([ovs-vsctl add-port br0 patch0 -- set interface patch0 ofport_request=100])\n+AT_CHECK([ovs-vsctl add-port br1 patch1 -- set interface patch1 ofport_request=100])\n+\n+AT_DATA([flows.txt], [dnl\n+table=0,priority=100,in_port=ovs-p0 actions=encap(mpls),set_mpls_label:2,encap(ethernet),set_field:00:00:00:00:00:02->dl_dst,set_field:00:00:00:00:00:01->dl_src,output:100\n+table=0,priority=100,in_port=100,dl_type=0x8847,mpls_label=2 actions=decap(),decap(packet_type(ns=0,type=0)),ovs-p0\n+])\n+\n+AT_DATA([flows1.txt], [dnl\n+table=0,priority=100,in_port=ovs-p1 actions=encap(mpls),set_mpls_label:2,encap(ethernet),set_field:00:00:00:00:00:02->dl_dst,set_field:00:00:00:00:00:01->dl_src,output:100\n+table=0,priority=100,in_port=100,dl_type=0x8847,mpls_label=2 actions=decap(),decap(packet_type(ns=0,type=0)),ovs-p1\n+])\n+\n+AT_CHECK([ovs-ofctl  -Oopenflow13 add-flows br0 flows.txt])\n+AT_CHECK([ovs-ofctl  -Oopenflow13 add-flows br1 flows1.txt])\n+\n+NS_CHECK_EXEC([at_ns0], [ping -q -c 3 -i 0.3  10.1.1.2 | FORMAT_PING], [0], [dnl\n+3 packets transmitted, 3 received, 0% packet loss, time 0ms\n+])\n+\n+\n+NS_CHECK_EXEC([at_ns1], [ping -q -c 3 -i 0.3  10.1.1.1 | FORMAT_PING], [0], [dnl\n+3 packets transmitted, 3 received, 0% packet loss, time 0ms\n+])\n+\n+OVS_TRAFFIC_VSWITCHD_STOP\n+AT_CLEANUP\n+\n+AT_SETUP([datapath - multiple encap decap mpls actions])\n+OVS_TRAFFIC_VSWITCHD_START([_ADD_BR([br1])])\n+\n+ADD_NAMESPACES(at_ns0, at_ns1)\n+\n+ADD_VETH(p0, at_ns0, br0, \"10.1.1.1/24\")\n+ADD_VETH(p1, at_ns1, br1, \"10.1.1.2/24\")\n+\n+AT_CHECK([ip link add patch0 type veth peer name patch1])\n+on_exit 'ip link del patch0'\n+\n+AT_CHECK([ip link set dev patch0 up])\n+AT_CHECK([ip link set dev patch1 up])\n+AT_CHECK([ovs-vsctl add-port br0 patch0 -- set interface patch0 ofport_request=100])\n+AT_CHECK([ovs-vsctl add-port br1 patch1 -- set interface patch1 ofport_request=100])\n+\n+AT_DATA([flows.txt], [dnl\n+table=0,priority=100,in_port=ovs-p0 actions=encap(mpls),set_mpls_label:3, encap(mpls),set_mpls_label:2,encap(ethernet),set_field:00:00:00:00:00:02->dl_dst,set_field:00:00:00:00:00:01->dl_src,output:100\n+table=0,priority=100,in_port=100,dl_type=0x8847,mpls_label=2 actions=decap(),decap(packet_type(ns=1,type=0x8847)),decap(packet_type(ns=0,type=0)),ovs-p0\n+])\n+\n+AT_DATA([flows1.txt], [dnl\n+table=0,priority=100,in_port=ovs-p1 actions=encap(mpls),set_mpls_label:3, encap(mpls),set_mpls_label:2,encap(ethernet),set_field:00:00:00:00:00:02->dl_dst,set_field:00:00:00:00:00:01->dl_src,output:100\n+table=0,priority=100,in_port=100,dl_type=0x8847,mpls_label=2 actions=decap(),decap(packet_type(ns=1,type=0x8847)),decap(packet_type(ns=0,type=0)),ovs-p1\n+])\n+\n+AT_CHECK([ovs-ofctl  -Oopenflow13 add-flows br0 flows.txt])\n+AT_CHECK([ovs-ofctl  -Oopenflow13 add-flows br1 flows1.txt])\n+\n+NS_CHECK_EXEC([at_ns0], [ping -q -c 3 -i 0.3 10.1.1.2 | FORMAT_PING], [0], [dnl\n+3 packets transmitted, 3 received, 0% packet loss, time 0ms\n+])\n+\n+\n+NS_CHECK_EXEC([at_ns1], [ping -q -c 3 -i 0.3 10.1.1.1 | FORMAT_PING], [0], [dnl\n+3 packets transmitted, 3 received, 0% packet loss, time 0ms\n+])\n+\n+OVS_TRAFFIC_VSWITCHD_STOP\n+AT_CLEANUP\n+\n+AT_SETUP([datapath - encap mpls pop mpls actions])\n+OVS_TRAFFIC_VSWITCHD_START([_ADD_BR([br1])])\n+\n+ADD_NAMESPACES(at_ns0, at_ns1)\n+\n+ADD_VETH(p0, at_ns0, br0, \"10.1.1.1/24\", 36:b1:ee:7c:01:03)\n+ADD_VETH(p1, at_ns1, br1, \"10.1.1.2/24\", 36:b1:ee:7c:01:02)\n+\n+AT_CHECK([ip link add patch0 type veth peer name patch1])\n+on_exit 'ip link del patch0'\n+\n+AT_CHECK([ip link set dev patch0 up])\n+AT_CHECK([ip link set dev patch1 up])\n+AT_CHECK([ovs-vsctl add-port br0 patch0 -- set interface patch0 ofport_request=100])\n+AT_CHECK([ovs-vsctl add-port br1 patch1 -- set interface patch1 ofport_request=100])\n+\n+AT_DATA([flows.txt], [dnl\n+table=0,priority=100,dl_type=0x0800 actions=decap,encap(mpls),set_mpls_label:2,encap(ethernet),mod_dl_dst:36:b1:ee:7c:01:02,mod_dl_src:36:b1:ee:7c:01:03,output:100\n+table=0,priority=100,dl_type=0x8847,mpls_label=2 actions=pop_mpls:0x0800,resubmit(,3)\n+table=0,priority=10 actions=resubmit(,3)\n+table=3,priority=10 actions=normal\n+])\n+\n+AT_DATA([flows1.txt], [dnl\n+table=0,priority=100,dl_type=0x0800 actions=decap,encap(mpls),set_mpls_label:2,encap(ethernet),mod_dl_dst:36:b1:ee:7c:01:03,mod_dl_src:36:b1:ee:7c:01:02,output:100\n+table=0,priority=100,dl_type=0x8847,mpls_label=2 actions=pop_mpls:0x0800,resubmit(,3)\n+table=0,priority=10 actions=resubmit(,3)\n+table=3,priority=10 actions=normal\n+])\n+\n+AT_CHECK([ovs-ofctl  -Oopenflow13 add-flows br0 flows.txt])\n+AT_CHECK([ovs-ofctl  -Oopenflow13 add-flows br1 flows1.txt])\n+\n+NS_CHECK_EXEC([at_ns0], [ping -q -c 3 -i 0.3 10.1.1.2 | FORMAT_PING], [0], [dnl\n+3 packets transmitted, 3 received, 0% packet loss, time 0ms\n+])\n+\n+NS_CHECK_EXEC([at_ns1], [ping -q -c 3 -i 0.3 10.1.1.1 | FORMAT_PING], [0], [dnl\n+3 packets transmitted, 3 received, 0% packet loss, time 0ms\n+])\n+\n+OVS_TRAFFIC_VSWITCHD_STOP\n+AT_CLEANUP\n+\n+AT_SETUP([datapath - push mpls decap mpls actions])\n+OVS_TRAFFIC_VSWITCHD_START([_ADD_BR([br1])])\n+\n+ADD_NAMESPACES(at_ns0, at_ns1)\n+\n+ADD_VETH(p0, at_ns0, br0, \"10.1.1.1/24\", 36:b1:ee:7c:01:03)\n+ADD_VETH(p1, at_ns1, br1, \"10.1.1.2/24\", 36:b1:ee:7c:01:02)\n+\n+AT_CHECK([ip link add patch0 type veth peer name patch1])\n+on_exit 'ip link del patch0'\n+\n+AT_CHECK([ip link set dev patch0 up])\n+AT_CHECK([ip link set dev patch1 up])\n+AT_CHECK([ovs-vsctl add-port br0 patch0 -- set interface patch0 ofport_request=100])\n+AT_CHECK([ovs-vsctl add-port br1 patch1 -- set interface patch1 ofport_request=100])\n+\n+AT_DATA([flows.txt], [dnl\n+table=0,priority=100,dl_type=0x0800 actions=push_mpls:0x8847,set_field:2->mpls_label,output:100\n+table=0,priority=100,dl_type=0x8847,mpls_label=2 actions=decap,decap(packet_type(ns=1,type=0x0800)),encap(ethernet),mod_dl_dst:36:b1:ee:7c:01:03,mod_dl_src:36:b1:ee:7c:01:02,resubmit(,3)\n+table=0,priority=10 actions=resubmit(,3)\n+table=3,priority=10 actions=normal\n+])\n+\n+AT_DATA([flows1.txt], [dnl\n+table=0,priority=100,dl_type=0x0800 actions=push_mpls:0x8847,set_field:2->mpls_label,output:100\n+table=0,priority=100,dl_type=0x8847,mpls_label=2 actions=decap,decap(packet_type(ns=1,type=0x0800)),encap(ethernet),mod_dl_dst:36:b1:ee:7c:01:02,mod_dl_src:36:b1:ee:7c:01:03,resubmit(,3)\n+table=0,priority=10 actions=resubmit(,3)\n+table=3,priority=10 actions=normal\n+])\n+\n+AT_CHECK([ovs-ofctl  -Oopenflow13 add-flows br0 flows.txt])\n+AT_CHECK([ovs-ofctl  -Oopenflow13 add-flows br1 flows1.txt])\n+\n+NS_CHECK_EXEC([at_ns0], [ping -q -c 3 -i 0.3 10.1.1.2 | FORMAT_PING], [0], [dnl\n+3 packets transmitted, 3 received, 0% packet loss, time 0ms\n+])\n+\n+NS_CHECK_EXEC([at_ns1], [ping -q -c 3 -i 0.3 10.1.1.1 | FORMAT_PING], [0], [dnl\n+3 packets transmitted, 3 received, 0% packet loss, time 0ms\n+])\n+\n+OVS_TRAFFIC_VSWITCHD_STOP\n+AT_CLEANUP\n+\n AT_SETUP([datapath - basic truncate action])\n AT_SKIP_IF([test $HAVE_NC = no])\n OVS_TRAFFIC_VSWITCHD_START()\n",
    "prefixes": [
        "ovs-dev",
        "v8"
    ]
}