summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGuo Ruijing <ruijing.guo@intel.com>2016-05-24 07:59:45 +0000
committerGuo Ruijing <ruijing.guo@intel.com>2016-05-24 08:06:51 +0000
commit2bad5a25e9a5cabb6f5c767cef287fd1f2701bdd (patch)
treece0251e8f3a9ab1930a33470a475a58845727b03
parentb15c57083b8646ffd38271bee81704cf120f5599 (diff)
refactor scripts and update NSH patch
Change-Id: Ifc76e9bf2f83f904e765e6e8216ed98910642bae Signed-off-by: Guo Ruijing <ruijing.guo@intel.com>
Notes
Notes (review): Code-Review+2: Ruijing <ruijing.guo@intel.com> Workflow+1: Ruijing <ruijing.guo@intel.com> Verified+2: Jenkins Submitted-by: Jenkins Submitted-at: Tue, 24 May 2016 08:10:49 +0000 Reviewed-on: https://review.openstack.org/319087 Project: openstack/fuel-plugin-ovs Branch: refs/heads/master
-rw-r--r--deployment_scripts/install.sh23
-rw-r--r--deployment_scripts/puppet/manifests/ovs-install-compute.pp22
-rw-r--r--deployment_tasks.yaml21
-rw-r--r--ovs_build/Dockerfile10
-rwxr-xr-xovs_build/build-ovs-dpdk.sh50
-rwxr-xr-xovs_build/build-ovs-nsh-dpdk.sh118
-rwxr-xr-xovs_build/build-ovs-nsh.sh23
-rw-r--r--ovs_build/patches/0001-ovs-vxlan-gpe-vxlan-extension-to-support-vxlan-gpe-t.patch732
-rw-r--r--ovs_build/patches/0002-ovs-nsh-support-push-and-pop-actions-for-vxlan-gpe-a.patch2746
-rw-r--r--ovs_build/patches/0003-Add-userspace-dataplane-nsh-support-and-remove-push_.patch2327
-rw-r--r--ovs_build/patches/0004-Fix-too-large-stack-frame-size.patch264
-rw-r--r--ovs_build/patches/0005-Ethernet-header-must-be-kept-in-VxLAN-gpe-eth-NSH-fo.patch815
-rw-r--r--ovs_build/patches/060679.patch3187
-rw-r--r--ovs_build/patches/060680.patch788
-rw-r--r--ovs_build/patches/060681.patch1025
-rw-r--r--ovs_build/patches/060682.patch730
-rw-r--r--ovs_build/patches/060683.patch1334
-rw-r--r--ovs_build/patches/060684.patch151
-rw-r--r--ovs_build/patches/060685.patch675
-rw-r--r--ovs_build/patches/README1
-rw-r--r--ovs_package/ubuntu/dependencies.txt0
-rwxr-xr-xpre_build_hook27
-rwxr-xr-xrepositories/ubuntu/install.sh25
-rw-r--r--tasks.yaml9
24 files changed, 7071 insertions, 8032 deletions
diff --git a/deployment_scripts/install.sh b/deployment_scripts/install.sh
new file mode 100644
index 0000000..be01aa8
--- /dev/null
+++ b/deployment_scripts/install.sh
@@ -0,0 +1,23 @@
1#!/bin/bash
2set -eux
3
4INSTALL_HOME=/tmp/ovs-nshdpdk
5rm -rf $INSTALL_HOME; mkdir -p $INSTALL_HOME
6cd $INSTALL_HOME
7
8host=$1
9nsh=$2
10dpdk=$3
11
12wget -r -nd -np http://$host:8080/plugins/fuel-plugin-ovs-0.9/ovs_package/ubuntu
13
14if [ $nsh = 'true' ]
15then
16 dpkg -i openvswitch-datapath-dkms_2.5.90-1_all.deb
17 dpkg -i openvswitch-common_2.5.90-1_amd64.deb
18 dpkg -i openvswitch-switch_2.5.90-1_amd64.deb
19 if [ $dpdk = 'true' ]
20 then
21 dpkg -i openvswitch-switch-dpdk_2.5.90-1_amd64.deb
22 fi
23fi
diff --git a/deployment_scripts/puppet/manifests/ovs-install-compute.pp b/deployment_scripts/puppet/manifests/ovs-install-compute.pp
index dae0659..0d15ee1 100644
--- a/deployment_scripts/puppet/manifests/ovs-install-compute.pp
+++ b/deployment_scripts/puppet/manifests/ovs-install-compute.pp
@@ -1,21 +1,11 @@
1$fuel_settings = parseyaml(file('/etc/astute.yaml')) 1$fuel_settings = parseyaml(file('/etc/astute.yaml'))
2$master_ip = $::fuel_settings['master_ip']
3$support_nsh = $::fuel_settings['fuel-plugin-ovs']['support_nsh']
4$support_dpdk = $::fuel_settings['fuel-plugin-ovs']['support_dpdk']
2if $operatingsystem == 'Ubuntu' { 5if $operatingsystem == 'Ubuntu' {
3 if $fuel_settings['fuel-plugin-ovs']['support_nsh'] and 6 exec { 'install ovs_nsh_dpdk':
4 $fuel_settings['fuel-plugin-ovs']['support_dpdk'] { 7 command => "curl http://${master_ip}:8080/plugins/fuel-plugin-ovs-0.9/deployment_scripts/install.sh | bash -s ${master_ip} ${support_nsh} ${support_dpdk}",
5 exec { 'install ovs/nsh-dpdk': 8 path => "/usr/bin:/usr/sbin:/bin:/sbin";
6 command => '/usr/bin/curl http://10.20.0.2:8080/plugins/fuel-plugin-ovs-0.9/repositories/ubuntu/install.sh | /bin/bash -s nshdpdk'
7 }
8 } 9 }
9 elsif $fuel_settings['fuel-plugin-ovs']['support_dpdk'] {
10 exec { 'install ovs/dpdk':
11 command => '/usr/bin/curl http://10.20.0.2:8080/plugins/fuel-plugin-ovs-0.9/repositories/ubuntu/install.sh | /bin/bash -s dpdk'
12 }
13 }
14 elsif $fuel_settings['fuel-plugin-ovs']['support_nsh'] {
15 exec { 'install ovs/nsh':
16 command => '/usr/bin/curl http://10.20.0.2:8080/plugins/fuel-plugin-ovs-0.9/repositories/ubuntu/install.sh | /bin/bash -s nsh'
17 }
18 }
19
20} elsif $operatingsystem == 'CentOS' { 10} elsif $operatingsystem == 'CentOS' {
21} 11}
diff --git a/deployment_tasks.yaml b/deployment_tasks.yaml
index fe51488..12d9bc4 100644
--- a/deployment_tasks.yaml
+++ b/deployment_tasks.yaml
@@ -1 +1,20 @@
1[] 1- id: ovs_nsh_dpdk
2 type: group
3 role: ['compute']
4 requires: [deploy_start]
5 required_for: [deploy_end]
6 tasks: [hiera, setup_repositories, fuel_pkgs, globals, tools, logging, ovs_install_compute]
7 parameters:
8 strategy:
9 type: parallel
10
11- id: ovs_install_compute
12 type: puppet
13 version: 2.0.0
14 groups: [ovs_nsh_dpdk]
15 required_for: [pre_deployment_end]
16 requires: [pre_deployment_start]
17 parameters:
18 puppet_manifest: puppet/manifests/ovs-install-compute.pp
19 puppet_modules: puppet/modules:/etc/puppet/modules
20 timeout: 720
diff --git a/ovs_build/Dockerfile b/ovs_build/Dockerfile
index f92df82..e35eb64 100644
--- a/ovs_build/Dockerfile
+++ b/ovs_build/Dockerfile
@@ -3,12 +3,8 @@
3FROM ubuntu:14.04.3 3FROM ubuntu:14.04.3
4 4
5RUN apt-get update -y 5RUN apt-get update -y
6
7RUN rm -rf /lib/modules 6RUN rm -rf /lib/modules
8RUN apt-get install -y linux-headers-3.13.0-76-generic 7RUN apt-get install -y linux-headers-3.13.0-86-generic
9RUN ln -s /lib/modules/3.13.0-76-generic /lib/modules/`uname -r` 8RUN ln -s /lib/modules/3.13.0-86-generic /lib/modules/`uname -r`
10
11RUN apt-get build-dep openvswitch -y
12RUN apt-get -y install devscripts dpkg-dev git wget
13 9
14ADD ./ /ovs_build 10ADD ./ /ovs_build
diff --git a/ovs_build/build-ovs-dpdk.sh b/ovs_build/build-ovs-dpdk.sh
index 8ab7804..76667dd 100755
--- a/ovs_build/build-ovs-dpdk.sh
+++ b/ovs_build/build-ovs-dpdk.sh
@@ -1,16 +1,20 @@
1#!/bin/bash 1#!/bin/bash
2 2
3OVS_COMMIT=cd4764fdd8ce0aa0063525dad0e67f20b3bcf6e9 3OVS_COMMIT=cd4764fdd8ce0aa0063525dad0e67f20b3bcf6e9
4URL_OVS=https://github.com/openvswitch/ovs.git
5OVS_VER=${OVS_VER:-2.5.1}
6BUILD_HOME=$HOME/dpdk
7BUILD_DEST=${BUILD_DEST:-/deb}
4 8
5BUILD_HOME=`pwd`
6sudo apt-get update -y
7sudo apt-get build-dep openvswitch -y 9sudo apt-get build-dep openvswitch -y
8sudo apt-get -y install devscripts dpkg-dev git wget 10sudo apt-get -y install devscripts dpkg-dev git wget
9 11
12rm -rf ${BUILD_HOME}; mkdir -p ${BUILD_HOME}
13
10cd ${BUILD_HOME} 14cd ${BUILD_HOME}
11wget https://launchpad.net/ubuntu/+archive/primary/+files/dpdk_2.2.0-0ubuntu8.dsc 15wget -c https://launchpad.net/ubuntu/+archive/primary/+files/dpdk_2.2.0-0ubuntu8.dsc
12wget https://launchpad.net/ubuntu/+archive/primary/+files/dpdk_2.2.0.orig.tar.gz 16wget -c https://launchpad.net/ubuntu/+archive/primary/+files/dpdk_2.2.0.orig.tar.gz
13wget https://launchpad.net/ubuntu/+archive/primary/+files/dpdk_2.2.0-0ubuntu8.debian.tar.xz 17wget -c https://launchpad.net/ubuntu/+archive/primary/+files/dpdk_2.2.0-0ubuntu8.debian.tar.xz
14dpkg-source -x dpdk_2.2.0-0ubuntu8.dsc 18dpkg-source -x dpdk_2.2.0-0ubuntu8.dsc
15 19
16# copy from debian/control 20# copy from debian/control
@@ -29,15 +33,20 @@ sudo apt-get install -y debhelper \
29 texlive-fonts-recommended \ 33 texlive-fonts-recommended \
30 texlive-latex-extra 34 texlive-latex-extra
31 35
32cd dpdk-2.2.0; rm -rf debian/patches/; debian/rules build; fakeroot debian/rules binary 36cd dpdk-2.2.0; rm -rf debian/patches/;
37cat << EOF > debian/changelog
38dpdk (2.2.0-1) unstable; urgency=low
39 [ DPDK team]
40 * New upstream version
41EOF
42debian/rules build; fakeroot debian/rules binary
33cd ${BUILD_HOME}; sudo dpkg -i *.deb 43cd ${BUILD_HOME}; sudo dpkg -i *.deb
34 44
35cd ${BUILD_HOME} 45cd ${BUILD_HOME}
36wget https://launchpad.net/ubuntu/+archive/primary/+files/openvswitch-dpdk_2.4.0.orig.tar.gz 46wget -c https://launchpad.net/ubuntu/+archive/primary/+files/openvswitch-dpdk_2.4.0.orig.tar.gz
37wget https://launchpad.net/ubuntu/+archive/primary/+files/openvswitch-dpdk_2.4.0-0ubuntu1.dsc 47wget -c https://launchpad.net/ubuntu/+archive/primary/+files/openvswitch-dpdk_2.4.0-0ubuntu1.dsc
38wget https://launchpad.net/ubuntu/+archive/primary/+files/openvswitch-dpdk_2.4.0-0ubuntu1.debian.tar.xz 48wget -c https://launchpad.net/ubuntu/+archive/primary/+files/openvswitch-dpdk_2.4.0-0ubuntu1.debian.tar.xz
39dpkg-source -x openvswitch-dpdk_2.4.0-0ubuntu1.dsc 49dpkg-source -x openvswitch-dpdk_2.4.0-0ubuntu1.dsc
40
41 50
42# copy from debian/control 51# copy from debian/control
43sudo apt-get intall -y autoconf \ 52sudo apt-get intall -y autoconf \
@@ -56,16 +65,27 @@ sudo apt-get intall -y autoconf \
56 python-all \ 65 python-all \
57 python-qt4 \ 66 python-qt4 \
58 python-twisted-conch \ 67 python-twisted-conch \
59 python-zopeinterface 68 python-zopeinterface \
69 python-six
60 70
61git clone https://github.com/openvswitch/ovs.git 71git clone https://github.com/openvswitch/ovs.git
62cd ovs; git checkout ${OVS_COMMIT} 72cd ovs; git checkout ${OVS_COMMIT}
63cd ${BUILD_HOME}; tar czvf ovs.tar.gz ovs 73cd ${BUILD_HOME}; tar czvf ovs.tar.gz ovs
64rm -rf openvswitch-dpdk-2.5.0* 74rm -rf openvswitch-dpdk-${OVS_VER}*
65cd openvswitch-dpdk-2.4.0; uupdate -v 2.5.0 ../ovs.tar.gz 75cd openvswitch-dpdk-2.4.0; uupdate -v ${OVS_VER} ../ovs.tar.gz
66cd ../openvswitch-dpdk-2.5.0 76cd ../openvswitch-dpdk-${OVS_VER}
67sed -i "s/include\/rte_config.h/include\/dpdk\/rte_config.h/" acinclude.m4 77sed -i "s/include\/rte_config.h/include\/dpdk\/rte_config.h/" acinclude.m4
68sed -i 's/DPDK_INCLUDE=.*/DPDK_INCLUDE=$RTE_SDK\/include\/dpdk/' acinclude.m4 78sed -i 's/DPDK_INCLUDE=.*/DPDK_INCLUDE=$RTE_SDK\/include\/dpdk/' acinclude.m4
69autoreconf --install 79autoreconf --install
70rm -rf debian/patches/ .git; 80rm -rf debian/patches/ .git;
81cat << EOF > debian/changelog
82openvswitch-dpdk (${OVS_VER}-1) unstable; urgency=low
83 [ Open vSwitch team ]
84 * Open vSwitch Upstream
85EOF
71debian/rules build; fakeroot debian/rules binary 86debian/rules build; fakeroot debian/rules binary
87
88cd ${BUILD_HOME}/ovs
89debian/rules build; fakeroot debian/rules binary
90
91cp ${BUILD_HOME}/*.deb ${BUILD_DEST}
diff --git a/ovs_build/build-ovs-nsh-dpdk.sh b/ovs_build/build-ovs-nsh-dpdk.sh
index 3bb653c..d7c3e99 100755
--- a/ovs_build/build-ovs-nsh-dpdk.sh
+++ b/ovs_build/build-ovs-nsh-dpdk.sh
@@ -1,43 +1,97 @@
1#!/bin/bash 1#!/bin/bash
2 2
3DPDK_VER=2.1.0 3OVS_COMMIT=7d433ae57ebb90cd68e8fa948a096f619ac4e2d8
4BUILD_HOME=`pwd`/tmp 4URL_OVS=https://github.com/openvswitch/ovs.git
5OVS_VER=${OVS_VER:-2.5.90}
6BUILD_HOME=$HOME/nsh
7BUILD_DEST=${BUILD_DEST:-/deb}
5 8
6export RTE_TARGET=x86_64-native-linuxapp-gcc 9sudo apt-get build-dep openvswitch -y
7export RTE_SDK=${BUILD_HOME}/dpdk-${DPDK_VER} 10sudo apt-get -y install devscripts dpkg-dev git wget
8export DPDK_BUILD=${RTE_SDK}/${RTE_TARGET}
9 11
10OVS_COMMIT=121daded51b9798fe3722824b27a05c16806cbd1 12rm -rf ${BUILD_HOME}; mkdir -p ${BUILD_HOME}
11PATCHES="060679 060680 060681 060682 060683 060684 060685"
12URL_OVS=https://github.com/openvswitch/ovs.git
13URL_DPDK=http://dpdk.org/browse/dpdk/snapshot/dpdk-${DPDK_VER}.tar.gz
14 13
15mkdir -p ${BUILD_HOME}
16cd ${BUILD_HOME} 14cd ${BUILD_HOME}
17wget ${URL_DPDK} 15wget -c https://launchpad.net/ubuntu/+archive/primary/+files/dpdk_2.2.0-0ubuntu8.dsc
18tar -xzvf dpdk-${DPDK_VER}.tar.gz 16wget -c https://launchpad.net/ubuntu/+archive/primary/+files/dpdk_2.2.0.orig.tar.gz
19cd dpdk-${DPDK_VER} 17wget -c https://launchpad.net/ubuntu/+archive/primary/+files/dpdk_2.2.0-0ubuntu8.debian.tar.xz
20sed -i -e 's/CONFIG_RTE_LIBRTE_VHOST=n/CONFIG_RTE_LIBRTE_VHOST=y/' \ 18dpkg-source -x dpdk_2.2.0-0ubuntu8.dsc
21 -e 's/CONFIG_RTE_BUILD_COMBINE_LIBS=n/CONFIG_RTE_BUILD_COMBINE_LIBS=y/' \ 19
22 -e 's/CONFIG_RTE_PKTMBUF_HEADROOM=128/CONFIG_RTE_PKTMBUF_HEADROOM=256/' \ 20# copy from debian/control
23 config/common_linuxapp 21sudo apt-get install -y debhelper \
24make install T=${RTE_TARGET} 22 dh-python \
23 dh-systemd \
24 doxygen \
25 graphviz \
26 inkscape \
27 libcap-dev \
28 libpcap-dev \
29 libxen-dev \
30 libxenstore3.0 \
31 python \
32 python-sphinx \
33 texlive-fonts-recommended \
34 texlive-latex-extra
35
36cd dpdk-2.2.0; rm -rf debian/patches/;
37cat << EOF > debian/changelog
38dpdk (2.2.0-1) unstable; urgency=low
39 [ DPDK team]
40 * New upstream version
41EOF
42debian/rules build; fakeroot debian/rules binary
43cd ${BUILD_HOME}; sudo dpkg -i *.deb
25 44
26cd ${BUILD_HOME} 45cd ${BUILD_HOME}
27git clone ${URL_OVS} openvswitch 46wget -c https://launchpad.net/ubuntu/+archive/primary/+files/openvswitch-dpdk_2.4.0.orig.tar.gz
28cd openvswitch 47wget -c https://launchpad.net/ubuntu/+archive/primary/+files/openvswitch-dpdk_2.4.0-0ubuntu1.dsc
29git checkout ${OVS_COMMIT} -b development 48wget -c https://launchpad.net/ubuntu/+archive/primary/+files/openvswitch-dpdk_2.4.0-0ubuntu1.debian.tar.xz
49dpkg-source -x openvswitch-dpdk_2.4.0-0ubuntu1.dsc
50
51# copy from debian/control
52sudo apt-get intall -y autoconf \
53 automake \
54 bzip2 \
55 debhelper \
56 dh-autoreconf \
57 dh-systemd \
58 graphviz \
59 libdpdk-dev \
60 libfuse-dev \
61 libssl-dev \
62 libtool \
63 openssl \
64 procps \
65 python-all \
66 python-qt4 \
67 python-twisted-conch \
68 python-zopeinterface \
69 python-six
70
71git clone https://github.com/openvswitch/ovs.git
72cd ovs; git checkout ${OVS_COMMIT}
73DIR="$(dirname `readlink -f $0`)"
74PATCHES=$(cd patches; echo *patch; cd ..)
30for patch in ${PATCHES} 75for patch in ${PATCHES}
31do 76do
32 patch -p1 < /ovs_build/patches/${patch}.patch 77 patch -p1 < {DIR}/patches/${patch}
33done 78done
34export DEB_BUILD_OPTIONS='parallel=8 nocheck' 79cd ${BUILD_HOME}; tar czvf ovs.tar.gz ovs
35sed -i "s/2.4.90/2.4.90.nshdpdk/g" debian/changelog 80rm -rf openvswitch-dpdk-${OVS_VER}*
36sed -i "s/DATAPATH_CONFIGURE_OPTS.*=.*//" debian/rules 81cd openvswitch-dpdk-2.4.0; uupdate -v ${OVS_VER} ../ovs.tar.gz
37sed -i "2iDATAPATH_CONFIGURE_OPTS='--with-dpdk=$DPDK_BUILD'" debian/rules 82cd ../openvswitch-dpdk-${OVS_VER}
38sed -i "s/DATAPATH_CONFIGURE_OPTS.*=.*//" debian/rules.modules 83sed -i "s/include\/rte_config.h/include\/dpdk\/rte_config.h/" acinclude.m4
39sed -i "2iDATAPATH_CONFIGURE_OPTS='--with-dpdk=$DPDK_BUILD'" debian/rules.modules 84sed -i 's/DPDK_INCLUDE=.*/DPDK_INCLUDE=$RTE_SDK\/include\/dpdk/' acinclude.m4
40debian/rules build 85autoreconf --install
41fakeroot debian/rules binary 86rm -rf debian/patches/ .git;
42 87cat << EOF > debian/changelog
43cp ${BUILD_HOME}/*.deb /deb 88openvswitch-dpdk (${OVS_VER}-1) unstable; urgency=low
89 [ Open vSwitch team ]
90 * Support NSH
91EOF
92debian/rules build; fakeroot debian/rules binary
93
94cd ${BUILD_HOME}/ovs
95debian/rules build; fakeroot debian/rules binary
96
97cp ${BUILD_HOME}/*.deb ${BUILD_DEST}
diff --git a/ovs_build/build-ovs-nsh.sh b/ovs_build/build-ovs-nsh.sh
deleted file mode 100755
index 03db867..0000000
--- a/ovs_build/build-ovs-nsh.sh
+++ /dev/null
@@ -1,23 +0,0 @@
1#!/bin/bash
2
3BUILD_HOME=`pwd`/tmp
4
5OVS_COMMIT=121daded51b9798fe3722824b27a05c16806cbd1
6PATCHES="060679 060680 060681 060682 060683 060684 060685"
7URL_OVS=https://github.com/openvswitch/ovs.git
8
9mkdir -p ${BUILD_HOME}
10cd ${BUILD_HOME}
11git clone ${URL_OVS} openvswitch
12cd openvswitch
13git checkout ${OVS_COMMIT} -b development
14for patch in ${PATCHES}
15do
16 patch -p1 < /ovs_build/patches/${patch}.patch
17done
18
19export DEB_BUILD_OPTIONS='parallel=8 nocheck'
20sed -i "s/2.4.90/2.4.90.nsh/g" debian/changelog
21debian/rules build
22fakeroot debian/rules binary
23cp ${BUILD_HOME}/*.deb /deb
diff --git a/ovs_build/patches/0001-ovs-vxlan-gpe-vxlan-extension-to-support-vxlan-gpe-t.patch b/ovs_build/patches/0001-ovs-vxlan-gpe-vxlan-extension-to-support-vxlan-gpe-t.patch
new file mode 100644
index 0000000..ae0e269
--- /dev/null
+++ b/ovs_build/patches/0001-ovs-vxlan-gpe-vxlan-extension-to-support-vxlan-gpe-t.patch
@@ -0,0 +1,732 @@
1From 5d79831435ec4e5bea20cc36c3f83eacf6fd065c Mon Sep 17 00:00:00 2001
2From: Yi Yang <yi.y.yang@intel.com>
3Date: Mon, 11 Apr 2016 15:58:14 +0800
4Subject: [PATCH 1/5] ovs-vxlan-gpe: vxlan extension to support vxlan-gpe
5 tunnel port
6
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>
11---
12 datapath/flow_netlink.c | 8 +-
13 datapath/linux/compat/include/linux/openvswitch.h | 1 +
14 datapath/linux/compat/include/net/vxlan.h | 73 +++++++++++++++++++
15 datapath/linux/compat/vxlan.c | 30 ++++++++
16 datapath/vport-vxlan.c | 15 ++++
17 lib/flow.c | 8 ++
18 lib/match.c | 34 +++++++++
19 lib/match.h | 4 +
20 lib/meta-flow.c | 36 +++++++++
21 lib/meta-flow.h | 28 +++++++
22 lib/netdev-vport.c | 2 +
23 lib/nx-match.c | 4 +
24 lib/odp-util.c | 89 ++++++++++++++++++++++-
25 lib/packets.h | 4 +-
26 tests/ofproto.at | 4 +-
27 tests/ovs-ofctl.at | 4 +
28 16 files changed, 340 insertions(+), 4 deletions(-)
29
30diff --git a/datapath/flow_netlink.c b/datapath/flow_netlink.c
31index 6ffcc53..351a504 100644
32--- a/datapath/flow_netlink.c
33+++ b/datapath/flow_netlink.c
34@@ -309,6 +309,7 @@ size_t ovs_key_attr_size(void)
35
36 static const struct ovs_len_tbl ovs_vxlan_ext_key_lens[OVS_VXLAN_EXT_MAX + 1] = {
37 [OVS_VXLAN_EXT_GBP] = { .len = sizeof(u32) },
38+ [OVS_VXLAN_EXT_GPE] = { .len = sizeof(u32) },
39 };
40
41 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,
43 case OVS_VXLAN_EXT_GBP:
44 opts.gbp = nla_get_u32(a);
45 break;
46+ case OVS_VXLAN_EXT_GPE:
47+ opts.gpe = nla_get_u32(a);
48+ break;
49 default:
50 OVS_NLERR(log, "Unknown VXLAN extension attribute %d",
51 type);
52@@ -677,7 +681,9 @@ static int vxlan_opt_to_nlattr(struct sk_buff *skb,
53 if (!nla)
54 return -EMSGSIZE;
55
56- if (nla_put_u32(skb, OVS_VXLAN_EXT_GBP, opts->gbp) < 0)
57+ if (opts->gbp && nla_put_u32(skb, OVS_VXLAN_EXT_GBP, opts->gbp) < 0)
58+ return -EMSGSIZE;
59+ else if (opts->gpe && nla_put_u32(skb, OVS_VXLAN_EXT_GPE, opts->gpe) < 0)
60 return -EMSGSIZE;
61
62 nla_nest_end(skb, nla);
63diff --git a/datapath/linux/compat/include/linux/openvswitch.h b/datapath/linux/compat/include/linux/openvswitch.h
64index 3b39ebb..44adb81 100644
65--- a/datapath/linux/compat/include/linux/openvswitch.h
66+++ b/datapath/linux/compat/include/linux/openvswitch.h
67@@ -287,6 +287,7 @@ enum ovs_vport_attr {
68 enum {
69 OVS_VXLAN_EXT_UNSPEC,
70 OVS_VXLAN_EXT_GBP, /* Flag or __u32 */
71+ OVS_VXLAN_EXT_GPE,
72 __OVS_VXLAN_EXT_MAX,
73 };
74
75diff --git a/datapath/linux/compat/include/net/vxlan.h b/datapath/linux/compat/include/net/vxlan.h
76index 75a5a7a..2bfc3f8 100644
77--- a/datapath/linux/compat/include/net/vxlan.h
78+++ b/datapath/linux/compat/include/net/vxlan.h
79@@ -84,6 +84,75 @@ struct vxlanhdr_gbp {
80 #define VXLAN_GBP_POLICY_APPLIED (BIT(3) << 16)
81 #define VXLAN_GBP_ID_MASK (0xFFFF)
82
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 {
165 __be32 vni;
166 u32 gbp;
167+ u32 gpe;
168 };
169
170 #define VNI_HASH_BITS 10
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
186index 4faa18f..7ef051c 100644
187--- a/datapath/linux/compat/vxlan.c
188+++ b/datapath/linux/compat/vxlan.c
189@@ -971,6 +971,18 @@ static int vxlan_udp_encap_recv(struct sock *sk, struct sk_buff *skb)
190 md->gbp |= VXLAN_GBP_POLICY_APPLIED;
191
192 flags &= ~VXLAN_GBP_USED_BITS;
193+ } else if ((flags & VXLAN_HF_GPE) && (vs->flags & VXLAN_F_GPE)) {
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 }
206
207 if (flags || vni & ~VXLAN_VNI_MASK) {
208@@ -1023,6 +1035,22 @@ static void vxlan_build_gbp_hdr(struct vxlanhdr *vxh, u32 vxflags,
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)
234 vxlan_build_gbp_hdr(vxh, vxflags, md);
235+ else if (vxflags & VXLAN_F_GPE)
236+ vxlan_build_gpe_hdr(vxh, vxflags, md);
237
238 ovs_skb_set_inner_protocol(skb, htons(ETH_P_TEB));
239
240diff --git a/datapath/vport-vxlan.c b/datapath/vport-vxlan.c
241index c05f5d4..5d775cc 100644
242--- a/datapath/vport-vxlan.c
243+++ b/datapath/vport-vxlan.c
244@@ -52,6 +52,18 @@ static int vxlan_get_options(const struct vport *vport, struct sk_buff *skb)
245 return -EMSGSIZE;
246
247 nla_nest_end(skb, exts);
248+ } else if (vxlan->flags & VXLAN_F_GPE) {
249+ struct nlattr *exts;
250+
251+ exts = nla_nest_start(skb, OVS_TUNNEL_ATTR_EXTENSION);
252+ if (!exts)
253+ return -EMSGSIZE;
254+
255+ if (vxlan->flags & VXLAN_F_GPE &&
256+ nla_put_flag(skb, OVS_VXLAN_EXT_GPE))
257+ return -EMSGSIZE;
258+
259+ nla_nest_end(skb, exts);
260 }
261
262 return 0;
263@@ -59,6 +71,7 @@ static int vxlan_get_options(const struct vport *vport, struct sk_buff *skb)
264
265 static const struct nla_policy exts_policy[OVS_VXLAN_EXT_MAX + 1] = {
266 [OVS_VXLAN_EXT_GBP] = { .type = NLA_FLAG, },
267+ [OVS_VXLAN_EXT_GPE] = { .type = NLA_FLAG, },
268 };
269
270 static int vxlan_configure_exts(struct vport *vport, struct nlattr *attr,
271@@ -76,6 +89,8 @@ static int vxlan_configure_exts(struct vport *vport, struct nlattr *attr,
272
273 if (exts[OVS_VXLAN_EXT_GBP])
274 conf->flags |= VXLAN_F_GBP;
275+ else if (exts[OVS_VXLAN_EXT_GPE])
276+ conf->flags |= VXLAN_F_GPE;
277
278 return 0;
279 }
280diff --git a/lib/flow.c b/lib/flow.c
281index b9ce331..d24bdc9 100644
282--- a/lib/flow.c
283+++ b/lib/flow.c
284@@ -870,6 +870,12 @@ flow_get_metadata(const struct flow *flow, struct match *flow_metadata)
285 if (flow->tunnel.gbp_flags) {
286 match_set_tun_gbp_flags(flow_metadata, flow->tunnel.gbp_flags);
287 }
288+ if (flow->tunnel.gpe_np != htons(0)) {
289+ match_set_tun_gpe_np(flow_metadata, flow->tunnel.gpe_np);
290+ }
291+ if (flow->tunnel.gpe_flags) {
292+ match_set_tun_gpe_flags(flow_metadata, flow->tunnel.gpe_flags);
293+ }
294 tun_metadata_get_fmd(&flow->tunnel, flow_metadata);
295 if (flow->metadata != htonll(0)) {
296 match_set_metadata(flow_metadata, flow->metadata);
297@@ -1265,6 +1271,8 @@ void flow_wildcards_init_for_packet(struct flow_wildcards *wc,
298 WC_MASK_FIELD(wc, tunnel.tp_dst);
299 WC_MASK_FIELD(wc, tunnel.gbp_id);
300 WC_MASK_FIELD(wc, tunnel.gbp_flags);
301+ WC_MASK_FIELD(wc, tunnel.gpe_np);
302+ WC_MASK_FIELD(wc, tunnel.gpe_flags);
303
304 if (!(flow->tunnel.flags & FLOW_TNL_F_UDPIF)) {
305 if (flow->tunnel.metadata.present.map) {
306diff --git a/lib/match.c b/lib/match.c
307index fd571d9..52437c9 100644
308--- a/lib/match.c
309+++ b/lib/match.c
310@@ -289,6 +289,32 @@ match_set_tun_gbp_flags(struct match *match, uint8_t flags)
311 }
312
313 void
314+match_set_tun_gpe_np_masked(struct match *match, uint8_t np, uint8_t mask)
315+{
316+ match->wc.masks.tunnel.gpe_np = mask;
317+ match->flow.tunnel.gpe_np = np & mask;
318+}
319+
320+void
321+match_set_tun_gpe_np(struct match *match, uint8_t np)
322+{
323+ match_set_tun_gpe_np_masked(match, np, UINT8_MAX);
324+}
325+
326+void
327+match_set_tun_gpe_flags_masked(struct match *match, uint8_t flags, uint8_t mask)
328+{
329+ match->wc.masks.tunnel.gpe_flags = mask;
330+ match->flow.tunnel.gpe_flags = flags & mask;
331+}
332+
333+void
334+match_set_tun_gpe_flags(struct match *match, uint8_t flags)
335+{
336+ match_set_tun_gpe_flags_masked(match, flags, UINT8_MAX);
337+}
338+
339+void
340 match_set_in_port(struct match *match, ofp_port_t ofp_port)
341 {
342 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)
344 ds_put_format(s, "tun_gbp_flags=%#"PRIx8",", tnl->gbp_flags);
345 }
346
347+ if (wc->masks.tunnel.gpe_np) {
348+ ds_put_format(s, "tun_gpe_np=%#"PRIx8",", tnl->gpe_np);
349+ }
350+
351+ if (wc->masks.tunnel.gpe_flags) {
352+ ds_put_format(s, "tun_gpe_flags=%#"PRIx8",", tnl->gpe_flags);
353+ }
354+
355 if (wc->masks.tunnel.ip_tos) {
356 ds_put_format(s, "tun_tos=%"PRIx8",", tnl->ip_tos);
357 }
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
374index 721152c..ab77fca 100644
375--- a/lib/meta-flow.c
376+++ b/lib/meta-flow.c
377@@ -213,6 +213,10 @@ mf_is_all_wild(const struct mf_field *mf, const struct flow_wildcards *wc)
378 return !wc->masks.tunnel.gbp_id;
379 case MFF_TUN_GBP_FLAGS:
380 return !wc->masks.tunnel.gbp_flags;
381+ case MFF_TUN_GPE_NP:
382+ return !wc->masks.tunnel.gpe_np;
383+ case MFF_TUN_GPE_FLAGS:
384+ return !wc->masks.tunnel.gpe_flags;
385 CASE_MFF_TUN_METADATA:
386 return !ULLONG_GET(wc->masks.tunnel.metadata.present.map,
387 mf->id - MFF_TUN_METADATA0);
388@@ -515,6 +519,8 @@ mf_is_value_valid(const struct mf_field *mf, const union mf_value *value)
389 case MFF_TUN_TTL:
390 case MFF_TUN_GBP_ID:
391 case MFF_TUN_GBP_FLAGS:
392+ case MFF_TUN_GPE_NP:
393+ case MFF_TUN_GPE_FLAGS:
394 CASE_MFF_TUN_METADATA:
395 case MFF_METADATA:
396 case MFF_IN_PORT:
397@@ -648,6 +654,12 @@ mf_get_value(const struct mf_field *mf, const struct flow *flow,
398 case MFF_TUN_GBP_FLAGS:
399 value->u8 = flow->tunnel.gbp_flags;
400 break;
401+ case MFF_TUN_GPE_NP:
402+ value->u8 = flow->tunnel.gpe_np;
403+ break;
404+ case MFF_TUN_GPE_FLAGS:
405+ value->u8 = flow->tunnel.gpe_flags;
406+ break;
407 case MFF_TUN_TTL:
408 value->u8 = flow->tunnel.ip_ttl;
409 break;
410@@ -899,6 +911,12 @@ mf_set_value(const struct mf_field *mf,
411 case MFF_TUN_GBP_FLAGS:
412 match_set_tun_gbp_flags(match, value->u8);
413 break;
414+ case MFF_TUN_GPE_NP:
415+ match_set_tun_gpe_np(match, value->u8);
416+ break;
417+ case MFF_TUN_GPE_FLAGS:
418+ match_set_tun_gpe_flags(match, value->u8);
419+ break;
420 case MFF_TUN_TOS:
421 match_set_tun_tos(match, value->u8);
422 break;
423@@ -1216,6 +1234,12 @@ mf_set_flow_value(const struct mf_field *mf,
424 case MFF_TUN_GBP_FLAGS:
425 flow->tunnel.gbp_flags = value->u8;
426 break;
427+ case MFF_TUN_GPE_NP:
428+ flow->tunnel.gpe_np= value->u8;
429+ break;
430+ case MFF_TUN_GPE_FLAGS:
431+ flow->tunnel.gpe_flags= value->u8;
432+ break;
433 case MFF_TUN_TOS:
434 flow->tunnel.ip_tos = value->u8;
435 break;
436@@ -1535,6 +1559,12 @@ mf_set_wild(const struct mf_field *mf, struct match *match, char **err_str)
437 case MFF_TUN_GBP_FLAGS:
438 match_set_tun_gbp_flags_masked(match, 0, 0);
439 break;
440+ case MFF_TUN_GPE_NP:
441+ match_set_tun_gpe_np_masked(match, 0, 0);
442+ break;
443+ case MFF_TUN_GPE_FLAGS:
444+ match_set_tun_gpe_flags_masked(match, 0, 0);
445+ break;
446 case MFF_TUN_TOS:
447 match_set_tun_tos_masked(match, 0, 0);
448 break;
449@@ -1838,6 +1868,12 @@ mf_set(const struct mf_field *mf,
450 case MFF_TUN_GBP_FLAGS:
451 match_set_tun_gbp_flags_masked(match, value->u8, mask->u8);
452 break;
453+ case MFF_TUN_GPE_NP:
454+ match_set_tun_gpe_np_masked(match, value->u8, mask->u8);
455+ break;
456+ case MFF_TUN_GPE_FLAGS:
457+ match_set_tun_gpe_flags_masked(match, value->u8, mask->u8);
458+ break;
459 case MFF_TUN_TTL:
460 match_set_tun_ttl_masked(match, value->u8, mask->u8);
461 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
502index e398562..92ceec1 100644
503--- a/lib/netdev-vport.c
504+++ b/lib/netdev-vport.c
505@@ -583,6 +583,8 @@ set_tunnel_config(struct netdev *dev_, const struct smap *args)
506 while (ext) {
507 if (!strcmp(type, "vxlan") && !strcmp(ext, "gbp")) {
508 tnl_cfg.exts |= (1 << OVS_VXLAN_EXT_GBP);
509+ } else if (!strcmp(type, "vxlan") && !strcmp(ext, "gpe")) {
510+ tnl_cfg.exts |= (1 << OVS_VXLAN_EXT_GPE);
511 } else {
512 VLOG_WARN("%s: unknown extension '%s'", name, ext);
513 }
514diff --git a/lib/nx-match.c b/lib/nx-match.c
515index 9f0f452..0eecac7 100644
516--- a/lib/nx-match.c
517+++ b/lib/nx-match.c
518@@ -1037,6 +1037,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);
520 nxm_put_8m(b, MFF_TUN_GBP_FLAGS, oxm,
521 flow->tunnel.gbp_flags, match->wc.masks.tunnel.gbp_flags);
522+ nxm_put_8m(b, MFF_TUN_GPE_NP, oxm,
523+ flow->tunnel.gpe_np, match->wc.masks.tunnel.gpe_np);
524+ nxm_put_8m(b, MFF_TUN_GPE_FLAGS, oxm,
525+ flow->tunnel.gpe_flags, match->wc.masks.tunnel.gpe_flags);
526 tun_metadata_to_nx_match(b, oxm, match);
527
528 /* Registers. */
529diff --git a/lib/odp-util.c b/lib/odp-util.c
530index b4689cc..7983720 100644
531--- a/lib/odp-util.c
532+++ b/lib/odp-util.c
533@@ -1727,6 +1727,7 @@ odp_actions_from_string(const char *s, const struct simap *port_names,
534
535 static const struct attr_len_tbl ovs_vxlan_ext_attr_lens[OVS_VXLAN_EXT_MAX + 1] = {
536 [OVS_VXLAN_EXT_GBP] = { .len = 4 },
537+ [OVS_VXLAN_EXT_GPE] = { .len = 4 },
538 };
539
540 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,
542 break;
543 case OVS_TUNNEL_KEY_ATTR_VXLAN_OPTS: {
544 static const struct nl_policy vxlan_opts_policy[] = {
545- [OVS_VXLAN_EXT_GBP] = { .type = NL_A_U32 },
546+ [OVS_VXLAN_EXT_GBP] = { .type = NL_A_U32 ,
547+ .optional = true },
548+ [OVS_VXLAN_EXT_GPE] = { .type = NL_A_U32 ,
549+ .optional = true },
550 };
551 struct nlattr *ext[ARRAY_SIZE(vxlan_opts_policy)];
552
553@@ -1902,6 +1906,12 @@ odp_tun_key_from_attr__(const struct nlattr *attr,
554 tun->gbp_id = htons(gbp & 0xFFFF);
555 tun->gbp_flags = (gbp >> 16) & 0xFF;
556 }
557+ if (ext[OVS_VXLAN_EXT_GPE]) {
558+ uint32_t gpe = nl_attr_get_u32(ext[OVS_VXLAN_EXT_GPE]);
559+
560+ tun->gpe_np = gpe & 0xFF;
561+ tun->gpe_flags = gpe >> 24;
562+ }
563
564 break;
565 }
566@@ -1988,6 +1998,13 @@ tun_key_to_attr(struct ofpbuf *a, const struct flow_tnl *tun_key,
567 nl_msg_put_u32(a, OVS_VXLAN_EXT_GBP,
568 (tun_key->gbp_flags << 16) | ntohs(tun_key->gbp_id));
569 nl_msg_end_nested(a, vxlan_opts_ofs);
570+ } else if (tun_key->gpe_flags || tun_key->gpe_np) {
571+ size_t vxlan_opts_ofs;
572+
573+ vxlan_opts_ofs = nl_msg_start_nested(a, OVS_TUNNEL_KEY_ATTR_VXLAN_OPTS);
574+ nl_msg_put_u32(a, OVS_VXLAN_EXT_GPE,
575+ (tun_key->gpe_flags << 24) | (tun_key->gpe_np));
576+ nl_msg_end_nested(a, vxlan_opts_ofs);
577 }
578 tun_metadata_to_geneve_nlattr(tun_key, tun_flow_key, key_buf, a);
579
580@@ -2383,6 +2400,26 @@ format_odp_tun_vxlan_opt(const struct nlattr *attr,
581 ds_put_cstr(ds, "),");
582 break;
583 }
584+ case OVS_VXLAN_EXT_GPE: {
585+ uint32_t key = nl_attr_get_u32(a);
586+ uint8_t np, np_mask;
587+ uint8_t flags, flags_mask;
588+
589+ np = key & 0xFF;
590+ flags = (key >> 24) & 0xFF;
591+ if (ma) {
592+ uint32_t mask = nl_attr_get_u32(ma);
593+ np_mask = mask & 0xFF;
594+ flags_mask = (mask >> 24) & 0xFF;
595+ }
596+
597+ ds_put_cstr(ds, "gpe(");
598+ format_u8x(ds, "np", np, ma ? &np_mask : NULL, verbose);
599+ format_u8x(ds, "flags", flags, ma ? &flags_mask : NULL, verbose);
600+ ds_chomp(ds, ',');
601+ ds_put_cstr(ds, "),");
602+ break;
603+ }
604
605 default:
606 format_unknown_key(ds, a, ma);
607@@ -3670,6 +3707,40 @@ scan_vxlan_gbp(const char *s, uint32_t *key, uint32_t *mask)
608 }
609
610 static int
611+scan_vxlan_gpe(const char *s, uint32_t *key, uint32_t *mask)
612+{
613+ const char *s_base = s;
614+ uint8_t np = 0, np_mask = 0;
615+ uint8_t flags = 0, flags_mask = 0;
616+
617+ if (!strncmp(s, "np=", 3)) {
618+ s += 3;
619+ s += scan_u8(s, &np, mask ? &np_mask : NULL);
620+ }
621+
622+ if (s[0] == ',') {
623+ s++;
624+ }
625+ if (!strncmp(s, "flags=", 6)) {
626+ s += 6;
627+ s += scan_u8(s, &flags, mask ? &flags_mask : NULL);
628+ }
629+
630+ if (!strncmp(s, "))", 2)) {
631+ s += 2;
632+
633+ *key = (flags << 24) | np;
634+ if (mask) {
635+ *mask = (flags_mask << 24) | np_mask;
636+ }
637+
638+ return s - s_base;
639+ }
640+
641+ return 0;
642+}
643+
644+static int
645 scan_geneve(const char *s, struct geneve_scan *key, struct geneve_scan *mask)
646 {
647 const char *s_base = s;
648@@ -3796,6 +3867,21 @@ vxlan_gbp_to_attr(struct ofpbuf *a, const void *data_)
649 }
650
651 static void
652+vxlan_gpe_to_attr(struct ofpbuf *a, const void *data_)
653+{
654+ const uint32_t *gpe = data_;
655+
656+ if (*gpe) {
657+ size_t vxlan_opts_ofs;
658+
659+ vxlan_opts_ofs = nl_msg_start_nested(a, OVS_TUNNEL_KEY_ATTR_VXLAN_OPTS);
660+ nl_msg_put_u32(a, OVS_VXLAN_EXT_GPE, *gpe);
661+ nl_msg_end_nested(a, vxlan_opts_ofs);
662+ }
663+}
664+
665+
666+static void
667 geneve_to_attr(struct ofpbuf *a, const void *data_)
668 {
669 const struct geneve_scan *geneve = data_;
670@@ -4031,6 +4117,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);
672 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);
674+ SCAN_FIELD_NESTED_FUNC("vxlan(gpe(", uint32_t, vxlan_gpe, vxlan_gpe_to_attr);
675 SCAN_FIELD_NESTED_FUNC("geneve(", struct geneve_scan, geneve,
676 geneve_to_attr);
677 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
694index fbb6d71..6c7217d 100644
695--- a/tests/ofproto.at
696+++ b/tests/ofproto.at
697@@ -1775,7 +1775,7 @@ head_table () {
698 instructions: meter,apply_actions,clear_actions,write_actions,write_metadata,goto_table
699 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
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
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
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
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
705 matching:
706@@ -1790,6 +1790,8 @@ metadata in_port in_port_oxm pkt_mark ct_mark ct_label reg0 reg1 reg2 reg3 reg4
707 tun_flags: arbitrary mask
708 tun_gbp_id: arbitrary mask
709 tun_gbp_flags: arbitrary mask
710+ tun_gpe_np: arbitrary mask
711+ tun_gpe_flags: arbitrary mask
712 tun_metadata0: arbitrary mask
713 tun_metadata1: arbitrary mask
714 tun_metadata2: arbitrary mask
715diff --git a/tests/ovs-ofctl.at b/tests/ovs-ofctl.at
716index f26f622..dde603d 100644
717--- a/tests/ovs-ofctl.at
718+++ b/tests/ovs-ofctl.at
719@@ -17,6 +17,10 @@ for test_case in \
720 'tun_gbp_id=0/0x1 NXM,OXM' \
721 'tun_gbp_flags=0 NXM,OXM' \
722 'tun_gbp_flags=0/0x1 NXM,OXM' \
723+ 'tun_gpe_np=0 NXM,OXM' \
724+ 'tun_gpe_np=0/0x1 NXM,OXM' \
725+ 'tun_gpe_flags=0 NXM,OXM' \
726+ 'tun_gpe_flags=0/0x1 NXM,OXM' \
727 'tun_metadata0=0 NXM,OXM' \
728 'tun_metadata0=0/0x1 NXM,OXM' \
729 'tun_metadata0 NXM,OXM' \
730--
7311.9.3
732
diff --git a/ovs_build/patches/0002-ovs-nsh-support-push-and-pop-actions-for-vxlan-gpe-a.patch b/ovs_build/patches/0002-ovs-nsh-support-push-and-pop-actions-for-vxlan-gpe-a.patch
new file mode 100644
index 0000000..3e9e3dc
--- /dev/null
+++ b/ovs_build/patches/0002-ovs-nsh-support-push-and-pop-actions-for-vxlan-gpe-a.patch
@@ -0,0 +1,2746 @@
1From bd251cb247ac44e4362215da826e9bf1d6c61f27 Mon Sep 17 00:00:00 2001
2From: Yi Yang <yi.y.yang@intel.com>
3Date: Wed, 13 Apr 2016 11:15:42 +0800
4Subject: [PATCH 2/5] ovs-nsh: support push and pop actions for vxlan-gpe and
5 Ethernet nsh
6
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>
11---
12 datapath/actions.c | 73 ++++
13 datapath/datapath.h | 2 +
14 datapath/flow.c | 107 ++++++
15 datapath/flow.h | 15 +
16 datapath/flow_netlink.c | 81 ++++-
17 datapath/linux/compat/include/linux/openvswitch.h | 174 +++++++++
18 datapath/linux/compat/include/net/vxlan.h | 5 +-
19 lib/dpif-netdev.c | 4 +
20 lib/dpif.c | 4 +
21 lib/flow.c | 19 +
22 lib/flow.h | 21 +-
23 lib/match.c | 190 ++++++++++
24 lib/match.h | 24 ++
25 lib/meta-flow.c | 256 ++++++++++++-
26 lib/meta-flow.h | 174 +++++++++
27 lib/netdev-vport.c | 10 +-
28 lib/nx-match.c | 19 +
29 lib/odp-execute.c | 10 +
30 lib/odp-util.c | 417 +++++++++++++++++++++-
31 lib/odp-util.h | 10 +-
32 lib/ofp-actions.c | 154 +++++++-
33 lib/ofp-actions.h | 6 +
34 ofproto/ofproto-dpif-sflow.c | 2 +
35 ofproto/ofproto-dpif-upcall.c | 19 +
36 ofproto/ofproto-dpif-xlate.c | 22 ++
37 tests/ofproto.at | 13 +-
38 tests/tunnel.at | 157 ++++++++
39 27 files changed, 1976 insertions(+), 12 deletions(-)
40
41diff --git a/datapath/actions.c b/datapath/actions.c
42index dcf8591..16fc58f 100644
43--- a/datapath/actions.c
44+++ b/datapath/actions.c
45@@ -252,6 +252,63 @@ static int push_vlan(struct sk_buff *skb, struct sw_flow_key *key,
46 ntohs(vlan->vlan_tci) & ~VLAN_TAG_PRESENT);
47 }
48
49+static int pop_nsh(struct sk_buff *skb, struct sw_flow_key *key)
50+{
51+ if (!pskb_may_pull(skb, NSH_M_TYPE1_LEN))
52+ return -ENOMEM;
53+ else
54+ __skb_pull(skb, NSH_M_TYPE1_LEN);
55+
56+ return 0;
57+}
58+
59+static int push_nsh(struct sk_buff *skb, struct sw_flow_key *key,
60+ const struct ovs_action_push_nsh *nsh)
61+{
62+
63+ if (nsh->nsh_mdtype == NSH_M_TYPE1) {
64+ if (skb_cow_head(skb, NSH_M_TYPE1_LEN) < 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;
93+
94+ skb_push(skb, ENCAP_ETH_PUSH_HEADER_SIZE);
95+ OVS_CB(skb)->encap_eth_header = skb->data;
96+ memcpy(OVS_CB(skb)->encap_eth_header, encap_eth->header, ENCAP_ETH_PUSH_HEADER_SIZE);
97+ }
98+ else {
99+ return -EINVAL;
100+ }
101+
102+ return 0;
103+}
104+
105+
106 /* 'src' is already properly masked. */
107 static void ether_addr_copy_masked(u8 *dst_, const u8 *src_, const u8 *mask_)
108 {
109@@ -1079,6 +1136,22 @@ static int do_execute_actions(struct datapath *dp, struct sk_buff *skb,
110 err = pop_vlan(skb, key);
111 break;
112
113+ case OVS_ACTION_ATTR_PUSH_NSH:
114+ err = push_nsh(skb, key, nla_data(a));
115+ break;
116+
117+ case OVS_ACTION_ATTR_POP_NSH:
118+ err = pop_nsh(skb, key);
119+ break;
120+
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:
130 err = execute_recirc(dp, skb, key, a, rem);
131 if (nla_is_last(a, rem)) {
132diff --git a/datapath/datapath.h b/datapath/datapath.h
133index ceb3372..b2d5fcd 100644
134--- a/datapath/datapath.h
135+++ b/datapath/datapath.h
136@@ -102,6 +102,8 @@ struct datapath {
137 struct ovs_skb_cb {
138 struct vport *input_vport;
139 u16 mru;
140+ struct nsh_hdr *nsh_header;
141+ struct encap_eth_hdr *encap_eth_header;
142 };
143 #define OVS_CB(skb) ((struct ovs_skb_cb *)(skb)->cb)
144
145diff --git a/datapath/flow.c b/datapath/flow.c
146index c97c9c9..67b2f1d 100644
147--- a/datapath/flow.c
148+++ b/datapath/flow.c
149@@ -44,6 +44,7 @@
150 #include <net/ipv6.h>
151 #include <net/mpls.h>
152 #include <net/ndisc.h>
153+#include <net/vxlan.h>
154
155 #include "datapath.h"
156 #include "conntrack.h"
157@@ -318,6 +319,32 @@ static int parse_vlan(struct sk_buff *skb, struct sw_flow_key *key)
158 return 0;
159 }
160
161+static int parse_nsh(struct sk_buff *skb, struct sw_flow_key *key){
162+ struct nsh_hdr *nsh_hdr = (struct nsh_hdr *)skb->data;
163+ OVS_CB(skb)->nsh_header = nsh_hdr;
164+ key->nsh.nsh_mdtype = nsh_hdr->base.mdtype;
165+ if (key->nsh.nsh_mdtype != NSH_M_TYPE1)
166+ return -EPERM;
167+ key->nsh.nsh_np = nsh_hdr->base.proto;
168+ key->nsh.nsi = nsh_hdr->base.svc_idx;
169+ key->nsh.nsp = nsh_hdr->base.path_hdr << 8;
170+ key->nsh.nshc1 = nsh_hdr->ctx.nshc1;
171+ key->nsh.nshc2 = nsh_hdr->ctx.nshc2;
172+ key->nsh.nshc3 = nsh_hdr->ctx.nshc3;
173+ key->nsh.nshc4 = nsh_hdr->ctx.nshc4;
174+ return 0;
175+}
176+
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)
188 {
189 struct llc_snap_hdr {
190@@ -457,6 +484,24 @@ static int key_extract(struct sk_buff *skb, struct sw_flow_key *key)
191 int error;
192 struct ethhdr *eth;
193
194+ /* Extract ethernet+nsh if ethernet type is 0x894F */
195+ eth = (struct ethhdr *)skb->data;
196+ 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)))
201+ return -EINVAL;
202+ if (key->nsh.nsh_mdtype == NSH_M_TYPE1 && key->nsh.nsh_np == NSH_P_ETHERNET) {
203+ __skb_pull(skb, NSH_M_TYPE1_LEN);
204+ } else {
205+ return -EINVAL;
206+ }
207+ } else {
208+ void *encap_eth_hdr = &(key->encap_eth);
209+ memset(encap_eth_hdr, 0, ENCAP_ETH_LEN);
210+ }
211+
212 /* Flags are always used as part of stats */
213 key->tp.flags = 0;
214
215@@ -676,11 +721,54 @@ static int key_extract(struct sk_buff *skb, struct sw_flow_key *key)
216 }
217 }
218 }
219+
220+ if (key->encap_eth.encap_eth_type == htons(ETH_P_NSH))
221+ __skb_push(skb, ENCAP_ETH_LEN + NSH_M_TYPE1_LEN);
222+
223+ return 0;
224+}
225+
226+static void ovs_key_nsh_init(struct sw_flow_key *key, __u16 len) {
227+ void *nsh_hdr = &(key->nsh);
228+ memset(nsh_hdr, 0, len);
229+}
230+
231+static int nsh_extract(struct sk_buff *skb, struct sw_flow_key *key) {
232+ int ret;
233+
234+ /* only support NSH MD tpye1 */
235+ if (unlikely(parse_nsh(skb, key)))
236+ return -EINVAL;
237+ if (key->nsh.nsh_mdtype == NSH_M_TYPE1) {
238+ __skb_pull(skb, NSH_M_TYPE1_LEN);
239+ if(key->nsh.nsh_np == NSH_P_ETHERNET)
240+ ret = key_extract(skb, key);
241+ else
242+ return -EINVAL;
243+ __skb_push(skb, NSH_M_TYPE1_LEN);
244+
245+ return ret;
246+ } else {
247+ ovs_key_nsh_init(key, NSH_M_TYPE1_LEN);
248+ }
249+
250 return 0;
251 }
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+
258+ if (md && (md->gpe & VXLAN_GPE_NP_MASK) == VXLAN_GPE_NP_NSH)
259+ return true;
260+ else
261+ return false;
262+}
263+
264 int ovs_flow_key_update(struct sk_buff *skb, struct sw_flow_key *key)
265 {
266+ ovs_key_nsh_init(key, NSH_M_TYPE1_LEN);
267 return key_extract(skb, key);
268 }
269
270@@ -715,6 +803,15 @@ int ovs_flow_key_extract(const struct ip_tunnel_info *tun_info,
271 key->ovs_flow_hash = 0;
272 key->recirc_id = 0;
273
274+ /* 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)) {
276+ int ret ;
277+ ret = nsh_extract(skb, key);
278+ if (key->nsh.nsh_mdtype)
279+ return ret;
280+ } else {
281+ ovs_key_nsh_init(key, NSH_M_TYPE1_LEN);
282+ }
283 return key_extract(skb, key);
284 }
285
286@@ -729,5 +826,15 @@ int ovs_flow_key_extract_userspace(struct net *net, const struct nlattr *attr,
287 if (err)
288 return err;
289
290+ /* Extract NSH and inner Ethernet if NSH header exists */
291+ if (key && is_nsh_header(key->tun_opts, key->tun_key.tun_flags)) {
292+ int ret ;
293+ ret = nsh_extract(skb, key);
294+ if (key->nsh.nsh_mdtype)
295+ return ret;
296+ } else {
297+ ovs_key_nsh_init(key, NSH_M_TYPE1_LEN);
298+ }
299+
300 return key_extract(skb, key);
301 }
302diff --git a/datapath/flow.h b/datapath/flow.h
303index c0b628a..c8ccd5f 100644
304--- a/datapath/flow.h
305+++ b/datapath/flow.h
306@@ -63,6 +63,21 @@ struct sw_flow_key {
307 u32 skb_mark; /* SKB mark. */
308 u16 in_port; /* Input switch port (or DP_MAX_PORTS). */
309 } __packed phy; /* Safe when right after 'tun_key'. */
310+ struct {
311+ u32 nshc1; /* NSH context C1-C4 */
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. */
326 u32 recirc_id; /* Recirculation ID. */
327 struct {
328diff --git a/datapath/flow_netlink.c b/datapath/flow_netlink.c
329index 351a504..ebfae37 100644
330--- a/datapath/flow_netlink.c
331+++ b/datapath/flow_netlink.c
332@@ -284,7 +284,7 @@ size_t ovs_key_attr_size(void)
333 /* Whenever adding new OVS_KEY_ FIELDS, we should consider
334 * updating this function.
335 */
336- BUILD_BUG_ON(OVS_KEY_ATTR_TUNNEL_INFO != 26);
337+ BUILD_BUG_ON(OVS_KEY_ATTR_TUNNEL_INFO != 28);
338
339 return nla_total_size(4) /* OVS_KEY_ATTR_PRIORITY */
340 + nla_total_size(0) /* OVS_KEY_ATTR_TUNNEL */
341@@ -297,6 +297,8 @@ size_t ovs_key_attr_size(void)
342 + nla_total_size(2) /* OVS_KEY_ATTR_CT_ZONE */
343 + nla_total_size(4) /* OVS_KEY_ATTR_CT_MARK */
344 + nla_total_size(16) /* OVS_KEY_ATTR_CT_LABELS */
345+ + nla_total_size(24) /* OVS_KEY_ATTR_NSH */
346+ + nla_total_size(14) /* OVS_KEY_ATTR_ENCAP_ETH */
347 + nla_total_size(12) /* OVS_KEY_ATTR_ETHERNET */
348 + nla_total_size(2) /* OVS_KEY_ATTR_ETHERTYPE */
349 + 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] = {
351 [OVS_KEY_ATTR_PRIORITY] = { .len = sizeof(u32) },
352 [OVS_KEY_ATTR_IN_PORT] = { .len = sizeof(u32) },
353 [OVS_KEY_ATTR_SKB_MARK] = { .len = sizeof(u32) },
354+ [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) },
357 [OVS_KEY_ATTR_VLAN] = { .len = sizeof(__be16) },
358 [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,
360 if (err)
361 return err;
362
363+ if (attrs & (1ULL << OVS_KEY_ATTR_NSH)) {
364+ const struct ovs_key_nsh *nsh_key;
365+
366+ nsh_key = nla_data(a[OVS_KEY_ATTR_NSH]);
367+ SW_FLOW_KEY_PUT(match, nsh.nshc1,
368+ nsh_key->nshc1, is_mask);
369+ SW_FLOW_KEY_PUT(match, nsh.nshc2,
370+ nsh_key->nshc2, is_mask);
371+ SW_FLOW_KEY_PUT(match, nsh.nshc3,
372+ nsh_key->nshc3, is_mask);
373+ SW_FLOW_KEY_PUT(match, nsh.nshc4,
374+ nsh_key->nshc4, is_mask);
375+ SW_FLOW_KEY_PUT(match, nsh.nsh_mdtype,
376+ nsh_key->nsh_mdtype, is_mask);
377+ SW_FLOW_KEY_PUT(match, nsh.nsh_np,
378+ nsh_key->nsh_np, is_mask);
379+ SW_FLOW_KEY_PUT(match, nsh.nsp,
380+ nsh_key->nsp, is_mask);
381+ SW_FLOW_KEY_PUT(match, nsh.nsi,
382+ nsh_key->nsi, is_mask);
383+ attrs &= ~(1ULL << OVS_KEY_ATTR_NSH);
384+ }
385+
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)) {
400 const struct ovs_key_ethernet *eth_key;
401
402@@ -1386,6 +1426,35 @@ 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))
404 goto nla_put_failure;
405
406+ if ((swkey->nsh.nsh_mdtype || is_mask)) {
407+ struct ovs_key_nsh *nsh_key;
408+
409+ nla = nla_reserve(skb, OVS_KEY_ATTR_NSH, sizeof(*nsh_key));
410+ if (!nla)
411+ goto nla_put_failure;
412+ nsh_key = nla_data(nla);
413+ nsh_key->nsi = output->nsh.nsi;
414+ nsh_key->nsp = output->nsh.nsp;
415+ nsh_key->nsh_mdtype= output->nsh.nsh_mdtype;
416+ nsh_key->nsh_np= output->nsh.nsh_np;
417+ nsh_key->nshc1= output->nsh.nshc1;
418+ nsh_key->nshc2 = output->nsh.nshc2;
419+ nsh_key->nshc3 = output->nsh.nshc3;
420+ nsh_key->nshc4 = output->nsh.nshc4;
421+ }
422+
423+ if ((swkey->encap_eth.encap_eth_type || 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;
437
438@@ -2182,6 +2251,10 @@ static int __ovs_nla_copy_actions(struct net *net, const struct nlattr *attr,
439 [OVS_ACTION_ATTR_POP_MPLS] = sizeof(__be16),
440 [OVS_ACTION_ATTR_PUSH_VLAN] = sizeof(struct ovs_action_push_vlan),
441 [OVS_ACTION_ATTR_POP_VLAN] = 0,
442+ [OVS_ACTION_ATTR_PUSH_NSH] = sizeof(struct ovs_action_push_nsh),
443+ [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,
447 [OVS_ACTION_ATTR_SET_MASKED] = (u32)-1,
448 [OVS_ACTION_ATTR_SAMPLE] = (u32)-1,
449@@ -2226,6 +2299,12 @@ static int __ovs_nla_copy_actions(struct net *net, const struct nlattr *attr,
450 break;
451 }
452
453+ case OVS_ACTION_ATTR_PUSH_NSH:
454+ case OVS_ACTION_ATTR_POP_NSH:
455+ case OVS_ACTION_ATTR_PUSH_ETH:
456+ case OVS_ACTION_ATTR_POP_ETH:
457+ break;
458+
459 case OVS_ACTION_ATTR_POP_VLAN:
460 vlan_tci = htons(0);
461 break;
462diff --git a/datapath/linux/compat/include/linux/openvswitch.h b/datapath/linux/compat/include/linux/openvswitch.h
463index 44adb81..187bb9b 100644
464--- a/datapath/linux/compat/include/linux/openvswitch.h
465+++ b/datapath/linux/compat/include/linux/openvswitch.h
466@@ -42,6 +42,7 @@
467
468 #include <linux/types.h>
469 #include <linux/if_ether.h>
470+#include <asm/byteorder.h>
471
472 /**
473 * struct ovs_header - header for OVS Generic Netlink messages.
474@@ -328,6 +329,9 @@ enum ovs_key_attr {
475 OVS_KEY_ATTR_ENCAP, /* Nested set of encapsulated attributes. */
476 OVS_KEY_ATTR_PRIORITY, /* u32 skb->priority */
477 OVS_KEY_ATTR_IN_PORT, /* u32 OVS dp port number */
478+ OVS_KEY_ATTR_NSH, /* struct ovs_key_nsh. Only support NSH MD
479+ type 1 now */
480+ OVS_KEY_ATTR_ENCAP_ETH, /* struct ovs_key_encap_eth */
481 OVS_KEY_ATTR_ETHERNET, /* struct ovs_key_ethernet */
482 OVS_KEY_ATTR_VLAN, /* be16 VLAN TCI */
483 OVS_KEY_ATTR_ETHERTYPE, /* be16 Ethernet type */
484@@ -401,6 +405,24 @@ enum ovs_frag_type {
485
486 #define OVS_FRAG_TYPE_MAX (__OVS_FRAG_TYPE_MAX - 1)
487
488+struct ovs_key_nsh {
489+ __u32 nshc1;
490+ __u32 nshc2;
491+ __u32 nshc3;
492+ __u32 nshc4;
493+ __u32 nsp;
494+ __u8 nsi;
495+ __u8 nsh_mdtype;
496+ __u8 nsh_np;
497+ __u8 reserved;
498+};
499+
500+struct ovs_key_encap_eth {
501+ __u8 encap_eth_src[ETH_ALEN];
502+ __u8 encap_eth_dst[ETH_ALEN];
503+ __u16 encap_eth_type;
504+};
505+
506 struct ovs_key_ethernet {
507 __u8 eth_src[ETH_ALEN];
508 __u8 eth_dst[ETH_ALEN];
509@@ -630,6 +652,154 @@ struct ovs_action_push_vlan {
510 __be16 vlan_tci; /* 802.1Q TCI (VLAN ID and priority). */
511 };
512
513+/*
514+ * Network Service Header:
515+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
516+ * |Ver|O|C|R|R|R|R|R|R| Length | MD Type | Next Proto |
517+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
518+ * | Service Path ID | Service Index |
519+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
520+ * Ver = The version field is used to ensure backward compatibility
521+ * going forward with future NSH updates. It MUST be set to 0x0
522+ * by the sender, in this first revision of NSH.
523+ *
524+ * O = OAM. when set to 0x1 indicates that this packet is an operations
525+ * and management (OAM) packet. The receiving SFF and SFs nodes
526+ * MUST examine the payload and take appropriate action.
527+ *
528+ * C = context. Indicates that a critical metadata TLV is present.
529+ *
530+ * Length : total length, in 4-byte words, of NSH including the Base
531+ * Header, the Service Path Header and the optional variable
532+ * TLVs.
533+ * MD Type: indicates the format of NSH beyond the mandatory Base Header
534+ * and the Service Path Header.
535+ *
536+ * Next Protocol: indicates the protocol type of the original packet. A
537+ * new IANA registry will be created for protocol type.
538+ *
539+ * Service Path Identifier (SPI): identifies a service path.
540+ * Participating nodes MUST use this identifier for Service
541+ * Function Path selection.
542+ *
543+ * Service Index (SI): provides location within the SFP.
544+ *
545+ * [0] https://tools.ietf.org/html/draft-ietf-sfc-nsh-01
546+ */
547+
548+struct nsh_base {
549+#if defined(__LITTLE_ENDIAN_BITFIELD)
550+
551+ __u8 reserved_flags1:4;
552+ __u8 context_flag:1;
553+ __u8 oam_flag:1;
554+ __u8 version:2;
555+
556+ __u8 length:6;
557+ __u8 reserved_flags2:2;
558+#elif defined(__BIG_ENDIAN_BITFIELD)
559+
560+ __u8 version:2;
561+ __u8 oam_flag:1;
562+ __u8 context_flag:1;
563+ __u8 reserved_flags1:4;
564+
565+ __u8 reserved_flags2:2;
566+ __u8 length:6;
567+#else
568+#error "Bitfield Endianess not defined."
569+#endif
570+ __u8 mdtype;
571+ __u8 proto;
572+ union {
573+ struct {
574+ __u8 svc_path[3];
575+ __u8 svc_idx;
576+ };
577+ __be32 path_hdr;
578+ };
579+};
580+
581+
582+/**
583+ * struct nsh_ctx - Keeps track of NSH context data
584+ * @c<1-4>: NSH Contexts.
585+ */
586+struct nsh_ctx {
587+ __be32 nshc1;
588+ __be32 nshc2;
589+ __be32 nshc3;
590+ __be32 nshc4;
591+};
592+
593+/**
594+ * struct nshdr - Network Service header
595+ * @nsh_base: Network Service Base Header.
596+ * @nsh_ctx: Network Service Context Header.
597+ */
598+struct nsh_hdr {
599+ struct nsh_base base;
600+ struct nsh_ctx ctx;
601+};
602+
603+
604+#define ETH_P_NSH 0x894F /* Ethertype for NSH */
605+
606+/* NSH Base Header Next Protocol */
607+#define NSH_P_IPV4 0x01
608+#define NSH_P_IPV6 0x02
609+#define NSH_P_ETHERNET 0x03
610+
611+/* MD Type Registry */
612+#define NSH_M_TYPE1 0x01
613+#define NSH_M_EXP1 0xFE
614+#define NSH_M_EXP2 0xFF
615+
616+#define NSH_DST_PORT 4790 /* UDP Port for NSH on VXLAN */
617+
618+#define NSH_M_TYPE1_LEN 24
619+
620+/* Used for masking nsp and nsi values in field nsp below */
621+#define NSH_M_NSP 0x00FFFFFF
622+#define NSH_M_NSI 0xFF000000
623+
624+/* NSH header for MD type 1. Unit is bytes */
625+#define NSH_PUSH_TYPE1_HEADER_SIZE 24
626+#define NSH_PUSH_HEADER_SIZE 256
627+
628+#define ENCAP_ETH_LEN 14
629+
630+/**
631+ * struct encap_eth - encap ethernet header for ethernet NSH
632+ * @encap_eth_src: encap ethernet source address.
633+ * @encap_eth_src: encap ethernet destination address.
634+ * @encap_eth_type: encap ethernet type.
635+ */
636+struct encap_eth_hdr {
637+ __u8 encap_eth_dst[ETH_ALEN];
638+ __u8 encap_eth_src[ETH_ALEN];
639+ __u16 encap_eth_type;
640+};
641+
642+#define ENCAP_ETH_PUSH_HEADER_SIZE 14
643+/**
644+ * struct ovs_action_push_nsh - %OVS_ACTION_ATTR_PUSH_NSH action argument.
645+ * @header
646+ */
647+struct ovs_action_push_nsh {
648+ uint8_t nsh_mdtype;
649+ uint8_t header[NSH_PUSH_HEADER_SIZE];
650+};
651+
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.
662 *
663 * The algorithm type only specifies the fields in a flow
664@@ -793,6 +963,10 @@ enum ovs_action_attr {
665 OVS_ACTION_ATTR_SET, /* One nested OVS_KEY_ATTR_*. */
666 OVS_ACTION_ATTR_PUSH_VLAN, /* struct ovs_action_push_vlan. */
667 OVS_ACTION_ATTR_POP_VLAN, /* No argument. */
668+ OVS_ACTION_ATTR_PUSH_NSH, /* struct ovs_action_push_nsh. */
669+ 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_*. */
673 OVS_ACTION_ATTR_RECIRC, /* u32 recirc_id. */
674 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
676index 2bfc3f8..3aeac88 100644
677--- a/datapath/linux/compat/include/net/vxlan.h
678+++ b/datapath/linux/compat/include/net/vxlan.h
679@@ -85,7 +85,7 @@ struct vxlanhdr_gbp {
680 #define VXLAN_GBP_ID_MASK (0xFFFF)
681
682 /*
683- * VXLAN Generic Protocol Extension Extension:
684+ * VXLAN Generic Protocol Extension:
685 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
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 |
687 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
688@@ -103,6 +103,9 @@ struct vxlanhdr_gbp {
689 * O = OAM Flag Bit. The O bit is set to indicate that the packet
690 * is an OAM packet.
691 *
692+ * Next Protocol = This 8 bit field indicates the protocol header
693+ * immediately following the VXLAN GPE header.
694+ *
695 * [1] https://www.ietf.org/id/draft-ietf-nvo3-vxlan-gpe-01.txt
696 */
697
698diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c
699index 119dc2d..8e67bfd 100644
700--- a/lib/dpif-netdev.c
701+++ b/lib/dpif-netdev.c
702@@ -3874,6 +3874,10 @@ dp_execute_cb(void *aux_, struct dp_packet **packets, int cnt,
703 VLOG_WARN("Cannot execute conntrack action in userspace.");
704 break;
705
706+ case OVS_ACTION_ATTR_PUSH_NSH:
707+ 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:
711 case OVS_ACTION_ATTR_POP_VLAN:
712 case OVS_ACTION_ATTR_PUSH_MPLS:
713diff --git a/lib/dpif.c b/lib/dpif.c
714index a784de7..b5265c4 100644
715--- a/lib/dpif.c
716+++ b/lib/dpif.c
717@@ -1139,6 +1139,10 @@ dpif_execute_helper_cb(void *aux_, struct dp_packet **packets, int cnt,
718 }
719
720 case OVS_ACTION_ATTR_HASH:
721+ case OVS_ACTION_ATTR_PUSH_NSH:
722+ 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:
726 case OVS_ACTION_ATTR_POP_VLAN:
727 case OVS_ACTION_ATTR_PUSH_MPLS:
728diff --git a/lib/flow.c b/lib/flow.c
729index d24bdc9..fc8b98c 100644
730--- a/lib/flow.c
731+++ b/lib/flow.c
732@@ -1289,6 +1289,25 @@ void flow_wildcards_init_for_packet(struct flow_wildcards *wc,
733 WC_MASK_FIELD(wc, tunnel.tun_id);
734 }
735
736+ /* NSH fields wildcarded */
737+ if (flow->nsh_mdtype) {
738+ WC_MASK_FIELD(wc, nshc1);
739+ WC_MASK_FIELD(wc, nshc2);
740+ WC_MASK_FIELD(wc, nshc3);
741+ WC_MASK_FIELD(wc, nshc4);
742+ WC_MASK_FIELD(wc, nsh_mdtype);
743+ WC_MASK_FIELD(wc, nsh_np);
744+ WC_MASK_FIELD(wc, nsp);
745+ WC_MASK_FIELD(wc, nsi);
746+ }
747+
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. */
756
757 WC_MASK_FIELD(wc, skb_priority);
758diff --git a/lib/flow.h b/lib/flow.h
759index dc7130d..a8677b1 100644
760--- a/lib/flow.h
761+++ b/lib/flow.h
762@@ -111,6 +111,23 @@ struct flow {
763 ofp_port_t actset_output; /* Output port in action set. */
764 uint8_t pad2[2]; /* Pad to 64 bits. */
765
766+ /* NSH (64-bit aligned) */
767+ ovs_be32 nshc1;
768+ ovs_be32 nshc2;
769+ ovs_be32 nshc3;
770+ ovs_be32 nshc4;
771+ ovs_be32 nsp;
772+ uint8_t nsi;
773+ uint8_t nsh_mdtype;
774+ uint8_t nsh_np;
775+ uint8_t pad3;
776+
777+ /* ENCAP_ETH (64-bit aligned) */
778+ struct eth_addr encap_eth_src; /* Encap ethernet source address. */
779+ struct eth_addr encap_eth_dst; /* Encap ethernet destination address. */
780+ ovs_be16 encap_eth_type; /* Encap ethernet frame type. */
781+ uint8_t pad4[2];
782+
783 /* L2, Order the same as in the Ethernet header! (64-bit aligned) */
784 struct eth_addr dl_dst; /* Ethernet destination address. */
785 struct eth_addr dl_src; /* Ethernet source address. */
786@@ -132,7 +149,7 @@ struct flow {
787 struct eth_addr arp_sha; /* ARP/ND source hardware address. */
788 struct eth_addr arp_tha; /* ARP/ND target hardware address. */
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
805index 52437c9..3db2a2b 100644
806--- a/lib/match.c
807+++ b/lib/match.c
808@@ -862,6 +862,152 @@ match_set_nd_target_masked(struct match *match,
809 match->wc.masks.nd_target = *mask;
810 }
811
812+void
813+match_set_nsp_masked(struct match *match, ovs_be32 nsp, ovs_be32 mask)
814+{
815+ match->wc.masks.nsp = mask;
816+ match->flow.nsp = nsp & mask;
817+}
818+
819+void
820+match_set_nsi_masked(struct match *match, uint8_t nsi, uint8_t mask)
821+{
822+ match->wc.masks.nsi = mask;
823+ match->flow.nsi = nsi & mask;
824+}
825+
826+void
827+match_set_nsh_mdtype_masked(struct match *match, uint8_t nsh_mdtype, uint8_t mask)
828+{
829+ match->wc.masks.nsh_mdtype = mask;
830+ match->flow.nsh_mdtype = nsh_mdtype & mask;
831+}
832+
833+void
834+match_set_nsh_np_masked(struct match *match, uint8_t nsh_np, uint8_t mask)
835+{
836+ match->wc.masks.nsh_np = mask;
837+ match->flow.nsh_np = nsh_np & mask;
838+}
839+
840+void
841+match_set_encap_eth_src_masked(struct match *match,
842+ const struct eth_addr encap_eth_src,
843+ const struct eth_addr mask)
844+{
845+ set_eth_masked(encap_eth_src, mask, &match->flow.encap_eth_src, &match->wc.masks.encap_eth_src);
846+}
847+
848+void
849+match_set_encap_eth_dst_masked(struct match *match,
850+ const struct eth_addr encap_eth_dst,
851+ const struct eth_addr mask)
852+{
853+ set_eth_masked(encap_eth_dst, mask, &match->flow.encap_eth_dst, &match->wc.masks.encap_eth_dst);
854+}
855+
856+void
857+match_set_encap_eth_type_masked(struct match *match, ovs_be16 encap_eth_type, ovs_be16 mask)
858+{
859+ match->wc.masks.encap_eth_type = mask;
860+ match->flow.encap_eth_type = encap_eth_type & mask;
861+}
862+
863+void
864+match_set_nshc1_masked(struct match *match, ovs_be32 nshc1, ovs_be32 mask)
865+{
866+ match->wc.masks.nshc1 = mask;
867+ match->flow.nshc1 = nshc1 & mask;
868+}
869+
870+void
871+match_set_nshc2_masked(struct match *match, ovs_be32 nshc2, ovs_be32 mask)
872+{
873+ match->wc.masks.nshc2 = mask;
874+ match->flow.nshc2 = nshc2 & mask;
875+}
876+
877+void
878+match_set_nshc3_masked(struct match *match, ovs_be32 nshc3, ovs_be32 mask)
879+{
880+ match->wc.masks.nshc3 = mask;
881+ match->flow.nshc3 = nshc3 & mask;
882+}
883+
884+void
885+match_set_nshc4_masked(struct match *match, ovs_be32 nshc4, ovs_be32 mask)
886+{
887+ match->wc.masks.nshc4 = mask;
888+ match->flow.nshc4 = nshc4 & mask;
889+}
890+
891+void
892+match_set_nsp(struct match *match, ovs_be32 nsp)
893+{
894+ match_set_nsp_masked(match, nsp, OVS_BE32_MAX);
895+}
896+
897+void
898+match_set_nsi(struct match *match, uint8_t nsi)
899+{
900+ match_set_nsi_masked(match, nsi, UINT8_MAX);
901+}
902+
903+void
904+match_set_nsh_mdtype(struct match *match, uint8_t nsh_mdtype)
905+{
906+ match_set_nsh_mdtype_masked(match, nsh_mdtype, UINT8_MAX);
907+}
908+
909+void
910+match_set_nsh_np(struct match *match, uint8_t nsh_np)
911+{
912+ match_set_nsh_np_masked(match, nsh_np, UINT8_MAX);
913+}
914+
915+void
916+match_set_nshc1(struct match *match, ovs_be32 nshc1)
917+{
918+ match_set_nshc1_masked(match, nshc1, OVS_BE32_MAX);
919+}
920+
921+void
922+match_set_nshc2(struct match *match, ovs_be32 nshc2)
923+{
924+ match_set_nshc2_masked(match, nshc2, OVS_BE32_MAX);
925+}
926+
927+void
928+match_set_nshc3(struct match *match, ovs_be32 nshc3)
929+{
930+ match_set_nshc3_masked(match, nshc3, OVS_BE32_MAX);
931+}
932+
933+void
934+match_set_nshc4(struct match *match, ovs_be32 nshc4)
935+{
936+ match_set_nshc4_masked(match, nshc4, OVS_BE32_MAX);
937+}
938+
939+void
940+match_set_encap_eth_src(struct match *match, const struct eth_addr encap_eth_src)
941+{
942+ set_eth(encap_eth_src, &match->flow.encap_eth_src, &match->wc.masks.encap_eth_src);
943+}
944+
945+void
946+match_set_encap_eth_dst(struct match *match, const struct eth_addr encap_eth_dst)
947+{
948+ set_eth(encap_eth_dst, &match->flow.encap_eth_dst, &match->wc.masks.encap_eth_dst);
949+}
950+
951+void
952+match_set_encap_eth_type(struct match *match, uint16_t encap_eth_type)
953+{
954+ match_set_encap_eth_type_masked(match, encap_eth_type, UINT16_MAX);
955+}
956+
957+
958 /* Returns true if 'a' and 'b' wildcard the same fields and have the same
959 * values for fixed fields, otherwise false. */
960 bool
961@@ -1155,6 +1301,50 @@ match_format(const struct match *match, struct ds *s, int priority)
962 format_ct_label_masked(s, &f->ct_label, &wc->masks.ct_label);
963 }
964
965+ if (wc->masks.nsi) {
966+ ds_put_format(s, "nsi=%"PRIu8",", f->nsi);
967+ }
968+
969+ if (wc->masks.nsh_mdtype) {
970+ ds_put_format(s, "nsh_mdtype=%"PRIu8",", f->nsh_mdtype);
971+ }
972+
973+ if (wc->masks.nsh_np) {
974+ ds_put_format(s, "nsh_np=%"PRIu8",", f->nsh_np);
975+ }
976+
977+ if (wc->masks.nsp) {
978+ format_be32_masked(s, "nsp", f->nsp,
979+ wc->masks.nsp);
980+ }
981+
982+ if (wc->masks.nshc1) {
983+ format_be32_masked(s, "nshc1", f->nshc1,
984+ wc->masks.nshc1);
985+ }
986+
987+ if (wc->masks.nshc2) {
988+ format_be32_masked(s, "nshc2", f->nshc2,
989+ wc->masks.nshc2);
990+ }
991+
992+ if (wc->masks.nshc3) {
993+ format_be32_masked(s, "nshc3", f->nshc3,
994+ wc->masks.nshc3);
995+ }
996+
997+ if (wc->masks.nshc4) {
998+ format_be32_masked(s, "nshc4", f->nshc4,
999+ wc->masks.nshc4);
1000+ }
1001+
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);
1007+ format_eth_masked(s, "encap_eth_dst", f->encap_eth_dst, wc->masks.encap_eth_dst);
1008+
1009 if (wc->masks.dl_type) {
1010 skip_type = true;
1011 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
1048index ab77fca..648a753 100644
1049--- a/lib/meta-flow.c
1050+++ b/lib/meta-flow.c
1051@@ -243,7 +243,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);
1053 case MFF_ACTSET_OUTPUT:
1054 return !wc->masks.actset_output;
1055-
1056+ case MFF_NSP:
1057+ return !wc->masks.nsp;
1058+ case MFF_NSI:
1059+ return !wc->masks.nsi;
1060+ case MFF_NSH_C1:
1061+ return !wc->masks.nshc1;
1062+ case MFF_NSH_C2:
1063+ return !wc->masks.nshc2;
1064+ case MFF_NSH_C3:
1065+ return !wc->masks.nshc3;
1066+ case MFF_NSH_C4:
1067+ return !wc->masks.nshc4;
1068+ case MFF_NSH_MDTYPE:
1069+ return !wc->masks.nsh_mdtype;
1070+ case MFF_NSH_NP:
1071+ return !wc->masks.nsh_np;
1072+ case MFF_ENCAP_ETH_SRC:
1073+ return eth_addr_is_zero(wc->masks.encap_eth_src);
1074+ case MFF_ENCAP_ETH_DST:
1075+ return eth_addr_is_zero(wc->masks.encap_eth_dst);
1076+ case MFF_ENCAP_ETH_TYPE:
1077+ return !wc->masks.encap_eth_type;
1078 case MFF_ETH_SRC:
1079 return eth_addr_is_zero(wc->masks.dl_src);
1080 case MFF_ETH_DST:
1081@@ -557,6 +578,17 @@ mf_is_value_valid(const struct mf_field *mf, const union mf_value *value)
1082 case MFF_ICMPV6_TYPE:
1083 case MFF_ICMPV6_CODE:
1084 case MFF_ND_TARGET:
1085+ case MFF_NSP:
1086+ case MFF_NSI:
1087+ case MFF_NSH_MDTYPE:
1088+ case MFF_NSH_NP:
1089+ case MFF_NSH_C1:
1090+ case MFF_NSH_C2:
1091+ case MFF_NSH_C3:
1092+ case MFF_NSH_C4:
1093+ case MFF_ENCAP_ETH_SRC:
1094+ case MFF_ENCAP_ETH_DST:
1095+ case MFF_ENCAP_ETH_TYPE:
1096 case MFF_ND_SLL:
1097 case MFF_ND_TLL:
1098 return true;
1099@@ -716,6 +748,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));
1101 break;
1102
1103+ case MFF_NSP:
1104+ value->be32 = flow->nsp;
1105+ break;
1106+
1107+ case MFF_NSI:
1108+ value->u8 = flow->nsi;
1109+ break;
1110+
1111+ case MFF_NSH_C1:
1112+ value->be32 = flow->nshc1;
1113+ break;
1114+
1115+ case MFF_NSH_C2:
1116+ value->be32 = flow->nshc2;
1117+ break;
1118+
1119+ case MFF_NSH_C3:
1120+ value->be32 = flow->nshc3;
1121+ break;
1122+
1123+ case MFF_NSH_C4:
1124+ value->be32 = flow->nshc4;
1125+ break;
1126+
1127+ case MFF_NSH_MDTYPE:
1128+ value->u8 = flow->nsh_mdtype;
1129+ break;
1130+
1131+ case MFF_NSH_NP:
1132+ value->u8 = flow->nsh_np;
1133+ break;
1134+
1135+ case MFF_ENCAP_ETH_SRC:
1136+ value->mac = flow->encap_eth_src;
1137+ break;
1138+
1139+ case MFF_ENCAP_ETH_DST:
1140+ value->mac = flow->encap_eth_dst;
1141+ break;
1142+
1143+ case MFF_ENCAP_ETH_TYPE:
1144+ value->be16 = flow->encap_eth_type;
1145+ break;
1146+
1147 case MFF_ETH_SRC:
1148 value->mac = flow->dl_src;
1149 break;
1150@@ -1085,6 +1161,50 @@ mf_set_value(const struct mf_field *mf,
1151 match_set_arp_sha(match, value->mac);
1152 break;
1153
1154+ case MFF_NSP:
1155+ match_set_nsp(match, value->be32);
1156+ break;
1157+
1158+ case MFF_NSI:
1159+ match_set_nsi(match, value->u8);
1160+ break;
1161+
1162+ case MFF_NSH_MDTYPE:
1163+ match_set_nsh_mdtype(match, value->u8);
1164+ break;
1165+
1166+ case MFF_NSH_NP:
1167+ match_set_nsh_np(match, value->u8);
1168+ break;
1169+
1170+ case MFF_NSH_C1:
1171+ match_set_nshc1(match, value->be32);
1172+ break;
1173+
1174+ case MFF_NSH_C2:
1175+ match_set_nshc2(match, value->be32);
1176+ break;
1177+
1178+ case MFF_NSH_C3:
1179+ match_set_nshc3(match, value->be32);
1180+ break;
1181+
1182+ case MFF_NSH_C4:
1183+ match_set_nshc4(match, value->be32);
1184+ break;
1185+
1186+ case MFF_ENCAP_ETH_SRC:
1187+ match_set_encap_eth_src(match, value->mac);
1188+ break;
1189+
1190+ case MFF_ENCAP_ETH_DST:
1191+ match_set_encap_eth_dst(match, value->mac);
1192+ break;
1193+
1194+ case MFF_ENCAP_ETH_TYPE:
1195+ match_set_encap_eth_type(match, value->be16);
1196+ break;
1197+
1198 case MFF_ARP_THA:
1199 case MFF_ND_TLL:
1200 match_set_arp_tha(match, value->mac);
1201@@ -1296,6 +1416,50 @@ mf_set_flow_value(const struct mf_field *mf,
1202 flow_set_xreg(flow, mf->id - MFF_XREG0, ntohll(value->be64));
1203 break;
1204
1205+ case MFF_NSP:
1206+ flow->nsp = value->be32;
1207+ break;
1208+
1209+ case MFF_NSI:
1210+ flow->nsi = value->u8;
1211+ break;
1212+
1213+ case MFF_NSH_C1:
1214+ flow->nshc1 = value->be32;
1215+ break;
1216+
1217+ case MFF_NSH_C2:
1218+ flow->nshc2 = value->be32;
1219+ break;
1220+
1221+ case MFF_NSH_C3:
1222+ flow->nshc3 = value->be32;
1223+ break;
1224+
1225+ case MFF_NSH_C4:
1226+ flow->nshc4 = value->be32;
1227+ break;
1228+
1229+ case MFF_NSH_MDTYPE:
1230+ flow->nsh_mdtype = value->u8;
1231+ break;
1232+
1233+ case MFF_NSH_NP:
1234+ flow->nsh_np = value->u8;
1235+ break;
1236+
1237+ case MFF_ENCAP_ETH_SRC:
1238+ flow->encap_eth_src = value->mac;
1239+ break;
1240+
1241+ case MFF_ENCAP_ETH_DST:
1242+ flow->encap_eth_dst = value->mac;
1243+ break;
1244+
1245+ case MFF_ENCAP_ETH_TYPE:
1246+ flow->encap_eth_type = value->be16;
1247+ break;
1248+
1249 case MFF_ETH_SRC:
1250 flow->dl_src = value->mac;
1251 break;
1252@@ -1734,6 +1898,52 @@ mf_set_wild(const struct mf_field *mf, struct match *match, char **err_str)
1253 match->wc.masks.arp_sha = eth_addr_zero;
1254 break;
1255
1256+ case MFF_NSP:
1257+ match_set_nsp_masked(match, htonl(0), htonl(0));
1258+ break;
1259+
1260+ case MFF_NSI:
1261+ match_set_nsi_masked(match, 0, 0);
1262+ break;
1263+
1264+ case MFF_NSH_MDTYPE:
1265+ match_set_nsh_mdtype_masked(match, 0, 0);
1266+ break;
1267+
1268+ case MFF_NSH_NP:
1269+ match_set_nsh_np_masked(match, 0, 0);
1270+ break;
1271+
1272+ case MFF_NSH_C1:
1273+ match_set_nshc1_masked(match, htonl(0), htonl(0));
1274+ break;
1275+
1276+ case MFF_NSH_C2:
1277+ match_set_nshc2_masked(match, htonl(0), htonl(0));
1278+ break;
1279+
1280+ case MFF_NSH_C3:
1281+ match_set_nshc3_masked(match, htonl(0), htonl(0));
1282+ break;
1283+
1284+ case MFF_NSH_C4:
1285+ match_set_nshc4_masked(match, htonl(0), htonl(0));
1286+ break;
1287+
1288+ case MFF_ENCAP_ETH_SRC:
1289+ match->flow.encap_eth_src= eth_addr_zero;
1290+ match->wc.masks.encap_eth_src = eth_addr_zero;
1291+ break;
1292+
1293+ case MFF_ENCAP_ETH_DST:
1294+ match->flow.encap_eth_dst= eth_addr_zero;
1295+ match->wc.masks.encap_eth_dst = eth_addr_zero;
1296+ break;
1297+
1298+ case MFF_ENCAP_ETH_TYPE:
1299+ match_set_encap_eth_type_masked(match, htons(0), htons(0));
1300+ break;
1301+
1302 case MFF_ARP_THA:
1303 case MFF_ND_TLL:
1304 match->flow.arp_tha = eth_addr_zero;
1305@@ -1929,6 +2139,50 @@ mf_set(const struct mf_field *mf,
1306 match_set_arp_sha_masked(match, value->mac, mask->mac);
1307 break;
1308
1309+ case MFF_NSP:
1310+ match_set_nsp_masked(match, value->be32, mask->be32);
1311+ break;
1312+
1313+ case MFF_NSI:
1314+ match_set_nsi_masked(match, value->u8, mask->u8);
1315+ break;
1316+
1317+ case MFF_NSH_MDTYPE:
1318+ match_set_nsh_mdtype_masked(match, value->u8, mask->u8);
1319+ break;
1320+
1321+ case MFF_NSH_NP:
1322+ match_set_nsh_np_masked(match, value->u8, mask->u8);
1323+ break;
1324+
1325+ case MFF_NSH_C1:
1326+ match_set_nshc1_masked(match, value->be32, mask->be32);
1327+ break;
1328+
1329+ case MFF_NSH_C2:
1330+ match_set_nshc2_masked(match, value->be32, mask->be32);
1331+ break;
1332+
1333+ case MFF_NSH_C3:
1334+ match_set_nshc3_masked(match, value->be32, mask->be32);
1335+ break;
1336+
1337+ case MFF_NSH_C4:
1338+ match_set_nshc4_masked(match, value->be32, mask->be32);
1339+ break;
1340+
1341+ case MFF_ENCAP_ETH_SRC:
1342+ match_set_encap_eth_src_masked(match, value->mac, mask->mac);
1343+ break;
1344+
1345+ case MFF_ENCAP_ETH_DST:
1346+ match_set_encap_eth_dst_masked(match, value->mac, mask->mac);
1347+ break;
1348+
1349+ case MFF_ENCAP_ETH_TYPE:
1350+ match_set_encap_eth_type_masked(match, value->be16, mask->be16);
1351+ break;
1352+
1353 case MFF_ARP_THA:
1354 case MFF_ND_TLL:
1355 match_set_arp_tha_masked(match, value->mac, mask->mac);
1356diff --git a/lib/meta-flow.h b/lib/meta-flow.h
1357index 4bd9ff6..a226b79 100644
1358--- a/lib/meta-flow.h
1359+++ b/lib/meta-flow.h
1360@@ -1747,6 +1747,180 @@ enum OVS_PACKED_ENUM mf_field_id {
1361 */
1362 MFF_ND_TLL,
1363
1364+ /* "nsp".
1365+ *
1366+ * For a packet received including a (32-bit)
1367+ * network service header service path (nsp), the nsp is stored
1368+ * in the low 24-bits and the high bits are zeroed. For
1369+ * other packets, the value is 0.
1370+ *
1371+ * Type: be32.
1372+ * Maskable: bitwise.
1373+ * Formatting: hexadecimal.
1374+ * Prerequisites: none.
1375+ * Access: read/write.
1376+ * NXM: NXM_NX_NSP(113) since v1.1.
1377+ * OXM: none.
1378+ * Prefix lookup member: nsp.
1379+ */
1380+ MFF_NSP,
1381+
1382+ /* "nsi".
1383+ *
1384+ * For a packet received, it includes a (8-bit)
1385+ * network service header service index (nsi).
1386+ *
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+
1466+ /* "nsh_mdtype".
1467+ *
1468+ * For a packet received, it includes a (8-bit)
1469+ * nsh md-type field (md-type).
1470+ *
1471+ * Type: u8.
1472+ * Maskable: bitwise.
1473+ * Formatting: decimal.
1474+ * Prerequisites: none.
1475+ * Access: read/write.
1476+ * NXM: NXM_NX_NSH_MDTYPE(119) since v1.1.
1477+ * OXM: none.
1478+ */
1479+ MFF_NSH_MDTYPE,
1480+
1481+ /* "nsh_np".
1482+ *
1483+ * For a packet received, it includes a (8-bit)
1484+ * nsh next protocol field (np).
1485+ *
1486+ * Type: u8.
1487+ * Maskable: bitwise.
1488+ * Formatting: decimal.
1489+ * Prerequisites: none.
1490+ * Access: read/write.
1491+ * NXM: NXM_NX_NSH_NP(120) since v1.1.
1492+ * OXM: none.
1493+ */
1494+ MFF_NSH_NP,
1495+
1496+ /* "encap_eth_src".
1497+ *
1498+ * encap eth source address for Ethernet+NSH
1499+ *
1500+ * Type: MAC.
1501+ * Maskable: bitwise.
1502+ * Formatting: Ethernet.
1503+ * Prerequisites: none.
1504+ * Access: read/write.
1505+ * NXM: NXM_NX_ENCAP_ETH_SRC(121) since v1.1.
1506+ * OXM: none.
1507+ */
1508+ MFF_ENCAP_ETH_SRC,
1509+
1510+ /* "encap_eth_dst".
1511+ *
1512+ * encap eth destination address for Ethernet+NSH
1513+ *
1514+ * Type: MAC.
1515+ * Maskable: bitwise.
1516+ * Formatting: Ethernet.
1517+ * Prerequisites: none.
1518+ * Access: read/write.
1519+ * NXM: NXM_NX_ENCAP_ETH_DST(122) since v1.1.
1520+ * OXM: none.
1521+ */
1522+ MFF_ENCAP_ETH_DST,
1523+
1524+ /* "encap_eth_type".
1525+ *
1526+ * Encap Ethernet type.
1527+ *
1528+ * Type: be16.
1529+ * Maskable: no.
1530+ * Formatting: hexadecimal.
1531+ * Prerequisites: none.
1532+ * Access: read/write.
1533+ * NXM: NXM_NX_ENCAP_ETH_TYPE(123) since v1.1.
1534+ * OXM: none.
1535+ */
1536+ MFF_ENCAP_ETH_TYPE,
1537+
1538 MFF_N_IDS
1539 };
1540
1541diff --git a/lib/netdev-vport.c b/lib/netdev-vport.c
1542index 92ceec1..406a492 100644
1543--- a/lib/netdev-vport.c
1544+++ b/lib/netdev-vport.c
1545@@ -582,9 +582,15 @@ set_tunnel_config(struct netdev *dev_, const struct smap *args)
1546 ext = strtok_r(str, ",", &save_ptr);
1547 while (ext) {
1548 if (!strcmp(type, "vxlan") && !strcmp(ext, "gbp")) {
1549- tnl_cfg.exts |= (1 << OVS_VXLAN_EXT_GBP);
1550+ if (tnl_cfg.exts & (1 << OVS_VXLAN_EXT_GPE))
1551+ VLOG_WARN("VXLAN_GPE extension exists, VxLAN_GBP extension can't be added.");
1552+ else
1553+ tnl_cfg.exts |= (1 << OVS_VXLAN_EXT_GBP);
1554 } else if (!strcmp(type, "vxlan") && !strcmp(ext, "gpe")) {
1555- tnl_cfg.exts |= (1 << OVS_VXLAN_EXT_GPE);
1556+ if (tnl_cfg.exts & (1 << OVS_VXLAN_EXT_GBP))
1557+ VLOG_WARN("VXLAN_GBP extension exists, VxLAN_GPE extension can't be added.");
1558+ else
1559+ tnl_cfg.exts |= (1 << OVS_VXLAN_EXT_GPE);
1560 } else {
1561 VLOG_WARN("%s: unknown extension '%s'", name, ext);
1562 }
1563diff --git a/lib/nx-match.c b/lib/nx-match.c
1564index 0eecac7..8d2bc4b 100644
1565--- a/lib/nx-match.c
1566+++ b/lib/nx-match.c
1567@@ -949,6 +949,25 @@ nx_put_raw(struct ofpbuf *b, enum ofp_version oxm, const struct match *match,
1568 ofputil_port_to_ofp11(flow->actset_output));
1569 }
1570
1571+ /* NSH */
1572+ nxm_put_32m(b, MFF_NSP, oxm, flow->nsp, match->wc.masks.nsp);
1573+ nxm_put_8m(b, MFF_NSI, oxm, flow->nsi, match->wc.masks.nsi);
1574+ nxm_put_8m(b, MFF_NSH_MDTYPE, oxm, flow->nsh_mdtype, match->wc.masks.nsh_mdtype);
1575+ nxm_put_8m(b, MFF_NSH_NP, oxm, flow->nsh_np, match->wc.masks.nsh_np);
1576+ nxm_put_32m(b, MFF_NSH_C1, oxm, flow->nshc1, match->wc.masks.nshc1);
1577+ nxm_put_32m(b, MFF_NSH_C2, oxm, flow->nshc2, match->wc.masks.nshc2);
1578+ nxm_put_32m(b, MFF_NSH_C3, oxm, flow->nshc3, match->wc.masks.nshc3);
1579+ nxm_put_32m(b, MFF_NSH_C4, oxm, flow->nshc4, match->wc.masks.nshc4);
1580+
1581+ /* ENCAP Eth */
1582+ nxm_put_eth_masked(b, MFF_ENCAP_ETH_SRC, oxm,
1583+ flow->encap_eth_src, match->wc.masks.encap_eth_src);
1584+ nxm_put_eth_masked(b, MFF_ENCAP_ETH_DST, oxm,
1585+ flow->encap_eth_dst, match->wc.masks.encap_eth_dst);
1586+ nxm_put_16m(b, MFF_ENCAP_ETH_TYPE, oxm,
1587+ ofputil_dl_type_to_openflow(flow->encap_eth_type),
1588+ match->wc.masks.encap_eth_type); //uncertain
1589+
1590 /* Ethernet. */
1591 nxm_put_eth_masked(b, MFF_ETH_SRC, oxm,
1592 flow->dl_src, match->wc.masks.dl_src);
1593diff --git a/lib/odp-execute.c b/lib/odp-execute.c
1594index b5204b2..b6dcd98 100644
1595--- a/lib/odp-execute.c
1596+++ b/lib/odp-execute.c
1597@@ -434,6 +434,8 @@ odp_execute_masked_set_action(struct dp_packet *packet,
1598 case OVS_KEY_ATTR_ETHERTYPE:
1599 case OVS_KEY_ATTR_IN_PORT:
1600 case OVS_KEY_ATTR_VLAN:
1601+ case OVS_KEY_ATTR_NSH:
1602+ case OVS_KEY_ATTR_ENCAP_ETH:
1603 case OVS_KEY_ATTR_ICMP:
1604 case OVS_KEY_ATTR_ICMPV6:
1605 case OVS_KEY_ATTR_TCP_FLAGS:
1606@@ -497,6 +499,10 @@ requires_datapath_assistance(const struct nlattr *a)
1607
1608 case OVS_ACTION_ATTR_SET:
1609 case OVS_ACTION_ATTR_SET_MASKED:
1610+ case OVS_ACTION_ATTR_PUSH_NSH:
1611+ case OVS_ACTION_ATTR_POP_NSH:
1612+ case OVS_ACTION_ATTR_PUSH_ETH:
1613+ case OVS_ACTION_ATTR_POP_ETH:
1614 case OVS_ACTION_ATTR_PUSH_VLAN:
1615 case OVS_ACTION_ATTR_POP_VLAN:
1616 case OVS_ACTION_ATTR_SAMPLE:
1617@@ -623,6 +629,10 @@ odp_execute_actions(void *dp, struct dp_packet **packets, int cnt, bool steal,
1618 }
1619 break;
1620
1621+ case OVS_ACTION_ATTR_PUSH_NSH:
1622+ case OVS_ACTION_ATTR_POP_NSH:
1623+ case OVS_ACTION_ATTR_PUSH_ETH:
1624+ case OVS_ACTION_ATTR_POP_ETH:
1625 case OVS_ACTION_ATTR_OUTPUT:
1626 case OVS_ACTION_ATTR_TUNNEL_PUSH:
1627 case OVS_ACTION_ATTR_TUNNEL_POP:
1628diff --git a/lib/odp-util.c b/lib/odp-util.c
1629index 7983720..102dfd7 100644
1630--- a/lib/odp-util.c
1631+++ b/lib/odp-util.c
1632@@ -70,7 +70,8 @@ static void format_odp_key_attr(const struct nlattr *a,
1633 const struct nlattr *ma,
1634 const struct hmap *portno_names, struct ds *ds,
1635 bool verbose);
1636-
1637+static void format_eth(struct ds *ds, const char *name, const struct eth_addr key,
1638+ const struct eth_addr *mask, bool verbose);
1639 struct geneve_scan {
1640 struct geneve_opt d[63];
1641 int len;
1642@@ -112,6 +113,10 @@ odp_action_len(uint16_t type)
1643 case OVS_ACTION_ATTR_USERSPACE: return ATTR_LEN_VARIABLE;
1644 case OVS_ACTION_ATTR_PUSH_VLAN: return sizeof(struct ovs_action_push_vlan);
1645 case OVS_ACTION_ATTR_POP_VLAN: return 0;
1646+ case OVS_ACTION_ATTR_PUSH_NSH: return sizeof(struct ovs_action_push_nsh);
1647+ case OVS_ACTION_ATTR_POP_NSH: return 0;
1648+ case OVS_ACTION_ATTR_PUSH_ETH: return sizeof(struct ovs_action_push_eth);
1649+ case OVS_ACTION_ATTR_POP_ETH: return 0;
1650 case OVS_ACTION_ATTR_PUSH_MPLS: return sizeof(struct ovs_action_push_mpls);
1651 case OVS_ACTION_ATTR_POP_MPLS: return sizeof(ovs_be16);
1652 case OVS_ACTION_ATTR_RECIRC: return sizeof(uint32_t);
1653@@ -147,6 +152,8 @@ ovs_key_attr_to_string(enum ovs_key_attr attr, char *namebuf, size_t bufsize)
1654 case OVS_KEY_ATTR_CT_LABELS: return "ct_label";
1655 case OVS_KEY_ATTR_TUNNEL: return "tunnel";
1656 case OVS_KEY_ATTR_IN_PORT: return "in_port";
1657+ case OVS_KEY_ATTR_ENCAP_ETH: return "encap_eth";
1658+ case OVS_KEY_ATTR_NSH: return "nsh";
1659 case OVS_KEY_ATTR_ETHERNET: return "eth";
1660 case OVS_KEY_ATTR_VLAN: return "vlan";
1661 case OVS_KEY_ATTR_ETHERTYPE: return "eth_type";
1662@@ -373,6 +380,36 @@ format_vlan_tci(struct ds *ds, ovs_be16 tci, ovs_be16 mask, bool verbose)
1663 }
1664
1665 static void
1666+format_nsh(struct ds *ds, const struct ovs_action_push_nsh * nsh)
1667+{
1668+ const struct nsh_hdr *nsh_hdr =(struct nsh_hdr *)nsh->header;
1669+ ds_put_format(ds, "nsh_mdtype=%"PRIu8",nsh_np=%"PRIu8",nsp=%"PRIu32
1670+ ",nsi=%"PRIu8",nshc1=%"PRIu32",nshc2=%"PRIu32
1671+ ",nshc3=%"PRIu32",nshc4=%"PRIu32")",
1672+ nsh_hdr->base.mdtype,
1673+ nsh_hdr->base.proto,
1674+ ntohl(nsh_hdr->base.path_hdr << 8),
1675+ ntohl(nsh_hdr->base.path_hdr >> 24),
1676+ ntohl(nsh_hdr->ctx.nshc1),
1677+ ntohl(nsh_hdr->ctx.nshc2),
1678+ ntohl(nsh_hdr->ctx.nshc3),
1679+ ntohl(nsh_hdr->ctx.nshc4));
1680+}
1681+
1682+static void
1683+format_encap_eth(struct ds *ds, const struct ovs_action_push_eth *encap_eth)
1684+{
1685+ const struct encap_eth_hdr *encap_eth_hdr = (struct encap_eth_hdr *)encap_eth->header;
1686+ ds_put_format(ds, "encap_eth_type=%"PRIu16",",
1687+ ntohs(encap_eth_hdr->encap_eth_type));
1688+ format_eth(ds, "encap_eth_src", encap_eth_hdr->encap_eth_src,
1689+ NULL, true);
1690+ format_eth(ds, "encap_eth_dst", encap_eth_hdr->encap_eth_dst,
1691+ NULL, true);
1692+ ds_put_format(ds, ")");
1693+}
1694+
1695+static void
1696 format_mpls_lse(struct ds *ds, ovs_be32 mpls_lse)
1697 {
1698 ds_put_format(ds, "label=%"PRIu32",tc=%d,ttl=%d,bos=%d",
1699@@ -500,7 +537,7 @@ format_odp_tnl_push_header(struct ds *ds, struct ovs_action_push_tnl *data)
1700 gnh->oam ? "oam," : "",
1701 gnh->critical ? "crit," : "",
1702 ntohl(get_16aligned_be32(&gnh->vni)) >> 8);
1703-
1704+
1705 if (gnh->opt_len) {
1706 ds_put_cstr(ds, ",options(");
1707 format_geneve_opts(gnh->options, NULL, gnh->opt_len * 4,
1708@@ -760,6 +797,8 @@ format_odp_action(struct ds *ds, const struct nlattr *a)
1709 {
1710 int expected_len;
1711 enum ovs_action_attr type = nl_attr_type(a);
1712+ const struct ovs_action_push_nsh *nsh;
1713+ const struct ovs_action_push_eth *encap_eth;
1714 size_t size;
1715
1716 expected_len = odp_action_len(nl_attr_type(a));
1717@@ -830,6 +869,23 @@ format_odp_action(struct ds *ds, const struct nlattr *a)
1718 case OVS_ACTION_ATTR_POP_VLAN:
1719 ds_put_cstr(ds, "pop_vlan");
1720 break;
1721+ case OVS_ACTION_ATTR_PUSH_NSH:
1722+ nsh = nl_attr_get(a);
1723+ ds_put_cstr(ds, "push_nsh(");
1724+ format_nsh(ds, nsh);
1725+ break;
1726+ case OVS_ACTION_ATTR_POP_NSH:
1727+ ds_put_cstr(ds, "pop_nsh");
1728+ break;
1729+
1730+ case OVS_ACTION_ATTR_PUSH_ETH:
1731+ encap_eth = nl_attr_get(a);
1732+ ds_put_cstr(ds, "push_eth(");
1733+ format_encap_eth(ds, encap_eth);
1734+ break;
1735+ case OVS_ACTION_ATTR_POP_ETH:
1736+ ds_put_cstr(ds, "pop_eth");
1737+ break;
1738 case OVS_ACTION_ATTR_PUSH_MPLS: {
1739 const struct ovs_action_push_mpls *mpls = nl_attr_get(a);
1740 ds_put_cstr(ds, "push_mpls(");
1741@@ -1618,6 +1674,72 @@ parse_odp_action(const char *s, const struct simap *port_names,
1742 }
1743
1744 {
1745+ struct ovs_action_push_nsh push;
1746+ struct nsh_hdr *nsh = (struct nsh_hdr *)push.header;
1747+ ovs_be32 nsp, nshc1,nshc2,nshc3,nshc4;
1748+ uint8_t nsi, nsh_mdtype, nsh_np;
1749+ int n = -1;
1750+
1751+ if (ovs_scan_len(s, &n, "push_nsh(nsh_mdtype=%"SCNi8",nsh_np=%"SCNi8",nsp=0x%"SCNx32
1752+ ",nsi=%"SCNi8",nshc1=0x%"SCNx32",nshc2=0x%"SCNx32
1753+ ",nshc3=0x%"SCNx32",nshc4=0x%"SCNx32"))",
1754+ &nsh_mdtype, &nsh_np,
1755+ &nsp, &nsi,
1756+ &nshc1, &nshc2,
1757+ &nshc3, &nshc4)) {
1758+ if (nsh_mdtype == NSH_M_TYPE1) {
1759+ nsh->base.mdtype = NSH_M_TYPE1;
1760+ nsh->base.version = 0x01;
1761+ nsh->base.length = 6;
1762+ nsh->base.proto = nsh_np;
1763+ nsh->base.path_hdr= nsp;
1764+ nsh->base.svc_idx = nsi;
1765+ nsh->ctx.nshc1=nshc1;
1766+ nsh->ctx.nshc2=nshc2;
1767+ nsh->ctx.nshc3=nshc3;
1768+ nsh->ctx.nshc4=nshc4;
1769+ push.nsh_mdtype = NSH_M_TYPE1;
1770+ nl_msg_put_unspec(actions, OVS_ACTION_ATTR_PUSH_NSH,
1771+ &push, sizeof push);
1772+ }
1773+
1774+ return n;
1775+ }
1776+ }
1777+
1778+ if (!strncmp(s, "pop_nsh", 7)) {
1779+ nl_msg_put_flag(actions, OVS_ACTION_ATTR_POP_NSH);
1780+ return 7;
1781+ }
1782+
1783+ {
1784+ struct ovs_action_push_eth push;
1785+ struct encap_eth_hdr *encap_eth = (struct encap_eth_hdr *)push.header;
1786+ uint16_t encap_eth_type;
1787+ int n = -1;
1788+
1789+ if (ovs_scan_len(s, &n, "push_eth(encap_eth_type=0x%"SCNx16",encap_eth_dst="ETH_ADDR_SCAN_FMT",encap_eth_src="ETH_ADDR_SCAN_FMT")",
1790+ &encap_eth_type,
1791+ ETH_ADDR_SCAN_ARGS(encap_eth->encap_eth_dst),
1792+ ETH_ADDR_SCAN_ARGS(encap_eth->encap_eth_src))) {
1793+ if (encap_eth->encap_eth_type == ETH_P_NSH) {
1794+ push.encap_eth_type = ETH_P_NSH;
1795+ encap_eth->encap_eth_type = htons(ETH_P_NSH);
1796+ nl_msg_put_unspec(actions, OVS_ACTION_ATTR_PUSH_ETH,
1797+ &push, sizeof push);
1798+ }
1799+
1800+ return n;
1801+ }
1802+
1803+ }
1804+
1805+ if (!strncmp(s, "pop_eth", 7)) {
1806+ nl_msg_put_flag(actions, OVS_ACTION_ATTR_POP_ETH);
1807+ return 7;
1808+ }
1809+
1810+ {
1811 double percentage;
1812 int n = -1;
1813
1814@@ -1759,6 +1881,8 @@ static const struct attr_len_tbl ovs_flow_key_attr_lens[OVS_KEY_ATTR_MAX + 1] =
1815 .next = ovs_tun_key_attr_lens,
1816 .next_max = OVS_TUNNEL_KEY_ATTR_MAX },
1817 [OVS_KEY_ATTR_IN_PORT] = { .len = 4 },
1818+ [OVS_KEY_ATTR_ENCAP_ETH] = { .len = 14 },
1819+ [OVS_KEY_ATTR_NSH] = { .len = 24 },
1820 [OVS_KEY_ATTR_ETHERNET] = { .len = sizeof(struct ovs_key_ethernet) },
1821 [OVS_KEY_ATTR_VLAN] = { .len = 2 },
1822 [OVS_KEY_ATTR_ETHERTYPE] = { .len = 2 },
1823@@ -2146,6 +2270,23 @@ format_be64(struct ds *ds, const char *name, ovs_be64 key,
1824 }
1825
1826 static void
1827+format_be32(struct ds *ds, const char *name, ovs_be32 key,
1828+ const ovs_be32 *mask, bool verbose)
1829+{
1830+ bool mask_empty = mask && !*mask;
1831+
1832+ if (verbose || !mask_empty) {
1833+ bool mask_full = !mask || *mask == OVS_BE32_MAX;
1834+
1835+ ds_put_format(ds, "%s=%"PRIx32, name, ntohl(key));
1836+ if (!mask_full) { /* Partially masked. */
1837+ ds_put_format(ds, "/%#"PRIx32, ntohl(*mask));
1838+ }
1839+ ds_put_char(ds, ',');
1840+ }
1841+}
1842+
1843+static void
1844 format_ipv4(struct ds *ds, const char *name, ovs_be32 key,
1845 const ovs_be32 *mask, bool verbose)
1846 {
1847@@ -2798,6 +2939,34 @@ format_odp_key_attr(const struct nlattr *a, const struct nlattr *ma,
1848 }
1849 break;
1850
1851+ case OVS_KEY_ATTR_NSH: {
1852+ const struct ovs_key_nsh *mask = ma ? nl_attr_get(ma) : NULL;
1853+ const struct ovs_key_nsh *key = nl_attr_get(a);
1854+
1855+ format_u8u(ds, "nsi", key->nsi, MASK(mask, nsi), verbose);
1856+ format_be32(ds, "nsp", key->nsp, MASK(mask, nsp), verbose);
1857+ format_u8u(ds, "nsh_mdtype", key->nsh_mdtype, MASK(mask, nsh_mdtype), verbose);
1858+ format_u8u(ds, "nsh_np", key->nsh_np, MASK(mask, nsh_np), verbose);
1859+ format_be32(ds, "nshc1", key->nshc1, MASK(mask, nshc1), verbose);
1860+ format_be32(ds, "nshc2", key->nshc2, MASK(mask, nshc2), verbose);
1861+ format_be32(ds, "nshc3", key->nshc3, MASK(mask, nshc3), verbose);
1862+ format_be32(ds, "nshc4", key->nshc4, MASK(mask, nshc4), verbose);
1863+ ds_chomp(ds, ',');
1864+ break;
1865+ }
1866+
1867+ case OVS_KEY_ATTR_ENCAP_ETH: {
1868+ const struct ovs_key_encap_eth *mask = ma ? nl_attr_get(ma) : NULL;
1869+ const struct ovs_key_encap_eth *key = nl_attr_get(a);
1870+
1871+ format_be16(ds, "encap_eth_type", key->encap_eth_type, MASK(mask, encap_eth_type), verbose);
1872+ format_eth(ds, "encap_eth_src", key->encap_eth_src, MASK(mask, encap_eth_src), verbose);
1873+ format_eth(ds, "encap_eth_dst", key->encap_eth_dst, MASK(mask, encap_eth_dst), verbose);
1874+ ds_chomp(ds, ',');
1875+
1876+ break;
1877+ }
1878+
1879 case OVS_KEY_ATTR_ETHERNET: {
1880 const struct ovs_key_ethernet *mask = ma ? nl_attr_get(ma) : NULL;
1881 const struct ovs_key_ethernet *key = nl_attr_get(a);
1882@@ -3184,6 +3353,48 @@ scan_eth(const char *s, struct eth_addr *key, struct eth_addr *mask)
1883 }
1884
1885 static int
1886+scan_nsp(const char *s, uint32_t *key, uint32_t *mask)
1887+{
1888+ int n;
1889+
1890+ if (ovs_scan(s, "%"SCNi32"%n", key, &n)) {
1891+ int len = n;
1892+ *key = htonl(*key);
1893+ if (mask) {
1894+ if (ovs_scan(s + len, "/%"SCNi32"%n", mask, &n)) {
1895+ len += n;
1896+ *mask =htonl(*mask);
1897+ } else {
1898+ *mask = UINT32_MAX;
1899+ }
1900+ }
1901+ return len;
1902+ }
1903+ return 0;
1904+}
1905+
1906+static int
1907+scan_encap_eth_type(const char *s, uint16_t *key, uint16_t *mask)
1908+{
1909+ int n;
1910+
1911+ if (ovs_scan(s, "%"SCNi16"%n", key, &n)) {
1912+ int len = n;
1913+ *key = htons(*key);
1914+ if (mask) {
1915+ if (ovs_scan(s + len, "/%"SCNi16"%n", mask, &n)) {
1916+ len += n;
1917+ *mask = htons(*mask);
1918+ } else {
1919+ *mask = UINT16_MAX;
1920+ }
1921+ }
1922+ return len;
1923+ }
1924+ return 0;
1925+}
1926+
1927+static int
1928 scan_ipv4(const char *s, ovs_be32 *key, ovs_be32 *mask)
1929 {
1930 int n;
1931@@ -4123,6 +4334,23 @@ parse_odp_key_mask_attr(const char *s, const struct simap *port_names,
1932 SCAN_FIELD_NESTED_FUNC("flags(", uint16_t, tun_flags, tun_flags_to_attr);
1933 } SCAN_END_NESTED();
1934
1935+ SCAN_BEGIN("nsh(", struct ovs_key_nsh) {
1936+ SCAN_FIELD("nsh_mdtype=", u8, nsh_mdtype);
1937+ SCAN_FIELD("nsh_np=", u8, nsh_np);
1938+ SCAN_FIELD("nsp=", nsp, nsp);
1939+ SCAN_FIELD("nsi=", u8, nsi);
1940+ SCAN_FIELD("nshc1=", u32, nshc1);
1941+ SCAN_FIELD("nshc2=", u32, nshc2);
1942+ SCAN_FIELD("nshc3=", u32, nshc3);
1943+ SCAN_FIELD("nshc4=", u32, nshc4);
1944+ } SCAN_END(OVS_KEY_ATTR_NSH);
1945+
1946+ SCAN_BEGIN("encap_eth(", struct ovs_key_encap_eth) {
1947+ SCAN_FIELD("encap_eth_src=", eth, encap_eth_src);
1948+ SCAN_FIELD("encap_eth_dst=", eth, encap_eth_dst);
1949+ SCAN_FIELD("encap_eth_type=", encap_eth_type, encap_eth_type);
1950+ } SCAN_END(OVS_KEY_ATTR_ENCAP_ETH);
1951+
1952 SCAN_SINGLE_PORT("in_port(", uint32_t, OVS_KEY_ATTR_IN_PORT);
1953
1954 SCAN_BEGIN("eth(", struct ovs_key_ethernet) {
1955@@ -4325,11 +4553,35 @@ union ovs_key_tp {
1956 static void get_tp_key(const struct flow *, union ovs_key_tp *);
1957 static void put_tp_key(const union ovs_key_tp *, struct flow *);
1958
1959+void
1960+get_nsh_key(const struct flow *flow, struct ovs_key_nsh *nsh)
1961+{
1962+ nsh->nsi = flow->nsi;
1963+ nsh->nsp = flow->nsp;
1964+ nsh->nsh_mdtype = flow->nsh_mdtype;
1965+ nsh->nsh_np = flow->nsh_np;
1966+ nsh->reserved = 0;
1967+ nsh->nshc1 = flow->nshc1;
1968+ nsh->nshc2 = flow->nshc2;
1969+ nsh->nshc3 = flow->nshc3;
1970+ nsh->nshc4 = flow->nshc4;
1971+}
1972+
1973+void
1974+get_encap_eth_key(const struct flow *flow, struct ovs_key_encap_eth *encap_eth)
1975+{
1976+ encap_eth->encap_eth_type = flow->encap_eth_type;
1977+ encap_eth->encap_eth_src = flow->encap_eth_src;
1978+ encap_eth->encap_eth_dst = flow->encap_eth_dst;
1979+}
1980+
1981 static void
1982 odp_flow_key_from_flow__(const struct odp_flow_key_parms *parms,
1983 bool export_mask, struct ofpbuf *buf)
1984 {
1985 struct ovs_key_ethernet *eth_key;
1986+ struct ovs_key_nsh *nsh_key;
1987+ struct ovs_key_encap_eth *encap_eth_key;
1988 size_t encap;
1989 const struct flow *flow = parms->flow;
1990 const struct flow *data = export_mask ? parms->mask : parms->flow;
1991@@ -4368,6 +4620,18 @@ odp_flow_key_from_flow__(const struct odp_flow_key_parms *parms,
1992 nl_msg_put_odp_port(buf, OVS_KEY_ATTR_IN_PORT, parms->odp_in_port);
1993 }
1994
1995+ if (flow->nsh_mdtype) {
1996+ nsh_key = nl_msg_put_unspec_uninit(buf, OVS_KEY_ATTR_NSH,
1997+ sizeof *nsh_key);
1998+ get_nsh_key(data, nsh_key);
1999+ }
2000+
2001+ if (flow->encap_eth_type) {
2002+ encap_eth_key = nl_msg_put_unspec_uninit(buf, OVS_KEY_ATTR_ENCAP_ETH,
2003+ sizeof *encap_eth_key);
2004+ get_encap_eth_key(data, encap_eth_key);
2005+ }
2006+
2007 eth_key = nl_msg_put_unspec_uninit(buf, OVS_KEY_ATTR_ETHERNET,
2008 sizeof *eth_key);
2009 get_ethernet_key(data, eth_key);
2010@@ -5225,6 +5489,28 @@ odp_flow_key_to_flow__(const struct nlattr *key, size_t key_len,
2011 flow->in_port.odp_port = ODPP_NONE;
2012 }
2013
2014+ /* NSH header. */
2015+ if (present_attrs & (UINT64_C(1) << OVS_KEY_ATTR_NSH)) {
2016+ const struct ovs_key_nsh *nsh_key;
2017+
2018+ nsh_key = nl_attr_get(attrs[OVS_KEY_ATTR_NSH]);
2019+ put_nsh_key(nsh_key, flow);
2020+ if (is_mask) {
2021+ expected_attrs |= UINT64_C(1) << OVS_KEY_ATTR_NSH;
2022+ }
2023+ }
2024+
2025+ /* ENCAP Eth header. */
2026+ if (present_attrs & (UINT64_C(1) << OVS_KEY_ATTR_ENCAP_ETH)) {