[ovs-dev] [PATCH v9 1/3] nsh: add new flow key 'ttl'
Yi Yang
yi.y.yang at intel.com
Thu Jan 11 05:24:01 UTC 2018
IETF NSH draft added a new filed ttl in NSH header, this patch
is to add new nsh key 'ttl' for it.
Signed-off-by: Yi Yang <yi.y.yang at intel.com>
---
NEWS | 1 +
datapath/linux/compat/include/linux/openvswitch.h | 2 +-
include/openvswitch/flow.h | 6 +-
include/openvswitch/meta-flow.h | 14 +++
include/openvswitch/nsh.h | 102 ++++++++++++++++
include/openvswitch/packets.h | 12 +-
lib/flow.c | 23 ++--
lib/flow.h | 2 +-
lib/match.c | 12 +-
lib/meta-flow.c | 56 +++++++--
lib/meta-flow.xml | 139 ++++++++++++++++++----
lib/nx-match.c | 16 ++-
lib/odp-execute.c | 40 +++----
lib/odp-util.c | 130 +++++++++-----------
lib/odp-util.h | 2 +-
ofproto/ofproto-dpif-xlate.c | 7 +-
tests/nsh.at | 41 +++----
tests/ofproto.at | 3 +-
18 files changed, 422 insertions(+), 186 deletions(-)
diff --git a/NEWS b/NEWS
index 8caf6bb..ae684e3 100644
--- a/NEWS
+++ b/NEWS
@@ -1,6 +1,7 @@
Post-v2.8.0
--------------------
- NSH implementation now conforms to latest draft (draft-ietf-sfc-nsh-28).
+ * Add ttl field.
- OVSDB:
* New high-level documentation in ovsdb(7).
* New file format documentation for developers in ovsdb(5).
diff --git a/datapath/linux/compat/include/linux/openvswitch.h b/datapath/linux/compat/include/linux/openvswitch.h
index 3ddb1c5..c7142b6 100644
--- a/datapath/linux/compat/include/linux/openvswitch.h
+++ b/datapath/linux/compat/include/linux/openvswitch.h
@@ -504,9 +504,9 @@ enum ovs_nsh_key_attr {
struct ovs_nsh_key_base {
__u8 flags;
+ __u8 ttl;
__u8 mdtype;
__u8 np;
- __u8 pad;
__be32 path_hdr;
};
diff --git a/include/openvswitch/flow.h b/include/openvswitch/flow.h
index a658a58..cd61fff 100644
--- a/include/openvswitch/flow.h
+++ b/include/openvswitch/flow.h
@@ -146,7 +146,7 @@ struct flow {
struct eth_addr arp_tha; /* ARP/ND target hardware address. */
ovs_be16 tcp_flags; /* TCP flags. With L3 to avoid matching L4. */
ovs_be16 pad2; /* Pad to 64 bits. */
- struct flow_nsh nsh; /* Network Service Header keys */
+ struct ovs_key_nsh nsh; /* Network Service Header keys */
/* L4 (64-bit aligned) */
ovs_be16 tp_src; /* TCP/UDP/SCTP source port/ICMP type. */
@@ -159,13 +159,13 @@ struct flow {
};
BUILD_ASSERT_DECL(sizeof(struct flow) % sizeof(uint64_t) == 0);
BUILD_ASSERT_DECL(sizeof(struct flow_tnl) % sizeof(uint64_t) == 0);
-BUILD_ASSERT_DECL(sizeof(struct flow_nsh) % sizeof(uint64_t) == 0);
+BUILD_ASSERT_DECL(sizeof(struct ovs_key_nsh) % sizeof(uint64_t) == 0);
#define FLOW_U64S (sizeof(struct flow) / sizeof(uint64_t))
/* Remember to update FLOW_WC_SEQ when changing 'struct flow'. */
BUILD_ASSERT_DECL(offsetof(struct flow, igmp_group_ip4) + sizeof(uint32_t)
- == sizeof(struct flow_tnl) + sizeof(struct flow_nsh) + 300
+ == sizeof(struct flow_tnl) + sizeof(struct ovs_key_nsh) + 300
&& FLOW_WC_SEQ == 40);
/* Incremental points at which flow classification may be performed in
diff --git a/include/openvswitch/meta-flow.h b/include/openvswitch/meta-flow.h
index 436501f..d0844b3 100644
--- a/include/openvswitch/meta-flow.h
+++ b/include/openvswitch/meta-flow.h
@@ -1833,6 +1833,20 @@ enum OVS_PACKED_ENUM mf_field_id {
MFF_NSH_C3,
MFF_NSH_C4,
+ /* "nsh_ttl".
+ *
+ * TTL field in NSH base header.
+ *
+ * Type: u8.
+ * Maskable: no.
+ * Formatting: decimal.
+ * Prerequisites: NSH.
+ * Access: read/write.
+ * NXM: none.
+ * OXM: NXOXM_NSH_TTL(10) since OF1.3 and v2.9.
+ */
+ MFF_NSH_TTL,
+
MFF_N_IDS
};
diff --git a/include/openvswitch/nsh.h b/include/openvswitch/nsh.h
index 63b480e..55f59d6 100644
--- a/include/openvswitch/nsh.h
+++ b/include/openvswitch/nsh.h
@@ -299,6 +299,108 @@ nsh_reset_ver_flags_ttl_len(struct nsh_hdr *nsh)
nsh->ver_flags_ttl_len = 0;
}
+static inline uint8_t
+nsh_get_ttl(const struct nsh_hdr *nsh)
+{
+ return (ntohs(nsh->ver_flags_ttl_len) & NSH_TTL_MASK) >> NSH_TTL_SHIFT;
+}
+
+#ifndef __CHECKER__
+static inline ovs_be32
+nsh_16aligned_be32(const ovs_16aligned_be32 *x)
+{
+#ifdef WORDS_BIGENDIAN
+ return ((ovs_be32) x->hi << 16) | (ovs_be32) x->lo;
+#else
+ return ((ovs_be32) x->lo << 16) | (ovs_be32) x->hi;
+#endif
+}
+#else /* __CHECKER__ */
+/* Making sparse happy with these functions also makes them unreadable, so
+ * don't bother to show it their implementations. */
+ovs_be32 nsh_16aligned_be32(const ovs_16aligned_be32 *x);
+#endif
+
+static inline ovs_be32
+nsh_get_path_hdr(const struct nsh_hdr *nsh)
+{
+ return nsh_16aligned_be32(&nsh->path_hdr);
+}
+
+static inline ovs_be32
+nsh_get_spi(const struct nsh_hdr *nsh)
+{
+ uint32_t path_hdr = ntohl(nsh_get_path_hdr(nsh));
+ return htonl((path_hdr & NSH_SPI_MASK) >> NSH_SPI_SHIFT);
+}
+
+static inline uint8_t
+nsh_get_si(const struct nsh_hdr *nsh)
+{
+ uint32_t path_hdr = ntohl(nsh_get_path_hdr(nsh));
+ return (path_hdr & NSH_SI_MASK) >> NSH_SI_SHIFT;
+}
+
+static inline ovs_be32
+nsh_path_hdr_to_spi(ovs_be32 path_hdr)
+{
+ return htonl((ntohl(path_hdr) & NSH_SPI_MASK) >> NSH_SPI_SHIFT);
+}
+
+static inline uint32_t
+nsh_path_hdr_to_spi_uint32(ovs_be32 path_hdr)
+{
+ return (ntohl(path_hdr) & NSH_SPI_MASK) >> NSH_SPI_SHIFT;
+}
+
+static inline uint8_t
+nsh_path_hdr_to_si(ovs_be32 path_hdr)
+{
+ return (ntohl(path_hdr) & NSH_SI_MASK) >> NSH_SI_SHIFT;
+}
+
+static inline ovs_be32
+nsh_spi_si_to_path_hdr(uint32_t spi, uint8_t si)
+{
+ return htonl((spi << NSH_SPI_SHIFT) | si);
+}
+
+static inline void
+nsh_set_flags_and_ttl(struct nsh_hdr *nsh, uint8_t flags, uint8_t ttl)
+{
+ nsh->ver_flags_ttl_len
+ = htons((ntohs(nsh->ver_flags_ttl_len)
+ & ~(NSH_FLAGS_MASK | NSH_TTL_MASK))
+ | ((flags << NSH_FLAGS_SHIFT)& NSH_FLAGS_MASK)
+ | ((ttl << NSH_TTL_SHIFT) & NSH_TTL_MASK));
+}
+
+static inline void
+nsh_set_flags_ttl_len(struct nsh_hdr *nsh, uint8_t flags, uint8_t ttl,
+ uint16_t len)
+{
+ nsh->ver_flags_ttl_len
+ = htons((ntohs(nsh->ver_flags_ttl_len)
+ & ~(NSH_FLAGS_MASK | NSH_TTL_MASK | NSH_LEN_MASK))
+ | ((flags << NSH_FLAGS_SHIFT)& NSH_FLAGS_MASK)
+ | ((ttl << NSH_TTL_SHIFT) & NSH_TTL_MASK)
+ | (((len >> 2) << NSH_LEN_SHIFT) & NSH_LEN_MASK));
+}
+
+static inline void
+nsh_path_hdr_set_spi(ovs_be32 *path_hdr, ovs_be32 spi)
+{
+ *path_hdr = htonl((ntohl(*path_hdr) & ~NSH_SPI_MASK) |
+ ((ntohl(spi) << NSH_SPI_SHIFT) & NSH_SPI_MASK));
+}
+
+static inline void
+nsh_path_hdr_set_si(ovs_be32 *path_hdr, uint8_t si)
+{
+ *path_hdr = htonl((ntohl(*path_hdr) & ~NSH_SI_MASK) |
+ ((si << NSH_SI_SHIFT) & NSH_SI_MASK));
+}
+
#ifdef __cplusplus
}
#endif
diff --git a/include/openvswitch/packets.h b/include/openvswitch/packets.h
index ae1cf9c..fef756b 100644
--- a/include/openvswitch/packets.h
+++ b/include/openvswitch/packets.h
@@ -74,21 +74,11 @@ union flow_vlan_hdr {
};
};
-/* Network Service Header keys */
-struct flow_nsh {
- uint8_t flags;
- uint8_t mdtype;
- uint8_t np;
- uint8_t si;
- ovs_be32 spi;
- ovs_be32 context[4];
-};
-
struct ovs_key_nsh {
uint8_t flags;
+ uint8_t ttl;
uint8_t mdtype;
uint8_t np;
- uint8_t pad;
ovs_be32 path_hdr;
ovs_be32 context[4];
};
diff --git a/lib/flow.c b/lib/flow.c
index 964f734..f9d7c2a 100644
--- a/lib/flow.c
+++ b/lib/flow.c
@@ -530,11 +530,10 @@ parse_ipv6_ext_hdrs(const void **datap, size_t *sizep, uint8_t *nw_proto,
}
bool
-parse_nsh(const void **datap, size_t *sizep, struct flow_nsh *key)
+parse_nsh(const void **datap, size_t *sizep, struct ovs_key_nsh *key)
{
const struct nsh_hdr *nsh = (const struct nsh_hdr *) *datap;
- uint8_t version, length, flags;
- uint32_t path_hdr;
+ uint8_t version, length, flags, ttl;
/* Check if it is long enough for NSH header, doesn't support
* MD type 2 yet
@@ -546,18 +545,17 @@ parse_nsh(const void **datap, size_t *sizep, struct flow_nsh *key)
version = nsh_get_ver(nsh);
flags = nsh_get_flags(nsh);
length = nsh_hdr_len(nsh);
+ ttl = nsh_get_ttl(nsh);
if (OVS_UNLIKELY(length > *sizep || version != 0)) {
return false;
}
key->flags = flags;
+ key->ttl = ttl;
key->mdtype = nsh->md_type;
key->np = nsh->next_proto;
-
- path_hdr = ntohl(get_16aligned_be32(&nsh->path_hdr));
- key->si = (path_hdr & NSH_SI_MASK) >> NSH_SI_SHIFT;
- key->spi = htonl((path_hdr & NSH_SPI_MASK) >> NSH_SPI_SHIFT);
+ key->path_hdr = nsh_get_path_hdr(nsh);
switch (key->mdtype) {
case NSH_M_TYPE1:
@@ -876,11 +874,11 @@ miniflow_extract(struct dp_packet *packet, struct miniflow *dst)
miniflow_pad_to_64(mf, arp_tha);
}
} else if (dl_type == htons(ETH_TYPE_NSH)) {
- struct flow_nsh nsh;
+ struct ovs_key_nsh nsh;
if (OVS_LIKELY(parse_nsh(&data, &size, &nsh))) {
miniflow_push_words(mf, nsh, &nsh,
- sizeof(struct flow_nsh) /
+ sizeof(struct ovs_key_nsh) /
sizeof(uint64_t));
}
}
@@ -1684,10 +1682,10 @@ flow_wildcards_init_for_packet(struct flow_wildcards *wc,
return;
} else if (flow->dl_type == htons(ETH_TYPE_NSH)) {
WC_MASK_FIELD(wc, nsh.flags);
+ WC_MASK_FIELD(wc, nsh.ttl);
WC_MASK_FIELD(wc, nsh.mdtype);
WC_MASK_FIELD(wc, nsh.np);
- WC_MASK_FIELD(wc, nsh.spi);
- WC_MASK_FIELD(wc, nsh.si);
+ WC_MASK_FIELD(wc, nsh.path_hdr);
WC_MASK_FIELD(wc, nsh.context);
} else {
return; /* Unknown ethertype. */
@@ -1820,8 +1818,7 @@ flow_wc_map(const struct flow *flow, struct flowmap *map)
FLOWMAP_SET(map, nsh.flags);
FLOWMAP_SET(map, nsh.mdtype);
FLOWMAP_SET(map, nsh.np);
- FLOWMAP_SET(map, nsh.spi);
- FLOWMAP_SET(map, nsh.si);
+ FLOWMAP_SET(map, nsh.path_hdr);
FLOWMAP_SET(map, nsh.context);
}
}
diff --git a/lib/flow.h b/lib/flow.h
index b3128da..eb1e2bf 100644
--- a/lib/flow.h
+++ b/lib/flow.h
@@ -129,7 +129,7 @@ bool flow_compose(struct dp_packet *, const struct flow *, size_t);
bool parse_ipv6_ext_hdrs(const void **datap, size_t *sizep, uint8_t *nw_proto,
uint8_t *nw_frag);
ovs_be16 parse_dl_type(const struct eth_header *data_, size_t size);
-bool parse_nsh(const void **datap, size_t *sizep, struct flow_nsh *key);
+bool parse_nsh(const void **datap, size_t *sizep, struct ovs_key_nsh *key);
static inline uint64_t
flow_get_xreg(const struct flow *flow, int idx)
diff --git a/lib/match.c b/lib/match.c
index 8952c99..b880492 100644
--- a/lib/match.c
+++ b/lib/match.c
@@ -1260,11 +1260,19 @@ format_ct_label_masked(struct ds *s, const ovs_u128 *key, const ovs_u128 *mask)
static void
format_nsh_masked(struct ds *s, const struct flow *f, const struct flow *m)
{
+ ovs_be32 spi_mask = nsh_path_hdr_to_spi(m->nsh.path_hdr);
+ if (spi_mask == htonl(NSH_SPI_MASK >> NSH_SPI_SHIFT)) {
+ spi_mask = OVS_BE32_MAX;
+ }
format_uint8_masked(s, "nsh_flags", f->nsh.flags, m->nsh.flags);
+ format_uint8_masked(s, "nsh_ttl", f->nsh.ttl, m->nsh.ttl);
format_uint8_masked(s, "nsh_mdtype", f->nsh.mdtype, m->nsh.mdtype);
format_uint8_masked(s, "nsh_np", f->nsh.np, m->nsh.np);
- format_be32_masked_hex(s, "nsh_spi", f->nsh.spi, m->nsh.spi);
- format_uint8_masked(s, "nsh_si", f->nsh.si, m->nsh.si);
+
+ format_be32_masked_hex(s, "nsh_spi", nsh_path_hdr_to_spi(f->nsh.path_hdr),
+ spi_mask);
+ format_uint8_masked(s, "nsh_si", nsh_path_hdr_to_si(f->nsh.path_hdr),
+ nsh_path_hdr_to_si(m->nsh.path_hdr));
if (m->nsh.mdtype == UINT8_MAX && f->nsh.mdtype == NSH_M_TYPE1) {
format_be32_masked_hex(s, "nsh_c1", f->nsh.context[0],
m->nsh.context[0]);
diff --git a/lib/meta-flow.c b/lib/meta-flow.c
index beeddf1..ed41f50 100644
--- a/lib/meta-flow.c
+++ b/lib/meta-flow.c
@@ -40,6 +40,7 @@
#include "openvswitch/ofp-errors.h"
#include "openvswitch/vlog.h"
#include "vl-mff-map.h"
+#include "openvswitch/nsh.h"
VLOG_DEFINE_THIS_MODULE(meta_flow);
@@ -361,14 +362,16 @@ mf_is_all_wild(const struct mf_field *mf, const struct flow_wildcards *wc)
case MFF_NSH_FLAGS:
return !wc->masks.nsh.flags;
+ case MFF_NSH_TTL:
+ return !wc->masks.nsh.ttl;
case MFF_NSH_MDTYPE:
return !wc->masks.nsh.mdtype;
case MFF_NSH_NP:
return !wc->masks.nsh.np;
case MFF_NSH_SPI:
- return !wc->masks.nsh.spi;
+ return !(wc->masks.nsh.path_hdr & htonl(NSH_SPI_MASK));
case MFF_NSH_SI:
- return !wc->masks.nsh.si;
+ return !(wc->masks.nsh.path_hdr & htonl(NSH_SI_MASK));
case MFF_NSH_C1:
case MFF_NSH_C2:
case MFF_NSH_C3:
@@ -606,6 +609,8 @@ mf_is_value_valid(const struct mf_field *mf, const union mf_value *value)
case MFF_NSH_FLAGS:
return true;
+ case MFF_NSH_TTL:
+ return (value->u8 <= 63);
case MFF_NSH_MDTYPE:
return (value->u8 == 1 || value->u8 == 2);
case MFF_NSH_NP:
@@ -899,6 +904,9 @@ mf_get_value(const struct mf_field *mf, const struct flow *flow,
case MFF_NSH_FLAGS:
value->u8 = flow->nsh.flags;
break;
+ case MFF_NSH_TTL:
+ value->u8 = flow->nsh.ttl;
+ break;
case MFF_NSH_MDTYPE:
value->u8 = flow->nsh.mdtype;
break;
@@ -906,10 +914,13 @@ mf_get_value(const struct mf_field *mf, const struct flow *flow,
value->u8 = flow->nsh.np;
break;
case MFF_NSH_SPI:
- value->be32 = flow->nsh.spi;
+ value->be32 = nsh_path_hdr_to_spi(flow->nsh.path_hdr);
+ if (value->be32 == htonl(NSH_SPI_MASK >> NSH_SPI_SHIFT)) {
+ value->be32 = OVS_BE32_MAX;
+ }
break;
case MFF_NSH_SI:
- value->u8 = flow->nsh.si;
+ value->u8 = nsh_path_hdr_to_si(flow->nsh.path_hdr);
break;
case MFF_NSH_C1:
case MFF_NSH_C2:
@@ -1214,6 +1225,9 @@ mf_set_value(const struct mf_field *mf,
case MFF_NSH_FLAGS:
MATCH_SET_FIELD_UINT8(match, nsh.flags, value->u8);
break;
+ case MFF_NSH_TTL:
+ MATCH_SET_FIELD_UINT8(match, nsh.ttl, value->u8);
+ break;
case MFF_NSH_MDTYPE:
MATCH_SET_FIELD_UINT8(match, nsh.mdtype, value->u8);
break;
@@ -1221,10 +1235,12 @@ mf_set_value(const struct mf_field *mf,
MATCH_SET_FIELD_UINT8(match, nsh.np, value->u8);
break;
case MFF_NSH_SPI:
- MATCH_SET_FIELD_BE32(match, nsh.spi, value->be32);
+ match->wc.masks.nsh.path_hdr |= htonl(NSH_SPI_MASK);
+ nsh_path_hdr_set_spi(&match->flow.nsh.path_hdr, value->be32);
break;
case MFF_NSH_SI:
- MATCH_SET_FIELD_UINT8(match, nsh.si, value->u8);
+ match->wc.masks.nsh.path_hdr |= htonl(NSH_SI_MASK);
+ nsh_path_hdr_set_si(&match->flow.nsh.path_hdr, value->u8);
break;
case MFF_NSH_C1:
case MFF_NSH_C2:
@@ -1606,6 +1622,9 @@ mf_set_flow_value(const struct mf_field *mf,
case MFF_NSH_FLAGS:
flow->nsh.flags = value->u8;
break;
+ case MFF_NSH_TTL:
+ flow->nsh.ttl = value->u8;
+ break;
case MFF_NSH_MDTYPE:
flow->nsh.mdtype = value->u8;
break;
@@ -1613,10 +1632,10 @@ mf_set_flow_value(const struct mf_field *mf,
flow->nsh.np = value->u8;
break;
case MFF_NSH_SPI:
- flow->nsh.spi = value->be32;
+ nsh_path_hdr_set_spi(&flow->nsh.path_hdr, value->be32);
break;
case MFF_NSH_SI:
- flow->nsh.si = value->u8;
+ nsh_path_hdr_set_si(&flow->nsh.path_hdr, value->u8);
break;
case MFF_NSH_C1:
case MFF_NSH_C2:
@@ -1752,6 +1771,7 @@ mf_is_pipeline_field(const struct mf_field *mf)
case MFF_ND_SLL:
case MFF_ND_TLL:
case MFF_NSH_FLAGS:
+ case MFF_NSH_TTL:
case MFF_NSH_MDTYPE:
case MFF_NSH_NP:
case MFF_NSH_SPI:
@@ -2097,6 +2117,9 @@ mf_set_wild(const struct mf_field *mf, struct match *match, char **err_str)
case MFF_NSH_FLAGS:
MATCH_SET_FIELD_MASKED(match, nsh.flags, 0, 0);
break;
+ case MFF_NSH_TTL:
+ MATCH_SET_FIELD_MASKED(match, nsh.ttl, 0, 0);
+ break;
case MFF_NSH_MDTYPE:
MATCH_SET_FIELD_MASKED(match, nsh.mdtype, 0, 0);
break;
@@ -2104,10 +2127,12 @@ mf_set_wild(const struct mf_field *mf, struct match *match, char **err_str)
MATCH_SET_FIELD_MASKED(match, nsh.np, 0, 0);
break;
case MFF_NSH_SPI:
- MATCH_SET_FIELD_MASKED(match, nsh.spi, htonl(0), htonl(0));
+ match->wc.masks.nsh.path_hdr &= ~htonl(NSH_SPI_MASK);
+ nsh_path_hdr_set_spi(&match->flow.nsh.path_hdr, htonl(0));
break;
case MFF_NSH_SI:
- MATCH_SET_FIELD_MASKED(match, nsh.si, 0, 0);
+ match->wc.masks.nsh.path_hdr &= ~htonl(NSH_SI_MASK);
+ nsh_path_hdr_set_si(&match->flow.nsh.path_hdr, 0);
break;
case MFF_NSH_C1:
case MFF_NSH_C2:
@@ -2357,6 +2382,9 @@ mf_set(const struct mf_field *mf,
case MFF_NSH_FLAGS:
MATCH_SET_FIELD_MASKED(match, nsh.flags, value->u8, mask->u8);
break;
+ case MFF_NSH_TTL:
+ MATCH_SET_FIELD_MASKED(match, nsh.ttl, value->u8, mask->u8);
+ break;
case MFF_NSH_MDTYPE:
MATCH_SET_FIELD_MASKED(match, nsh.mdtype, value->u8, mask->u8);
break;
@@ -2364,10 +2392,14 @@ mf_set(const struct mf_field *mf,
MATCH_SET_FIELD_MASKED(match, nsh.np, value->u8, mask->u8);
break;
case MFF_NSH_SPI:
- MATCH_SET_FIELD_MASKED(match, nsh.spi, value->be32, mask->be32);
+ match->wc.masks.nsh.path_hdr |= mask->be32;
+ nsh_path_hdr_set_spi(&match->flow.nsh.path_hdr,
+ value->be32 & mask->be32);
break;
case MFF_NSH_SI:
- MATCH_SET_FIELD_MASKED(match, nsh.si, value->u8, mask->u8);
+ match->wc.masks.nsh.path_hdr |= htonl(mask->u8);
+ nsh_path_hdr_set_si(&match->flow.nsh.path_hdr,
+ value->u8 & mask->u8);
break;
case MFF_NSH_C1:
case MFF_NSH_C2:
diff --git a/lib/meta-flow.xml b/lib/meta-flow.xml
index 08ee0ec..933d4b8 100644
--- a/lib/meta-flow.xml
+++ b/lib/meta-flow.xml
@@ -1309,27 +1309,6 @@ tcp,tp_src=0x07c0/0xfff0
</field>
</group>
- <group title="Network Service Header">
- <field id="MFF_NSH_FLAGS"
- title="flags field (8 bits)"/>
- <field id="MFF_NSH_MDTYPE"
- title="mdtype field (8 bits)"/>
- <field id="MFF_NSH_NP"
- title="np (next protocol) field (8 bits)"/>
- <field id="MFF_NSH_SPI"
- title="spi (service path identifier) field (24 bits)"/>
- <field id="MFF_NSH_SI"
- title="si (service index) field (8 bits)"/>
- <field id="MFF_NSH_C1"
- title="c1 (Network Platform Context) field (32 bits)"/>
- <field id="MFF_NSH_C2"
- title="c2 (Network Shared Context) field (32 bits)"/>
- <field id="MFF_NSH_C3"
- title="c3 (Service Platform Context) field (32 bits)"/>
- <field id="MFF_NSH_C4"
- title="c4 (Service Shared Context) field (32 bits)"/>
- </group>
-
<group title="Tunnel">
<p>
The fields in this group relate to tunnels, which Open vSwitch
@@ -3964,7 +3943,7 @@ r r c c c.
listen for <code>OFPR_INVALID_TTL</code> ``packet-in'' messages via
OpenFlow.
</field>
-
+
<field id="MFF_IP_FRAG" title="IPv4/v6 Fragment Bitmask">
<p>
Specifies what kinds of IP fragments or non-fragments to match. The
@@ -4180,6 +4159,115 @@ r r c c c.
<field id="MFF_ARP_THA" title="ARP Target Ethernet Address"/>
</group>
+ <group title="Layer 3: NSH">
+ <p>
+ Service functions are widely deployed and essential in many networks.
+ These service functions provide a range of features such as security,
+ WAN acceleration, and server load balancing. Service functions may
+ be instantiated at different points in the network infrastructure
+ such as the wide area network, data center, and so forth.
+ </p>
+
+ <p>
+ Prior to development of the SFC architecture [RFC 7665] and the
+ protocol specified in this document, current service function
+ deployment models have been relatively static and bound to topology
+ for insertion and policy selection. Furthermore, they do not adapt
+ well to elastic service environments enabled by virtualization.
+ </p>
+
+ <p>
+ New data center network and cloud architectures require more flexible
+ service function deployment models. Additionally, the transition to
+ virtual platforms demands an agile service insertion model that
+ supports dynamic and elastic service delivery. Specifically, the
+ following functions are necessary:
+ </p>
+
+ <p>
+ 1. The movement of service functions and application workloads in
+ the network.
+ </p>
+
+ <p>
+ 2. The ability to easily bind service policy to granular
+ information, such as per-subscriber state.
+ </p>
+
+ <p>
+ 3. The capability to steer traffic to the requisite service
+ function(s).
+ </p>
+
+ <p>
+ The Network Service Header (NSH) specification defines a new data
+ plane protocol, which is an encapsulation for service function
+ chains. The NSH is designed to encapsulate an original packet or
+ frame, and in turn be encapsulated by an outer transport
+ encapsulation (which is used to deliver the NSH to NSH-aware network
+ elements), as shown in Figure 1:
+ </p>
+
+ <pre>
+
+ +------------------------------+
+ | Transport Encapsulation |
+ +------------------------------+
+ | Network Service Header (NSH) |
+ +------------------------------+
+ | Original Packet / Frame |
+ +------------------------------+
+
+ Figure 1: Network Service Header Encapsulation
+ </pre>
+
+ <p>
+ The NSH is composed of the following elements:
+ </p>
+
+ <p>
+ 1. Service Function Path identification.
+ </p>
+
+ <p>
+ 2. Indication of location within a Service Function Path.
+ </p>
+
+ <p>
+ 3. Optional, per packet metadata (fixed length or variable).
+ </p>
+
+ <p>
+ [RFC 7665] provides an overview of a service chaining architecture
+ that clearly defines the roles of the various elements and the scope
+ of a service function chaining encapsulation. Figure 3 of [RFC 7665]
+ depicts the SFC architectural components after classification. The
+ NSH is the SFC encapsulation referenced in [RFC 7665].
+ </p>
+
+ <field id="MFF_NSH_FLAGS"
+ title="flags field (2 bits)"/>
+ <field id="MFF_NSH_TTL"
+ title="TTL field (6 bits)"/>
+ <field id="MFF_NSH_MDTYPE"
+ title="mdtype field (8 bits)"/>
+ <field id="MFF_NSH_NP"
+ title="np (next protocol) field (8 bits)"/>
+ <field id="MFF_NSH_SPI"
+ title="spi (service path identifier) field (24 bits)"/>
+ <field id="MFF_NSH_SI"
+ title="si (service index) field (8 bits)"/>
+ <field id="MFF_NSH_C1"
+ title="c1 (Network Platform Context) field (32 bits)"/>
+ <field id="MFF_NSH_C2"
+ title="c2 (Network Shared Context) field (32 bits)"/>
+ <field id="MFF_NSH_C3"
+ title="c3 (Service Platform Context) field (32 bits)"/>
+ <field id="MFF_NSH_C4"
+ title="c4 (Service Shared Context) field (32 bits)"/>
+ </group>
+
+
<group title="Layer 4: TCP, UDP, and SCTP">
<p>
For matching purposes, no distinction is made whether these protocols are
@@ -4567,6 +4655,13 @@ r r c c c.
Layer 3 Networks, '' <url href="https://tools.ietf.org/html/rfc7348"/>.
</dd>
+ <dt>RFC 7665</dt>
+ <dd>
+ J. Halpern, Ed. and C. Pignataro, Ed.,
+ ``Service Function Chaining (SFC) Architecture,''
+ <url href="https://tools.ietf.org/html/rfc7665"/>.
+ </dd>
+
<dt>Srinivasan</dt>
<dd>
V. Srinivasan, S. Suriy, and G. Varghese, ``Packet
diff --git a/lib/nx-match.c b/lib/nx-match.c
index 8f2a442..aa7691a 100644
--- a/lib/nx-match.c
+++ b/lib/nx-match.c
@@ -1022,6 +1022,7 @@ nx_put_raw(struct ofpbuf *b, enum ofp_version oxm, const struct match *match,
const struct flow *flow = &match->flow;
const size_t start_len = b->size;
ovs_be16 dl_type = get_dl_type(flow);
+ ovs_be32 spi_mask;
int match_len;
int i;
@@ -1157,13 +1158,22 @@ nx_put_raw(struct ofpbuf *b, enum ofp_version oxm, const struct match *match,
/* Network Service Header */
nxm_put_8m(&ctx, MFF_NSH_FLAGS, oxm, flow->nsh.flags,
match->wc.masks.nsh.flags);
+ nxm_put_8m(&ctx, MFF_NSH_TTL, oxm, flow->nsh.ttl,
+ match->wc.masks.nsh.ttl);
nxm_put_8m(&ctx, MFF_NSH_MDTYPE, oxm, flow->nsh.mdtype,
match->wc.masks.nsh.mdtype);
nxm_put_8m(&ctx, MFF_NSH_NP, oxm, flow->nsh.np,
match->wc.masks.nsh.np);
- nxm_put_32m(&ctx, MFF_NSH_SPI, oxm, flow->nsh.spi,
- match->wc.masks.nsh.spi);
- nxm_put_8m(&ctx, MFF_NSH_SI, oxm, flow->nsh.si, match->wc.masks.nsh.si);
+ spi_mask = nsh_path_hdr_to_spi(match->wc.masks.nsh.path_hdr);
+ if (spi_mask == htonl(NSH_SPI_MASK >> NSH_SPI_SHIFT)) {
+ spi_mask = OVS_BE32_MAX;
+ }
+ nxm_put_32m(&ctx, MFF_NSH_SPI, oxm,
+ nsh_path_hdr_to_spi(flow->nsh.path_hdr),
+ spi_mask);
+ nxm_put_8m(&ctx, MFF_NSH_SI, oxm,
+ nsh_path_hdr_to_si(flow->nsh.path_hdr),
+ nsh_path_hdr_to_si(match->wc.masks.nsh.path_hdr));
for (int i = 0; i < 4; i++) {
nxm_put_32m(&ctx, MFF_NSH_C1 + i, oxm, flow->nsh.context[i],
match->wc.masks.nsh.context[i]);
diff --git a/lib/odp-execute.c b/lib/odp-execute.c
index 7f9d419..c680364 100644
--- a/lib/odp-execute.c
+++ b/lib/odp-execute.c
@@ -274,19 +274,16 @@ odp_set_nd(struct dp_packet *packet, const struct ovs_key_nd *key,
/* Set the NSH header. Assumes the NSH header is present and matches the
* MD format of the key. The slow path must take case of that. */
static void
-odp_set_nsh(struct dp_packet *packet, const struct flow_nsh *key,
- const struct flow_nsh *mask)
+odp_set_nsh(struct dp_packet *packet, const struct ovs_key_nsh *key,
+ const struct ovs_key_nsh *mask)
{
struct nsh_hdr *nsh = dp_packet_l3(packet);
uint8_t mdtype = nsh_md_type(nsh);
ovs_be32 path_hdr;
if (!mask) {
- nsh->ver_flags_ttl_len = htons(key->flags << NSH_FLAGS_SHIFT) |
- (nsh->ver_flags_ttl_len & ~htons(NSH_FLAGS_MASK));
- path_hdr = htonl((ntohl(key->spi) << NSH_SPI_SHIFT) |
- key->si);
- put_16aligned_be32(&nsh->path_hdr, path_hdr);
+ nsh_set_flags_and_ttl(nsh, key->flags, key->ttl);
+ put_16aligned_be32(&nsh->path_hdr, key->path_hdr);
switch (mdtype) {
case NSH_M_TYPE1:
for (int i = 0; i < 4; i++) {
@@ -299,22 +296,25 @@ odp_set_nsh(struct dp_packet *packet, const struct flow_nsh *key,
break;
}
} else {
- uint8_t flags = (ntohs(nsh->ver_flags_ttl_len) & NSH_FLAGS_MASK) >>
- NSH_FLAGS_SHIFT;
+ uint8_t flags = nsh_get_flags(nsh);
+ uint8_t ttl = nsh_get_ttl(nsh);
+
flags = key->flags | (flags & ~mask->flags);
- nsh->ver_flags_ttl_len = htons(flags << NSH_FLAGS_SHIFT) |
- (nsh->ver_flags_ttl_len & ~htons(NSH_FLAGS_MASK));
+ ttl = key->ttl | (ttl & ~mask->ttl);
+ nsh_set_flags_and_ttl(nsh, flags, ttl);
- path_hdr = get_16aligned_be32(&nsh->path_hdr);
- uint32_t spi = (ntohl(path_hdr) & NSH_SPI_MASK) >> NSH_SPI_SHIFT;
- uint8_t si = (ntohl(path_hdr) & NSH_SI_MASK) >> NSH_SI_SHIFT;
- uint32_t spi_mask = ntohl(mask->spi);
+ uint32_t spi = ntohl(nsh_get_spi(nsh));
+ uint8_t si = nsh_get_si(nsh);
+ uint32_t spi_mask = nsh_path_hdr_to_spi_uint32(mask->path_hdr);
+ uint8_t si_mask = nsh_path_hdr_to_si(mask->path_hdr);
if (spi_mask == 0x00ffffff) {
spi_mask = UINT32_MAX;
}
- spi = ntohl(key->spi) | (spi & ~spi_mask);
- si = key->si | (si & ~mask->si);
- path_hdr = htonl((spi << NSH_SPI_SHIFT) | si);
+ spi = nsh_path_hdr_to_spi_uint32(key->path_hdr) | (spi & ~spi_mask);
+ si = nsh_path_hdr_to_si(key->path_hdr) | (si & ~si_mask);
+ path_hdr = nsh_get_path_hdr(nsh);
+ nsh_path_hdr_set_spi(&path_hdr, htonl(spi));
+ nsh_path_hdr_set_si(&path_hdr, si);
put_16aligned_be32(&nsh->path_hdr, path_hdr);
switch (mdtype) {
case NSH_M_TYPE1:
@@ -359,7 +359,7 @@ odp_execute_set_action(struct dp_packet *packet, const struct nlattr *a)
break;
case OVS_KEY_ATTR_NSH: {
- struct flow_nsh nsh;
+ struct ovs_key_nsh nsh;
odp_nsh_key_from_attr(a, &nsh);
odp_set_nsh(packet, &nsh, NULL);
break;
@@ -490,7 +490,7 @@ odp_execute_masked_set_action(struct dp_packet *packet,
break;
case OVS_KEY_ATTR_NSH: {
- struct flow_nsh nsh, nsh_mask;
+ struct ovs_key_nsh nsh, nsh_mask;
struct {
struct nlattr nla;
uint8_t data[sizeof(struct ovs_nsh_key_base) + NSH_CTX_HDRS_MAX_LEN
diff --git a/lib/odp-util.c b/lib/odp-util.c
index ff08821..69c34ca 100644
--- a/lib/odp-util.c
+++ b/lib/odp-util.c
@@ -246,12 +246,13 @@ static void
format_nsh_key(struct ds *ds, const struct ovs_key_nsh *key)
{
ds_put_format(ds, "flags=%d", key->flags);
+ ds_put_format(ds, "ttl=%d", key->ttl);
ds_put_format(ds, ",mdtype=%d", key->mdtype);
ds_put_format(ds, ",np=%d", key->np);
ds_put_format(ds, ",spi=0x%x",
- (ntohl(key->path_hdr) & NSH_SPI_MASK) >> NSH_SPI_SHIFT);
+ nsh_path_hdr_to_spi_uint32(key->path_hdr));
ds_put_format(ds, ",si=%d",
- (ntohl(key->path_hdr) & NSH_SI_MASK) >> NSH_SI_SHIFT);
+ nsh_path_hdr_to_si(key->path_hdr));
switch (key->mdtype) {
case NSH_M_TYPE1:
@@ -311,17 +312,16 @@ format_nsh_key_mask(struct ds *ds, const struct ovs_key_nsh *key,
format_nsh_key(ds, key);
} else {
bool first = true;
- uint32_t spi = (ntohl(key->path_hdr) & NSH_SPI_MASK) >> NSH_SPI_SHIFT;
- uint32_t spi_mask = (ntohl(mask->path_hdr) & NSH_SPI_MASK) >>
- NSH_SPI_SHIFT;
- if (spi_mask == 0x00ffffff) {
+ uint32_t spi = nsh_path_hdr_to_spi_uint32(key->path_hdr);
+ uint32_t spi_mask = nsh_path_hdr_to_spi_uint32(mask->path_hdr);
+ if (spi_mask == (NSH_SPI_MASK >> NSH_SPI_SHIFT)) {
spi_mask = UINT32_MAX;
}
- uint8_t si = (ntohl(key->path_hdr) & NSH_SI_MASK) >> NSH_SI_SHIFT;
- uint8_t si_mask = (ntohl(mask->path_hdr) & NSH_SI_MASK) >>
- NSH_SI_SHIFT;
+ uint8_t si = nsh_path_hdr_to_si(key->path_hdr);
+ uint8_t si_mask = nsh_path_hdr_to_si(mask->path_hdr);
format_uint8_masked(ds, &first, "flags", key->flags, mask->flags);
+ format_uint8_masked(ds, &first, "ttl", key->ttl, mask->ttl);
format_uint8_masked(ds, &first, "mdtype", key->mdtype, mask->mdtype);
format_uint8_masked(ds, &first, "np", key->np, mask->np);
format_be32_masked(ds, &first, "spi", htonl(spi), htonl(spi_mask));
@@ -342,13 +342,14 @@ format_odp_push_nsh_action(struct ds *ds,
const struct nsh_hdr *nsh_hdr)
{
size_t mdlen = nsh_hdr_len(nsh_hdr) - NSH_BASE_HDR_LEN;
- uint32_t path_hdr = ntohl(get_16aligned_be32(&nsh_hdr->path_hdr));
- uint32_t spi = (path_hdr & NSH_SPI_MASK) >> NSH_SPI_SHIFT;
- uint8_t si = (path_hdr & NSH_SI_MASK) >> NSH_SI_SHIFT;
+ uint32_t spi = ntohl(nsh_get_spi(nsh_hdr));
+ uint8_t si = nsh_get_si(nsh_hdr);
uint8_t flags = nsh_get_flags(nsh_hdr);
+ uint8_t ttl = nsh_get_ttl(nsh_hdr);
ds_put_cstr(ds, "push_nsh(");
ds_put_format(ds, "flags=%d", flags);
+ ds_put_format(ds, ",ttl=%d", ttl);
ds_put_format(ds, ",mdtype=%d", nsh_hdr->md_type);
ds_put_format(ds, ",np=%d", nsh_hdr->next_proto);
ds_put_format(ds, ",spi=0x%x", spi);
@@ -1785,7 +1786,7 @@ find_end:
}
static void
-nsh_key_to_attr(struct ofpbuf *buf, const struct flow_nsh *nsh,
+nsh_key_to_attr(struct ofpbuf *buf, const struct ovs_key_nsh *nsh,
uint8_t * metadata, size_t md_size,
bool is_mask)
{
@@ -1793,10 +1794,10 @@ nsh_key_to_attr(struct ofpbuf *buf, const struct flow_nsh *nsh,
struct ovs_nsh_key_base base;
base.flags = nsh->flags;
+ base.ttl = nsh->ttl;
base.mdtype = nsh->mdtype;
base.np = nsh->np;
- base.path_hdr = htonl((ntohl(nsh->spi) << NSH_SPI_SHIFT) |
- nsh->si);
+ base.path_hdr = nsh->path_hdr;
nsh_key_ofs = nl_msg_start_nested(buf, OVS_KEY_ATTR_NSH);
nl_msg_put_unspec(buf, OVS_NSH_KEY_ATTR_BASE, &base, sizeof base);
@@ -1831,8 +1832,9 @@ parse_odp_push_nsh_action(const char *s, struct ofpbuf *actions)
int n = 0;
int ret = 0;
uint32_t spi = 0;
+ uint8_t si = 255;
uint32_t cd;
- struct flow_nsh nsh;
+ struct ovs_key_nsh nsh;
uint8_t metadata[NSH_CTX_HDRS_MAX_LEN];
uint8_t md_size = 0;
@@ -1843,10 +1845,10 @@ parse_odp_push_nsh_action(const char *s, struct ofpbuf *actions)
/* The default is NSH_M_TYPE1 */
nsh.flags = 0;
+ nsh.ttl = 63;
nsh.mdtype = NSH_M_TYPE1;
nsh.np = NSH_P_ETHERNET;
- nsh.spi = 0;
- nsh.si = 255;
+ nsh.path_hdr = nsh_spi_si_to_path_hdr(0, 255);
memset(nsh.context, 0, NSH_M_TYPE1_MDLEN);
for (;;) {
@@ -1858,6 +1860,9 @@ parse_odp_push_nsh_action(const char *s, struct ofpbuf *actions)
if (ovs_scan_len(s, &n, "flags=%"SCNi8, &nsh.flags)) {
continue;
}
+ if (ovs_scan_len(s, &n, "ttl=%"SCNi8, &nsh.ttl)) {
+ continue;
+ }
if (ovs_scan_len(s, &n, "mdtype=%"SCNi8, &nsh.mdtype)) {
switch (nsh.mdtype) {
case NSH_M_TYPE1:
@@ -1877,10 +1882,9 @@ parse_odp_push_nsh_action(const char *s, struct ofpbuf *actions)
continue;
}
if (ovs_scan_len(s, &n, "spi=0x%"SCNx32, &spi)) {
- nsh.spi = htonl(spi);
continue;
}
- if (ovs_scan_len(s, &n, "si=%"SCNi8, &nsh.si)) {
+ if (ovs_scan_len(s, &n, "si=%"SCNi8, &si)) {
continue;
}
if (nsh.mdtype == NSH_M_TYPE1) {
@@ -1925,6 +1929,7 @@ parse_odp_push_nsh_action(const char *s, struct ofpbuf *actions)
}
out:
if (ret >= 0) {
+ nsh.path_hdr = nsh_spi_si_to_path_hdr(spi, si);
size_t offset = nl_msg_start_nested(actions, OVS_ACTION_ATTR_PUSH_NSH);
nsh_key_to_attr(actions, &nsh, metadata, md_size, false);
nl_msg_end_nested(actions, offset);
@@ -2352,6 +2357,7 @@ odp_nsh_hdr_from_attr(const struct nlattr *attr,
const struct nlattr *a;
bool unknown = false;
uint8_t flags = 0;
+ uint8_t ttl = 63;
size_t mdlen = 0;
bool has_md1 = false;
bool has_md2 = false;
@@ -2373,6 +2379,7 @@ odp_nsh_hdr_from_attr(const struct nlattr *attr,
nsh_hdr->md_type = base->mdtype;
put_16aligned_be32(&nsh_hdr->path_hdr, base->path_hdr);
flags = base->flags;
+ ttl = base->ttl;
break;
}
case OVS_NSH_KEY_ATTR_MD1: {
@@ -2416,14 +2423,13 @@ odp_nsh_hdr_from_attr(const struct nlattr *attr,
}
/* nsh header length = NSH_BASE_HDR_LEN + mdlen */
- nsh_hdr->ver_flags_ttl_len = htons(flags << NSH_FLAGS_SHIFT |
- (NSH_BASE_HDR_LEN + mdlen) >> 2);
+ nsh_set_flags_ttl_len(nsh_hdr, flags, ttl, NSH_BASE_HDR_LEN + mdlen);
return ODP_FIT_PERFECT;
}
enum odp_key_fitness
-odp_nsh_key_from_attr(const struct nlattr *attr, struct flow_nsh *nsh)
+odp_nsh_key_from_attr(const struct nlattr *attr, struct ovs_key_nsh *nsh)
{
unsigned int left;
const struct nlattr *a;
@@ -2444,11 +2450,10 @@ odp_nsh_key_from_attr(const struct nlattr *attr, struct flow_nsh *nsh)
case OVS_NSH_KEY_ATTR_BASE: {
const struct ovs_nsh_key_base *base = nl_attr_get(a);
nsh->flags = base->flags;
+ nsh->ttl = base->ttl;
nsh->mdtype = base->mdtype;
nsh->np = base->np;
- nsh->spi = htonl((ntohl(base->path_hdr) & NSH_SPI_MASK) >>
- NSH_SPI_SHIFT);
- nsh->si = (ntohl(base->path_hdr) & NSH_SI_MASK) >> NSH_SI_SHIFT;
+ nsh->path_hdr = base->path_hdr;
break;
}
case OVS_NSH_KEY_ATTR_MD1: {
@@ -3197,15 +3202,17 @@ format_odp_nsh_attr(const struct nlattr *attr, const struct nlattr *mask_attr,
case OVS_NSH_KEY_ATTR_UNSPEC:
break;
case OVS_NSH_KEY_ATTR_BASE: {
- const struct ovs_nsh_key_base * base = nl_attr_get(a);
- const struct ovs_nsh_key_base * base_mask
+ const struct ovs_nsh_key_base *base = nl_attr_get(a);
+ const struct ovs_nsh_key_base *base_mask
= ma ? nl_attr_get(ma) : NULL;
nsh.flags = base->flags;
+ nsh.ttl = base->ttl;
nsh.mdtype = base->mdtype;
nsh.np = base->np;
nsh.path_hdr = base->path_hdr;
if (base_mask) {
nsh_mask.flags = base_mask->flags;
+ nsh_mask.ttl = base_mask->ttl;
nsh_mask.mdtype = base_mask->mdtype;
nsh_mask.np = base_mask->np;
nsh_mask.path_hdr = base_mask->path_hdr;
@@ -3213,8 +3220,8 @@ format_odp_nsh_attr(const struct nlattr *attr, const struct nlattr *mask_attr,
break;
}
case OVS_NSH_KEY_ATTR_MD1: {
- const struct ovs_nsh_key_md1 * md1 = nl_attr_get(a);
- const struct ovs_nsh_key_md1 * md1_mask
+ const struct ovs_nsh_key_md1 *md1 = nl_attr_get(a);
+ const struct ovs_nsh_key_md1 *md1_mask
= ma ? nl_attr_get(ma) : NULL;
memcpy(nsh.context, md1->context, sizeof md1->context);
if (md1_mask) {
@@ -4822,7 +4829,9 @@ parse_odp_nsh_key_mask_attr(const char *s, struct ofpbuf *key,
if (strncmp(s, "nsh(", 4) == 0) {
const char *start = s;
int len;
- struct flow_nsh skey, smask;
+ struct ovs_key_nsh skey, smask;
+ uint32_t spi = 0, spi_mask = 0;
+ uint8_t si = 0, si_mask = 0;
s += 4;
@@ -4863,7 +4872,7 @@ parse_odp_nsh_key_mask_attr(const char *s, struct ofpbuf *key,
if (strncmp(s, "spi=", 4) == 0) {
s += 4;
- len = scan_be32(s, &skey.spi, mask ? &smask.spi : NULL);
+ len = scan_u32(s, &spi, mask ? &spi_mask : NULL);
if (len == 0) {
return -EINVAL;
}
@@ -4873,7 +4882,7 @@ parse_odp_nsh_key_mask_attr(const char *s, struct ofpbuf *key,
if (strncmp(s, "si=", 3) == 0) {
s += 3;
- len = scan_u8(s, &skey.si, mask ? &smask.si : NULL);
+ len = scan_u8(s, &si, mask ? &si_mask : NULL);
if (len == 0) {
return -EINVAL;
}
@@ -4929,6 +4938,9 @@ parse_odp_nsh_key_mask_attr(const char *s, struct ofpbuf *key,
return -EINVAL;
}
+ skey.path_hdr = nsh_spi_si_to_path_hdr(spi, si);
+ smask.path_hdr = nsh_spi_si_to_path_hdr(spi_mask, si_mask);
+
nsh_key_to_attr(key, &skey, NULL, 0, false);
if (mask) {
nsh_key_to_attr(mask, &smask, NULL, 0, true);
@@ -6990,59 +7002,29 @@ commit_set_nw_action(const struct flow *flow, struct flow *base,
return 0;
}
-static void
+static inline void
get_nsh_key(const struct flow *flow, struct ovs_key_nsh *nsh, bool is_mask)
{
- nsh->flags = flow->nsh.flags;
- nsh->mdtype = flow->nsh.mdtype;
- nsh->np = flow->nsh.np;
- nsh->path_hdr = htonl((ntohl(flow->nsh.spi) << NSH_SPI_SHIFT) |
- flow->nsh.si);
- if (is_mask) {
- for (int i = 0; i < 4; i++) {
- nsh->context[i] = flow->nsh.context[i];
- }
- } else {
- switch (nsh->mdtype) {
- case NSH_M_TYPE1:
- for (int i = 0; i < 4; i++) {
- nsh->context[i] = flow->nsh.context[i];
- }
- break;
- case NSH_M_TYPE2:
- default:
- /* No match support for other MD formats yet. */
- break;
+ *nsh = flow->nsh;
+ if (!is_mask) {
+ if (nsh->mdtype != NSH_M_TYPE1) {
+ memset(nsh->context, 0, sizeof(nsh->context));
}
}
}
-static void
+static inline void
put_nsh_key(const struct ovs_key_nsh *nsh, struct flow *flow,
bool is_mask OVS_UNUSED)
{
- flow->nsh.flags = nsh->flags;
- flow->nsh.mdtype = nsh->mdtype;
- flow->nsh.np = nsh->np;
- flow->nsh.spi = htonl((ntohl(nsh->path_hdr) & NSH_SPI_MASK) >>
- NSH_SPI_SHIFT);
- flow->nsh.si = (ntohl(nsh->path_hdr) & NSH_SI_MASK) >> NSH_SI_SHIFT;
- switch (nsh->mdtype) {
- case NSH_M_TYPE1:
- for (int i = 0; i < 4; i++) {
- flow->nsh.context[i] = nsh->context[i];
- }
- break;
- case NSH_M_TYPE2:
- default:
- /* No match support for other MD formats yet. */
- memset(flow->nsh.context, 0, sizeof flow->nsh.context);
- break;
+ flow->nsh = *nsh;
+ if (flow->nsh.mdtype != NSH_M_TYPE1) {
+ memset(flow->nsh.context, 0, sizeof(flow->nsh.context));
}
}
static bool
-commit_nsh(const struct flow_nsh * flow_nsh, bool use_masked_set,
+commit_nsh(const struct ovs_key_nsh * flow_nsh, bool use_masked_set,
const struct ovs_key_nsh *key, struct ovs_key_nsh *base,
struct ovs_key_nsh *mask, size_t size,
struct ofpbuf *odp_actions)
@@ -7068,11 +7050,13 @@ commit_nsh(const struct flow_nsh * flow_nsh, bool use_masked_set,
OVS_ACTION_ATTR_SET_MASKED);
nsh_base.flags = key->flags;
+ nsh_base.ttl = key->ttl;
nsh_base.mdtype = key->mdtype;
nsh_base.np = key->np;
nsh_base.path_hdr = key->path_hdr;
nsh_base_mask.flags = mask->flags;
+ nsh_base_mask.ttl = mask->ttl;
nsh_base_mask.mdtype = mask->mdtype;
nsh_base_mask.np = mask->np;
nsh_base_mask.path_hdr = mask->path_hdr;
diff --git a/lib/odp-util.h b/lib/odp-util.h
index f7ce206..fafea62 100644
--- a/lib/odp-util.h
+++ b/lib/odp-util.h
@@ -159,7 +159,7 @@ struct odputil_keybuf {
enum odp_key_fitness odp_tun_key_from_attr(const struct nlattr *,
struct flow_tnl *);
enum odp_key_fitness odp_nsh_key_from_attr(const struct nlattr *,
- struct flow_nsh *);
+ struct ovs_key_nsh *);
enum odp_key_fitness odp_nsh_hdr_from_attr(const struct nlattr *,
struct nsh_hdr *, size_t size);
diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c
index c77477c..2f0a19c 100644
--- a/ofproto/ofproto-dpif-xlate.c
+++ b/ofproto/ofproto-dpif-xlate.c
@@ -5935,10 +5935,10 @@ rewrite_flow_push_nsh(struct xlate_ctx *ctx,
/* Populate the flow with the new NSH header. */
flow->packet_type = htonl(PT_NSH);
flow->dl_type = htons(ETH_TYPE_NSH);
- flow->nsh.flags = 0; /* */
+ flow->nsh.flags = 0;
+ flow->nsh.ttl = 63;
flow->nsh.np = np;
- flow->nsh.spi = 0;
- flow->nsh.si = 255;
+ flow->nsh.path_hdr = htonl(255);
if (md_type == NSH_M_TYPE1) {
flow->nsh.mdtype = NSH_M_TYPE1;
@@ -5951,6 +5951,7 @@ rewrite_flow_push_nsh(struct xlate_ctx *ctx,
} else if (md_type == NSH_M_TYPE2) {
flow->nsh.mdtype = NSH_M_TYPE2;
}
+ flow->nsh.mdtype &= NSH_MDTYPE_MASK;
return buf;
}
diff --git a/tests/nsh.at b/tests/nsh.at
index bec6e87..6177cea 100644
--- a/tests/nsh.at
+++ b/tests/nsh.at
@@ -13,7 +13,7 @@ OVS_VSWITCHD_START([dnl
add-port br0 p2 -- set Interface p2 type=dummy ofport_request=2])
AT_DATA([flows.txt], [dnl
- table=0,in_port=1,dl_type=0x894f,nsh_mdtype=1,nsh_np=3,nsh_spi=0x123456,nsh_si=255,nsh_c1=0x11223344,actions=set_field:0x80->nsh_flags,set_field:254->nsh_si,set_field:0x44332211->nsh_c1,2
+ table=0,in_port=1,dl_type=0x894f,nsh_ttl=63,nsh_mdtype=1,nsh_np=3,nsh_spi=0x123456,nsh_si=255,nsh_c1=0x11223344,actions=set_field:0x2->nsh_flags,set_field:254->nsh_si,set_field:0x44332211->nsh_c1,2
])
AT_CHECK([
@@ -21,25 +21,25 @@ AT_CHECK([
ovs-ofctl -Oopenflow13 add-flows br0 flows.txt
ovs-ofctl -Oopenflow13 dump-flows br0 | ofctl_strip | sort | grep actions
], [0], [dnl
- in_port=1,dl_type=0x894f,nsh_mdtype=1,nsh_np=3,nsh_spi=0x123456,nsh_si=255,nsh_c1=0x11223344 actions=set_field:128->nsh_flags,set_field:254->nsh_si,set_field:0x44332211->nsh_c1,output:2
+ in_port=1,dl_type=0x894f,nsh_ttl=63,nsh_mdtype=1,nsh_np=3,nsh_spi=0x123456,nsh_si=255,nsh_c1=0x11223344 actions=set_field:2->nsh_flags,set_field:254->nsh_si,set_field:0x44332211->nsh_c1,output:2
])
AT_CHECK([
- ovs-appctl ofproto/trace br0 'in_port=1,dl_type=0x894f,nsh_mdtype=1,nsh_np=3,nsh_spi=0x123456,nsh_si=255,nsh_c1=0x11223344,nsh_c2=0x55667788,nsh_c3=0x99aabbcc,nsh_c4=0xddeeff00'
+ ovs-appctl ofproto/trace br0 'in_port=1,dl_type=0x894f,nsh_ttl=63,nsh_mdtype=1,nsh_np=3,nsh_spi=0x123456,nsh_si=255,nsh_c1=0x11223344,nsh_c2=0x55667788,nsh_c3=0x99aabbcc,nsh_c4=0xddeeff00'
], [0], [dnl
-Flow: in_port=1,vlan_tci=0x0000,dl_src=00:00:00:00:00:00,dl_dst=00:00:00:00:00:00,dl_type=0x894f,nsh_flags=0,nsh_mdtype=1,nsh_np=3,nsh_spi=0x123456,nsh_si=255,nsh_c1=0x11223344,nsh_c2=0x55667788,nsh_c3=0x99aabbcc,nsh_c4=0xddeeff00,nw_proto=0,nw_tos=0,nw_ecn=0,nw_ttl=0
+Flow: in_port=1,vlan_tci=0x0000,dl_src=00:00:00:00:00:00,dl_dst=00:00:00:00:00:00,dl_type=0x894f,nsh_flags=0,nsh_ttl=63,nsh_mdtype=1,nsh_np=3,nsh_spi=0x123456,nsh_si=255,nsh_c1=0x11223344,nsh_c2=0x55667788,nsh_c3=0x99aabbcc,nsh_c4=0xddeeff00,nw_proto=0,nw_tos=0,nw_ecn=0,nw_ttl=0
bridge("br0")
-------------
- 0. in_port=1,dl_type=0x894f,nsh_mdtype=1,nsh_np=3,nsh_spi=0x123456,nsh_si=255,nsh_c1=0x11223344, priority 32768
- set_field:128->nsh_flags
+ 0. in_port=1,dl_type=0x894f,nsh_ttl=63,nsh_mdtype=1,nsh_np=3,nsh_spi=0x123456,nsh_si=255,nsh_c1=0x11223344, priority 32768
+ set_field:2->nsh_flags
set_field:254->nsh_si
set_field:0x44332211->nsh_c1
output:2
-Final flow: in_port=1,vlan_tci=0x0000,dl_src=00:00:00:00:00:00,dl_dst=00:00:00:00:00:00,dl_type=0x894f,nsh_flags=128,nsh_mdtype=1,nsh_np=3,nsh_spi=0x123456,nsh_si=254,nsh_c1=0x44332211,nsh_c2=0x55667788,nsh_c3=0x99aabbcc,nsh_c4=0xddeeff00,nw_proto=0,nw_tos=0,nw_ecn=0,nw_ttl=0
-Megaflow: recirc_id=0,eth,in_port=1,dl_type=0x894f,nsh_flags=0,nsh_mdtype=1,nsh_np=3,nsh_spi=0x123456,nsh_si=255,nsh_c1=0x11223344
-Datapath actions: set(nsh(flags=128,spi=0x123456,si=254,c1=0x44332211)),2
+Final flow: in_port=1,vlan_tci=0x0000,dl_src=00:00:00:00:00:00,dl_dst=00:00:00:00:00:00,dl_type=0x894f,nsh_flags=2,nsh_ttl=63,nsh_mdtype=1,nsh_np=3,nsh_spi=0x123456,nsh_si=254,nsh_c1=0x44332211,nsh_c2=0x55667788,nsh_c3=0x99aabbcc,nsh_c4=0xddeeff00,nw_proto=0,nw_tos=0,nw_ecn=0,nw_ttl=0
+Megaflow: recirc_id=0,eth,in_port=1,dl_type=0x894f,nsh_flags=0,nsh_ttl=63,nsh_mdtype=1,nsh_np=3,nsh_spi=0x123456,nsh_si=255,nsh_c1=0x11223344
+Datapath actions: set(nsh(flags=2,ttl=63,spi=0x123456,si=254,c1=0x44332211)),2
])
OVS_VSWITCHD_STOP
@@ -103,15 +103,15 @@ bridge("br0")
decap()
decap()
-Final flow: in_port=1,vlan_tci=0x0000,dl_src=00:00:00:00:00:00,dl_dst=11:22:33:44:55:66,dl_type=0x894f,nsh_flags=0,nsh_mdtype=1,nsh_np=3,nsh_spi=0x1234,nsh_si=255,nsh_c1=0x11223344,nsh_c2=0x0,nsh_c3=0x0,nsh_c4=0x0,nw_proto=0,nw_tos=0,nw_ecn=0,nw_ttl=0
+Final flow: in_port=1,vlan_tci=0x0000,dl_src=00:00:00:00:00:00,dl_dst=11:22:33:44:55:66,dl_type=0x894f,nsh_flags=0,nsh_ttl=63,nsh_mdtype=1,nsh_np=3,nsh_spi=0x1234,nsh_si=255,nsh_c1=0x11223344,nsh_c2=0x0,nsh_c3=0x0,nsh_c4=0x0,nw_proto=0,nw_tos=0,nw_ecn=0,nw_ttl=0
Megaflow: recirc_id=0,eth,ip,in_port=1,dl_dst=66:77:88:99:aa:bb,nw_frag=no
-Datapath actions: push_nsh(flags=0,mdtype=1,np=3,spi=0x1234,si=255,c1=0x11223344,c2=0x0,c3=0x0,c4=0x0),push_eth(src=00:00:00:00:00:00,dst=11:22:33:44:55:66),pop_eth,pop_nsh(),set(eth(dst=11:22:33:44:55:66)),recirc(0x1)
+Datapath actions: push_nsh(flags=0,ttl=63,mdtype=1,np=3,spi=0x1234,si=255,c1=0x11223344,c2=0x0,c3=0x0,c4=0x0),push_eth(src=00:00:00:00:00:00,dst=11:22:33:44:55:66),pop_eth,pop_nsh(),set(eth(dst=11:22:33:44:55:66)),recirc(0x1)
])
AT_CHECK([
ovs-appctl ofproto/trace br0 'in_port=4,dl_type=0x894f,nsh_mdtype=1,nsh_np=3,nsh_spi=0x1234,nsh_c1=0x11223344'
], [0], [dnl
-Flow: in_port=4,vlan_tci=0x0000,dl_src=00:00:00:00:00:00,dl_dst=00:00:00:00:00:00,dl_type=0x894f,nsh_flags=0,nsh_mdtype=1,nsh_np=3,nsh_spi=0x1234,nsh_si=0,nsh_c1=0x11223344,nsh_c2=0x0,nsh_c3=0x0,nsh_c4=0x0,nw_proto=0,nw_tos=0,nw_ecn=0,nw_ttl=0
+Flow: in_port=4,vlan_tci=0x0000,dl_src=00:00:00:00:00:00,dl_dst=00:00:00:00:00:00,dl_type=0x894f,nsh_flags=0,nsh_ttl=0,nsh_mdtype=1,nsh_np=3,nsh_spi=0x1234,nsh_si=0,nsh_c1=0x11223344,nsh_c2=0x0,nsh_c3=0x0,nsh_c4=0x0,nw_proto=0,nw_tos=0,nw_ecn=0,nw_ttl=0
bridge("br0")
-------------
@@ -139,7 +139,7 @@ ovs-appctl time/warp 1000
AT_CHECK([
ovs-appctl dpctl/dump-flows dummy at ovs-dummy | strip_used | grep -v ipv6 | sort
], [0], [flow-dump from non-dpdk interfaces:
-recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth(dst=1e:2c:e9:2a:66:9e),eth_type(0x0800),ipv4(frag=no), packets:1, bytes:98, used:0.0s, actions:push_nsh(flags=0,mdtype=1,np=3,spi=0x1234,si=255,c1=0x11223344,c2=0x0,c3=0x0,c4=0x0),push_eth(src=00:00:00:00:00:00,dst=11:22:33:44:55:66),pop_eth,pop_nsh(),set(eth(dst=11:22:33:44:55:66)),recirc(0x3)
+recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth(dst=1e:2c:e9:2a:66:9e),eth_type(0x0800),ipv4(frag=no), packets:1, bytes:98, used:0.0s, actions:push_nsh(flags=0,ttl=63,mdtype=1,np=3,spi=0x1234,si=255,c1=0x11223344,c2=0x0,c3=0x0,c4=0x0),push_eth(src=00:00:00:00:00:00,dst=11:22:33:44:55:66),pop_eth,pop_nsh(),set(eth(dst=11:22:33:44:55:66)),recirc(0x3)
recirc_id(0x3),in_port(1),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(frag=no), packets:1, bytes:98, used:0.0s, actions:2
])
@@ -172,7 +172,7 @@ ovs-appctl time/warp 1000
AT_CHECK([
ovs-appctl dpctl/dump-flows dummy at ovs-dummy | strip_used | grep -v ipv6 | sort
], [0], [flow-dump from non-dpdk interfaces:
-recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(frag=no), packets:1, bytes:98, used:0.0s, actions:push_vlan(vid=100,pcp=0),push_nsh(flags=0,mdtype=1,np=3,spi=0x0,si=255,c1=0x0,c2=0x0,c3=0x0,c4=0x0),pop_nsh(),recirc(0x4)
+recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(frag=no), packets:1, bytes:98, used:0.0s, actions:push_vlan(vid=100,pcp=0),push_nsh(flags=0,ttl=63,mdtype=1,np=3,spi=0x0,si=255,c1=0x0,c2=0x0,c3=0x0,c4=0x0),pop_nsh(),recirc(0x4)
recirc_id(0x4),in_port(1),packet_type(ns=0,id=0),eth_type(0x8100),vlan(vid=100,pcp=0),encap(eth_type(0x0800),ipv4(frag=no)), packets:1, bytes:102, used:0.0s, actions:2
])
@@ -230,15 +230,15 @@ bridge("br0")
decap()
decap()
-Final flow: in_port=1,vlan_tci=0x0000,dl_src=00:00:00:00:00:00,dl_dst=11:22:33:44:55:66,dl_type=0x894f,nsh_flags=0,nsh_mdtype=2,nsh_np=3,nsh_spi=0x1234,nsh_si=255,nw_proto=0,nw_tos=0,nw_ecn=0,nw_ttl=0
+Final flow: in_port=1,vlan_tci=0x0000,dl_src=00:00:00:00:00:00,dl_dst=11:22:33:44:55:66,dl_type=0x894f,nsh_flags=0,nsh_ttl=63,nsh_mdtype=2,nsh_np=3,nsh_spi=0x1234,nsh_si=255,nw_proto=0,nw_tos=0,nw_ecn=0,nw_ttl=0
Megaflow: recirc_id=0,eth,ip,in_port=1,dl_dst=66:77:88:99:aa:bb,nw_frag=no
-Datapath actions: push_nsh(flags=0,mdtype=2,np=3,spi=0x1234,si=255,md2=0x10000a041234567820001408fedcba9876543210),push_eth(src=00:00:00:00:00:00,dst=11:22:33:44:55:66),pop_eth,pop_nsh(),set(eth(dst=11:22:33:44:55:66)),recirc(0x1)
+Datapath actions: push_nsh(flags=0,ttl=63,mdtype=2,np=3,spi=0x1234,si=255,md2=0x10000a041234567820001408fedcba9876543210),push_eth(src=00:00:00:00:00:00,dst=11:22:33:44:55:66),pop_eth,pop_nsh(),set(eth(dst=11:22:33:44:55:66)),recirc(0x1)
])
AT_CHECK([
ovs-appctl ofproto/trace br0 'in_port=4,dl_type=0x894f,nsh_mdtype=2,nsh_np=3,nsh_spi=0x1234'
], [0], [dnl
-Flow: in_port=4,vlan_tci=0x0000,dl_src=00:00:00:00:00:00,dl_dst=00:00:00:00:00:00,dl_type=0x894f,nsh_flags=0,nsh_mdtype=2,nsh_np=3,nsh_spi=0x1234,nsh_si=0,nw_proto=0,nw_tos=0,nw_ecn=0,nw_ttl=0
+Flow: in_port=4,vlan_tci=0x0000,dl_src=00:00:00:00:00:00,dl_dst=00:00:00:00:00:00,dl_type=0x894f,nsh_flags=0,nsh_ttl=0,nsh_mdtype=2,nsh_np=3,nsh_spi=0x1234,nsh_si=0,nw_proto=0,nw_tos=0,nw_ecn=0,nw_ttl=0
bridge("br0")
-------------
@@ -266,7 +266,7 @@ ovs-appctl time/warp 1000
AT_CHECK([
ovs-appctl dpctl/dump-flows dummy at ovs-dummy | strip_used | grep -v ipv6 | sort
], [0], [flow-dump from non-dpdk interfaces:
-recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth(dst=1e:2c:e9:2a:66:9e),eth_type(0x0800),ipv4(frag=no), packets:1, bytes:98, used:0.0s, actions:push_nsh(flags=0,mdtype=2,np=3,spi=0x1234,si=255,md2=0x10000a041234567820001408fedcba9876543210),push_eth(src=00:00:00:00:00:00,dst=11:22:33:44:55:66),pop_eth,pop_nsh(),set(eth(dst=11:22:33:44:55:66)),recirc(0x3)
+recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth(dst=1e:2c:e9:2a:66:9e),eth_type(0x0800),ipv4(frag=no), packets:1, bytes:98, used:0.0s, actions:push_nsh(flags=0,ttl=63,mdtype=2,np=3,spi=0x1234,si=255,md2=0x10000a041234567820001408fedcba9876543210),push_eth(src=00:00:00:00:00:00,dst=11:22:33:44:55:66),pop_eth,pop_nsh(),set(eth(dst=11:22:33:44:55:66)),recirc(0x3)
recirc_id(0x3),in_port(1),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(frag=no), packets:1, bytes:98, used:0.0s, actions:2
])
@@ -575,11 +575,12 @@ AT_CHECK([
ovs-appctl time/warp 1000
ovs-appctl time/warp 1000
+ovs-appctl time/warp 1000
AT_CHECK([
ovs-appctl dpctl/dump-flows dummy at ovs-dummy | strip_used | grep -v ipv6 | sort
], [0], [flow-dump from non-dpdk interfaces:
-recirc_id(0),in_port(4),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(dst=192.168.10.30,frag=no), packets:1, bytes:98, used:0.0s, actions:pop_eth,push_nsh(flags=0,mdtype=1,np=1,spi=0x3000,si=255,c1=0x0,c2=0x0,c3=0x0,c4=0x0),clone(tnl_push(tnl_port(4789),header(size=50,type=4,eth(dst=aa:55:00:00:00:03,src=aa:55:00:00:00:01,dl_type=0x0800),ipv4(src=10.0.0.1,dst=10.0.0.3,proto=17,tos=0,ttl=64,frag=0x4000),udp(src=0,dst=4789,csum=0x0),vxlan(flags=0xc000004,vni=0x0)),out_port(1)),set(ipv4(src=30.0.0.1,dst=30.0.0.3)),tnl_pop(4789))
+recirc_id(0),in_port(4),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(dst=192.168.10.30,frag=no), packets:1, bytes:98, used:0.0s, actions:pop_eth,push_nsh(flags=0,ttl=63,mdtype=1,np=1,spi=0x3000,si=255,c1=0x0,c2=0x0,c3=0x0,c4=0x0),clone(tnl_push(tnl_port(4789),header(size=50,type=4,eth(dst=aa:55:00:00:00:03,src=aa:55:00:00:00:01,dl_type=0x0800),ipv4(src=10.0.0.1,dst=10.0.0.3,proto=17,tos=0,ttl=64,frag=0x4000),udp(src=0,dst=4789,csum=0x0),vxlan(flags=0xc000004,vni=0x0)),out_port(1)),set(ipv4(src=30.0.0.1,dst=30.0.0.3)),tnl_pop(4789))
tunnel(tun_id=0x0,src=30.0.0.1,dst=30.0.0.3,flags(-df-csum+key)),recirc_id(0),in_port(4789),packet_type(ns=1,id=0x894f),nsh(np=1,spi=0x3000,si=255), packets:1, bytes:108, used:0.0s, actions:pop_nsh(),recirc(0x1)
tunnel(tun_id=0x0,src=30.0.0.1,dst=30.0.0.3,flags(-df-csum+key)),recirc_id(0x1),in_port(4789),packet_type(ns=1,id=0x800),ipv4(frag=no), packets:1, bytes:84, used:0.0s, actions:push_eth(src=00:00:00:00:00:00,dst=aa:55:aa:55:00:03),6
])
@@ -633,7 +634,7 @@ ovs-appctl time/warp 1000
AT_CHECK([
ovs-appctl dpctl/dump-flows dummy at ovs-dummy | strip_used | grep -v ipv6 | sort
], [0], [flow-dump from non-dpdk interfaces:
-recirc_id(0),in_port(4),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(dst=192.168.10.20/255.255.255.248,frag=no), packets:1, bytes:98, used:0.0s, actions:pop_eth,push_nsh(flags=0,mdtype=1,np=1,spi=0x3020,si=255,c1=0x0,c2=0x0,c3=0x0,c4=0x0),clone(tnl_push(tnl_port(4789),header(size=50,type=4,eth(dst=aa:55:00:00:00:02,src=aa:55:00:00:00:01,dl_type=0x0800),ipv4(src=10.0.0.1,dst=10.0.0.2,proto=17,tos=0,ttl=64,frag=0x4000),udp(src=0,dst=4789,csum=0x0),vxlan(flags=0xc000004,vni=0x0)),out_port(1)),set(ipv4(src=20.0.0.1,dst=20.0.0.2)),tnl_pop(4789))
+recirc_id(0),in_port(4),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(dst=192.168.10.20/255.255.255.248,frag=no), packets:1, bytes:98, used:0.0s, actions:pop_eth,push_nsh(flags=0,ttl=63,mdtype=1,np=1,spi=0x3020,si=255,c1=0x0,c2=0x0,c3=0x0,c4=0x0),clone(tnl_push(tnl_port(4789),header(size=50,type=4,eth(dst=aa:55:00:00:00:02,src=aa:55:00:00:00:01,dl_type=0x0800),ipv4(src=10.0.0.1,dst=10.0.0.2,proto=17,tos=0,ttl=64,frag=0x4000),udp(src=0,dst=4789,csum=0x0),vxlan(flags=0xc000004,vni=0x0)),out_port(1)),set(ipv4(src=20.0.0.1,dst=20.0.0.2)),tnl_pop(4789))
tunnel(tun_id=0x0,src=20.0.0.1,dst=20.0.0.2,flags(-df-csum+key)),recirc_id(0),in_port(4789),packet_type(ns=1,id=0x894f),nsh(spi=0x3020,si=255), packets:1, bytes:108, used:0.0s, actions:push_eth(src=00:00:00:00:00:00,dst=11:22:33:44:55:66),set(nsh(spi=0x3020,si=254)),pop_eth,clone(tnl_push(tnl_port(4789),header(size=50,type=4,eth(dst=aa:55:00:00:00:03,src=aa:55:00:00:00:02,dl_type=0x0800),ipv4(src=20.0.0.2,dst=20.0.0.3,proto=17,tos=0,ttl=64,frag=0x4000),udp(src=0,dst=4789,csum=0x0),vxlan(flags=0xc000004,vni=0x0)),out_port(2)),set(ipv4(src=30.0.0.2,dst=30.0.0.3)),tnl_pop(4789))
tunnel(tun_id=0x0,src=30.0.0.2,dst=30.0.0.3,flags(-df-csum+key)),recirc_id(0),in_port(4789),packet_type(ns=1,id=0x894f),nsh(np=1,spi=0x3020,si=254), packets:1, bytes:108, used:0.0s, actions:pop_nsh(),recirc(0x2)
tunnel(tun_id=0x0,src=30.0.0.2,dst=30.0.0.3,flags(-df-csum+key)),recirc_id(0x2),in_port(4789),packet_type(ns=1,id=0x800),ipv4(frag=no), packets:1, bytes:84, used:0.0s, actions:push_eth(src=00:00:00:00:00:00,dst=aa:55:aa:55:00:03),6
diff --git a/tests/ofproto.at b/tests/ofproto.at
index ec1dc51..b49f546 100644
--- a/tests/ofproto.at
+++ b/tests/ofproto.at
@@ -2396,7 +2396,7 @@ head_table () {
actions: output group set_field strip_vlan push_vlan mod_nw_ttl dec_ttl set_mpls_ttl dec_mpls_ttl push_mpls pop_mpls set_queue
supported on Set-Field: tun_id tun_src tun_dst tun_ipv6_src tun_ipv6_dst tun_flags tun_gbp_id tun_gbp_flags tun_metadata0 dnl
tun_metadata1 tun_metadata2 tun_metadata3 tun_metadata4 tun_metadata5 tun_metadata6 tun_metadata7 tun_metadata8 tun_metadata9 tun_metadata10 tun_metadata11 tun_metadata12 tun_metadata13 tun_metadata14 tun_metadata15 tun_metadata16 tun_metadata17 tun_metadata18 tun_metadata19 tun_metadata20 tun_metadata21 tun_metadata22 tun_metadata23 tun_metadata24 tun_metadata25 tun_metadata26 tun_metadata27 tun_metadata28 tun_metadata29 tun_metadata30 tun_metadata31 tun_metadata32 tun_metadata33 tun_metadata34 tun_metadata35 tun_metadata36 tun_metadata37 tun_metadata38 tun_metadata39 tun_metadata40 tun_metadata41 tun_metadata42 tun_metadata43 tun_metadata44 tun_metadata45 tun_metadata46 tun_metadata47 tun_metadata48 tun_metadata49 tun_metadata50 tun_metadata51 tun_metadata52 tun_metadata53 tun_metadata54 tun_metadata55 tun_metadata56 tun_metadata57 tun_metadata58 tun_metadata59 tun_metadata60 tun_metadata61 tun_metadata62 tun_metadata63 dnl
-metadata in_port in_port_oxm pkt_mark ct_mark ct_label reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 reg9 reg10 reg11 reg12 reg13 reg14 reg15 xreg0 xreg1 xreg2 xreg3 xreg4 xreg5 xreg6 xreg7 xxreg0 xxreg1 xxreg2 xxreg3 eth_src eth_dst vlan_tci vlan_vid vlan_pcp mpls_label mpls_tc mpls_ttl ip_src ip_dst ipv6_src ipv6_dst ipv6_label nw_tos ip_dscp nw_ecn nw_ttl arp_op arp_spa arp_tpa arp_sha arp_tha tcp_src tcp_dst udp_src udp_dst sctp_src sctp_dst icmp_type icmp_code icmpv6_type icmpv6_code nd_target nd_sll nd_tll nsh_flags nsh_spi nsh_si nsh_c1 nsh_c2 nsh_c3 nsh_c4
+metadata in_port in_port_oxm pkt_mark ct_mark ct_label reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 reg9 reg10 reg11 reg12 reg13 reg14 reg15 xreg0 xreg1 xreg2 xreg3 xreg4 xreg5 xreg6 xreg7 xxreg0 xxreg1 xxreg2 xxreg3 eth_src eth_dst vlan_tci vlan_vid vlan_pcp mpls_label mpls_tc mpls_ttl ip_src ip_dst ipv6_src ipv6_dst ipv6_label nw_tos ip_dscp nw_ecn nw_ttl arp_op arp_spa arp_tpa arp_sha arp_tha tcp_src tcp_dst udp_src udp_dst sctp_src sctp_dst icmp_type icmp_code icmpv6_type icmpv6_code nd_target nd_sll nd_tll nsh_flags nsh_spi nsh_si nsh_c1 nsh_c2 nsh_c3 nsh_c4 nsh_ttl
matching:
dp_hash: arbitrary mask
recirc_id: exact match or wildcard
@@ -2567,6 +2567,7 @@ metadata in_port in_port_oxm pkt_mark ct_mark ct_label reg0 reg1 reg2 reg3 reg4
nsh_c2: arbitrary mask
nsh_c3: arbitrary mask
nsh_c4: arbitrary mask
+ nsh_ttl: exact match or wildcard
' $1
}
--
2.1.0
More information about the dev
mailing list