summaryrefslogtreecommitdiff
path: root/lib/flow.c
diff options
context:
space:
mode:
authorJan Scheurich <jan.scheurich@ericsson.com>2017-08-05 13:41:08 +0800
committerBen Pfaff <blp@ovn.org>2017-08-07 11:26:09 -0700
commit3d2fbd70bda514f7327970b859663f34f994290c (patch)
tree5a5fb77fbc30f598c56c5af1d666a70bf815a796 /lib/flow.c
parent05f282c2e16126577de7704b16f9dd591b927904 (diff)
downloadopenvswitch-3d2fbd70bda514f7327970b859663f34f994290c.tar.gz
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>
Diffstat (limited to 'lib/flow.c')
-rw-r--r--lib/flow.c103
1 files changed, 95 insertions, 8 deletions
diff --git a/lib/flow.c b/lib/flow.c
index 2ce3e12ff..b2b10aa48 100644
--- a/lib/flow.c
+++ b/lib/flow.c
@@ -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;