On Thu, Aug 17, 2017 at 12:04:25PM +0000, Jan Scheurich wrote: > Hi Yi, > > As discussed please adjust the netlink uAPI for NSH as follows: > > OVS_KEY_ATTR_NSH > -- OVS_NSH_KEY_ATTR_BASE mandatory > -- OVS_NSH_KEY_ATTR_MD1 conditional: if mdtype=MD1 > > OVS_ACTION_ATTR_PUSH_NSH > -- OVS_NSH_KEY_ATTR_BASE mandatory > -- OVS_NSH_PUSH_ATTR_CONTEXT conditional: currently if MD1 or > MD2 with TLV encap properties > > OVS_ACTION_ATTR_POP_NSH no data > > Remove OVS_NSH_KEY_ATTR_MD2 because the MD2 context headers will not > be modelled as dedicated key fields but mapped to some generic TLV fields, > similar to but independent from the current tunnel metadata TLV registers. > > Using the name OVS_NSH_KEY_ATTR_MD2 for the opaque context data in > PUSH_NSH would be misleading as the variable length byte array can carry > any type of metadata format: MD1, MD2, or any future MD type. For that > reason I prefer the generic name OVS_NSH_PUSH_ATTR_CONTEXT.
Then why even have ATTR_MD1? Sounds a single attribute is enough to support all cases. > > Note that this attribute will not be used as part of the NSH key, so you > might > consider generalizing the NSH attribute enum definition to > > enum ovs_nsh_attr { > OVS_NSH_KEY_ATTR_BASE, /* struct ovs_nsh_key_base. */ > OVS_NSH_KEY_ATTR_MD1, /* struct ovs_nsh_key_md1. */ > OVS_NSH_PUSH_ATTR_CONTEXT, /* opaque context headers */ > __OVS_NSH_ATTR_MAX > }; > > BR, Jan > > > > -----Original Message----- > > From: ovs-dev-boun...@openvswitch.org [mailto:ovs-dev- > > boun...@openvswitch.org] On Behalf Of Yi Yang > > Sent: Wednesday, 16 August, 2017 09:56 > > To: d...@openvswitch.org > > Subject: [ovs-dev] [PATCH] nsh: rework NSH netlink keys and actions > > > > Per kernel data path requirements, this patch changes > > OVS_KEY_ATTR_NSH > > to nested attribute and adds three new NSH sub attribute keys: > > > > OVS_NSH_KEY_ATTR_BASE: for length-fixed NSH base header > > OVS_NSH_KEY_ATTR_MD1: for length-fixed MD type 1 context > > OVS_NSH_KEY_ATTR_MD2: for length-variable MD type 2 metadata > > > > NSH match fields, set and PUSH_NSH action all use the below > > nested attribute format: > > > > OVS_KEY_ATTR_NSH begin > > OVS_NSH_KEY_ATTR_BASE > > OVS_NSH_KEY_ATTR_MD1 > > OVS_KEY_ATTR_NSH end > > > > or > > > > OVS_KEY_ATTR_NSH begin > > OVS_NSH_KEY_ATTR_BASE > > OVS_NSH_KEY_ATTR_MD2 > > OVS_KEY_ATTR_NSH end > > > > In addition, NSH encap and decap actions are renamed as push_nsh > > and pop_nsh to meet action naming convention. > > > > Signed-off-by: Yi Yang <yi.y.y...@intel.com> > > --- > > datapath/linux/compat/include/linux/openvswitch.h | 57 +- > > include/openvswitch/nsh.h | 32 +- > > include/openvswitch/packets.h | 11 +- > > lib/dpif-netdev.c | 4 +- > > lib/dpif.c | 4 +- > > lib/flow.c | 15 +- > > lib/match.c | 12 +- > > lib/meta-flow.c | 13 +- > > lib/nx-match.c | 4 +- > > lib/odp-execute.c | 76 ++- > > lib/odp-util.c | 713 > > ++++++++++++++++++---- > > lib/odp-util.h | 4 + > > lib/packets.c | 24 +- > > lib/packets.h | 6 +- > > ofproto/ofproto-dpif-ipfix.c | 4 +- > > ofproto/ofproto-dpif-sflow.c | 4 +- > > ofproto/ofproto-dpif-xlate.c | 24 +- > > tests/nsh.at | 28 +- > > 18 files changed, 773 insertions(+), 262 deletions(-) > > > > diff --git a/datapath/linux/compat/include/linux/openvswitch.h > > b/datapath/linux/compat/include/linux/openvswitch.h > > index bc6c94b..d7f9029 100644 > > --- a/datapath/linux/compat/include/linux/openvswitch.h > > +++ b/datapath/linux/compat/include/linux/openvswitch.h > > @@ -369,7 +369,7 @@ enum ovs_key_attr { > > #ifndef __KERNEL__ > > /* Only used within userspace data path. */ > > OVS_KEY_ATTR_PACKET_TYPE, /* be32 packet type */ > > - OVS_KEY_ATTR_NSH, /* struct ovs_key_nsh */ > > + OVS_KEY_ATTR_NSH, /* Nested set of ovs_nsh_key_* */ > > #endif > > > > __OVS_KEY_ATTR_MAX > > @@ -492,13 +492,27 @@ struct ovs_key_ct_labels { > > }; > > }; > > > > -struct ovs_key_nsh { > > - __u8 flags; > > - __u8 mdtype; > > - __u8 np; > > - __u8 pad; > > - __be32 path_hdr; > > - __be32 c[4]; > > +enum ovs_nsh_key_attr { > > + OVS_NSH_KEY_ATTR_BASE, /* struct ovs_nsh_key_base. */ > > + OVS_NSH_KEY_ATTR_MD1, /* struct ovs_nsh_key_md1. */ > > + OVS_NSH_KEY_ATTR_MD2, /* variable-length octets. */ > > + __OVS_NSH_KEY_ATTR_MAX > > +}; > > + > > +#define OVS_NSH_KEY_ATTR_MAX (__OVS_NSH_KEY_ATTR_MAX - 1) > > + > > +struct ovs_nsh_key_base { > > + __u8 flags; > > + __u8 mdtype; > > + __u8 np; > > + __u8 pad; > > + __be32 path_hdr; > > +}; > > + > > +#define NSH_MD1_CONTEXT_SIZE 4 > > + > > +struct ovs_nsh_key_md1 { > > + __be32 context[NSH_MD1_CONTEXT_SIZE]; > > }; > > > > /* OVS_KEY_ATTR_CT_STATE flags */ > > @@ -793,24 +807,7 @@ struct ovs_action_push_eth { > > struct ovs_key_ethernet addresses; > > }; > > > > -#define OVS_ENCAP_NSH_MAX_MD_LEN 16 > > -/* > > - * struct ovs_action_encap_nsh - %OVS_ACTION_ATTR_ENCAP_NSH > > - * @flags: NSH header flags. > > - * @mdtype: NSH metadata type. > > - * @mdlen: Length of NSH metadata in bytes. > > - * @np: NSH next_protocol: Inner packet type. > > - * @path_hdr: NSH service path id and service index. > > - * @metadata: NSH metadata for MD type 1 or 2 > > - */ > > -struct ovs_action_encap_nsh { > > - uint8_t flags; > > - uint8_t mdtype; > > - uint8_t mdlen; > > - uint8_t np; > > - __be32 path_hdr; > > - uint8_t metadata[OVS_ENCAP_NSH_MAX_MD_LEN]; > > -}; > > +#define OVS_PUSH_NSH_MAX_MD_LEN 248 > > > > /** > > * enum ovs_nat_attr - Attributes for %OVS_CT_ATTR_NAT. > > @@ -887,8 +884,8 @@ enum ovs_nat_attr { > > * @OVS_ACTION_ATTR_PUSH_ETH: Push a new outermost Ethernet > > header onto the > > * packet. > > * @OVS_ACTION_ATTR_POP_ETH: Pop the outermost Ethernet header off > > the packet. > > - * @OVS_ACTION_ATTR_ENCAP_NSH: encap NSH action to push NSH > > header. > > - * @OVS_ACTION_ATTR_DECAP_NSH: decap NSH action to remove NSH > > header. > > + * @OVS_ACTION_ATTR_PUSH_NSH: push NSH header to the packet. > > + * @OVS_ACTION_ATTR_POP_NSH: pop the outermost NSH header off > > the packet. > > * > > * Only a single header can be set with a single %OVS_ACTION_ATTR_SET. > > Not all > > * fields within a header are modifiable, e.g. the IPv4 protocol and > > fragment > > @@ -930,8 +927,8 @@ enum ovs_action_attr { > > OVS_ACTION_ATTR_TUNNEL_POP, /* u32 port number. */ > > OVS_ACTION_ATTR_CLONE, /* Nested OVS_CLONE_ATTR_*. > > */ > > OVS_ACTION_ATTR_METER, /* u32 meter number. */ > > - OVS_ACTION_ATTR_ENCAP_NSH, /* struct > > ovs_action_encap_nsh. */ > > - OVS_ACTION_ATTR_DECAP_NSH, /* No argument. */ > > + OVS_ACTION_ATTR_PUSH_NSH, /* Nested > > OVS_NSH_KEY_ATTR_*. */ > > + OVS_ACTION_ATTR_POP_NSH, /* No argument. */ > > #endif > > __OVS_ACTION_ATTR_MAX, /* Nothing past this will be > > accepted > > * from userspace. */ > > diff --git a/include/openvswitch/nsh.h b/include/openvswitch/nsh.h > > index f4ccadc..7f35513 100644 > > --- a/include/openvswitch/nsh.h > > +++ b/include/openvswitch/nsh.h > > @@ -51,7 +51,7 @@ extern "C" { > > * @nshc<1-4>: NSH Contexts. > > */ > > struct nsh_md1_ctx { > > - ovs_16aligned_be32 c[4]; > > + ovs_16aligned_be32 context[4]; > > }; > > > > struct nsh_md2_tlv { > > @@ -72,6 +72,16 @@ struct nsh_hdr { > > }; > > }; > > > > +#define NSH_M_TYPE2_MAX_LEN 256 > > + > > +struct push_nsh_para { > > + ovs_be16 ver_flags_len; > > + uint8_t md_type; > > + uint8_t next_proto; > > + ovs_16aligned_be32 path_hdr; > > + uint8_t metadata[NSH_M_TYPE2_MAX_LEN-8]; > > +}; > > + > > /* Masking NSH header fields. */ > > #define NSH_VER_MASK 0xc000 > > #define NSH_VER_SHIFT 14 > > @@ -113,7 +123,7 @@ struct nsh_hdr { > > static inline uint16_t > > nsh_hdr_len(const struct nsh_hdr *nsh) > > { > > - return 4 * (ntohs(nsh->ver_flags_len) & NSH_LEN_MASK) >> > > NSH_LEN_SHIFT; > > + return ((ntohs(nsh->ver_flags_len) & NSH_LEN_MASK) >> > > NSH_LEN_SHIFT) << 2; > > } > > > > static inline struct nsh_md1_ctx * > > @@ -128,6 +138,24 @@ nsh_md2_ctx(struct nsh_hdr *nsh) > > return &nsh->md2; > > } > > > > +static inline uint8_t > > +nsh_get_ver(const struct nsh_hdr *nsh) > > +{ > > + return (ntohs(nsh->ver_flags_len) & NSH_VER_MASK) >> > > NSH_VER_SHIFT; > > +} > > + > > +static inline uint8_t > > +nsh_get_len(const struct nsh_hdr *nsh) > > +{ > > + return (ntohs(nsh->ver_flags_len) & NSH_LEN_MASK) >> > > NSH_LEN_SHIFT; > > +} > > + > > +static inline uint8_t > > +nsh_get_flags(const struct nsh_hdr *nsh) > > +{ > > + return (ntohs(nsh->ver_flags_len) & NSH_FLAGS_MASK) >> > > NSH_FLAGS_SHIFT; > > +} > > + > > #ifdef __cplusplus > > } > > #endif > > diff --git a/include/openvswitch/packets.h b/include/openvswitch/packets.h > > index be91e02..5ee3099 100644 > > --- a/include/openvswitch/packets.h > > +++ b/include/openvswitch/packets.h > > @@ -84,7 +84,16 @@ struct flow_nsh { > > uint8_t np; > > uint8_t si; > > ovs_be32 spi; > > - ovs_be32 c[4]; > > + ovs_be32 context[4]; > > +}; > > + > > +struct ovs_key_nsh { > > + uint8_t flags; > > + uint8_t mdtype; > > + uint8_t np; > > + uint8_t pad; > > + ovs_be32 path_hdr; > > + ovs_be32 context[4]; > > }; > > > > /* NSH flags */ > > diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c > > index e2cd931..527fa0e 100644 > > --- a/lib/dpif-netdev.c > > +++ b/lib/dpif-netdev.c > > @@ -5407,8 +5407,8 @@ dp_execute_cb(void *aux_, struct > > dp_packet_batch *packets_, > > case OVS_ACTION_ATTR_PUSH_ETH: > > case OVS_ACTION_ATTR_POP_ETH: > > case OVS_ACTION_ATTR_CLONE: > > - case OVS_ACTION_ATTR_ENCAP_NSH: > > - case OVS_ACTION_ATTR_DECAP_NSH: > > + case OVS_ACTION_ATTR_PUSH_NSH: > > + case OVS_ACTION_ATTR_POP_NSH: > > case __OVS_ACTION_ATTR_MAX: > > OVS_NOT_REACHED(); > > } > > diff --git a/lib/dpif.c b/lib/dpif.c > > index 4c5eac6..2e6cd17 100644 > > --- a/lib/dpif.c > > +++ b/lib/dpif.c > > @@ -1263,8 +1263,8 @@ dpif_execute_helper_cb(void *aux_, struct > > dp_packet_batch *packets_, > > case OVS_ACTION_ATTR_PUSH_ETH: > > case OVS_ACTION_ATTR_POP_ETH: > > case OVS_ACTION_ATTR_CLONE: > > - case OVS_ACTION_ATTR_ENCAP_NSH: > > - case OVS_ACTION_ATTR_DECAP_NSH: > > + case OVS_ACTION_ATTR_PUSH_NSH: > > + case OVS_ACTION_ATTR_POP_NSH: > > case OVS_ACTION_ATTR_UNSPEC: > > case __OVS_ACTION_ATTR_MAX: > > OVS_NOT_REACHED(); > > diff --git a/lib/flow.c b/lib/flow.c > > index b2b10aa..4f898fc 100644 > > --- a/lib/flow.c > > +++ b/lib/flow.c > > @@ -533,7 +533,6 @@ bool > > parse_nsh(const void **datap, size_t *sizep, struct flow_nsh *key) > > { > > const struct nsh_hdr *nsh = (const struct nsh_hdr *) *datap; > > - uint16_t ver_flags_len; > > uint8_t version, length, flags; > > uint32_t path_hdr; > > > > @@ -546,12 +545,10 @@ parse_nsh(const void **datap, size_t *sizep, > > struct flow_nsh *key) > > > > memset(key, 0, sizeof(struct flow_nsh)); > > > > - ver_flags_len = ntohs(nsh->ver_flags_len); > > - version = (ver_flags_len & NSH_VER_MASK) >> NSH_VER_SHIFT; > > - flags = (ver_flags_len & NSH_FLAGS_MASK) >> NSH_FLAGS_SHIFT; > > + version = nsh_get_ver(nsh); > > + flags = nsh_get_flags(nsh); > > > > - /* NSH header length is in 4 byte words. */ > > - length = ((ver_flags_len & NSH_LEN_MASK) >> NSH_LEN_SHIFT) << 2; > > + length = nsh_hdr_len(nsh); > > > > if (version != 0) { > > return false; > > @@ -572,7 +569,7 @@ parse_nsh(const void **datap, size_t *sizep, struct > > flow_nsh *key) > > switch (key->mdtype) { > > case NSH_M_TYPE1: > > for (size_t i = 0; i < 4; i++) { > > - key->c[i] = get_16aligned_be32(&nsh->md1.c[i]); > > + key->context[i] = get_16aligned_be32(&nsh->md1.context[i]); > > } > > break; > > case NSH_M_TYPE2: > > @@ -1692,7 +1689,7 @@ flow_wildcards_init_for_packet(struct > > flow_wildcards *wc, > > WC_MASK_FIELD(wc, nsh.np); > > WC_MASK_FIELD(wc, nsh.spi); > > WC_MASK_FIELD(wc, nsh.si); > > - WC_MASK_FIELD(wc, nsh.c); > > + WC_MASK_FIELD(wc, nsh.context); > > } else { > > return; /* Unknown ethertype. */ > > } > > @@ -1826,7 +1823,7 @@ flow_wc_map(const struct flow *flow, struct > > flowmap *map) > > FLOWMAP_SET(map, nsh.np); > > FLOWMAP_SET(map, nsh.spi); > > FLOWMAP_SET(map, nsh.si); > > - FLOWMAP_SET(map, nsh.c); > > + FLOWMAP_SET(map, nsh.context); > > } > > } > > > > diff --git a/lib/match.c b/lib/match.c > > index 36c78eb..8952c99 100644 > > --- a/lib/match.c > > +++ b/lib/match.c > > @@ -1266,10 +1266,14 @@ format_nsh_masked(struct ds *s, const struct > > flow *f, const struct flow *m) > > 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); > > if (m->nsh.mdtype == UINT8_MAX && f->nsh.mdtype == NSH_M_TYPE1) > > { > > - format_be32_masked_hex(s, "nsh_c1", f->nsh.c[0], m->nsh.c[0]); > > - format_be32_masked_hex(s, "nsh_c2", f->nsh.c[1], m->nsh.c[1]); > > - format_be32_masked_hex(s, "nsh_c3", f->nsh.c[2], m->nsh.c[2]); > > - format_be32_masked_hex(s, "nsh_c4", f->nsh.c[3], m->nsh.c[3]); > > + format_be32_masked_hex(s, "nsh_c1", f->nsh.context[0], > > + m->nsh.context[0]); > > + format_be32_masked_hex(s, "nsh_c2", f->nsh.context[1], > > + m->nsh.context[1]); > > + format_be32_masked_hex(s, "nsh_c3", f->nsh.context[2], > > + m->nsh.context[2]); > > + format_be32_masked_hex(s, "nsh_c4", f->nsh.context[3], > > + m->nsh.context[3]); > > } > > } > > > > diff --git a/lib/meta-flow.c b/lib/meta-flow.c > > index 64a8cf1..beeddf1 100644 > > --- a/lib/meta-flow.c > > +++ b/lib/meta-flow.c > > @@ -373,7 +373,7 @@ mf_is_all_wild(const struct mf_field *mf, const > > struct flow_wildcards *wc) > > case MFF_NSH_C2: > > case MFF_NSH_C3: > > case MFF_NSH_C4: > > - return !wc->masks.nsh.c[mf->id - MFF_NSH_C1]; > > + return !wc->masks.nsh.context[mf->id - MFF_NSH_C1]; > > > > case MFF_N_IDS: > > default: > > @@ -915,7 +915,7 @@ mf_get_value(const struct mf_field *mf, const > > struct flow *flow, > > case MFF_NSH_C2: > > case MFF_NSH_C3: > > case MFF_NSH_C4: > > - value->be32 = flow->nsh.c[mf->id - MFF_NSH_C1]; > > + value->be32 = flow->nsh.context[mf->id - MFF_NSH_C1]; > > break; > > > > case MFF_N_IDS: > > @@ -1230,7 +1230,8 @@ mf_set_value(const struct mf_field *mf, > > case MFF_NSH_C2: > > case MFF_NSH_C3: > > case MFF_NSH_C4: > > - MATCH_SET_FIELD_BE32(match, nsh.c[mf->id - MFF_NSH_C1], > > value->be32); > > + MATCH_SET_FIELD_BE32(match, nsh.context[mf->id - > > MFF_NSH_C1], > > + value->be32); > > break; > > > > case MFF_N_IDS: > > @@ -1621,7 +1622,7 @@ mf_set_flow_value(const struct mf_field *mf, > > case MFF_NSH_C2: > > case MFF_NSH_C3: > > case MFF_NSH_C4: > > - flow->nsh.c[mf->id - MFF_NSH_C1] = value->be32; > > + flow->nsh.context[mf->id - MFF_NSH_C1] = value->be32; > > break; > > > > case MFF_N_IDS: > > @@ -2112,7 +2113,7 @@ mf_set_wild(const struct mf_field *mf, struct > > match *match, char **err_str) > > case MFF_NSH_C2: > > case MFF_NSH_C3: > > case MFF_NSH_C4: > > - MATCH_SET_FIELD_MASKED(match, nsh.c[mf->id - MFF_NSH_C1], > > + MATCH_SET_FIELD_MASKED(match, nsh.context[mf->id - > > MFF_NSH_C1], > > htonl(0), htonl(0)); > > break; > > > > @@ -2372,7 +2373,7 @@ mf_set(const struct mf_field *mf, > > case MFF_NSH_C2: > > case MFF_NSH_C3: > > case MFF_NSH_C4: > > - MATCH_SET_FIELD_MASKED(match, nsh.c[mf->id - MFF_NSH_C1], > > + MATCH_SET_FIELD_MASKED(match, nsh.context[mf->id - > > MFF_NSH_C1], > > value->be32, mask->be32); > > break; > > > > diff --git a/lib/nx-match.c b/lib/nx-match.c > > index b782e8c..8f2a442 100644 > > --- a/lib/nx-match.c > > +++ b/lib/nx-match.c > > @@ -1165,8 +1165,8 @@ nx_put_raw(struct ofpbuf *b, enum ofp_version > > oxm, const struct match *match, > > match->wc.masks.nsh.spi); > > nxm_put_8m(&ctx, MFF_NSH_SI, oxm, flow->nsh.si, match- > > >wc.masks.nsh.si); > > for (int i = 0; i < 4; i++) { > > - nxm_put_32m(&ctx, MFF_NSH_C1 + i, oxm, flow->nsh.c[i], > > - match->wc.masks.nsh.c[i]); > > + nxm_put_32m(&ctx, MFF_NSH_C1 + i, oxm, flow->nsh.context[i], > > + match->wc.masks.nsh.context[i]); > > } > > > > /* Registers. */ > > diff --git a/lib/odp-execute.c b/lib/odp-execute.c > > index 5f4d23a..1254c7a 100644 > > --- a/lib/odp-execute.c > > +++ b/lib/odp-execute.c > > @@ -273,19 +273,22 @@ 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 ovs_key_nsh *key, > > - const struct ovs_key_nsh *mask) > > +odp_set_nsh(struct dp_packet *packet, const struct flow_nsh *key, > > + const struct flow_nsh *mask) > > { > > struct nsh_hdr *nsh = dp_packet_l3(packet); > > + ovs_be32 path_hdr; > > > > if (!mask) { > > nsh->ver_flags_len = htons(key->flags << NSH_FLAGS_SHIFT) | > > (nsh->ver_flags_len & ~htons(NSH_FLAGS_MASK)); > > - put_16aligned_be32(&nsh->path_hdr, key->path_hdr); > > + path_hdr = htonl((ntohl(key->spi) << NSH_SPI_SHIFT) | > > + key->si); > > + put_16aligned_be32(&nsh->path_hdr, path_hdr); > > switch (nsh->md_type) { > > case NSH_M_TYPE1: > > for (int i = 0; i < 4; i++) { > > - put_16aligned_be32(&nsh->md1.c[i], key->c[i]); > > + put_16aligned_be32(&nsh->md1.context[i], > > key->context[i]); > > } > > break; > > case NSH_M_TYPE2: > > @@ -300,16 +303,24 @@ odp_set_nsh(struct dp_packet *packet, const > > struct ovs_key_nsh *key, > > nsh->ver_flags_len = htons(flags << NSH_FLAGS_SHIFT) | > > (nsh->ver_flags_len & ~htons(NSH_FLAGS_MASK)); > > > > - ovs_be32 path_hdr = get_16aligned_be32(&nsh->path_hdr); > > - path_hdr = key->path_hdr | (path_hdr & ~mask->path_hdr); > > + 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); > > + 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); > > put_16aligned_be32(&nsh->path_hdr, path_hdr); > > switch (nsh->md_type) { > > case NSH_M_TYPE1: > > for (int i = 0; i < 4; i++) { > > - ovs_be32 p = get_16aligned_be32(&nsh->md1.c[i]); > > - ovs_be32 k = key->c[i]; > > - ovs_be32 m = mask->c[i]; > > - put_16aligned_be32(&nsh->md1.c[i], k | (p & ~m)); > > + ovs_be32 p = get_16aligned_be32(&nsh->md1.context[i]); > > + ovs_be32 k = key->context[i]; > > + ovs_be32 m = mask->context[i]; > > + put_16aligned_be32(&nsh->md1.context[i], k | (p & ~m)); > > } > > break; > > case NSH_M_TYPE2: > > @@ -345,9 +356,12 @@ odp_execute_set_action(struct dp_packet > > *packet, const struct nlattr *a) > > odp_eth_set_addrs(packet, nl_attr_get(a), NULL); > > break; > > > > - case OVS_KEY_ATTR_NSH: > > - odp_set_nsh(packet, nl_attr_get(a), NULL); > > + case OVS_KEY_ATTR_NSH: { > > + struct flow_nsh nsh; > > + odp_nsh_key_from_attr(a, &nsh); > > + odp_set_nsh(packet, &nsh, NULL); > > break; > > + } > > > > case OVS_KEY_ATTR_IPV4: > > ipv4_key = nl_attr_get_unspec(a, sizeof(struct ovs_key_ipv4)); > > @@ -473,10 +487,26 @@ odp_execute_masked_set_action(struct > > dp_packet *packet, > > get_mask(a, struct ovs_key_ethernet)); > > break; > > > > - case OVS_KEY_ATTR_NSH: > > - odp_set_nsh(packet, nl_attr_get(a), > > - get_mask(a, struct ovs_key_nsh)); > > + case OVS_KEY_ATTR_NSH: { > > + struct flow_nsh nsh, nsh_mask; > > + size_t size = nl_attr_get_size(a) / 2; > > + > > + struct nlattr attr[1 + DIV_ROUND_UP(sizeof(struct ovs_key_ipv6), > > + sizeof(struct nlattr))]; > > + struct nlattr mask[1 + DIV_ROUND_UP(sizeof(struct ovs_key_ipv6), > > + sizeof(struct nlattr))]; > > + > > + mask->nla_type = attr->nla_type = nl_attr_type(a); > > + mask->nla_len = attr->nla_len = NLA_HDRLEN + size; > > + memcpy(attr + 1, (char *)(a + 1), size); > > + memcpy(mask + 1, (char *)(a + 1) + size, size); > > + > > + odp_nsh_key_from_attr(attr, &nsh); > > + odp_nsh_key_from_attr(mask, &nsh_mask); > > + odp_set_nsh(packet, &nsh, &nsh_mask); > > + > > break; > > + } > > > > case OVS_KEY_ATTR_IPV4: > > odp_set_ipv4(packet, nl_attr_get(a), > > @@ -652,8 +682,8 @@ requires_datapath_assistance(const struct nlattr > > *a) > > case OVS_ACTION_ATTR_PUSH_ETH: > > case OVS_ACTION_ATTR_POP_ETH: > > case OVS_ACTION_ATTR_CLONE: > > - case OVS_ACTION_ATTR_ENCAP_NSH: > > - case OVS_ACTION_ATTR_DECAP_NSH: > > + case OVS_ACTION_ATTR_PUSH_NSH: > > + case OVS_ACTION_ATTR_POP_NSH: > > return false; > > > > case OVS_ACTION_ATTR_UNSPEC: > > @@ -818,18 +848,20 @@ odp_execute_actions(void *dp, struct > > dp_packet_batch *batch, bool steal, > > } > > break; > > > > - case OVS_ACTION_ATTR_ENCAP_NSH: { > > - const struct ovs_action_encap_nsh *enc_nsh = nl_attr_get(a); > > + case OVS_ACTION_ATTR_PUSH_NSH: { > > + struct push_nsh_para pnp; > > + const struct push_nsh_para * pnpp = &pnp; > > + odp_push_nsh_para_from_attr(nl_attr_get(a), &pnp); > > DP_PACKET_BATCH_FOR_EACH (packet, batch) { > > - encap_nsh(packet, enc_nsh); > > + push_nsh(packet, pnpp); > > } > > break; > > } > > - case OVS_ACTION_ATTR_DECAP_NSH: { > > + case OVS_ACTION_ATTR_POP_NSH: { > > size_t i, num = batch->count; > > > > DP_PACKET_BATCH_REFILL_FOR_EACH (i, num, packet, batch) { > > - if (decap_nsh(packet)) { > > + if (pop_nsh(packet)) { > > dp_packet_batch_refill(batch, packet, i); > > } else { > > dp_packet_delete(packet); > > diff --git a/lib/odp-util.c b/lib/odp-util.c > > index 4f1499e..a8cb1b4 100644 > > --- a/lib/odp-util.c > > +++ b/lib/odp-util.c > > @@ -129,8 +129,8 @@ odp_action_len(uint16_t type) > > case OVS_ACTION_ATTR_PUSH_ETH: return sizeof(struct > > ovs_action_push_eth); > > case OVS_ACTION_ATTR_POP_ETH: return 0; > > case OVS_ACTION_ATTR_CLONE: return ATTR_LEN_VARIABLE; > > - case OVS_ACTION_ATTR_ENCAP_NSH: return ATTR_LEN_VARIABLE; > > - case OVS_ACTION_ATTR_DECAP_NSH: return 0; > > + case OVS_ACTION_ATTR_PUSH_NSH: return ATTR_LEN_VARIABLE; > > + case OVS_ACTION_ATTR_POP_NSH: return 0; > > > > case OVS_ACTION_ATTR_UNSPEC: > > case __OVS_ACTION_ATTR_MAX: > > @@ -264,7 +264,7 @@ format_nsh_key(struct ds *ds, const struct > > ovs_key_nsh *key) > > switch (key->mdtype) { > > case NSH_M_TYPE1: > > for (int i = 0; i < 4; i++) { > > - ds_put_format(ds, ",c%d=0x%x", i + 1, ntohl(key->c[i])); > > + ds_put_format(ds, ",c%d=0x%x", i + 1, > > ntohl(key->context[i])); > > } > > break; > > case NSH_M_TYPE2: > > @@ -334,40 +334,48 @@ format_nsh_key_mask(struct ds *ds, const struct > > ovs_key_nsh *key, > > format_uint8_masked(ds, &first, "np", key->np, mask->np); > > format_be32_masked(ds, &first, "spi", htonl(spi), htonl(spi_mask)); > > format_uint8_masked(ds, &first, "si", si, si_mask); > > - format_be32_masked(ds, &first, "c1", key->c[0], mask->c[0]); > > - format_be32_masked(ds, &first, "c2", key->c[1], mask->c[1]); > > - format_be32_masked(ds, &first, "c3", key->c[2], mask->c[2]); > > - format_be32_masked(ds, &first, "c4", key->c[3], mask->c[3]); > > + format_be32_masked(ds, &first, "c1", key->context[0], > > + mask->context[0]); > > + format_be32_masked(ds, &first, "c2", key->context[1], > > + mask->context[1]); > > + format_be32_masked(ds, &first, "c3", key->context[2], > > + mask->context[2]); > > + format_be32_masked(ds, &first, "c4", key->context[3], > > + mask->context[3]); > > } > > } > > > > static void > > -format_odp_encap_nsh_action(struct ds *ds, > > - const struct ovs_action_encap_nsh *encap_nsh) > > +format_odp_push_nsh_action(struct ds *ds, > > + const struct push_nsh_para *push_nsh) > > { > > - uint32_t path_hdr = ntohl(encap_nsh->path_hdr); > > + size_t mdlen = (((ntohs(push_nsh->ver_flags_len) & NSH_LEN_MASK) > > + >> NSH_LEN_SHIFT) << 2) - NSH_BASE_HDR_LEN; > > + uint32_t path_hdr = ntohl(get_16aligned_be32(&push_nsh->path_hdr)); > > uint32_t spi = (path_hdr & NSH_SPI_MASK) >> NSH_SPI_SHIFT; > > uint8_t si = (path_hdr & NSH_SI_MASK) >> NSH_SI_SHIFT; > > + uint8_t flags = (ntohs(push_nsh->ver_flags_len) & NSH_FLAGS_MASK) > > + >> NSH_FLAGS_SHIFT; > > > > - ds_put_cstr(ds, "encap_nsh("); > > - ds_put_format(ds, "flags=%d", encap_nsh->flags); > > - ds_put_format(ds, ",mdtype=%d", encap_nsh->mdtype); > > - ds_put_format(ds, ",np=%d", encap_nsh->np); > > + ds_put_cstr(ds, "push_nsh("); > > + ds_put_format(ds, "flags=%d", flags); > > + ds_put_format(ds, ",mdtype=%d", push_nsh->md_type); > > + ds_put_format(ds, ",np=%d", push_nsh->next_proto); > > ds_put_format(ds, ",spi=0x%x", spi); > > ds_put_format(ds, ",si=%d", si); > > - switch (encap_nsh->mdtype) { > > + switch (push_nsh->md_type) { > > case NSH_M_TYPE1: { > > struct nsh_md1_ctx *md1_ctx = > > - ALIGNED_CAST(struct nsh_md1_ctx *, encap_nsh->metadata); > > + ALIGNED_CAST(struct nsh_md1_ctx *, push_nsh->metadata); > > for (int i = 0; i < 4; i++) { > > ds_put_format(ds, ",c%d=0x%x", i + 1, > > - ntohl(get_16aligned_be32(&md1_ctx->c[i]))); > > + ntohl(get_16aligned_be32(&md1_ctx->context[i]))); > > } > > break; > > } > > case NSH_M_TYPE2: > > ds_put_cstr(ds, ",md2="); > > - ds_put_hex(ds, encap_nsh->metadata, encap_nsh->mdlen); > > + ds_put_hex(ds, push_nsh->metadata, mdlen); > > break; > > default: > > OVS_NOT_REACHED(); > > @@ -1057,11 +1065,15 @@ format_odp_action(struct ds *ds, const struct > > nlattr *a, > > case OVS_ACTION_ATTR_CLONE: > > format_odp_clone_action(ds, a, portno_names); > > break; > > - case OVS_ACTION_ATTR_ENCAP_NSH: > > - format_odp_encap_nsh_action(ds, nl_attr_get(a)); > > + case OVS_ACTION_ATTR_PUSH_NSH: { > > + struct push_nsh_para pnp; > > + const struct push_nsh_para *pnpp = &pnp; > > + odp_push_nsh_para_from_attr(nl_attr_get(a), &pnp); > > + format_odp_push_nsh_action(ds, pnpp); > > break; > > - case OVS_ACTION_ATTR_DECAP_NSH: > > - ds_put_cstr(ds, "decap_nsh()"); > > + } > > + case OVS_ACTION_ATTR_POP_NSH: > > + ds_put_cstr(ds, "pop_nsh()"); > > break; > > case OVS_ACTION_ATTR_UNSPEC: > > case __OVS_ACTION_ATTR_MAX: > > @@ -1780,27 +1792,74 @@ find_end: > > return s - s_; > > } > > > > +static void > > +nsh_key_to_attr(struct ofpbuf *buf, const struct flow_nsh *nsh, > > + uint8_t * metadata, size_t md_size, > > + bool is_mask) > > +{ > > + size_t nsh_key_ofs; > > + struct ovs_nsh_key_base base; > > + struct ovs_nsh_key_md1 md1; > > + > > + base.flags = nsh->flags; > > + base.mdtype = nsh->mdtype; > > + base.np = nsh->np; > > + base.path_hdr = htonl((ntohl(nsh->spi) << NSH_SPI_SHIFT) | > > + nsh->si); > > + > > + 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); > > + > > + if (is_mask) { > > + for (int i = 0; i < 4; i++) { > > + md1.context[i] = nsh->context[i]; > > + } > > + nl_msg_put_unspec(buf, OVS_NSH_KEY_ATTR_MD1, &md1, sizeof > > md1); > > + } else { > > + switch (nsh->mdtype) { > > + case NSH_M_TYPE1: > > + for (int i = 0; i < 4; i++) { > > + md1.context[i] = nsh->context[i]; > > + } > > + nl_msg_put_unspec(buf, OVS_NSH_KEY_ATTR_MD1, &md1, sizeof > > md1); > > + break; > > + case NSH_M_TYPE2: > > + if (metadata && md_size > 0) { > > + nl_msg_put_unspec(buf, OVS_NSH_KEY_ATTR_MD2, metadata, > > + md_size); > > + } > > + break; > > + default: > > + /* No match support for other MD formats yet. */ > > + break; > > + } > > + } > > + nl_msg_end_nested(buf, nsh_key_ofs); > > +} > > + > > + > > static int > > -parse_odp_encap_nsh_action(const char *s, struct ofpbuf *actions) > > +parse_odp_push_nsh_action(const char *s, struct ofpbuf *actions) > > { > > int n = 0; > > int ret = 0; > > - struct ovs_action_encap_nsh encap_nsh; > > - uint32_t spi; > > - uint8_t si; > > uint32_t cd; > > + struct flow_nsh nsh; > > + uint8_t *metadata = NULL; > > + uint8_t md_size = 0; > > > > - if (!ovs_scan_len(s, &n, "encap_nsh(")) { > > + if (!ovs_scan_len(s, &n, "push_nsh(")) { > > ret = -EINVAL; > > goto out; > > } > > > > /* The default is NSH_M_TYPE1 */ > > - encap_nsh.flags = 0; > > - encap_nsh.mdtype = NSH_M_TYPE1; > > - encap_nsh.mdlen = NSH_M_TYPE1_MDLEN; > > - encap_nsh.path_hdr = htonl(255); > > - memset(encap_nsh.metadata, 0, NSH_M_TYPE1_MDLEN); > > + nsh.flags = 0; > > + nsh.mdtype = NSH_M_TYPE1; > > + nsh.np = NSH_P_ETHERNET; > > + nsh.spi = 0; > > + nsh.si = 255; > > + memset(nsh.context, 0, NSH_M_TYPE1_MDLEN); > > > > for (;;) { > > n += strspn(s + n, delimiters); > > @@ -1808,17 +1867,17 @@ parse_odp_encap_nsh_action(const char *s, > > struct ofpbuf *actions) > > break; > > } > > > > - if (ovs_scan_len(s, &n, "flags=%"SCNi8, &encap_nsh.flags)) { > > + if (ovs_scan_len(s, &n, "flags=%"SCNi8, &nsh.flags)) { > > continue; > > } > > - if (ovs_scan_len(s, &n, "mdtype=%"SCNi8, &encap_nsh.mdtype)) { > > - switch (encap_nsh.mdtype) { > > + if (ovs_scan_len(s, &n, "mdtype=%"SCNi8, &nsh.mdtype)) { > > + switch (nsh.mdtype) { > > case NSH_M_TYPE1: > > /* This is the default format. */; > > break; > > case NSH_M_TYPE2: > > /* Length will be updated later. */ > > - encap_nsh.mdlen = 0; > > + md_size = 0; > > break; > > default: > > ret = -EINVAL; > > @@ -1826,65 +1885,60 @@ parse_odp_encap_nsh_action(const char *s, > > struct ofpbuf *actions) > > } > > continue; > > } > > - if (ovs_scan_len(s, &n, "np=%"SCNi8, &encap_nsh.np)) { > > + if (ovs_scan_len(s, &n, "np=%"SCNi8, &nsh.np)) { > > continue; > > } > > - if (ovs_scan_len(s, &n, "spi=0x%"SCNx32, &spi)) { > > - encap_nsh.path_hdr = > > - htonl(((spi << NSH_SPI_SHIFT) & NSH_SPI_MASK) | > > - (ntohl(encap_nsh.path_hdr) & ~NSH_SPI_MASK)); > > + if (ovs_scan_len(s, &n, "spi=0x%"SCNx32, &nsh.spi)) { > > + nsh.spi = htonl(nsh.spi); > > continue; > > } > > - if (ovs_scan_len(s, &n, "si=%"SCNi8, &si)) { > > - encap_nsh.path_hdr = > > - htonl((si << NSH_SI_SHIFT) | > > - (ntohl(encap_nsh.path_hdr) & ~NSH_SI_MASK)); > > + if (ovs_scan_len(s, &n, "si=%"SCNi8, &nsh.si)) { > > continue; > > } > > - if (encap_nsh.mdtype == NSH_M_TYPE1) { > > - struct nsh_md1_ctx *md1 = > > - ALIGNED_CAST(struct nsh_md1_ctx *, encap_nsh.metadata); > > + if (nsh.mdtype == NSH_M_TYPE1) { > > if (ovs_scan_len(s, &n, "c1=0x%"SCNx32, &cd)) { > > - put_16aligned_be32(&md1->c[0], htonl(cd)); > > + nsh.context[0] = htonl(cd); > > continue; > > } > > if (ovs_scan_len(s, &n, "c2=0x%"SCNx32, &cd)) { > > - put_16aligned_be32(&md1->c[1], htonl(cd)); > > + nsh.context[1] = htonl(cd); > > continue; > > } > > if (ovs_scan_len(s, &n, "c3=0x%"SCNx32, &cd)) { > > - put_16aligned_be32(&md1->c[2], htonl(cd)); > > + nsh.context[2] = htonl(cd); > > continue; > > } > > if (ovs_scan_len(s, &n, "c4=0x%"SCNx32, &cd)) { > > - put_16aligned_be32(&md1->c[3], htonl(cd)); > > + nsh.context[3] = htonl(cd); > > continue; > > } > > } > > - else if (encap_nsh.mdtype == NSH_M_TYPE2) { > > + else if (nsh.mdtype == NSH_M_TYPE2) { > > struct ofpbuf b; > > char buf[512]; > > size_t mdlen; > > if (ovs_scan_len(s, &n, "md2=0x%511[0-9a-fA-F]", buf)) { > > - ofpbuf_use_stub(&b, encap_nsh.metadata, > > - OVS_ENCAP_NSH_MAX_MD_LEN); > > + metadata = xmalloc(NSH_M_TYPE2_MAX_LEN - 8); > > + ofpbuf_use_stub(&b, metadata, > > + NSH_M_TYPE2_MAX_LEN - 8); > > ofpbuf_put_hex(&b, buf, &mdlen); > > - encap_nsh.mdlen = mdlen; > > + md_size = mdlen; > > ofpbuf_uninit(&b); > > } > > continue; > > } > > } > > out: > > - if (ret < 0) { > > - return ret; > > - } else { > > - size_t size = offsetof(struct ovs_action_encap_nsh, metadata) > > - + ROUND_UP(encap_nsh.mdlen, 4); > > - nl_msg_put_unspec(actions, OVS_ACTION_ATTR_ENCAP_NSH, > > - &encap_nsh, size); > > - return n; > > + if (ret >= 0) { > > + 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); > > + ret = n; > > + } > > + if (metadata != NULL) { > > + free(metadata); > > } > > + return ret; > > } > > > > static int > > @@ -2089,8 +2143,8 @@ parse_odp_action(const char *s, const struct > > simap *port_names, > > } > > > > { > > - if (!strncmp(s, "encap_nsh(", 10)) { > > - int retval = parse_odp_encap_nsh_action(s, actions); > > + if (!strncmp(s, "push_nsh(", 9)) { > > + int retval = parse_odp_push_nsh_action(s, actions); > > if (retval < 0) { > > return retval; > > } > > @@ -2100,8 +2154,8 @@ parse_odp_action(const char *s, const struct > > simap *port_names, > > > > { > > int n; > > - if (ovs_scan(s, "decap_nsh()%n", &n)) { > > - nl_msg_put_flag(actions, OVS_ACTION_ATTR_DECAP_NSH); > > + if (ovs_scan(s, "pop_nsh()%n", &n)) { > > + nl_msg_put_flag(actions, OVS_ACTION_ATTR_POP_NSH); > > return n; > > } > > } > > @@ -2198,6 +2252,13 @@ static const struct attr_len_tbl > > ovs_tun_key_attr_lens[OVS_TUNNEL_KEY_ATTR_MAX + > > [OVS_TUNNEL_KEY_ATTR_IPV6_DST] = { .len = 16 }, > > }; > > > > +static const struct attr_len_tbl > > +ovs_nsh_key_attr_lens[OVS_NSH_KEY_ATTR_MAX + 1] = { > > + [OVS_NSH_KEY_ATTR_BASE] = { .len = 8 }, > > + [OVS_NSH_KEY_ATTR_MD1] = { .len = 16 }, > > + [OVS_NSH_KEY_ATTR_MD2] = { .len = ATTR_LEN_VARIABLE }, > > +}; > > + > > static const struct attr_len_tbl > > ovs_flow_key_attr_lens[OVS_KEY_ATTR_MAX + 1] = { > > [OVS_KEY_ATTR_ENCAP] = { .len = ATTR_LEN_NESTED }, > > [OVS_KEY_ATTR_PRIORITY] = { .len = 4 }, > > @@ -2229,7 +2290,9 @@ static const struct attr_len_tbl > > ovs_flow_key_attr_lens[OVS_KEY_ATTR_MAX + 1] = > > [OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV4] = { .len = sizeof(struct > > ovs_key_ct_tuple_ipv4) }, > > [OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV6] = { .len = sizeof(struct > > ovs_key_ct_tuple_ipv6) }, > > [OVS_KEY_ATTR_PACKET_TYPE] = { .len = 4 }, > > - [OVS_KEY_ATTR_NSH] = { .len = sizeof(struct ovs_key_nsh) }, > > + [OVS_KEY_ATTR_NSH] = { .len = ATTR_LEN_NESTED, > > + .next = ovs_nsh_key_attr_lens, > > + .next_max = OVS_NSH_KEY_ATTR_MAX }, > > }; > > > > /* Returns the correct length of the payload for a flow key attribute of > > the > > @@ -2280,6 +2343,116 @@ ovs_frag_type_to_string(enum ovs_frag_type > > type) > > } > > } > > > > +enum odp_key_fitness > > +odp_push_nsh_para_from_attr(const struct nlattr *attr, > > + struct push_nsh_para * pnp) > > +{ > > + unsigned int left; > > + const struct nlattr *a; > > + bool unknown = false; > > + uint8_t flags = 0; > > + size_t mdlen = 0; > > + > > + NL_NESTED_FOR_EACH (a, left, attr) { > > + uint16_t type = nl_attr_type(a); > > + size_t len = nl_attr_get_size(a); > > + int expected_len = odp_key_attr_len(ovs_nsh_key_attr_lens, > > + OVS_NSH_KEY_ATTR_MAX, type); > > + > > + if (len != expected_len && expected_len >= 0) { > > + return ODP_FIT_ERROR; > > + } > > + > > + switch (type) { > > + case OVS_NSH_KEY_ATTR_BASE: { > > + const struct ovs_nsh_key_base *base = nl_attr_get(a); > > + pnp->next_proto = base->np; > > + pnp->md_type = base->mdtype; > > + put_16aligned_be32(&pnp->path_hdr, base->path_hdr); > > + flags = base->flags; > > + break; > > + } > > + case OVS_NSH_KEY_ATTR_MD1: { > > + const struct ovs_nsh_key_md1 *md1 = nl_attr_get(a); > > + mdlen = sizeof *md1; > > + memcpy(pnp->metadata, md1, mdlen); > > + break; > > + } > > + case OVS_NSH_KEY_ATTR_MD2: { > > + const uint8_t *md2 = nl_attr_get(a); > > + mdlen = nl_attr_get_size(a); > > + memcpy(pnp->metadata, md2, mdlen); > > + break; > > + } > > + default: > > + /* Allow this to show up as unexpected, if there are unknown > > + * tunnel attribute, eventually resulting in ODP_FIT_TOO_MUCH. > > */ > > + unknown = true; > > + break; > > + } > > + } > > + > > + /* nsh header length = NSH_BASE_HDR_LEN + mdlen */ > > + pnp->ver_flags_len = htons(flags << NSH_FLAGS_SHIFT | > > + (NSH_BASE_HDR_LEN + mdlen) >> 2); > > + > > + if (unknown) { > > + return ODP_FIT_TOO_MUCH; > > + } > > + return ODP_FIT_PERFECT; > > +} > > + > > +enum odp_key_fitness > > +odp_nsh_key_from_attr(const struct nlattr *attr, struct flow_nsh *nsh) > > +{ > > + unsigned int left; > > + const struct nlattr *a; > > + bool unknown = false; > > + > > + NL_NESTED_FOR_EACH (a, left, attr) { > > + uint16_t type = nl_attr_type(a); > > + size_t len = nl_attr_get_size(a); > > + int expected_len = odp_key_attr_len(ovs_nsh_key_attr_lens, > > + OVS_NSH_KEY_ATTR_MAX, type); > > + > > + if (len != expected_len && expected_len >= 0) { > > + return ODP_FIT_ERROR; > > + } > > + > > + 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; > > + break; > > + } > > + case OVS_NSH_KEY_ATTR_MD1: { > > + const struct ovs_nsh_key_md1 *md1 = nl_attr_get(a); > > + nsh->context[0] = md1->context[0]; > > + nsh->context[1] = md1->context[1]; > > + nsh->context[2] = md1->context[2]; > > + nsh->context[3] = md1->context[3]; > > + break; > > + } > > + case OVS_NSH_KEY_ATTR_MD2: > > + default: > > + /* Allow this to show up as unexpected, if there are unknown > > + * tunnel attribute, eventually resulting in ODP_FIT_TOO_MUCH. > > */ > > + unknown = true; > > + break; > > + } > > + } > > + > > + if (unknown) { > > + return ODP_FIT_TOO_MUCH; > > + } > > + return ODP_FIT_PERFECT; > > +} > > + > > static enum odp_key_fitness > > odp_tun_key_from_attr__(const struct nlattr *attr, bool is_mask, > > struct flow_tnl *tun) > > @@ -2971,6 +3144,80 @@ format_odp_tun_geneve(const struct nlattr > > *attr, > > } > > > > static void > > +format_odp_nsh_attr(const struct nlattr *attr, const struct nlattr > > *mask_attr, > > + struct ds *ds) > > +{ > > + unsigned int left; > > + const struct nlattr *a; > > + struct ovs_key_nsh nsh; > > + struct ovs_key_nsh nsh_mask; > > + > > + memset(&nsh, 0, sizeof nsh); > > + memset(&nsh_mask, 0xff, sizeof nsh_mask); > > + > > + NL_NESTED_FOR_EACH (a, left, attr) { > > + enum ovs_nsh_key_attr type = nl_attr_type(a); > > + const struct nlattr *ma = NULL; > > + > > + if (mask_attr) { > > + ma = nl_attr_find__(nl_attr_get(mask_attr), > > + nl_attr_get_size(mask_attr), type); > > + } > > + > > + if (!check_attr_len(ds, a, ma, ovs_nsh_key_attr_lens, > > + OVS_NSH_KEY_ATTR_MAX, true)) { > > + continue; > > + } > > + > > + switch (type) { > > + 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 > > + = ma ? nl_attr_get(ma) : NULL; > > + nsh.flags = base->flags; > > + 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.mdtype = base_mask->mdtype; > > + nsh_mask.np = base_mask->np; > > + nsh_mask.path_hdr = base_mask->path_hdr; > > + } > > + 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 > > + = ma ? nl_attr_get(ma) : NULL; > > + nsh.context[0] = md1->context[0]; > > + nsh.context[1] = md1->context[1]; > > + nsh.context[2] = md1->context[2]; > > + nsh.context[3] = md1->context[3]; > > + if (md1_mask) { > > + nsh_mask.context[0] = md1_mask->context[0]; > > + nsh_mask.context[1] = md1_mask->context[1]; > > + nsh_mask.context[2] = md1_mask->context[2]; > > + nsh_mask.context[3] = md1_mask->context[3]; > > + } > > + break; > > + } > > + case OVS_NSH_KEY_ATTR_MD2: > > + case __OVS_NSH_KEY_ATTR_MAX: > > + default: > > + /* No support for matching other metadata formats yet. */ > > + break; > > + } > > + } > > + > > + if (mask_attr) { > > + format_nsh_key_mask(ds, &nsh, &nsh_mask); > > + } else { > > + format_nsh_key(ds, &nsh); > > + } > > +} > > + > > +static void > > format_odp_tun_attr(const struct nlattr *attr, const struct nlattr > > *mask_attr, > > struct ds *ds, bool verbose) > > { > > @@ -3448,9 +3695,7 @@ format_odp_key_attr__(const struct nlattr *a, > > const struct nlattr *ma, > > break; > > } > > case OVS_KEY_ATTR_NSH: { > > - const struct ovs_key_nsh *mask = ma ? nl_attr_get(ma) : NULL; > > - const struct ovs_key_nsh *key = nl_attr_get(a); > > - format_nsh_key_mask(ds, key, mask); > > + format_odp_nsh_attr(a, ma, ds); > > break; > > } > > case OVS_KEY_ATTR_UNSPEC: > > @@ -4549,6 +4794,129 @@ geneve_to_attr(struct ofpbuf *a, const void > > *data_) > > } SCAN_END_SINGLE(ATTR) > > > > static int > > +parse_odp_nsh_key_mask_attr(const char *s, struct ofpbuf *key, > > + struct ofpbuf *mask) > > +{ > > + if (strncmp(s, "nsh(", 4) == 0) { > > + const char *start = s; > > + int len; > > + struct flow_nsh skey, smask; > > + > > + s += 4; > > + > > + memset(&skey, 0, sizeof skey); > > + memset(&smask, 0, sizeof smask); > > + do { > > + len = 0; > > + > > + if (strncmp(s, "flags=", 6) == 0) { > > + s += 6; > > + len = scan_u8(s, &skey.flags, mask ? &smask.flags : NULL); > > + if (len == 0) { > > + return -EINVAL; > > + } > > + s += len; > > + continue; > > + } > > + > > + if (strncmp(s, "mdtype=", 7) == 0) { > > + s += 7; > > + len = scan_u8(s, &skey.mdtype, mask ? &smask.mdtype : > > NULL); > > + if (len == 0) { > > + return -EINVAL; > > + } > > + s += len; > > + continue; > > + } > > + > > + if (strncmp(s, "np=", 3) == 0) { > > + s += 3; > > + len = scan_u8(s, &skey.np, mask ? &smask.np : NULL); > > + if (len == 0) { > > + return -EINVAL; > > + } > > + s += len; > > + continue; > > + } > > + > > + if (strncmp(s, "spi=", 4) == 0) { > > + s += 4; > > + len = scan_be32(s, &skey.spi, mask ? &smask.spi : NULL); > > + if (len == 0) { > > + return -EINVAL; > > + } > > + s += len; > > + continue; > > + } > > + > > + if (strncmp(s, "si=", 3) == 0) { > > + s += 3; > > + len = scan_u8(s, &skey.si, mask ? &smask.si : NULL); > > + if (len == 0) { > > + return -EINVAL; > > + } > > + s += len; > > + continue; > > + } > > + > > + if (strncmp(s, "c1=", 3) == 0) { > > + s += 3; > > + len = scan_be32(s, &skey.context[0], > > + mask ? &smask.context[0] : NULL); > > + if (len == 0) { > > + return -EINVAL; > > + } > > + s += len; > > + continue; > > + } > > + > > + if (strncmp(s, "c2=", 3) == 0) { > > + s += 3; > > + len = scan_be32(s, &skey.context[1], > > + mask ? &smask.context[1] : NULL); > > + if (len == 0) { > > + return -EINVAL; > > + } > > + s += len; > > + continue; > > + } > > + > > + if (strncmp(s, "c3=", 3) == 0) { > > + s += 3; > > + len = scan_be32(s, &skey.context[2], > > + mask ? &smask.context[2] : NULL); > > + if (len == 0) { > > + return -EINVAL; > > + } > > + s += len; > > + continue; > > + } > > + > > + if (strncmp(s, "c4=", 3) == 0) { > > + s += 3; > > + len = scan_be32(s, &skey.context[3], > > + mask ? &smask.context[3] : NULL); > > + if (len == 0) { > > + return -EINVAL; > > + } > > + s += len; > > + continue; > > + } > > + } while (*s++ == ',' && len != 0); > > + if (s[-1] != ')') { > > + return -EINVAL; > > + } > > + > > + nsh_key_to_attr(key, &skey, NULL, 0, false); > > + if (mask) { > > + nsh_key_to_attr(mask, &smask, NULL, 0, true); > > + } > > + return s - start; > > + } > > + return 0; > > +} > > + > > +static int > > parse_odp_key_mask_attr(const char *s, const struct simap *port_names, > > struct ofpbuf *key, struct ofpbuf *mask) > > { > > @@ -4694,16 +5062,13 @@ parse_odp_key_mask_attr(const char *s, > > const struct simap *port_names, > > SCAN_FIELD("id=", be16, id); > > } SCAN_END(OVS_KEY_ATTR_PACKET_TYPE); > > > > - SCAN_BEGIN("nsh(", struct ovs_key_nsh) { > > - SCAN_FIELD("flags=", u8, flags); > > - SCAN_FIELD("mdtype=", u8, mdtype); > > - SCAN_FIELD("np=", u8, np); > > - SCAN_FIELD("path_hdr=", be32, path_hdr); > > - SCAN_FIELD("c1=", be32, c[0]); > > - SCAN_FIELD("c2=", be32, c[1]); > > - SCAN_FIELD("c3=", be32, c[2]); > > - SCAN_FIELD("c4=", be32, c[2]); > > - } SCAN_END(OVS_KEY_ATTR_NSH); > > + /* nsh is nested, it needs special process */ > > + int ret = parse_odp_nsh_key_mask_attr(s, key, mask); > > + if (ret < 0) { > > + return ret; > > + } else { > > + s += ret; > > + } > > > > /* Encap open-coded. */ > > if (!strncmp(s, "encap(", 6)) { > > @@ -4994,11 +5359,7 @@ odp_flow_key_from_flow__(const struct > > odp_flow_key_parms *parms, > > mpls_key[i].mpls_lse = data->mpls_lse[i]; > > } > > } else if (flow->dl_type == htons(ETH_TYPE_NSH)) { > > - struct ovs_key_nsh *nsh_key; > > - > > - nsh_key = nl_msg_put_unspec_uninit(buf, OVS_KEY_ATTR_NSH, > > - sizeof *nsh_key); > > - get_nsh_key(data, nsh_key, export_mask); > > + nsh_key_to_attr(buf, &data->nsh, NULL, 0, export_mask); > > } > > > > if (is_ip_any(flow) && !(flow->nw_frag & FLOW_NW_FRAG_LATER)) { > > @@ -5558,13 +5919,10 @@ parse_l2_5_onward(const struct nlattr > > *attrs[OVS_KEY_ATTR_MAX + 1], > > expected_attrs |= UINT64_C(1) << OVS_KEY_ATTR_NSH; > > } > > if (present_attrs & (UINT64_C(1) << OVS_KEY_ATTR_NSH)) { > > - const struct ovs_key_nsh *nsh_key; > > - > > - nsh_key = nl_attr_get(attrs[OVS_KEY_ATTR_NSH]); > > - put_nsh_key(nsh_key, flow, false); > > + odp_nsh_key_from_attr(attrs[OVS_KEY_ATTR_NSH], &flow->nsh); > > if (is_mask) { > > - check_start = nsh_key; > > - check_len = sizeof *nsh_key; > > + check_start = nl_attr_get(attrs[OVS_KEY_ATTR_NSH]); > > + check_len = nl_attr_get_size(attrs[OVS_KEY_ATTR_NSH]); > > expected_bit = OVS_KEY_ATTR_NSH; > > } > > } > > @@ -6620,13 +6978,13 @@ get_nsh_key(const struct flow *flow, struct > > ovs_key_nsh *nsh, bool is_mask) > > flow->nsh.si); > > if (is_mask) { > > for (int i = 0; i < 4; i++) { > > - nsh->c[i] = flow->nsh.c[i]; > > + nsh->context[i] = flow->nsh.context[i]; > > } > > } else { > > switch (nsh->mdtype) { > > case NSH_M_TYPE1: > > for (int i = 0; i < 4; i++) { > > - nsh->c[i] = flow->nsh.c[i]; > > + nsh->context[i] = flow->nsh.context[i]; > > } > > break; > > case NSH_M_TYPE2: > > @@ -6650,17 +7008,125 @@ put_nsh_key(const struct ovs_key_nsh *nsh, > > struct flow *flow, > > switch (nsh->mdtype) { > > case NSH_M_TYPE1: > > for (int i = 0; i < 4; i++) { > > - flow->nsh.c[i] = nsh->c[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.c, 0, sizeof flow->nsh.c); > > + memset(flow->nsh.context, 0, sizeof flow->nsh.context); > > break; > > } > > } > > > > +static bool > > +commit_nsh(const struct flow_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) > > +{ > > + enum ovs_key_attr attr = OVS_KEY_ATTR_NSH; > > + > > + if (memcmp(key, base, size) == 0) { > > + /* Mask bits are set when we have either read or set the > > corresponding > > + * values. Masked bits will be exact-matched, no need to set them > > + * if the value did not actually change. */ > > + return false; > > + } > > + > > + bool fully_masked = odp_mask_is_exact(attr, mask, size); > > + > > + if (use_masked_set && !fully_masked) { > > + size_t nsh_key_ofs; > > + struct ovs_nsh_key_base nsh_base; > > + struct ovs_nsh_key_base nsh_base_mask; > > + struct ovs_nsh_key_md1 md1; > > + struct ovs_nsh_key_md1 md1_mask; > > + 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; > > + > > + /* OVS_KEY_ATTR_NSH keys */ > > + nsh_key_ofs = nl_msg_start_nested(odp_actions, > > OVS_KEY_ATTR_NSH); > > + > > + char *data = nl_msg_put_unspec_uninit(odp_actions, > > + OVS_NSH_KEY_ATTR_BASE, > > + sizeof(nsh_base)); > > + const char *lkey = (char *)&nsh_base, *lmask = (char > > *)&nsh_base_mask; > > + size_t lkey_size = sizeof(nsh_base); > > + > > + while (lkey_size--) { > > + *data++ = *lkey++ & *lmask++; > > + } > > + > > + switch (key->mdtype) { > > + case NSH_M_TYPE1: > > + for (int i = 0; i < 4; i++) { > > + md1.context[i] = key->context[i]; > > + md1_mask.context[i] = mask->context[i]; > > + } > > + data = nl_msg_put_unspec_uninit(odp_actions, > > + OVS_NSH_KEY_ATTR_MD1, > > + sizeof(md1)); > > + lkey = (char *)&md1; > > + lmask = (char *)&md1_mask; > > + lkey_size = sizeof(md1); > > + > > + while (lkey_size--) { > > + *data++ = *lkey++ & *lmask++; > > + } > > + break; > > + case NSH_M_TYPE2: > > + default: > > + /* No match support for other MD formats yet. */ > > + break; > > + } > > + > > + /* OVS_KEY_ATTR_NSH masks */ > > + data = nl_msg_put_unspec_uninit(odp_actions, > > + OVS_NSH_KEY_ATTR_BASE, > > + sizeof(nsh_base_mask)); > > + lmask = (char *)&nsh_base_mask; > > + > > + memcpy(data, lmask, sizeof(nsh_base_mask)); > > + > > + switch (key->mdtype) { > > + case NSH_M_TYPE1: > > + data = nl_msg_put_unspec_uninit(odp_actions, > > + OVS_NSH_KEY_ATTR_MD1, > > + sizeof(md1_mask)); > > + lmask = (char *)&md1_mask; > > + memcpy(data, lmask, sizeof(md1_mask)); > > + break; > > + case NSH_M_TYPE2: > > + default: > > + /* No match support for other MD formats yet. */ > > + break; > > + } > > + nl_msg_end_nested(odp_actions, nsh_key_ofs); > > + > > + nl_msg_end_nested(odp_actions, offset); > > + } else { > > + if (!fully_masked) { > > + memset(mask, 0xff, size); > > + } > > + size_t offset = nl_msg_start_nested(odp_actions, > > OVS_ACTION_ATTR_SET); > > + nsh_key_to_attr(odp_actions, flow_nsh, NULL, 0, false); > > + nl_msg_end_nested(odp_actions, offset); > > + } > > + memcpy(base, key, size); > > + return true; > > +} > > + > > static void > > commit_set_nsh_action(const struct flow *flow, struct flow *base_flow, > > struct ofpbuf *odp_actions, > > @@ -6684,8 +7150,8 @@ commit_set_nsh_action(const struct flow *flow, > > struct flow *base_flow, > > mask.mdtype = 0; /* Not writable. */ > > mask.np = 0; /* Not writable. */ > > > > - if (commit(OVS_KEY_ATTR_NSH, use_masked, &key, &base, &mask, > > sizeof key, > > - odp_actions)) { > > + if (commit_nsh(&base_flow->nsh, use_masked, &key, &base, &mask, > > + sizeof key, odp_actions)) { > > put_nsh_key(&base, base_flow, false); > > if (mask.mdtype != 0) { /* Mask was changed by commit(). */ > > put_nsh_key(&mask, &wc->masks, true); > > @@ -6788,49 +7254,36 @@ commit_set_pkt_mark_action(const struct > > flow *flow, struct flow *base_flow, > > } > > > > static void > > -odp_put_decap_nsh_action(struct ofpbuf *odp_actions) > > +odp_put_pop_nsh_action(struct ofpbuf *odp_actions) > > { > > - nl_msg_put_flag(odp_actions, OVS_ACTION_ATTR_DECAP_NSH); > > + nl_msg_put_flag(odp_actions, OVS_ACTION_ATTR_POP_NSH); > > } > > > > static void > > -odp_put_encap_nsh_action(struct ofpbuf *odp_actions, > > +odp_put_push_nsh_action(struct ofpbuf *odp_actions, > > const struct flow *flow, > > struct ofpbuf *encap_data) > > { > > - struct ovs_action_encap_nsh encap_nsh; > > + uint8_t * metadata = NULL; > > + uint8_t md_size = 0; > > > > - encap_nsh.flags = flow->nsh.flags; > > - encap_nsh.mdtype = flow->nsh.mdtype; > > - encap_nsh.np = flow->nsh.np; > > - encap_nsh.path_hdr = htonl((ntohl(flow->nsh.spi) << NSH_SPI_SHIFT) | > > - flow->nsh.si); > > - > > - switch (encap_nsh.mdtype) { > > - case NSH_M_TYPE1: { > > - struct nsh_md1_ctx *md1 = > > - ALIGNED_CAST(struct nsh_md1_ctx *, encap_nsh.metadata); > > - encap_nsh.mdlen = NSH_M_TYPE1_MDLEN; > > - for (int i = 0; i < 4; i++) { > > - put_16aligned_be32(&md1->c[i], flow->nsh.c[i]); > > - } > > - break; > > - } > > + switch (flow->nsh.mdtype) { > > case NSH_M_TYPE2: > > if (encap_data) { > > - ovs_assert(encap_data->size < OVS_ENCAP_NSH_MAX_MD_LEN); > > - encap_nsh.mdlen = encap_data->size; > > - memcpy(encap_nsh.metadata, encap_data->data, encap_data- > > >size); > > + ovs_assert(encap_data->size < OVS_PUSH_NSH_MAX_MD_LEN); > > + metadata = encap_data->data; > > + md_size = encap_data->size; > > } else { > > - encap_nsh.mdlen = 0; > > + md_size = 0; > > } > > break; > > default: > > - encap_nsh.mdlen = 0; > > + md_size = 0; > > break; > > } > > - nl_msg_put_unspec(odp_actions, OVS_ACTION_ATTR_ENCAP_NSH, > > - &encap_nsh, sizeof(encap_nsh)); > > + size_t offset = nl_msg_start_nested(odp_actions, > > OVS_ACTION_ATTR_PUSH_NSH); > > + nsh_key_to_attr(odp_actions, &flow->nsh, metadata, md_size, false); > > + nl_msg_end_nested(odp_actions, offset); > > } > > > > static void > > @@ -6857,8 +7310,8 @@ commit_packet_type_change(const struct flow > > *flow, > > break; > > } > > case PT_NSH: > > - /* encap_nsh */ > > - odp_put_encap_nsh_action(odp_actions, flow, encap_data); > > + /* push_nsh */ > > + odp_put_push_nsh_action(odp_actions, flow, encap_data); > > base_flow->packet_type = flow->packet_type; > > /* Update all packet headers in base_flow. */ > > memcpy(&base_flow->dl_dst, &flow->dl_dst, > > @@ -6883,8 +7336,8 @@ commit_packet_type_change(const struct flow > > *flow, > > * No need to update the base flow here. */ > > switch (ntohl(base_flow->packet_type)) { > > case PT_NSH: > > - /* decap_nsh. */ > > - odp_put_decap_nsh_action(odp_actions); > > + /* pop_nsh. */ > > + odp_put_pop_nsh_action(odp_actions); > > break; > > default: > > /* Checks are done during translation. */ > > diff --git a/lib/odp-util.h b/lib/odp-util.h > > index 27c2ab4..e3cd4b5 100644 > > --- a/lib/odp-util.h > > +++ b/lib/odp-util.h > > @@ -158,6 +158,10 @@ 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 *); > > +enum odp_key_fitness odp_push_nsh_para_from_attr(const struct nlattr > > *, > > + struct push_nsh_para *); > > > > int odp_ufid_from_string(const char *s_, ovs_u128 *ufid); > > void odp_format_ufid(const ovs_u128 *ufid, struct ds *); > > diff --git a/lib/packets.c b/lib/packets.c > > index 74d87ed..7270183 100644 > > --- a/lib/packets.c > > +++ b/lib/packets.c > > @@ -403,10 +403,11 @@ pop_mpls(struct dp_packet *packet, ovs_be16 > > ethtype) > > } > > > > void > > -encap_nsh(struct dp_packet *packet, const struct ovs_action_encap_nsh > > *encap) > > +push_nsh(struct dp_packet *packet, const struct push_nsh_para *pnp) > > { > > struct nsh_hdr *nsh; > > - size_t length = NSH_BASE_HDR_LEN + encap->mdlen; > > + size_t length = ((ntohs(pnp->ver_flags_len) & NSH_LEN_MASK) > > + >> NSH_LEN_SHIFT) << 2; > > uint8_t next_proto; > > > > switch (ntohl(packet->packet_type)) { > > @@ -427,23 +428,8 @@ encap_nsh(struct dp_packet *packet, const struct > > ovs_action_encap_nsh *encap) > > } > > > > nsh = (struct nsh_hdr *) dp_packet_push_uninit(packet, length); > > - nsh->ver_flags_len = htons(encap->flags << NSH_FLAGS_SHIFT | length > > >> 2); > > + memcpy(nsh, pnp, length); > > nsh->next_proto = next_proto; > > - put_16aligned_be32(&nsh->path_hdr, encap->path_hdr); > > - nsh->md_type = encap->mdtype; > > - switch (nsh->md_type) { > > - case NSH_M_TYPE1: > > - nsh->md1 = *ALIGNED_CAST(struct nsh_md1_ctx *, encap- > > >metadata); > > - break; > > - case NSH_M_TYPE2: { > > - /* The MD2 metadata in encap is already padded to 4 bytes. */ > > - size_t len = ROUND_UP(encap->mdlen, 4); > > - memcpy(&nsh->md2, encap->metadata, len); > > - break; > > - } > > - default: > > - OVS_NOT_REACHED(); > > - } > > > > packet->packet_type = htonl(PT_NSH); > > dp_packet_reset_offsets(packet); > > @@ -451,7 +437,7 @@ encap_nsh(struct dp_packet *packet, const struct > > ovs_action_encap_nsh *encap) > > } > > > > bool > > -decap_nsh(struct dp_packet *packet) > > +pop_nsh(struct dp_packet *packet) > > { > > struct nsh_hdr *nsh = (struct nsh_hdr *) dp_packet_l3(packet); > > size_t length; > > diff --git a/lib/packets.h b/lib/packets.h > > index 705d0b2..6f59c2f 100644 > > --- a/lib/packets.h > > +++ b/lib/packets.h > > @@ -434,9 +434,9 @@ void push_eth(struct dp_packet *packet, const > > struct eth_addr *dst, > > const struct eth_addr *src); > > void pop_eth(struct dp_packet *packet); > > > > -void encap_nsh(struct dp_packet *packet, > > - const struct ovs_action_encap_nsh *encap_nsh); > > -bool decap_nsh(struct dp_packet *packet); > > +void push_nsh(struct dp_packet *packet, > > + const struct push_nsh_para *oapn); > > +bool pop_nsh(struct dp_packet *packet); > > > > #define LLC_DSAP_SNAP 0xaa > > #define LLC_SSAP_SNAP 0xaa > > diff --git a/ofproto/ofproto-dpif-ipfix.c b/ofproto/ofproto-dpif-ipfix.c > > index 472c272..16976c4 100644 > > --- a/ofproto/ofproto-dpif-ipfix.c > > +++ b/ofproto/ofproto-dpif-ipfix.c > > @@ -2823,8 +2823,8 @@ dpif_ipfix_read_actions(const struct flow *flow, > > case OVS_ACTION_ATTR_POP_MPLS: > > case OVS_ACTION_ATTR_PUSH_ETH: > > case OVS_ACTION_ATTR_POP_ETH: > > - case OVS_ACTION_ATTR_ENCAP_NSH: > > - case OVS_ACTION_ATTR_DECAP_NSH: > > + case OVS_ACTION_ATTR_PUSH_NSH: > > + case OVS_ACTION_ATTR_POP_NSH: > > case OVS_ACTION_ATTR_UNSPEC: > > case __OVS_ACTION_ATTR_MAX: > > default: > > diff --git a/ofproto/ofproto-dpif-sflow.c b/ofproto/ofproto-dpif-sflow.c > > index 65a2003..1af1569 100644 > > --- a/ofproto/ofproto-dpif-sflow.c > > +++ b/ofproto/ofproto-dpif-sflow.c > > @@ -1199,8 +1199,8 @@ dpif_sflow_read_actions(const struct flow *flow, > > break; > > case OVS_ACTION_ATTR_SAMPLE: > > case OVS_ACTION_ATTR_CLONE: > > - case OVS_ACTION_ATTR_ENCAP_NSH: > > - case OVS_ACTION_ATTR_DECAP_NSH: > > + case OVS_ACTION_ATTR_PUSH_NSH: > > + case OVS_ACTION_ATTR_POP_NSH: > > case OVS_ACTION_ATTR_UNSPEC: > > case __OVS_ACTION_ATTR_MAX: > > default: > > diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c > > index 973e760..437c519 100644 > > --- a/ofproto/ofproto-dpif-xlate.c > > +++ b/ofproto/ofproto-dpif-xlate.c > > @@ -4392,8 +4392,8 @@ xlate_fixup_actions(struct ofpbuf *b, const struct > > nlattr *actions, > > case OVS_ACTION_ATTR_CT: > > case OVS_ACTION_ATTR_PUSH_ETH: > > case OVS_ACTION_ATTR_POP_ETH: > > - case OVS_ACTION_ATTR_ENCAP_NSH: > > - case OVS_ACTION_ATTR_DECAP_NSH: > > + case OVS_ACTION_ATTR_PUSH_NSH: > > + case OVS_ACTION_ATTR_POP_NSH: > > case OVS_ACTION_ATTR_METER: > > ofpbuf_put(b, a, nl_attr_len_pad(a, left)); > > break; > > @@ -5804,17 +5804,17 @@ rewrite_flow_encap_ethernet(struct xlate_ctx > > *ctx, > > > > /* For an MD2 NSH header returns a pointer to an ofpbuf with the > > encoded > > * MD2 TLVs provided as encap properties to the encap operation. This > > - * will be stored as encap_data in the ctx and copied into the encap_nsh > > + * will be stored as encap_data in the ctx and copied into the push_nsh > > * action at the next commit. */ > > static struct ofpbuf * > > -rewrite_flow_encap_nsh(struct xlate_ctx *ctx, > > - const struct ofpact_encap *encap, > > - struct flow *flow, > > - struct flow_wildcards *wc) > > +rewrite_flow_push_nsh(struct xlate_ctx *ctx, > > + const struct ofpact_encap *encap, > > + struct flow *flow, > > + struct flow_wildcards *wc) > > { > > ovs_be32 packet_type = flow->packet_type; > > const char *ptr = (char *) encap->props; > > - struct ofpbuf *buf = ofpbuf_new(OVS_ENCAP_NSH_MAX_MD_LEN); > > + struct ofpbuf *buf = ofpbuf_new(OVS_PUSH_NSH_MAX_MD_LEN); > > uint8_t md_type = NSH_M_TYPE1; > > uint8_t np = 0; > > int i; > > @@ -5854,7 +5854,7 @@ rewrite_flow_encap_nsh(struct xlate_ctx *ctx, > > } > > ptr += ROUND_UP(prop_ptr->len, 8); > > } > > - if (buf->size == 0 || buf->size > OVS_ENCAP_NSH_MAX_MD_LEN) { > > + if (buf->size == 0 || buf->size > OVS_PUSH_NSH_MAX_MD_LEN) { > > ofpbuf_delete(buf); > > buf = NULL; > > } > > @@ -5899,7 +5899,7 @@ rewrite_flow_encap_nsh(struct xlate_ctx *ctx, > > > > if (md_type == NSH_M_TYPE1) { > > flow->nsh.mdtype = NSH_M_TYPE1; > > - memset(flow->nsh.c, 0, sizeof flow->nsh.c); > > + memset(flow->nsh.context, 0, sizeof flow->nsh.context); > > if (buf) { > > /* Drop any MD2 context TLVs. */ > > ofpbuf_delete(buf); > > @@ -5930,7 +5930,7 @@ xlate_generic_encap_action(struct xlate_ctx > > *ctx, > > rewrite_flow_encap_ethernet(ctx, flow, wc); > > break; > > case PT_NSH: > > - encap_data = rewrite_flow_encap_nsh(ctx, encap, flow, wc); > > + encap_data = rewrite_flow_push_nsh(ctx, encap, flow, wc); > > break; > > default: > > /* New packet type was checked during decoding. */ > > @@ -5973,7 +5973,7 @@ xlate_generic_decap_action(struct xlate_ctx > > *ctx, > > } > > return false; > > case PT_NSH: > > - /* The decap_nsh action is generated at the commit executed as > > + /* The pop_nsh action is generated at the commit executed as > > * part of freezing the ctx for recirculation. Here we just set > > * the new packet type based on the NSH next protocol field. */ > > switch (flow->nsh.np) { > > diff --git a/tests/nsh.at b/tests/nsh.at > > index aa80a2a..562f3da 100644 > > --- a/tests/nsh.at > > +++ b/tests/nsh.at > > @@ -105,7 +105,7 @@ bridge("br0") > > > > 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,ns > > h_si=255,nsh_c1=0x11223344,nsh_c2=0x0,nsh_c3=0x0,nsh_c4=0x0,nw_pro > > to=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: > > encap_nsh(flags=0,mdtype=1,np=3,spi=0x1234,si=255,c1=0x11223344,c2=0 > > x0,c3=0x0,c4=0x0),push_eth(src=00:00:00:00:00:00,dst=11:22:33:44:55:66), > > pop_eth,decap_nsh(),set(eth(dst=11:22:33:44:55:66)),recirc(0x1) > > +Datapath actions: > > push_nsh(flags=0,mdtype=1,np=3,spi=0x1234,si=255,c1=0x11223344,c2=0x > > 0,c3=0x0,c4=0x0),push_eth(src=00:00:00:00:00:00,dst=11:22:33:44:55:66),p > > op_eth,pop_nsh(),set(eth(dst=11:22:33:44:55:66)),recirc(0x1) > > ]) > > > > AT_CHECK([ > > @@ -121,7 +121,7 @@ bridge("br0") > > > > Final flow: unchanged > > Megaflow: > > recirc_id=0,eth,in_port=4,dl_type=0x894f,nsh_mdtype=1,nsh_np=3,nsh_spi > > =0x1234,nsh_c1=0x11223344 > > -Datapath actions: pop_eth,decap_nsh(),recirc(0x2) > > +Datapath actions: pop_eth,pop_nsh(),recirc(0x2) > > ]) > > > > # Now send two real ICMP echo request packets in on port p1 > > @@ -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),e > > th_type(0x0800),ipv4(frag=no), packets:1, bytes:98, used:0.0s, > > actions:encap_nsh(flags=0,mdtype=1,np=3,spi=0x1234,si=255,c1=0x112233 > > 44,c2=0x0,c3=0x0,c4=0x0),push_eth(src=00:00:00:00:00:00,dst=11:22:33:44 > > :55:66),pop_eth,decap_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,mdtype=1,np=3,spi=0x1234,si=255,c1=0x1122334 > > 4,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(fra > > g=no), packets:1, bytes:98, used:0.0s, actions:2 > > ]) > > > > @@ -170,7 +170,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),encap_nsh(flags=0,mdtype=1,np=3,spi=0 > > x0,si=255,c1=0x0,c2=0x0,c3=0x0,c4=0x0),decap_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,mdtype=1,np=3,spi=0x > > 0,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 > > ]) > > > > @@ -195,7 +195,7 @@ ovs-vsctl set bridge br0 datapath_type=dummy \ > > add-port br0 v4 -- set Interface v4 type=patch options:peer=v3 > > ofport_request=4]) > > > > AT_DATA([flows.txt], [dnl > > - > > table=0,in_port=1,ip,actions=encap(nsh(md_type=2,tlv(0x1000,10,0x12345 > > 678))),set_field:0x1234- > > >nsh_spi,encap(ethernet),set_field:11:22:33:44:55:66->dl_dst,3 > > + > > table=0,in_port=1,ip,actions=encap(nsh(md_type=2,tlv(0x1000,10,0x12345 > > 678),tlv(0x2000,20,0xfedcba9876543210))),set_field:0x1234- > > >nsh_spi,encap(ethernet),set_field:11:22:33:44:55:66->dl_dst,3 > > > > table=0,in_port=4,dl_type=0x894f,nsh_mdtype=2,nsh_spi=0x1234,actions= > > decap(),decap(),2 > > ]) > > > > @@ -205,7 +205,7 @@ AT_CHECK([ > > ovs-ofctl -Oopenflow13 dump-flows br0 | ofctl_strip | sort | grep > > actions > > ], [0], [dnl > > in_port=4,dl_type=0x894f,nsh_mdtype=2,nsh_spi=0x1234 > > actions=decap(),decap(),output:2 > > - ip,in_port=1 > > actions=encap(nsh(md_type=2,tlv(0x1000,10,0x12345678))),set_field:0x123 > > 4->nsh_spi,encap(ethernet),set_field:11:22:33:44:55:66->eth_dst,output:3 > > + ip,in_port=1 > > actions=encap(nsh(md_type=2,tlv(0x1000,10,0x12345678),tlv(0x2000,20,0x > > fedcba9876543210))),set_field:0x1234- > > >nsh_spi,encap(ethernet),set_field:11:22:33:44:55:66->eth_dst,output:3 > > ]) > > > > AT_CHECK([ > > @@ -216,7 +216,7 @@ Flow: > > icmp,in_port=1,vlan_tci=0x0000,dl_src=00:11:22:33:44:55,dl_dst=66:77:88: > > 99 > > bridge("br0") > > ------------- > > 0. ip,in_port=1, priority 32768 > > - encap(nsh(md_type=2,tlv(0x1000,10,0x12345678))) > > + > > encap(nsh(md_type=2,tlv(0x1000,10,0x12345678),tlv(0x2000,20,0xfedcba9 > > 876543210))) > > set_field:0x1234->nsh_spi > > encap(ethernet) > > set_field:11:22:33:44:55:66->eth_dst > > @@ -230,7 +230,7 @@ bridge("br0") > > > > 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,ns > > h_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: > > encap_nsh(flags=0,mdtype=2,np=3,spi=0x1234,si=255,md2=0x10000a0412 > > 345678),push_eth(src=00:00:00:00:00:00,dst=11:22:33:44:55:66),pop_eth,d > > ecap_nsh(),set(eth(dst=11:22:33:44:55:66)),recirc(0x1) > > +Datapath actions: > > push_nsh(flags=0,mdtype=2,np=3,spi=0x1234,si=255,md2=0x10000a04123 > > 4567820001408fedcba9876543210),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([ > > @@ -246,7 +246,7 @@ bridge("br0") > > > > Final flow: unchanged > > Megaflow: > > recirc_id=0,eth,in_port=4,dl_type=0x894f,nsh_mdtype=2,nsh_np=3,nsh_spi > > =0x1234 > > -Datapath actions: pop_eth,decap_nsh(),recirc(0x2) > > +Datapath actions: pop_eth,pop_nsh(),recirc(0x2) > > ]) > > > > # Now send two real ICMP echo request packets in on port p1 > > @@ -264,7 +264,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),e > > th_type(0x0800),ipv4(frag=no), packets:1, bytes:98, used:0.0s, > > actions:encap_nsh(flags=0,mdtype=2,np=3,spi=0x1234,si=255,md2=0x1000 > > 0a0412345678),push_eth(src=00:00:00:00:00:00,dst=11:22:33:44:55:66),po > > p_eth,decap_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,mdtype=2,np=3,spi=0x1234,si=255,md2=0x10000 > > a041234567820001408fedcba9876543210),push_eth(src=00:00:00:00:00:0 > > 0,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(fra > > g=no), packets:1, bytes:98, used:0.0s, actions:2 > > ]) > > > > @@ -577,8 +577,8 @@ 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=1 > > 92.168.10.30,frag=no), packets:1, bytes:98, used:0.0s, > > actions:pop_eth,encap_nsh(flags=0,mdtype=1,np=1,spi=0x3000,si=255,c1=0 > > x0,c2=0x0,c3=0x0,c4=0x0),clone(tnl_push(tnl_port(4789),header(size=50,ty > > pe=4,eth(dst=aa:55:00:00:00:03,src=aa:55:00:00:00:01,dl_type=0x0800),ipv > > 4(src=10.0.0.1,dst=10.0.0.3,proto=17,tos=0,ttl=64,frag=0x4000),udp(src=0,d > > st=4789,csum=0x0),vxlan(flags=0xc000004,vni=0x0)),out_port(1)),set(ipv4(s > > rc=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:decap_nsh(),recirc(0x1) > > +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=0x > > 0,c2=0x0,c3=0x0,c4=0x0),clone(tnl_push(tnl_port(4789),header(size=50,typ > > e=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,ds > > t=4789,csum=0x0),vxlan(flags=0xc000004,vni=0x0)),out_port(1)),set(ipv4(sr > > c=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(f > > rag=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 > > ]) > > > > @@ -631,9 +631,9 @@ 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=1 > > 92.168.10.20/255.255.255.248,frag=no), packets:1, bytes:98, used:0.0s, > > actions:pop_eth,encap_nsh(flags=0,mdtype=1,np=1,spi=0x3020,si=255,c1=0 > > x0,c2=0x0,c3=0x0,c4=0x0),clone(tnl_push(tnl_port(4789),header(size=50,ty > > pe=4,eth(dst=aa:55:00:00:00:02,src=aa:55:00:00:00:01,dl_type=0x0800),ipv > > 4(src=10.0.0.1,dst=10.0.0.2,proto=17,tos=0,ttl=64,frag=0x4000),udp(src=0,d > > st=4789,csum=0x0),vxlan(flags=0xc000004,vni=0x0)),out_port(1)),set(ipv4(s > > rc=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,mdtype=1,np=1,spi=0x3020,si=255,c1=0x > > 0,c2=0x0,c3=0x0,c4=0x0),clone(tnl_push(tnl_port(4789),header(size=50,typ > > e=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,ds > > t=4789,csum=0x0),vxlan(flags=0xc000004,vni=0x0)),out_port(1)),set(ipv4(sr > > c=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,typ > > e=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,ds > > t=4789,csum=0x0),vxlan(flags=0xc000004,vni=0x0)),out_port(2)),set(ipv4(sr > > c=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:decap_nsh(),recirc(0x2) > > +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(f > > rag=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 > > > > _______________________________________________ > > dev mailing list > > d...@openvswitch.org > > https://mail.openvswitch.org/mailman/listinfo/ovs-dev > _______________________________________________ > dev mailing list > d...@openvswitch.org > https://mail.openvswitch.org/mailman/listinfo/ovs-dev _______________________________________________ dev mailing list d...@openvswitch.org https://mail.openvswitch.org/mailman/listinfo/ovs-dev