2
0
mirror of https://github.com/openvswitch/ovs synced 2025-09-02 23:35:27 +00:00

userspace: Add support for NSH MD1 match fields

This patch adds support for NSH packet header fields to the OVS
control plane and the userspace datapath. Initially we support the
fields of the NSH base header as defined in
https://www.ietf.org/id/draft-ietf-sfc-nsh-13.txt
and the fixed context headers specified for metadata format MD1.
The variable length MD2 format is parsed but the TLV context headers
are not yet available for matching.

The NSH fields are modelled as experimenter fields with the dedicated
experimenter class 0x005ad650 proposed for NSH in ONF. The following
fields are defined:

NXOXM code            ofctl name    Size      Comment
=====================================================================
NXOXM_NSH_FLAGS       nsh_flags       8       Bits 2-9 of 1st NSH word
(0x005ad650,1)
NXOXM_NSH_MDTYPE      nsh_mdtype      8       Bits 16-23
(0x005ad650,2)
NXOXM_NSH_NEXTPROTO   nsh_np          8       Bits 24-31
(0x005ad650,3)
NXOXM_NSH_SPI         nsh_spi         24      Bits 0-23 of 2nd NSH word
(0x005ad650,4)
NXOXM_NSH_SI          nsh_si          8       Bits 24-31
(0x005ad650,5)
NXOXM_NSH_C1          nsh_c1          32      Maskable, nsh_mdtype==1
(0x005ad650,6)
NXOXM_NSH_C2          nsh_c2          32      Maskable, nsh_mdtype==1
(0x005ad650,7)
NXOXM_NSH_C3          nsh_c3          32      Maskable, nsh_mdtype==1
(0x005ad650,8)
NXOXM_NSH_C4          nsh_c4          32      Maskable, nsh_mdtype==1
(0x005ad650,9)

Co-authored-by: Johnson Li <johnson.li@intel.com>
Signed-off-by: Yi Yang <yi.y.yang@intel.com>
Signed-off-by: Jan Scheurich <jan.scheurich@ericsson.com>
Signed-off-by: Ben Pfaff <blp@ovn.org>
This commit is contained in:
Jan Scheurich
2017-08-05 13:41:08 +08:00
committed by Ben Pfaff
parent 05f282c2e1
commit 3d2fbd70bd
24 changed files with 984 additions and 27 deletions

View File

