[ovs-dev] [PATCH v2 5/7] nsh: userland support for network service index

Pritesh Kothari pritesh.kothari at cisco.com
Tue Feb 25 23:44:18 UTC 2014


From: pritesh <pritesh.kothari at cisco.com>

Support for nsh service index (nsi) is added, mainly incoming
nsi in a flow can be matched and appropriate action can be
taken on the flow based on it.

Signed-off-by: Pritesh Kothari <pritesh.kothari at cisco.com>

diff --git a/lib/flow.c b/lib/flow.c
index 28e96ec..e1b7d74 100644
--- a/lib/flow.c
+++ b/lib/flow.c
@@ -565,6 +565,8 @@ flow_tun_flag_to_string(uint32_t flags)
         return "key";
     case FLOW_TNL_F_NSP:
         return "nsp";
+    case FLOW_TNL_F_NSI:
+        return "nsi";
     default:
         return NULL;
     }
diff --git a/lib/flow.h b/lib/flow.h
index 6086904..8c03e75 100644
--- a/lib/flow.h
+++ b/lib/flow.h
@@ -57,6 +57,7 @@ BUILD_ASSERT_DECL(FLOW_NW_FRAG_LATER == NX_IP_FRAG_LATER);
 #define FLOW_TNL_F_CSUM (1 << 1)
 #define FLOW_TNL_F_KEY (1 << 2)
 #define FLOW_TNL_F_NSP (1 << 3)
+#define FLOW_TNL_F_NSI (1 << 4)
 
 const char *flow_tun_flag_to_string(uint32_t flags);
 
@@ -68,6 +69,7 @@ struct flow_tnl {
     uint16_t flags;
     uint8_t ip_tos;
     uint8_t ip_ttl;
+    uint8_t nsi;
 };
 
 /* Unfortunately, a "struct flow" sometimes has to handle OpenFlow port
diff --git a/lib/match.c b/lib/match.c
index 091ada5..fe24317 100644
--- a/lib/match.c
+++ b/lib/match.c
@@ -73,6 +73,9 @@ match_wc_init(struct match *match, const struct flow *flow)
         if (flow->tunnel.flags & FLOW_TNL_F_NSP) {
             memset(&wc->masks.tunnel.nsp, 0xff, sizeof wc->masks.tunnel.nsp);
         }
+        if (flow->tunnel.flags & FLOW_TNL_F_NSI) {
+            memset(&wc->masks.tunnel.nsi, 0xff, sizeof wc->masks.tunnel.nsi);
+        }
         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);
@@ -86,6 +89,10 @@ match_wc_init(struct match *match, const struct flow *flow)
         memset(&wc->masks.tunnel.nsp, 0xff, sizeof wc->masks.tunnel.nsp);
     }
 
+    if (flow->tunnel.nsi) {
+        memset(&wc->masks.tunnel.nsi, 0xff, sizeof wc->masks.tunnel.nsi);
+    }
+
     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);
@@ -771,6 +778,19 @@ match_set_nsp(struct match *match, ovs_be32 nsp)
     match_set_nsp_masked(match, nsp, htonl(UINT32_MAX));
 }
 
+void
+match_set_nsi_masked(struct match *match, uint8_t nsi, uint8_t mask)
+{
+    match->wc.masks.tunnel.nsi = mask;
+    match->flow.tunnel.nsi = nsi & mask;
+}
+
+void
+match_set_nsi(struct match *match, uint8_t nsi)
+{
+    match_set_nsi_masked(match, nsi, UINT8_MAX);
+}
+
 /* Returns true if 'a' and 'b' wildcard the same fields and have the same
  * values for fixed fields, otherwise false. */
 bool
@@ -888,6 +908,11 @@ format_flow_tunnel(struct ds *s, const struct match *match)
 
     format_be64_masked(s, "tun_id", tnl->tun_id, wc->masks.tunnel.tun_id);
     format_uint32_masked(s, "nsp", tnl->nsp, wc->masks.tunnel.nsp);
