diff --git a/lib/netdev-vport.c b/lib/netdev-vport.c
index 3f85386..a0a4da2 100644
--- a/lib/netdev-vport.c
+++ b/lib/netdev-vport.c
@@ -67,6 +67,12 @@ static struct vlog_rate_limit err_rl = VLOG_RATE_LIMIT_INIT(60, 5);
                             sizeof(struct udp_header) +         \
                             sizeof(struct genevehdr))
 
+#define VXNSH_HLEN   (sizeof(struct eth_header) +         \
+                      sizeof(struct ip_header)  +         \
+                      sizeof(struct udp_header) +         \
+                      sizeof(struct vxgpehdr)   +         \
+                      sizeof(struct nshhdr))
+
 #define DEFAULT_TTL 64
 
 struct netdev_vport {
@@ -1462,29 +1468,69 @@ netdev_vxlan_pop_header(struct dp_packet *packet)
 {
     struct pkt_metadata *md = &packet->md;
     struct flow_tnl *tnl = &md->tunnel;
-    struct vxlanhdr *vxh;
+    struct udp_header *udp;
 
     pkt_metadata_init_tnl(md);
     if (VXLAN_HLEN > dp_packet_size(packet)) {
         return EINVAL;
     }
 
-    vxh = udp_extract_tnl_md(packet, tnl);
-    if (!vxh) {
-        return EINVAL;
+    udp = ip_extract_tnl_md(packet, tnl);
+    if (!udp) {
+        return EINVAL;;
     }
 
-    if (get_16aligned_be32(&vxh->vx_flags) != htonl(VXLAN_FLAGS) ||
-       (get_16aligned_be32(&vxh->vx_vni) & htonl(0xff))) {
-        VLOG_WARN_RL(&err_rl, "invalid vxlan flags=%#x vni=%#x\n",
-                     ntohl(get_16aligned_be32(&vxh->vx_flags)),
-                     ntohl(get_16aligned_be32(&vxh->vx_vni)));
-        return EINVAL;
-    }
-    tnl->tun_id = htonll(ntohl(get_16aligned_be32(&vxh->vx_vni)) >> 8);
-    tnl->flags |= FLOW_TNL_F_KEY;
+    if (ntohs(udp->udp_dst) == VXGPE_DST_PORT) {
+
+        struct vxgpehdr *vxg = (struct vxgpehdr *) (udp + 1);
+
+        if (get_16aligned_be32(&vxg->vx_vni) & htonl(0xff)) {
+            VLOG_WARN_RL(&err_rl, "invalid vxlan-gpe vni=%#x\n",
+                         ntohl(get_16aligned_be32(&vxg->vx_vni)));
+            return EINVAL;;
+        }
+
+        tnl->tp_src = udp->udp_src;
+        tnl->tp_dst = udp->udp_dst;
+        tnl->tun_id = htonll(ntohl(get_16aligned_be32(&vxg->vx_vni)) >> 8);
+
+        if (vxg->p == 0x01 && vxg->proto == VXG_P_NSH) {
+            struct nshhdr *nsh = (struct nshhdr *) (vxg + 1);
+
+            tnl->nsp = nsh->b.b2 << 8;
+            tnl->nsi = nsh->b.svc_idx;
+            tnl->nshc1 = nsh->c.nshc1;
+            tnl->nshc2 = nsh->c.nshc2;
+            tnl->nshc3 = nsh->c.nshc3;
+            tnl->nshc4 = nsh->c.nshc4;
+            tnl->flags |= FLOW_TNL_F_NSP;
+            tnl->flags |= FLOW_TNL_F_NSI;
+            tnl->flags |= FLOW_TNL_F_NSH_C1 | FLOW_TNL_F_NSH_C2 | \
+                        FLOW_TNL_F_NSH_C3 | FLOW_TNL_F_NSH_C4;
+
+            dp_packet_reset_packet(packet, VXNSH_HLEN);
+        } else {
+            VLOG_WARN("Unsupported vxlan GPE + NSH format!");
+            return EINVAL;;
+        }
+
+    } else {
+
+        struct vxlanhdr *vxh = (struct vxlanhdr *) (udp + 1);
 
-    dp_packet_reset_packet(packet, VXLAN_HLEN);
+        if (get_16aligned_be32(&vxh->vx_flags) != htonl(VXLAN_FLAGS) ||
+               (get_16aligned_be32(&vxh->vx_vni) & htonl(0xff))) {
+            VLOG_WARN_RL(&err_rl, "invalid vxlan flags=%#x vni=%#x\n",
+                         ntohl(get_16aligned_be32(&vxh->vx_flags)),
+                         ntohl(get_16aligned_be32(&vxh->vx_vni)));
+            return EINVAL;;
+        }
+
+        tnl->tp_src = udp->udp_src;
+        tnl->tp_dst = udp->udp_dst;
+        tnl->tun_id = htonll(ntohl(get_16aligned_be32(&vxh->vx_vni)) >> 8);
+        dp_packet_reset_packet(packet, VXLAN_HLEN);
+    }
 
     return 0;
 }
@@ -1496,23 +1542,103 @@ netdev_vxlan_build_header(const struct netdev *netdev,
 {
     struct netdev_vport *dev = netdev_vport_cast(netdev);
     struct netdev_tunnel_config *tnl_cfg;
-    struct vxlanhdr *vxh;
+    struct ip_header *ip;
+    struct udp_header *udp;
+    bool isnsh = false;
 
     /* XXX: RCUfy tnl_cfg. */
     ovs_mutex_lock(&dev->mutex);
     tnl_cfg = &dev->tnl_cfg;
 
-    vxh = udp_build_header(tnl_cfg, tnl_flow, data);
+    ip = ip_hdr(data->header);
+    ip->ip_proto = IPPROTO_UDP;
+
+    udp = (struct udp_header *) (ip + 1);
+    udp->udp_dst = tnl_cfg->dst_port;
+
+    if (tnl_flow->tunnel.flags & FLOW_TNL_F_CSUM) {
+            /* Write a value in now to mark that we should compute the checksum
+             * later. 0xffff is handy because it is transparent to the
+             * calculation. */
+            udp->udp_csum = htons(0xffff);
+    }
+
+    if (ntohs(udp->udp_dst) == VXGPE_DST_PORT){
+        struct vxgpehdr *vxg = (struct vxgpehdr *) (udp + 1);
 
-    put_16aligned_be32(&vxh->vx_flags, htonl(VXLAN_FLAGS));
-    put_16aligned_be32(&vxh->vx_vni, htonl(ntohll(tnl_flow->tunnel.tun_id) << 8));
+        memset(vxg, 0, sizeof *vxg);
+        vxg->i = 0x01;
+        vxg->p = 0x01;
+        vxg->ver = 0x01;
+        vxg->proto = VXG_P_NSH;
+        put_16aligned_be32(&vxg->vx_vni, htonl(ntohll(tnl_flow->tunnel.tun_id) << 8));
+
+        if (vxg->p && vxg->proto == VXG_P_NSH){
+            struct nshhdr *nsh = (struct nshhdr *) (vxg + 1);
+
+            memset(nsh, 0, sizeof *nsh);
+            nsh->b.ver = 0x01;
+            nsh->b.len = 6;
+            nsh->b.mdtype = NSH_M_TYPE1;
+            nsh->b.proto = NSH_P_ETHERNET;
+
+            nsh->b.b2 = tnl_flow->tunnel.nsp >> 8;
+            nsh->b.svc_idx = tnl_flow->tunnel.nsi;
+
+            nsh->c.nshc1 = tnl_flow->tunnel.nshc1;
+            nsh->c.nshc2 = tnl_flow->tunnel.nshc2;
+            nsh->c.nshc3 = tnl_flow->tunnel.nshc3;
+            nsh->c.nshc4 = tnl_flow->tunnel.nshc4;
+
+            isnsh = true;
+        }
+
+    } else {
+        struct vxlanhdr *vxh = (struct vxlanhdr *) (udp + 1);
+        put_16aligned_be32(&vxh->vx_flags, htonl(VXLAN_FLAGS));
+        put_16aligned_be32(&vxh->vx_vni, htonl(ntohll(tnl_flow->tunnel.tun_id) << 8));
+    }
 
     ovs_mutex_unlock(&dev->mutex);
-    data->header_len = VXLAN_HLEN;
+
+    if(isnsh)
+        data->header_len = VXNSH_HLEN;
+    else
+        data->header_len = VXLAN_HLEN;
     data->tnl_type = OVS_VPORT_TYPE_VXLAN;
+
     return 0;
 }
 
+static void
+netdev_vxlan_push_header(struct dp_packet *packet,
+                         const struct ovs_action_push_tnl *data)
+{
+    int ip_tot_size;
+    int size = data->header_len;
+    const void *header = data->header;
+    struct udp_header *udp;
+
+    udp = push_ip_header(packet, header, size, &ip_tot_size);
+
+    /* set udp src port */
+    udp->udp_src = get_src_port(packet);
+    udp->udp_len = htons(ip_tot_size - sizeof (struct ip_header));
+    /* udp_csum is zero */
+
+    if (udp->udp_csum) {
+        uint32_t csum = packet_csum_pseudoheader(ip_hdr(dp_packet_data(packet)));
+
+        csum = csum_continue(csum, udp,
+                             ip_tot_size - sizeof (struct ip_header));
+        udp->udp_csum = csum_finish(csum);
+
+        if (!udp->udp_csum) {
+            udp->udp_csum = htons(0xffff);
+        }
+    }
+}
+
 static int
 netdev_geneve_pop_header(struct dp_packet *packet)
 {
@@ -1736,7 +1862,7 @@ netdev_vport_tunnel_register(void)
                                        netdev_gre_pop_header),
         TUNNEL_CLASS("ipsec_gre", "gre_sys", NULL, NULL, NULL),
         TUNNEL_CLASS("vxlan", "vxlan_sys", netdev_vxlan_build_header,
-                                           push_udp_header,
+                                           netdev_vxlan_push_header,
                                            netdev_vxlan_pop_header),
         TUNNEL_CLASS("lisp", "lisp_sys", NULL, NULL, NULL),
         TUNNEL_CLASS("stt", "stt_sys", NULL, NULL, NULL),
diff --git a/lib/odp-util.c b/lib/odp-util.c
index e8bc86d..1696f77 100644
--- a/lib/odp-util.c
+++ b/lib/odp-util.c
@@ -468,12 +468,42 @@ format_odp_tnl_push_header(struct ds *ds, struct ovs_action_push_tnl *data)
 
     if (data->tnl_type == OVS_VPORT_TYPE_VXLAN) {
         const struct vxlanhdr *vxh;
-
-        vxh = format_udp_tnl_push_header(ds, ip);
-
-        ds_put_format(ds, "vxlan(flags=0x%"PRIx32",vni=0x%"PRIx32")",
-                      ntohl(get_16aligned_be32(&vxh->vx_flags)),
-                      ntohl(get_16aligned_be32(&vxh->vx_vni)) >> 8);
+        const struct udp_header *udp;
+        const struct vxgpehdr *vxg;
+
+        /* UDP */
+        udp = (const struct udp_header *) (ip + 1);
+        ds_put_format(ds, "udp(src=%"PRIu16",dst=%"PRIu16",csum=0x%"PRIx16"),",
+              ntohs(udp->udp_src), ntohs(udp->udp_dst),
+              ntohs(udp->udp_csum));
+
+        /* VxLan & VxLan GPE(UDP port: 4790) */
+        if (ntohs(udp->udp_dst) == 4790) {
+            vxg = (const struct vxgpehdr *)   (udp + 1);
+
+            ds_put_format(ds, "vxlangpe(vni=0x%"PRIx32",",
+                          ntohl(get_16aligned_be32(&vxg->vx_vni)));
+            ds_put_format(ds, "proto=%"PRIu8"),", vxg->proto);
+            if (vxg->p == 0x01 && vxg->proto == VXG_P_NSH) {
+                const struct nshhdr *nsh = (struct nshhdr *) (vxg + 1);
+
+                /* NSH */
+                ds_put_format(ds, "nsh(mdtype=%"PRIu8",proto=%"PRIu8",",
+                              nsh->b.mdtype, nsh->b.proto);
+                ds_put_format(ds, "nsp=%"PRIx32",nsi=%"PRIu8",",
+                              nsh->b.b2 & 0x00FFFFFF, nsh->b.svc_idx);
+                ds_put_format(ds, "nshc1=%"PRIx32",nshc2=%"PRIx32",",
+                              ntohl(nsh->c.nshc1), ntohl(nsh->c.nshc2));
+                ds_put_format(ds, "nshc3=%"PRIx32",nshc4=%"PRIx32",",
+                              ntohl(nsh->c.nshc3), ntohl(nsh->c.nshc4));
+                ds_put_format(ds, ")");
+            }
+        } else {
+            vxh = (const struct vxlanhdr *)   (udp + 1);
+            ds_put_format(ds, "vxlan(flags=0x%"PRIx32",vni=0x%"PRIx32")",
+                          ntohl(get_16aligned_be32(&vxh->vx_flags)),
+                          ntohl(get_16aligned_be32(&vxh->vx_vni))>>8);
+        }
     } else if (data->tnl_type == OVS_VPORT_TYPE_GENEVE) {
         const struct genevehdr *gnh;
 
@@ -490,8 +520,8 @@ format_odp_tnl_push_header(struct ds *ds, struct ovs_action_push_tnl *data)
                                ds, false);
             ds_put_char(ds, ')');
         }
-
         ds_put_char(ds, ')');
+
     } else if (data->tnl_type == OVS_VPORT_TYPE_GRE) {
         const struct gre_base_hdr *greh;
         ovs_16aligned_be32 *options;
@@ -504,7 +534,7 @@ format_odp_tnl_push_header(struct ds *ds, struct ovs_action_push_tnl *data)
                            ntohs(greh->flags), ntohs(greh->protocol));
         options = (ovs_16aligned_be32 *)(greh + 1);
         if (greh->flags & htons(GRE_CSUM)) {
-            ds_put_format(ds, ",csum=0x%"PRIx16, ntohs(*((ovs_be16 *)options)));
+            ds_put_format(ds, ",csum=0x%"PRIx32, ntohl(get_16aligned_be32(options)));
             options++;
         }
         if (greh->flags & htons(GRE_KEY)) {
@@ -791,8 +821,10 @@ ovs_parse_tnl_push(const char *s, struct ovs_action_push_tnl *data)
     struct ip_header *ip;
     struct udp_header *udp;
     struct gre_base_hdr *greh;
+    struct nshhdr *nsh;
     uint16_t gre_proto, gre_flags, dl_type, udp_src, udp_dst, csum;
-    ovs_be32 sip, dip;
+    ovs_be32 sip, dip, nsp, nshc1,nshc2,nshc3,nshc4;
+    uint8_t nsi;
     uint32_t tnl_type = 0, header_len = 0;
     void *l3, *l4;
     int n = 0;
@@ -837,71 +869,108 @@ ovs_parse_tnl_push(const char *s, struct ovs_action_push_tnl *data)
     udp = (struct udp_header *) l4;
     greh = (struct gre_base_hdr *) l4;
     if (ovs_scan_len(s, &n, "udp(src=%"SCNi16",dst=%"SCNi16",csum=0x%"SCNx16"),",
-                         &udp_src, &udp_dst, &csum)) {
-        uint32_t vx_flags, vni;
+                     &udp_src, &udp_dst, &csum)) {
+        struct vxlanhdr *vxh;
+        struct vxgpehdr *vxg;
+        uint32_t vx_flags, vx_vni;
+        uint32_t geneve_vni;
 
         udp->udp_src = htons(udp_src);
         udp->udp_dst = htons(udp_dst);
         udp->udp_len = 0;
         udp->udp_csum = htons(csum);
 
+        vxh = (struct vxlanhdr *) (udp + 1);
+        vxg = (struct vxgpehdr *) (udp + 1);
+
         if (ovs_scan_len(s, &n, "vxlan(flags=0x%"SCNx32",vni=0x%"SCNx32"))",
-                            &vx_flags, &vni)) {
-            struct vxlanhdr *vxh = (struct vxlanhdr *) (udp + 1);
+                            &vx_flags, &vx_vni)) {
+            tnl_type = OVS_VPORT_TYPE_VXLAN;
 
             put_16aligned_be32(&vxh->vx_flags, htonl(vx_flags));
-            put_16aligned_be32(&vxh->vx_vni, htonl(vni << 8));
-            tnl_type = OVS_VPORT_TYPE_VXLAN;
+            put_16aligned_be32(&vxh->vx_vni, htonl(vx_vni<<8));
+
             header_len = sizeof *eth + sizeof *ip +
                          sizeof *udp + sizeof *vxh;
-        } else if (ovs_scan_len(s, &n, "geneve(")) {
-            struct genevehdr *gnh = (struct genevehdr *) (udp + 1);
 
-            memset(gnh, 0, sizeof *gnh);
-            header_len = sizeof *eth + sizeof *ip +
-                         sizeof *udp + sizeof *gnh;
+        } else if (ovs_scan_len(s, &n, "vxlangpe(vni=0x%"SCNx32",proto="SCNi8"),",
+                                   &vx_vni, &vxg->proto)) {
+            struct nshhdr *nsh = (struct nshhdr *) (vxg + 1);
 
-            if (ovs_scan_len(s, &n, "oam,")) {
-                gnh->oam = 1;
-            }
-            if (ovs_scan_len(s, &n, "crit,")) {
-                gnh->critical = 1;
-            }
-            if (!ovs_scan_len(s, &n, "vni=%"SCNi32, &vni)) {
+            tnl_type = OVS_VPORT_TYPE_VXLAN;
+            vxg->i = 0x01;
+            vxg->p = 0x01;
+            vxg->ver = 0x01;
+            put_16aligned_be32(&vxg->vx_vni, htonl(vx_vni));
+
+            if (ovs_scan_len(s, &n, "nsh(mdtype=%"SCNi8",proto=%"SCNi8",nsp=0x%"SCNx32
+                                ",nsi=%"SCNi8",nshc1=0x%"SCNx32",nshc2=0x%"SCNx32
+                                ",nshc3=0x%"SCNx32",nshc4=0x%"SCNx32"))",
+                                &nsh->b.mdtype, &nsh->b.proto,
+                                &nsp, &nsi,
+                                &nshc1, &nshc2,
+                                &nshc3, &nshc4)) {
+                nsh->b.ver = 0x01;
+                nsh->b.len = 6;
+                nsh->b.b2 = nsp;
+                nsh->b.svc_idx = nsi;
+                nsh->c.nshc1=nshc1;
+                nsh->c.nshc2=nshc2;
+                nsh->c.nshc3=nshc3;
+                nsh->c.nshc4=nshc4;
+                header_len = sizeof *eth + sizeof *ip +
+                             sizeof *udp + sizeof *vxh + sizeof *nsh;
+            } else {
                 return -EINVAL;
             }
-            if (ovs_scan_len(s, &n, ",options(")) {
-                struct geneve_scan options;
-                int len;
-
-                memset(&options, 0, sizeof options);
-                len = scan_geneve(s + n, &options, NULL);
-                if (!len) {
-                    return -EINVAL;
-                }
+        } else if (ovs_scan_len(s, &n, "geneve(")) {
+            struct genevehdr *gnh = (struct genevehdr *) (udp + 1);
 
-                memcpy(gnh->options, options.d, options.len);
-                gnh->opt_len = options.len / 4;
-                header_len += options.len;
+        memset(gnh, 0, sizeof *gnh);
+        header_len = sizeof *eth + sizeof *ip +
+                     sizeof *udp + sizeof *gnh;
 
-                n += len;
-            }
-            if (!ovs_scan_len(s, &n, "))")) {
+        if (ovs_scan_len(s, &n, "oam,")) {
+            gnh->oam = 1;
+        }
+        if (ovs_scan_len(s, &n, "crit,")) {
+            gnh->critical = 1;
+        }
+        if (!ovs_scan_len(s, &n, "vni=%"SCNi32, &geneve_vni)) {
+            return -EINVAL;
+        }
+        if (ovs_scan_len(s, &n, ",options(")) {
+            struct geneve_scan options;
+            int len;
+
+            memset(&options, 0, sizeof options);
+            len = scan_geneve(s + n, &options, NULL);
+            if (!len) {
                 return -EINVAL;
             }
 
-            gnh->proto_type = htons(ETH_TYPE_TEB);
-            put_16aligned_be32(&gnh->vni, htonl(vni << 8));
-            tnl_type = OVS_VPORT_TYPE_GENEVE;
-        } else {
+            memcpy(gnh->options, options.d, options.len);
+            gnh->opt_len = options.len / 4;
+            header_len += options.len;
+
+            n += len;
+        }
+        if (!ovs_scan_len(s, &n, "))")) {
             return -EINVAL;
         }
-    } else if (ovs_scan_len(s, &n, "gre((flags=0x%"SCNx16",proto=0x%"SCNx16")",
-                         &gre_flags, &gre_proto)){
 
-        tnl_type = OVS_VPORT_TYPE_GRE;
-        greh->flags = htons(gre_flags);
-        greh->protocol = htons(gre_proto);
+        gnh->proto_type = htons(ETH_TYPE_TEB);
+        put_16aligned_be32(&gnh->vni, htonl(geneve_vni << 8));
+        tnl_type = OVS_VPORT_TYPE_GENEVE;
+    } else {
+        return -EINVAL;
+    }
+} else if (ovs_scan_len(s, &n, "gre((flags=0x%"SCNx16",proto=0x%"SCNx16")",
+                     &gre_flags, &gre_proto)){
+
+         tnl_type = OVS_VPORT_TYPE_GRE;
+         greh->flags = htons(gre_flags);
+         greh->protocol = htons(gre_proto);
         ovs_16aligned_be32 *options = (ovs_16aligned_be32 *) (greh + 1);
 
         if (greh->flags & htons(GRE_CSUM)) {
@@ -941,7 +1010,7 @@ ovs_parse_tnl_push(const char *s, struct ovs_action_push_tnl *data)
                      ((uint8_t *) options - (uint8_t *) greh);
     } else {
         return -EINVAL;
-    }
+       }
 
     /* check tunnel meta data. */
     if (data->tnl_type != tnl_type) {
@@ -1120,6 +1189,7 @@ parse_odp_action(const char *s, const struct simap *port_names,
         struct ovs_action_push_tnl data;
         int n;
 
+        memset(&data, 0, sizeof data);
         n = ovs_parse_tnl_push(s, &data);
         if (n > 0) {
             odp_put_tnl_push_action(actions, &data);
@@ -3285,7 +3355,6 @@ parse_odp_key_mask_attr(const char *s, const struct simap *port_names,
         SCAN_FIELD_NESTED_FUNC("flags(", uint16_t, tun_flags, tun_flags_to_attr);
     } SCAN_END_NESTED();
 
-
     SCAN_SINGLE_PORT("in_port(", uint32_t, OVS_KEY_ATTR_IN_PORT);
 
     SCAN_BEGIN("eth(", struct ovs_key_ethernet) {
diff --git a/lib/packets.h b/lib/packets.h
index 12f2239..7f9ab98 100644
--- a/lib/packets.h
+++ b/lib/packets.h
@@ -33,7 +33,6 @@
 struct dp_packet;
 struct ds;
 
-/* Tunnel information used in flow key and metadata. */
 struct flow_tnl {
     ovs_be32 ip_dst;
     ovs_be32 ip_src;
@@ -913,6 +912,120 @@ struct vxlanhdr {
 /* VXLAN GPE UDP DST PORT */
 #define VXGPE_DST_PORT 4790
 
+/**
+ * struct vxlan_gpehdr - Generic Protocol Extension for VXLAN header.
+ * @p: Next Protocol field indicator bit
+ * @o: Operations and Management Packet indicator bit.
+ * @proto: IEEE Ethertypes to indicate the frame within.
+ * @vni: VXLAN Network Identifier.
+ */
+struct vxgpehdr {
+#ifdef WORDS_BIGENDIAN
+    uint8_t    res1:4;
+    uint8_t    i:1;
+    uint8_t    p:1;
+    uint8_t    res2:1;
+    uint8_t    o:1;
+
+    uint8_t    ver:2;
+    uint8_t    res3:6;
+#else
+    uint8_t    o:1;
+    uint8_t    res2:1;
+    uint8_t    p:1;
+    uint8_t    i:1;
+    uint8_t    res1:4;
+
+    uint8_t    res3:6;
+    uint8_t    ver:2;
+#endif
+    uint8_t    res4;
+    uint8_t    proto;
+    ovs_16aligned_be32 vx_vni;
+};
+
+/* VxLAN-GPE Header Next Protocol */
+#define VXG_P_IPV4        0x01
+#define VXG_P_IPV6        0x02
+#define VXG_P_ETHERNET    0x03
+#define VXG_P_NSH        0x04
+
+/**
+ * struct nsh_bhdr - Network Service Base Header.
+ * @o: Operations and Management Packet indicator bit
+ * @c: If this bit is set then one or more contexts are in use.
+ * @proto: IEEE Ethertypes to indicate the frame within.
+ * @svc_idx: TTL functionality and location within service path.
+ * @svc_path: To uniquely identify service path.
+ */
+struct nsh_base {
+#ifdef WORDS_BIGENDIAN
+    uint8_t    ver:2;
+    uint8_t    o:1;
+    uint8_t    c:1;
+    uint8_t    res1:4;
+
+    uint8_t    res2:2;
+    uint8_t    len:6;
+#else
+    uint8_t    res1:4;
+    uint8_t    c:1;
+    uint8_t    o:1;
+    uint8_t    ver:2;
+
+    uint8_t    len:6;
+    uint8_t    res2:2;
+#endif
+    uint8_t    mdtype;
+    uint8_t    proto;
+    union {
+        struct {
+            uint8_t    svc_path[3];
+            uint8_t    svc_idx;
+        };
+        ovs_be32 b2;
+    };
+};
+
+/**
+ * struct nsh_ctx - Keeps track of NSH context data
+ * @npc: NSH network platform context
+ * @nsc: NSH network shared context
+ * @spc: NSH service platform context
+ * @ssc: NSH service shared context
+ */
+struct nsh_ctx {
+    ovs_be32 nshc1;
+    ovs_be32 nshc2;
+    ovs_be32 nshc3;
+    ovs_be32 nshc4;
+};
+
+/**
+ * struct nshdr - Network Service header
+ * @nsh_base: Network Service Base Header.
+ * @nsh_ctx: Network Service Context Header.
+ */
+struct nshhdr {
+    struct nsh_base b;
+    struct nsh_ctx c;
+};
+
+/* NSH Base Header Next Protocol */
+#define NSH_P_IPV4        0x01
+#define NSH_P_IPV6        0x02
+#define NSH_P_ETHERNET    0x03
+
+/* MD Type Registry */
+#define NSH_M_TYPE1     0x01
+#define NSH_M_TYPE2     0x02
+#define NSH_M_EXP1      0xFE
+#define NSH_M_EXP2      0xFF
+
+/* Used for masking nsp and nsi values in field nsp below */
+#define NSH_M_NSP    0xFFFFFF00 //uncertain
+#define NSH_M_NSI    0x000000FF
+
 #define VXLAN_FLAGS 0x08000000  /* struct vxlanhdr.vx_flags required value. */
 
 void format_ipv6_addr(char *addr_str, const struct in6_addr *addr);
diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c
index 4bb9801..9c64c24 100644
--- a/ofproto/ofproto-dpif-xlate.c
+++ b/ofproto/ofproto-dpif-xlate.c
@@ -4780,7 +4780,6 @@ xlate_actions(struct xlate_in *xin, struct xlate_out *xout)
     if (!xbridge) {
         return;
     }
-
     struct flow *flow = &xin->flow;
 
     union mf_subvalue stack_stub[1024 / sizeof(union mf_subvalue)];
diff --git a/tests/tunnel.at b/tests/tunnel.at
index f43a07d..5ec5e6c 100644
--- a/tests/tunnel.at
+++ b/tests/tunnel.at
@@ -527,6 +527,124 @@ AT_CHECK([tail -1 stdout], [0],
 OVS_VSWITCHD_STOP(["/receive tunnel port not found/d"])
 AT_CLEANUP
 
+AT_SETUP([tunnel - VXLAN-GPE NSH user space])
+OVS_VSWITCHD_START([add-port br0 p1 -- set Interface p1 type=vxlan \
+                    options:remote_ip=1.1.1.1 ofport_request=1 options:dst_port=4790])
+
+AT_CHECK([ovs-appctl dpif/show | tail -n +3], [0], [dnl
+		br0 65534/100: (dummy)
+		p1 1/4790: (vxlan: dst_port=4790, remote_ip=1.1.1.1)
+])
+OVS_VSWITCHD_STOP(["/The Open vSwitch kernel module is probably not loaded/d"])
+AT_CLEANUP
+
+AT_SETUP([tunnel VXLAN-GPE NSH - encap - nsh/nsi/nshc user space])
+OVS_VSWITCHD_START([add-port br0 p1 -- set Interface p1 type=vxlan options:key=flow \
+        options:remote_ip=1.1.1.1 options:dst_port=4790 ofport_request=1 \
+    -- add-port br0 p2 -- set Interface p2 type=vxlan options:key=flow \
+        options:remote_ip=flow options:dst_port=4790 ofport_request=2 \
+    -- add-port br0 p3 -- set Interface p3 type=vxlan options:key=flow \
+        options:remote_ip=2.2.2.2 options:dst_port=4790 options:nsp=111 options:nsi=11 options:nshc1=11 options:nshc2=12 options:nshc3=13 options:nshc4=14 ofport_request=3 \
+    -- add-port br0 p4 -- set Interface p4 type=vxlan options:key=flow \
+        options:remote_ip=3.3.3.3 options:dst_port=4790 options:nsp=222 options:nsi=22 options:nshc1=flow options:nshc2=flow options:nshc3=flow options:nshc4=flow ofport_request=4 \
+    -- add-port br0 p5 -- set Interface p5 type=vxlan options:key=flow \
+        options:remote_ip=4.4.4.4 options:dst_port=4790 options:nsp=flow options:nsi=flow options:nshc1=flow options:nshc2=flow options:nshc3=flow options:nshc4=flow ofport_request=5 \
+    -- add-port br0 p6 -- set Interface p6 type=vxlan options:key=flow \
+        options:remote_ip=flow options:dst_port=4790 options:nsp=flow options:nsi=flow options:nshc1=flow options:nshc2=flow options:nshc3=flow options:nshc4=flow ofport_request=6])
+
+AT_CHECK([ovs-appctl netdev-dummy/ip4addr br0 2.2.2.22/24], [0], [OK
+])
+AT_CHECK([ovs-vsctl add-port br0 p7 -- set Interface p7 type=dummy ofport_request=7])
+AT_CHECK([ovs-vsctl add-port br0 p8 -- set Interface p8 type=dummy ofport_request=8])
+
+AT_CHECK([
+ovs-appctl ovs/route/add 1.1.1.1/24 br0
+ovs-appctl tnl/arp/set br0 1.1.1.1 68:05:ca:30:6b:d1
+ovs-appctl ovs/route/add 2.2.2.2/24 br0
+ovs-appctl tnl/arp/set br0 2.2.2.2 68:05:ca:30:6b:d2
+ovs-appctl ovs/route/add 3.3.3.3/24 br0
+ovs-appctl tnl/arp/set br0 3.3.3.3 68:05:ca:30:6b:d3
+ovs-appctl ovs/route/add 4.4.4.4/24 br0
+ovs-appctl tnl/arp/set br0 4.4.4.4 68:05:ca:30:6b:d4
+ovs-appctl ovs/route/add 5.5.5.5/24 br0
+ovs-appctl tnl/arp/set br0 5.5.5.5 68:05:ca:30:6b:d5
+],[0],[stdout])
+
+AT_DATA([flows.txt], [dnl
+in_port=7  actions=resubmit:1,resubmit:2,resubmit:3
+in_port=1 actions=output:1
+in_port=2 actions=set_field:3.3.3.3->tun_dst,output:2
+in_port=3 actions=output:3
+])
+AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
+AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(7),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=1,tos=0,ttl=128,frag=no),      icmp(type=8,code=0)'], [0], [stdout])
+AT_CHECK([tail -1 stdout], [0],
+  [Datapath actions: tnl_push(tnl_port(4790),header(size=74,type=4,eth(dst=68:05:ca:30:6b:d1,src=aa:55:aa:55:00:00,dl_type=0x0800),ipv4(src=2.2.2.22,dst=1.1.1.1,proto=17,tos=0,ttl=64,frag=0x40),udp(src=0,dst=4790,csum=0x0),vxlangpe(vni=0x0,proto=4),nsh(mdtype=1,proto=3,nsp=0,nsi=1,nshc1=0,nshc2=0,nshc3=0,nshc4=0,)),out_port(100)),tnl_push(tnl_port(4790),header(size=74,type=4,eth(dst=68:05:ca:30:6b:d3,src=aa:55:aa:55:00:00,dl_type=0x0800),ipv4(src=2.2.2.22,dst=3.3.3.3,proto=17,tos=0,ttl=64,frag=0x40),udp(src=0,dst=4790,csum=0x0),vxlangpe(vni=0x0,proto=4),nsh(mdtype=1,proto=3,nsp=0,nsi=1,nshc1=0,nshc2=0,nshc3=0,nshc4=0,)),out_port(100)),tnl_push(tnl_port(4790),header(size=74,type=4,eth(dst=68:05:ca:30:6b:d2,src=aa:55:aa:55:00:00,dl_type=0x0800),ipv4(src=2.2.2.22,dst=2.2.2.2,proto=17,tos=0,ttl=64,frag=0x40),udp(src=0,dst=4790,csum=0x0),vxlangpe(vni=0x0,proto=4),nsh(mdtype=1,proto=3,nsp=6f0000,nsi=11,nshc1=b,nshc2=c,nshc3=d,nshc4=e,)),out_port(100))
+])
+
+AT_DATA([flows.txt], [dnl
+in_port=8  actions=resubmit:4,resubmit:5,resubmit:6
+in_port=4 actions=set_nshc1:22,set_nshc2:23,set_nshc3:24,set_nshc4:25,output:4
+in_port=5 actions=set_nsp:333,set_nsi:33,set_nshc1:33,set_nshc2:34,set_nshc3:35,set_nshc4:36,output:5
+in_port=6 actions=set_field:5.5.5.5->tun_dst,set_nsp:444,set_nsi:44,set_nshc1:44,set_nshc2:45,set_nshc3:46,set_nshc4:47,output:6
+])
+AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
+AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(8),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=1,tos=0,ttl=128,frag=no),      icmp(type=8,code=0)'], [0], [stdout])
+AT_CHECK([tail -1 stdout], [0],
+  [Datapath actions: tnl_push(tnl_port(4790),header(size=74,type=4,eth(dst=68:05:ca:30:6b:d3,src=aa:55:aa:55:00:00,dl_type=0x0800),ipv4(src=2.2.2.22,dst=3.3.3.3,proto=17,tos=0,ttl=64,frag=0x40),udp(src=0,dst=4790,csum=0x0),vxlangpe(vni=0x0,proto=4),nsh(mdtype=1,proto=3,nsp=de0000,nsi=22,nshc1=16,nshc2=17,nshc3=18,nshc4=19,)),out_port(100)),tnl_push(tnl_port(4790),header(size=74,type=4,eth(dst=68:05:ca:30:6b:d4,src=aa:55:aa:55:00:00,dl_type=0x0800),ipv4(src=2.2.2.22,dst=4.4.4.4,proto=17,tos=0,ttl=64,frag=0x40),udp(src=0,dst=4790,csum=0x0),vxlangpe(vni=0x0,proto=4),nsh(mdtype=1,proto=3,nsp=4d0100,nsi=33,nshc1=21,nshc2=22,nshc3=23,nshc4=24,)),out_port(100)),tnl_push(tnl_port(4790),header(size=74,type=4,eth(dst=68:05:ca:30:6b:d5,src=aa:55:aa:55:00:00,dl_type=0x0800),ipv4(src=2.2.2.22,dst=5.5.5.5,proto=17,tos=0,ttl=64,frag=0x40),udp(src=0,dst=4790,csum=0x0),vxlangpe(vni=0x0,proto=4),nsh(mdtype=1,proto=3,nsp=bc0100,nsi=44,nshc1=2c,nshc2=2d,nshc3=2e,nshc4=2f,)),out_port(100))
+])
+OVS_VSWITCHD_STOP(["/The Open vSwitch kernel module is probably not loaded/d"])
+AT_CLEANUP
+
+AT_SETUP([tunnel VXLAN-GPE NSH - decap - nsh/nsi/nshc user space])
+OVS_VSWITCHD_START([add-port br0 p0 -- set Interface p0 type=dummy ofport_request=1 other-config:hwaddr=aa:55:aa:55:00:00])
+AT_CHECK([ovs-vsctl add-br int-br -- set bridge int-br datapath_type=dummy], [0])
+AT_CHECK([ovs-vsctl add-port int-br p1 -- set Interface p1 type=vxlan options:key=flow \
+        options:remote_ip=1.1.1.1 options:dst_port=4790 options:nsp=111 options:nsi=11 options:nshc1=11 options:nshc2=12 options:nshc3=13 options:nshc4=14 ofport_request=2 \
+    -- add-port int-br p2 -- set Interface p2 type=vxlan options:key=flow \
+        options:remote_ip=2.2.2.2 options:dst_port=4790 options:nsp=flow options:nsi=flow options:nshc1=flow options:nshc2=flow options:nshc3=flow options:nshc4=flow ofport_request=3 \
+    -- add-port int-br p3 -- set Interface p3 type=vxlan options:key=flow \
+        options:remote_ip=flow options:dst_port=4790 options:nsp=flow options:nsi=flow options:nshc1=flow options:nshc2=flow options:nshc3=flow options:nshc4=flow ofport_request=4], [0])
+
+AT_CHECK([ovs-appctl netdev-dummy/ip4addr br0 2.2.2.22/24], [0], [OK
+])
+AT_CHECK([ovs-appctl ovs/route/add 1.1.1.1/24 br0], [0], [OK
+])
+AT_CHECK([ovs-ofctl add-flow br0 action=normal])
+
+AT_CHECK([ovs-appctl dpif/show | tail -n +3], [0], [dnl
+		br0 65534/100: (dummy)
+		p0 1/1: (dummy)
+	int-br:
+		int-br 65534/2: (dummy)
+		p1 2/4790: (vxlan: dst_port=4790, key=flow, nshc1=0xb, nshc2=0xc, nshc3=0xd, nshc4=0xe, nsi=11, nsp=0x6f, remote_ip=1.1.1.1)
+		p2 3/4790: (vxlan: dst_port=4790, key=flow, nshc1=flow, nshc2=flow, nshc3=flow, nshc4=flow, nsi=flow, nsp=flow, remote_ip=2.2.2.2)
+		p3 4/4790: (vxlan: dst_port=4790, key=flow, nshc1=flow, nshc2=flow, nshc3=flow, nshc4=flow, nsi=flow, nsp=flow, remote_ip=flow)
+])
+
+AT_CHECK([ovs-appctl tnl/ports/show |sort], [0], [dnl
+Listening ports:
+vxlan_sys_4790 (4790)
+])
+
+AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(1),eth(src=50:54:00:00:00:05,dst=aa:55:aa:55:00:00),eth_type(0x0800),ipv4(src=1.1.1.1,dst=2.2.2.22,proto=17,tos=0,ttl=64,frag=no),udp(src=51283,dst=4790)'], [0], [stdout])
+AT_CHECK([tail -1 stdout], [0],
+  [Datapath actions: tnl_pop(4790)
+])
+
+AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(1),eth(src=50:54:00:00:00:05,dst=aa:55:aa:55:00:00),eth_type(0x0800),ipv4(src=2.2.2.2,dst=2.2.2.22,proto=17,tos=0,ttl=64,frag=no),udp(src=51283,dst=4790)'], [0], [stdout])
+AT_CHECK([tail -1 stdout], [0],
+  [Datapath actions: tnl_pop(4790)
+])
+
+AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(1),eth(src=50:54:00:00:00:05,dst=aa:55:aa:55:00:00),eth_type(0x0800),ipv4(src=3.4.5.6,dst=2.2.2.22,proto=17,tos=0,ttl=64,frag=no),udp(src=51283,dst=4790)'], [0], [stdout])
+AT_CHECK([tail -1 stdout], [0],
+  [Datapath actions: tnl_pop(4790)
+])
+
+OVS_VSWITCHD_STOP(["/The Open vSwitch kernel module is probably not loaded/d"])
+AT_CLEANUP
+
 AT_SETUP([tunnel - Geneve metadata])
 OVS_VSWITCHD_START([add-port br0 p1 -- set Interface p1 type=geneve \
                     options:remote_ip=1.1.1.1 ofport_request=1 \
