[ovs-dev,1/1] Encap & Decap actions for MPLS Packet Type.
diff mbox series

Message ID 79c4707a0317492a2cf7c696310dd3c2823ccab7.1570345101.git.martinvarghesenokia@gmail.com
State New
Headers show
Series
  • Encap & Decap actions for MPLS Packet Type
Related show

Commit Message

Martin Varghese Oct. 8, 2019, 2:43 a.m. UTC
Encap & Decap actions are extended to support MPLS packet type.
The encap & decap adds and removes MPLS header at the start of
packet.

CLI syntax for Encap & Decap
	- encap(mpls(ether_type=0x8847))
        - decap(packet_type(ns=x,type=y))

Signed-off-by: Martin Varghese <martinvarghesenokia@gmail.com>
---
 datapath/actions.c                                | 57 ++++++++++++++
 datapath/flow_netlink.c                           | 13 ++++
 datapath/linux/compat/include/linux/openvswitch.h |  2 +
 include/openvswitch/ofp-ed-props.h                | 18 +++++
 lib/dpif.c                                        |  2 +
 lib/odp-execute.c                                 |  2 +
 lib/odp-util.c                                    | 46 +++++++++--
 lib/ofp-actions.c                                 |  5 ++
 lib/ofp-ed-props.c                                | 93 ++++++++++++++++++++++-
 ofproto/ofproto-dpif-xlate.c                      | 58 +++++++++++++-
 10 files changed, 288 insertions(+), 8 deletions(-)

Comments

0-day Robot Oct. 8, 2019, 2:58 a.m. UTC | #1
Bleep bloop.  Greetings Martin Varghese, I am a robot and I have tried out your patch.
Thanks for your contribution.

I encountered some error that I wasn't expecting.  See the details below.


checkpatch:
WARNING: Line is 84 characters long (recommended limit is 79)
#246 FILE: lib/odp-util.c:144:
    case OVS_ACTION_ATTR_PTAP_PUSH_MPLS: return sizeof(struct ovs_action_push_mpls);

WARNING: Line is 81 characters long (recommended limit is 79)
#259 FILE: lib/odp-util.c:1216:
        ds_put_format(ds, ",eth_type=0x%"PRIx16")", ntohs(mpls->mpls_ethertype));

WARNING: Line is 83 characters long (recommended limit is 79)
#269 FILE: lib/odp-util.c:1226:
        ds_put_format(ds, "ptap_pop_mpls(eth_type=0x%"PRIx16")", ntohs(ethertype));

WARNING: Line is 84 characters long (recommended limit is 79)
#300 FILE: lib/odp-util.c:7731:
               nl_msg_put_be16(odp_actions, OVS_ACTION_ATTR_PTAP_POP_MPLS, dl_type);

Lines checked: 630, Warnings: 4, Errors: 0


