diff mbox

[ovs-dev,RFC,v2,3/5] parse NSH key in key_extract of openvswitch

Message ID 1468344990-11907-1-git-send-email-johnson.li@intel.com
State Changes Requested
Headers show

Commit Message

Johnson.Li July 12, 2016, 5:36 p.m. UTC
Parse the Network Service Header to fullfill the fields in the
struct sw_flow_key.

Signed-off-by: Johnson Li <johnson.li@intel.com>

Comments

Simon Horman Aug. 9, 2016, 2:53 p.m. UTC | #1
On Wed, Jul 13, 2016 at 01:36:30AM +0800, Johnson Li wrote:
> Parse the Network Service Header to fullfill the fields in the
> struct sw_flow_key.
> 
> Signed-off-by: Johnson Li <johnson.li@intel.com>
> 
> diff --git a/datapath/flow.c b/datapath/flow.c
> index fd09cec..debac6f 100644
> --- a/datapath/flow.c
> +++ b/datapath/flow.c
> @@ -44,6 +44,7 @@
>  #include <net/ipv6.h>
>  #include <net/mpls.h>
>  #include <net/ndisc.h>
> +#include <net/nsh.h>
>  
>  #include "datapath.h"
>  #include "conntrack.h"
> @@ -296,6 +297,45 @@ static bool icmp6hdr_ok(struct sk_buff *skb)
>  				  sizeof(struct icmp6hdr));
>  }
>  
> +static int parse_nsh(struct sk_buff *skb, struct sw_flow_key *key)
> +{
> +	struct nsh_hdr *nsh_hdr = (struct nsh_hdr *)skb_mac_header(skb);

I'm a little surprised to see the NSH header be accessed via
skb_mac_header() here. I would have expected the skb_mac_header()
to point to any Ethernet header that is present.

> +	uint16_t retval = -1;

I don't think there is any need to initialise retval above
as it is initialised before use below.

> +	// uint16_t length = 0; /* For MD type 2 support */

Please remove or use this and other unused code.

> +
> +	retval = nsh_hdr->base.length << 2;
> +	if (retval > NSH_LEN_MAX)
> +		return -EINVAL;

Perhaps the local retval variable could be removed as its only
set and then compared above.

[...]
diff mbox

Patch

diff --git a/datapath/flow.c b/datapath/flow.c
index fd09cec..debac6f 100644
--- a/datapath/flow.c
+++ b/datapath/flow.c
@@ -44,6 +44,7 @@ 
 #include <net/ipv6.h>
 #include <net/mpls.h>
 #include <net/ndisc.h>
+#include <net/nsh.h>
 
 #include "datapath.h"
 #include "conntrack.h"
@@ -296,6 +297,45 @@  static bool icmp6hdr_ok(struct sk_buff *skb)
 				  sizeof(struct icmp6hdr));
 }
 
+static int parse_nsh(struct sk_buff *skb, struct sw_flow_key *key)
+{
+	struct nsh_hdr *nsh_hdr = (struct nsh_hdr *)skb_mac_header(skb);
+	uint16_t retval = -1;
+	// uint16_t length = 0; /* For MD type 2 support */
+
+	retval = nsh_hdr->base.length << 2;
+	if (retval > NSH_LEN_MAX)
+		return -EINVAL;
+
+	key->nsh.md_type = nsh_hdr->base.md_type;
+	key->nsh.next_proto = nsh_hdr->base.next_proto;
+	key->nsh.nsi = nsh_hdr->base.svc_idx;
+	key->nsh.nsp = nsh_hdr->base.path_hdr << 8;
+
+	if (nsh_hdr->base.md_type == NSH_M_TYPE1) {
+		struct nsh_md1_ctx *ctx = (struct nsh_md1_ctx *)(nsh_hdr->ctx);
+
+		key->nsh.nshc1 = ctx->nshc1;
+		key->nsh.nshc2 = ctx->nshc2;
+		key->nsh.nshc3 = ctx->nshc3;
+		key->nsh.nshc4 = ctx->nshc4;
+#if 0
+        } else if (nsh_hdr->base.md_type == NSH_M_TYPE2) {
+		/* Todo: Add full support for MD type 2.
+                 * Just prototype with TUN_METADATA APIs here.
+                 */
+		struct nsh_md2_ctx *ctx = (struct nsh_md2_ctx *)(nsh_hdr->ctx);
+		length = retval - sizeof *nsh_hdr;
+
+		memcpy(TUN_METADATA_OPTS(key, length), ctx, length);
+		key->tun_opts_len = length;
+#endif
+        }
+
+	__skb_pull(skb, retval);
+	return retval;
+}
+
 static int parse_vlan(struct sk_buff *skb, struct sw_flow_key *key)
 {
 	struct qtag_prefix {
@@ -454,7 +494,7 @@  invalid:
  */
 static int key_extract(struct sk_buff *skb, struct sw_flow_key *key)
 {
-	int error;
+	int error, nsh_len = -1;
 	struct ethhdr *eth;
 
 	/* Flags are always used as part of stats */
@@ -491,6 +531,11 @@  static int key_extract(struct sk_buff *skb, struct sw_flow_key *key)
 
 	/* Network Service Header */
 	memset(&key->nsh, 0, sizeof(key->nsh));
+	if (key->eth.type == htons(ETH_P_NSH)) {
+		nsh_len = parse_nsh(skb, key);
+		if (unlikely(nsh_len < 0))
+			return -EINVAL;
+	}
 
 	/* Network layer. */
 	if (key->eth.type == htons(ETH_P_IP)) {
@@ -679,6 +724,11 @@  static int key_extract(struct sk_buff *skb, struct sw_flow_key *key)
 			}
 		}
 	}
+
+	if (nsh_len > 0) {
+		__skb_push(skb, nsh_len);
+	}
+
 	return 0;
 }
 
