NSH service path (nsp) can be set/unset while creating the port
as well nsp can be matched on incoming packets.

Signed-off-by: pritesh <pritesh.koth...@cisco.com>

diff --git a/lib/flow.c b/lib/flow.c
index 9ab1961..452f338 100644
--- a/lib/flow.c
+++ b/lib/flow.c
@@ -543,6 +543,8 @@ flow_tun_flag_to_string(uint32_t flags)
         return "csum";
     case FLOW_TNL_F_KEY:
         return "key";
+    case FLOW_TNL_F_NSP:
+        return "nsp";
     default:
         return NULL;
     }
diff --git a/lib/flow.h b/lib/flow.h
index 75d95e8..e59c7bd 100644
--- a/lib/flow.h
+++ b/lib/flow.h
@@ -56,11 +56,13 @@ BUILD_ASSERT_DECL(FLOW_NW_FRAG_LATER == NX_IP_FRAG_LATER);
 #define FLOW_TNL_F_DONT_FRAGMENT (1 << 0)
 #define FLOW_TNL_F_CSUM (1 << 1)
 #define FLOW_TNL_F_KEY (1 << 2)
+#define FLOW_TNL_F_NSP (1 << 3)
 
 const char *flow_tun_flag_to_string(uint32_t flags);
 
 struct flow_tnl {
     ovs_be64 tun_id;
+    ovs_be32 nsp;
     ovs_be32 ip_src;
     ovs_be32 ip_dst;
     uint16_t flags;
diff --git a/lib/match.c b/lib/match.c
index 03413fa..6ebe2f3 100644
--- a/lib/match.c
+++ b/lib/match.c
@@ -74,6 +74,9 @@ match_wc_init(struct match *match, const struct flow *flow)
         if (flow->tunnel.flags & FLOW_TNL_F_KEY) {
             memset(&wc->masks.tunnel.tun_id, 0xff, sizeof 
wc->masks.tunnel.tun_id);
         }
+        if (flow->tunnel.flags & FLOW_TNL_F_NSP) {
+            memset(&wc->masks.tunnel.nsp, 0xff, sizeof wc->masks.tunnel.nsp);
+        }
         memset(&wc->masks.tunnel.ip_src, 0xff, sizeof wc->masks.tunnel.ip_src);
         memset(&wc->masks.tunnel.ip_dst, 0xff, sizeof wc->masks.tunnel.ip_dst);
         memset(&wc->masks.tunnel.flags, 0xff, sizeof wc->masks.tunnel.flags);
@@ -83,6 +86,10 @@ match_wc_init(struct match *match, const struct flow *flow)
         memset(&wc->masks.tunnel.tun_id, 0xff, sizeof wc->masks.tunnel.tun_id);
     }
 
+    if (flow->tunnel.nsp) {
+        memset(&wc->masks.tunnel.nsp, 0xff, sizeof wc->masks.tunnel.nsp);
+    }
+
     memset(&wc->masks.metadata, 0xff, sizeof wc->masks.metadata);
     memset(&wc->masks.in_port, 0xff, sizeof wc->masks.in_port);
     memset(&wc->masks.vlan_tci, 0xff, sizeof wc->masks.vlan_tci);
@@ -721,6 +728,19 @@ match_set_nd_target_masked(struct match *match,
     match->wc.masks.nd_target = *mask;
 }
 
+void
+match_set_nsp_masked(struct match *match, ovs_be32 nsp, ovs_be32 mask)
+{
+    match->wc.masks.tunnel.nsp = mask;
+    match->flow.tunnel.nsp = nsp & mask;
+}
+
+void
+match_set_nsp(struct match *match, ovs_be32 nsp)
+{
+    match_set_nsp_masked(match, nsp, htonl(UINT32_MAX));
+}
+
 /* Returns true if 'a' and 'b' wildcard the same fields and have the same
  * values for fixed fields, otherwise false. */
 bool
@@ -807,6 +827,20 @@ format_flow_tunnel(struct ds *s, const struct match *match)
                       ntohll(wc->masks.tunnel.tun_id));
         break;
     }
+
+    switch (wc->masks.tunnel.nsp) {
+    case 0:
+        break;
+    case CONSTANT_HTONL(UINT32_MAX):
+        ds_put_format(s, "nsp=%#"PRIx32",", ntohl(tnl->nsp));
+        break;
+    default:
+        ds_put_format(s, "nsp=%#"PRIx32"/%#"PRIx32",",
+                      ntohl(tnl->nsp),
+                      ntohl(wc->masks.tunnel.nsp));
+        break;
+    }
+
     format_ip_netmask(s, "tun_src", tnl->ip_src, wc->masks.tunnel.ip_src);
     format_ip_netmask(s, "tun_dst", tnl->ip_dst, wc->masks.tunnel.ip_dst);
 
diff --git a/lib/match.h b/lib/match.h
index 7b104ee..dbe13f1 100644
--- a/lib/match.h
+++ b/lib/match.h
@@ -120,6 +120,8 @@ void match_set_ipv6_label_masked(struct match *, ovs_be32, 
ovs_be32);
 void match_set_nd_target(struct match *, const struct in6_addr *);
 void match_set_nd_target_masked(struct match *, const struct in6_addr *,
                                 const struct in6_addr *);
+void match_set_nsp(struct match *, ovs_be32 nsp);
+void match_set_nsp_masked(struct match *, ovs_be32 nsp, ovs_be32 mask);
 
 bool match_equal(const struct match *, const struct match *);
 uint32_t match_hash(const struct match *, uint32_t basis);
diff --git a/lib/meta-flow.c b/lib/meta-flow.c
index 3a31c29..1d175d5 100644
--- a/lib/meta-flow.c
+++ b/lib/meta-flow.c
@@ -694,7 +694,24 @@ static const struct mf_field mf_fields[MFF_N_IDS] = {
         OXM_OF_IPV6_ND_TLL, "OXM_OF_IPV6_ND_TLL",
         OFPUTIL_P_NXM_OXM_ANY,
         OFPUTIL_P_NXM_OXM_ANY,
-    }
+    },
+
+    /* ## ---- ## */
+    /* ## L"S" ## */
+    /* ## ---- ## */
+
+    {
+        MFF_NSP, "nsp", NULL,
+        sizeof(ovs_be32), 24,
+        MFM_FULLY,
+        MFS_HEXADECIMAL,
+        MFP_NONE,
+        false,
+        0, NULL,
+        0, NULL,
+        OFPUTIL_P_OF10_NXM_ANY,
+        OFPUTIL_P_OF10_NXM_ANY,
+    },
 };
 
 /* Maps an NXM or OXM header value to an mf_field. */
@@ -823,6 +840,8 @@ mf_is_all_wild(const struct mf_field *mf, const struct 
flow_wildcards *wc)
     case MFF_TUN_TTL:
     case MFF_TUN_FLAGS:
         return !wc->masks.tunnel.tun_id;
+    case MFF_NSP:
+        return !wc->masks.tunnel.nsp;
     case MFF_METADATA:
         return !wc->masks.metadata;
     case MFF_IN_PORT:
@@ -1069,6 +1088,7 @@ mf_is_value_valid(const struct mf_field *mf, const union 
mf_value *value)
     case MFF_ND_TARGET:
     case MFF_ND_SLL:
     case MFF_ND_TLL:
+    case MFF_NSP:
         return true;
 
     case MFF_IN_PORT_OXM: {
@@ -1296,6 +1316,10 @@ mf_get_value(const struct mf_field *mf, const struct 
flow *flow,
         value->ipv6 = flow->nd_target;
         break;
 
+    case MFF_NSP:
+        value->be32 = flow->tunnel.nsp;
+        break;
+
     case MFF_N_IDS:
     default:
         NOT_REACHED();
@@ -1488,6 +1512,10 @@ mf_set_value(const struct mf_field *mf,
         match_set_nd_target(match, &value->ipv6);
         break;
 
+    case MFF_NSP:
+        match_set_nsp(match, value->be32);
+        break;
+
     case MFF_N_IDS:
     default:
         NOT_REACHED();
@@ -1682,6 +1710,10 @@ mf_set_flow_value(const struct mf_field *mf,
         flow->nd_target = value->ipv6;
         break;
 
+    case MFF_NSP:
+        flow->tunnel.nsp = value->be32;
+        break;
+
     case MFF_N_IDS:
     default:
         NOT_REACHED();
@@ -1885,6 +1917,10 @@ mf_set_wild(const struct mf_field *mf, struct match 
*match)
         memset(&match->flow.nd_target, 0, sizeof match->flow.nd_target);
         break;
 
+    case MFF_NSP:
+        match_set_nsp_masked(match, htonl(0), htonl(0));
+        break;
+
     case MFF_N_IDS:
     default:
         NOT_REACHED();
@@ -2049,6 +2085,10 @@ mf_set(const struct mf_field *mf,
         match_set_tp_dst_masked(match, value->be16, mask->be16);
         break;
 
+    case MFF_NSP:
+        match_set_nsp_masked(match, value->be32, mask->be32);
+        break;
+
     case MFF_N_IDS:
     default:
         NOT_REACHED();
@@ -2168,6 +2208,7 @@ mf_random_value(const struct mf_field *mf, union mf_value 
*value)
     case MFF_ND_TARGET:
     case MFF_ND_SLL:
     case MFF_ND_TLL:
+    case MFF_NSP:
         break;
 
     case MFF_IN_PORT_OXM:
diff --git a/lib/meta-flow.h b/lib/meta-flow.h
index dd8b95d..4d1c3fb 100644
--- a/lib/meta-flow.h
+++ b/lib/meta-flow.h
@@ -136,6 +136,9 @@ enum mf_field_id {
     MFF_ND_SLL,                 /* mac */
     MFF_ND_TLL,                 /* mac */
 
+    /* Network Service Headers (NSH) Fields */
+    MFF_NSP,                    /* be32 */
+
     MFF_N_IDS
 };
 
diff --git a/lib/netdev-vport.c b/lib/netdev-vport.c
index 0374ae3..181977c 100644
--- a/lib/netdev-vport.c
+++ b/lib/netdev-vport.c
@@ -322,6 +322,33 @@ parse_key(const struct smap *args, const char *name,
     }
 }
 
+static ovs_be32
+parse_nsp(const struct smap *args, const char *name,
+          bool *present, bool *flow)
+{
+    const char *s;
+
+    *present = false;
+    *flow = false;
+
+    s = smap_get(args, name);
+    if (!s) {
+        s = smap_get(args, "nsp");
+        if (!s) {
+            return 0;
+        }
+    }
+
+    *present = true;
+
+    if (!strcmp(s, "flow")) {
+        *flow = true;
+        return 0;
+    } else {
+        return htonl(strtoul(s, NULL, 0));
+    }
+}
+
 static int
 set_tunnel_config(struct netdev *dev_, const struct smap *args)
 {
@@ -425,6 +452,10 @@ set_tunnel_config(struct netdev *dev_, const struct smap 
*args)
                    !strcmp(node->key, "in_key") ||
                    !strcmp(node->key, "out_key")) {
             /* Handled separately below. */
+        } else if (!strcmp(node->key, "nsp") ||
+                   !strcmp(node->key, "in_nsp") ||
+                   !strcmp(node->key, "out_nsp")) {
+            /* Handled separately below. */
         } else {
             VLOG_WARN("%s: unknown %s argument '%s'", name, type, node->key);
         }
@@ -493,6 +524,14 @@ set_tunnel_config(struct netdev *dev_, const struct smap 
*args)
                                &tnl_cfg.out_key_present,
                                &tnl_cfg.out_key_flow);
 
+    tnl_cfg.in_nsp = parse_nsp(args, "in_nsp",
+                               &tnl_cfg.in_nsp_present,
+                               &tnl_cfg.in_nsp_flow);
+
+    tnl_cfg.out_nsp = parse_nsp(args, "out_nsp",
+                                &tnl_cfg.out_nsp_present,
+                                &tnl_cfg.out_nsp_flow);
+
     ovs_mutex_lock(&dev->mutex);
     dev->tnl_cfg = tnl_cfg;
     netdev_vport_poll_notify(dev);
@@ -506,6 +545,7 @@ get_tunnel_config(const struct netdev *dev, struct smap 
*args)
 {
     struct netdev_vport *netdev = netdev_vport_cast(dev);
     struct netdev_tunnel_config tnl_cfg;
+    const char *type = netdev_get_type(dev);
 
     ovs_mutex_lock(&netdev->mutex);
     tnl_cfg = netdev->tnl_cfg;
@@ -544,6 +584,27 @@ get_tunnel_config(const struct netdev *dev, struct smap 
*args)
         }
     }
 
+    if (tnl_cfg.in_nsp_flow && tnl_cfg.out_nsp_flow) {
+        smap_add(args, "nsp", "flow");
+    } else if (tnl_cfg.in_nsp_present && tnl_cfg.out_nsp_present
+               && tnl_cfg.in_nsp == tnl_cfg.out_nsp) {
+        smap_add_format(args, "nsp", "%#"PRIx32, ntohl(tnl_cfg.in_nsp));
+    } else {
+        if (tnl_cfg.in_nsp_flow) {
+            smap_add(args, "in_nsp", "flow");
+        } else if (tnl_cfg.in_nsp_present) {
+            smap_add_format(args, "in_nsp", "%#"PRIx32,
+                            ntohl(tnl_cfg.in_nsp));
+        }
+
+        if (tnl_cfg.out_nsp_flow) {
+            smap_add(args, "out_nsp", "flow");
+        } else if (tnl_cfg.out_nsp_present) {
+            smap_add_format(args, "out_nsp", "%#"PRIx32,
+                            ntohl(tnl_cfg.out_nsp));
+        }
+    }
+
     if (tnl_cfg.ttl_inherit) {
         smap_add(args, "ttl", "inherit");
     } else if (tnl_cfg.ttl != DEFAULT_TTL) {
@@ -558,7 +619,6 @@ get_tunnel_config(const struct netdev *dev, struct smap 
*args)
 
     if (tnl_cfg.dst_port) {
         uint16_t dst_port = ntohs(tnl_cfg.dst_port);
-        const char *type = netdev_get_type(dev);
 
         if ((!strcmp("vxlan", type) && dst_port != VXLAN_DST_PORT) ||
             (!strcmp("lisp", type) && dst_port != LISP_DST_PORT)) {
diff --git a/lib/netdev.h b/lib/netdev.h
index bafa50e..36817f5 100644
--- a/lib/netdev.h
+++ b/lib/netdev.h
@@ -102,6 +102,14 @@ struct netdev_stats {
 
 /* Configuration specific to tunnels. */
 struct netdev_tunnel_config {
+    bool in_nsp_present;
+    bool in_nsp_flow;
+    ovs_be32 in_nsp;            /* incoming NSH service path */
+
+    bool out_nsp_present;
+    bool out_nsp_flow;
+    ovs_be32 out_nsp;           /* outgoing NSH service path */
+
     bool in_key_present;
     bool in_key_flow;
     ovs_be64 in_key;
diff --git a/lib/odp-util.c b/lib/odp-util.c
index 5ca8baf..379c49b 100644
--- a/lib/odp-util.c
+++ b/lib/odp-util.c
@@ -806,6 +806,7 @@ tunnel_key_attr_len(int type)
     case OVS_TUNNEL_KEY_ATTR_TTL: return 1;
     case OVS_TUNNEL_KEY_ATTR_DONT_FRAGMENT: return 0;
     case OVS_TUNNEL_KEY_ATTR_CSUM: return 0;
+    case OVS_TUNNEL_KEY_ATTR_NSP: return 4;
     case __OVS_TUNNEL_KEY_ATTR_MAX:
         return -1;
     }
@@ -853,6 +854,10 @@ odp_tun_key_from_attr(const struct nlattr *attr, struct 
flow_tnl *tun)
         case OVS_TUNNEL_KEY_ATTR_CSUM:
             tun->flags |= FLOW_TNL_F_CSUM;
             break;
+        case OVS_TUNNEL_KEY_ATTR_NSP:
+            tun->nsp = nl_attr_get_be32(a);
+            tun->flags |= FLOW_TNL_F_NSP;
+            break;
         default:
             /* Allow this to show up as unexpected, if there are unknown
              * tunnel attribute, eventually resulting in ODP_FIT_TOO_MUCH. */
@@ -896,6 +901,9 @@ tun_key_to_attr(struct ofpbuf *a, const struct flow_tnl 
*tun_key)
     if (tun_key->flags & FLOW_TNL_F_CSUM) {
         nl_msg_put_flag(a, OVS_TUNNEL_KEY_ATTR_CSUM);
     }
+    if (tun_key->flags & FLOW_TNL_F_NSP) {
+        nl_msg_put_be32(a, OVS_TUNNEL_KEY_ATTR_NSP, tun_key->nsp);
+    }
 
     nl_msg_end_nested(a, tun_key_ofs);
 }
@@ -922,6 +930,7 @@ odp_mask_attr_is_exact(const struct nlattr *ma)
         odp_tun_key_from_attr(ma, &tun_mask);
         if (tun_mask.flags == (FLOW_TNL_F_KEY
                                | FLOW_TNL_F_DONT_FRAGMENT
+                               | FLOW_TNL_F_NSP
                                | FLOW_TNL_F_CSUM)) {
             /* The flags are exact match, check the remaining fields. */
             tun_mask.flags = 0xffff;
@@ -1006,10 +1015,12 @@ format_odp_key_attr(const struct nlattr *a, const 
struct nlattr *ma,
             memset(&tun_mask, 0, sizeof tun_mask);
             odp_tun_key_from_attr(ma, &tun_mask);
             ds_put_format(ds, "tun_id=%#"PRIx64"/%#"PRIx64
+                          ",nsp=%#"PRIx32"/%#"PRIx32
                           ",src="IP_FMT"/"IP_FMT",dst="IP_FMT"/"IP_FMT
                           ",tos=%#"PRIx8"/%#"PRIx8",ttl=%"PRIu8"/%#"PRIx8
                           ",flags(",
                           ntohll(tun_key.tun_id), ntohll(tun_mask.tun_id),
+                          ntohl(tun_key.nsp), ntohl(tun_mask.nsp),
                           IP_ARGS(tun_key.ip_src), IP_ARGS(tun_mask.ip_src),
                           IP_ARGS(tun_key.ip_dst), IP_ARGS(tun_mask.ip_dst),
                           tun_key.ip_tos, tun_mask.ip_tos,
@@ -1025,9 +1036,11 @@ format_odp_key_attr(const struct nlattr *a, const struct 
nlattr *ma,
             */
             ds_put_char(ds, ')');
         } else {
-            ds_put_format(ds, "tun_id=0x%"PRIx64",src="IP_FMT",dst="IP_FMT","
+            ds_put_format(ds, "tun_id=0x%"PRIx64",nsp=0x%"PRIx32
+                          ",src="IP_FMT",dst="IP_FMT","
                           "tos=0x%"PRIx8",ttl=%"PRIu8",flags(",
                           ntohll(tun_key.tun_id),
+                          ntohl(tun_key.nsp),
                           IP_ARGS(tun_key.ip_src),
                           IP_ARGS(tun_key.ip_dst),
                           tun_key.ip_tos, tun_key.ip_ttl);
@@ -1568,12 +1581,15 @@ parse_odp_key_mask_attr(const char *s, const struct 
simap *port_names,
         int tos, tos_mask, ttl, ttl_mask;
         struct flow_tnl tun_key, tun_key_mask;
         unsigned long long tun_id_mask;
+        uint32_t nsp, nsp_mask;
         int n = -1;
 
         if (mask && sscanf(s, 
"tunnel(tun_id=%31[x0123456789abcdefABCDEF]/%llx,"
+                   "nsp=%"PRIx32"/%"PRIx32
                    "src="IP_SCAN_FMT"/"IP_SCAN_FMT",dst="IP_SCAN_FMT
                    "/"IP_SCAN_FMT",tos=%i/%i,ttl=%i/%i,flags%n",
                    tun_id_s, &tun_id_mask,
+                   &nsp, &nsp_mask,
                    IP_SCAN_ARGS(&tun_key.ip_src),
                    IP_SCAN_ARGS(&tun_key_mask.ip_src),
                    IP_SCAN_ARGS(&tun_key.ip_dst),
@@ -1585,6 +1601,8 @@ parse_odp_key_mask_attr(const char *s, const struct simap 
*port_names,
 
             tun_key.tun_id = htonll(strtoull(tun_id_s, NULL, 0));
             tun_key_mask.tun_id = htonll(tun_id_mask);
+            tun_key.nsp = htonl(nsp);
+            tun_key_mask.nsp = htonl(nsp_mask);
             tun_key.ip_tos = tos;
             tun_key_mask.ip_tos = tos_mask;
             tun_key.ip_ttl = ttl;
@@ -1607,8 +1625,10 @@ parse_odp_key_mask_attr(const char *s, const struct 
simap *port_names,
             }
             return n;
         } else if (sscanf(s, "tunnel(tun_id=%31[x0123456789abcdefABCDEF],"
+                   "nsp=%"PRIx32","
                    "src="IP_SCAN_FMT",dst="IP_SCAN_FMT
                    ",tos=%i,ttl=%i,flags%n", tun_id_s,
+                   &tun_key.nsp,
                     IP_SCAN_ARGS(&tun_key.ip_src),
                     IP_SCAN_ARGS(&tun_key.ip_dst), &tos, &ttl,
                     &n) > 0 && n > 0) {
@@ -1616,6 +1636,7 @@ parse_odp_key_mask_attr(const char *s, const struct simap 
*port_names,
             uint32_t flags;
 
             tun_key.tun_id = htonll(strtoull(tun_id_s, NULL, 0));
+            tun_key.nsp = htonl(tun_key.nsp);
             tun_key.ip_tos = tos;
             tun_key.ip_ttl = ttl;
             res = parse_flags(&s[n], flow_tun_flag_to_string, &flags);
diff --git a/lib/odp-util.h b/lib/odp-util.h
index 192cfa0..4642b17 100644
--- a/lib/odp-util.h
+++ b/lib/odp-util.h
@@ -64,6 +64,7 @@ int odp_actions_from_string(const char *, const struct simap 
*port_names,
  *  - OVS_TUNNEL_KEY_ATTR_TTL            1    3      4      8
  *  - OVS_TUNNEL_KEY_ATTR_DONT_FRAGMENT  0    --     4      4
  *  - OVS_TUNNEL_KEY_ATTR_CSUM           0    --     4      4
+ *  - OVS_TUNNEL_KEY_ATTR_NSP            4    --     4      8
  *  OVS_KEY_ATTR_IN_PORT                 4    --     4      8
  *  OVS_KEY_ATTR_SKB_MARK                4    --     4      8
  *  OVS_KEY_ATTR_ETHERNET               12    --     4     16
@@ -75,7 +76,7 @@ int odp_actions_from_string(const char *, const struct simap 
*port_names,
  *  OVS_KEY_ATTR_ICMPV6                  2     2     4      8
  *  OVS_KEY_ATTR_ND                     28    --     4     32
  *  ----------------------------------------------------------
- *  total                                                 208
+ *  total                                                 216
  *
  * We include some slack space in case the calculation isn't quite right or we
  * add another field and forget to adjust this value.
diff --git a/ofproto/tunnel.c b/ofproto/tunnel.c
index 7821315..35aa98b 100644
--- a/ofproto/tunnel.c
+++ b/ofproto/tunnel.c
@@ -36,11 +36,13 @@ VLOG_DEFINE_THIS_MODULE(tunnel);
 
 struct tnl_match {
     ovs_be64 in_key;
+    ovs_be32 in_nsp;
     ovs_be32 ip_src;
     ovs_be32 ip_dst;
     odp_port_t odp_port;
     uint32_t pkt_mark;
     bool in_key_flow;
+    bool in_nsp_flow;
     bool ip_src_flow;
     bool ip_dst_flow;
 };
@@ -100,12 +102,14 @@ tnl_port_add__(const struct ofport_dpif *ofport, const 
struct netdev *netdev,
     tnl_port->netdev_seq = netdev_change_seq(tnl_port->netdev);
 
     tnl_port->match.in_key = cfg->in_key;
+    tnl_port->match.in_nsp = cfg->in_nsp;
     tnl_port->match.ip_src = cfg->ip_src;
     tnl_port->match.ip_dst = cfg->ip_dst;
     tnl_port->match.ip_src_flow = cfg->ip_src_flow;
     tnl_port->match.ip_dst_flow = cfg->ip_dst_flow;
     tnl_port->match.pkt_mark = cfg->ipsec ? IPSEC_MARK : 0;
     tnl_port->match.in_key_flow = cfg->in_key_flow;
+    tnl_port->match.in_nsp_flow = cfg->in_nsp_flow;
     tnl_port->match.odp_port = odp_port;
 
     existing_port = tnl_find_exact(&tnl_port->match);
@@ -322,6 +326,10 @@ tnl_port_send(const struct ofport_dpif *ofport, struct 
flow *flow,
         flow->tunnel.tun_id = cfg->out_key;
     }
 
+    if (!cfg->out_nsp_flow) {
+        flow->tunnel.nsp = cfg->out_nsp;
+    }
+
     if (cfg->ttl_inherit && is_ip_any(flow)) {
         wc->masks.nw_ttl = 0xff;
         flow->tunnel.ip_ttl = flow->nw_ttl;
@@ -349,6 +357,7 @@ tnl_port_send(const struct ofport_dpif *ofport, struct flow 
*flow,
 
     flow->tunnel.flags = (cfg->dont_fragment ? FLOW_TNL_F_DONT_FRAGMENT : 0)
         | (cfg->csum ? FLOW_TNL_F_CSUM : 0)
+        | (cfg->out_nsp_present ? FLOW_TNL_F_NSP : 0)
         | (cfg->out_key_present ? FLOW_TNL_F_KEY : 0);
 
     if (pre_flow_str) {
@@ -418,16 +427,23 @@ tnl_find(const struct flow *flow) OVS_REQ_RDLOCK(rwlock)
     struct tnl_match_pattern {
         bool in_key_flow;
         bool ip_dst_flow;
+        bool in_nsp_flow;
         enum ip_src_type ip_src;
     };
 
     static const struct tnl_match_pattern patterns[] = {
-        { false, false, IP_SRC_EXACT }, /* remote_ip, local_ip, in_key. */
-        { false, false, IP_SRC_ANY },   /* remote_ip, in_key. */
-        { true,  false, IP_SRC_EXACT }, /* remote_ip, local_ip. */
-        { true,  false, IP_SRC_ANY },   /* remote_ip. */
-        { true,  true,  IP_SRC_ANY },   /* Flow-based remote. */
-        { true,  true,  IP_SRC_FLOW },  /* Flow-based everything. */
+        { false, false, false, IP_SRC_EXACT }, /* remote_ip, local_ip, in_key. 
*/
+        { false, false, false, IP_SRC_ANY },   /* remote_ip, in_key. */
+        { true,  false, false, IP_SRC_EXACT }, /* remote_ip, local_ip. */
+        { true,  false, false, IP_SRC_ANY },   /* remote_ip. */
+        { true,  true,  false, IP_SRC_ANY },   /* Flow-based remote. */
+        { true,  true,  false, IP_SRC_FLOW },  /* Flow-based everything. */
+        { false, false, true,  IP_SRC_EXACT }, /* remote_ip, local_ip, in_key. 
*/
+        { false, false, true,  IP_SRC_ANY },   /* remote_ip, in_key. */
+        { true,  false, true,  IP_SRC_EXACT }, /* remote_ip, local_ip. */
+        { true,  false, true,  IP_SRC_ANY },   /* remote_ip. */
+        { true,  true,  true,  IP_SRC_ANY },   /* Flow-based remote. */
+        { true,  true,  true,  IP_SRC_FLOW },  /* Flow-based everything. */
     };
 
     const struct tnl_match_pattern *p;
@@ -443,6 +459,9 @@ tnl_find(const struct flow *flow) OVS_REQ_RDLOCK(rwlock)
         match.in_key_flow = p->in_key_flow;
         match.in_key = p->in_key_flow ? 0 : flow->tunnel.tun_id;
 
+        match.in_nsp_flow = p->in_nsp_flow;
+        match.in_nsp = p->in_nsp_flow ? 0 : flow->tunnel.nsp;
+
         match.ip_dst_flow = p->ip_dst_flow;
         match.ip_dst = p->ip_dst_flow ? 0 : flow->tunnel.ip_src;
 
@@ -477,6 +496,12 @@ tnl_match_fmt(const struct tnl_match *match, struct ds *ds)
         ds_put_format(ds, ", key=%#"PRIx64, ntohll(match->in_key));
     }
 
+    if (match->in_nsp_flow) {
+        ds_put_cstr(ds, ", nsp=flow");
+    } else {
+        ds_put_format(ds, ", nsp=%#"PRIx32, ntohl(match->in_nsp));
+    }
+
     ds_put_format(ds, ", dp port=%"PRIu32, match->odp_port);
     ds_put_format(ds, ", pkt mark=%"PRIu32, match->pkt_mark);
 }
@@ -520,6 +545,19 @@ tnl_port_fmt(const struct tnl_port *tnl_port) 
OVS_REQ_RDLOCK(rwlock)
         }
     }
 
+    if (cfg->out_nsp != cfg->in_nsp ||
+        cfg->out_nsp_present != cfg->in_nsp_present ||
+        cfg->out_nsp_flow != cfg->in_nsp_flow) {
+        ds_put_cstr(&ds, ", out_nsp=");
+        if (!cfg->out_nsp_present) {
+            ds_put_cstr(&ds, "none");
+        } else if (cfg->out_nsp_flow) {
+            ds_put_cstr(&ds, "flow");
+        } else {
+            ds_put_format(&ds, "%#"PRIx32, ntohl(cfg->out_nsp));
+        }
+    }
+
     if (cfg->ttl_inherit) {
         ds_put_cstr(&ds, ", ttl=inherit");
     } else {
-- 
1.7.9.5

_______________________________________________
dev mailing list
dev@openvswitch.org
http://openvswitch.org/mailman/listinfo/dev

Reply via email to