+
+    if (wc->masks.tunnel.nsi) {
+        ds_put_format(s, "nsi=%"PRIu8",", tnl->nsi);
+    }
+
     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 1c8dd15..b738d21 100644
--- a/lib/match.h
+++ b/lib/match.h
@@ -126,6 +126,8 @@ 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);
+void match_set_nsi_masked(struct match *match, uint8_t nsi, uint8_t mask);
+void match_set_nsi(struct match *match, uint8_t nsi);
 
 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 8b64de2..d9473ad 100644
--- a/lib/meta-flow.c
+++ b/lib/meta-flow.c
@@ -781,6 +781,18 @@ const struct mf_field mf_fields[MFF_N_IDS] = {
         OFPUTIL_P_NXM_OXM_ANY,
         OFPUTIL_P_NXM_OXM_ANY,
         -1,
+    }, {
+        MFF_NSI, "nsi", NULL,
+        MF_FIELD_SIZES(u8),
+        MFM_NONE,
+        MFS_DECIMAL,
+        MFP_NONE,
+        false,
+        0, NULL,
+        0, NULL,
+        OFPUTIL_P_NONE,
+        OFPUTIL_P_NONE,
+        -1,
     },
 };
 
@@ -908,6 +920,8 @@ mf_is_all_wild(const struct mf_field *mf, const struct flow_wildcards *wc)
         return !wc->masks.tunnel.tun_id;
     case MFF_NSP:
         return !wc->masks.tunnel.nsp;
+    case MFF_NSI:
+        return !wc->masks.tunnel.nsi;
     case MFF_METADATA:
         return !wc->masks.metadata;
     case MFF_IN_PORT:
@@ -1183,6 +1197,7 @@ mf_is_value_valid(const struct mf_field *mf, const union mf_value *value)
     case MFF_ND_SLL:
     case MFF_ND_TLL:
     case MFF_NSP:
