mirror of
https://github.com/openvswitch/ovs
synced 2025-08-22 09:58:01 +00:00
nsh: add new flow key 'ttl'
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@intel.com> Signed-off-by: Ben Pfaff <blp@ovn.org>
This commit is contained in:
parent
74868f2c38
commit
17553f27ba
1
NEWS
1
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).
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
};
|
||||
|
||||
|
@ -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
|
||||
|
@ -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];
|
||||
};
|
||||
|
23
lib/flow.c
23
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);
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
|
12
lib/match.c
12
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]);
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
@ -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
|
||||
|
@ -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]);
|
||||
|
@ -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;
|
||||
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));
|
||||
uint8_t flags = nsh_get_flags(nsh);
|
||||
uint8_t ttl = nsh_get_ttl(nsh);
|
||||
|
||||
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);
|
||||
flags = key->flags | (flags & ~mask->flags);
|
||||
ttl = key->ttl | (ttl & ~mask->ttl);
|
||||
nsh_set_flags_and_ttl(nsh, flags, ttl);
|
||||
|
||||
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
|
||||
|
130
lib/odp-util.c
130
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);
|
||||
@ -1826,7 +1827,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)
|
||||
{
|
||||
@ -1834,10 +1835,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);
|
||||
@ -1872,8 +1873,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;
|
||||
|
||||
@ -1884,10 +1886,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 (;;) {
|
||||
@ -1899,6 +1901,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:
|
||||
@ -1918,10 +1923,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) {
|
||||
@ -1966,6 +1970,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);
|
||||
@ -2393,6 +2398,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;
|
||||
@ -2414,6 +2420,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: {
|
||||
@ -2457,14 +2464,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;
|
||||
@ -2485,11 +2491,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: {
|
||||
@ -3238,15 +3243,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;
|
||||
@ -3254,8 +3261,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) {
|
||||
@ -4863,7 +4870,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;
|
||||
|
||||
@ -4904,7 +4913,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;
|
||||
}
|
||||
@ -4914,7 +4923,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;
|
||||
}
|
||||
@ -4970,6 +4979,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);
|
||||
@ -7031,59 +7043,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)
|
||||
@ -7109,11 +7091,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;
|
||||
|
@ -158,7 +158,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);
|
||||
|
||||
|
@ -5774,10 +5774,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;
|
||||
@ -5790,6 +5790,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;
|
||||
}
|
||||
|
41
tests/nsh.at
41
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@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@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@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
|
||||
])
|
||||
|
||||
@ -573,13 +573,14 @@ AT_CHECK([
|
||||
ovs-appctl netdev-dummy/receive n1 1e2ce92a669e3a6dd2099cab0800450000548a83400040011aadc0a80a0ac0a80a1e0800b7170a4d0002fd509a5800000000de1c020000000000101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f3031323334353637
|
||||
], [0], [ignore])
|
||||
|
||||
ovs-appctl time/warp 1000
|
||||
ovs-appctl time/warp 1000
|
||||
ovs-appctl time/warp 1000
|
||||
|
||||
AT_CHECK([
|
||||
ovs-appctl dpctl/dump-flows dummy@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@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
|
||||
|
@ -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
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user