@@ -40,6 +40,7 @@
#include "random.h"
#include "unaligned.h"
#include "util.h"
#include "openvswitch/nsh.h"
COVERAGE_DEFINE(flow_extract);
COVERAGE_DEFINE(miniflow_malloc);
@@ -125,7 +126,7 @@ struct mf_ctx {
* away. Some GCC versions gave warnings on ALWAYS_INLINE, so these are
* defined as macros. */
#if (FLOW_WC_SEQ != 39)
#if (FLOW_WC_SEQ != 40)
#define MINIFLOW_ASSERT(X) ovs_assert(X)
BUILD_MESSAGE("FLOW_WC_SEQ changed: miniflow_extract() will have runtime "
"assertions enabled. Consider updating FLOW_WC_SEQ after "
@@ -528,6 +529,63 @@ parse_ipv6_ext_hdrs(const void **datap, size_t *sizep, uint8_t *nw_proto,
return parse_ipv6_ext_hdrs__(datap, sizep, nw_proto, nw_frag);
}
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;
/* Check if it is long enough for NSH header, doesn't support
* MD type 2 yet
*/
if (OVS_UNLIKELY(*sizep < NSH_M_TYPE1_LEN)) {
return false;
}
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;
/* NSH header length is in 4 byte words. */
length = ((ver_flags_len & NSH_LEN_MASK) >> NSH_LEN_SHIFT) << 2;
if (version != 0) {
return false;
}
if (length != NSH_M_TYPE1_LEN) {
return false;
}
key->flags = flags;
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);
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]);
}
break;
case NSH_M_TYPE2:
/* Don't support MD type 2 yet, so return false */
default:
return false;
}
data_pull(datap, sizep, length);
return true;
}
/* Initializes 'flow' members from 'packet' and 'md', taking the packet type
* into account.
*
@@ -817,6 +875,21 @@ miniflow_extract(struct dp_packet *packet, struct miniflow *dst)
miniflow_push_macs(mf, arp_sha, arp_buf);
miniflow_pad_to_64(mf, arp_tha);
}
} else if (dl_type == htons(ETH_TYPE_NSH)) {
struct flow_nsh nsh;
if (OVS_LIKELY(parse_nsh(&data, &size, &nsh))) {
if (nsh.mdtype == NSH_M_TYPE1) {
miniflow_push_words(mf, nsh, &nsh,
sizeof(struct flow_nsh) /
sizeof(uint64_t));
}
else if (nsh.mdtype == NSH_M_TYPE2) {
/* parse_nsh has stopped it from arriving here for
* MD type 2, will add MD type 2 support code here later
*/
}
}
}
goto out;
}
@@ -950,7 +1023,7 @@ flow_get_metadata(const struct flow *flow, struct match *flow_metadata)
{
int i;
BUILD_ASSERT_DECL(FLOW_WC_SEQ == 39);
BUILD_ASSERT_DECL(FLOW_WC_SEQ == 40);
match_init_catchall(flow_metadata);
if (flow->tunnel.tun_id != htonll(0)) {
@@ -1514,7 +1587,7 @@ flow_wildcards_init_for_packet(struct flow_wildcards *wc,
memset(&wc->masks, 0x0, sizeof wc->masks);
/* Update this function whenever struct flow changes. */
BUILD_ASSERT_DECL(FLOW_WC_SEQ == 39);
BUILD_ASSERT_DECL(FLOW_WC_SEQ == 40);
if (flow_tnl_dst_is_set(&flow->tunnel)) {
if (flow->tunnel.flags & FLOW_TNL_F_KEY) {
@@ -1613,6 +1686,13 @@ 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.mdtype);
WC_MASK_FIELD(wc, nsh.np);
WC_MASK_FIELD(wc, nsh.spi);
WC_MASK_FIELD(wc, nsh.si);
WC_MASK_FIELD(wc, nsh.c);
} else {
return; /* Unknown ethertype. */
}
@@ -1654,7 +1734,7 @@ void
flow_wc_map(const struct flow *flow, struct flowmap *map)
{
/* Update this function whenever struct flow changes. */
BUILD_ASSERT_DECL(FLOW_WC_SEQ == 39);
BUILD_ASSERT_DECL(FLOW_WC_SEQ == 40);
flowmap_init(map);
@@ -1740,6 +1820,13 @@ flow_wc_map(const struct flow *flow, struct flowmap *map)
FLOWMAP_SET(map, nw_proto);
FLOWMAP_SET(map, arp_sha);
FLOWMAP_SET(map, arp_tha);
} else if (flow->dl_type == htons(ETH_TYPE_NSH)) {
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.c);
}
}
@@ -1749,7 +1836,7 @@ void
flow_wildcards_clear_non_packet_fields(struct flow_wildcards *wc)
{
/* Update this function whenever struct flow changes. */
BUILD_ASSERT_DECL(FLOW_WC_SEQ == 39);
BUILD_ASSERT_DECL(FLOW_WC_SEQ == 40);
memset(&wc->masks.metadata, 0, sizeof wc->masks.metadata);
memset(&wc->masks.regs, 0, sizeof wc->masks.regs);
@@ -1893,7 +1980,7 @@ flow_wildcards_set_xxreg_mask(struct flow_wildcards *wc, int idx,
uint32_t
miniflow_hash_5tuple(const struct miniflow *flow, uint32_t basis)
{
BUILD_ASSERT_DECL(FLOW_WC_SEQ == 39);
BUILD_ASSERT_DECL(FLOW_WC_SEQ == 40);
uint32_t hash = basis;
if (flow) {
@@ -1940,7 +2027,7 @@ ASSERT_SEQUENTIAL(ipv6_src, ipv6_dst);
uint32_t
flow_hash_5tuple(const struct flow *flow, uint32_t basis)
{
BUILD_ASSERT_DECL(FLOW_WC_SEQ == 39);
BUILD_ASSERT_DECL(FLOW_WC_SEQ == 40);
uint32_t hash = basis;
if (flow) {
@@ -2529,7 +2616,7 @@ flow_push_mpls(struct flow *flow, int n, ovs_be16 mpls_eth_type,
if (clear_flow_L3) {
/* Clear all L3 and L4 fields and dp_hash. */
BUILD_ASSERT(FLOW_WC_SEQ == 39);
BUILD_ASSERT(FLOW_WC_SEQ == 40);
memset((char *) flow + FLOW_SEGMENT_2_ENDS_AT, 0,
sizeof(struct flow) - FLOW_SEGMENT_2_ENDS_AT);
flow->dp_hash = 0;