diff --git a/datapath/linux/Modules.mk b/datapath/linux/Modules.mk
index d6ec06a..155cdbc 100644
--- a/datapath/linux/Modules.mk
+++ b/datapath/linux/Modules.mk
@@ -93,6 +93,7 @@  openvswitch_headers += \
 	linux/compat/include/net/stt.h \
 	linux/compat/include/net/vrf.h \
 	linux/compat/include/net/vxlan.h \
+	linux/compat/include/net/nsh.h \
 	linux/compat/include/net/netfilter/nf_conntrack.h \
 	linux/compat/include/net/netfilter/nf_conntrack_core.h \
 	linux/compat/include/net/netfilter/nf_conntrack_expect.h \
diff --git a/datapath/linux/compat/include/net/nsh.h b/datapath/linux/compat/include/net/nsh.h
new file mode 100644
index 0000000..00cab48
--- /dev/null
+++ b/datapath/linux/compat/include/net/nsh.h
@@ -0,0 +1,125 @@ 
+#ifndef __NET_NSH_H
+#define __NET_NSH_H 1
+
+#include <asm/byteorder.h>
+
+/*
+ * Network Service Header:
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |Ver|O|C|R|R|R|R|R|R|    Length   |   MD Type   |  Next Proto   |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |                Service Path ID                | Service Index |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |                                                               |
+ * ~               Mandatory/Optional Context Header               ~
+ * |                                                               |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * Ver = The version field is used to ensure backward compatibility
+ *       going forward with future NSH updates.  It MUST be set to 0x0
+ *       by the sender, in this first revision of NSH.
+ *
+ * O = OAM. when set to 0x1 indicates that this packet is an operations
+ *     and management (OAM) packet.  The receiving SFF and SFs nodes
+ *     MUST examine the payload and take appropriate action.
+ *
+ * C = context. Indicates that a critical metadata TLV is present.
+ *
+ * Length : total length, in 4-byte words, of NSH including the Base
+ *          Header, the Service Path Header and the optional variable
+ *          TLVs.
+ * MD Type: indicates the format of NSH beyond the mandatory Base Header
+ *          and the Service Path Header.
+ *
+ * Next Protocol: indicates the protocol type of the original packet. A
+ *          new IANA registry will be created for protocol type.
+ *
+ * Service Path Identifier (SPI): identifies a service path.
+ *          Participating nodes MUST use this identifier for Service
+ *          Function Path selection.
+ *
+ * Service Index (SI): provides location within the SFP.
+ *
+ * [0] https://tools.ietf.org/html/draft-ietf-sfc-nsh-01
+ */
+struct nsh_base {
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+	__u8    reserved_flags1:4;
+	__u8    context_flag:1;
+	__u8    oam_flag:1;
+	__u8    version:2;
+
+	__u8    length:6;
+	__u8    reserved_flags2:2;
+#elif defined(__BIG_ENDIAN_BITFIELD)
+	__u8    version:2;
+	__u8    oam_flag:1;
+	__u8    context_flag:1;
+	__u8    reserved_flags1:4;
+
+	__u8    reserved_flags2:2;
+	__u8    length:6;
+#else
+#error "Bitfield Endianess not defined."
+#endif
+	__u8    md_type;
+	__u8    next_proto;
+	union {
+		struct {
+			__u8    svc_path[3];
+			__u8    svc_idx;
+		};
+		__be32 path_hdr;
+	};
+};
+
+/**
+ * struct nsh_md1_ctx - Keeps track of NSH context data
+ * @nshc<1-4>: NSH Contexts.
+ */
+struct nsh_md1_ctx {
+	__be32 nshc1;
+	__be32 nshc2;
+	__be32 nshc3;
+	__be32 nshc4;
+};
+
+struct nsh_md2_ctx {
+	__be16 md_class;
+	uint8_t type;
+	uint8_t length;
+	uint8_t md_value[];
+};
+
+/**
+ * struct nshdr - Network Service header
+ * @base: Network Service Base Header.
+ * @ctx: Network Service Context Header.
+ */
+struct nsh_hdr {
+	struct nsh_base base;
+	__be32 ctx[0]; /* Mandatory/optional Context Header */
+};
+
+#define NSH_DST_PORT    4790   /* UDP Port for NSH on VXLAN */
+#define ETH_P_NSH       0x894F   /* Ethertype for NSH */
+
+/* NSH Base Header Next Protocol */
+#define NSH_P_IPV4        0x01
+#define NSH_P_IPV6        0x02
+#define NSH_P_ETHERNET    0x03
+
+/* MD Type Registry */
+#define NSH_M_TYPE1     0x01
+#define NSH_M_TYPE2     0x02
+#define NSH_M_EXP1      0xFE
+#define NSH_M_EXP2      0xFF
+
+/* Used for masking nsp and nsi values in field nsp below */
+#define NSH_M_NSP   0x00FFFFFF
+#define NSH_M_NSI   0xFF000000
+
+/* sizeof(struct nsh_hdr) + sizeof(struct nsh_md1_ctx) */
+#define NSH_M_TYPE1_LEN     24
+#define NSH_LEN_MAX	    256
+
+#endif