From: pritesh <pritesh.koth...@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.koth...@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 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev