[ovs-dev] [PATCH v7 2/4] nsh: add new flow key 'ttl'
Yi Yang
yi.y.yang at intel.com
Sat Jan 6 05:47:52 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>
---
datapath/linux/compat/include/linux/openvswitch.h | 2 +-
include/openvswitch/flow.h | 6 +-
include/openvswitch/meta-flow.h | 31 +++--
include/openvswitch/nsh.h | 96 ++++++++++++++
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 | 6 +-
lib/nx-match.c | 16 ++-
lib/odp-execute.c | 40 +++---
lib/odp-util.c | 151 ++++++++--------------
lib/odp-util.h | 2 +-
lib/packets.c | 1 +
ofproto/ofproto-dpif-xlate.c | 7 +-
tests/nsh.at | 41 +++---
17 files changed, 308 insertions(+), 196 deletions(-)
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..14e6b59 100644
--- a/include/openvswitch/meta-flow.h
+++ b/include/openvswitch/meta-flow.h
@@ -1757,6 +1757,21 @@ enum OVS_PACKED_ENUM mf_field_id {
*/
MFF_NSH_FLAGS,
+ /* "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(2) since OF1.3 and v2.8.
+ */
+ MFF_NSH_TTL,
+
+
/* "nsh_mdtype".
*
* mdtype field in NSH base header.
@@ -1767,7 +1782,7 @@ enum OVS_PACKED_ENUM mf_field_id {
* Prerequisites: NSH.
* Access: read-only.
* NXM: none.
- * OXM: NXOXM_NSH_MDTYPE(2) since OF1.3 and v2.8.
+ * OXM: NXOXM_NSH_MDTYPE(3) since OF1.3 and v2.8.
*/
MFF_NSH_MDTYPE,
@@ -1781,7 +1796,7 @@ enum OVS_PACKED_ENUM mf_field_id {
* Prerequisites: NSH.
* Access: read-only.
* NXM: none.
- * OXM: NXOXM_NSH_NP(3) since OF1.3 and v2.8.
+ * OXM: NXOXM_NSH_NP(4) since OF1.3 and v2.8.
*/
MFF_NSH_NP,
@@ -1795,7 +1810,7 @@ enum OVS_PACKED_ENUM mf_field_id {
* Prerequisites: NSH.
* Access: read/write.
* NXM: none.
- * OXM: NXOXM_NSH_SPI(4) since OF1.3 and v2.8.
+ * OXM: NXOXM_NSH_SPI(5) since OF1.3 and v2.8.
*/
MFF_NSH_SPI,
@@ -1809,7 +1824,7 @@ enum OVS_PACKED_ENUM mf_field_id {
* Prerequisites: NSH.
* Access: read/write.
* NXM: none.
- * OXM: NXOXM_NSH_SI(5) since OF1.3 and v2.8.
+ * OXM: NXOXM_NSH_SI(6) since OF1.3 and v2.8.
*/
MFF_NSH_SI,
@@ -1823,10 +1838,10 @@ enum OVS_PACKED_ENUM mf_field_id {
* Prerequisites: NSH.
* Access: read/write.
* NXM: none.
- * OXM: NXOXM_NSH_C1(6) since OF1.3 and v2.8. <1>
- * OXM: NXOXM_NSH_C2(7) since OF1.3 and v2.8. <2>
- * OXM: NXOXM_NSH_C3(8) since OF1.3 and v2.8. <3>
- * OXM: NXOXM_NSH_C4(9) since OF1.3 and v2.8. <4>
+ * OXM: NXOXM_NSH_C1(7) since OF1.3 and v2.8. <1>
+ * OXM: NXOXM_NSH_C2(8) since OF1.3 and v2.8. <2>
+ * OXM: NXOXM_NSH_C3(9) since OF1.3 and v2.8. <3>
+ * OXM: NXOXM_NSH_C4(10) since OF1.3 and v2.8. <4>
*/
MFF_NSH_C1,
MFF_NSH_C2,
diff --git a/include/openvswitch/nsh.h b/include/openvswitch/nsh.h
index 63b480e..9b02146 100644
--- a/include/openvswitch/nsh.h
+++ b/include/openvswitch/nsh.h
@@ -299,6 +299,102 @@ 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;
+}
+
+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
+}
+
+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)
+{
+ ovs_be32 path_hdr = ntohl(nsh_16aligned_be32(&nsh->path_hdr));
+ return htonl((path_hdr & NSH_SPI_MASK) >> NSH_SPI_SHIFT);
+}
+
+static inline uint8_t
+nsh_get_si(const struct nsh_hdr *nsh)
+{
+ ovs_be32 path_hdr = ntohl(nsh_16aligned_be32(&nsh->path_hdr));
+ 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..8e00c68 100644
--- a/lib/meta-flow.xml
+++ b/lib/meta-flow.xml
@@ -1311,7 +1311,9 @@ tcp,tp_src=0x07c0/0xfff0
<group title="Network Service Header">
<field id="MFF_NSH_FLAGS"
- title="flags field (8 bits)"/>
+ 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"
@@ -3964,7 +3966,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
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..95fef7e 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,18 +1786,14 @@ 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)
{
size_t nsh_key_ofs;
struct ovs_nsh_key_base base;
- base.flags = nsh->flags;
- base.mdtype = nsh->mdtype;
- base.np = nsh->np;
- base.path_hdr = htonl((ntohl(nsh->spi) << NSH_SPI_SHIFT) |
- nsh->si);
+ memcpy(&base, nsh, sizeof(base));
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 +1828,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 +1841,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 +1856,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 +1878,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 +1925,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 +2353,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 +2375,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 +2419,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;
@@ -2443,12 +2445,7 @@ odp_nsh_key_from_attr(const struct nlattr *attr, struct flow_nsh *nsh)
switch (type) {
case OVS_NSH_KEY_ATTR_BASE: {
const struct ovs_nsh_key_base *base = nl_attr_get(a);
- nsh->flags = base->flags;
- 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;
+ memcpy(nsh, base, sizeof(*base));
break;
}
case OVS_NSH_KEY_ATTR_MD1: {
@@ -3197,24 +3194,18 @@ 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.mdtype = base->mdtype;
- nsh.np = base->np;
- nsh.path_hdr = base->path_hdr;
+ memcpy(&nsh, base, sizeof(*base));
if (base_mask) {
- nsh_mask.flags = base_mask->flags;
- nsh_mask.mdtype = base_mask->mdtype;
- nsh_mask.np = base_mask->np;
- nsh_mask.path_hdr = base_mask->path_hdr;
+ memcpy(&nsh_mask, base_mask, sizeof(*base_mask));
}
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 +4813,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 +4856,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_be32(s, &spi, mask ? &spi_mask : NULL);
if (len == 0) {
return -EINVAL;
}
@@ -4873,7 +4866,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 +4922,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 +6986,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;
+ memcpy(nsh, &flow->nsh, sizeof(*nsh));
+ if (!is_mask) {
+ if (nsh->mdtype != NSH_M_TYPE1) {
+ memset(nsh, 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;
+ memcpy(&flow->nsh, nsh, sizeof(*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)
@@ -7067,15 +7033,8 @@ commit_nsh(const struct flow_nsh * flow_nsh, bool use_masked_set,
size_t offset = nl_msg_start_nested(odp_actions,
OVS_ACTION_ATTR_SET_MASKED);
- nsh_base.flags = key->flags;
- 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.mdtype = mask->mdtype;
- nsh_base_mask.np = mask->np;
- nsh_base_mask.path_hdr = mask->path_hdr;
+ memcpy(&nsh_base, key, sizeof(nsh_base));
+ memcpy(&nsh_base_mask, mask, sizeof(nsh_base_mask));
/* OVS_KEY_ATTR_NSH keys */
nsh_key_ofs = nl_msg_start_nested(odp_actions, OVS_KEY_ATTR_NSH);
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/lib/packets.c b/lib/packets.c
index 8ebae8c..4a3bee6 100644
--- a/lib/packets.c
+++ b/lib/packets.c
@@ -441,6 +441,7 @@ push_nsh(struct dp_packet *packet, const struct nsh_hdr *nsh_hdr_src)
nsh = (struct nsh_hdr *) dp_packet_push_uninit(packet, length);
memcpy(nsh, nsh_hdr_src, length);
nsh->next_proto = next_proto;
+ nsh->md_type &= NSH_MDTYPE_MASK;
packet->packet_type = htonl(PT_NSH);
dp_packet_reset_offsets(packet);
packet->l3_ofs = 0;
diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c
index 4506150..bf8b060 100644
--- a/ofproto/ofproto-dpif-xlate.c
+++ b/ofproto/ofproto-dpif-xlate.c
@@ -5926,10 +5926,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;
@@ -5942,6 +5942,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
--
2.1.0
More information about the dev
mailing list