+    case MFF_NSI:
         return true;
 
     case MFF_IN_PORT_OXM: {
@@ -1421,6 +1436,10 @@ mf_get_value(const struct mf_field *mf, const struct flow *flow,
         value->be32 = flow->tunnel.nsp;
         break;
 
+    case MFF_NSI:
+        value->u8 = flow->tunnel.nsi;
+        break;
+
     case MFF_N_IDS:
     default:
         OVS_NOT_REACHED();
@@ -1622,6 +1641,10 @@ mf_set_value(const struct mf_field *mf,
         match_set_nsp(match, value->be32);
         break;
 
+    case MFF_NSI:
+        match_set_nsi(match, value->u8);
+        break;
+
     case MFF_N_IDS:
     default:
         OVS_NOT_REACHED();
@@ -1843,6 +1866,10 @@ mf_set_flow_value(const struct mf_field *mf,
         flow->tunnel.nsp = value->be32;
         break;
 
+    case MFF_NSI:
+        flow->tunnel.nsi = value->u8;
+        break;
+
     case MFF_N_IDS:
     default:
         OVS_NOT_REACHED();
@@ -2056,6 +2083,10 @@ mf_set_wild(const struct mf_field *mf, struct match *match)
         match_set_nsp_masked(match, htonl(0), htonl(0));
         break;
 
+    case MFF_NSI:
+        match_set_nsi_masked(match, 0, 0);
+        break;
+
     case MFF_N_IDS:
     default:
         OVS_NOT_REACHED();
@@ -2228,6 +2259,10 @@ mf_set(const struct mf_field *mf,
         match_set_nsp_masked(match, value->be32, mask->be32);
         break;
 
+    case MFF_NSI:
+        match_set_nsi_masked(match, value->u8, mask->u8);
+        break;
+
     case MFF_N_IDS:
     default:
         OVS_NOT_REACHED();
diff --git a/lib/meta-flow.h b/lib/meta-flow.h
index a2977e4..da5a2bc 100644
--- a/lib/meta-flow.h
+++ b/lib/meta-flow.h
@@ -141,6 +141,7 @@ enum OVS_PACKED_ENUM mf_field_id {
 
     /* Network Service Headers (NSH) Fields */
     MFF_NSP,                    /* be32 */
+    MFF_NSI,                    /* u8 */
 
     MFF_N_IDS
 };
diff --git a/lib/netdev-vport.c b/lib/netdev-vport.c
index ce33150..57140f8 100644
--- a/lib/netdev-vport.c
+++ b/lib/netdev-vport.c
@@ -339,6 +339,33 @@ parse_nsp(const struct smap *args, const char *name,
     }
 }
 
+static uint8_t
+parse_nsi(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, "nsi");
+        if (!s) {
+            return 0;
+        }
+    }
+
+    *present = true;
+
+    if (!strcmp(s, "flow")) {
+        *flow = true;
+        return 0;
+    } else {
+        return strtoul(s, NULL, 0);
+    }
+}
+
 static int
 set_tunnel_config(struct netdev *dev_, const struct smap *args)
 {
@@ -446,6 +473,10 @@ set_tunnel_config(struct netdev *dev_, const struct smap *args)
                    !strcmp(node->key, "in_nsp") ||
                    !strcmp(node->key, "out_nsp")) {
             /* Handled separately below. */
+        } else if (!strcmp(node->key, "nsi") ||
+                   !strcmp(node->key, "in_nsi") ||
+                   !strcmp(node->key, "out_nsi")) {
+            /* Handled separately below. */
         } else {
             VLOG_WARN("%s: unknown %s argument '%s'", name, type, node->key);
         }
@@ -522,6 +553,23 @@ set_tunnel_config(struct netdev *dev_, const struct smap *args)
         tnl_cfg.out_nsp = parse_nsp(args, "out_nsp",
                                     &tnl_cfg.out_nsp_present,
                                     &tnl_cfg.out_nsp_flow);
+
+        tnl_cfg.in_nsi = parse_nsi(args, "in_nsi",
+                                   &tnl_cfg.in_nsi_present,
+                                   &tnl_cfg.in_nsi_flow);
+
+        tnl_cfg.out_nsi = parse_nsi(args, "out_nsi",
+                                    &tnl_cfg.out_nsi_present,
+                                    &tnl_cfg.out_nsi_flow);
+
+        /* Default nsh service index is 1, if lower packet is dropped */
+        if (!tnl_cfg.in_nsi) {
+            tnl_cfg.in_nsi = 1;
+        }
+
+        if (!tnl_cfg.out_nsi) {
+            tnl_cfg.out_nsi = 1;
+        }
     }
 
     ovs_mutex_lock(&dev->mutex);
diff --git a/lib/netdev.h b/lib/netdev.h
index ba99062..eefcd4c 100644
--- a/lib/netdev.h
+++ b/lib/netdev.h
@@ -110,6 +110,14 @@ struct netdev_tunnel_config {
     bool out_nsp_flow;
     ovs_be32 out_nsp;           /* outgoing NSH service path */
 
+    bool in_nsi_present;
+    bool in_nsi_flow;
+    uint8_t in_nsi;             /* incoming NSH service index */
+
+    bool out_nsi_present;
+    bool out_nsi_flow;
+    uint8_t out_nsi;            /* outgoing NSH service index */
+
     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 8cfcca5..cb881de 100644
--- a/lib/odp-util.c
+++ b/lib/odp-util.c
@@ -802,6 +802,7 @@ tunnel_key_attr_len(int type)
     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_NSI: return 1;
     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)
             tun->nsp = nl_attr_get_be32(a);
             tun->flags |= FLOW_TNL_F_NSP;
             break;
+        case OVS_TUNNEL_KEY_ATTR_NSI:
+            tun->nsi = nl_attr_get_u8(a);
+            tun->flags |= FLOW_TNL_F_NSI;
+            break;
         default:
             /* Allow this to show up as unexpected, if there are unknown
              * tunnel attribute, eventually resulting in ODP_FIT_TOO_MUCH. */
@@ -899,6 +904,9 @@ tun_key_to_attr(struct ofpbuf *a, const struct flow_tnl *tun_key)
     if (tun_key->flags & FLOW_TNL_F_NSP) {
         nl_msg_put_be32(a, OVS_TUNNEL_KEY_ATTR_NSP, tun_key->nsp);
     }
+    if (tun_key->flags & FLOW_TNL_F_NSI) {
+        nl_msg_put_u8(a, OVS_TUNNEL_KEY_ATTR_NSI, tun_key->nsi);
+    }
 
     nl_msg_end_nested(a, tun_key_ofs);
 }
