summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGuo Ruijing <ruijing.guo@intel.com>2016-12-20 17:56:39 -0500
committerGuo Ruijing <ruijing.guo@intel.com>2016-12-20 19:46:17 -0500
commitdb6380e4059dc317043e3704f63caf74c8aa6d42 (patch)
treea030a39661b8ec2352e9ee8af3610fa4b4ea2767
parenta8f78d202d502f0bc51d12d88b39905a8e8278e8 (diff)
enable ovs 2.6.1 with NSH
1. port from https://github.com/yyang13/ovs_nsh_patches/ 2. todo: ovs 2.6.1 with NSH & DPDK 16.07 Change-Id: If887bdf072e891d2220b37c34ea7aac433fa8d66 Signed-off-by: Guo Ruijing <ruijing.guo@intel.com>
Notes
Notes (review): Code-Review+1: Michael Polenchuk <mpolenchuk@mirantis.com> Code-Review+2: Ruijing <ruijing.guo@intel.com> Workflow+1: Ruijing <ruijing.guo@intel.com> Verified+2: Jenkins Submitted-by: Jenkins Submitted-at: Thu, 22 Dec 2016 00:54:48 +0000 Reviewed-on: https://review.openstack.org/413421 Project: openstack/fuel-plugin-ovs Branch: refs/heads/master
-rw-r--r--deployment_scripts/install.sh12
-rwxr-xr-xovs_build/build-ovs-nsh-dpdk.sh69
-rw-r--r--ovs_build/ovs_nsh_patches/v2.6.1/0001-Enable-current-VxLAN-gpe-work-and-meet-NSH-requireme.patch (renamed from ovs_build/patches/0001-ovs-vxlan-gpe-vxlan-extension-to-support-vxlan-gpe-t.patch)420
-rw-r--r--ovs_build/ovs_nsh_patches/v2.6.1/0002-Add-NSH-support-in-kernel-and-userspace-data-planes.patch (renamed from ovs_build/patches/0002-ovs-nsh-support-push-and-pop-actions-for-vxlan-gpe-a.patch)2389
-rw-r--r--ovs_build/ovs_nsh_patches/v2.6.1/0003-Fix-too-large-stack-frame-size.patch (renamed from ovs_build/patches/0004-Fix-too-large-stack-frame-size.patch)67
-rw-r--r--ovs_build/ovs_nsh_patches/v2.6.1/0004-Fix-vxlangpe-issues-on-DPDK-netdev.patch127
-rw-r--r--ovs_build/ovs_nsh_patches/v2.6.1/0005-Change-match-field-IDs-and-action-IDs-to-adapt-to-OD.patch197
-rw-r--r--ovs_build/ovs_nsh_patches/v2.6.1/0006-To-be-compatible-with-vpp_nsh.patch31
-rw-r--r--ovs_build/ovs_nsh_patches/v2.6.1/0007-Fix-struct-ovs_gso_cb-size-issue.patch67
-rw-r--r--ovs_build/ovs_nsh_patches/v2.6.1/0008-tunnel-set-udp-dst-port-in-tunnel-metadata.patch84
-rw-r--r--ovs_build/patches/0003-Add-userspace-dataplane-nsh-support-and-remove-push_.patch2327
-rw-r--r--ovs_build/patches/0005-Ethernet-header-must-be-kept-in-VxLAN-gpe-eth-NSH-fo.patch74
-rw-r--r--ovs_build/patches/0006-Fix-VxLAN-gpe-Eth-NSH-issues.patch82
-rw-r--r--ovs_build/patches/README1
14 files changed, 2098 insertions, 3849 deletions
diff --git a/deployment_scripts/install.sh b/deployment_scripts/install.sh
index 5e4d269..c6c1d62 100644
--- a/deployment_scripts/install.sh
+++ b/deployment_scripts/install.sh
@@ -10,19 +10,21 @@ nsh=$2
10dpdk=$3 10dpdk=$3
11dpdk_socket_mem=${4:-''} 11dpdk_socket_mem=${4:-''}
12 12
13apt-get install -y dkms
14
13if [ $nsh = 'true' ] 15if [ $nsh = 'true' ]
14then 16then
15 curl http://$host:8080/plugins/fuel-plugin-ovs-1.0/repositories/ubuntu/ovs-nsh-dpdk.tar.gz | tar -xzv 17 curl http://$host:8080/plugins/fuel-plugin-ovs-1.0/repositories/ubuntu/ovs-nsh-dpdk.tar.gz | tar -xzv
16 dpkg -i openvswitch-datapath-dkms_2.5.90-1.nsh_all.deb 18 dpkg -i openvswitch-datapath-dkms_2.6.1-1.nsh_all.deb
17 dpkg -i openvswitch-common_2.5.90-1.nsh_amd64.deb 19 dpkg -i openvswitch-common_2.6.1-1.nsh_amd64.deb
18 dpkg -i openvswitch-switch_2.5.90-1.nsh_amd64.deb 20 dpkg -i openvswitch-switch_2.6.1-1.nsh_amd64.deb
19 dpkg -i python-openvswitch_2.5.90-1.nsh_all.deb 21 dpkg -i python-openvswitch_2.6.1-1.nsh_all.deb
20 if [ $dpdk = 'true' ] 22 if [ $dpdk = 'true' ]
21 then 23 then
22 dpkg -i libxenstore3.0*.deb 24 dpkg -i libxenstore3.0*.deb
23 dpkg -i libdpdk0_2.2.0-1_amd64.deb 25 dpkg -i libdpdk0_2.2.0-1_amd64.deb
24 dpkg -i dpdk_2.2.0-1_amd64.deb 26 dpkg -i dpdk_2.2.0-1_amd64.deb
25 dpkg -i openvswitch-switch-dpdk_2.5.90-1.nsh_amd64.deb 27 dpkg -i openvswitch-switch-dpdk_2.6.1-1.nsh_amd64.deb
26 fi 28 fi
27else 29else
28 curl http://$host:8080/plugins/fuel-plugin-ovs-1.0/repositories/ubuntu/ovs-dpdk.tar.gz | tar -xzv 30 curl http://$host:8080/plugins/fuel-plugin-ovs-1.0/repositories/ubuntu/ovs-dpdk.tar.gz | tar -xzv
diff --git a/ovs_build/build-ovs-nsh-dpdk.sh b/ovs_build/build-ovs-nsh-dpdk.sh
index 1b42df1..f80d081 100755
--- a/ovs_build/build-ovs-nsh-dpdk.sh
+++ b/ovs_build/build-ovs-nsh-dpdk.sh
@@ -2,100 +2,47 @@
2 2
3set -eux 3set -eux
4 4
5OVS_COMMIT=7d433ae57ebb90cd68e8fa948a096f619ac4e2d8 5OVS_COMMIT=f4b0e64cffb4777ff03d48621c3eadcf1d8c19f3
6URL_OVS=https://github.com/openvswitch/ovs.git 6URL_OVS=https://github.com/openvswitch/ovs.git
7OVS_VER=${OVS_VER:-2.5.90} 7OVS_VER=${OVS_VER:-2.6.1}
8BUILD_HOME=$HOME/nsh 8BUILD_HOME=$HOME/nsh
9BUILD_DEST=${BUILD_DEST:-/deb} 9BUILD_DEST=${BUILD_DEST:-/deb}
10DIR="$(dirname `readlink -f $0`)" 10DIR="$(dirname `readlink -f $0`)"
11 11
12export DEB_BUILD_OPTIONS='parallel=8 nocheck' 12export DEB_BUILD_OPTIONS='parallel=8 nocheck'
13 13
14sudo apt-get build-dep openvswitch -y
15sudo apt-get -y install devscripts dpkg-dev git wget 14sudo apt-get -y install devscripts dpkg-dev git wget
16 15
17rm -rf ${BUILD_HOME}; mkdir -p ${BUILD_HOME} 16rm -rf ${BUILD_HOME}; mkdir -p ${BUILD_HOME}
18 17
19cd ${BUILD_HOME} 18cd ${BUILD_HOME}
20wget -c https://launchpad.net/ubuntu/+archive/primary/+files/dpdk_2.2.0-0ubuntu8.dsc
21wget -c https://launchpad.net/ubuntu/+archive/primary/+files/dpdk_2.2.0.orig.tar.gz
22wget -c https://launchpad.net/ubuntu/+archive/primary/+files/dpdk_2.2.0-0ubuntu8.debian.tar.xz
23dpkg-source -x dpdk_2.2.0-0ubuntu8.dsc
24 19
25# copy from debian/control 20# copy from debian/control
26sudo apt-get install -y debhelper \ 21sudo apt-get install -y \
27 dh-python \ 22 graphviz \
28 dh-systemd \ 23 autoconf \
29 doxygen \
30 graphviz \
31 inkscape \
32 libcap-dev \
33 libpcap-dev \
34 libxen-dev \
35 libxenstore3.0 \
36 python \
37 python-sphinx \
38 texlive-fonts-recommended \
39 texlive-latex-extra
40
41cd dpdk-2.2.0; rm -rf debian/patches/;
42cat << EOF > debian/changelog
43dpdk (2.2.0-1) unstable; urgency=low
44 * DPDK 2.2.0
45 -- DPDK team <dev@dpdk.org> $(date --rfc-2822)
46EOF
47debian/rules build; fakeroot debian/rules binary
48cd ${BUILD_HOME}; sudo dpkg -i *.deb
49apt-get download libxenstore3.0
50
51cd ${BUILD_HOME}
52wget -c https://launchpad.net/ubuntu/+archive/primary/+files/openvswitch-dpdk_2.4.0.orig.tar.gz
53wget -c https://launchpad.net/ubuntu/+archive/primary/+files/openvswitch-dpdk_2.4.0-0ubuntu1.dsc
54wget -c https://launchpad.net/ubuntu/+archive/primary/+files/openvswitch-dpdk_2.4.0-0ubuntu1.debian.tar.xz
55dpkg-source -x openvswitch-dpdk_2.4.0-0ubuntu1.dsc
56
57# copy from debian/control
58sudo apt-get install -y autoconf \
59 automake \ 24 automake \
60 bzip2 \ 25 bzip2 \
61 debhelper \ 26 debhelper \
62 dh-autoreconf \ 27 dh-autoreconf \
63 dh-systemd \
64 graphviz \
65 libdpdk-dev \
66 libfuse-dev \
67 libssl-dev \ 28 libssl-dev \
68 libtool \ 29 libtool \
69 openssl \ 30 openssl \
70 procps \ 31 procps \
71 python-all \ 32 python-all \
72 python-qt4 \
73 python-twisted-conch \ 33 python-twisted-conch \
74 python-zopeinterface \ 34 python-zopeinterface \
75 python-six 35 python-six
76 36
77git clone https://github.com/openvswitch/ovs.git 37git clone https://github.com/openvswitch/ovs.git
78cd ovs; git checkout ${OVS_COMMIT} 38cd ovs; git checkout ${OVS_COMMIT}
79PATCHES=$(cd ${DIR}/patches; echo *patch) 39PATCHES=$(cd ${DIR}/ovs_nsh_patches/v2.6.1/; echo *patch)
80for patch in ${PATCHES} 40for patch in ${PATCHES}
81do 41do
82 patch -p1 < ${DIR}/patches/${patch} 42 patch -p1 < ${DIR}/ovs_nsh_patches/v2.6.1/${patch}
83done 43done
84cd ${BUILD_HOME}; tar czvf ovs.tar.gz ovs
85rm -rf openvswitch-dpdk-${OVS_VER}*
86cd openvswitch-dpdk-2.4.0; uupdate -v ${OVS_VER} ../ovs.tar.gz
87cd ../openvswitch-dpdk-${OVS_VER}
88sed -i "s/include\/rte_config.h/include\/dpdk\/rte_config.h/" acinclude.m4
89sed -i 's/DPDK_INCLUDE=.*/DPDK_INCLUDE=$RTE_SDK\/include\/dpdk/' acinclude.m4
90autoreconf --install
91rm -rf debian/patches/ .git;
92cat << EOF > debian/changelog
93openvswitch-dpdk (${OVS_VER}-1.nsh) unstable; urgency=low
94 * Support NSH
95 -- Open vSwitch team <dev@openvswitch.org> $(date --rfc-2822)
96EOF
97debian/rules build; fakeroot debian/rules binary
98 44
45# build ovs
99cd ${BUILD_HOME}/ovs 46cd ${BUILD_HOME}/ovs
100cat << EOF > debian/changelog 47cat << EOF > debian/changelog
101openvswitch (${OVS_VER}-1.nsh) unstable; urgency=low 48openvswitch (${OVS_VER}-1.nsh) unstable; urgency=low
diff --git a/ovs_build/patches/0001-ovs-vxlan-gpe-vxlan-extension-to-support-vxlan-gpe-t.patch b/ovs_build/ovs_nsh_patches/v2.6.1/0001-Enable-current-VxLAN-gpe-work-and-meet-NSH-requireme.patch
index c172320..63b7597 100644
--- a/ovs_build/patches/0001-ovs-vxlan-gpe-vxlan-extension-to-support-vxlan-gpe-t.patch
+++ b/ovs_build/ovs_nsh_patches/v2.6.1/0001-Enable-current-VxLAN-gpe-work-and-meet-NSH-requireme.patch
@@ -1,34 +1,31 @@
1From 5d79831435ec4e5bea20cc36c3f83eacf6fd065c Mon Sep 17 00:00:00 2001 1From 9f7148f9dc03053a4a3231a7cf819c447a178a17 Mon Sep 17 00:00:00 2001
2From: Yi Yang <yi.y.yang@intel.com> 2From: Yi Yang <yi.y.yang@intel.com>
3Date: Mon, 11 Apr 2016 15:58:14 +0800 3Date: Fri, 11 Nov 2016 11:13:18 +0800
4Subject: [PATCH 1/6] ovs-vxlan-gpe: vxlan extension to support vxlan-gpe 4Subject: [PATCH 1/8] Enable current VxLAN-gpe work and meet NSH requirements
5 tunnel port
6 5
7Signed-off-by: Mengke Liu <mengke.liu@intel.com>
8Signed-off-by: Ricky Li <ricky.li@intel.com>
9Signed-off-by: Johnson Li <johnson.li@intel.com>
10Signed-off-by: Yi Yang <yi.y.yang@intel.com> 6Signed-off-by: Yi Yang <yi.y.yang@intel.com>
11--- 7---
12 datapath/flow_netlink.c | 8 +- 8 datapath/flow_netlink.c | 8 +-
13 datapath/linux/compat/include/linux/openvswitch.h | 1 + 9 datapath/linux/compat/include/linux/openvswitch.h | 1 +
14 datapath/linux/compat/include/net/vxlan.h | 73 +++++++++++++++++++ 10 datapath/linux/compat/include/net/vxlan.h | 1 +
15 datapath/linux/compat/vxlan.c | 30 ++++++++ 11 datapath/linux/compat/vxlan.c | 4 +-
12 datapath/vport-netdev.c | 3 +-
16 datapath/vport-vxlan.c | 15 ++++ 13 datapath/vport-vxlan.c | 15 ++++
14 include/openvswitch/match.h | 4 +
15 include/openvswitch/meta-flow.h | 28 +++++++
16 include/openvswitch/packets.h | 4 +-
17 lib/flow.c | 8 ++ 17 lib/flow.c | 8 ++
18 lib/match.c | 34 +++++++++ 18 lib/match.c | 34 +++++++++
19 lib/match.h | 4 +
20 lib/meta-flow.c | 36 +++++++++ 19 lib/meta-flow.c | 36 +++++++++
21 lib/meta-flow.h | 28 +++++++
22 lib/netdev-vport.c | 2 + 20 lib/netdev-vport.c | 2 +
23 lib/nx-match.c | 4 + 21 lib/nx-match.c | 4 +
24 lib/odp-util.c | 89 ++++++++++++++++++++++- 22 lib/odp-util.c | 89 ++++++++++++++++++++++-
25 lib/packets.h | 4 +-
26 tests/ofproto.at | 4 +- 23 tests/ofproto.at | 4 +-
27 tests/ovs-ofctl.at | 4 + 24 tests/ovs-ofctl.at | 4 +
28 16 files changed, 340 insertions(+), 4 deletions(-) 25 17 files changed, 241 insertions(+), 8 deletions(-)
29 26
30diff --git a/datapath/flow_netlink.c b/datapath/flow_netlink.c 27diff --git a/datapath/flow_netlink.c b/datapath/flow_netlink.c
31index 6ffcc53..351a504 100644 28index 0f32664..2dcae07 100644
32--- a/datapath/flow_netlink.c 29--- a/datapath/flow_netlink.c
33+++ b/datapath/flow_netlink.c 30+++ b/datapath/flow_netlink.c
34@@ -309,6 +309,7 @@ size_t ovs_key_attr_size(void) 31@@ -309,6 +309,7 @@ size_t ovs_key_attr_size(void)
@@ -39,7 +36,7 @@ index 6ffcc53..351a504 100644
39 }; 36 };
40 37
41 static const struct ovs_len_tbl ovs_tunnel_key_lens[OVS_TUNNEL_KEY_ATTR_MAX + 1] = { 38 static const struct ovs_len_tbl ovs_tunnel_key_lens[OVS_TUNNEL_KEY_ATTR_MAX + 1] = {
42@@ -521,6 +522,9 @@ static int vxlan_tun_opt_from_nlattr(const struct nlattr *attr, 39@@ -523,6 +524,9 @@ static int vxlan_tun_opt_from_nlattr(const struct nlattr *attr,
43 case OVS_VXLAN_EXT_GBP: 40 case OVS_VXLAN_EXT_GBP:
44 opts.gbp = nla_get_u32(a); 41 opts.gbp = nla_get_u32(a);
45 break; 42 break;
@@ -49,7 +46,7 @@ index 6ffcc53..351a504 100644
49 default: 46 default:
50 OVS_NLERR(log, "Unknown VXLAN extension attribute %d", 47 OVS_NLERR(log, "Unknown VXLAN extension attribute %d",
51 type); 48 type);
52@@ -677,7 +681,9 @@ static int vxlan_opt_to_nlattr(struct sk_buff *skb, 49@@ -709,7 +713,9 @@ static int vxlan_opt_to_nlattr(struct sk_buff *skb,
53 if (!nla) 50 if (!nla)
54 return -EMSGSIZE; 51 return -EMSGSIZE;
55 52
@@ -61,10 +58,10 @@ index 6ffcc53..351a504 100644
61 58
62 nla_nest_end(skb, nla); 59 nla_nest_end(skb, nla);
63diff --git a/datapath/linux/compat/include/linux/openvswitch.h b/datapath/linux/compat/include/linux/openvswitch.h 60diff --git a/datapath/linux/compat/include/linux/openvswitch.h b/datapath/linux/compat/include/linux/openvswitch.h
64index 3b39ebb..44adb81 100644 61index 12260d8..44b7ce4 100644
65--- a/datapath/linux/compat/include/linux/openvswitch.h 62--- a/datapath/linux/compat/include/linux/openvswitch.h
66+++ b/datapath/linux/compat/include/linux/openvswitch.h 63+++ b/datapath/linux/compat/include/linux/openvswitch.h
67@@ -287,6 +287,7 @@ enum ovs_vport_attr { 64@@ -291,6 +291,7 @@ enum ovs_vport_attr {
68 enum { 65 enum {
69 OVS_VXLAN_EXT_UNSPEC, 66 OVS_VXLAN_EXT_UNSPEC,
70 OVS_VXLAN_EXT_GBP, /* Flag or __u32 */ 67 OVS_VXLAN_EXT_GBP, /* Flag or __u32 */
@@ -73,172 +70,57 @@ index 3b39ebb..44adb81 100644
73 }; 70 };
74 71
75diff --git a/datapath/linux/compat/include/net/vxlan.h b/datapath/linux/compat/include/net/vxlan.h 72diff --git a/datapath/linux/compat/include/net/vxlan.h b/datapath/linux/compat/include/net/vxlan.h
76index 75a5a7a..2bfc3f8 100644 73index 5bc8969..5a994b2 100644
77--- a/datapath/linux/compat/include/net/vxlan.h 74--- a/datapath/linux/compat/include/net/vxlan.h
78+++ b/datapath/linux/compat/include/net/vxlan.h 75+++ b/datapath/linux/compat/include/net/vxlan.h
79@@ -84,6 +84,75 @@ struct vxlanhdr_gbp { 76@@ -201,6 +201,7 @@ reserved_flags2:2;
80 #define VXLAN_GBP_POLICY_APPLIED (BIT(3) << 16)
81 #define VXLAN_GBP_ID_MASK (0xFFFF)
82 77
83+/*
84+ * VXLAN Generic Protocol Extension Extension:
85+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
86+ * |R|R|Ver|I|P|R|O|R|R|R|R|R|R|R|R|R|R|R|R|R|R|R|R| Next Proto |
87+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
88+ * | VXLAN Network Identifier (VNI) | Reserved |
89+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
90+ * Ver = Version. Indicates VXLAN GPE protocol version. The initial
91+ * version is 0. If a receiver does not support the version
92+ * indicated it MUST drop the packet.
93+ *
94+ * I = Instance Bit. The I bit MUST be set to indicate a valid VNI.
95+ *
96+ * P = Next Protocol Bit. The P bit is set to indicate that the
97+ * Next Protocol field is present.
98+ *
99+ * O = OAM Flag Bit. The O bit is set to indicate that the packet
100+ * is an OAM packet.
101+ *
102+ * [1] https://www.ietf.org/id/draft-ietf-nvo3-vxlan-gpe-01.txt
103+ */
104+
105+struct vxlanhdr_gpe {
106+#ifdef __LITTLE_ENDIAN_BITFIELD
107+ uint8_t oam_flag:1;
108+ uint8_t reserved_flags1:1;
109+ uint8_t np_applied:1;
110+ uint8_t instance_applied:1;
111+ uint8_t gpe_version:2;
112+ uint8_t reserved_flags2:2;
113+#elif defined(__BIG_ENDIAN_BITFIELD)
114+ uint8_t reserved_flags2:2;
115+ uint8_t gpe_version:2;
116+ uint8_t instance_applied:1;
117+ uint8_t np_applied:1;
118+ uint8_t reserved_flags1:1;
119+ uint8_t oam_flag:1;
120+#else
121+#error "Please fix <asm/byteorder.h>"
122+#endif
123+ uint8_t reserved_flags3;
124+ uint8_t reserved_flags4;
125+ uint8_t next_proto;
126+ __be32 vx_vni;
127+};
128+
129+/* VxLAN-GPE Header Next Protocol */
130+#define VXLAN_GPE_NP_IPV4 0x01
131+#define VXLAN_GPE_NP_IPV6 0x02
132+#define VXLAN_GPE_NP_ETHERNET 0x03
133+#define VXLAN_GPE_NP_NSH 0x04
134+
135+/* skb->mark mapping
136+ *
137+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
138+ * |R|R|Ver|I|P|R|O|R|R|R|R|R|R|R|R|R|R|R|R|R|R|R|R| Next Proto |
139+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
140+ */
141+
142+#define VXLAN_GPE_OAM_FLAG (BIT(0) << 24)
143+#define VXLAN_GPE_NP_APPLIED (BIT(0) << 26)
144+#define VXLAN_GPE_INSTANCE_APPLIED (BIT(0) << 27)
145+#define VXLAN_GPE_VERSION ((BIT(0) << 28) | (BIT(0) << 29))
146+
147+#define VXLAN_GPE_NP_MASK (0xFF)
148+
149+#define VXLAN_GPE_USED_BITS (VXLAN_GPE_OAM_FLAG | VXLAN_GPE_NP_APPLIED \
150+ | VXLAN_GPE_INSTANCE_APPLIED | VXLAN_GPE_VERSION | 0xFF)
151+
152 /* VXLAN protocol header:
153 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
154 * |G|R|R|R|I|R|R|C| Reserved |
155@@ -104,6 +173,7 @@ struct vxlanhdr {
156 #define VXLAN_HF_RCO BIT(21)
157 #define VXLAN_HF_VNI BIT(27)
158 #define VXLAN_HF_GBP BIT(31)
159+#define VXLAN_HF_GPE BIT(26)
160
161 /* Remote checksum offload header option */
162 #define VXLAN_RCO_MASK 0x7f /* Last byte of vni field */
163@@ -120,6 +190,7 @@ struct vxlanhdr {
164 struct vxlan_metadata { 78 struct vxlan_metadata {
165 __be32 vni; 79 u32 gbp;
166 u32 gbp; 80+ u32 gpe;
167+ u32 gpe;
168 }; 81 };
169 82
170 #define VNI_HASH_BITS 10 83 /* per UDP socket information */
171@@ -205,11 +276,13 @@ struct vxlan_dev {
172 #define VXLAN_F_GBP 0x800
173 #define VXLAN_F_REMCSUM_NOPARTIAL 0x1000
174 #define VXLAN_F_COLLECT_METADATA 0x2000
175+#define VXLAN_F_GPE 0x4000
176
177 /* Flags that are used in the receive path. These flags must match in
178 * order for a socket to be shareable
179 */
180 #define VXLAN_F_RCV_FLAGS (VXLAN_F_GBP | \
181+ VXLAN_F_GPE | \
182 VXLAN_F_UDP_ZERO_CSUM6_RX | \
183 VXLAN_F_REMCSUM_RX | \
184 VXLAN_F_REMCSUM_NOPARTIAL | \
185diff --git a/datapath/linux/compat/vxlan.c b/datapath/linux/compat/vxlan.c 84diff --git a/datapath/linux/compat/vxlan.c b/datapath/linux/compat/vxlan.c
186index 4faa18f..7ef051c 100644 85index d5dbe8d..a80610b 100644
187--- a/datapath/linux/compat/vxlan.c 86--- a/datapath/linux/compat/vxlan.c
188+++ b/datapath/linux/compat/vxlan.c 87+++ b/datapath/linux/compat/vxlan.c
189@@ -971,6 +971,18 @@ static int vxlan_udp_encap_recv(struct sock *sk, struct sk_buff *skb) 88@@ -705,7 +705,6 @@ static int vxlan_rcv(struct sock *sk, struct sk_buff *skb)
190 md->gbp |= VXLAN_GBP_POLICY_APPLIED; 89 if (vs->flags & VXLAN_F_GPE) {
191 90 if (!vxlan_parse_gpe_hdr(&unparsed, &protocol, skb, vs->flags))
192 flags &= ~VXLAN_GBP_USED_BITS; 91 goto drop;
193+ } else if ((flags & VXLAN_HF_GPE) && (vs->flags & VXLAN_F_GPE)) { 92- raw_proto = true;
194+ struct vxlanhdr_gpe *gpe;
195+
196+ gpe = (struct vxlanhdr_gpe *)vxh;
197+ md->gpe = ntohs(gpe->next_proto);
198+
199+ buf.dst.u.tun_info.key.tun_flags |= TUNNEL_VXLAN_OPT;
200+
201+ if (gpe->oam_flag)
202+ md->gpe |= VXLAN_GPE_OAM_FLAG;
203+
204+ flags &= ~VXLAN_GPE_USED_BITS;
205 } 93 }
206 94
207 if (flags || vni & ~VXLAN_VNI_MASK) { 95 if (__iptunnel_pull_header(skb, VXLAN_HLEN, protocol, raw_proto,
208@@ -1023,6 +1035,22 @@ static void vxlan_build_gbp_hdr(struct vxlanhdr *vxh, u32 vxflags, 96@@ -896,10 +895,9 @@ static int vxlan_build_skb(struct sk_buff *skb, struct dst_entry *dst,
209 gbp->policy_id = htons(md->gbp & VXLAN_GBP_ID_MASK);
210 }
211
212+static void vxlan_build_gpe_hdr(struct vxlanhdr *vxh, u32 vxflags,
213+ struct vxlan_metadata *md)
214+{
215+ struct vxlanhdr_gpe *gpe;
216+
217+ if (!md->gpe)
218+ return;
219+
220+ gpe = (struct vxlanhdr_gpe*)vxh;
221+ vxh->vx_flags |= htonl(VXLAN_HF_GPE);
222+
223+ if (md->gpe & VXLAN_GPE_OAM_FLAG)
224+ gpe->oam_flag = 1;
225+ gpe->next_proto = md->gpe & VXLAN_GPE_NP_MASK;
226+}
227+
228 #if IS_ENABLED(CONFIG_IPV6)
229 static int vxlan6_xmit_skb(struct dst_entry *dst, struct sock *sk,
230 struct sk_buff *skb,
231@@ -1106,6 +1134,8 @@ static int vxlan6_xmit_skb(struct dst_entry *dst, struct sock *sk,
232
233 if (vxflags & VXLAN_F_GBP) 97 if (vxflags & VXLAN_F_GBP)
234 vxlan_build_gbp_hdr(vxh, vxflags, md); 98 vxlan_build_gbp_hdr(vxh, vxflags, md);
235+ else if (vxflags & VXLAN_F_GPE) 99 if (vxflags & VXLAN_F_GPE) {
236+ vxlan_build_gpe_hdr(vxh, vxflags, md); 100- err = vxlan_build_gpe_hdr(vxh, vxflags, skb->protocol);
101+ err = vxlan_build_gpe_hdr(vxh, vxflags, inner_protocol);
102 if (err < 0)
103 goto out_free;
104- inner_protocol = skb->protocol;
105 }
237 106
238 ovs_skb_set_inner_protocol(skb, htons(ETH_P_TEB)); 107 ovs_skb_set_inner_protocol(skb, inner_protocol);
108diff --git a/datapath/vport-netdev.c b/datapath/vport-netdev.c
109index 970f7d3..0ee076b 100644
110--- a/datapath/vport-netdev.c
111+++ b/datapath/vport-netdev.c
112@@ -102,7 +102,8 @@ struct vport *ovs_netdev_link(struct vport *vport, const char *name)
113 }
239 114
115 if (vport->dev->flags & IFF_LOOPBACK ||
116- vport->dev->type != ARPHRD_ETHER ||
117+ (vport->dev->type != ARPHRD_ETHER &&
118+ vport->dev->type != ARPHRD_NONE) ||
119 ovs_is_internal_dev(vport->dev)) {
120 err = -EINVAL;
121 goto error_put;
240diff --git a/datapath/vport-vxlan.c b/datapath/vport-vxlan.c 122diff --git a/datapath/vport-vxlan.c b/datapath/vport-vxlan.c
241index c05f5d4..5d775cc 100644 123index 11965c0..e32c970 100644
242--- a/datapath/vport-vxlan.c 124--- a/datapath/vport-vxlan.c
243+++ b/datapath/vport-vxlan.c 125+++ b/datapath/vport-vxlan.c
244@@ -52,6 +52,18 @@ static int vxlan_get_options(const struct vport *vport, struct sk_buff *skb) 126@@ -52,6 +52,18 @@ static int vxlan_get_options(const struct vport *vport, struct sk_buff *skb)
@@ -277,11 +159,80 @@ index c05f5d4..5d775cc 100644
277 159
278 return 0; 160 return 0;
279 } 161 }
162diff --git a/include/openvswitch/match.h b/include/openvswitch/match.h
163index 3b7f32f..93af1b8 100644
164--- a/include/openvswitch/match.h
165+++ b/include/openvswitch/match.h
166@@ -89,6 +89,10 @@ void match_set_tun_gbp_id_masked(struct match *match, ovs_be16 gbp_id, ovs_be16
167 void match_set_tun_gbp_id(struct match *match, ovs_be16 gbp_id);
168 void match_set_tun_gbp_flags_masked(struct match *match, uint8_t flags, uint8_t mask);
169 void match_set_tun_gbp_flags(struct match *match, uint8_t flags);
170+void match_set_tun_gpe_np_masked(struct match *match, uint8_t gpe_np, uint8_t mask);
171+void match_set_tun_gpe_np(struct match *match, uint8_t gpe_np);
172+void match_set_tun_gpe_flags_masked(struct match *match, uint8_t flags, uint8_t mask);
173+void match_set_tun_gpe_flags(struct match *match, uint8_t flags);
174 void match_set_in_port(struct match *, ofp_port_t ofp_port);
175 void match_set_pkt_mark(struct match *, uint32_t pkt_mark);
176 void match_set_pkt_mark_masked(struct match *, uint32_t pkt_mark, uint32_t mask);
177diff --git a/include/openvswitch/meta-flow.h b/include/openvswitch/meta-flow.h
178index b091c1b..9e569ef 100644
179--- a/include/openvswitch/meta-flow.h
180+++ b/include/openvswitch/meta-flow.h
181@@ -493,6 +493,34 @@ enum OVS_PACKED_ENUM mf_field_id {
182 */
183 MFF_TUN_GBP_FLAGS,
184
185+ /* "tun_gpe_np".
186+ *
187+ * VXLAN Generic Protocol Extension next_proto
188+ *
189+ * Type: u8.
190+ * Maskable: bitwise.
191+ * Formatting: hexadecimal.
192+ * Prerequisites: none.
193+ * Access: read/write.
194+ * NXM: NXM_NX_TUN_GPE_NP(200) since v2.4.
195+ * OXM: none.
196+ */
197+ MFF_TUN_GPE_NP,
198+
199+ /* "tun_gpe_flags".
200+ *
201+ * VXLAN Generic Protocol Extension flag
202+ *
203+ * Type: u8.
204+ * Maskable: bitwise.
205+ * Formatting: hexadecimal.
206+ * Prerequisites: none.
207+ * Access: read/write.
208+ * NXM: NXM_NX_TUN_GPE_FLAGS(201) since v2.4.
209+ * OXM: none.
210+ */
211+ MFF_TUN_GPE_FLAGS,
212+
213 #if TUN_METADATA_NUM_OPTS == 64
214 /* "tun_metadata<N>".
215 *
216diff --git a/include/openvswitch/packets.h b/include/openvswitch/packets.h
217index 5d97309..1e82df0 100644
218--- a/include/openvswitch/packets.h
219+++ b/include/openvswitch/packets.h
220@@ -34,7 +34,9 @@ struct flow_tnl {
221 ovs_be16 tp_dst;
222 ovs_be16 gbp_id;
223 uint8_t gbp_flags;
224- uint8_t pad1[5]; /* Pad to 64 bits. */
225+ uint8_t gpe_np;
226+ uint8_t gpe_flags;
227+ uint8_t pad1[3]; /* Pad to 64 bits. */
228 struct tun_metadata metadata;
229 };
230
280diff --git a/lib/flow.c b/lib/flow.c 231diff --git a/lib/flow.c b/lib/flow.c
281index b9ce331..d24bdc9 100644 232index ba4f8c7..375979b 100644
282--- a/lib/flow.c 233--- a/lib/flow.c
283+++ b/lib/flow.c 234+++ b/lib/flow.c
284@@ -870,6 +870,12 @@ flow_get_metadata(const struct flow *flow, struct match *flow_metadata) 235@@ -897,6 +897,12 @@ flow_get_metadata(const struct flow *flow, struct match *flow_metadata)
285 if (flow->tunnel.gbp_flags) { 236 if (flow->tunnel.gbp_flags) {
286 match_set_tun_gbp_flags(flow_metadata, flow->tunnel.gbp_flags); 237 match_set_tun_gbp_flags(flow_metadata, flow->tunnel.gbp_flags);
287 } 238 }
@@ -294,7 +245,7 @@ index b9ce331..d24bdc9 100644
294 tun_metadata_get_fmd(&flow->tunnel, flow_metadata); 245 tun_metadata_get_fmd(&flow->tunnel, flow_metadata);
295 if (flow->metadata != htonll(0)) { 246 if (flow->metadata != htonll(0)) {
296 match_set_metadata(flow_metadata, flow->metadata); 247 match_set_metadata(flow_metadata, flow->metadata);
297@@ -1265,6 +1271,8 @@ void flow_wildcards_init_for_packet(struct flow_wildcards *wc, 248@@ -1292,6 +1298,8 @@ void flow_wildcards_init_for_packet(struct flow_wildcards *wc,
298 WC_MASK_FIELD(wc, tunnel.tp_dst); 249 WC_MASK_FIELD(wc, tunnel.tp_dst);
299 WC_MASK_FIELD(wc, tunnel.gbp_id); 250 WC_MASK_FIELD(wc, tunnel.gbp_id);
300 WC_MASK_FIELD(wc, tunnel.gbp_flags); 251 WC_MASK_FIELD(wc, tunnel.gbp_flags);
@@ -304,10 +255,10 @@ index b9ce331..d24bdc9 100644
304 if (!(flow->tunnel.flags & FLOW_TNL_F_UDPIF)) { 255 if (!(flow->tunnel.flags & FLOW_TNL_F_UDPIF)) {
305 if (flow->tunnel.metadata.present.map) { 256 if (flow->tunnel.metadata.present.map) {
306diff --git a/lib/match.c b/lib/match.c 257diff --git a/lib/match.c b/lib/match.c
307index fd571d9..52437c9 100644 258index d78e6a1..f19648d 100644
308--- a/lib/match.c 259--- a/lib/match.c
309+++ b/lib/match.c 260+++ b/lib/match.c
310@@ -289,6 +289,32 @@ match_set_tun_gbp_flags(struct match *match, uint8_t flags) 261@@ -305,6 +305,32 @@ match_set_tun_gbp_flags(struct match *match, uint8_t flags)
311 } 262 }
312 263
313 void 264 void
@@ -340,7 +291,7 @@ index fd571d9..52437c9 100644
340 match_set_in_port(struct match *match, ofp_port_t ofp_port) 291 match_set_in_port(struct match *match, ofp_port_t ofp_port)
341 { 292 {
342 match->wc.masks.in_port.ofp_port = u16_to_ofp(UINT16_MAX); 293 match->wc.masks.in_port.ofp_port = u16_to_ofp(UINT16_MAX);
343@@ -1013,6 +1039,14 @@ format_flow_tunnel(struct ds *s, const struct match *match) 294@@ -1029,6 +1055,14 @@ format_flow_tunnel(struct ds *s, const struct match *match)
344 ds_put_format(s, "tun_gbp_flags=%#"PRIx8",", tnl->gbp_flags); 295 ds_put_format(s, "tun_gbp_flags=%#"PRIx8",", tnl->gbp_flags);
345 } 296 }
346 297
@@ -355,23 +306,8 @@ index fd571d9..52437c9 100644
355 if (wc->masks.tunnel.ip_tos) { 306 if (wc->masks.tunnel.ip_tos) {
356 ds_put_format(s, "tun_tos=%"PRIx8",", tnl->ip_tos); 307 ds_put_format(s, "tun_tos=%"PRIx8",", tnl->ip_tos);
357 } 308 }
358diff --git a/lib/match.h b/lib/match.h
359index 0a6ac29..48aa0b1 100644
360--- a/lib/match.h
361+++ b/lib/match.h
362@@ -86,6 +86,10 @@ void match_set_tun_gbp_id_masked(struct match *match, ovs_be16 gbp_id, ovs_be16
363 void match_set_tun_gbp_id(struct match *match, ovs_be16 gbp_id);
364 void match_set_tun_gbp_flags_masked(struct match *match, uint8_t flags, uint8_t mask);
365 void match_set_tun_gbp_flags(struct match *match, uint8_t flags);
366+void match_set_tun_gpe_np_masked(struct match *match, uint8_t gpe_np, uint8_t mask);
367+void match_set_tun_gpe_np(struct match *match, uint8_t gpe_np);
368+void match_set_tun_gpe_flags_masked(struct match *match, uint8_t flags, uint8_t mask);
369+void match_set_tun_gpe_flags(struct match *match, uint8_t flags);
370 void match_set_in_port(struct match *, ofp_port_t ofp_port);
371 void match_set_pkt_mark(struct match *, uint32_t pkt_mark);
372 void match_set_pkt_mark_masked(struct match *, uint32_t pkt_mark, uint32_t mask);
373diff --git a/lib/meta-flow.c b/lib/meta-flow.c 309diff --git a/lib/meta-flow.c b/lib/meta-flow.c
374index 721152c..ab77fca 100644 310index d07f927..5d0721f 100644
375--- a/lib/meta-flow.c 311--- a/lib/meta-flow.c
376+++ b/lib/meta-flow.c 312+++ b/lib/meta-flow.c
377@@ -213,6 +213,10 @@ mf_is_all_wild(const struct mf_field *mf, const struct flow_wildcards *wc) 313@@ -213,6 +213,10 @@ mf_is_all_wild(const struct mf_field *mf, const struct flow_wildcards *wc)
@@ -385,7 +321,7 @@ index 721152c..ab77fca 100644
385 CASE_MFF_TUN_METADATA: 321 CASE_MFF_TUN_METADATA:
386 return !ULLONG_GET(wc->masks.tunnel.metadata.present.map, 322 return !ULLONG_GET(wc->masks.tunnel.metadata.present.map,
387 mf->id - MFF_TUN_METADATA0); 323 mf->id - MFF_TUN_METADATA0);
388@@ -515,6 +519,8 @@ mf_is_value_valid(const struct mf_field *mf, const union mf_value *value) 324@@ -434,6 +438,8 @@ mf_is_value_valid(const struct mf_field *mf, const union mf_value *value)
389 case MFF_TUN_TTL: 325 case MFF_TUN_TTL:
390 case MFF_TUN_GBP_ID: 326 case MFF_TUN_GBP_ID:
391 case MFF_TUN_GBP_FLAGS: 327 case MFF_TUN_GBP_FLAGS:
@@ -394,7 +330,7 @@ index 721152c..ab77fca 100644
394 CASE_MFF_TUN_METADATA: 330 CASE_MFF_TUN_METADATA:
395 case MFF_METADATA: 331 case MFF_METADATA:
396 case MFF_IN_PORT: 332 case MFF_IN_PORT:
397@@ -648,6 +654,12 @@ mf_get_value(const struct mf_field *mf, const struct flow *flow, 333@@ -568,6 +574,12 @@ mf_get_value(const struct mf_field *mf, const struct flow *flow,
398 case MFF_TUN_GBP_FLAGS: 334 case MFF_TUN_GBP_FLAGS:
399 value->u8 = flow->tunnel.gbp_flags; 335 value->u8 = flow->tunnel.gbp_flags;
400 break; 336 break;
@@ -407,7 +343,7 @@ index 721152c..ab77fca 100644
407 case MFF_TUN_TTL: 343 case MFF_TUN_TTL:
408 value->u8 = flow->tunnel.ip_ttl; 344 value->u8 = flow->tunnel.ip_ttl;
409 break; 345 break;
410@@ -899,6 +911,12 @@ mf_set_value(const struct mf_field *mf, 346@@ -823,6 +835,12 @@ mf_set_value(const struct mf_field *mf,
411 case MFF_TUN_GBP_FLAGS: 347 case MFF_TUN_GBP_FLAGS:
412 match_set_tun_gbp_flags(match, value->u8); 348 match_set_tun_gbp_flags(match, value->u8);
413 break; 349 break;
@@ -420,7 +356,7 @@ index 721152c..ab77fca 100644
420 case MFF_TUN_TOS: 356 case MFF_TUN_TOS:
421 match_set_tun_tos(match, value->u8); 357 match_set_tun_tos(match, value->u8);
422 break; 358 break;
423@@ -1216,6 +1234,12 @@ mf_set_flow_value(const struct mf_field *mf, 359@@ -1161,6 +1179,12 @@ mf_set_flow_value(const struct mf_field *mf,
424 case MFF_TUN_GBP_FLAGS: 360 case MFF_TUN_GBP_FLAGS:
425 flow->tunnel.gbp_flags = value->u8; 361 flow->tunnel.gbp_flags = value->u8;
426 break; 362 break;
@@ -433,7 +369,7 @@ index 721152c..ab77fca 100644
433 case MFF_TUN_TOS: 369 case MFF_TUN_TOS:
434 flow->tunnel.ip_tos = value->u8; 370 flow->tunnel.ip_tos = value->u8;
435 break; 371 break;
436@@ -1535,6 +1559,12 @@ mf_set_wild(const struct mf_field *mf, struct match *match, char **err_str) 372@@ -1484,6 +1508,12 @@ mf_set_wild(const struct mf_field *mf, struct match *match, char **err_str)
437 case MFF_TUN_GBP_FLAGS: 373 case MFF_TUN_GBP_FLAGS:
438 match_set_tun_gbp_flags_masked(match, 0, 0); 374 match_set_tun_gbp_flags_masked(match, 0, 0);
439 break; 375 break;
@@ -446,7 +382,7 @@ index 721152c..ab77fca 100644
446 case MFF_TUN_TOS: 382 case MFF_TUN_TOS:
447 match_set_tun_tos_masked(match, 0, 0); 383 match_set_tun_tos_masked(match, 0, 0);
448 break; 384 break;
449@@ -1838,6 +1868,12 @@ mf_set(const struct mf_field *mf, 385@@ -1793,6 +1823,12 @@ mf_set(const struct mf_field *mf,
450 case MFF_TUN_GBP_FLAGS: 386 case MFF_TUN_GBP_FLAGS:
451 match_set_tun_gbp_flags_masked(match, value->u8, mask->u8); 387 match_set_tun_gbp_flags_masked(match, value->u8, mask->u8);
452 break; 388 break;
@@ -459,50 +395,11 @@ index 721152c..ab77fca 100644
459 case MFF_TUN_TTL: 395 case MFF_TUN_TTL:
460 match_set_tun_ttl_masked(match, value->u8, mask->u8); 396 match_set_tun_ttl_masked(match, value->u8, mask->u8);
461 break; 397 break;
462diff --git a/lib/meta-flow.h b/lib/meta-flow.h
463index c73a1af..4bd9ff6 100644
464--- a/lib/meta-flow.h
465+++ b/lib/meta-flow.h
466@@ -491,6 +491,34 @@ enum OVS_PACKED_ENUM mf_field_id {
467 */
468 MFF_TUN_GBP_FLAGS,
469
470+ /* "tun_gpe_np".
471+ *
472+ * VXLAN Generic Protocol Extension next_proto
473+ *
474+ * Type: u8.
475+ * Maskable: bitwise.
476+ * Formatting: hexadecimal.
477+ * Prerequisites: none.
478+ * Access: read/write.
479+ * NXM: NXM_NX_TUN_GPE_NP(111) since v2.4.
480+ * OXM: none.
481+ */
482+ MFF_TUN_GPE_NP,
483+
484+ /* "tun_gpe_flags".
485+ *
486+ * VXLAN Generic Protocol Extension flag
487+ *
488+ * Type: u8.
489+ * Maskable: bitwise.
490+ * Formatting: hexadecimal.
491+ * Prerequisites: none.
492+ * Access: read/write.
493+ * NXM: NXM_NX_TUN_GPE_FLAGS(112) since v2.4.
494+ * OXM: none.
495+ */
496+ MFF_TUN_GPE_FLAGS,
497+
498 #if TUN_METADATA_NUM_OPTS == 64
499 /* "tun_metadata<N>".
500 *
501diff --git a/lib/netdev-vport.c b/lib/netdev-vport.c 398diff --git a/lib/netdev-vport.c b/lib/netdev-vport.c
502index e398562..92ceec1 100644 399index ac31da6..cff0f5c 100644
503--- a/lib/netdev-vport.c 400--- a/lib/netdev-vport.c
504+++ b/lib/netdev-vport.c 401+++ b/lib/netdev-vport.c
505@@ -583,6 +583,8 @@ set_tunnel_config(struct netdev *dev_, const struct smap *args) 402@@ -526,6 +526,8 @@ set_tunnel_config(struct netdev *dev_, const struct smap *args)
506 while (ext) { 403 while (ext) {
507 if (!strcmp(type, "vxlan") && !strcmp(ext, "gbp")) { 404 if (!strcmp(type, "vxlan") && !strcmp(ext, "gbp")) {
508 tnl_cfg.exts |= (1 << OVS_VXLAN_EXT_GBP); 405 tnl_cfg.exts |= (1 << OVS_VXLAN_EXT_GBP);
@@ -512,10 +409,10 @@ index e398562..92ceec1 100644
512 VLOG_WARN("%s: unknown extension '%s'", name, ext); 409 VLOG_WARN("%s: unknown extension '%s'", name, ext);
513 } 410 }
514diff --git a/lib/nx-match.c b/lib/nx-match.c 411diff --git a/lib/nx-match.c b/lib/nx-match.c
515index 9f0f452..0eecac7 100644 412index b03ccf2..65d7ee3 100644
516--- a/lib/nx-match.c 413--- a/lib/nx-match.c
517+++ b/lib/nx-match.c 414+++ b/lib/nx-match.c
518@@ -1037,6 +1037,10 @@ nx_put_raw(struct ofpbuf *b, enum ofp_version oxm, const struct match *match, 415@@ -1036,6 +1036,10 @@ nx_put_raw(struct ofpbuf *b, enum ofp_version oxm, const struct match *match,
519 flow->tunnel.gbp_id, match->wc.masks.tunnel.gbp_id); 416 flow->tunnel.gbp_id, match->wc.masks.tunnel.gbp_id);
520 nxm_put_8m(b, MFF_TUN_GBP_FLAGS, oxm, 417 nxm_put_8m(b, MFF_TUN_GBP_FLAGS, oxm,
521 flow->tunnel.gbp_flags, match->wc.masks.tunnel.gbp_flags); 418 flow->tunnel.gbp_flags, match->wc.masks.tunnel.gbp_flags);
@@ -527,10 +424,10 @@ index 9f0f452..0eecac7 100644
527 424
528 /* Registers. */ 425 /* Registers. */
529diff --git a/lib/odp-util.c b/lib/odp-util.c 426diff --git a/lib/odp-util.c b/lib/odp-util.c
530index b4689cc..7983720 100644 427index 6d29b67..b9e8aa7 100644
531--- a/lib/odp-util.c 428--- a/lib/odp-util.c
532+++ b/lib/odp-util.c 429+++ b/lib/odp-util.c
533@@ -1727,6 +1727,7 @@ odp_actions_from_string(const char *s, const struct simap *port_names, 430@@ -1755,6 +1755,7 @@ odp_actions_from_string(const char *s, const struct simap *port_names,
534 431
535 static const struct attr_len_tbl ovs_vxlan_ext_attr_lens[OVS_VXLAN_EXT_MAX + 1] = { 432 static const struct attr_len_tbl ovs_vxlan_ext_attr_lens[OVS_VXLAN_EXT_MAX + 1] = {
536 [OVS_VXLAN_EXT_GBP] = { .len = 4 }, 433 [OVS_VXLAN_EXT_GBP] = { .len = 4 },
@@ -538,7 +435,7 @@ index b4689cc..7983720 100644
538 }; 435 };
539 436
540 static const struct attr_len_tbl ovs_tun_key_attr_lens[OVS_TUNNEL_KEY_ATTR_MAX + 1] = { 437 static const struct attr_len_tbl ovs_tun_key_attr_lens[OVS_TUNNEL_KEY_ATTR_MAX + 1] = {
541@@ -1888,7 +1889,10 @@ odp_tun_key_from_attr__(const struct nlattr *attr, 438@@ -1916,7 +1917,10 @@ odp_tun_key_from_attr__(const struct nlattr *attr,
542 break; 439 break;
543 case OVS_TUNNEL_KEY_ATTR_VXLAN_OPTS: { 440 case OVS_TUNNEL_KEY_ATTR_VXLAN_OPTS: {
544 static const struct nl_policy vxlan_opts_policy[] = { 441 static const struct nl_policy vxlan_opts_policy[] = {
@@ -550,7 +447,7 @@ index b4689cc..7983720 100644
550 }; 447 };
551 struct nlattr *ext[ARRAY_SIZE(vxlan_opts_policy)]; 448 struct nlattr *ext[ARRAY_SIZE(vxlan_opts_policy)];
552 449
553@@ -1902,6 +1906,12 @@ odp_tun_key_from_attr__(const struct nlattr *attr, 450@@ -1930,6 +1934,12 @@ odp_tun_key_from_attr__(const struct nlattr *attr,
554 tun->gbp_id = htons(gbp & 0xFFFF); 451 tun->gbp_id = htons(gbp & 0xFFFF);
555 tun->gbp_flags = (gbp >> 16) & 0xFF; 452 tun->gbp_flags = (gbp >> 16) & 0xFF;
556 } 453 }
@@ -563,7 +460,7 @@ index b4689cc..7983720 100644
563 460
564 break; 461 break;
565 } 462 }
566@@ -1988,6 +1998,13 @@ tun_key_to_attr(struct ofpbuf *a, const struct flow_tnl *tun_key, 463@@ -2016,6 +2026,13 @@ tun_key_to_attr(struct ofpbuf *a, const struct flow_tnl *tun_key,
567 nl_msg_put_u32(a, OVS_VXLAN_EXT_GBP, 464 nl_msg_put_u32(a, OVS_VXLAN_EXT_GBP,
568 (tun_key->gbp_flags << 16) | ntohs(tun_key->gbp_id)); 465 (tun_key->gbp_flags << 16) | ntohs(tun_key->gbp_id));
569 nl_msg_end_nested(a, vxlan_opts_ofs); 466 nl_msg_end_nested(a, vxlan_opts_ofs);
@@ -577,7 +474,7 @@ index b4689cc..7983720 100644
577 } 474 }
578 tun_metadata_to_geneve_nlattr(tun_key, tun_flow_key, key_buf, a); 475 tun_metadata_to_geneve_nlattr(tun_key, tun_flow_key, key_buf, a);
579 476
580@@ -2383,6 +2400,26 @@ format_odp_tun_vxlan_opt(const struct nlattr *attr, 477@@ -2410,6 +2427,26 @@ format_odp_tun_vxlan_opt(const struct nlattr *attr,
581 ds_put_cstr(ds, "),"); 478 ds_put_cstr(ds, "),");
582 break; 479 break;
583 } 480 }
@@ -604,7 +501,7 @@ index b4689cc..7983720 100644
604 501
605 default: 502 default:
606 format_unknown_key(ds, a, ma); 503 format_unknown_key(ds, a, ma);
607@@ -3670,6 +3707,40 @@ scan_vxlan_gbp(const char *s, uint32_t *key, uint32_t *mask) 504@@ -3705,6 +3742,40 @@ scan_vxlan_gbp(const char *s, uint32_t *key, uint32_t *mask)
608 } 505 }
609 506
610 static int 507 static int
@@ -645,7 +542,7 @@ index b4689cc..7983720 100644
645 scan_geneve(const char *s, struct geneve_scan *key, struct geneve_scan *mask) 542 scan_geneve(const char *s, struct geneve_scan *key, struct geneve_scan *mask)
646 { 543 {
647 const char *s_base = s; 544 const char *s_base = s;
648@@ -3796,6 +3867,21 @@ vxlan_gbp_to_attr(struct ofpbuf *a, const void *data_) 545@@ -3831,6 +3902,21 @@ vxlan_gbp_to_attr(struct ofpbuf *a, const void *data_)
649 } 546 }
650 547
651 static void 548 static void
@@ -667,7 +564,7 @@ index b4689cc..7983720 100644
667 geneve_to_attr(struct ofpbuf *a, const void *data_) 564 geneve_to_attr(struct ofpbuf *a, const void *data_)
668 { 565 {
669 const struct geneve_scan *geneve = data_; 566 const struct geneve_scan *geneve = data_;
670@@ -4031,6 +4117,7 @@ parse_odp_key_mask_attr(const char *s, const struct simap *port_names, 567@@ -4066,6 +4152,7 @@ parse_odp_key_mask_attr(const char *s, const struct simap *port_names,
671 SCAN_FIELD_NESTED("tp_src=", ovs_be16, be16, OVS_TUNNEL_KEY_ATTR_TP_SRC); 568 SCAN_FIELD_NESTED("tp_src=", ovs_be16, be16, OVS_TUNNEL_KEY_ATTR_TP_SRC);
672 SCAN_FIELD_NESTED("tp_dst=", ovs_be16, be16, OVS_TUNNEL_KEY_ATTR_TP_DST); 569 SCAN_FIELD_NESTED("tp_dst=", ovs_be16, be16, OVS_TUNNEL_KEY_ATTR_TP_DST);
673 SCAN_FIELD_NESTED_FUNC("vxlan(gbp(", uint32_t, vxlan_gbp, vxlan_gbp_to_attr); 570 SCAN_FIELD_NESTED_FUNC("vxlan(gbp(", uint32_t, vxlan_gbp, vxlan_gbp_to_attr);
@@ -675,35 +572,20 @@ index b4689cc..7983720 100644
675 SCAN_FIELD_NESTED_FUNC("geneve(", struct geneve_scan, geneve, 572 SCAN_FIELD_NESTED_FUNC("geneve(", struct geneve_scan, geneve,
676 geneve_to_attr); 573 geneve_to_attr);
677 SCAN_FIELD_NESTED_FUNC("flags(", uint16_t, tun_flags, tun_flags_to_attr); 574 SCAN_FIELD_NESTED_FUNC("flags(", uint16_t, tun_flags, tun_flags_to_attr);
678diff --git a/lib/packets.h b/lib/packets.h
679index a8ea24b..dc97333 100644
680--- a/lib/packets.h
681+++ b/lib/packets.h
682@@ -49,7 +49,9 @@ struct flow_tnl {
683 ovs_be16 tp_dst;
684 ovs_be16 gbp_id;
685 uint8_t gbp_flags;
686- uint8_t pad1[5]; /* Pad to 64 bits. */
687+ uint8_t gpe_np;
688+ uint8_t gpe_flags;
689+ uint8_t pad1[3]; /* Pad to 64 bits. */
690 struct tun_metadata metadata;
691 };
692
693diff --git a/tests/ofproto.at b/tests/ofproto.at 575diff --git a/tests/ofproto.at b/tests/ofproto.at
694index fbb6d71..6c7217d 100644 576index 6e55270..7b7f02b 100644
695--- a/tests/ofproto.at 577--- a/tests/ofproto.at
696+++ b/tests/ofproto.at 578+++ b/tests/ofproto.at
697@@ -1775,7 +1775,7 @@ head_table () { 579@@ -2190,7 +2190,7 @@ head_table () {
698 instructions: meter,apply_actions,clear_actions,write_actions,write_metadata,goto_table 580 instructions: meter,apply_actions,clear_actions,write_actions,write_metadata,goto_table
699 Write-Actions and Apply-Actions features: 581 Write-Actions and Apply-Actions features:
700 actions: output group set_field strip_vlan push_vlan mod_nw_ttl dec_ttl set_mpls_ttl dec_mpls_ttl push_mpls pop_mpls set_queue 582 actions: output group set_field strip_vlan push_vlan mod_nw_ttl dec_ttl set_mpls_ttl dec_mpls_ttl push_mpls pop_mpls set_queue
701- supported on Set-Field: tun_id tun_src tun_dst tun_ipv6_src tun_ipv6_dst tun_flags tun_gbp_id tun_gbp_flags tun_metadata0 dnl 583- supported on Set-Field: tun_id tun_src tun_dst tun_ipv6_src tun_ipv6_dst tun_flags tun_gbp_id tun_gbp_flags tun_metadata0 dnl
702+ supported on Set-Field: tun_id tun_src tun_dst tun_ipv6_src tun_ipv6_dst tun_flags tun_gbp_id tun_gbp_flags tun_gpe_np tun_gpe_flags tun_metadata0 dnl 584+ supported on Set-Field: tun_id tun_src tun_dst tun_ipv6_src tun_ipv6_dst tun_flags tun_gbp_id tun_gbp_flags tun_gpe_np tun_gpe_flags tun_metadata0 dnl
703 tun_metadata1 tun_metadata2 tun_metadata3 tun_metadata4 tun_metadata5 tun_metadata6 tun_metadata7 tun_metadata8 tun_metadata9 tun_metadata10 tun_metadata11 tun_metadata12 tun_metadata13 tun_metadata14 tun_metadata15 tun_metadata16 tun_metadata17 tun_metadata18 tun_metadata19 tun_metadata20 tun_metadata21 tun_metadata22 tun_metadata23 tun_metadata24 tun_metadata25 tun_metadata26 tun_metadata27 tun_metadata28 tun_metadata29 tun_metadata30 tun_metadata31 tun_metadata32 tun_metadata33 tun_metadata34 tun_metadata35 tun_metadata36 tun_metadata37 tun_metadata38 tun_metadata39 tun_metadata40 tun_metadata41 tun_metadata42 tun_metadata43 tun_metadata44 tun_metadata45 tun_metadata46 tun_metadata47 tun_metadata48 tun_metadata49 tun_metadata50 tun_metadata51 tun_metadata52 tun_metadata53 tun_metadata54 tun_metadata55 tun_metadata56 tun_metadata57 tun_metadata58 tun_metadata59 tun_metadata60 tun_metadata61 tun_metadata62 tun_metadata63 dnl 585 tun_metadata1 tun_metadata2 tun_metadata3 tun_metadata4 tun_metadata5 tun_metadata6 tun_metadata7 tun_metadata8 tun_metadata9 tun_metadata10 tun_metadata11 tun_metadata12 tun_metadata13 tun_metadata14 tun_metadata15 tun_metadata16 tun_metadata17 tun_metadata18 tun_metadata19 tun_metadata20 tun_metadata21 tun_metadata22 tun_metadata23 tun_metadata24 tun_metadata25 tun_metadata26 tun_metadata27 tun_metadata28 tun_metadata29 tun_metadata30 tun_metadata31 tun_metadata32 tun_metadata33 tun_metadata34 tun_metadata35 tun_metadata36 tun_metadata37 tun_metadata38 tun_metadata39 tun_metadata40 tun_metadata41 tun_metadata42 tun_metadata43 tun_metadata44 tun_metadata45 tun_metadata46 tun_metadata47 tun_metadata48 tun_metadata49 tun_metadata50 tun_metadata51 tun_metadata52 tun_metadata53 tun_metadata54 tun_metadata55 tun_metadata56 tun_metadata57 tun_metadata58 tun_metadata59 tun_metadata60 tun_metadata61 tun_metadata62 tun_metadata63 dnl
704 metadata in_port in_port_oxm pkt_mark ct_mark ct_label reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 xreg0 xreg1 xreg2 xreg3 eth_src eth_dst vlan_tci vlan_vid vlan_pcp mpls_label mpls_tc mpls_ttl ip_src ip_dst ipv6_src ipv6_dst ipv6_label nw_tos ip_dscp nw_ecn nw_ttl arp_op arp_spa arp_tpa arp_sha arp_tha tcp_src tcp_dst udp_src udp_dst sctp_src sctp_dst icmp_type icmp_code icmpv6_type icmpv6_code nd_target nd_sll nd_tll 586 metadata in_port in_port_oxm pkt_mark ct_mark ct_label reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 reg9 reg10 reg11 reg12 reg13 reg14 reg15 xreg0 xreg1 xreg2 xreg3 xreg4 xreg5 xreg6 xreg7 xxreg0 xxreg1 xxreg2 xxreg3 eth_src eth_dst vlan_tci vlan_vid vlan_pcp mpls_label mpls_tc mpls_ttl ip_src ip_dst ipv6_src ipv6_dst ipv6_label nw_tos ip_dscp nw_ecn nw_ttl arp_op arp_spa arp_tpa arp_sha arp_tha tcp_src tcp_dst udp_src udp_dst sctp_src sctp_dst icmp_type icmp_code icmpv6_type icmpv6_code nd_target nd_sll nd_tll
705 matching: 587 matching:
706@@ -1790,6 +1790,8 @@ metadata in_port in_port_oxm pkt_mark ct_mark ct_label reg0 reg1 reg2 reg3 reg4 588@@ -2205,6 +2205,8 @@ metadata in_port in_port_oxm pkt_mark ct_mark ct_label reg0 reg1 reg2 reg3 reg4
707 tun_flags: arbitrary mask 589 tun_flags: arbitrary mask
708 tun_gbp_id: arbitrary mask 590 tun_gbp_id: arbitrary mask
709 tun_gbp_flags: arbitrary mask 591 tun_gbp_flags: arbitrary mask
@@ -713,7 +595,7 @@ index fbb6d71..6c7217d 100644
713 tun_metadata1: arbitrary mask 595 tun_metadata1: arbitrary mask
714 tun_metadata2: arbitrary mask 596 tun_metadata2: arbitrary mask
715diff --git a/tests/ovs-ofctl.at b/tests/ovs-ofctl.at 597diff --git a/tests/ovs-ofctl.at b/tests/ovs-ofctl.at
716index f26f622..dde603d 100644 598index cbb818e..2267be0 100644
717--- a/tests/ovs-ofctl.at 599--- a/tests/ovs-ofctl.at
718+++ b/tests/ovs-ofctl.at 600+++ b/tests/ovs-ofctl.at
719@@ -17,6 +17,10 @@ for test_case in \ 601@@ -17,6 +17,10 @@ for test_case in \
@@ -728,5 +610,5 @@ index f26f622..dde603d 100644
728 'tun_metadata0=0/0x1 NXM,OXM' \ 610 'tun_metadata0=0/0x1 NXM,OXM' \
729 'tun_metadata0 NXM,OXM' \ 611 'tun_metadata0 NXM,OXM' \
730-- 612--
7311.9.3 6132.1.0
732 614
diff --git a/ovs_build/patches/0002-ovs-nsh-support-push-and-pop-actions-for-vxlan-gpe-a.patch b/ovs_build/ovs_nsh_patches/v2.6.1/0002-Add-NSH-support-in-kernel-and-userspace-data-planes.patch
index 24f8e59..f22e8de 100644
--- a/ovs_build/patches/0002-ovs-nsh-support-push-and-pop-actions-for-vxlan-gpe-a.patch
+++ b/ovs_build/ovs_nsh_patches/v2.6.1/0002-Add-NSH-support-in-kernel-and-userspace-data-planes.patch
@@ -1,57 +1,68 @@
1From bd251cb247ac44e4362215da826e9bf1d6c61f27 Mon Sep 17 00:00:00 2001 1From 653c2f6777a6c4f3559a55c8f5a88f4aca313788 Mon Sep 17 00:00:00 2001
2From: Yi Yang <yi.y.yang@intel.com> 2From: Yi Yang <yi.y.yang@intel.com>
3Date: Wed, 13 Apr 2016 11:15:42 +0800 3Date: Mon, 14 Nov 2016 12:08:14 +0800
4Subject: [PATCH 2/6] ovs-nsh: support push and pop actions for vxlan-gpe and 4Subject: [PATCH 2/8] Add NSH support in kernel and userspace data planes
5 Ethernet nsh 5
6features includes:
7 * push_nsh and pop_nsh actions
8 * support Ethernet+NSH and VxLAN-gpe+NSH
9 * support the same features in DPDK netdev
10 * news match fields: nsp, nsi, nshc1, nshc2, nshc3, nshc4, nsh_mdtype,
11 nsh_np, encap_eth_src, encap_eth_dst, encap_eth_type, gpe_np
6 12
7Signed-off-by: Mengke Liu <mengke.liu@intel.com>
8Signed-off-by: Ricky Li <ricky.li@intel.com>
9Signed-off-by: Johnson Li <johnson.li@intel.com>
10Signed-off-by: Yi Yang <yi.y.yang@intel.com> 13Signed-off-by: Yi Yang <yi.y.yang@intel.com>
11--- 14---
12 datapath/actions.c | 73 ++++ 15 datapath/actions.c | 39 +++
13 datapath/datapath.h | 2 + 16 datapath/datapath.h | 2 +
14 datapath/flow.c | 107 ++++++ 17 datapath/flow.c | 101 +++++++
15 datapath/flow.h | 15 + 18 datapath/flow.h | 1 +
16 datapath/flow_netlink.c | 81 ++++- 19 datapath/flow_netlink.c | 59 +++-
17 datapath/linux/compat/include/linux/openvswitch.h | 174 +++++++++ 20 datapath/linux/compat/include/linux/openvswitch.h | 166 ++++++++++++
18 datapath/linux/compat/include/net/vxlan.h | 5 +- 21 include/openvswitch/automake.mk | 3 +-
19 lib/dpif-netdev.c | 4 + 22 include/openvswitch/flow.h | 19 +-
20 lib/dpif.c | 4 + 23 include/openvswitch/match.h | 24 ++
21 lib/flow.c | 19 + 24 include/openvswitch/meta-flow.h | 174 ++++++++++++
22 lib/flow.h | 21 +- 25 include/openvswitch/ofp-actions.h | 4 +
23 lib/match.c | 190 ++++++++++ 26 include/openvswitch/vxlangpe.h | 76 ++++++
24 lib/match.h | 24 ++ 27 lib/dpif-netdev.c | 39 ++-
25 lib/meta-flow.c | 256 ++++++++++++- 28 lib/dpif.c | 2 +
26 lib/meta-flow.h | 174 +++++++++ 29 lib/flow.c | 106 +++++++-
30 lib/match.c | 189 +++++++++++++
31 lib/meta-flow.c | 256 +++++++++++++++++-
32 lib/netdev-native-tnl.c | 91 ++++++-
27 lib/netdev-vport.c | 10 +- 33 lib/netdev-vport.c | 10 +-
28 lib/nx-match.c | 19 + 34 lib/netdev-vport.h | 6 +
29 lib/odp-execute.c | 10 + 35 lib/nx-match.c | 18 ++
30 lib/odp-util.c | 417 +++++++++++++++++++++- 36 lib/odp-execute.c | 19 ++
31 lib/odp-util.h | 10 +- 37 lib/odp-util.c | 279 ++++++++++++++++++-
32 lib/ofp-actions.c | 154 +++++++- 38 lib/odp-util.h | 6 +-
33 lib/ofp-actions.h | 6 + 39 lib/ofp-actions.c | 80 +++++-
34 ofproto/ofproto-dpif-sflow.c | 2 + 40 lib/packets.c | 23 ++
35 ofproto/ofproto-dpif-upcall.c | 19 + 41 lib/packets.h | 3 +
36 ofproto/ofproto-dpif-xlate.c | 22 ++ 42 ofproto/ofproto-dpif-sflow.c | 1 +
37 tests/ofproto.at | 13 +- 43 ofproto/ofproto-dpif-upcall.c | 11 +
38 tests/tunnel.at | 157 ++++++++ 44 ofproto/ofproto-dpif-xlate.c | 13 +
39 27 files changed, 1976 insertions(+), 12 deletions(-) 45 ofproto/ofproto-dpif.h | 1 -
46 ofproto/tunnel.c | 1 +
47 tests/ofproto.at | 12 +-
48 tests/tunnel.at | 316 ++++++++++++++++++++++
49 34 files changed, 2115 insertions(+), 35 deletions(-)
50 create mode 100644 include/openvswitch/vxlangpe.h
40 51
41diff --git a/datapath/actions.c b/datapath/actions.c 52diff --git a/datapath/actions.c b/datapath/actions.c
42index dcf8591..16fc58f 100644 53index 82833d0..c979596 100644
43--- a/datapath/actions.c 54--- a/datapath/actions.c
44+++ b/datapath/actions.c 55+++ b/datapath/actions.c
45@@ -252,6 +252,63 @@ static int push_vlan(struct sk_buff *skb, struct sw_flow_key *key, 56@@ -265,6 +265,37 @@ static int push_vlan(struct sk_buff *skb, struct sw_flow_key *key,
46 ntohs(vlan->vlan_tci) & ~VLAN_TAG_PRESENT); 57 ntohs(vlan->vlan_tci) & ~VLAN_TAG_PRESENT);
47 } 58 }
48 59
49+static int pop_nsh(struct sk_buff *skb, struct sw_flow_key *key) 60+static int pop_nsh(struct sk_buff *skb, struct sw_flow_key *key)
50+{ 61+{
51+ if (!pskb_may_pull(skb, NSH_M_TYPE1_LEN)) 62+ if (!pskb_may_pull(skb, ETH_NSH_TYPE1_HEADER_SIZE))
52+ return -ENOMEM; 63+ return -ENOMEM;
53+ else 64+ else
54+ __skb_pull(skb, NSH_M_TYPE1_LEN); 65+ __skb_pull(skb, ETH_NSH_TYPE1_HEADER_SIZE);
55+ 66+
56+ return 0; 67+ return 0;
57+} 68+}
@@ -61,52 +72,26 @@ index dcf8591..16fc58f 100644
61+{ 72+{
62+ 73+
63+ if (nsh->nsh_mdtype == NSH_M_TYPE1) { 74+ if (nsh->nsh_mdtype == NSH_M_TYPE1) {
64+ if (skb_cow_head(skb, NSH_M_TYPE1_LEN) < 0) 75+ if (skb_cow_head(skb, ETH_NSH_TYPE1_HEADER_SIZE) < 0) {
65+ return -ENOMEM;
66+
67+ skb_push(skb, NSH_M_TYPE1_LEN);
68+ OVS_CB(skb)->nsh_header = skb->data;
69+ memcpy(OVS_CB(skb)->nsh_header, nsh->header, NSH_M_TYPE1_LEN);
70+ }
71+ else
72+ return -EINVAL;
73+
74+ return 0;
75+}
76+
77+static int pop_eth(struct sk_buff *skb, struct sw_flow_key *key)
78+{
79+ if (!pskb_may_pull(skb, ENCAP_ETH_PUSH_HEADER_SIZE))
80+ return -ENOMEM;
81+ else
82+ __skb_pull(skb, ENCAP_ETH_PUSH_HEADER_SIZE);
83+
84+ return 0;
85+}
86+
87+static int push_eth(struct sk_buff *skb, struct sw_flow_key *key,
88+ const struct ovs_action_push_eth *encap_eth)
89+{
90+ if (encap_eth->encap_eth_type == htons(ETH_P_NSH)) {
91+ if (skb_cow_head(skb, ENCAP_ETH_PUSH_HEADER_SIZE) < 0)
92+ return -ENOMEM; 76+ return -ENOMEM;
77+ }
93+ 78+
94+ skb_push(skb, ENCAP_ETH_PUSH_HEADER_SIZE); 79+ skb_push(skb, ETH_NSH_TYPE1_HEADER_SIZE);
95+ OVS_CB(skb)->encap_eth_header = skb->data; 80+ OVS_CB(skb)->encap_eth_header = (struct encap_eth_hdr *)skb->data;
96+ memcpy(OVS_CB(skb)->encap_eth_header, encap_eth->header, ENCAP_ETH_PUSH_HEADER_SIZE); 81+ OVS_CB(skb)->nsh_header = (struct nsh_hdr *)(skb->data + ENCAP_ETH_LEN);
82+ memcpy(skb->data, nsh->header, ETH_NSH_TYPE1_HEADER_SIZE);
83+ OVS_CB(skb)->encap_eth_header->encap_eth_type = htons(ETH_P_NSH);
97+ } 84+ }
98+ else { 85+ else
99+ return -EINVAL; 86+ return -EINVAL;
100+ }
101+ 87+
102+ return 0; 88+ return 0;
103+} 89+}
104+ 90+
105+
106 /* 'src' is already properly masked. */ 91 /* 'src' is already properly masked. */
107 static void ether_addr_copy_masked(u8 *dst_, const u8 *src_, const u8 *mask_) 92 static void ether_addr_copy_masked(u8 *dst_, const u8 *src_, const u8 *mask_)
108 { 93 {
109@@ -1079,6 +1136,22 @@ static int do_execute_actions(struct datapath *dp, struct sk_buff *skb, 94@@ -1140,6 +1171,14 @@ static int do_execute_actions(struct datapath *dp, struct sk_buff *skb,
110 err = pop_vlan(skb, key); 95 err = pop_vlan(skb, key);
111 break; 96 break;
112 97
@@ -118,32 +103,24 @@ index dcf8591..16fc58f 100644
118+ err = pop_nsh(skb, key); 103+ err = pop_nsh(skb, key);
119+ break; 104+ break;
120+ 105+
121+ case OVS_ACTION_ATTR_PUSH_ETH:
122+ err = push_eth(skb, key, nla_data(a));
123+ break;
124+
125+ case OVS_ACTION_ATTR_POP_ETH:
126+ err = pop_eth(skb, key);
127+ break;
128+
129 case OVS_ACTION_ATTR_RECIRC: 106 case OVS_ACTION_ATTR_RECIRC:
130 err = execute_recirc(dp, skb, key, a, rem); 107 err = execute_recirc(dp, skb, key, a, rem);
131 if (nla_is_last(a, rem)) { 108 if (nla_is_last(a, rem)) {
132diff --git a/datapath/datapath.h b/datapath/datapath.h 109diff --git a/datapath/datapath.h b/datapath/datapath.h
133index ceb3372..b2d5fcd 100644 110index 22bbaac..a6b2a44 100644
134--- a/datapath/datapath.h 111--- a/datapath/datapath.h
135+++ b/datapath/datapath.h 112+++ b/datapath/datapath.h
136@@ -102,6 +102,8 @@ struct datapath { 113@@ -108,6 +108,8 @@ struct ovs_skb_cb {
137 struct ovs_skb_cb {
138 struct vport *input_vport; 114 struct vport *input_vport;
139 u16 mru; 115 u16 mru;
140+ struct nsh_hdr *nsh_header; 116 u32 cutlen;
141+ struct encap_eth_hdr *encap_eth_header; 117+ struct nsh_hdr *nsh_header;
118+ struct encap_eth_hdr *encap_eth_header;
142 }; 119 };
143 #define OVS_CB(skb) ((struct ovs_skb_cb *)(skb)->cb) 120 #define OVS_CB(skb) ((struct ovs_skb_cb *)(skb)->cb)
144 121
145diff --git a/datapath/flow.c b/datapath/flow.c 122diff --git a/datapath/flow.c b/datapath/flow.c
146index c97c9c9..67b2f1d 100644 123index 390286c..8c4d583 100644
147--- a/datapath/flow.c 124--- a/datapath/flow.c
148+++ b/datapath/flow.c 125+++ b/datapath/flow.c
149@@ -44,6 +44,7 @@ 126@@ -44,6 +44,7 @@
@@ -154,13 +131,17 @@ index c97c9c9..67b2f1d 100644
154 131
155 #include "datapath.h" 132 #include "datapath.h"
156 #include "conntrack.h" 133 #include "conntrack.h"
157@@ -318,6 +319,32 @@ static int parse_vlan(struct sk_buff *skb, struct sw_flow_key *key) 134@@ -323,6 +324,26 @@ static int parse_vlan(struct sk_buff *skb, struct sw_flow_key *key)
158 return 0; 135 return 0;
159 } 136 }
160 137
161+static int parse_nsh(struct sk_buff *skb, struct sw_flow_key *key){ 138+static int parse_nsh(struct sk_buff *skb, struct sw_flow_key *key){
162+ struct nsh_hdr *nsh_hdr = (struct nsh_hdr *)skb->data; 139+ struct nsh_hdr *nsh_hdr = NULL;
140+
141+ OVS_CB(skb)->encap_eth_header = (struct encap_eth_hdr *)skb->data;
142+ nsh_hdr = (struct nsh_hdr *)((const char *)skb->data + ENCAP_ETH_LEN);
163+ OVS_CB(skb)->nsh_header = nsh_hdr; 143+ OVS_CB(skb)->nsh_header = nsh_hdr;
144+ memcpy(&key->nsh.encap_eth_dst, skb->data, ENCAP_ETH_LEN);
164+ key->nsh.nsh_mdtype = nsh_hdr->base.mdtype; 145+ key->nsh.nsh_mdtype = nsh_hdr->base.mdtype;
165+ if (key->nsh.nsh_mdtype != NSH_M_TYPE1) 146+ if (key->nsh.nsh_mdtype != NSH_M_TYPE1)
166+ return -EPERM; 147+ return -EPERM;
@@ -174,58 +155,46 @@ index c97c9c9..67b2f1d 100644
174+ return 0; 155+ return 0;
175+} 156+}
176+ 157+
177+static void parse_encap_eth(struct sk_buff *skb, struct sw_flow_key *key){
178+ struct encap_eth_hdr *encap_eth_header = (struct encap_eth_hdr *)skb->data;
179+ OVS_CB(skb)->encap_eth_header = encap_eth_header;
180+ key->encap_eth.encap_eth_type = encap_eth_header->encap_eth_type;
181+ ether_addr_copy(key->encap_eth.encap_eth_src, encap_eth_header->encap_eth_src);
182+ ether_addr_copy(key->encap_eth.encap_eth_dst, encap_eth_header->encap_eth_dst);
183+
184+ return;
185+}
186+
187 static __be16 parse_ethertype(struct sk_buff *skb) 158 static __be16 parse_ethertype(struct sk_buff *skb)
188 { 159 {
189 struct llc_snap_hdr { 160 struct llc_snap_hdr {
190@@ -457,6 +484,24 @@ static int key_extract(struct sk_buff *skb, struct sw_flow_key *key) 161@@ -461,6 +482,22 @@ static int key_extract(struct sk_buff *skb, struct sw_flow_key *key)
162 {
191 int error; 163 int error;
192 struct ethhdr *eth; 164 struct ethhdr *eth;
193 165+ int is_eth_nsh = 0;
166+
194+ /* Extract ethernet+nsh if ethernet type is 0x894F */ 167+ /* Extract ethernet+nsh if ethernet type is 0x894F */
195+ eth = (struct ethhdr *)skb->data; 168+ eth = (struct ethhdr *)skb->data;
196+ if (eth->h_proto == htons(ETH_P_NSH)) { 169+ if (eth->h_proto == htons(ETH_P_NSH)) {
197+ parse_encap_eth(skb, key);
198+ __skb_pull(skb, ENCAP_ETH_LEN);
199+
200+ if (unlikely(parse_nsh(skb, key))) 170+ if (unlikely(parse_nsh(skb, key)))
201+ return -EINVAL; 171+ return -EINVAL;
202+ if (key->nsh.nsh_mdtype == NSH_M_TYPE1 && key->nsh.nsh_np == NSH_P_ETHERNET) { 172+ if (key->nsh.nsh_mdtype == NSH_M_TYPE1 && key->nsh.nsh_np == NSH_P_ETHERNET) {
203+ __skb_pull(skb, NSH_M_TYPE1_LEN); 173+ __skb_pull(skb, ENCAP_ETH_LEN + NSH_M_TYPE1_LEN);
174+ is_eth_nsh = 1;
204+ } else { 175+ } else {
205+ return -EINVAL; 176+ return -EINVAL;
206+ } 177+ }
207+ } else { 178+ } else {
208+ void *encap_eth_hdr = &(key->encap_eth); 179+ memset(&key->nsh, 0, sizeof(key->nsh));
209+ memset(encap_eth_hdr, 0, ENCAP_ETH_LEN);
210+ } 180+ }
211+ 181
212 /* Flags are always used as part of stats */ 182 /* Flags are always used as part of stats */
213 key->tp.flags = 0; 183 key->tp.flags = 0;
214 184@@ -685,11 +722,56 @@ static int key_extract(struct sk_buff *skb, struct sw_flow_key *key)
215@@ -676,11 +721,54 @@ static int key_extract(struct sk_buff *skb, struct sw_flow_key *key)
216 } 185 }
217 } 186 }
218 } 187 }
219+ 188+
220+ if (key->encap_eth.encap_eth_type == htons(ETH_P_NSH)) 189+ if (is_eth_nsh == 1) {
221+ __skb_push(skb, ENCAP_ETH_LEN + NSH_M_TYPE1_LEN); 190+ __skb_push(skb, ENCAP_ETH_LEN + NSH_M_TYPE1_LEN);
191+ }
222+ 192+
223+ return 0; 193 return 0;
224+} 194 }
225+ 195
226+static void ovs_key_nsh_init(struct sw_flow_key *key, __u16 len) { 196+static void ovs_key_nsh_init(struct sw_flow_key *key) {
227+ void *nsh_hdr = &(key->nsh); 197+ memset(&key->nsh, 0, sizeof(key->nsh));
228+ memset(nsh_hdr, 0, len);
229+} 198+}
230+ 199+
231+static int nsh_extract(struct sk_buff *skb, struct sw_flow_key *key) { 200+static int nsh_extract(struct sk_buff *skb, struct sw_flow_key *key) {
@@ -235,98 +204,86 @@ index c97c9c9..67b2f1d 100644
235+ if (unlikely(parse_nsh(skb, key))) 204+ if (unlikely(parse_nsh(skb, key)))
236+ return -EINVAL; 205+ return -EINVAL;
237+ if (key->nsh.nsh_mdtype == NSH_M_TYPE1) { 206+ if (key->nsh.nsh_mdtype == NSH_M_TYPE1) {
238+ __skb_pull(skb, NSH_M_TYPE1_LEN); 207+ __skb_pull(skb, ENCAP_ETH_LEN + NSH_M_TYPE1_LEN);
239+ if(key->nsh.nsh_np == NSH_P_ETHERNET) 208+ if(key->nsh.nsh_np == NSH_P_ETHERNET)
240+ ret = key_extract(skb, key); 209+ ret = key_extract(skb, key);
241+ else 210+ else
242+ return -EINVAL; 211+ return -EINVAL;
243+ __skb_push(skb, NSH_M_TYPE1_LEN); 212+ __skb_push(skb, ENCAP_ETH_LEN + NSH_M_TYPE1_LEN);
244+ 213+
245+ return ret; 214+ return ret;
246+ } else { 215+ } else {
247+ ovs_key_nsh_init(key, NSH_M_TYPE1_LEN); 216+ ovs_key_nsh_init(key);
248+ } 217+ }
249+ 218+
250 return 0; 219+ return 0;
251 } 220+}
252
253+static bool is_nsh_header(const void *tun_opts, __be16 tun_flags) {
254+ struct vxlan_metadata *md = NULL;
255+ if (tun_opts && (tun_flags & TUNNEL_VXLAN_OPT))
256+ md = (struct vxlan_metadata *)tun_opts;
257+ 221+
258+ if (md && (md->gpe & VXLAN_GPE_NP_MASK) == VXLAN_GPE_NP_NSH) 222+static bool is_nsh_header(const void *tun_opts, __be16 tun_flags, struct sk_buff *skb) {
223+ if (tun_opts && (tun_flags & TUNNEL_VXLAN_OPT)) {
224+ /* ethernet+nsh if ethernet type is 0x894F */
225+ struct ethhdr * eth = (struct ethhdr *)skb->data;
226+ if (eth->h_proto == htons(ETH_P_NSH)) {
259+ return true; 227+ return true;
260+ else 228+ } else {
261+ return false; 229+ return false;
230+ }
231+ }
232+ return false;
262+} 233+}
263+ 234+
264 int ovs_flow_key_update(struct sk_buff *skb, struct sw_flow_key *key) 235 int ovs_flow_key_update(struct sk_buff *skb, struct sw_flow_key *key)
265 { 236 {
266+ ovs_key_nsh_init(key, NSH_M_TYPE1_LEN); 237+ ovs_key_nsh_init(key);
267 return key_extract(skb, key); 238 return key_extract(skb, key);
268 } 239 }
269 240
270@@ -715,6 +803,15 @@ int ovs_flow_key_extract(const struct ip_tunnel_info *tun_info, 241@@ -723,6 +805,15 @@ int ovs_flow_key_extract(const struct ip_tunnel_info *tun_info,
271 key->ovs_flow_hash = 0; 242 key->ovs_flow_hash = 0;
272 key->recirc_id = 0; 243 key->recirc_id = 0;
273 244
274+ /* Extract NSH and inner Ethernet if NSH header exists */ 245+ /* Extract NSH and inner Ethernet if NSH header exists */
275+ if (tun_info && is_nsh_header(ip_tunnel_info_opts(tun_info), key->tun_key.tun_flags)) { 246+ if (tun_info && is_nsh_header(TUN_METADATA_OPTS(key, key->tun_opts_len), key->tun_key.tun_flags, skb)) {
276+ int ret ; 247+ int ret ;
277+ ret = nsh_extract(skb, key); 248+ ret = nsh_extract(skb, key);
278+ if (key->nsh.nsh_mdtype) 249+ if (key->nsh.nsh_mdtype)
279+ return ret; 250+ return ret;
280+ } else { 251+ } else {
281+ ovs_key_nsh_init(key, NSH_M_TYPE1_LEN); 252+ ovs_key_nsh_init(key);
282+ } 253+ }
283 return key_extract(skb, key); 254 return key_extract(skb, key);
284 } 255 }
285 256
286@@ -729,5 +826,15 @@ int ovs_flow_key_extract_userspace(struct net *net, const struct nlattr *attr, 257@@ -739,5 +830,15 @@ int ovs_flow_key_extract_userspace(struct net *net, const struct nlattr *attr,
287 if (err) 258 if (err)
288 return err; 259 return err;
289 260
290+ /* Extract NSH and inner Ethernet if NSH header exists */ 261+ /* Extract NSH and inner Ethernet if NSH header exists */
291+ if (key && is_nsh_header(key->tun_opts, key->tun_key.tun_flags)) { 262+ if (key && is_nsh_header(key->tun_opts, key->tun_key.tun_flags, skb)) {
292+ int ret ; 263+ int ret ;
293+ ret = nsh_extract(skb, key); 264+ ret = nsh_extract(skb, key);
294+ if (key->nsh.nsh_mdtype) 265+ if (key->nsh.nsh_mdtype)
295+ return ret; 266+ return ret;
296+ } else { 267+ } else {
297+ ovs_key_nsh_init(key, NSH_M_TYPE1_LEN); 268+ ovs_key_nsh_init(key);
298+ } 269+ }
299+ 270+
300 return key_extract(skb, key); 271 return key_extract(skb, key);
301 } 272 }
302diff --git a/datapath/flow.h b/datapath/flow.h 273diff --git a/datapath/flow.h b/datapath/flow.h
303index c0b628a..c8ccd5f 100644 274index 2dd0696..bfe3423 100644
304--- a/datapath/flow.h 275--- a/datapath/flow.h
305+++ b/datapath/flow.h 276+++ b/datapath/flow.h
306@@ -63,6 +63,21 @@ struct sw_flow_key { 277@@ -64,6 +64,7 @@ struct sw_flow_key {
307 u32 skb_mark; /* SKB mark. */
308 u16 in_port; /* Input switch port (or DP_MAX_PORTS). */ 278 u16 in_port; /* Input switch port (or DP_MAX_PORTS). */
309 } __packed phy; /* Safe when right after 'tun_key'. */ 279 } __packed phy; /* Safe when right after 'tun_key'. */
310+ struct { 280 u8 tun_proto; /* Protocol of encapsulating tunnel. */
311+ u32 nshc1; /* NSH context C1-C4 */ 281+ struct ovs_key_nsh nsh; /* network service header */
312+ u32 nshc2;
313+ u32 nshc3;
314+ u32 nshc4;
315+ u32 nsp; /* NSH path id */
316+ u8 nsi; /* NSH index */
317+ u8 nsh_mdtype; /* NSH metadata type */
318+ u8 nsh_np; /* NSH next protocol */
319+ }__packed nsh; /* network service header */
320+ struct {
321+ u8 encap_eth_src[ETH_ALEN]; /* ENCAP ethernet source address. */
322+ u8 encap_eth_dst[ETH_ALEN]; /* ENCAP ethernet destination address. */
323+ u16 encap_eth_type; /* ENCAP ethernet type. */
324+ } encap_eth;
325 u32 ovs_flow_hash; /* Datapath computed hash value. */ 282 u32 ovs_flow_hash; /* Datapath computed hash value. */
326 u32 recirc_id; /* Recirculation ID. */ 283 u32 recirc_id; /* Recirculation ID. */
327 struct { 284 struct {
328diff --git a/datapath/flow_netlink.c b/datapath/flow_netlink.c 285diff --git a/datapath/flow_netlink.c b/datapath/flow_netlink.c
329index 351a504..ebfae37 100644 286index 2dcae07..6952380 100644
330--- a/datapath/flow_netlink.c 287--- a/datapath/flow_netlink.c
331+++ b/datapath/flow_netlink.c 288+++ b/datapath/flow_netlink.c
332@@ -284,7 +284,7 @@ size_t ovs_key_attr_size(void) 289@@ -284,7 +284,7 @@ size_t ovs_key_attr_size(void)
@@ -334,72 +291,63 @@ index 351a504..ebfae37 100644
334 * updating this function. 291 * updating this function.
335 */ 292 */
336- BUILD_BUG_ON(OVS_KEY_ATTR_TUNNEL_INFO != 26); 293- BUILD_BUG_ON(OVS_KEY_ATTR_TUNNEL_INFO != 26);
337+ BUILD_BUG_ON(OVS_KEY_ATTR_TUNNEL_INFO != 28); 294+ BUILD_BUG_ON(OVS_KEY_ATTR_TUNNEL_INFO != 27);
338 295
339 return nla_total_size(4) /* OVS_KEY_ATTR_PRIORITY */ 296 return nla_total_size(4) /* OVS_KEY_ATTR_PRIORITY */
340 + nla_total_size(0) /* OVS_KEY_ATTR_TUNNEL */ 297 + nla_total_size(0) /* OVS_KEY_ATTR_TUNNEL */
341@@ -297,6 +297,8 @@ size_t ovs_key_attr_size(void) 298@@ -297,6 +297,7 @@ size_t ovs_key_attr_size(void)
342 + nla_total_size(2) /* OVS_KEY_ATTR_CT_ZONE */ 299 + nla_total_size(2) /* OVS_KEY_ATTR_CT_ZONE */
343 + nla_total_size(4) /* OVS_KEY_ATTR_CT_MARK */ 300 + nla_total_size(4) /* OVS_KEY_ATTR_CT_MARK */
344 + nla_total_size(16) /* OVS_KEY_ATTR_CT_LABELS */ 301 + nla_total_size(16) /* OVS_KEY_ATTR_CT_LABELS */
345+ + nla_total_size(24) /* OVS_KEY_ATTR_NSH */ 302+ + nla_total_size(40) /* OVS_KEY_ATTR_NSH */
346+ + nla_total_size(14) /* OVS_KEY_ATTR_ENCAP_ETH */
347 + nla_total_size(12) /* OVS_KEY_ATTR_ETHERNET */ 303 + nla_total_size(12) /* OVS_KEY_ATTR_ETHERNET */
348 + nla_total_size(2) /* OVS_KEY_ATTR_ETHERTYPE */ 304 + nla_total_size(2) /* OVS_KEY_ATTR_ETHERTYPE */
349 + nla_total_size(4) /* OVS_KEY_ATTR_VLAN */ 305 + nla_total_size(4) /* OVS_KEY_ATTR_VLAN */
350@@ -334,6 +336,8 @@ static const struct ovs_len_tbl ovs_key_lens[OVS_KEY_ATTR_MAX + 1] = { 306@@ -336,6 +337,7 @@ static const struct ovs_len_tbl ovs_key_lens[OVS_KEY_ATTR_MAX + 1] = {
351 [OVS_KEY_ATTR_PRIORITY] = { .len = sizeof(u32) }, 307 [OVS_KEY_ATTR_PRIORITY] = { .len = sizeof(u32) },
352 [OVS_KEY_ATTR_IN_PORT] = { .len = sizeof(u32) }, 308 [OVS_KEY_ATTR_IN_PORT] = { .len = sizeof(u32) },
353 [OVS_KEY_ATTR_SKB_MARK] = { .len = sizeof(u32) }, 309 [OVS_KEY_ATTR_SKB_MARK] = { .len = sizeof(u32) },
354+ [OVS_KEY_ATTR_NSH] = { .len = sizeof(struct ovs_key_nsh) }, 310+ [OVS_KEY_ATTR_NSH] = { .len = sizeof(struct ovs_key_nsh) },
355+ [OVS_KEY_ATTR_ENCAP_ETH] = { .len = sizeof(struct ovs_key_encap_eth) },
356 [OVS_KEY_ATTR_ETHERNET] = { .len = sizeof(struct ovs_key_ethernet) }, 311 [OVS_KEY_ATTR_ETHERNET] = { .len = sizeof(struct ovs_key_ethernet) },
357 [OVS_KEY_ATTR_VLAN] = { .len = sizeof(__be16) }, 312 [OVS_KEY_ATTR_VLAN] = { .len = sizeof(__be16) },
358 [OVS_KEY_ATTR_ETHERTYPE] = { .len = sizeof(__be16) }, 313 [OVS_KEY_ATTR_ETHERTYPE] = { .len = sizeof(__be16) },
359@@ -869,6 +873,42 @@ static int ovs_key_from_nlattrs(struct net *net, struct sw_flow_match *match, 314@@ -919,6 +921,35 @@ static int ovs_key_from_nlattrs(struct net *net, struct sw_flow_match *match,
360 if (err) 315 if (err)
361 return err; 316 return err;
362 317
363+ if (attrs & (1ULL << OVS_KEY_ATTR_NSH)) { 318+ if (attrs & (1ULL << OVS_KEY_ATTR_NSH)) {
364+ const struct ovs_key_nsh *nsh_key; 319+ const struct ovs_key_nsh *nsh_key;
365+ 320+
366+ nsh_key = nla_data(a[OVS_KEY_ATTR_NSH]); 321+ nsh_key = nla_data(a[OVS_KEY_ATTR_NSH]);
367+ SW_FLOW_KEY_PUT(match, nsh.nshc1, 322+ SW_FLOW_KEY_MEMCPY(match, nsh.encap_eth_src,
323+ nsh_key->encap_eth_src, ETH_ALEN, is_mask);
324+ SW_FLOW_KEY_MEMCPY(match, nsh.encap_eth_dst,
325+ nsh_key->encap_eth_dst, ETH_ALEN, is_mask);
326+ SW_FLOW_KEY_PUT(match, nsh.encap_eth_type,
327+ nsh_key->encap_eth_type, is_mask);
328+ SW_FLOW_KEY_PUT(match, nsh.nshc1,
368+ nsh_key->nshc1, is_mask); 329+ nsh_key->nshc1, is_mask);
369+ SW_FLOW_KEY_PUT(match, nsh.nshc2, 330+ SW_FLOW_KEY_PUT(match, nsh.nshc2,
370+ nsh_key->nshc2, is_mask); 331+ nsh_key->nshc2, is_mask);
371+ SW_FLOW_KEY_PUT(match, nsh.nshc3, 332+ SW_FLOW_KEY_PUT(match, nsh.nshc3,
372+ nsh_key->nshc3, is_mask); 333+ nsh_key->nshc3, is_mask);
373+ SW_FLOW_KEY_PUT(match, nsh.nshc4, 334+ SW_FLOW_KEY_PUT(match, nsh.nshc4,
374+ nsh_key->nshc4, is_mask); 335+ nsh_key->nshc4, is_mask);
375+ SW_FLOW_KEY_PUT(match, nsh.nsh_mdtype, 336+ SW_FLOW_KEY_PUT(match, nsh.nsh_mdtype,
376+ nsh_key->nsh_mdtype, is_mask); 337+ nsh_key->nsh_mdtype, is_mask);
377+ SW_FLOW_KEY_PUT(match, nsh.nsh_np, 338+ SW_FLOW_KEY_PUT(match, nsh.nsh_np,
378+ nsh_key->nsh_np, is_mask); 339+ nsh_key->nsh_np, is_mask);
379+ SW_FLOW_KEY_PUT(match, nsh.nsp, 340+ SW_FLOW_KEY_PUT(match, nsh.nsp,
380+ nsh_key->nsp, is_mask); 341+ nsh_key->nsp, is_mask);
381+ SW_FLOW_KEY_PUT(match, nsh.nsi, 342+ SW_FLOW_KEY_PUT(match, nsh.nsi,
382+ nsh_key->nsi, is_mask); 343+ nsh_key->nsi, is_mask);
383+ attrs &= ~(1ULL << OVS_KEY_ATTR_NSH); 344+ attrs &= ~(1ULL << OVS_KEY_ATTR_NSH);
384+ } 345+ }
385+ 346+
386+ if (attrs & (1ULL << OVS_KEY_ATTR_ENCAP_ETH)) {
387+ const struct ovs_key_encap_eth *encap_eth_key;
388+
389+ encap_eth_key = nla_data(a[OVS_KEY_ATTR_ENCAP_ETH]);
390+ SW_FLOW_KEY_MEMCPY(match, encap_eth.encap_eth_src,
391+ encap_eth_key->encap_eth_src, ETH_ALEN, is_mask);
392+ SW_FLOW_KEY_MEMCPY(match, encap_eth.encap_eth_dst,
393+ encap_eth_key->encap_eth_dst, ETH_ALEN, is_mask);
394+ SW_FLOW_KEY_PUT(match, encap_eth.encap_eth_type,
395+ encap_eth_key->encap_eth_type, is_mask);
396+ attrs &= ~(1ULL << OVS_KEY_ATTR_ENCAP_ETH);
397+ }
398+
399 if (attrs & (1ULL << OVS_KEY_ATTR_ETHERNET)) { 347 if (attrs & (1ULL << OVS_KEY_ATTR_ETHERNET)) {
400 const struct ovs_key_ethernet *eth_key; 348 const struct ovs_key_ethernet *eth_key;
401 349
402@@ -1386,6 +1426,35 @@ static int __ovs_nla_put_key(const struct sw_flow_key *swkey, 350@@ -1434,6 +1465,26 @@ static int __ovs_nla_put_key(const struct sw_flow_key *swkey,
403 if (nla_put_u32(skb, OVS_KEY_ATTR_PRIORITY, output->phy.priority)) 351 if (nla_put_u32(skb, OVS_KEY_ATTR_PRIORITY, output->phy.priority))
404 goto nla_put_failure; 352 goto nla_put_failure;
405 353
@@ -410,6 +358,9 @@ index 351a504..ebfae37 100644
410+ if (!nla) 358+ if (!nla)
411+ goto nla_put_failure; 359+ goto nla_put_failure;
412+ nsh_key = nla_data(nla); 360+ nsh_key = nla_data(nla);
361+ memcpy(nsh_key->encap_eth_dst, output->nsh.encap_eth_dst, ETH_ALEN);
362+ memcpy(nsh_key->encap_eth_src, output->nsh.encap_eth_src, ETH_ALEN);
363+ nsh_key->encap_eth_type = output->nsh.encap_eth_type;
413+ nsh_key->nsi = output->nsh.nsi; 364+ nsh_key->nsi = output->nsh.nsi;
414+ nsh_key->nsp = output->nsh.nsp; 365+ nsh_key->nsp = output->nsh.nsp;
415+ nsh_key->nsh_mdtype= output->nsh.nsh_mdtype; 366+ nsh_key->nsh_mdtype= output->nsh.nsh_mdtype;
@@ -420,47 +371,31 @@ index 351a504..ebfae37 100644
420+ nsh_key->nshc4 = output->nsh.nshc4; 371+ nsh_key->nshc4 = output->nsh.nshc4;
421+ } 372+ }
422+ 373+
423+ if ((swkey->encap_eth.encap_eth_type || is_mask)) { 374 if ((swkey->tun_proto || is_mask)) {
424+ struct ovs_key_encap_eth *encap_eth_key;
425+
426+ nla = nla_reserve(skb, OVS_KEY_ATTR_ENCAP_ETH, sizeof(*encap_eth_key));
427+ if (!nla)
428+ goto nla_put_failure;
429+ encap_eth_key = nla_data(nla);
430+ memcpy(encap_eth_key->encap_eth_src, output->encap_eth.encap_eth_src, ETH_ALEN);
431+ memcpy(encap_eth_key->encap_eth_dst, output->encap_eth.encap_eth_dst, ETH_ALEN);
432+ encap_eth_key->encap_eth_type= output->encap_eth.encap_eth_type;
433+ }
434+
435 if ((swkey->tun_key.u.ipv4.dst || is_mask)) {
436 const void *opts = NULL; 375 const void *opts = NULL;
437 376
438@@ -2182,6 +2251,10 @@ static int __ovs_nla_copy_actions(struct net *net, const struct nlattr *attr, 377@@ -2235,6 +2286,8 @@ static int __ovs_nla_copy_actions(struct net *net, const struct nlattr *attr,
439 [OVS_ACTION_ATTR_POP_MPLS] = sizeof(__be16), 378 [OVS_ACTION_ATTR_POP_MPLS] = sizeof(__be16),
440 [OVS_ACTION_ATTR_PUSH_VLAN] = sizeof(struct ovs_action_push_vlan), 379 [OVS_ACTION_ATTR_PUSH_VLAN] = sizeof(struct ovs_action_push_vlan),
441 [OVS_ACTION_ATTR_POP_VLAN] = 0, 380 [OVS_ACTION_ATTR_POP_VLAN] = 0,
442+ [OVS_ACTION_ATTR_PUSH_NSH] = sizeof(struct ovs_action_push_nsh), 381+ [OVS_ACTION_ATTR_PUSH_NSH] = sizeof(struct ovs_action_push_nsh),
443+ [OVS_ACTION_ATTR_POP_NSH] = 0, 382+ [OVS_ACTION_ATTR_POP_NSH] = 0,
444+ [OVS_ACTION_ATTR_PUSH_ETH] = sizeof(struct ovs_action_push_eth),
445+ [OVS_ACTION_ATTR_POP_ETH] = 0,
446 [OVS_ACTION_ATTR_SET] = (u32)-1, 383 [OVS_ACTION_ATTR_SET] = (u32)-1,
447 [OVS_ACTION_ATTR_SET_MASKED] = (u32)-1, 384 [OVS_ACTION_ATTR_SET_MASKED] = (u32)-1,
448 [OVS_ACTION_ATTR_SAMPLE] = (u32)-1, 385 [OVS_ACTION_ATTR_SAMPLE] = (u32)-1,
449@@ -2226,6 +2299,12 @@ static int __ovs_nla_copy_actions(struct net *net, const struct nlattr *attr, 386@@ -2288,6 +2341,10 @@ static int __ovs_nla_copy_actions(struct net *net, const struct nlattr *attr,
450 break; 387 break;
451 } 388 }
452 389
453+ case OVS_ACTION_ATTR_PUSH_NSH: 390+ case OVS_ACTION_ATTR_PUSH_NSH:
454+ case OVS_ACTION_ATTR_POP_NSH: 391+ case OVS_ACTION_ATTR_POP_NSH:
455+ case OVS_ACTION_ATTR_PUSH_ETH:
456+ case OVS_ACTION_ATTR_POP_ETH:
457+ break; 392+ break;
458+ 393+
459 case OVS_ACTION_ATTR_POP_VLAN: 394 case OVS_ACTION_ATTR_POP_VLAN:
460 vlan_tci = htons(0); 395 vlan_tci = htons(0);
461 break; 396 break;
462diff --git a/datapath/linux/compat/include/linux/openvswitch.h b/datapath/linux/compat/include/linux/openvswitch.h 397diff --git a/datapath/linux/compat/include/linux/openvswitch.h b/datapath/linux/compat/include/linux/openvswitch.h
463index 44adb81..187bb9b 100644 398index 44b7ce4..090843a 100644
464--- a/datapath/linux/compat/include/linux/openvswitch.h 399--- a/datapath/linux/compat/include/linux/openvswitch.h
465+++ b/datapath/linux/compat/include/linux/openvswitch.h 400+++ b/datapath/linux/compat/include/linux/openvswitch.h
466@@ -42,6 +42,7 @@ 401@@ -42,6 +42,7 @@
@@ -471,42 +406,38 @@ index 44adb81..187bb9b 100644
471 406
472 /** 407 /**
473 * struct ovs_header - header for OVS Generic Netlink messages. 408 * struct ovs_header - header for OVS Generic Netlink messages.
474@@ -328,6 +329,9 @@ enum ovs_key_attr { 409@@ -332,6 +333,7 @@ enum ovs_key_attr {
475 OVS_KEY_ATTR_ENCAP, /* Nested set of encapsulated attributes. */ 410 OVS_KEY_ATTR_ENCAP, /* Nested set of encapsulated attributes. */
476 OVS_KEY_ATTR_PRIORITY, /* u32 skb->priority */ 411 OVS_KEY_ATTR_PRIORITY, /* u32 skb->priority */
477 OVS_KEY_ATTR_IN_PORT, /* u32 OVS dp port number */ 412 OVS_KEY_ATTR_IN_PORT, /* u32 OVS dp port number */
478+ OVS_KEY_ATTR_NSH, /* struct ovs_key_nsh. Only support NSH MD 413+ OVS_KEY_ATTR_NSH, /* struct ovs_key_nsh, MD type 1 only */
479+ type 1 now */
480+ OVS_KEY_ATTR_ENCAP_ETH, /* struct ovs_key_encap_eth */
481 OVS_KEY_ATTR_ETHERNET, /* struct ovs_key_ethernet */ 414 OVS_KEY_ATTR_ETHERNET, /* struct ovs_key_ethernet */
482 OVS_KEY_ATTR_VLAN, /* be16 VLAN TCI */ 415 OVS_KEY_ATTR_VLAN, /* be16 VLAN TCI */
483 OVS_KEY_ATTR_ETHERTYPE, /* be16 Ethernet type */ 416 OVS_KEY_ATTR_ETHERTYPE, /* be16 Ethernet type */
484@@ -401,6 +405,24 @@ enum ovs_frag_type { 417@@ -406,6 +408,22 @@ enum ovs_frag_type {
485 418
486 #define OVS_FRAG_TYPE_MAX (__OVS_FRAG_TYPE_MAX - 1) 419 #define OVS_FRAG_TYPE_MAX (__OVS_FRAG_TYPE_MAX - 1)
487 420
488+struct ovs_key_nsh { 421+struct ovs_key_nsh {
489+ __u32 nshc1; 422+ __u8 encap_eth_dst[ETH_ALEN];
490+ __u32 nshc2; 423+ __u8 encap_eth_src[ETH_ALEN];
491+ __u32 nshc3; 424+ __u16 encap_eth_type;
492+ __u32 nshc4; 425+ __u16 pad1;
493+ __u32 nsp; 426+ __u32 nshc1;
494+ __u8 nsi; 427+ __u32 nshc2;
495+ __u8 nsh_mdtype; 428+ __u32 nshc3;
496+ __u8 nsh_np; 429+ __u32 nshc4;
497+ __u8 reserved; 430+ __u32 nsp;
498+}; 431+ __u8 nsi;
499+ 432+ __u8 nsh_mdtype;
500+struct ovs_key_encap_eth { 433+ __u8 nsh_np;
501+ __u8 encap_eth_src[ETH_ALEN]; 434+ __u8 pad2;
502+ __u8 encap_eth_dst[ETH_ALEN]; 435+} __packed;
503+ __u16 encap_eth_type;
504+};
505+ 436+
506 struct ovs_key_ethernet { 437 struct ovs_key_ethernet {
507 __u8 eth_src[ETH_ALEN]; 438 __u8 eth_src[ETH_ALEN];
508 __u8 eth_dst[ETH_ALEN]; 439 __u8 eth_dst[ETH_ALEN];
509@@ -630,6 +652,154 @@ struct ovs_action_push_vlan { 440@@ -640,6 +658,151 @@ struct ovs_action_push_vlan {
510 __be16 vlan_tci; /* 802.1Q TCI (VLAN ID and priority). */ 441 __be16 vlan_tci; /* 802.1Q TCI (VLAN ID and priority). */
511 }; 442 };
512 443
@@ -627,6 +558,7 @@ index 44adb81..187bb9b 100644
627+ 558+
628+#define ENCAP_ETH_LEN 14 559+#define ENCAP_ETH_LEN 14
629+ 560+
561+#define ETH_NSH_TYPE1_HEADER_SIZE (NSH_PUSH_TYPE1_HEADER_SIZE + ENCAP_ETH_LEN)
630+/** 562+/**
631+ * struct encap_eth - encap ethernet header for ethernet NSH 563+ * struct encap_eth - encap ethernet header for ethernet NSH
632+ * @encap_eth_src: encap ethernet source address. 564+ * @encap_eth_src: encap ethernet source address.
@@ -639,6 +571,11 @@ index 44adb81..187bb9b 100644
639+ __u16 encap_eth_type; 571+ __u16 encap_eth_type;
640+}; 572+};
641+ 573+
574+struct eth_nsh_hdr {
575+ struct encap_eth_hdr encap_eth_header;
576+ struct nsh_hdr nsh_hdr __attribute__((packed));
577+};
578+
642+#define ENCAP_ETH_PUSH_HEADER_SIZE 14 579+#define ENCAP_ETH_PUSH_HEADER_SIZE 14
643+/** 580+/**
644+ * struct ovs_action_push_nsh - %OVS_ACTION_ATTR_PUSH_NSH action argument. 581+ * struct ovs_action_push_nsh - %OVS_ACTION_ATTR_PUSH_NSH action argument.
@@ -649,92 +586,609 @@ index 44adb81..187bb9b 100644
649+ uint8_t header[NSH_PUSH_HEADER_SIZE]; 586+ uint8_t header[NSH_PUSH_HEADER_SIZE];
650+}; 587+};
651+ 588+
652+/**
653+ * struct ovs_action_push_nsh - %OVS_ACTION_ATTR_PUSH_NSH action argument.
654+ * @header
655+ */
656+struct ovs_action_push_eth {
657+ uint16_t encap_eth_type;
658+ uint8_t header[ENCAP_ETH_PUSH_HEADER_SIZE];
659+};
660+
661 /* Data path hash algorithm for computing Datapath hash. 589 /* Data path hash algorithm for computing Datapath hash.
662 * 590 *
663 * The algorithm type only specifies the fields in a flow 591 * The algorithm type only specifies the fields in a flow
664@@ -793,6 +963,10 @@ enum ovs_action_attr { 592@@ -679,6 +842,7 @@ struct ovs_action_push_tnl {
593 uint32_t out_port;
594 uint32_t header_len;
595 uint32_t tnl_type; /* For logging. */
596+ uint32_t exts;
597 uint8_t header[TNL_PUSH_HEADER_SIZE];
598 };
599 #endif
600@@ -804,6 +968,8 @@ enum ovs_action_attr {
665 OVS_ACTION_ATTR_SET, /* One nested OVS_KEY_ATTR_*. */ 601 OVS_ACTION_ATTR_SET, /* One nested OVS_KEY_ATTR_*. */
666 OVS_ACTION_ATTR_PUSH_VLAN, /* struct ovs_action_push_vlan. */ 602 OVS_ACTION_ATTR_PUSH_VLAN, /* struct ovs_action_push_vlan. */
667 OVS_ACTION_ATTR_POP_VLAN, /* No argument. */ 603 OVS_ACTION_ATTR_POP_VLAN, /* No argument. */
668+ OVS_ACTION_ATTR_PUSH_NSH, /* struct ovs_action_push_nsh. */ 604+ OVS_ACTION_ATTR_PUSH_NSH, /* struct ovs_action_push_nsh. */
669+ OVS_ACTION_ATTR_POP_NSH, /* No argument. */ 605+ OVS_ACTION_ATTR_POP_NSH, /* No argument. */
670+ OVS_ACTION_ATTR_PUSH_ETH, /* struct ovs_action_push_eth. */
671+ OVS_ACTION_ATTR_POP_ETH, /* No argument. */
672 OVS_ACTION_ATTR_SAMPLE, /* Nested OVS_SAMPLE_ATTR_*. */ 606 OVS_ACTION_ATTR_SAMPLE, /* Nested OVS_SAMPLE_ATTR_*. */
673 OVS_ACTION_ATTR_RECIRC, /* u32 recirc_id. */ 607 OVS_ACTION_ATTR_RECIRC, /* u32 recirc_id. */
674 OVS_ACTION_ATTR_HASH, /* struct ovs_action_hash. */ 608 OVS_ACTION_ATTR_HASH, /* struct ovs_action_hash. */
675diff --git a/datapath/linux/compat/include/net/vxlan.h b/datapath/linux/compat/include/net/vxlan.h 609diff --git a/include/openvswitch/automake.mk b/include/openvswitch/automake.mk
676index 2bfc3f8..3aeac88 100644 610index c0e276f..732b775 100644
677--- a/datapath/linux/compat/include/net/vxlan.h 611--- a/include/openvswitch/automake.mk
678+++ b/datapath/linux/compat/include/net/vxlan.h 612+++ b/include/openvswitch/automake.mk
679@@ -85,7 +85,7 @@ struct vxlanhdr_gbp { 613@@ -29,5 +29,6 @@ openvswitchinclude_HEADERS = \
680 #define VXLAN_GBP_ID_MASK (0xFFFF) 614 include/openvswitch/uuid.h \
681 615 include/openvswitch/version.h \
682 /* 616 include/openvswitch/vconn.h \
683- * VXLAN Generic Protocol Extension Extension: 617- include/openvswitch/vlog.h
684+ * VXLAN Generic Protocol Extension: 618+ include/openvswitch/vlog.h \
685 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 619+ include/openvswitch/vxlangpe.h
686 * |R|R|Ver|I|P|R|O|R|R|R|R|R|R|R|R|R|R|R|R|R|R|R|R| Next Proto | 620
687 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 621diff --git a/include/openvswitch/flow.h b/include/openvswitch/flow.h
688@@ -103,6 +103,9 @@ struct vxlanhdr_gbp { 622index df80dfe..84c7997 100644
689 * O = OAM Flag Bit. The O bit is set to indicate that the packet 623--- a/include/openvswitch/flow.h
690 * is an OAM packet. 624+++ b/include/openvswitch/flow.h
691 * 625@@ -99,6 +99,21 @@ struct flow {
626 uint32_t conj_id; /* Conjunction ID. */
627 ofp_port_t actset_output; /* Output port in action set. */
628
629+ /* ETH + NSH (64-bit aligned) */
630+ struct eth_addr encap_eth_dst; /* Encap eth destination address. */
631+ struct eth_addr encap_eth_src; /* Encap eth source address. */
632+ ovs_be16 encap_eth_type; /* Encap eth frame type. */
633+ uint8_t pad2[2]; /* Pad to 64 bits. */
634+ ovs_be32 nshc1;
635+ ovs_be32 nshc2;
636+ ovs_be32 nshc3;
637+ ovs_be32 nshc4;
638+ ovs_be32 nsp;
639+ uint8_t nsi;
640+ uint8_t nsh_mdtype;
641+ uint8_t nsh_np;
642+ uint8_t pad3;
643+
644 /* L2, Order the same as in the Ethernet header! (64-bit aligned) */
645 struct eth_addr dl_dst; /* Ethernet destination address. */
646 struct eth_addr dl_src; /* Ethernet source address. */
647@@ -120,7 +135,7 @@ struct flow {
648 struct eth_addr arp_sha; /* ARP/ND source hardware address. */
649 struct eth_addr arp_tha; /* ARP/ND target hardware address. */
650 ovs_be16 tcp_flags; /* TCP flags. With L3 to avoid matching L4. */
651- ovs_be16 pad3; /* Pad to 64 bits. */
652+ ovs_be16 pad4; /* Pad to 64 bits. */
653
654 /* L4 (64-bit aligned) */
655 ovs_be16 tp_src; /* TCP/UDP/SCTP source port/ICMP type. */
656@@ -135,7 +150,7 @@ BUILD_ASSERT_DECL(sizeof(struct flow_tnl) % sizeof(uint64_t) == 0);
657
658 /* Remember to update FLOW_WC_SEQ when changing 'struct flow'. */
659 BUILD_ASSERT_DECL(offsetof(struct flow, igmp_group_ip4) + sizeof(uint32_t)
660- == sizeof(struct flow_tnl) + 248
661+ == sizeof(struct flow_tnl) + 288
662 && FLOW_WC_SEQ == 36);
663
664 /* Incremental points at which flow classification may be performed in
665diff --git a/include/openvswitch/match.h b/include/openvswitch/match.h
666index 93af1b8..c5fa48a 100644
667--- a/include/openvswitch/match.h
668+++ b/include/openvswitch/match.h
669@@ -168,6 +168,30 @@ void match_set_nd_target(struct match *, const struct in6_addr *);
670 void match_set_nd_target_masked(struct match *, const struct in6_addr *,
671 const struct in6_addr *);
672
673+void match_set_nsp_masked(struct match *, ovs_be32 nsp, ovs_be32 mask);
674+void match_set_nsi_masked(struct match *match, uint8_t nsi, uint8_t mask);
675+void match_set_nsh_mdtype_masked(struct match *match, uint8_t nsh_mdtype, uint8_t mask);
676+void match_set_nsh_np_masked(struct match *match, uint8_t nsh_np, uint8_t mask);
677+void match_set_nshc1_masked(struct match *, ovs_be32 nshc1, ovs_be32 mask);
678+void match_set_nshc2_masked(struct match *, ovs_be32 nshc2, ovs_be32 mask);
679+void match_set_nshc3_masked(struct match *, ovs_be32 nshc3, ovs_be32 mask);
680+void match_set_nshc4_masked(struct match *, ovs_be32 nshc4, ovs_be32 mask);
681+void match_set_encap_eth_src_masked(struct match *match, const struct eth_addr encap_eth_src, const struct eth_addr mask);
682+void match_set_encap_eth_dst_masked(struct match *match, const struct eth_addr encap_eth_dst, const struct eth_addr mask);
683+void match_set_encap_eth_type_masked(struct match *match, ovs_be16 encap_eth_type, ovs_be16 mask);
684+
685+void match_set_nsp(struct match *, ovs_be32 nsp);
686+void match_set_nsi(struct match *match, uint8_t nsi);
687+void match_set_nsh_mdtype(struct match *match, uint8_t nsh_mdtype);
688+void match_set_nsh_np(struct match *match, uint8_t nsh_np);
689+void match_set_nshc1(struct match *, ovs_be32 nshc1);
690+void match_set_nshc2(struct match *, ovs_be32 nshc2);
691+void match_set_nshc3(struct match *, ovs_be32 nshc3);
692+void match_set_nshc4(struct match *, ovs_be32 nshc4);
693+void match_set_encap_eth_src(struct match *match, const struct eth_addr encap_eth_src);
694+void match_set_encap_eth_dst(struct match *match, const struct eth_addr encap_eth_dst);
695+void match_set_encap_eth_type(struct match *match, ovs_be16 encap_eth_type);
696+
697 bool match_equal(const struct match *, const struct match *);
698 uint32_t match_hash(const struct match *, uint32_t basis);
699
700diff --git a/include/openvswitch/meta-flow.h b/include/openvswitch/meta-flow.h
701index 9e569ef..fa4129c 100644
702--- a/include/openvswitch/meta-flow.h
703+++ b/include/openvswitch/meta-flow.h
704@@ -1801,6 +1801,180 @@ enum OVS_PACKED_ENUM mf_field_id {
705 */
706 MFF_ND_TLL,
707
708+ /* "nsp".
709+ *
710+ * For a packet received including a (32-bit)
711+ * network service header service path (nsp), the nsp is stored
712+ * in the low 24-bits and the high bits are zeroed. For
713+ * other packets, the value is 0.
714+ *
715+ * Type: be32.
716+ * Maskable: bitwise.
717+ * Formatting: hexadecimal.
718+ * Prerequisites: none.
719+ * Access: read/write.
720+ * NXM: NXM_NX_NSP(202) since v1.1.
721+ * OXM: none.
722+ * Prefix lookup member: nsp.
723+ */
724+ MFF_NSP,
725+
726+ /* "nsi".
727+ *
728+ * For a packet received, it includes a (8-bit)
729+ * network service header service index (nsi).
730+ *
731+ * Type: u8.
732+ * Maskable: bitwise.
733+ * Formatting: decimal.
734+ * Prerequisites: none.
735+ * Access: read/write.
736+ * NXM: NXM_NX_NSI(203) since v1.1.
737+ * OXM: none.
738+ * Prefix lookup member: nsi.
739+ */
740+ MFF_NSI,
741+
742+ /* "nshc1".
743+ *
744+ * For a packet received including a (32-bit)
745+ * Network Platform Context (nshc1), the nshc1 is stored
746+ * in the 32-bits. For other packets, the value is 0.
747+ *
748+ * Type: be32.
749+ * Maskable: bitwise.
750+ * Formatting: hexadecimal.
751+ * Prerequisites: none.
752+ * Access: read/write.
753+ * NXM: NXM_NX_NSH_C1(204) since v1.1.
754+ * OXM: none.
755+ * Prefix lookup member: nshc1.
756+ */
757+ MFF_NSH_C1,
758+
759+ /* "nshc2".
760+ *
761+ * For a packet received including a (32-bit)
762+ * Network Shared Context (nshc2), the nshc2 is stored
763+ * in the 32-bits. For other packets, the value is 0.
764+ *
765+ * Type: be32.
766+ * Maskable: bitwise.
767+ * Formatting: hexadecimal.
768+ * Prerequisites: none.
769+ * Access: read/write.
770+ * NXM: NXM_NX_NSH_C2(205) since v1.1.
771+ * OXM: none.
772+ * Prefix lookup member: nshc2.
773+ */
774+ MFF_NSH_C2,
775+
776+ /* "nshc3".
777+ *
778+ * For a packet received via including a (32-bit)
779+ * Service Platform Context (nshc3), the nshc3 is stored
780+ * in the 32-bits. For other packets, the value is 0.
781+ *
782+ * Type: be32.
783+ * Maskable: bitwise.
784+ * Formatting: hexadecimal.
785+ * Prerequisites: none.
786+ * Access: read/write.
787+ * NXM: NXM_NX_NSH_C3(206) since v1.1.
788+ * OXM: none.
789+ * Prefix lookup member: nshc3.
790+ */
791+ MFF_NSH_C3,
792+
793+ /* "nshc4".
794+ *
795+ * For a packet received including a (32-bit)
796+ * Service Shared Context (nshc4), the nshc4 is stored
797+ * in the 32-bits. For other packets, the value is 0.
798+ *
799+ * Type: be32.
800+ * Maskable: bitwise.
801+ * Formatting: hexadecimal.
802+ * Prerequisites: none.
803+ * Access: read/write.
804+ * NXM: NXM_NX_NSH_C4(207) since v1.1.
805+ * OXM: none.
806+ * Prefix lookup member: nshc4.
807+ */
808+ MFF_NSH_C4,
809+
810+ /* "nsh_mdtype".
811+ *
812+ * For a packet received, it includes a (8-bit)
813+ * nsh md-type field (md-type).
814+ *
815+ * Type: u8.
816+ * Maskable: bitwise.
817+ * Formatting: decimal.
818+ * Prerequisites: none.
819+ * Access: read/write.
820+ * NXM: NXM_NX_NSH_MDTYPE(208) since v1.1.
821+ * OXM: none.
822+ */
823+ MFF_NSH_MDTYPE,
824+
825+ /* "nsh_np".
826+ *
827+ * For a packet received, it includes a (8-bit)
828+ * nsh next protocol field (np).
829+ *
830+ * Type: u8.
831+ * Maskable: bitwise.
832+ * Formatting: decimal.
833+ * Prerequisites: none.
834+ * Access: read/write.
835+ * NXM: NXM_NX_NSH_NP(209) since v1.1.
836+ * OXM: none.
837+ */
838+ MFF_NSH_NP,
839+
840+ /* "encap_eth_src".
841+ *
842+ * encap eth source address for Ethernet+NSH
843+ *
844+ * Type: MAC.
845+ * Maskable: bitwise.
846+ * Formatting: Ethernet.
847+ * Prerequisites: none.
848+ * Access: read/write.
849+ * NXM: NXM_NX_ENCAP_ETH_SRC(210) since v1.1.
850+ * OXM: none.
851+ */
852+ MFF_ENCAP_ETH_SRC,
853+
854+ /* "encap_eth_dst".
855+ *
856+ * encap eth destination address for Ethernet+NSH
857+ *
858+ * Type: MAC.
859+ * Maskable: bitwise.
860+ * Formatting: Ethernet.
861+ * Prerequisites: none.
862+ * Access: read/write.
863+ * NXM: NXM_NX_ENCAP_ETH_DST(211) since v1.1.
864+ * OXM: none.
865+ */
866+ MFF_ENCAP_ETH_DST,
867+
868+ /* "encap_eth_type".
869+ *
870+ * Encap Ethernet type.
871+ *
872+ * Type: be16.
873+ * Maskable: no.
874+ * Formatting: hexadecimal.
875+ * Prerequisites: none.
876+ * Access: read-only.
877+ * NXM: NXM_NX_ENCAP_ETH_TYPE(212) since v1.1.
878+ * OXM: none.
879+ */
880+ MFF_ENCAP_ETH_TYPE,
881+
882 MFF_N_IDS
883 };
884
885diff --git a/include/openvswitch/ofp-actions.h b/include/openvswitch/ofp-actions.h
886index 01b1790..8bef529 100644
887--- a/include/openvswitch/ofp-actions.h
888+++ b/include/openvswitch/ofp-actions.h
889@@ -93,6 +93,10 @@
890 OFPACT(POP_QUEUE, ofpact_null, ofpact, "pop_queue") \
891 OFPACT(FIN_TIMEOUT, ofpact_fin_timeout, ofpact, "fin_timeout") \
892 \
893+ /* NSH */ \
894+ OFPACT(PUSH_NSH, ofpact_null, ofpact, "push_nsh") \
895+ OFPACT(POP_NSH, ofpact_null, ofpact, "pop_nsh") \
896+ \
897 /* Flow table interaction. */ \
898 OFPACT(RESUBMIT, ofpact_resubmit, ofpact, "resubmit") \
899 OFPACT(LEARN, ofpact_learn, specs, "learn") \
900diff --git a/include/openvswitch/vxlangpe.h b/include/openvswitch/vxlangpe.h
901new file mode 100644
902index 0000000..b5ab7e0
903--- /dev/null
904+++ b/include/openvswitch/vxlangpe.h
905@@ -0,0 +1,76 @@
906+#ifndef __OPENVSWITCH_VXLANGPE_H
907+#define __OPENVSWITCH_VXLANGPE_H 1
908+
909+#include "openvswitch/types.h"
910+
911+#define u8 uint8_t
912+#define u32 uint8_t
913+#define __be32 ovs_be32
914+
915+/*
916+ * VXLAN Generic Protocol Extension (VXLAN_F_GPE):
917+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
918+ * |R|R|Ver|I|P|R|O| Reserved |Next Protocol |
919+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
920+ * | VXLAN Network Identifier (VNI) | Reserved |
921+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
922+ *
923+ * Ver = Version. Indicates VXLAN GPE protocol version.
924+ *
925+ * P = Next Protocol Bit. The P bit is set to indicate that the
926+ * Next Protocol field is present.
927+ *
928+ * O = OAM Flag Bit. The O bit is set to indicate that the packet
929+ * is an OAM packet.
930+ *
692+ * Next Protocol = This 8 bit field indicates the protocol header 931+ * Next Protocol = This 8 bit field indicates the protocol header
693+ * immediately following the VXLAN GPE header. 932+ * immediately following the VXLAN GPE header.
694+ * 933+ *
695 * [1] https://www.ietf.org/id/draft-ietf-nvo3-vxlan-gpe-01.txt 934+ * https://tools.ietf.org/html/draft-ietf-nvo3-vxlan-gpe-01
696 */ 935+ */
697 936+
937+struct vxlanhdr_gpe {
938+#ifdef WORDS_BIGENDIAN
939+ u8 reserved_flags2:2,
940+ version:2,
941+ instance_applied:1,
942+ np_applied:1,
943+ reserved_flags1:1,
944+ oam_flag:1;
945+#else
946+ u8 oam_flag:1,
947+ reserved_flags1:1,
948+ np_applied:1,
949+ instance_applied:1,
950+ version:2,
951+ reserved_flags2:2;
952+#endif
953+ u8 reserved_flags3;
954+ u8 reserved_flags4;
955+ u8 next_protocol;
956+ __be32 vx_vni;
957+};
958+
959+/* VXLAN-GPE header flags. */
960+#define VXLAN_HF_VER ((1UL <<29) | (1UL <<28))
961+#define VXLAN_HF_NP (1UL <<26)
962+#define VXLAN_HF_OAM (1UL <<24)
963+
964+#define VXLAN_GPE_USED_BITS (VXLAN_HF_VER | VXLAN_HF_NP | VXLAN_HF_OAM | \
965+ 0xff)
966+
967+/* VXLAN-GPE header Next Protocol. */
968+#define VXLAN_GPE_NP_IPV4 0x01
969+#define VXLAN_GPE_NP_IPV6 0x02
970+#define VXLAN_GPE_NP_ETHERNET 0x03
971+#define VXLAN_GPE_NP_NSH 0x04
972+
973+struct vxlan_metadata {
974+ u32 gbp;
975+ u32 gpe;
976+};
977+
978+#define VXLAN_F_GPE 0x4000
979+#define VXLAN_HF_GPE 0x04000000
980+
981+#endif /* __OPENVSWITCH_VXLANGPE_H */
698diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c 982diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c
699index 119dc2d..8e67bfd 100644 983index 44ec1a0..c779c78 100644
700--- a/lib/dpif-netdev.c 984--- a/lib/dpif-netdev.c
701+++ b/lib/dpif-netdev.c 985+++ b/lib/dpif-netdev.c
702@@ -3874,6 +3874,10 @@ dp_execute_cb(void *aux_, struct dp_packet **packets, int cnt, 986@@ -533,7 +533,7 @@ static int get_port_by_name(struct dp_netdev *dp, const char *devname,
703 VLOG_WARN("Cannot execute conntrack action in userspace."); 987 static void dp_netdev_free(struct dp_netdev *)
988 OVS_REQUIRES(dp_netdev_mutex);
989 static int do_add_port(struct dp_netdev *dp, const char *devname,
990- const char *type, odp_port_t port_no)
991+ const char *type, odp_port_t port_no, uint32_t exts)
992 OVS_REQUIRES(dp->port_mutex);
993 static void do_del_port(struct dp_netdev *dp, struct dp_netdev_port *)
994 OVS_REQUIRES(dp->port_mutex);
995@@ -1010,7 +1010,7 @@ create_dp_netdev(const char *name, const struct dpif_class *class,
996
997 error = do_add_port(dp, name, dpif_netdev_port_open_type(dp->class,
998 "internal"),
999- ODPP_LOCAL);
1000+ ODPP_LOCAL, 0);
1001 ovs_mutex_unlock(&dp->port_mutex);
1002 if (error) {
1003 dp_netdev_free(dp);
1004@@ -1213,9 +1213,21 @@ hash_port_no(odp_port_t port_no)
1005 return hash_int(odp_to_u32(port_no), 0);
1006 }
1007
1008+static void add_vxlan_gpe_exts(struct netdev *netdev, uint32_t exts)
1009+{
1010+ const char *type = netdev_get_type(netdev);
1011+ if (!strcmp(type, "vxlan")) {
1012+ struct netdev_tunnel_config *cfg;
1013+ cfg = netdev_get_tunnel_config(netdev);
1014+
1015+ if(exts & (1 << OVS_VXLAN_EXT_GPE))
1016+ cfg->exts |= (1 << OVS_VXLAN_EXT_GPE);
1017+ }
1018+}
1019+
1020 static int
1021 port_create(const char *devname, const char *type,
1022- odp_port_t port_no, struct dp_netdev_port **portp)
1023+ odp_port_t port_no, struct dp_netdev_port **portp, uint32_t exts)
1024 {
1025 struct netdev_saved_flags *sf;
1026 struct dp_netdev_port *port;
1027@@ -1273,6 +1285,7 @@ port_create(const char *devname, const char *type,
1028 }
1029 }
1030
1031+ add_vxlan_gpe_exts(netdev, exts);
1032 port = xzalloc(sizeof *port);
1033 port->port_no = port_no;
1034 port->netdev = netdev;
1035@@ -1321,7 +1334,7 @@ out:
1036
1037 static int
1038 do_add_port(struct dp_netdev *dp, const char *devname, const char *type,
1039- odp_port_t port_no)
1040+ odp_port_t port_no, uint32_t exts)
1041 OVS_REQUIRES(dp->port_mutex)
1042 {
1043 struct dp_netdev_port *port;
1044@@ -1332,7 +1345,7 @@ do_add_port(struct dp_netdev *dp, const char *devname, const char *type,
1045 return EEXIST;
1046 }
1047
1048- error = port_create(devname, type, port_no, &port);
1049+ error = port_create(devname, type, port_no, &port, exts);
1050 if (error) {
1051 return error;
1052 }
1053@@ -1373,7 +1386,12 @@ dpif_netdev_port_add(struct dpif *dpif, struct netdev *netdev,
1054 }
1055 if (!error) {
1056 *port_nop = port_no;
1057- error = do_add_port(dp, dpif_port, netdev_get_type(netdev), port_no);
1058+ const struct netdev_tunnel_config *cfg;
1059+ uint32_t exts = 0;
1060+ cfg = netdev_get_tunnel_config(netdev);
1061+ if (cfg)
1062+ exts = cfg->exts;
1063+ error = do_add_port(dp, dpif_port, netdev_get_type(netdev), port_no, exts);
1064 }
1065 ovs_mutex_unlock(&dp->port_mutex);
1066
1067@@ -2148,8 +2166,11 @@ dpif_netdev_flow_from_nlattrs(const struct nlattr *key, uint32_t key_len,
1068 struct flow *flow)
1069 {
1070 odp_port_t in_port;
1071+ enum odp_key_fitness fitness;
1072
1073- if (odp_flow_key_to_flow_udpif(key, key_len, flow)) {
1074+ fitness = odp_flow_key_to_flow_udpif(key, key_len, flow);
1075+
1076+ if (fitness) {
1077 /* This should not happen: it indicates that odp_flow_key_from_flow()
1078 * and odp_flow_key_to_flow() disagree on the acceptable form of a
1079 * flow. Log the problem as an error, with enough details to enable
1080@@ -2161,7 +2182,7 @@ dpif_netdev_flow_from_nlattrs(const struct nlattr *key, uint32_t key_len,
1081
1082 ds_init(&s);
1083 odp_flow_format(key, key_len, NULL, 0, NULL, &s, true);
1084- VLOG_ERR("internal error parsing flow key %s", ds_cstr(&s));
1085+ VLOG_ERR("internal error parsing flow key %s (%s)", ds_cstr(&s), odp_key_fitness_to_string(fitness));
1086 ds_destroy(&s);
1087 }
1088
1089@@ -4612,6 +4633,8 @@ dp_execute_cb(void *aux_, struct dp_packet_batch *packets_,
704 break; 1090 break;
1091 }
705 1092
706+ case OVS_ACTION_ATTR_PUSH_NSH: 1093+ case OVS_ACTION_ATTR_PUSH_NSH:
707+ case OVS_ACTION_ATTR_POP_NSH: 1094+ case OVS_ACTION_ATTR_POP_NSH:
708+ case OVS_ACTION_ATTR_PUSH_ETH:
709+ case OVS_ACTION_ATTR_POP_ETH:
710 case OVS_ACTION_ATTR_PUSH_VLAN: 1095 case OVS_ACTION_ATTR_PUSH_VLAN:
711 case OVS_ACTION_ATTR_POP_VLAN: 1096 case OVS_ACTION_ATTR_POP_VLAN:
712 case OVS_ACTION_ATTR_PUSH_MPLS: 1097 case OVS_ACTION_ATTR_PUSH_MPLS:
713diff --git a/lib/dpif.c b/lib/dpif.c 1098diff --git a/lib/dpif.c b/lib/dpif.c
714index a784de7..b5265c4 100644 1099index 53958c5..86e30e0 100644
715--- a/lib/dpif.c 1100--- a/lib/dpif.c
716+++ b/lib/dpif.c 1101+++ b/lib/dpif.c
717@@ -1139,6 +1139,10 @@ dpif_execute_helper_cb(void *aux_, struct dp_packet **packets, int cnt, 1102@@ -1178,6 +1178,8 @@ dpif_execute_helper_cb(void *aux_, struct dp_packet_batch *packets_,
718 } 1103 }
719 1104
720 case OVS_ACTION_ATTR_HASH: 1105 case OVS_ACTION_ATTR_HASH:
721+ case OVS_ACTION_ATTR_PUSH_NSH: 1106+ case OVS_ACTION_ATTR_PUSH_NSH:
722+ case OVS_ACTION_ATTR_POP_NSH: 1107+ case OVS_ACTION_ATTR_POP_NSH:
723+ case OVS_ACTION_ATTR_PUSH_ETH:
724+ case OVS_ACTION_ATTR_POP_ETH:
725 case OVS_ACTION_ATTR_PUSH_VLAN: 1108 case OVS_ACTION_ATTR_PUSH_VLAN:
726 case OVS_ACTION_ATTR_POP_VLAN: 1109 case OVS_ACTION_ATTR_POP_VLAN:
727 case OVS_ACTION_ATTR_PUSH_MPLS: 1110 case OVS_ACTION_ATTR_PUSH_MPLS:
728diff --git a/lib/flow.c b/lib/flow.c 1111diff --git a/lib/flow.c b/lib/flow.c
729index d24bdc9..fc8b98c 100644 1112index 375979b..e387c8b 100644
730--- a/lib/flow.c 1113--- a/lib/flow.c
731+++ b/lib/flow.c 1114+++ b/lib/flow.c
732@@ -1289,6 +1289,25 @@ void flow_wildcards_init_for_packet(struct flow_wildcards *wc, 1115@@ -547,6 +547,25 @@ flow_extract(struct dp_packet *packet, struct flow *flow)
1116 miniflow_expand(&m.mf, flow);
1117 }
1118
1119+/* parse Ethernet+NSH */
1120+static int parse_nsh(const void *data, struct ovs_key_nsh *nsh)
1121+{
1122+ memcpy(&nsh->encap_eth_dst, data, ENCAP_ETH_LEN);
1123+ const struct nsh_hdr *nsh_hdr = (const struct nsh_hdr *)((const char *)data + ENCAP_ETH_LEN);
1124+
1125+ nsh->nsh_mdtype = nsh_hdr->base.mdtype;
1126+ if (nsh->nsh_mdtype != NSH_M_TYPE1)
1127+ return -1;
1128+ nsh->nsh_np = nsh_hdr->base.proto;
1129+ nsh->nsi = nsh_hdr->base.svc_idx;
1130+ nsh->nsp = nsh_hdr->base.path_hdr << 8;
1131+ nsh->nshc1 = nsh_hdr->ctx.nshc1;
1132+ nsh->nshc2 = nsh_hdr->ctx.nshc2;
1133+ nsh->nshc3 = nsh_hdr->ctx.nshc3;
1134+ nsh->nshc4 = nsh_hdr->ctx.nshc4;
1135+ return 0;
1136+}
1137+
1138 /* Caller is responsible for initializing 'dst' with enough storage for
1139 * FLOW_U64S * 8 bytes. */
1140 void
1141@@ -607,6 +626,32 @@ miniflow_extract(struct dp_packet *packet, struct miniflow *dst)
1142 }
1143 }
1144
1145+ /* Extract Etherenet + NSH if the Ethernet type is 0x894F in packet */
1146+ if (OVS_UNLIKELY(size < sizeof(struct eth_header)))
1147+ goto out;
1148+ else {
1149+ const struct eth_header *eth = data;
1150+ if (eth->eth_type == htons(ETH_P_NSH)) {
1151+ /* extract Ethernet+nsh */
1152+ struct ovs_key_nsh nsh;
1153+ if (OVS_UNLIKELY(parse_nsh(data, &nsh)))
1154+ goto out;
1155+
1156+ /* Now only support NSH mdtype 1 */
1157+ if (nsh.nsh_mdtype == NSH_M_TYPE1){
1158+ /* Push all field related with Ethernet+nsh at once. */
1159+ miniflow_push_words(mf, encap_eth_dst, &nsh,
1160+ (sizeof (struct ovs_key_nsh)+sizeof(uint64_t) - 1) /
1161+ sizeof(uint64_t));
1162+ data = (const char *)data + NSH_M_TYPE1_LEN + ENCAP_ETH_LEN;
1163+ } else
1164+ goto out;
1165+
1166+ if(nsh.nsh_np != NSH_P_ETHERNET)
1167+ goto out;
1168+ }
1169+ }
1170+
1171 /* Initialize packet's layer pointer and offsets. */
1172 l2 = data;
1173 dp_packet_reset_offsets(packet);
1174@@ -897,7 +942,7 @@ flow_get_metadata(const struct flow *flow, struct match *flow_metadata)
1175 if (flow->tunnel.gbp_flags) {
1176 match_set_tun_gbp_flags(flow_metadata, flow->tunnel.gbp_flags);
1177 }
1178- if (flow->tunnel.gpe_np != htons(0)) {
1179+ if (flow->tunnel.gpe_np != 0) {
1180 match_set_tun_gpe_np(flow_metadata, flow->tunnel.gpe_np);
1181 }
1182 if (flow->tunnel.gpe_flags) {
1183@@ -1316,6 +1361,21 @@ void flow_wildcards_init_for_packet(struct flow_wildcards *wc,
733 WC_MASK_FIELD(wc, tunnel.tun_id); 1184 WC_MASK_FIELD(wc, tunnel.tun_id);
734 } 1185 }
735 1186
736+ /* NSH fields wildcarded */ 1187+ /* NSH fields wildcarded */
737+ if (flow->nsh_mdtype) { 1188+ if (flow->nsh_mdtype) {
1189+ WC_MASK_FIELD(wc, encap_eth_src);
1190+ WC_MASK_FIELD(wc, encap_eth_dst);
1191+ WC_MASK_FIELD(wc, encap_eth_type);
738+ WC_MASK_FIELD(wc, nshc1); 1192+ WC_MASK_FIELD(wc, nshc1);
739+ WC_MASK_FIELD(wc, nshc2); 1193+ WC_MASK_FIELD(wc, nshc2);
740+ WC_MASK_FIELD(wc, nshc3); 1194+ WC_MASK_FIELD(wc, nshc3);
@@ -745,67 +1199,79 @@ index d24bdc9..fc8b98c 100644
745+ WC_MASK_FIELD(wc, nsi); 1199+ WC_MASK_FIELD(wc, nsi);
746+ } 1200+ }
747+ 1201+
748+ /* ENCAP Eth wildcarded */
749+ if (flow->encap_eth_type) {
750+ WC_MASK_FIELD(wc, encap_eth_src);
751+ WC_MASK_FIELD(wc, encap_eth_dst);
752+ WC_MASK_FIELD(wc, encap_eth_type);
753+ }
754+
755 /* metadata, regs, and conj_id wildcarded. */ 1202 /* metadata, regs, and conj_id wildcarded. */
756 1203
757 WC_MASK_FIELD(wc, skb_priority); 1204 WC_MASK_FIELD(wc, skb_priority);
758diff --git a/lib/flow.h b/lib/flow.h 1205@@ -1432,6 +1492,19 @@ flow_wc_map(const struct flow *flow, struct flowmap *map)
759index dc7130d..a8677b1 100644 1206 FLOWMAP_SET(map, ct_mark);
760--- a/lib/flow.h 1207 FLOWMAP_SET(map, ct_label);
761+++ b/lib/flow.h 1208
762@@ -111,6 +111,23 @@ struct flow { 1209+ /* NSH fields */
763 ofp_port_t actset_output; /* Output port in action set. */ 1210+ FLOWMAP_SET(map, encap_eth_src);
764 uint8_t pad2[2]; /* Pad to 64 bits. */ 1211+ FLOWMAP_SET(map, encap_eth_dst);
1212+ FLOWMAP_SET(map, encap_eth_type);
1213+ FLOWMAP_SET(map, nshc1);
1214+ FLOWMAP_SET(map, nshc2);
1215+ FLOWMAP_SET(map, nshc3);
1216+ FLOWMAP_SET(map, nshc4);
1217+ FLOWMAP_SET(map, nsp);
1218+ FLOWMAP_SET(map, nsi);
1219+ FLOWMAP_SET(map, nsh_mdtype);
1220+ FLOWMAP_SET(map, nsh_np);
1221+
1222 /* Ethertype-dependent fields. */
1223 if (OVS_LIKELY(flow->dl_type == htons(ETH_TYPE_IP))) {
1224 FLOWMAP_SET(map, nw_src);
1225@@ -2352,6 +2425,33 @@ flow_compose_l4_csum(struct dp_packet *p, const struct flow *flow,
1226 }
1227 }
765 1228
766+ /* NSH (64-bit aligned) */ 1229+/* push ethernet+nsh header at the beginning of packets */
767+ ovs_be32 nshc1; 1230+static void
768+ ovs_be32 nshc2; 1231+flow_compose_nsh(struct dp_packet *p, const struct flow *flow)
769+ ovs_be32 nshc3; 1232+{
770+ ovs_be32 nshc4; 1233+ struct eth_nsh_hdr *eth_nsh_header;
771+ ovs_be32 nsp; 1234+
772+ uint8_t nsi; 1235+ /* Now only support mdtype1 */
773+ uint8_t nsh_mdtype; 1236+ if (flow->nsh_mdtype != NSH_M_TYPE1)
774+ uint8_t nsh_np; 1237+ return;
775+ uint8_t pad3; 1238+
1239+ eth_nsh_header = dp_packet_push_uninit(p, ETH_NSH_TYPE1_HEADER_SIZE);
1240+ eth_nsh_header->encap_eth_header.encap_eth_dst = flow->encap_eth_dst;
1241+ eth_nsh_header->encap_eth_header.encap_eth_src = flow->encap_eth_src;
1242+ eth_nsh_header->encap_eth_header.encap_eth_type = htons(ETH_P_NSH);
1243+
1244+ memset(&eth_nsh_header->nsh_hdr, 0, sizeof (struct nsh_hdr));
1245+ eth_nsh_header->nsh_hdr.base.length = 6;
1246+ eth_nsh_header->nsh_hdr.base.proto = flow->nsh_np;
1247+ eth_nsh_header->nsh_hdr.base.mdtype = flow->nsh_mdtype;
1248+ eth_nsh_header->nsh_hdr.base.proto = flow->nsh_np;
1249+ eth_nsh_header->nsh_hdr.base.path_hdr = flow->nsp >> 8 | flow->nsi << 24;
1250+ eth_nsh_header->nsh_hdr.ctx.nshc1 = flow->nshc1;
1251+ eth_nsh_header->nsh_hdr.ctx.nshc2 = flow->nshc2;
1252+ eth_nsh_header->nsh_hdr.ctx.nshc3 = flow->nshc3;
1253+ eth_nsh_header->nsh_hdr.ctx.nshc4 = flow->nshc4;
1254+}
776+ 1255+
777+ /* ENCAP_ETH (64-bit aligned) */ 1256 /* Puts into 'b' a packet that flow_extract() would parse as having the given
778+ struct eth_addr encap_eth_src; /* Encap ethernet source address. */ 1257 * 'flow'.
779+ struct eth_addr encap_eth_dst; /* Encap ethernet destination address. */ 1258 *
780+ ovs_be16 encap_eth_type; /* Encap ethernet frame type. */ 1259@@ -2459,6 +2559,10 @@ flow_compose(struct dp_packet *p, const struct flow *flow)
781+ uint8_t pad4[2]; 1260 push_mpls(p, flow->dl_type, flow->mpls_lse[--n]);
1261 }
1262 }
782+ 1263+
783 /* L2, Order the same as in the Ethernet header! (64-bit aligned) */ 1264+ if (flow->nsh_mdtype) {
784 struct eth_addr dl_dst; /* Ethernet destination address. */ 1265+ flow_compose_nsh(p, flow);
785 struct eth_addr dl_src; /* Ethernet source address. */ 1266+ }
786@@ -132,7 +149,7 @@ struct flow { 1267 }
787 struct eth_addr arp_sha; /* ARP/ND source hardware address. */ 1268
788 struct eth_addr arp_tha; /* ARP/ND target hardware address. */ 1269 /* Compressed flow. */
789 ovs_be16 tcp_flags; /* TCP flags. With L3 to avoid matching L4. */
790- ovs_be16 pad3; /* Pad to 64 bits. */
791+ ovs_be16 pad5; /* Pad to 64 bits. */
792
793 /* L4 (64-bit aligned) */
794 ovs_be16 tp_src; /* TCP/UDP/SCTP source port/ICMP type. */
795@@ -158,7 +175,7 @@ BUILD_ASSERT_DECL(sizeof(struct flow_tnl) % sizeof(uint64_t) == 0);
796
797 /* Remember to update FLOW_WC_SEQ when changing 'struct flow'. */
798 BUILD_ASSERT_DECL(offsetof(struct flow, igmp_group_ip4) + sizeof(uint32_t)
799- == sizeof(struct flow_tnl) + 216
800+ == sizeof(struct flow_tnl) + 256
801 && FLOW_WC_SEQ == 35);
802
803 /* Incremental points at which flow classification may be performed in
804diff --git a/lib/match.c b/lib/match.c 1270diff --git a/lib/match.c b/lib/match.c
805index 52437c9..3db2a2b 100644 1271index f19648d..daf0b87 100644
806--- a/lib/match.c 1272--- a/lib/match.c
807+++ b/lib/match.c 1273+++ b/lib/match.c
808@@ -862,6 +862,152 @@ match_set_nd_target_masked(struct match *match, 1274@@ -878,6 +878,152 @@ match_set_nd_target_masked(struct match *match,
809 match->wc.masks.nd_target = *mask; 1275 match->wc.masks.nd_target = *mask;
810 } 1276 }
811 1277
@@ -949,16 +1415,16 @@ index 52437c9..3db2a2b 100644
949+} 1415+}
950+ 1416+
951+void 1417+void
952+match_set_encap_eth_type(struct match *match, uint16_t encap_eth_type) 1418+match_set_encap_eth_type(struct match *match, ovs_be16 encap_eth_type)
953+{ 1419+{
954+ match_set_encap_eth_type_masked(match, encap_eth_type, UINT16_MAX); 1420+ match->wc.masks.encap_eth_type = OVS_BE16_MAX;
1421+ match->flow.encap_eth_type = encap_eth_type;
955+} 1422+}
956+ 1423+
957+
958 /* Returns true if 'a' and 'b' wildcard the same fields and have the same 1424 /* Returns true if 'a' and 'b' wildcard the same fields and have the same
959 * values for fixed fields, otherwise false. */ 1425 * values for fixed fields, otherwise false. */
960 bool 1426 bool
961@@ -1155,6 +1301,50 @@ match_format(const struct match *match, struct ds *s, int priority) 1427@@ -1171,6 +1317,49 @@ match_format(const struct match *match, struct ds *s, int priority)
962 format_ct_label_masked(s, &f->ct_label, &wc->masks.ct_label); 1428 format_ct_label_masked(s, &f->ct_label, &wc->masks.ct_label);
963 } 1429 }
964 1430
@@ -999,57 +1465,21 @@ index 52437c9..3db2a2b 100644
999+ wc->masks.nshc4); 1465+ wc->masks.nshc4);
1000+ } 1466+ }
1001+ 1467+
1002+ if (wc->masks.encap_eth_type) {
1003+ ds_put_format(s, "encap_eth_type=%"PRIu16",", f->encap_eth_type);
1004+ }
1005+
1006+ format_eth_masked(s, "encap_eth_src", f->encap_eth_src, wc->masks.encap_eth_src); 1468+ format_eth_masked(s, "encap_eth_src", f->encap_eth_src, wc->masks.encap_eth_src);
1007+ format_eth_masked(s, "encap_eth_dst", f->encap_eth_dst, wc->masks.encap_eth_dst); 1469+ format_eth_masked(s, "encap_eth_dst", f->encap_eth_dst, wc->masks.encap_eth_dst);
1470+ if (wc->masks.encap_eth_type) {
1471+ ds_put_format(s, "encap_eth_type=0x%04"PRIx16",", ntohs(f->encap_eth_type));
1472+ }
1008+ 1473+
1009 if (wc->masks.dl_type) { 1474 if (wc->masks.dl_type) {
1010 skip_type = true; 1475 skip_type = true;
1011 if (f->dl_type == htons(ETH_TYPE_IP)) { 1476 if (f->dl_type == htons(ETH_TYPE_IP)) {
1012diff --git a/lib/match.h b/lib/match.h
1013index 48aa0b1..529350e 100644
1014--- a/lib/match.h
1015+++ b/lib/match.h
1016@@ -165,6 +165,30 @@ void match_set_nd_target(struct match *, const struct in6_addr *);
1017 void match_set_nd_target_masked(struct match *, const struct in6_addr *,
1018 const struct in6_addr *);
1019
1020+void match_set_nsp_masked(struct match *, ovs_be32 nsp, ovs_be32 mask);
1021+void match_set_nsi_masked(struct match *match, uint8_t nsi, uint8_t mask);
1022+void match_set_nsh_mdtype_masked(struct match *match, uint8_t nsh_mdtype, uint8_t mask);
1023+void match_set_nsh_np_masked(struct match *match, uint8_t nsh_np, uint8_t mask);
1024+void match_set_nshc1_masked(struct match *, ovs_be32 nshc1, ovs_be32 mask);
1025+void match_set_nshc2_masked(struct match *, ovs_be32 nshc2, ovs_be32 mask);
1026+void match_set_nshc3_masked(struct match *, ovs_be32 nshc3, ovs_be32 mask);
1027+void match_set_nshc4_masked(struct match *, ovs_be32 nshc4, ovs_be32 mask);
1028+void match_set_encap_eth_src_masked(struct match *match, const struct eth_addr encap_eth_src, const struct eth_addr mask);
1029+void match_set_encap_eth_dst_masked(struct match *match, const struct eth_addr encap_eth_dst, const struct eth_addr mask);
1030+void match_set_encap_eth_type_masked(struct match *match, ovs_be16 encap_eth_type, ovs_be16 mask);
1031+
1032+void match_set_nsp(struct match *, ovs_be32 nsp);
1033+void match_set_nsi(struct match *match, uint8_t nsi);
1034+void match_set_nsh_mdtype(struct match *match, uint8_t nsh_mdtype);
1035+void match_set_nsh_np(struct match *match, uint8_t nsh_np);
1036+void match_set_nshc1(struct match *, ovs_be32 nshc1);
1037+void match_set_nshc2(struct match *, ovs_be32 nshc2);
1038+void match_set_nshc3(struct match *, ovs_be32 nshc3);
1039+void match_set_nshc4(struct match *, ovs_be32 nshc4);
1040+void match_set_encap_eth_src(struct match *match, const struct eth_addr encap_eth_src);
1041+void match_set_encap_eth_dst(struct match *match, const struct eth_addr encap_eth_dst);
1042+void match_set_encap_eth_type(struct match *match, uint16_t encap_eth_type);
1043+
1044 bool match_equal(const struct match *, const struct match *);
1045 uint32_t match_hash(const struct match *, uint32_t basis);
1046
1047diff --git a/lib/meta-flow.c b/lib/meta-flow.c 1477diff --git a/lib/meta-flow.c b/lib/meta-flow.c
1048index ab77fca..648a753 100644 1478index 5d0721f..cf2e7b6 100644
1049--- a/lib/meta-flow.c 1479--- a/lib/meta-flow.c
1050+++ b/lib/meta-flow.c 1480+++ b/lib/meta-flow.c
1051@@ -243,7 +243,28 @@ mf_is_all_wild(const struct mf_field *mf, const struct flow_wildcards *wc) 1481@@ -247,7 +247,28 @@ mf_is_all_wild(const struct mf_field *mf, const struct flow_wildcards *wc)
1052 return !flow_get_xreg(&wc->masks, mf->id - MFF_XREG0); 1482 }
1053 case MFF_ACTSET_OUTPUT: 1483 case MFF_ACTSET_OUTPUT:
1054 return !wc->masks.actset_output; 1484 return !wc->masks.actset_output;
1055- 1485-
@@ -1078,7 +1508,7 @@ index ab77fca..648a753 100644
1078 case MFF_ETH_SRC: 1508 case MFF_ETH_SRC:
1079 return eth_addr_is_zero(wc->masks.dl_src); 1509 return eth_addr_is_zero(wc->masks.dl_src);
1080 case MFF_ETH_DST: 1510 case MFF_ETH_DST:
1081@@ -557,6 +578,17 @@ mf_is_value_valid(const struct mf_field *mf, const union mf_value *value) 1511@@ -477,6 +498,17 @@ mf_is_value_valid(const struct mf_field *mf, const union mf_value *value)
1082 case MFF_ICMPV6_TYPE: 1512 case MFF_ICMPV6_TYPE:
1083 case MFF_ICMPV6_CODE: 1513 case MFF_ICMPV6_CODE:
1084 case MFF_ND_TARGET: 1514 case MFF_ND_TARGET:
@@ -1096,8 +1526,8 @@ index ab77fca..648a753 100644
1096 case MFF_ND_SLL: 1526 case MFF_ND_SLL:
1097 case MFF_ND_TLL: 1527 case MFF_ND_TLL:
1098 return true; 1528 return true;
1099@@ -716,6 +748,50 @@ mf_get_value(const struct mf_field *mf, const struct flow *flow, 1529@@ -640,6 +672,50 @@ mf_get_value(const struct mf_field *mf, const struct flow *flow,
1100 value->be64 = htonll(flow_get_xreg(flow, mf->id - MFF_XREG0)); 1530 value->be128 = hton128(flow_get_xxreg(flow, mf->id - MFF_XXREG0));
1101 break; 1531 break;
1102 1532
1103+ case MFF_NSP: 1533+ case MFF_NSP:
@@ -1147,7 +1577,7 @@ index ab77fca..648a753 100644
1147 case MFF_ETH_SRC: 1577 case MFF_ETH_SRC:
1148 value->mac = flow->dl_src; 1578 value->mac = flow->dl_src;
1149 break; 1579 break;
1150@@ -1085,6 +1161,50 @@ mf_set_value(const struct mf_field *mf, 1580@@ -1013,6 +1089,50 @@ mf_set_value(const struct mf_field *mf,
1151 match_set_arp_sha(match, value->mac); 1581 match_set_arp_sha(match, value->mac);
1152 break; 1582 break;
1153 1583
@@ -1198,8 +1628,8 @@ index ab77fca..648a753 100644
1198 case MFF_ARP_THA: 1628 case MFF_ARP_THA:
1199 case MFF_ND_TLL: 1629 case MFF_ND_TLL:
1200 match_set_arp_tha(match, value->mac); 1630 match_set_arp_tha(match, value->mac);
1201@@ -1296,6 +1416,50 @@ mf_set_flow_value(const struct mf_field *mf, 1631@@ -1245,6 +1365,50 @@ mf_set_flow_value(const struct mf_field *mf,
1202 flow_set_xreg(flow, mf->id - MFF_XREG0, ntohll(value->be64)); 1632 flow_set_xxreg(flow, mf->id - MFF_XXREG0, ntoh128(value->be128));
1203 break; 1633 break;
1204 1634
1205+ case MFF_NSP: 1635+ case MFF_NSP:
@@ -1249,7 +1679,7 @@ index ab77fca..648a753 100644
1249 case MFF_ETH_SRC: 1679 case MFF_ETH_SRC:
1250 flow->dl_src = value->mac; 1680 flow->dl_src = value->mac;
1251 break; 1681 break;
1252@@ -1734,6 +1898,52 @@ mf_set_wild(const struct mf_field *mf, struct match *match, char **err_str) 1682@@ -1689,6 +1853,52 @@ mf_set_wild(const struct mf_field *mf, struct match *match, char **err_str)
1253 match->wc.masks.arp_sha = eth_addr_zero; 1683 match->wc.masks.arp_sha = eth_addr_zero;
1254 break; 1684 break;
1255 1685
@@ -1302,7 +1732,7 @@ index ab77fca..648a753 100644
1302 case MFF_ARP_THA: 1732 case MFF_ARP_THA:
1303 case MFF_ND_TLL: 1733 case MFF_ND_TLL:
1304 match->flow.arp_tha = eth_addr_zero; 1734 match->flow.arp_tha = eth_addr_zero;
1305@@ -1929,6 +2139,50 @@ mf_set(const struct mf_field *mf, 1735@@ -1890,6 +2100,50 @@ mf_set(const struct mf_field *mf,
1306 match_set_arp_sha_masked(match, value->mac, mask->mac); 1736 match_set_arp_sha_masked(match, value->mac, mask->mac);
1307 break; 1737 break;
1308 1738
@@ -1353,218 +1783,181 @@ index ab77fca..648a753 100644
1353 case MFF_ARP_THA: 1783 case MFF_ARP_THA:
1354 case MFF_ND_TLL: 1784 case MFF_ND_TLL:
1355 match_set_arp_tha_masked(match, value->mac, mask->mac); 1785 match_set_arp_tha_masked(match, value->mac, mask->mac);
1356diff --git a/lib/meta-flow.h b/lib/meta-flow.h 1786diff --git a/lib/netdev-native-tnl.c b/lib/netdev-native-tnl.c
1357index 4bd9ff6..a226b79 100644 1787index ce2582f..2fe2722 100644
1358--- a/lib/meta-flow.h 1788--- a/lib/netdev-native-tnl.c
1359+++ b/lib/meta-flow.h 1789+++ b/lib/netdev-native-tnl.c
1360@@ -1747,6 +1747,180 @@ enum OVS_PACKED_ENUM mf_field_id { 1790@@ -44,6 +44,7 @@
1361 */ 1791 #include "unaligned.h"
1362 MFF_ND_TLL, 1792 #include "unixctl.h"
1793 #include "openvswitch/vlog.h"
1794+#include "openvswitch/vxlangpe.h"
1795
1796 VLOG_DEFINE_THIS_MODULE(native_tnl);
1797 static struct vlog_rate_limit err_rl = VLOG_RATE_LIMIT_INIT(60, 5);
1798@@ -209,6 +210,9 @@ netdev_tnl_push_udp_header(struct dp_packet *packet,
1799 struct udp_header *udp;
1800 int ip_tot_size;
1801
1802+ if ((data->tnl_type == OVS_VPORT_TYPE_VXLAN) && (data->exts & (1 << VXLAN_GPE_POP_ETH)))
1803+ dp_packet_reset_packet(packet, ENCAP_ETH_LEN);
1804+
1805 udp = netdev_tnl_push_ip_header(packet, data->header, data->header_len, &ip_tot_size);
1806
1807 /* set udp src port */
1808@@ -478,6 +482,8 @@ netdev_vxlan_pop_header(struct dp_packet *packet)
1809 struct flow_tnl *tnl = &md->tunnel;
1810 struct vxlanhdr *vxh;
1811 unsigned int hlen;
1812+ ovs_be32 flag;
1813+ ovs_be32 vni;
1814
1815 pkt_metadata_init_tnl(md);
1816 if (VXLAN_HLEN > dp_packet_l4_size(packet)) {
1817@@ -489,17 +495,59 @@ netdev_vxlan_pop_header(struct dp_packet *packet)
1818 goto err;
1819 }
1363 1820
1364+ /* "nsp". 1821- if (get_16aligned_be32(&vxh->vx_flags) != htonl(VXLAN_FLAGS) ||
1365+ * 1822- (get_16aligned_be32(&vxh->vx_vni) & htonl(0xff))) {
1366+ * For a packet received including a (32-bit) 1823- VLOG_WARN_RL(&err_rl, "invalid vxlan flags=%#x vni=%#x\n",
1367+ * network service header service path (nsp), the nsp is stored 1824- ntohl(get_16aligned_be32(&vxh->vx_flags)),
1368+ * in the low 24-bits and the high bits are zeroed. For 1825- ntohl(get_16aligned_be32(&vxh->vx_vni)));
1369+ * other packets, the value is 0. 1826- goto err;
1370+ * 1827- }
1371+ * Type: be32. 1828- tnl->tun_id = htonll(ntohl(get_16aligned_be32(&vxh->vx_vni)) >> 8);
1372+ * Maskable: bitwise. 1829- tnl->flags |= FLOW_TNL_F_KEY;
1373+ * Formatting: hexadecimal. 1830+ /* vxlan-gpe packets*/
1374+ * Prerequisites: none. 1831+ flag = get_16aligned_be32(&vxh->vx_flags);
1375+ * Access: read/write. 1832+ vni = get_16aligned_be32(&vxh->vx_vni);
1376+ * NXM: NXM_NX_NSP(113) since v1.1. 1833+
1377+ * OXM: none. 1834+ if (flag & VXLAN_HF_GPE) {
1378+ * Prefix lookup member: nsp. 1835+ flag &= ~VXLAN_GPE_USED_BITS;
1379+ */ 1836+ if ((flag & ~VXLAN_GPE_USED_BITS) ||
1380+ MFF_NSP, 1837+ (vni & htonl(0xff))) {
1381+ 1838+
1382+ /* "nsi". 1839+ VLOG_WARN_RL(&err_rl, "invalid vxlan flags=%#x vni=%#x\n for vxlan-gpe",
1383+ * 1840+ ntohl(flag),
1384+ * For a packet received, it includes a (8-bit) 1841+ ntohl(vni));
1385+ * network service header service index (nsi). 1842+ goto err;
1386+ * 1843+ }
1387+ * Type: u8.
1388+ * Maskable: bitwise.
1389+ * Formatting: decimal.
1390+ * Prerequisites: none.
1391+ * Access: read/write.
1392+ * NXM: NXM_NX_NSI(114) since v1.1.
1393+ * OXM: none.
1394+ * Prefix lookup member: nsi.
1395+ */
1396+ MFF_NSI,
1397+
1398+ /* "nshc1".
1399+ *
1400+ * For a packet received including a (32-bit)
1401+ * Network Platform Context (nshc1), the nshc1 is stored
1402+ * in the 32-bits. For other packets, the value is 0.
1403+ *
1404+ * Type: be32.
1405+ * Maskable: bitwise.
1406+ * Formatting: hexadecimal.
1407+ * Prerequisites: none.
1408+ * Access: read/write.
1409+ * NXM: NXM_NX_NSH_C1(115) since v1.1.
1410+ * OXM: none.
1411+ * Prefix lookup member: nshc1.
1412+ */
1413+ MFF_NSH_C1,
1414+
1415+ /* "nshc2".
1416+ *
1417+ * For a packet received including a (32-bit)
1418+ * Network Shared Context (nshc2), the nshc2 is stored
1419+ * in the 32-bits. For other packets, the value is 0.
1420+ *
1421+ * Type: be32.
1422+ * Maskable: bitwise.
1423+ * Formatting: hexadecimal.
1424+ * Prerequisites: none.
1425+ * Access: read/write.
1426+ * NXM: NXM_NX_NSH_C2(116) since v1.1.
1427+ * OXM: none.
1428+ * Prefix lookup member: nshc2.
1429+ */
1430+ MFF_NSH_C2,
1431+
1432+ /* "nshc3".
1433+ *
1434+ * For a packet received via including a (32-bit)
1435+ * Service Platform Context (nshc3), the nshc3 is stored
1436+ * in the 32-bits. For other packets, the value is 0.
1437+ *
1438+ * Type: be32.
1439+ * Maskable: bitwise.
1440+ * Formatting: hexadecimal.
1441+ * Prerequisites: none.
1442+ * Access: read/write.
1443+ * NXM: NXM_NX_NSH_C3(117) since v1.1.
1444+ * OXM: none.
1445+ * Prefix lookup member: nshc3.
1446+ */
1447+ MFF_NSH_C3,
1448+
1449+ /* "nshc4".
1450+ *
1451+ * For a packet received including a (32-bit)
1452+ * Service Shared Context (nshc4), the nshc4 is stored
1453+ * in the 32-bits. For other packets, the value is 0.
1454+ *
1455+ * Type: be32.
1456+ * Maskable: bitwise.
1457+ * Formatting: hexadecimal.
1458+ * Prerequisites: none.
1459+ * Access: read/write.
1460+ * NXM: NXM_NX_NSH_C4(118) since v1.1.
1461+ * OXM: none.
1462+ * Prefix lookup member: nshc4.
1463+ */
1464+ MFF_NSH_C4,
1465+ 1844+
1466+ /* "nsh_mdtype". 1845+ struct vxlanhdr_gpe *gpe;
1467+ * 1846+
1468+ * For a packet received, it includes a (8-bit) 1847+ gpe = (struct vxlanhdr_gpe *)vxh;
1469+ * nsh md-type field (md-type). 1848+ tnl->gpe_np = gpe->next_protocol;
1470+ * 1849
1471+ * Type: u8. 1850- dp_packet_reset_packet(packet, hlen + VXLAN_HLEN);
1472+ * Maskable: bitwise. 1851+ /* Drop the OAM packets */
1473+ * Formatting: decimal. 1852+ if (gpe->oam_flag)
1474+ * Prerequisites: none. 1853+ goto err;
1475+ * Access: read/write. 1854+
1476+ * NXM: NXM_NX_NSH_MDTYPE(119) since v1.1. 1855+ tnl->tun_id = htonll(ntohl(vni) >> 8);
1477+ * OXM: none. 1856+ tnl->flags |= FLOW_TNL_F_KEY;
1478+ */ 1857+
1479+ MFF_NSH_MDTYPE, 1858+ if (tnl->gpe_np == VXLAN_GPE_NP_NSH) {
1859+ /* Add a faked ethernet header which type is 0x894F, so the OVS
1860+ * can receive frame starting with ethernet header.
1861+ */
1862+ struct eth_header * encap_eth;
1863+ struct eth_header * eth = dp_packet_l2(packet);
1864+
1865+ memmove((char *)eth + hlen + VXLAN_HLEN - ENCAP_ETH_LEN, (char *)eth + hlen + VXLAN_HLEN + NSH_PUSH_TYPE1_HEADER_SIZE, 2 * ETH_ADDR_LEN);