Patch Detail
get:
Show a patch.
patch:
Update a patch.
put:
Update a patch.
GET /api/patches/1561024/
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, ð_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" ] }{ "id": 1561024, "url": "