@@ -926,6 +934,7 @@ odp_mask_attr_is_exact(const struct nlattr *ma)
         if (tun_mask.flags == (FLOW_TNL_F_KEY
                                | FLOW_TNL_F_DONT_FRAGMENT
                                | FLOW_TNL_F_NSP
+                               | FLOW_TNL_F_NSI
                                | FLOW_TNL_F_CSUM)) {
             /* The flags are exact match, check the remaining fields. */
             tun_mask.flags = 0xffff;
@@ -1051,11 +1060,13 @@ format_odp_key_attr(const struct nlattr *a, const struct nlattr *ma,
             odp_tun_key_from_attr(ma, &tun_mask);
             ds_put_format(ds, "tun_id=%#"PRIx64"/%#"PRIx64
                           ",nsp=%#"PRIx32"/%#"PRIx32
+                          ",nsi=%"PRIu8"/%"PRIu8
                           ",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),
+                          tun_key.nsi, tun_mask.nsi,
                           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,
@@ -1072,10 +1083,10 @@ 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",nsp=0x%"PRIx32
-                          ",src="IP_FMT",dst="IP_FMT","
+                          ",nsi=%"PRIu8",src="IP_FMT",dst="IP_FMT","
                           "tos=0x%"PRIx8",ttl=%"PRIu8",flags(",
                           ntohll(tun_key.tun_id),
-                          ntohl(tun_key.nsp),
+                          ntohl(tun_key.nsp), tun_key.nsi,
                           IP_ARGS(tun_key.ip_src),
                           IP_ARGS(tun_key.ip_dst),
                           tun_key.ip_tos, tun_key.ip_ttl);
@@ -1638,12 +1649,12 @@ parse_odp_key_mask_attr(const char *s, const struct simap *port_names,
         int n = -1;
 
         if (mask && ovs_scan(s, "tunnel(tun_id=%"SCNi64"/%"SCNi64","
-                             "nsp=%"PRIx32"/%"PRIx32","
+                             "nsp=%"PRIx32"/%"PRIx32",nsi=%"SCNi8"/%"SCNi8","
                              "src="IP_SCAN_FMT"/"IP_SCAN_FMT",dst="IP_SCAN_FMT
                              "/"IP_SCAN_FMT",tos=%"SCNi8"/%"SCNi8","
                              "ttl=%"SCNi8"/%"SCNi8",flags%n",
                              &tun_id, &tun_id_mask,
-                             &nsp, &nsp_mask,
+                             &nsp, &nsp_mask, &tun_key.nsi, &tun_key_mask.nsi,
                              IP_SCAN_ARGS(&tun_key.ip_src),
                              IP_SCAN_ARGS(&tun_key_mask.ip_src),
                              IP_SCAN_ARGS(&tun_key.ip_dst),
@@ -1675,10 +1686,10 @@ parse_odp_key_mask_attr(const char *s, const struct simap *port_names,
             }
             return n;
         } else if (ovs_scan(s, "tunnel(tun_id=%"SCNi64","
-                            "nsp=%"PRIx32","
+                            "nsp=%"PRIx32",nsi=%"SCNi8","
                             "src="IP_SCAN_FMT",dst="IP_SCAN_FMT
                             ",tos=%"SCNi8",ttl=%"SCNi8",flags%n", &tun_id,
-                            &tun_key.nsp,
+                            &tun_key.nsp, &tun_key.nsi,
                             IP_SCAN_ARGS(&tun_key.ip_src),
                             IP_SCAN_ARGS(&tun_key.ip_dst),
                             &tun_key.ip_tos, &tun_key.ip_ttl, &n)) {
diff --git a/lib/odp-util.h b/lib/odp-util.h
index 1ad272e..2b38327 100644
--- a/lib/odp-util.h
+++ b/lib/odp-util.h
@@ -107,6 +107,7 @@ void odp_portno_names_destroy(struct hmap *portno_names);
  *  - 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_TUNNEL_KEY_ATTR_NSI            1    3      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
@@ -118,7 +119,7 @@ void odp_portno_names_destroy(struct hmap *portno_names);
  *  OVS_KEY_ATTR_ICMPV6                  2     2     4      8
  *  OVS_KEY_ATTR_ND                     28    --     4     32
  *  ----------------------------------------------------------
- *  total                                                 216
+ *  total                                                 224
  *
  * 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 d1d629c..687ed18 100644
--- a/ofproto/tunnel.c
+++ b/ofproto/tunnel.c
@@ -43,10 +43,12 @@ struct tnl_match {
     ovs_be32 ip_dst;
     odp_port_t odp_port;
     uint32_t pkt_mark;
+    uint8_t in_nsi;
     bool in_key_flow;
     bool in_nsp_flow;
     bool ip_src_flow;
     bool ip_dst_flow;
+    bool in_nsi_flow;
 };
 
 struct tnl_port {
@@ -82,17 +84,21 @@ static struct ovs_rwlock rwlock = OVS_RWLOCK_INITIALIZER;
  *       false) or arrange for the service path to be matched as tunnel.in_nsp
  *       in the OpenFlow flow (in_nsp_flow == true).
  *
+ *     - in_nsi: A vport may match a specific NSH service index (in_nsi_flow ==
+ *       false) or arrange for the service index to be matched as tunnel.in_nsi
+ *       in the OpenFlow flow (in_nsi_flow == true).
+ *
  *     - ip_src: A vport may match a specific IP source address (ip_src_flow ==
  *       false, ip_src != 0), wildcard all source addresses (ip_src_flow ==
  *       false, ip_src == 0), or arrange for the IP source address to be
  *       handled in the OpenFlow flow table (ip_src_flow == true).
  *
- * Thus, there are 2 * 2 * 2 * 3 == 24 possible ways a vport can match
+ * Thus, there are 2 * 2 * 2 * 2 * 3 == 48 possible ways a vport can match
  * against a tunnel packet.  We number the possibilities for each field in
  * increasing order as listed in each bullet above.  We order the 24 overall
  * combinations in lexicographic order considering in_key first, then ip_dst,
- * then in_nsp, then ip_src. */
-#define N_MATCH_TYPES (2 * 2 * 2 * 3)
+ * then in_nsp, then in_nsi, then ip_src. */
+#define N_MATCH_TYPES (2 * 2 * 2 * 2 * 3)
 
 /* The three possibilities (see above) for vport ip_src matches. */
 enum ip_src_type {
@@ -160,6 +166,7 @@ tnl_port_add__(const struct ofport_dpif *ofport, const struct netdev *netdev,
 
     tnl_port->match.in_key = cfg->in_key;
     tnl_port->match.in_nsp = cfg->in_nsp;
+    tnl_port->match.in_nsi = cfg->in_nsi;
     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;
@@ -167,6 +174,7 @@ tnl_port_add__(const struct ofport_dpif *ofport, const struct netdev *netdev,
     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.in_nsi_flow = cfg->in_nsi_flow;
     tnl_port->match.odp_port = odp_port;
 
     idx = tnl_match_m_to_idx(&tnl_port->match);
@@ -408,6 +416,10 @@ tnl_port_send(const struct ofport_dpif *ofport, struct flow *flow,
         flow->tunnel.nsp = cfg->out_nsp;
     }
 
+    if (!cfg->out_nsi_flow) {
+        flow->tunnel.nsi = cfg->out_nsi;
+    }
+
     if (cfg->ttl_inherit && is_ip_any(flow)) {
         wc->masks.nw_ttl = 0xff;
         flow->tunnel.ip_ttl = flow->nw_ttl;
@@ -436,6 +448,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_nsi_present ? FLOW_TNL_F_NSI : 0)
         | (cfg->out_key_present ? FLOW_TNL_F_KEY : 0);
 
     if (pre_flow_str) {
@@ -530,6 +543,7 @@ tnl_match_idx_to_m(const struct flow *flow, unsigned int idx,
     bool in_key_flow;
     bool ip_dst_flow;
     bool in_nsp_flow;
+    bool in_nsi_flow;
 
     if (!m)
         return;
@@ -549,6 +563,11 @@ tnl_match_idx_to_m(const struct flow *flow, unsigned int idx,
     if (idx >= (N_MATCH_TYPES / (2 * 2 * 2)))
         idx -= (N_MATCH_TYPES / (2 * 2 * 2));
 
+    in_nsi_flow = (idx < (N_MATCH_TYPES / (2 * 2 * 2 * 2))) ? false : true;
+
+    if (idx >= (N_MATCH_TYPES / (2 * 2 * 2 * 2)))
+        idx -= (N_MATCH_TYPES / (2 * 2 * 2 * 2));
+
     ip_src = idx;
 
     /* The apparent mix-up of 'ip_dst' and 'ip_src' below is
@@ -561,12 +580,14 @@ tnl_match_idx_to_m(const struct flow *flow, unsigned int idx,
                     ? flow->tunnel.ip_dst
                     : 0);
     m->in_nsp = in_nsp_flow ? 0 : flow->tunnel.nsp;
+    m->in_nsi = in_nsi_flow ? 1 : flow->tunnel.nsi;
     m->ip_dst = ip_dst_flow ? 0 : flow->tunnel.ip_src;
     m->odp_port = flow->in_port.odp_port;
     m->pkt_mark = flow->pkt_mark;
     m->in_key_flow = in_key_flow;
     m->ip_dst_flow = ip_dst_flow;
     m->in_nsp_flow = in_nsp_flow;
+    m->in_nsi_flow = in_nsi_flow;
     m->ip_src_flow = ip_src == IP_SRC_FLOW;
 }
 
@@ -583,6 +604,7 @@ tnl_match_m_to_idx(const struct tnl_match *m)
     return (m->in_key_flow * (N_MATCH_TYPES / 2) +
             m->ip_dst_flow * (N_MATCH_TYPES / (2 * 2)) +
             m->in_nsp_flow * (N_MATCH_TYPES / (2 * 2 * 2)) +
+            m->in_nsi_flow * (N_MATCH_TYPES / (2 * 2 * 2 * 2)) +
             ip_src);
 }
 
@@ -643,6 +665,12 @@ tnl_match_fmt(const struct tnl_match *match, struct ds *ds)
         ds_put_format(ds, ", nsp=%#"PRIx32, ntohl(match->in_nsp));
     }
 
+    if (match->in_nsi_flow) {
+        ds_put_cstr(ds, ", nsi=flow");
+    } else {
+        ds_put_format(ds, ", nsi=%"PRIu8, match->in_nsi);
+    }
+
     ds_put_format(ds, ", dp port=%"PRIu32, match->odp_port);
     ds_put_format(ds, ", pkt mark=%"PRIu32, match->pkt_mark);
 }
@@ -699,6 +727,19 @@ tnl_port_fmt(const struct tnl_port *tnl_port) OVS_REQ_RDLOCK(rwlock)
         }
     }
 
+    if (cfg->out_nsi != cfg->in_nsi ||
+        cfg->out_nsi_present != cfg->in_nsi_present ||
+        cfg->out_nsi_flow != cfg->in_nsi_flow) {
+        ds_put_cstr(&ds, ", out_nsi=");
+        if (!cfg->out_nsi_present) {
+            ds_put_cstr(&ds, "none");
+        } else if (cfg->out_nsi_flow) {
+            ds_put_cstr(&ds, "flow");
+        } else {
+            ds_put_format(&ds, "%"PRIu8, cfg->out_nsi);
+        }
+    }
+
     if (cfg->ttl_inherit) {
         ds_put_cstr(&ds, ", ttl=inherit");
     } else {
-- 
1.7.9.5




More information about the dev mailing list