build:
mv -f $depbase.Tpo $depbase.Plo
libtool: compile:  gcc -std=gnu99 -DHAVE_CONFIG_H -I. -I ./include -I ./include -I ./lib -I ./lib -Wstrict-prototypes -Wall -Wextra -Wno-sign-compare -Wpointer-arith -Wformat -Wformat-security -Wswitch-enum -Wunused-parameter -Wbad-function-cast -Wcast-align -Wstrict-prototypes -Wold-style-definition -Wmissing-prototypes -Wmissing-field-initializers -fno-strict-aliasing -Wshadow -Werror -Werror -g -O2 -MT lib/dpctl.lo -MD -MP -MF lib/.deps/dpctl.Tpo -c lib/dpctl.c -o lib/dpctl.o
depbase=`echo lib/dp-packet.lo | sed 's|[^/]*$|.deps/&|;s|\.lo$||'`;\
/bin/sh ./libtool  --tag=CC   --mode=compile gcc -std=gnu99 -DHAVE_CONFIG_H -I.    -I ./include -I ./include -I ./lib -I ./lib    -Wstrict-prototypes -Wall -Wextra -Wno-sign-compare -Wpointer-arith -Wformat -Wformat-security -Wswitch-enum -Wunused-parameter -Wbad-function-cast -Wcast-align -Wstrict-prototypes -Wold-style-definition -Wmissing-prototypes -Wmissing-field-initializers -fno-strict-aliasing -Wshadow -Werror -Werror   -g -O2 -MT lib/dp-packet.lo -MD -MP -MF $depbase.Tpo -c -o lib/dp-packet.lo lib/dp-packet.c &&\
mv -f $depbase.Tpo $depbase.Plo
libtool: compile:  gcc -std=gnu99 -DHAVE_CONFIG_H -I. -I ./include -I ./include -I ./lib -I ./lib -Wstrict-prototypes -Wall -Wextra -Wno-sign-compare -Wpointer-arith -Wformat -Wformat-security -Wswitch-enum -Wunused-parameter -Wbad-function-cast -Wcast-align -Wstrict-prototypes -Wold-style-definition -Wmissing-prototypes -Wmissing-field-initializers -fno-strict-aliasing -Wshadow -Werror -Werror -g -O2 -MT lib/dp-packet.lo -MD -MP -MF lib/.deps/dp-packet.Tpo -c lib/dp-packet.c -o lib/dp-packet.o
depbase=`echo lib/dpif-netdev-lookup-generic.lo | sed 's|[^/]*$|.deps/&|;s|\.lo$||'`;\
/bin/sh ./libtool  --tag=CC   --mode=compile gcc -std=gnu99 -DHAVE_CONFIG_H -I.    -I ./include -I ./include -I ./lib -I ./lib    -Wstrict-prototypes -Wall -Wextra -Wno-sign-compare -Wpointer-arith -Wformat -Wformat-security -Wswitch-enum -Wunused-parameter -Wbad-function-cast -Wcast-align -Wstrict-prototypes -Wold-style-definition -Wmissing-prototypes -Wmissing-field-initializers -fno-strict-aliasing -Wshadow -Werror -Werror   -g -O2 -MT lib/dpif-netdev-lookup-generic.lo -MD -MP -MF $depbase.Tpo -c -o lib/dpif-netdev-lookup-generic.lo lib/dpif-netdev-lookup-generic.c &&\
mv -f $depbase.Tpo $depbase.Plo
libtool: compile:  gcc -std=gnu99 -DHAVE_CONFIG_H -I. -I ./include -I ./include -I ./lib -I ./lib -Wstrict-prototypes -Wall -Wextra -Wno-sign-compare -Wpointer-arith -Wformat -Wformat-security -Wswitch-enum -Wunused-parameter -Wbad-function-cast -Wcast-align -Wstrict-prototypes -Wold-style-definition -Wmissing-prototypes -Wmissing-field-initializers -fno-strict-aliasing -Wshadow -Werror -Werror -g -O2 -MT lib/dpif-netdev-lookup-generic.lo -MD -MP -MF lib/.deps/dpif-netdev-lookup-generic.Tpo -c lib/dpif-netdev-lookup-generic.c -o lib/dpif-netdev-lookup-generic.o
depbase=`echo lib/dpif-netdev.lo | sed 's|[^/]*$|.deps/&|;s|\.lo$||'`;\
/bin/sh ./libtool  --tag=CC   --mode=compile gcc -std=gnu99 -DHAVE_CONFIG_H -I.    -I ./include -I ./include -I ./lib -I ./lib    -Wstrict-prototypes -Wall -Wextra -Wno-sign-compare -Wpointer-arith -Wformat -Wformat-security -Wswitch-enum -Wunused-parameter -Wbad-function-cast -Wcast-align -Wstrict-prototypes -Wold-style-definition -Wmissing-prototypes -Wmissing-field-initializers -fno-strict-aliasing -Wshadow -Werror -Werror   -g -O2 -MT lib/dpif-netdev.lo -MD -MP -MF $depbase.Tpo -c -o lib/dpif-netdev.lo lib/dpif-netdev.c &&\
mv -f $depbase.Tpo $depbase.Plo
libtool: compile:  gcc -std=gnu99 -DHAVE_CONFIG_H -I. -I ./include -I ./include -I ./lib -I ./lib -Wstrict-prototypes -Wall -Wextra -Wno-sign-compare -Wpointer-arith -Wformat -Wformat-security -Wswitch-enum -Wunused-parameter -Wbad-function-cast -Wcast-align -Wstrict-prototypes -Wold-style-definition -Wmissing-prototypes -Wmissing-field-initializers -fno-strict-aliasing -Wshadow -Werror -Werror -g -O2 -MT lib/dpif-netdev.lo -MD -MP -MF lib/.deps/dpif-netdev.Tpo -c lib/dpif-netdev.c -o lib/dpif-netdev.o
lib/dpif-netdev.c: In function 'dp_execute_cb':
lib/dpif-netdev.c:7029:5: error: enumeration value 'OVS_ACTION_ATTR_PTAP_PUSH_MPLS' not handled in switch [-Werror=switch]
     switch ((enum ovs_action_attr)type) {
     ^
lib/dpif-netdev.c:7029:5: error: enumeration value 'OVS_ACTION_ATTR_PTAP_POP_MPLS' not handled in switch [-Werror=switch]
cc1: all warnings being treated as errors
make[2]: *** [lib/dpif-netdev.lo] Error 1
make[2]: Leaving directory `/var/lib/jenkins/jobs/upstream_build_from_pw/workspace'
make[1]: *** [all-recursive] Error 1
make[1]: Leaving directory `/var/lib/jenkins/jobs/upstream_build_from_pw/workspace'
make: *** [all] Error 2


Please check this out.  If you feel there has been an error, please email aconole@redhat.com

Thanks,
0-day Robot

Patch
diff mbox series

diff --git a/datapath/actions.c b/datapath/actions.c
index a44e804..98559f4 100644
--- a/datapath/actions.c
+++ b/datapath/actions.c
@@ -184,6 +184,55 @@  static void update_ethertype(struct sk_buff *skb, struct ethhdr *hdr,
 	hdr->h_proto = ethertype;
 }
 
+static int push_ptap_mpls(struct sk_buff *skb, struct sw_flow_key *key,
+		const struct ovs_action_push_mpls *mpls)
+{
+
+	struct mpls_shim_hdr *lse;
+	int err;
+
+	if (unlikely(!eth_p_mpls(mpls->mpls_ethertype)))
+		return -EINVAL;
+
+	/* Networking stack does not allow simultaneous Tunnel and MPLS GSO. */
+	if (skb->encapsulation)
+		return -EINVAL;
+
+	err = skb_cow_head(skb, MPLS_HLEN);
+	if (unlikely(err))
+		return err;
+
+	if (!skb->inner_protocol) {
+		skb_set_inner_network_header(skb, skb->mac_len);
+		skb_set_inner_protocol(skb, skb->protocol);
+	}
+
+	skb_push(skb, MPLS_HLEN);
+	skb_reset_mac_header(skb);
+	skb_reset_network_header(skb);
+
+	lse = mpls_hdr(skb);
+	lse->label_stack_entry = mpls->mpls_lse;
+	skb_postpush_rcsum(skb, lse, MPLS_HLEN);
+	skb->protocol = mpls->mpls_ethertype;
+
+	invalidate_flow_key(key);
+	return 0;
+}
+
+static int ptap_pop_mpls(struct sk_buff *skb, struct sw_flow_key *key,
+		const __be16 ethertype)
+{
+	int err;
+
+	if(!ethertype)
+		key->mac_proto = MAC_PROTO_ETHERNET;
+
+	pop_mpls(skb, key, ethertype);
+	invalidate_flow_key(key);
+	return 0;
+}
+
 static int push_mpls(struct sk_buff *skb, struct sw_flow_key *key,
 		     const struct ovs_action_push_mpls *mpls)
 {
@@ -1313,10 +1362,18 @@  static int do_execute_actions(struct datapath *dp, struct sk_buff *skb,
 			err = push_mpls(skb, key, nla_data(a));
 			break;
 
+		case OVS_ACTION_ATTR_PTAP_PUSH_MPLS:
+                        err = push_ptap_mpls(skb, key, nla_data(a));
+                        break;
+
 		case OVS_ACTION_ATTR_POP_MPLS:
 			err = pop_mpls(skb, key, nla_get_be16(a));
 			break;
 
+		 case OVS_ACTION_ATTR_PTAP_POP_MPLS:
+                        err = ptap_pop_mpls(skb, key, nla_get_be16(a));
+                        break;
+
 		case OVS_ACTION_ATTR_PUSH_VLAN:
 			err = push_vlan(skb, key, nla_data(a));
 			break;
diff --git a/datapath/flow_netlink.c b/datapath/flow_netlink.c
index 0f7ab53..b454536 100644
--- a/datapath/flow_netlink.c
+++ b/datapath/flow_netlink.c
@@ -83,10 +83,12 @@  static bool actions_may_change_flow(const struct nlattr *actions)
 		case OVS_ACTION_ATTR_HASH:
 		case OVS_ACTION_ATTR_POP_ETH:
 		case OVS_ACTION_ATTR_POP_MPLS:
+		case OVS_ACTION_ATTR_PTAP_POP_MPLS:
 		case OVS_ACTION_ATTR_POP_NSH:
 		case OVS_ACTION_ATTR_POP_VLAN:
 		case OVS_ACTION_ATTR_PUSH_ETH:
 		case OVS_ACTION_ATTR_PUSH_MPLS:
+		case OVS_ACTION_ATTR_PTAP_PUSH_MPLS:
 		case OVS_ACTION_ATTR_PUSH_NSH:
 		case OVS_ACTION_ATTR_PUSH_VLAN:
 		case OVS_ACTION_ATTR_SAMPLE:
@@ -2975,6 +2977,8 @@  static int __ovs_nla_copy_actions(struct net *net, const struct nlattr *attr,
 			[OVS_ACTION_ATTR_METER] = sizeof(u32),
 			[OVS_ACTION_ATTR_CLONE] = (u32)-1,
 			[OVS_ACTION_ATTR_CHECK_PKT_LEN] = (u32)-1,
+			[OVS_ACTION_ATTR_PTAP_PUSH_MPLS] = sizeof(struct ovs_action_push_mpls),
+			[OVS_ACTION_ATTR_PTAP_POP_MPLS] = sizeof(__be16),
 		};
 		const struct ovs_action_push_vlan *vlan;
 		int type = nla_type(a);
@@ -3042,6 +3046,14 @@  static int __ovs_nla_copy_actions(struct net *net, const struct nlattr *attr,
 		case OVS_ACTION_ATTR_RECIRC:
 			break;
 
+		case OVS_ACTION_ATTR_PTAP_PUSH_MPLS: {
+			const struct ovs_action_push_mpls *mpls = nla_data(a);
+
+			mac_proto = MAC_PROTO_NONE;
+			eth_type = mpls->mpls_ethertype;
+			break;
+		}
+
 		case OVS_ACTION_ATTR_PUSH_MPLS: {
 			const struct ovs_action_push_mpls *mpls = nla_data(a);
 
@@ -3062,6 +3074,7 @@  static int __ovs_nla_copy_actions(struct net *net, const struct nlattr *attr,
 		}
 
 		case OVS_ACTION_ATTR_POP_MPLS:
+		case OVS_ACTION_ATTR_POP_MPLS:
 			if (vlan_tci & htons(VLAN_CFI_MASK) ||
 			    !eth_p_mpls(eth_type))
 				return -EINVAL;
diff --git a/datapath/linux/compat/include/linux/openvswitch.h b/datapath/linux/compat/include/linux/openvswitch.h
index 65a003a..b8a375f 100644
--- a/datapath/linux/compat/include/linux/openvswitch.h
+++ b/datapath/linux/compat/include/linux/openvswitch.h
@@ -985,6 +985,8 @@  enum ovs_action_attr {
 	OVS_ACTION_ATTR_METER,        /* u32 meter number. */
 	OVS_ACTION_ATTR_CLONE,        /* Nested OVS_CLONE_ATTR_*.  */
 	OVS_ACTION_ATTR_CHECK_PKT_LEN, /* Nested OVS_CHECK_PKT_LEN_ATTR_*. */
+	OVS_ACTION_ATTR_PTAP_PUSH_MPLS,    /* struct ovs_action_push_mpls. */
+	OVS_ACTION_ATTR_PTAP_POP_MPLS,     /* __be16 ethertype. */
 
 #ifndef __KERNEL__
 	OVS_ACTION_ATTR_TUNNEL_PUSH,   /* struct ovs_action_push_tnl*/
diff --git a/include/openvswitch/ofp-ed-props.h b/include/openvswitch/ofp-ed-props.h
index 306c6fe..bb1566c 100644
--- a/include/openvswitch/ofp-ed-props.h
+++ b/include/openvswitch/ofp-ed-props.h
@@ -46,6 +46,11 @@  enum ofp_ed_nsh_prop_type {
     OFPPPT_PROP_NSH_TLV = 2,     /* property TLV in NSH */
 };
 
+enum ofp_ed_mpls_prop_type {
+    OFPPPT_PROP_MPLS_NONE = 0,    /* unused */
+    OFPPPT_PROP_MPLS_ETHERTYPE = 1,  /* MPLS Ethertype */
+};
+
 /*
  * External representation of encap/decap properties.
  * These must be padded to a multiple of 8 bytes.
@@ -72,6 +77,13 @@  struct ofp_ed_prop_nsh_tlv {
     uint8_t data[0];
 };
 
+struct ofp_ed_prop_mpls_ethertype {
+    struct ofp_ed_prop_header header;
+    uint16_t ether_type;         /* NSH MD type .*/
+    uint8_t pad[2];          /* Padding to 8 bytes. */
+};
+
+
 /*
  * Internal representation of encap/decap properties
  */
@@ -96,6 +108,12 @@  struct ofpact_ed_prop_nsh_tlv {
     /* tlv_len octets of metadata value, padded to a multiple of 8 bytes. */
     uint8_t data[0];
 };
+
+struct ofpact_ed_prop_mpls_ethertype {
+    struct ofpact_ed_prop header;
+    uint16_t ether_type;         /* MPLS ether type .*/
+    uint8_t pad[2];          /* Padding to 2 bytes. */
+};
 enum ofperr decode_ed_prop(const struct ofp_ed_prop_header **ofp_prop,
                            struct ofpbuf *out, size_t *remaining);
 enum ofperr encode_ed_prop(const struct ofpact_ed_prop **prop,
diff --git a/lib/dpif.c b/lib/dpif.c
index c88b210..a27ff97 100644
--- a/lib/dpif.c
+++ b/lib/dpif.c
@@ -1274,6 +1274,8 @@  dpif_execute_helper_cb(void *aux_, struct dp_packet_batch *packets_,
     case OVS_ACTION_ATTR_CT_CLEAR:
     case OVS_ACTION_ATTR_UNSPEC:
     case OVS_ACTION_ATTR_CHECK_PKT_LEN:
+    case OVS_ACTION_ATTR_PTAP_PUSH_MPLS:
+    case OVS_ACTION_ATTR_PTAP_POP_MPLS:
     case __OVS_ACTION_ATTR_MAX:
         OVS_NOT_REACHED();
     }
diff --git a/lib/odp-execute.c b/lib/odp-execute.c
index 563ad1d..2ab3cc6 100644
--- a/lib/odp-execute.c
+++ b/lib/odp-execute.c
@@ -749,6 +749,8 @@  requires_datapath_assistance(const struct nlattr *a)
     case OVS_ACTION_ATTR_POP_NSH:
     case OVS_ACTION_ATTR_CT_CLEAR:
     case OVS_ACTION_ATTR_CHECK_PKT_LEN:
+    case OVS_ACTION_ATTR_PTAP_PUSH_MPLS:
+    case OVS_ACTION_ATTR_PTAP_POP_MPLS:
         return false;
 
     case OVS_ACTION_ATTR_UNSPEC:
diff --git a/lib/odp-util.c b/lib/odp-util.c
index 84ea4c1..bb5c194 100644
--- a/lib/odp-util.c
+++ b/lib/odp-util.c
@@ -140,6 +140,8 @@  odp_action_len(uint16_t type)
     case OVS_ACTION_ATTR_PUSH_NSH: return ATTR_LEN_VARIABLE;
     case OVS_ACTION_ATTR_POP_NSH: return 0;
     case OVS_ACTION_ATTR_CHECK_PKT_LEN: return ATTR_LEN_VARIABLE;
+    case OVS_ACTION_ATTR_PTAP_PUSH_MPLS: return sizeof(struct ovs_action_push_mpls);
+    case OVS_ACTION_ATTR_PTAP_POP_MPLS: return sizeof(ovs_be16);
 
     case OVS_ACTION_ATTR_UNSPEC:
     case __OVS_ACTION_ATTR_MAX:
@@ -1199,11 +1201,24 @@  format_odp_action(struct ds *ds, const struct nlattr *a,
         ds_put_format(ds, ",eth_type=0x%"PRIx16")", ntohs(mpls->mpls_ethertype));
         break;
     }
+    case OVS_ACTION_ATTR_PTAP_PUSH_MPLS: {
+        const struct ovs_action_push_mpls *mpls = nl_attr_get(a);
+        ds_put_cstr(ds, "ptap_push_mpls(");
+        format_mpls_lse(ds, mpls->mpls_lse);
+        ds_put_format(ds, ",eth_type=0x%"PRIx16")", ntohs(mpls->mpls_ethertype));
+        break;
+    }
     case OVS_ACTION_ATTR_POP_MPLS: {
         ovs_be16 ethertype = nl_attr_get_be16(a);
         ds_put_format(ds, "pop_mpls(eth_type=0x%"PRIx16")", ntohs(ethertype));
         break;
     }
+    case OVS_ACTION_ATTR_PTAP_POP_MPLS: {
+        ovs_be16 ethertype = nl_attr_get_be16(a);
+        ds_put_format(ds, "ptap_pop_mpls(eth_type=0x%"PRIx16")", ntohs(ethertype));
+        break;
+    }
+
     case OVS_ACTION_ATTR_SAMPLE:
         format_odp_sample_action(ds, a, portno_names);
         break;
@@ -7443,7 +7458,6 @@  odp_put_push_eth_action(struct ofpbuf *odp_actions,
     nl_msg_put_unspec(odp_actions, OVS_ACTION_ATTR_PUSH_ETH,
                       &eth, sizeof eth);
 }
-
 void
 odp_put_tunnel_action(const struct flow_tnl *tunnel,
                       struct ofpbuf *odp_actions, const char *tnl_type)
@@ -7647,7 +7661,8 @@  commit_vlan_action(const struct flow* flow, struct flow *base,
 /* Wildcarding already done at action translation time. */
 static void
 commit_mpls_action(const struct flow *flow, struct flow *base,
-                   struct ofpbuf *odp_actions)
+                   struct ofpbuf *odp_actions,  bool pending_encap,
+                   bool pending_decap)
 {
     int base_n = flow_count_mpls_labels(base, NULL);
     int flow_n = flow_count_mpls_labels(flow, NULL);
@@ -7686,7 +7701,11 @@  commit_mpls_action(const struct flow *flow, struct flow *base,
             } else {
                 dl_type = flow->dl_type;
             }
-            nl_msg_put_be16(odp_actions, OVS_ACTION_ATTR_POP_MPLS, dl_type);
+            if (pending_decap) {
+               nl_msg_put_be16(odp_actions, OVS_ACTION_ATTR_PTAP_POP_MPLS, dl_type);
+            } else {
+               nl_msg_put_be16(odp_actions, OVS_ACTION_ATTR_POP_MPLS, dl_type);
+            }
             ovs_assert(flow_pop_mpls(base, base_n, flow->dl_type, NULL));
             base_n--;
         }
@@ -7697,9 +7716,16 @@  commit_mpls_action(const struct flow *flow, struct flow *base,
     while (base_n < flow_n) {
         struct ovs_action_push_mpls *mpls;
 
-        mpls = nl_msg_put_unspec_zero(odp_actions,
+        if (!pending_encap) {
+            mpls = nl_msg_put_unspec_zero(odp_actions,
                                       OVS_ACTION_ATTR_PUSH_MPLS,
                                       sizeof *mpls);
+        } else {
+            mpls = nl_msg_put_unspec_zero(odp_actions,
+                                      OVS_ACTION_ATTR_PTAP_PUSH_MPLS,
+                                      sizeof *mpls);
+
+        }
         mpls->mpls_ethertype = flow->dl_type;
         mpls->mpls_lse = flow->mpls_lse[flow_n - base_n - 1];
         /* Update base flow's MPLS stack, but do not clear L3.  We need the L3
@@ -8346,6 +8372,10 @@  commit_encap_decap_action(const struct flow *flow,
             memcpy(&base_flow->dl_dst, &flow->dl_dst,
                    sizeof(*flow) - offsetof(struct flow, dl_dst));
             break;
+        case PT_MPLS:
+             commit_mpls_action(flow, base_flow, odp_actions, pending_encap,
+                                pending_decap);
+             break;
         default:
             /* Only the above protocols are supported for encap.
              * The check is done at action translation. */
@@ -8368,6 +8398,10 @@  commit_encap_decap_action(const struct flow *flow,
                 /* pop_nsh. */
                 odp_put_pop_nsh_action(odp_actions);
                 break;
+            case PT_MPLS:
+                 commit_mpls_action(flow, base_flow, odp_actions,pending_encap,
+                                    pending_decap);
+                 break;
             default:
                 /* Checks are done during translation. */
                 OVS_NOT_REACHED();
@@ -8413,7 +8447,7 @@  commit_odp_actions(const struct flow *flow, struct flow *base,
     /* Make packet a non-MPLS packet before committing L3/4 actions,
      * which would otherwise do nothing. */
     if (eth_type_mpls(base->dl_type) && !eth_type_mpls(flow->dl_type)) {
-        commit_mpls_action(flow, base, odp_actions);
+        commit_mpls_action(flow, base, odp_actions, false, false);
         mpls_done = true;
     }
     commit_set_nsh_action(flow, base, odp_actions, wc, use_masked);
@@ -8421,7 +8455,7 @@  commit_odp_actions(const struct flow *flow, struct flow *base,
     commit_set_port_action(flow, base, odp_actions, wc, use_masked);
     slow2 = commit_set_icmp_action(flow, base, odp_actions, wc);
     if (!mpls_done) {
-        commit_mpls_action(flow, base, odp_actions);
+        commit_mpls_action(flow, base, odp_actions, false, false);
     }
     commit_vlan_action(flow, base, odp_actions, wc);
     commit_set_priority_action(flow, base, odp_actions, wc, use_masked);
diff --git a/lib/ofp-actions.c b/lib/ofp-actions.c
index ddef3b0..fb392fe 100644
--- a/lib/ofp-actions.c
+++ b/lib/ofp-actions.c
@@ -4355,6 +4355,7 @@  decode_NXAST_RAW_ENCAP(const struct nx_action_encap *nae,
     switch (ntohl(nae->new_pkt_type)) {
     case PT_ETH:
     case PT_NSH:
+    case PT_MPLS:
         /* Add supported encap header types here. */
         break;
     default:
@@ -4405,6 +4406,8 @@  parse_encap_header(const char *hdr, ovs_be32 *packet_type)
         *packet_type = htonl(PT_ETH);
     } else if (strcmp(hdr, "nsh") == 0) {
         *packet_type = htonl(PT_NSH);
+    } else if (strcmp(hdr, "mpls") == 0) {
+        *packet_type = htonl(PT_MPLS);
     } else {
         return false;
     }
@@ -4486,6 +4489,8 @@  format_encap_pkt_type(const ovs_be32 pkt_type)
         return "ethernet";
     case PT_NSH:
         return "nsh";
+    case PT_MPLS:
+        return "mpls";
     default:
         return "UNKNOWN";
     }
diff --git a/lib/ofp-ed-props.c b/lib/ofp-ed-props.c
index 28382e0..50458e6 100644
--- a/lib/ofp-ed-props.c
+++ b/lib/ofp-ed-props.c
@@ -79,6 +79,27 @@  decode_ed_prop(const struct ofp_ed_prop_header **ofp_prop,
         }
         break;
     }
+    case OFPPPC_MPLS: {
+       switch (prop_type) {
+        case OFPPPT_PROP_MPLS_ETHERTYPE: {
+            struct ofp_ed_prop_mpls_ethertype *opnmt =
+                ALIGNED_CAST(struct ofp_ed_prop_mpls_ethertype *, *ofp_prop);
+            if (len > sizeof(*opnmt) || len > *remaining) {
+                return OFPERR_NXBAC_BAD_ED_PROP;
+            }
+            struct ofpact_ed_prop_mpls_ethertype *pnmt =
+                    ofpbuf_put_uninit(out, sizeof(*pnmt));
+            pnmt->header.prop_class = prop_class;
+            pnmt->header.type = prop_type;
+            pnmt->header.len = len;
+            pnmt->ether_type = opnmt->ether_type;
+            break;
+        }
+        default:
+            return OFPERR_NXBAC_UNKNOWN_ED_PROP;
+        }
+        break;
+    }
     default:
         return OFPERR_NXBAC_UNKNOWN_ED_PROP;
     }
@@ -133,6 +154,27 @@  encode_ed_prop(const struct ofpact_ed_prop **prop,
         }
         break;
     }
+    case OFPPPC_MPLS: {
+       switch ((*prop)->type) {
+       case OFPPPT_PROP_MPLS_ETHERTYPE: {
+           struct ofp_ed_prop_mpls_ethertype *pnmt =
+                ALIGNED_CAST(struct ofp_ed_prop_mpls_ethertype *, *prop);
+            struct ofpact_ed_prop_mpls_ethertype *opnmt =
+                    ofpbuf_put_uninit(out, sizeof(*opnmt));
+            opnmt->header.prop_class = htons((*prop)->prop_class);
+            opnmt->header.type = (*prop)->type;
+            opnmt->header.len =
+                    offsetof(struct ofpact_ed_prop_mpls_ethertype, pad);
+            opnmt->ether_type = pnmt->ether_type;
+            prop_len = sizeof(*pnmt);
+            break;
+
+       }
+       default:
+            return OFPERR_OFPBAC_BAD_ARGUMENT;
+       }
+       break;
+    }
     default:
         return OFPERR_OFPBAC_BAD_ARGUMENT;
     }
@@ -180,6 +222,11 @@  parse_ed_prop_type(uint16_t prop_class,
         } else {
             return false;
         }
+    case OFPPPC_MPLS:
+        if (!strcmp(str, "ether_type")) {
+            *type = OFPPPT_PROP_MPLS_ETHERTYPE;
+            return true;
+        }
     default:
         return false;
     }
@@ -253,11 +300,34 @@  parse_ed_prop_value(uint16_t prop_class, uint8_t prop_type OVS_UNUSED,
             }
             break;
         }
+
         default:
             /* Unsupported property types rejected before. */
             OVS_NOT_REACHED();
         }
-        break;
+       break;
+   case OFPPPC_MPLS:
+     switch (prop_type) {
+            case OFPPPT_PROP_MPLS_ETHERTYPE: {
+            uint16_t ethertype;
+            error = str_to_u16(value, "ether_type", &ethertype);
+            if (error != NULL) {
+                return error;
+            }
+            struct ofpact_ed_prop_mpls_ethertype *pnmt =
+                    ofpbuf_put_uninit(out, sizeof(*pnmt));
+            pnmt->header.prop_class = prop_class;
+            pnmt->header.type = prop_type;
+            pnmt->header.len =
+                    offsetof(struct ofpact_ed_prop_mpls_ethertype, pad);
+            pnmt->ether_type = ethertype;
+
+            break;
+            }
+            default:
+                break;
+      }
+      break;
     default:
         /* Unsupported property classes rejected before. */
         OVS_NOT_REACHED();
@@ -299,6 +369,14 @@  format_ed_prop_type(const struct ofpact_ed_prop *prop)
             OVS_NOT_REACHED();
         }
         break;
+    case OFPPPC_MPLS:
+         switch (prop->type) {
+         case OFPPPT_PROP_MPLS_ETHERTYPE:
+              return "ether_type";
+         default:
+               OVS_NOT_REACHED();
+         }
+         break;
     default:
         OVS_NOT_REACHED();
     }
@@ -331,6 +409,19 @@  format_ed_prop(struct ds *s OVS_UNUSED,
         default:
             OVS_NOT_REACHED();
         }
+     case OFPPPC_MPLS:
+        switch (prop->type) {
+        case OFPPPT_PROP_MPLS_ETHERTYPE: {
+          struct ofpact_ed_prop_mpls_ethertype *pnmt =
+                ALIGNED_CAST(struct ofpact_ed_prop_mpls_ethertype *, prop);
+            ds_put_format(s, "%s=%d", format_ed_prop_type(prop),
+                          pnmt->ether_type);
+            return;
+        }
+        default:
+            OVS_NOT_REACHED();
+        }
+
     default:
         OVS_NOT_REACHED();
     }
diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c
index 28a7fdd..f17f8b9 100644
--- a/ofproto/ofproto-dpif-xlate.c
+++ b/ofproto/ofproto-dpif-xlate.c
@@ -3938,7 +3938,6 @@  check_output_prerequisites(struct xlate_ctx *ctx,
             return false;
         }
     }
-
     if (xport->pt_mode == NETDEV_PT_LEGACY_L2 &&
         flow->packet_type != htonl(PT_ETH)) {
         xlate_report(ctx, OFT_WARN, "Trying to send non-Ethernet packet "
@@ -6235,6 +6234,48 @@  rewrite_flow_encap_ethernet(struct xlate_ctx *ctx,
         ctx->error = XLATE_UNSUPPORTED_PACKET_TYPE;
     }
 }
+static void
+rewrite_flow_encap_mpls(struct xlate_ctx *ctx,
+                        const struct ofpact_encap *encap,
+                        struct flow *flow,
+                        struct flow_wildcards *wc)
+{
+    int n;
+    uint32_t i;
+    uint16_t ether_type;
+    const char *ptr = (char *) encap->props;
+
+     for (i = 0; i < encap->n_props; i++) {
+        struct ofpact_ed_prop *prop_ptr =
+            ALIGNED_CAST(struct ofpact_ed_prop *, ptr);
+        if (prop_ptr->prop_class == OFPPPC_MPLS) {
+            switch (prop_ptr->type) {
+                case OFPPPT_PROP_MPLS_ETHERTYPE: {
+                     struct ofpact_ed_prop_mpls_ethertype *prop_ether_type =
+                        ALIGNED_CAST(struct ofpact_ed_prop_mpls_ethertype *,
+                                     prop_ptr);
+                    ether_type = prop_ether_type->ether_type;
+                    break;
+                 }
+            }
+        }
+     }
+
+    wc->masks.packet_type = OVS_BE32_MAX;
+    if ((flow->packet_type == htonl(PT_ETH)) ||
+        (flow->packet_type == htonl(PT_MPLS))) {
+        flow->packet_type = htonl(PT_MPLS);
+        n = flow_count_mpls_labels(flow, ctx->wc);
+        flow_push_mpls(flow, n, htons(ether_type), ctx->wc, true);
+    } else {
+        /* Error handling: drop packet. */
+        xlate_report_debug(ctx, OFT_ACTION,
+                           "Dropping packet as encap(ethernet) is not "
+                           "supported for packet type ethernet.");
+        ctx->error = XLATE_UNSUPPORTED_PACKET_TYPE;
+    }
+}
+
 
 /* For an MD2 NSH header returns a pointer to an ofpbuf with the encoded
  * MD2 TLVs provided as encap properties to the encap operation. This
@@ -6367,6 +6408,9 @@  xlate_generic_encap_action(struct xlate_ctx *ctx,
         case PT_NSH:
             encap_data = rewrite_flow_push_nsh(ctx, encap, flow, wc);
             break;
+        case PT_MPLS:
+            rewrite_flow_encap_mpls(ctx, encap,  flow, wc);
+            break;
         default:
             /* New packet type was checked during decoding. */
             OVS_NOT_REACHED();
@@ -6436,6 +6480,18 @@  xlate_generic_decap_action(struct xlate_ctx *ctx,
             ctx->pending_decap = true;
             /* Trigger recirculation. */
             return true;
+        case PT_MPLS: {
+             int n;
+             ovs_be16 ethertype;
+
+             flow->packet_type = decap->new_pkt_type;
+             ethertype = pt_ns_type_be(flow->packet_type);
+
+             n = flow_count_mpls_labels(flow, ctx->wc);
+             flow_pop_mpls(flow, n, ethertype, ctx->wc);
+             ctx->pending_decap = true;
+             return true;
+        }
         default:
             /* Error handling: drop packet. */
             xlate_report_debug(