refactor scripts and update NSH patch

Change-Id: Ifc76e9bf2f83f904e765e6e8216ed98910642bae
Signed-off-by: Guo Ruijing <ruijing.guo@intel.com>
This commit is contained in:
Guo Ruijing 2016-05-24 07:59:45 +00:00
parent b15c57083b
commit 2bad5a25e9
24 changed files with 7072 additions and 8033 deletions

View File

@ -0,0 +1,23 @@
#!/bin/bash
set -eux
INSTALL_HOME=/tmp/ovs-nshdpdk
rm -rf $INSTALL_HOME; mkdir -p $INSTALL_HOME
cd $INSTALL_HOME
host=$1
nsh=$2
dpdk=$3
wget -r -nd -np http://$host:8080/plugins/fuel-plugin-ovs-0.9/ovs_package/ubuntu
if [ $nsh = 'true' ]
then
dpkg -i openvswitch-datapath-dkms_2.5.90-1_all.deb
dpkg -i openvswitch-common_2.5.90-1_amd64.deb
dpkg -i openvswitch-switch_2.5.90-1_amd64.deb
if [ $dpdk = 'true' ]
then
dpkg -i openvswitch-switch-dpdk_2.5.90-1_amd64.deb
fi
fi

View File

@ -1,21 +1,11 @@
$fuel_settings = parseyaml(file('/etc/astute.yaml'))
$master_ip = $::fuel_settings['master_ip']
$support_nsh = $::fuel_settings['fuel-plugin-ovs']['support_nsh']
$support_dpdk = $::fuel_settings['fuel-plugin-ovs']['support_dpdk']
if $operatingsystem == 'Ubuntu' {
if $fuel_settings['fuel-plugin-ovs']['support_nsh'] and
$fuel_settings['fuel-plugin-ovs']['support_dpdk'] {
exec { 'install ovs/nsh-dpdk':
command => '/usr/bin/curl http://10.20.0.2:8080/plugins/fuel-plugin-ovs-0.9/repositories/ubuntu/install.sh | /bin/bash -s nshdpdk'
}
exec { 'install ovs_nsh_dpdk':
command => "curl http://${master_ip}:8080/plugins/fuel-plugin-ovs-0.9/deployment_scripts/install.sh | bash -s ${master_ip} ${support_nsh} ${support_dpdk}",
path => "/usr/bin:/usr/sbin:/bin:/sbin";
}
elsif $fuel_settings['fuel-plugin-ovs']['support_dpdk'] {
exec { 'install ovs/dpdk':
command => '/usr/bin/curl http://10.20.0.2:8080/plugins/fuel-plugin-ovs-0.9/repositories/ubuntu/install.sh | /bin/bash -s dpdk'
}
}
elsif $fuel_settings['fuel-plugin-ovs']['support_nsh'] {
exec { 'install ovs/nsh':
command => '/usr/bin/curl http://10.20.0.2:8080/plugins/fuel-plugin-ovs-0.9/repositories/ubuntu/install.sh | /bin/bash -s nsh'
}
}
} elsif $operatingsystem == 'CentOS' {
}

View File

@ -1 +1,20 @@
[]
- id: ovs_nsh_dpdk
type: group
role: ['compute']
requires: [deploy_start]
required_for: [deploy_end]
tasks: [hiera, setup_repositories, fuel_pkgs, globals, tools, logging, ovs_install_compute]
parameters:
strategy:
type: parallel
- id: ovs_install_compute
type: puppet
version: 2.0.0
groups: [ovs_nsh_dpdk]
required_for: [pre_deployment_end]
requires: [pre_deployment_start]
parameters:
puppet_manifest: puppet/manifests/ovs-install-compute.pp
puppet_modules: puppet/modules:/etc/puppet/modules
timeout: 720

View File

@ -3,12 +3,8 @@
FROM ubuntu:14.04.3
RUN apt-get update -y
RUN rm -rf /lib/modules
RUN apt-get install -y linux-headers-3.13.0-76-generic
RUN ln -s /lib/modules/3.13.0-76-generic /lib/modules/`uname -r`
RUN apt-get install -y linux-headers-3.13.0-86-generic
RUN ln -s /lib/modules/3.13.0-86-generic /lib/modules/`uname -r`
RUN apt-get build-dep openvswitch -y
RUN apt-get -y install devscripts dpkg-dev git wget
ADD ./ /ovs_build
ADD ./ /ovs_build

View File

@ -1,16 +1,20 @@
#!/bin/bash
OVS_COMMIT=cd4764fdd8ce0aa0063525dad0e67f20b3bcf6e9
URL_OVS=https://github.com/openvswitch/ovs.git
OVS_VER=${OVS_VER:-2.5.1}
BUILD_HOME=$HOME/dpdk
BUILD_DEST=${BUILD_DEST:-/deb}
BUILD_HOME=`pwd`
sudo apt-get update -y
sudo apt-get build-dep openvswitch -y
sudo apt-get -y install devscripts dpkg-dev git wget
rm -rf ${BUILD_HOME}; mkdir -p ${BUILD_HOME}
cd ${BUILD_HOME}
wget https://launchpad.net/ubuntu/+archive/primary/+files/dpdk_2.2.0-0ubuntu8.dsc
wget https://launchpad.net/ubuntu/+archive/primary/+files/dpdk_2.2.0.orig.tar.gz
wget https://launchpad.net/ubuntu/+archive/primary/+files/dpdk_2.2.0-0ubuntu8.debian.tar.xz
wget -c https://launchpad.net/ubuntu/+archive/primary/+files/dpdk_2.2.0-0ubuntu8.dsc
wget -c https://launchpad.net/ubuntu/+archive/primary/+files/dpdk_2.2.0.orig.tar.gz
wget -c https://launchpad.net/ubuntu/+archive/primary/+files/dpdk_2.2.0-0ubuntu8.debian.tar.xz
dpkg-source -x dpdk_2.2.0-0ubuntu8.dsc
# copy from debian/control
@ -29,15 +33,20 @@ sudo apt-get install -y debhelper \
texlive-fonts-recommended \
texlive-latex-extra
cd dpdk-2.2.0; rm -rf debian/patches/; debian/rules build; fakeroot debian/rules binary
cd dpdk-2.2.0; rm -rf debian/patches/;
cat << EOF > debian/changelog
dpdk (2.2.0-1) unstable; urgency=low
[ DPDK team]
* New upstream version
EOF
debian/rules build; fakeroot debian/rules binary
cd ${BUILD_HOME}; sudo dpkg -i *.deb
cd ${BUILD_HOME}
wget https://launchpad.net/ubuntu/+archive/primary/+files/openvswitch-dpdk_2.4.0.orig.tar.gz
wget https://launchpad.net/ubuntu/+archive/primary/+files/openvswitch-dpdk_2.4.0-0ubuntu1.dsc
wget https://launchpad.net/ubuntu/+archive/primary/+files/openvswitch-dpdk_2.4.0-0ubuntu1.debian.tar.xz
dpkg-source -x openvswitch-dpdk_2.4.0-0ubuntu1.dsc
wget -c https://launchpad.net/ubuntu/+archive/primary/+files/openvswitch-dpdk_2.4.0.orig.tar.gz
wget -c https://launchpad.net/ubuntu/+archive/primary/+files/openvswitch-dpdk_2.4.0-0ubuntu1.dsc
wget -c https://launchpad.net/ubuntu/+archive/primary/+files/openvswitch-dpdk_2.4.0-0ubuntu1.debian.tar.xz
dpkg-source -x openvswitch-dpdk_2.4.0-0ubuntu1.dsc
# copy from debian/control
sudo apt-get intall -y autoconf \
@ -56,16 +65,27 @@ sudo apt-get intall -y autoconf \
python-all \
python-qt4 \
python-twisted-conch \
python-zopeinterface
python-zopeinterface \
python-six
git clone https://github.com/openvswitch/ovs.git
cd ovs; git checkout ${OVS_COMMIT}
cd ${BUILD_HOME}; tar czvf ovs.tar.gz ovs
rm -rf openvswitch-dpdk-2.5.0*
cd openvswitch-dpdk-2.4.0; uupdate -v 2.5.0 ../ovs.tar.gz
cd ../openvswitch-dpdk-2.5.0
rm -rf openvswitch-dpdk-${OVS_VER}*
cd openvswitch-dpdk-2.4.0; uupdate -v ${OVS_VER} ../ovs.tar.gz
cd ../openvswitch-dpdk-${OVS_VER}
sed -i "s/include\/rte_config.h/include\/dpdk\/rte_config.h/" acinclude.m4
sed -i 's/DPDK_INCLUDE=.*/DPDK_INCLUDE=$RTE_SDK\/include\/dpdk/' acinclude.m4
autoreconf --install
rm -rf debian/patches/ .git;
cat << EOF > debian/changelog
openvswitch-dpdk (${OVS_VER}-1) unstable; urgency=low
[ Open vSwitch team ]
* Open vSwitch Upstream
EOF
debian/rules build; fakeroot debian/rules binary
cd ${BUILD_HOME}/ovs
debian/rules build; fakeroot debian/rules binary
cp ${BUILD_HOME}/*.deb ${BUILD_DEST}

View File

@ -1,43 +1,97 @@
#!/bin/bash
DPDK_VER=2.1.0
BUILD_HOME=`pwd`/tmp
export RTE_TARGET=x86_64-native-linuxapp-gcc
export RTE_SDK=${BUILD_HOME}/dpdk-${DPDK_VER}
export DPDK_BUILD=${RTE_SDK}/${RTE_TARGET}
OVS_COMMIT=121daded51b9798fe3722824b27a05c16806cbd1
PATCHES="060679 060680 060681 060682 060683 060684 060685"
OVS_COMMIT=7d433ae57ebb90cd68e8fa948a096f619ac4e2d8
URL_OVS=https://github.com/openvswitch/ovs.git
URL_DPDK=http://dpdk.org/browse/dpdk/snapshot/dpdk-${DPDK_VER}.tar.gz
OVS_VER=${OVS_VER:-2.5.90}
BUILD_HOME=$HOME/nsh
BUILD_DEST=${BUILD_DEST:-/deb}
mkdir -p ${BUILD_HOME}
cd ${BUILD_HOME}
wget ${URL_DPDK}
tar -xzvf dpdk-${DPDK_VER}.tar.gz
cd dpdk-${DPDK_VER}
sed -i -e 's/CONFIG_RTE_LIBRTE_VHOST=n/CONFIG_RTE_LIBRTE_VHOST=y/' \
-e 's/CONFIG_RTE_BUILD_COMBINE_LIBS=n/CONFIG_RTE_BUILD_COMBINE_LIBS=y/' \
-e 's/CONFIG_RTE_PKTMBUF_HEADROOM=128/CONFIG_RTE_PKTMBUF_HEADROOM=256/' \
config/common_linuxapp
make install T=${RTE_TARGET}
sudo apt-get build-dep openvswitch -y
sudo apt-get -y install devscripts dpkg-dev git wget
rm -rf ${BUILD_HOME}; mkdir -p ${BUILD_HOME}
cd ${BUILD_HOME}
git clone ${URL_OVS} openvswitch
cd openvswitch
git checkout ${OVS_COMMIT} -b development
wget -c https://launchpad.net/ubuntu/+archive/primary/+files/dpdk_2.2.0-0ubuntu8.dsc
wget -c https://launchpad.net/ubuntu/+archive/primary/+files/dpdk_2.2.0.orig.tar.gz
wget -c https://launchpad.net/ubuntu/+archive/primary/+files/dpdk_2.2.0-0ubuntu8.debian.tar.xz
dpkg-source -x dpdk_2.2.0-0ubuntu8.dsc
# copy from debian/control
sudo apt-get install -y debhelper \
dh-python \
dh-systemd \
doxygen \
graphviz \
inkscape \
libcap-dev \
libpcap-dev \
libxen-dev \
libxenstore3.0 \
python \
python-sphinx \
texlive-fonts-recommended \
texlive-latex-extra
cd dpdk-2.2.0; rm -rf debian/patches/;
cat << EOF > debian/changelog
dpdk (2.2.0-1) unstable; urgency=low
[ DPDK team]
* New upstream version
EOF
debian/rules build; fakeroot debian/rules binary
cd ${BUILD_HOME}; sudo dpkg -i *.deb
cd ${BUILD_HOME}
wget -c https://launchpad.net/ubuntu/+archive/primary/+files/openvswitch-dpdk_2.4.0.orig.tar.gz
wget -c https://launchpad.net/ubuntu/+archive/primary/+files/openvswitch-dpdk_2.4.0-0ubuntu1.dsc
wget -c https://launchpad.net/ubuntu/+archive/primary/+files/openvswitch-dpdk_2.4.0-0ubuntu1.debian.tar.xz
dpkg-source -x openvswitch-dpdk_2.4.0-0ubuntu1.dsc
# copy from debian/control
sudo apt-get intall -y autoconf \
automake \
bzip2 \
debhelper \
dh-autoreconf \
dh-systemd \
graphviz \
libdpdk-dev \
libfuse-dev \
libssl-dev \
libtool \
openssl \
procps \
python-all \
python-qt4 \
python-twisted-conch \
python-zopeinterface \
python-six
git clone https://github.com/openvswitch/ovs.git
cd ovs; git checkout ${OVS_COMMIT}
DIR="$(dirname `readlink -f $0`)"
PATCHES=$(cd patches; echo *patch; cd ..)
for patch in ${PATCHES}
do
patch -p1 < /ovs_build/patches/${patch}.patch
patch -p1 < {DIR}/patches/${patch}
done
export DEB_BUILD_OPTIONS='parallel=8 nocheck'
sed -i "s/2.4.90/2.4.90.nshdpdk/g" debian/changelog
sed -i "s/DATAPATH_CONFIGURE_OPTS.*=.*//" debian/rules
sed -i "2iDATAPATH_CONFIGURE_OPTS='--with-dpdk=$DPDK_BUILD'" debian/rules
sed -i "s/DATAPATH_CONFIGURE_OPTS.*=.*//" debian/rules.modules
sed -i "2iDATAPATH_CONFIGURE_OPTS='--with-dpdk=$DPDK_BUILD'" debian/rules.modules
debian/rules build
fakeroot debian/rules binary
cd ${BUILD_HOME}; tar czvf ovs.tar.gz ovs
rm -rf openvswitch-dpdk-${OVS_VER}*
cd openvswitch-dpdk-2.4.0; uupdate -v ${OVS_VER} ../ovs.tar.gz
cd ../openvswitch-dpdk-${OVS_VER}
sed -i "s/include\/rte_config.h/include\/dpdk\/rte_config.h/" acinclude.m4
sed -i 's/DPDK_INCLUDE=.*/DPDK_INCLUDE=$RTE_SDK\/include\/dpdk/' acinclude.m4
autoreconf --install
rm -rf debian/patches/ .git;
cat << EOF > debian/changelog
openvswitch-dpdk (${OVS_VER}-1) unstable; urgency=low
[ Open vSwitch team ]
* Support NSH
EOF
debian/rules build; fakeroot debian/rules binary
cp ${BUILD_HOME}/*.deb /deb
cd ${BUILD_HOME}/ovs
debian/rules build; fakeroot debian/rules binary
cp ${BUILD_HOME}/*.deb ${BUILD_DEST}

View File

@ -1,23 +0,0 @@
#!/bin/bash
BUILD_HOME=`pwd`/tmp
OVS_COMMIT=121daded51b9798fe3722824b27a05c16806cbd1
PATCHES="060679 060680 060681 060682 060683 060684 060685"
URL_OVS=https://github.com/openvswitch/ovs.git
mkdir -p ${BUILD_HOME}
cd ${BUILD_HOME}
git clone ${URL_OVS} openvswitch
cd openvswitch
git checkout ${OVS_COMMIT} -b development
for patch in ${PATCHES}
do
patch -p1 < /ovs_build/patches/${patch}.patch
done
export DEB_BUILD_OPTIONS='parallel=8 nocheck'
sed -i "s/2.4.90/2.4.90.nsh/g" debian/changelog
debian/rules build
fakeroot debian/rules binary
cp ${BUILD_HOME}/*.deb /deb

View File

@ -0,0 +1,732 @@
From 5d79831435ec4e5bea20cc36c3f83eacf6fd065c Mon Sep 17 00:00:00 2001
From: Yi Yang <yi.y.yang@intel.com>
Date: Mon, 11 Apr 2016 15:58:14 +0800
Subject: [PATCH 1/5] ovs-vxlan-gpe: vxlan extension to support vxlan-gpe
tunnel port
Signed-off-by: Mengke Liu <mengke.liu@intel.com>
Signed-off-by: Ricky Li <ricky.li@intel.com>
Signed-off-by: Johnson Li <johnson.li@intel.com>
Signed-off-by: Yi Yang <yi.y.yang@intel.com>
---
datapath/flow_netlink.c | 8 +-
datapath/linux/compat/include/linux/openvswitch.h | 1 +
datapath/linux/compat/include/net/vxlan.h | 73 +++++++++++++++++++
datapath/linux/compat/vxlan.c | 30 ++++++++
datapath/vport-vxlan.c | 15 ++++
lib/flow.c | 8 ++
lib/match.c | 34 +++++++++
lib/match.h | 4 +
lib/meta-flow.c | 36 +++++++++
lib/meta-flow.h | 28 +++++++
lib/netdev-vport.c | 2 +
lib/nx-match.c | 4 +
lib/odp-util.c | 89 ++++++++++++++++++++++-
lib/packets.h | 4 +-
tests/ofproto.at | 4 +-
tests/ovs-ofctl.at | 4 +
16 files changed, 340 insertions(+), 4 deletions(-)
diff --git a/datapath/flow_netlink.c b/datapath/flow_netlink.c
index 6ffcc53..351a504 100644
--- a/datapath/flow_netlink.c
+++ b/datapath/flow_netlink.c
@@ -309,6 +309,7 @@ size_t ovs_key_attr_size(void)
static const struct ovs_len_tbl ovs_vxlan_ext_key_lens[OVS_VXLAN_EXT_MAX + 1] = {
[OVS_VXLAN_EXT_GBP] = { .len = sizeof(u32) },
+ [OVS_VXLAN_EXT_GPE] = { .len = sizeof(u32) },
};
static const struct ovs_len_tbl ovs_tunnel_key_lens[OVS_TUNNEL_KEY_ATTR_MAX + 1] = {
@@ -521,6 +522,9 @@ static int vxlan_tun_opt_from_nlattr(const struct nlattr *attr,
case OVS_VXLAN_EXT_GBP:
opts.gbp = nla_get_u32(a);
break;
+ case OVS_VXLAN_EXT_GPE:
+ opts.gpe = nla_get_u32(a);
+ break;
default:
OVS_NLERR(log, "Unknown VXLAN extension attribute %d",
type);
@@ -677,7 +681,9 @@ static int vxlan_opt_to_nlattr(struct sk_buff *skb,
if (!nla)
return -EMSGSIZE;
- if (nla_put_u32(skb, OVS_VXLAN_EXT_GBP, opts->gbp) < 0)
+ if (opts->gbp && nla_put_u32(skb, OVS_VXLAN_EXT_GBP, opts->gbp) < 0)
+ return -EMSGSIZE;
+ else if (opts->gpe && nla_put_u32(skb, OVS_VXLAN_EXT_GPE, opts->gpe) < 0)
return -EMSGSIZE;
nla_nest_end(skb, nla);
diff --git a/datapath/linux/compat/include/linux/openvswitch.h b/datapath/linux/compat/include/linux/openvswitch.h
index 3b39ebb..44adb81 100644
--- a/datapath/linux/compat/include/linux/openvswitch.h
+++ b/datapath/linux/compat/include/linux/openvswitch.h
@@ -287,6 +287,7 @@ enum ovs_vport_attr {
enum {
OVS_VXLAN_EXT_UNSPEC,
OVS_VXLAN_EXT_GBP, /* Flag or __u32 */
+ OVS_VXLAN_EXT_GPE,
__OVS_VXLAN_EXT_MAX,
};
diff --git a/datapath/linux/compat/include/net/vxlan.h b/datapath/linux/compat/include/net/vxlan.h
index 75a5a7a..2bfc3f8 100644
--- a/datapath/linux/compat/include/net/vxlan.h
+++ b/datapath/linux/compat/include/net/vxlan.h
@@ -84,6 +84,75 @@ struct vxlanhdr_gbp {
#define VXLAN_GBP_POLICY_APPLIED (BIT(3) << 16)
#define VXLAN_GBP_ID_MASK (0xFFFF)
+/*
+ * VXLAN Generic Protocol Extension Extension:
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |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 |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | VXLAN Network Identifier (VNI) | Reserved |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * Ver = Version. Indicates VXLAN GPE protocol version. The initial
+ * version is 0. If a receiver does not support the version
+ * indicated it MUST drop the packet.
+ *
+ * I = Instance Bit. The I bit MUST be set to indicate a valid VNI.
+ *
+ * P = Next Protocol Bit. The P bit is set to indicate that the
+ * Next Protocol field is present.
+ *
+ * O = OAM Flag Bit. The O bit is set to indicate that the packet
+ * is an OAM packet.
+ *
+ * [1] https://www.ietf.org/id/draft-ietf-nvo3-vxlan-gpe-01.txt
+ */
+
+struct vxlanhdr_gpe {
+#ifdef __LITTLE_ENDIAN_BITFIELD
+ uint8_t oam_flag:1;
+ uint8_t reserved_flags1:1;
+ uint8_t np_applied:1;
+ uint8_t instance_applied:1;
+ uint8_t gpe_version:2;
+ uint8_t reserved_flags2:2;
+#elif defined(__BIG_ENDIAN_BITFIELD)
+ uint8_t reserved_flags2:2;
+ uint8_t gpe_version:2;
+ uint8_t instance_applied:1;
+ uint8_t np_applied:1;
+ uint8_t reserved_flags1:1;
+ uint8_t oam_flag:1;
+#else
+#error "Please fix <asm/byteorder.h>"
+#endif
+ uint8_t reserved_flags3;
+ uint8_t reserved_flags4;
+ uint8_t next_proto;
+ __be32 vx_vni;
+};
+
+/* VxLAN-GPE Header Next Protocol */
+#define VXLAN_GPE_NP_IPV4 0x01
+#define VXLAN_GPE_NP_IPV6 0x02
+#define VXLAN_GPE_NP_ETHERNET 0x03
+#define VXLAN_GPE_NP_NSH 0x04
+
+/* skb->mark mapping
+ *
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |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 |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+
+#define VXLAN_GPE_OAM_FLAG (BIT(0) << 24)
+#define VXLAN_GPE_NP_APPLIED (BIT(0) << 26)
+#define VXLAN_GPE_INSTANCE_APPLIED (BIT(0) << 27)
+#define VXLAN_GPE_VERSION ((BIT(0) << 28) | (BIT(0) << 29))
+
+#define VXLAN_GPE_NP_MASK (0xFF)
+
+#define VXLAN_GPE_USED_BITS (VXLAN_GPE_OAM_FLAG | VXLAN_GPE_NP_APPLIED \
+ | VXLAN_GPE_INSTANCE_APPLIED | VXLAN_GPE_VERSION | 0xFF)
+
/* VXLAN protocol header:
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* |G|R|R|R|I|R|R|C| Reserved |
@@ -104,6 +173,7 @@ struct vxlanhdr {
#define VXLAN_HF_RCO BIT(21)
#define VXLAN_HF_VNI BIT(27)
#define VXLAN_HF_GBP BIT(31)
+#define VXLAN_HF_GPE BIT(26)
/* Remote checksum offload header option */
#define VXLAN_RCO_MASK 0x7f /* Last byte of vni field */
@@ -120,6 +190,7 @@ struct vxlanhdr {
struct vxlan_metadata {
__be32 vni;
u32 gbp;
+ u32 gpe;
};
#define VNI_HASH_BITS 10
@@ -205,11 +276,13 @@ struct vxlan_dev {
#define VXLAN_F_GBP 0x800
#define VXLAN_F_REMCSUM_NOPARTIAL 0x1000
#define VXLAN_F_COLLECT_METADATA 0x2000
+#define VXLAN_F_GPE 0x4000
/* Flags that are used in the receive path. These flags must match in
* order for a socket to be shareable
*/
#define VXLAN_F_RCV_FLAGS (VXLAN_F_GBP | \
+ VXLAN_F_GPE | \
VXLAN_F_UDP_ZERO_CSUM6_RX | \
VXLAN_F_REMCSUM_RX | \
VXLAN_F_REMCSUM_NOPARTIAL | \
diff --git a/datapath/linux/compat/vxlan.c b/datapath/linux/compat/vxlan.c
index 4faa18f..7ef051c 100644
--- a/datapath/linux/compat/vxlan.c
+++ b/datapath/linux/compat/vxlan.c
@@ -971,6 +971,18 @@ static int vxlan_udp_encap_recv(struct sock *sk, struct sk_buff *skb)
md->gbp |= VXLAN_GBP_POLICY_APPLIED;
flags &= ~VXLAN_GBP_USED_BITS;
+ } else if ((flags & VXLAN_HF_GPE) && (vs->flags & VXLAN_F_GPE)) {
+ struct vxlanhdr_gpe *gpe;
+
+ gpe = (struct vxlanhdr_gpe *)vxh;
+ md->gpe = ntohs(gpe->next_proto);
+
+ buf.dst.u.tun_info.key.tun_flags |= TUNNEL_VXLAN_OPT;
+
+ if (gpe->oam_flag)
+ md->gpe |= VXLAN_GPE_OAM_FLAG;
+
+ flags &= ~VXLAN_GPE_USED_BITS;
}
if (flags || vni & ~VXLAN_VNI_MASK) {
@@ -1023,6 +1035,22 @@ static void vxlan_build_gbp_hdr(struct vxlanhdr *vxh, u32 vxflags,
gbp->policy_id = htons(md->gbp & VXLAN_GBP_ID_MASK);
}
+static void vxlan_build_gpe_hdr(struct vxlanhdr *vxh, u32 vxflags,
+ struct vxlan_metadata *md)
+{
+ struct vxlanhdr_gpe *gpe;
+
+ if (!md->gpe)
+ return;
+
+ gpe = (struct vxlanhdr_gpe*)vxh;
+ vxh->vx_flags |= htonl(VXLAN_HF_GPE);
+
+ if (md->gpe & VXLAN_GPE_OAM_FLAG)
+ gpe->oam_flag = 1;
+ gpe->next_proto = md->gpe & VXLAN_GPE_NP_MASK;
+}
+
#if IS_ENABLED(CONFIG_IPV6)
static int vxlan6_xmit_skb(struct dst_entry *dst, struct sock *sk,
struct sk_buff *skb,
@@ -1106,6 +1134,8 @@ static int vxlan6_xmit_skb(struct dst_entry *dst, struct sock *sk,
if (vxflags & VXLAN_F_GBP)
vxlan_build_gbp_hdr(vxh, vxflags, md);
+ else if (vxflags & VXLAN_F_GPE)
+ vxlan_build_gpe_hdr(vxh, vxflags, md);
ovs_skb_set_inner_protocol(skb, htons(ETH_P_TEB));
diff --git a/datapath/vport-vxlan.c b/datapath/vport-vxlan.c
index c05f5d4..5d775cc 100644
--- a/datapath/vport-vxlan.c
+++ b/datapath/vport-vxlan.c
@@ -52,6 +52,18 @@ static int vxlan_get_options(const struct vport *vport, struct sk_buff *skb)
return -EMSGSIZE;
nla_nest_end(skb, exts);
+ } else if (vxlan->flags & VXLAN_F_GPE) {
+ struct nlattr *exts;
+
+ exts = nla_nest_start(skb, OVS_TUNNEL_ATTR_EXTENSION);
+ if (!exts)
+ return -EMSGSIZE;
+
+ if (vxlan->flags & VXLAN_F_GPE &&
+ nla_put_flag(skb, OVS_VXLAN_EXT_GPE))
+ return -EMSGSIZE;
+
+ nla_nest_end(skb, exts);
}
return 0;
@@ -59,6 +71,7 @@ static int vxlan_get_options(const struct vport *vport, struct sk_buff *skb)
static const struct nla_policy exts_policy[OVS_VXLAN_EXT_MAX + 1] = {
[OVS_VXLAN_EXT_GBP] = { .type = NLA_FLAG, },
+ [OVS_VXLAN_EXT_GPE] = { .type = NLA_FLAG, },
};
static int vxlan_configure_exts(struct vport *vport, struct nlattr *attr,
@@ -76,6 +89,8 @@ static int vxlan_configure_exts(struct vport *vport, struct nlattr *attr,
if (exts[OVS_VXLAN_EXT_GBP])
conf->flags |= VXLAN_F_GBP;
+ else if (exts[OVS_VXLAN_EXT_GPE])
+ conf->flags |= VXLAN_F_GPE;
return 0;
}
diff --git a/lib/flow.c b/lib/flow.c
index b9ce331..d24bdc9 100644
--- a/lib/flow.c
+++ b/lib/flow.c
@@ -870,6 +870,12 @@ flow_get_metadata(const struct flow *flow, struct match *flow_metadata)
if (flow->tunnel.gbp_flags) {
match_set_tun_gbp_flags(flow_metadata, flow->tunnel.gbp_flags);
}
+ if (flow->tunnel.gpe_np != htons(0)) {
+ match_set_tun_gpe_np(flow_metadata, flow->tunnel.gpe_np);
+ }
+ if (flow->tunnel.gpe_flags) {
+ match_set_tun_gpe_flags(flow_metadata, flow->tunnel.gpe_flags);
+ }
tun_metadata_get_fmd(&flow->tunnel, flow_metadata);
if (flow->metadata != htonll(0)) {
match_set_metadata(flow_metadata, flow->metadata);
@@ -1265,6 +1271,8 @@ void flow_wildcards_init_for_packet(struct flow_wildcards *wc,
WC_MASK_FIELD(wc, tunnel.tp_dst);
WC_MASK_FIELD(wc, tunnel.gbp_id);
WC_MASK_FIELD(wc, tunnel.gbp_flags);
+ WC_MASK_FIELD(wc, tunnel.gpe_np);
+ WC_MASK_FIELD(wc, tunnel.gpe_flags);
if (!(flow->tunnel.flags & FLOW_TNL_F_UDPIF)) {
if (flow->tunnel.metadata.present.map) {
diff --git a/lib/match.c b/lib/match.c
index fd571d9..52437c9 100644
--- a/lib/match.c
+++ b/lib/match.c
@@ -289,6 +289,32 @@ match_set_tun_gbp_flags(struct match *match, uint8_t flags)
}
void
+match_set_tun_gpe_np_masked(struct match *match, uint8_t np, uint8_t mask)
+{
+ match->wc.masks.tunnel.gpe_np = mask;
+ match->flow.tunnel.gpe_np = np & mask;
+}
+
+void
+match_set_tun_gpe_np(struct match *match, uint8_t np)
+{
+ match_set_tun_gpe_np_masked(match, np, UINT8_MAX);
+}
+
+void
+match_set_tun_gpe_flags_masked(struct match *match, uint8_t flags, uint8_t mask)
+{
+ match->wc.masks.tunnel.gpe_flags = mask;
+ match->flow.tunnel.gpe_flags = flags & mask;
+}
+
+void
+match_set_tun_gpe_flags(struct match *match, uint8_t flags)
+{
+ match_set_tun_gpe_flags_masked(match, flags, UINT8_MAX);
+}
+
+void
match_set_in_port(struct match *match, ofp_port_t ofp_port)
{
match->wc.masks.in_port.ofp_port = u16_to_ofp(UINT16_MAX);
@@ -1013,6 +1039,14 @@ format_flow_tunnel(struct ds *s, const struct match *match)
ds_put_format(s, "tun_gbp_flags=%#"PRIx8",", tnl->gbp_flags);
}
+ if (wc->masks.tunnel.gpe_np) {
+ ds_put_format(s, "tun_gpe_np=%#"PRIx8",", tnl->gpe_np);
+ }
+
+ if (wc->masks.tunnel.gpe_flags) {
+ ds_put_format(s, "tun_gpe_flags=%#"PRIx8",", tnl->gpe_flags);
+ }
+
if (wc->masks.tunnel.ip_tos) {
ds_put_format(s, "tun_tos=%"PRIx8",", tnl->ip_tos);
}
diff --git a/lib/match.h b/lib/match.h
index 0a6ac29..48aa0b1 100644
--- a/lib/match.h
+++ b/lib/match.h
@@ -86,6 +86,10 @@ void match_set_tun_gbp_id_masked(struct match *match, ovs_be16 gbp_id, ovs_be16
void match_set_tun_gbp_id(struct match *match, ovs_be16 gbp_id);
void match_set_tun_gbp_flags_masked(struct match *match, uint8_t flags, uint8_t mask);
void match_set_tun_gbp_flags(struct match *match, uint8_t flags);
+void match_set_tun_gpe_np_masked(struct match *match, uint8_t gpe_np, uint8_t mask);
+void match_set_tun_gpe_np(struct match *match, uint8_t gpe_np);
+void match_set_tun_gpe_flags_masked(struct match *match, uint8_t flags, uint8_t mask);
+void match_set_tun_gpe_flags(struct match *match, uint8_t flags);
void match_set_in_port(struct match *, ofp_port_t ofp_port);
void match_set_pkt_mark(struct match *, uint32_t pkt_mark);
void match_set_pkt_mark_masked(struct match *, uint32_t pkt_mark, uint32_t mask);
diff --git a/lib/meta-flow.c b/lib/meta-flow.c
index 721152c..ab77fca 100644
--- a/lib/meta-flow.c
+++ b/lib/meta-flow.c
@@ -213,6 +213,10 @@ mf_is_all_wild(const struct mf_field *mf, const struct flow_wildcards *wc)
return !wc->masks.tunnel.gbp_id;
case MFF_TUN_GBP_FLAGS:
return !wc->masks.tunnel.gbp_flags;
+ case MFF_TUN_GPE_NP:
+ return !wc->masks.tunnel.gpe_np;
+ case MFF_TUN_GPE_FLAGS:
+ return !wc->masks.tunnel.gpe_flags;
CASE_MFF_TUN_METADATA:
return !ULLONG_GET(wc->masks.tunnel.metadata.present.map,
mf->id - MFF_TUN_METADATA0);
@@ -515,6 +519,8 @@ mf_is_value_valid(const struct mf_field *mf, const union mf_value *value)
case MFF_TUN_TTL:
case MFF_TUN_GBP_ID:
case MFF_TUN_GBP_FLAGS:
+ case MFF_TUN_GPE_NP:
+ case MFF_TUN_GPE_FLAGS:
CASE_MFF_TUN_METADATA:
case MFF_METADATA:
case MFF_IN_PORT:
@@ -648,6 +654,12 @@ mf_get_value(const struct mf_field *mf, const struct flow *flow,
case MFF_TUN_GBP_FLAGS:
value->u8 = flow->tunnel.gbp_flags;
break;
+ case MFF_TUN_GPE_NP:
+ value->u8 = flow->tunnel.gpe_np;
+ break;
+ case MFF_TUN_GPE_FLAGS:
+ value->u8 = flow->tunnel.gpe_flags;
+ break;
case MFF_TUN_TTL:
value->u8 = flow->tunnel.ip_ttl;
break;
@@ -899,6 +911,12 @@ mf_set_value(const struct mf_field *mf,
case MFF_TUN_GBP_FLAGS:
match_set_tun_gbp_flags(match, value->u8);
break;
+ case MFF_TUN_GPE_NP:
+ match_set_tun_gpe_np(match, value->u8);
+ break;
+ case MFF_TUN_GPE_FLAGS:
+ match_set_tun_gpe_flags(match, value->u8);
+ break;
case MFF_TUN_TOS:
match_set_tun_tos(match, value->u8);
break;
@@ -1216,6 +1234,12 @@ mf_set_flow_value(const struct mf_field *mf,
case MFF_TUN_GBP_FLAGS:
flow->tunnel.gbp_flags = value->u8;
break;
+ case MFF_TUN_GPE_NP:
+ flow->tunnel.gpe_np= value->u8;
+ break;
+ case MFF_TUN_GPE_FLAGS:
+ flow->tunnel.gpe_flags= value->u8;
+ break;
case MFF_TUN_TOS:
flow->tunnel.ip_tos = value->u8;
break;
@@ -1535,6 +1559,12 @@ mf_set_wild(const struct mf_field *mf, struct match *match, char **err_str)
case MFF_TUN_GBP_FLAGS:
match_set_tun_gbp_flags_masked(match, 0, 0);
break;
+ case MFF_TUN_GPE_NP:
+ match_set_tun_gpe_np_masked(match, 0, 0);
+ break;
+ case MFF_TUN_GPE_FLAGS:
+ match_set_tun_gpe_flags_masked(match, 0, 0);
+ break;
case MFF_TUN_TOS:
match_set_tun_tos_masked(match, 0, 0);
break;
@@ -1838,6 +1868,12 @@ mf_set(const struct mf_field *mf,
case MFF_TUN_GBP_FLAGS:
match_set_tun_gbp_flags_masked(match, value->u8, mask->u8);
break;
+ case MFF_TUN_GPE_NP:
+ match_set_tun_gpe_np_masked(match, value->u8, mask->u8);
+ break;
+ case MFF_TUN_GPE_FLAGS:
+ match_set_tun_gpe_flags_masked(match, value->u8, mask->u8);
+ break;
case MFF_TUN_TTL:
match_set_tun_ttl_masked(match, value->u8, mask->u8);
break;
diff --git a/lib/meta-flow.h b/lib/meta-flow.h
index c73a1af..4bd9ff6 100644
--- a/lib/meta-flow.h
+++ b/lib/meta-flow.h
@@ -491,6 +491,34 @@ enum OVS_PACKED_ENUM mf_field_id {
*/
MFF_TUN_GBP_FLAGS,
+ /* "tun_gpe_np".
+ *
+ * VXLAN Generic Protocol Extension next_proto
+ *
+ * Type: u8.
+ * Maskable: bitwise.
+ * Formatting: hexadecimal.
+ * Prerequisites: none.
+ * Access: read/write.
+ * NXM: NXM_NX_TUN_GPE_NP(111) since v2.4.
+ * OXM: none.
+ */
+ MFF_TUN_GPE_NP,
+
+ /* "tun_gpe_flags".
+ *
+ * VXLAN Generic Protocol Extension flag
+ *
+ * Type: u8.
+ * Maskable: bitwise.
+ * Formatting: hexadecimal.
+ * Prerequisites: none.
+ * Access: read/write.
+ * NXM: NXM_NX_TUN_GPE_FLAGS(112) since v2.4.
+ * OXM: none.
+ */
+ MFF_TUN_GPE_FLAGS,
+
#if TUN_METADATA_NUM_OPTS == 64
/* "tun_metadata<N>".
*
diff --git a/lib/netdev-vport.c b/lib/netdev-vport.c
index e398562..92ceec1 100644
--- a/lib/netdev-vport.c
+++ b/lib/netdev-vport.c
@@ -583,6 +583,8 @@ set_tunnel_config(struct netdev *dev_, const struct smap *args)
while (ext) {
if (!strcmp(type, "vxlan") && !strcmp(ext, "gbp")) {
tnl_cfg.exts |= (1 << OVS_VXLAN_EXT_GBP);
+ } else if (!strcmp(type, "vxlan") && !strcmp(ext, "gpe")) {
+ tnl_cfg.exts |= (1 << OVS_VXLAN_EXT_GPE);
} else {
VLOG_WARN("%s: unknown extension '%s'", name, ext);
}
diff --git a/lib/nx-match.c b/lib/nx-match.c
index 9f0f452..0eecac7 100644
--- a/lib/nx-match.c
+++ b/lib/nx-match.c
@@ -1037,6 +1037,10 @@ nx_put_raw(struct ofpbuf *b, enum ofp_version oxm, const struct match *match,
flow->tunnel.gbp_id, match->wc.masks.tunnel.gbp_id);
nxm_put_8m(b, MFF_TUN_GBP_FLAGS, oxm,
flow->tunnel.gbp_flags, match->wc.masks.tunnel.gbp_flags);
+ nxm_put_8m(b, MFF_TUN_GPE_NP, oxm,
+ flow->tunnel.gpe_np, match->wc.masks.tunnel.gpe_np);
+ nxm_put_8m(b, MFF_TUN_GPE_FLAGS, oxm,
+ flow->tunnel.gpe_flags, match->wc.masks.tunnel.gpe_flags);
tun_metadata_to_nx_match(b, oxm, match);
/* Registers. */
diff --git a/lib/odp-util.c b/lib/odp-util.c
index b4689cc..7983720 100644
--- a/lib/odp-util.c
+++ b/lib/odp-util.c
@@ -1727,6 +1727,7 @@ odp_actions_from_string(const char *s, const struct simap *port_names,
static const struct attr_len_tbl ovs_vxlan_ext_attr_lens[OVS_VXLAN_EXT_MAX + 1] = {
[OVS_VXLAN_EXT_GBP] = { .len = 4 },
+ [OVS_VXLAN_EXT_GPE] = { .len = 4 },
};
static const struct attr_len_tbl ovs_tun_key_attr_lens[OVS_TUNNEL_KEY_ATTR_MAX + 1] = {
@@ -1888,7 +1889,10 @@ odp_tun_key_from_attr__(const struct nlattr *attr,
break;
case OVS_TUNNEL_KEY_ATTR_VXLAN_OPTS: {
static const struct nl_policy vxlan_opts_policy[] = {
- [OVS_VXLAN_EXT_GBP] = { .type = NL_A_U32 },
+ [OVS_VXLAN_EXT_GBP] = { .type = NL_A_U32 ,
+ .optional = true },
+ [OVS_VXLAN_EXT_GPE] = { .type = NL_A_U32 ,
+ .optional = true },
};
struct nlattr *ext[ARRAY_SIZE(vxlan_opts_policy)];
@@ -1902,6 +1906,12 @@ odp_tun_key_from_attr__(const struct nlattr *attr,
tun->gbp_id = htons(gbp & 0xFFFF);
tun->gbp_flags = (gbp >> 16) & 0xFF;
}
+ if (ext[OVS_VXLAN_EXT_GPE]) {
+ uint32_t gpe = nl_attr_get_u32(ext[OVS_VXLAN_EXT_GPE]);
+
+ tun->gpe_np = gpe & 0xFF;
+ tun->gpe_flags = gpe >> 24;
+ }
break;
}
@@ -1988,6 +1998,13 @@ tun_key_to_attr(struct ofpbuf *a, const struct flow_tnl *tun_key,
nl_msg_put_u32(a, OVS_VXLAN_EXT_GBP,
(tun_key->gbp_flags << 16) | ntohs(tun_key->gbp_id));
nl_msg_end_nested(a, vxlan_opts_ofs);
+ } else if (tun_key->gpe_flags || tun_key->gpe_np) {
+ size_t vxlan_opts_ofs;
+
+ vxlan_opts_ofs = nl_msg_start_nested(a, OVS_TUNNEL_KEY_ATTR_VXLAN_OPTS);
+ nl_msg_put_u32(a, OVS_VXLAN_EXT_GPE,
+ (tun_key->gpe_flags << 24) | (tun_key->gpe_np));
+ nl_msg_end_nested(a, vxlan_opts_ofs);
}
tun_metadata_to_geneve_nlattr(tun_key, tun_flow_key, key_buf, a);
@@ -2383,6 +2400,26 @@ format_odp_tun_vxlan_opt(const struct nlattr *attr,
ds_put_cstr(ds, "),");
break;
}
+ case OVS_VXLAN_EXT_GPE: {
+ uint32_t key = nl_attr_get_u32(a);
+ uint8_t np, np_mask;
+ uint8_t flags, flags_mask;
+
+ np = key & 0xFF;
+ flags = (key >> 24) & 0xFF;
+ if (ma) {
+ uint32_t mask = nl_attr_get_u32(ma);
+ np_mask = mask & 0xFF;
+ flags_mask = (mask >> 24) & 0xFF;
+ }
+
+ ds_put_cstr(ds, "gpe(");
+ format_u8x(ds, "np", np, ma ? &np_mask : NULL, verbose);
+ format_u8x(ds, "flags", flags, ma ? &flags_mask : NULL, verbose);
+ ds_chomp(ds, ',');
+ ds_put_cstr(ds, "),");
+ break;
+ }
default:
format_unknown_key(ds, a, ma);
@@ -3670,6 +3707,40 @@ scan_vxlan_gbp(const char *s, uint32_t *key, uint32_t *mask)
}
static int
+scan_vxlan_gpe(const char *s, uint32_t *key, uint32_t *mask)
+{
+ const char *s_base = s;
+ uint8_t np = 0, np_mask = 0;
+ uint8_t flags = 0, flags_mask = 0;
+
+ if (!strncmp(s, "np=", 3)) {
+ s += 3;
+ s += scan_u8(s, &np, mask ? &np_mask : NULL);
+ }
+
+ if (s[0] == ',') {
+ s++;
+ }
+ if (!strncmp(s, "flags=", 6)) {
+ s += 6;
+ s += scan_u8(s, &flags, mask ? &flags_mask : NULL);
+ }
+
+ if (!strncmp(s, "))", 2)) {
+ s += 2;
+
+ *key = (flags << 24) | np;
+ if (mask) {
+ *mask = (flags_mask << 24) | np_mask;
+ }
+
+ return s - s_base;
+ }
+
+ return 0;
+}
+
+static int
scan_geneve(const char *s, struct geneve_scan *key, struct geneve_scan *mask)
{
const char *s_base = s;
@@ -3796,6 +3867,21 @@ vxlan_gbp_to_attr(struct ofpbuf *a, const void *data_)
}
static void
+vxlan_gpe_to_attr(struct ofpbuf *a, const void *data_)
+{
+ const uint32_t *gpe = data_;
+
+ if (*gpe) {
+ size_t vxlan_opts_ofs;
+
+ vxlan_opts_ofs = nl_msg_start_nested(a, OVS_TUNNEL_KEY_ATTR_VXLAN_OPTS);
+ nl_msg_put_u32(a, OVS_VXLAN_EXT_GPE, *gpe);
+ nl_msg_end_nested(a, vxlan_opts_ofs);
+ }
+}
+
+
+static void
geneve_to_attr(struct ofpbuf *a, const void *data_)
{
const struct geneve_scan *geneve = data_;
@@ -4031,6 +4117,7 @@ parse_odp_key_mask_attr(const char *s, const struct simap *port_names,
SCAN_FIELD_NESTED("tp_src=", ovs_be16, be16, OVS_TUNNEL_KEY_ATTR_TP_SRC);
SCAN_FIELD_NESTED("tp_dst=", ovs_be16, be16, OVS_TUNNEL_KEY_ATTR_TP_DST);
SCAN_FIELD_NESTED_FUNC("vxlan(gbp(", uint32_t, vxlan_gbp, vxlan_gbp_to_attr);
+ SCAN_FIELD_NESTED_FUNC("vxlan(gpe(", uint32_t, vxlan_gpe, vxlan_gpe_to_attr);
SCAN_FIELD_NESTED_FUNC("geneve(", struct geneve_scan, geneve,
geneve_to_attr);
SCAN_FIELD_NESTED_FUNC("flags(", uint16_t, tun_flags, tun_flags_to_attr);
diff --git a/lib/packets.h b/lib/packets.h
index a8ea24b..dc97333 100644
--- a/lib/packets.h
+++ b/lib/packets.h
@@ -49,7 +49,9 @@ struct flow_tnl {
ovs_be16 tp_dst;
ovs_be16 gbp_id;
uint8_t gbp_flags;
- uint8_t pad1[5]; /* Pad to 64 bits. */
+ uint8_t gpe_np;
+ uint8_t gpe_flags;
+ uint8_t pad1[3]; /* Pad to 64 bits. */
struct tun_metadata metadata;
};
diff --git a/tests/ofproto.at b/tests/ofproto.at
index fbb6d71..6c7217d 100644
--- a/tests/ofproto.at
+++ b/tests/ofproto.at
@@ -1775,7 +1775,7 @@ head_table () {
instructions: meter,apply_actions,clear_actions,write_actions,write_metadata,goto_table
Write-Actions and Apply-Actions features:
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
- 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
+ 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
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
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
matching:
@@ -1790,6 +1790,8 @@ metadata in_port in_port_oxm pkt_mark ct_mark ct_label reg0 reg1 reg2 reg3 reg4
tun_flags: arbitrary mask
tun_gbp_id: arbitrary mask
tun_gbp_flags: arbitrary mask
+ tun_gpe_np: arbitrary mask
+ tun_gpe_flags: arbitrary mask
tun_metadata0: arbitrary mask
tun_metadata1: arbitrary mask
tun_metadata2: arbitrary mask
diff --git a/tests/ovs-ofctl.at b/tests/ovs-ofctl.at
index f26f622..dde603d 100644
--- a/tests/ovs-ofctl.at
+++ b/tests/ovs-ofctl.at
@@ -17,6 +17,10 @@ for test_case in \
'tun_gbp_id=0/0x1 NXM,OXM' \
'tun_gbp_flags=0 NXM,OXM' \
'tun_gbp_flags=0/0x1 NXM,OXM' \
+ 'tun_gpe_np=0 NXM,OXM' \
+ 'tun_gpe_np=0/0x1 NXM,OXM' \
+ 'tun_gpe_flags=0 NXM,OXM' \
+ 'tun_gpe_flags=0/0x1 NXM,OXM' \
'tun_metadata0=0 NXM,OXM' \
'tun_metadata0=0/0x1 NXM,OXM' \
'tun_metadata0 NXM,OXM' \
--
1.9.3

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,264 @@
From e6f9b1f96a3ac4066c9d7d4c0a9da7e8abb1597f Mon Sep 17 00:00:00 2001
From: Yi Yang <yi.y.yang@intel.com>
Date: Wed, 13 Apr 2016 18:17:21 +0800
Subject: [PATCH 4/5] Fix too large stack frame size
Signed-off-by: Yi Yang <yi.y.yang@intel.com>
---
datapath/datapath.c | 92 +++++++++++++++++++++++++++++++++++++++++++++--------
1 file changed, 78 insertions(+), 14 deletions(-)
diff --git a/datapath/datapath.c b/datapath/datapath.c
index 5bec072..4baf242 100644
--- a/datapath/datapath.c
+++ b/datapath/datapath.c
@@ -928,7 +928,7 @@ static int ovs_flow_cmd_new(struct sk_buff *skb, struct genl_info *info)
struct sw_flow_mask mask;
struct sk_buff *reply;
struct datapath *dp;
- struct sw_flow_key key;
+ struct sw_flow_key *key = NULL;
struct sw_flow_actions *acts;
struct sw_flow_match match;
u32 ufid_flags = ovs_nla_get_ufid_flags(a[OVS_FLOW_ATTR_UFID_FLAGS]);
@@ -946,6 +946,12 @@ static int ovs_flow_cmd_new(struct sk_buff *skb, struct genl_info *info)
goto error;
}
+ error = -ENOMEM;
+ key = kzalloc(sizeof(struct sw_flow_key), GFP_KERNEL);
+ if (key == NULL) {
+ goto error;
+ }
+
/* Most of the time we need to allocate a new flow, do it before
* locking.
*/
@@ -956,17 +962,17 @@ static int ovs_flow_cmd_new(struct sk_buff *skb, struct genl_info *info)
}
/* Extract key. */
- ovs_match_init(&match, &key, &mask);
+ ovs_match_init(&match, key, &mask);
error = ovs_nla_get_match(net, &match, a[OVS_FLOW_ATTR_KEY],
a[OVS_FLOW_ATTR_MASK], log);
if (error)
goto err_kfree_flow;
- ovs_flow_mask_key(&new_flow->key, &key, true, &mask);
+ ovs_flow_mask_key(&new_flow->key, key, true, &mask);
/* Extract flow identifier. */
error = ovs_nla_get_identifier(&new_flow->id, a[OVS_FLOW_ATTR_UFID],
- &key, log);
+ key, log);
if (error)
goto err_kfree_flow;
@@ -996,7 +1002,7 @@ static int ovs_flow_cmd_new(struct sk_buff *skb, struct genl_info *info)
if (ovs_identifier_is_ufid(&new_flow->id))
flow = ovs_flow_tbl_lookup_ufid(&dp->table, &new_flow->id);
if (!flow)
- flow = ovs_flow_tbl_lookup(&dp->table, &key);
+ flow = ovs_flow_tbl_lookup(&dp->table, key);
if (likely(!flow)) {
rcu_assign_pointer(new_flow->sf_acts, acts);
@@ -1066,6 +1072,10 @@ static int ovs_flow_cmd_new(struct sk_buff *skb, struct genl_info *info)
if (reply)
ovs_notify(&dp_flow_genl_family, &ovs_dp_flow_multicast_group, reply, info);
+ if (key != NULL) {
+ kfree(key);
+ key = NULL;
+ }
return 0;
err_unlock_ovs:
@@ -1076,6 +1086,10 @@ err_kfree_acts:
err_kfree_flow:
ovs_flow_free(new_flow, false);
error:
+ if (key != NULL) {
+ kfree(key);
+ key = NULL;
+ }
return error;
}
@@ -1106,7 +1120,7 @@ static int ovs_flow_cmd_set(struct sk_buff *skb, struct genl_info *info)
struct net *net = sock_net(skb->sk);
struct nlattr **a = info->attrs;
struct ovs_header *ovs_header = info->userhdr;
- struct sw_flow_key key;
+ struct sw_flow_key *key = NULL;
struct sw_flow *flow;
struct sw_flow_mask mask;
struct sk_buff *reply = NULL;
@@ -1119,6 +1133,12 @@ static int ovs_flow_cmd_set(struct sk_buff *skb, struct genl_info *info)
bool log = !a[OVS_FLOW_ATTR_PROBE];
bool ufid_present;
+ error = -ENOMEM;
+ key = kzalloc(sizeof(struct sw_flow_key), GFP_KERNEL);
+ if (key == NULL) {
+ goto error;
+ }
+
/* Extract key. */
error = -EINVAL;
if (!a[OVS_FLOW_ATTR_KEY]) {
@@ -1127,7 +1147,7 @@ static int ovs_flow_cmd_set(struct sk_buff *skb, struct genl_info *info)
}
ufid_present = ovs_nla_get_ufid(&sfid, a[OVS_FLOW_ATTR_UFID], log);
- ovs_match_init(&match, &key, &mask);
+ ovs_match_init(&match, key, &mask);
error = ovs_nla_get_match(net, &match, a[OVS_FLOW_ATTR_KEY],
a[OVS_FLOW_ATTR_MASK], log);
if (error)
@@ -1135,7 +1155,7 @@ static int ovs_flow_cmd_set(struct sk_buff *skb, struct genl_info *info)
/* Validate actions. */
if (a[OVS_FLOW_ATTR_ACTIONS]) {
- acts = get_flow_actions(net, a[OVS_FLOW_ATTR_ACTIONS], &key,
+ acts = get_flow_actions(net, a[OVS_FLOW_ATTR_ACTIONS], key,
&mask, log);
if (IS_ERR(acts)) {
error = PTR_ERR(acts);
@@ -1203,6 +1223,10 @@ static int ovs_flow_cmd_set(struct sk_buff *skb, struct genl_info *info)
if (old_acts)
ovs_nla_free_flow_actions_rcu(old_acts);
+ if (key != NULL) {
+ kfree(key);
+ key = NULL;
+ }
return 0;
err_unlock_ovs:
@@ -1211,6 +1235,10 @@ err_unlock_ovs:
err_kfree_acts:
ovs_nla_free_flow_actions(acts);
error:
+ if (key != NULL) {
+ kfree(key);
+ key = NULL;
+ }
return error;
}
@@ -1219,7 +1247,7 @@ static int ovs_flow_cmd_get(struct sk_buff *skb, struct genl_info *info)
struct nlattr **a = info->attrs;
struct ovs_header *ovs_header = info->userhdr;
struct net *net = sock_net(skb->sk);
- struct sw_flow_key key;
+ struct sw_flow_key *key = NULL;
struct sk_buff *reply;
struct sw_flow *flow;
struct datapath *dp;
@@ -1230,9 +1258,15 @@ static int ovs_flow_cmd_get(struct sk_buff *skb, struct genl_info *info)
bool log = !a[OVS_FLOW_ATTR_PROBE];
bool ufid_present;
+ err = -ENOMEM;
+ key = kzalloc(sizeof(struct sw_flow_key), GFP_KERNEL);
+ if (key == NULL) {
+ return err;
+ }
+
ufid_present = ovs_nla_get_ufid(&ufid, a[OVS_FLOW_ATTR_UFID], log);
if (a[OVS_FLOW_ATTR_KEY]) {
- ovs_match_init(&match, &key, NULL);
+ ovs_match_init(&match, key, NULL);
err = ovs_nla_get_match(net, &match, a[OVS_FLOW_ATTR_KEY], NULL,
log);
} else if (!ufid_present) {
@@ -1240,9 +1274,13 @@ static int ovs_flow_cmd_get(struct sk_buff *skb, struct genl_info *info)
"Flow get message rejected, Key attribute missing.");
err = -EINVAL;
}
- if (err)
+ if (err) {
+ if (key != NULL) {
+ kfree(key);
+ key = NULL;
+ }
return err;
-
+ }
ovs_lock();
dp = get_dp(sock_net(skb->sk), ovs_header->dp_ifindex);
if (!dp) {
@@ -1267,9 +1305,17 @@ static int ovs_flow_cmd_get(struct sk_buff *skb, struct genl_info *info)
}
ovs_unlock();
+ if (key != NULL) {
+ kfree(key);
+ key = NULL;
+ }
return genlmsg_reply(reply, info);
unlock:
ovs_unlock();
+ if (key != NULL) {
+ kfree(key);
+ key = NULL;
+ }
return err;
}
@@ -1278,7 +1324,7 @@ static int ovs_flow_cmd_del(struct sk_buff *skb, struct genl_info *info)
struct nlattr **a = info->attrs;
struct ovs_header *ovs_header = info->userhdr;
struct net *net = sock_net(skb->sk);
- struct sw_flow_key key;
+ struct sw_flow_key *key = NULL;
struct sk_buff *reply;
struct sw_flow *flow = NULL;
struct datapath *dp;
@@ -1289,12 +1335,22 @@ static int ovs_flow_cmd_del(struct sk_buff *skb, struct genl_info *info)
bool log = !a[OVS_FLOW_ATTR_PROBE];
bool ufid_present;
+ err = -ENOMEM;
+ key = kzalloc(sizeof(struct sw_flow_key), GFP_KERNEL);
+ if (key == NULL) {
+ return err;
+ }
+
ufid_present = ovs_nla_get_ufid(&ufid, a[OVS_FLOW_ATTR_UFID], log);
if (a[OVS_FLOW_ATTR_KEY]) {
- ovs_match_init(&match, &key, NULL);
+ ovs_match_init(&match, key, NULL);
err = ovs_nla_get_match(net, &match, a[OVS_FLOW_ATTR_KEY],
NULL, log);
if (unlikely(err))
+ if (key != NULL) {
+ kfree(key);
+ key = NULL;
+ }
return err;
}
@@ -1344,9 +1400,17 @@ static int ovs_flow_cmd_del(struct sk_buff *skb, struct genl_info *info)
}
ovs_flow_free(flow, true);
+ if (key != NULL) {
+ kfree(key);
+ key = NULL;
+ }
return 0;
unlock:
ovs_unlock();
+ if (key != NULL) {
+ kfree(key);
+ key = NULL;
+ }
return err;
}
--
1.9.3

View File

@ -0,0 +1,815 @@
<!DOCTYPE html>
<html lang="en" class="">
<head prefix="og: http://ogp.me/ns# fb: http://ogp.me/ns/fb# object: http://ogp.me/ns/object# article: http://ogp.me/ns/article# profile: http://ogp.me/ns/profile#">
<meta charset='utf-8'>
<link crossorigin="anonymous" href="https://assets-cdn.github.com/assets/frameworks-536bcdee57776d99649d118d29a291c9d7b41d101696162d6456c87b07314253.css" media="all" rel="stylesheet" />
<link crossorigin="anonymous" href="https://assets-cdn.github.com/assets/github-62cdd177894e003285e5b8b6fa72b4a92fb79f11a1ec44c2f2ae0f6f4ad2e724.css" media="all" rel="stylesheet" />
<link crossorigin="anonymous" href="https://assets-cdn.github.com/assets/site-c4b4365da282e51c06e107368db8502a2ecf82e64094d29d791b797372212de2.css" media="all" rel="stylesheet" />
<link as="script" href="https://assets-cdn.github.com/assets/frameworks-b0aaa1e644508a5d5c3f7509d91f5f950c180e1d933a999f21747c5ec5411d92.js" rel="preload" />
<link as="script" href="https://assets-cdn.github.com/assets/github-7c9ed6fd84382ad236d74c9ec5853f75fca061537cb1914241807b12c289216e.js" rel="preload" />
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta http-equiv="Content-Language" content="en">
<meta name="viewport" content="width=device-width">
<title>ovs_nsh_patches/0005-Ethernet-header-must-be-kept-in-VxLAN-gpe-eth-NSH-fo.patch at master · yyang13/ovs_nsh_patches · GitHub</title>
<link rel="search" type="application/opensearchdescription+xml" href="/opensearch.xml" title="GitHub">
<link rel="fluid-icon" href="https://github.com/fluidicon.png" title="GitHub">
<link rel="apple-touch-icon" href="/apple-touch-icon.png">
<link rel="apple-touch-icon" sizes="57x57" href="/apple-touch-icon-57x57.png">
<link rel="apple-touch-icon" sizes="60x60" href="/apple-touch-icon-60x60.png">
<link rel="apple-touch-icon" sizes="72x72" href="/apple-touch-icon-72x72.png">
<link rel="apple-touch-icon" sizes="76x76" href="/apple-touch-icon-76x76.png">
<link rel="apple-touch-icon" sizes="114x114" href="/apple-touch-icon-114x114.png">
<link rel="apple-touch-icon" sizes="120x120" href="/apple-touch-icon-120x120.png">
<link rel="apple-touch-icon" sizes="144x144" href="/apple-touch-icon-144x144.png">
<link rel="apple-touch-icon" sizes="152x152" href="/apple-touch-icon-152x152.png">
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon-180x180.png">
<meta property="fb:app_id" content="1401488693436528">
<meta content="https://avatars0.githubusercontent.com/u/1381010?v=3&amp;s=400" name="twitter:image:src" /><meta content="@github" name="twitter:site" /><meta content="summary" name="twitter:card" /><meta content="yyang13/ovs_nsh_patches" name="twitter:title" /><meta content="Contribute to ovs_nsh_patches development by creating an account on GitHub." name="twitter:description" />
<meta content="https://avatars0.githubusercontent.com/u/1381010?v=3&amp;s=400" property="og:image" /><meta content="GitHub" property="og:site_name" /><meta content="object" property="og:type" /><meta content="yyang13/ovs_nsh_patches" property="og:title" /><meta content="https://github.com/yyang13/ovs_nsh_patches" property="og:url" /><meta content="Contribute to ovs_nsh_patches development by creating an account on GitHub." property="og:description" />
<meta name="browser-stats-url" content="https://api.github.com/_private/browser/stats">
<meta name="browser-errors-url" content="https://api.github.com/_private/browser/errors">
<link rel="assets" href="https://assets-cdn.github.com/">
<meta name="pjax-timeout" content="1000">
<meta name="msapplication-TileImage" content="/windows-tile.png">
<meta name="msapplication-TileColor" content="#ffffff">
<meta name="selected-link" value="repo_source" data-pjax-transient>
<meta name="google-site-verification" content="KT5gs8h0wvaagLKAVWq8bbeNwnZZK1r1XQysX3xurLU">
<meta name="google-site-verification" content="ZzhVyEFwb7w3e0-uOTltm8Jsck2F5StVihD0exw2fsA">
<meta name="google-analytics" content="UA-3769691-2">
<meta content="collector.githubapp.com" name="octolytics-host" /><meta content="github" name="octolytics-app-id" /><meta content="C0C69725:55E6:90FE12E:57427806" name="octolytics-dimension-request_id" />
<meta content="/&lt;user-name&gt;/&lt;repo-name&gt;/blob/show" data-pjax-transient="true" name="analytics-location" />
<meta class="js-ga-set" name="dimension1" content="Logged Out">
<meta name="hostname" content="github.com">
<meta name="user-login" content="">
<meta name="expected-hostname" content="github.com">
<meta name="js-proxy-site-detection-payload" content="OWZlYzg2YjY2MGNkZWMzYWIyMjEyODRmYjUxZDc3NDQ2NmZiMDU4MjIzOTM0YTM0M2QxN2UxMDI5ZThiYmMwZnx7InJlbW90ZV9hZGRyZXNzIjoiMTkyLjE5OC4xNTEuMzciLCJyZXF1ZXN0X2lkIjoiQzBDNjk3MjU6NTVFNjo5MEZFMTJFOjU3NDI3ODA2IiwidGltZXN0YW1wIjoxNDYzOTczODk5fQ==">
<link rel="mask-icon" href="https://assets-cdn.github.com/pinned-octocat.svg" color="#4078c0">
<link rel="icon" type="image/x-icon" href="https://assets-cdn.github.com/favicon.ico">
<meta name="html-safe-nonce" content="d5a3f38662558f7acd81904f7ac14af9db6f4815">
<meta content="336822eb21d878aecfe61a4b1500927049b82186" name="form-nonce" />
<meta http-equiv="x-pjax-version" content="7af64f947f90d1be70195bdfb0943dda">
<meta name="description" content="Contribute to ovs_nsh_patches development by creating an account on GitHub.">
<meta name="go-import" content="github.com/yyang13/ovs_nsh_patches git https://github.com/yyang13/ovs_nsh_patches.git">
<meta content="1381010" name="octolytics-dimension-user_id" /><meta content="yyang13" name="octolytics-dimension-user_login" /><meta content="55125011" name="octolytics-dimension-repository_id" /><meta content="yyang13/ovs_nsh_patches" name="octolytics-dimension-repository_nwo" /><meta content="true" name="octolytics-dimension-repository_public" /><meta content="false" name="octolytics-dimension-repository_is_fork" /><meta content="55125011" name="octolytics-dimension-repository_network_root_id" /><meta content="yyang13/ovs_nsh_patches" name="octolytics-dimension-repository_network_root_nwo" />
<link href="https://github.com/yyang13/ovs_nsh_patches/commits/master.atom" rel="alternate" title="Recent Commits to ovs_nsh_patches:master" type="application/atom+xml">
<link rel="canonical" href="https://github.com/yyang13/ovs_nsh_patches/blob/master/0005-Ethernet-header-must-be-kept-in-VxLAN-gpe-eth-NSH-fo.patch" data-pjax-transient>
</head>
<body class="logged-out env-production vis-public page-blob">
<div id="js-pjax-loader-bar" class="pjax-loader-bar"></div>
<a href="#start-of-content" tabindex="1" class="accessibility-aid js-skip-to-content">Skip to content</a>
<header class="site-header js-details-container" role="banner">
<div class="container-responsive">
<a class="header-logo-invertocat" href="https://github.com/" aria-label="Homepage" data-ga-click="(Logged out) Header, go to homepage, icon:logo-wordmark">
<svg aria-hidden="true" class="octicon octicon-mark-github" height="32" version="1.1" viewBox="0 0 16 16" width="32"><path d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59 0.4 0.07 0.55-0.17 0.55-0.38 0-0.19-0.01-0.82-0.01-1.49-2.01 0.37-2.53-0.49-2.69-0.94-0.09-0.23-0.48-0.94-0.82-1.13-0.28-0.15-0.68-0.52-0.01-0.53 0.63-0.01 1.08 0.58 1.23 0.82 0.72 1.21 1.87 0.87 2.33 0.66 0.07-0.52 0.28-0.87 0.51-1.07-1.78-0.2-3.64-0.89-3.64-3.95 0-0.87 0.31-1.59 0.82-2.15-0.08-0.2-0.36-1.02 0.08-2.12 0 0 0.67-0.21 2.2 0.82 0.64-0.18 1.32-0.27 2-0.27 0.68 0 1.36 0.09 2 0.27 1.53-1.04 2.2-0.82 2.2-0.82 0.44 1.1 0.16 1.92 0.08 2.12 0.51 0.56 0.82 1.27 0.82 2.15 0 3.07-1.87 3.75-3.65 3.95 0.29 0.25 0.54 0.73 0.54 1.48 0 1.07-0.01 1.93-0.01 2.2 0 0.21 0.15 0.46 0.55 0.38C13.71 14.53 16 11.53 16 8 16 3.58 12.42 0 8 0z"></path></svg>
</a>
<button class="btn-link right site-header-toggle js-details-target" type="button" aria-label="Toggle navigation">
<svg aria-hidden="true" class="octicon octicon-three-bars" height="24" version="1.1" viewBox="0 0 12 16" width="18"><path d="M11.41 9H0.59c-0.59 0-0.59-0.41-0.59-1s0-1 0.59-1h10.81c0.59 0 0.59 0.41 0.59 1s0 1-0.59 1z m0-4H0.59c-0.59 0-0.59-0.41-0.59-1s0-1 0.59-1h10.81c0.59 0 0.59 0.41 0.59 1s0 1-0.59 1zM0.59 11h10.81c0.59 0 0.59 0.41 0.59 1s0 1-0.59 1H0.59c-0.59 0-0.59-0.41-0.59-1s0-1 0.59-1z"></path></svg>
</button>
<div class="site-header-menu">
<nav class="site-header-nav site-header-nav-main">
<a href="/personal" class="js-selected-navigation-item nav-item nav-item-personal" data-ga-click="Header, click, Nav menu - item:personal" data-selected-links="/personal /personal">
Personal
</a> <a href="/open-source" class="js-selected-navigation-item nav-item nav-item-opensource" data-ga-click="Header, click, Nav menu - item:opensource" data-selected-links="/open-source /open-source">
Open source
</a> <a href="/business" class="js-selected-navigation-item nav-item nav-item-business" data-ga-click="Header, click, Nav menu - item:business" data-selected-links="/business /business/features /business/customers /business">
Business
</a> <a href="/explore" class="js-selected-navigation-item nav-item nav-item-explore" data-ga-click="Header, click, Nav menu - item:explore" data-selected-links="/explore /trending /trending/developers /integrations /integrations/feature/code /integrations/feature/collaborate /integrations/feature/ship /explore">
Explore
</a> </nav>
<div class="site-header-actions">
<a class="btn btn-primary site-header-actions-btn" href="/join?source=header-repo" data-ga-click="(Logged out) Header, clicked Sign up, text:sign-up">Sign up</a>
<a class="btn site-header-actions-btn mr-2" href="/login?return_to=%2Fyyang13%2Fovs_nsh_patches%2Fblob%2Fmaster%2F0005-Ethernet-header-must-be-kept-in-VxLAN-gpe-eth-NSH-fo.patch" data-ga-click="(Logged out) Header, clicked Sign in, text:sign-in">Sign in</a>
</div>
<nav class="site-header-nav site-header-nav-secondary">
<a class="nav-item" href="/pricing">Pricing</a>
<a class="nav-item" href="/blog">Blog</a>
<a class="nav-item" href="https://help.github.com">Support</a>
<a class="nav-item header-search-link" href="https://github.com/search">Search GitHub</a>
<div class="header-search scoped-search site-scoped-search js-site-search" role="search">
<!-- </textarea> --><!-- '"` --><form accept-charset="UTF-8" action="/yyang13/ovs_nsh_patches/search" class="js-site-search-form" data-scoped-search-url="/yyang13/ovs_nsh_patches/search" data-unscoped-search-url="/search" method="get"><div style="margin:0;padding:0;display:inline"><input name="utf8" type="hidden" value="&#x2713;" /></div>
<label class="form-control header-search-wrapper js-chromeless-input-container">
<div class="header-search-scope">This repository</div>
<input type="text"
class="form-control header-search-input js-site-search-focus js-site-search-field is-clearable"
data-hotkey="s"
name="q"
placeholder="Search"
aria-label="Search this repository"
data-unscoped-placeholder="Search GitHub"
data-scoped-placeholder="Search"
tabindex="1"
autocapitalize="off">
</label>
</form></div>
</nav>
</div>
</div>
</header>
<div id="start-of-content" class="accessibility-aid"></div>
<div id="js-flash-container">
</div>
<div role="main" class="main-content">
<div itemscope itemtype="http://schema.org/SoftwareSourceCode">
<div id="js-repo-pjax-container" data-pjax-container>
<div class="pagehead repohead instapaper_ignore readability-menu experiment-repo-nav">
<div class="container repohead-details-container">
<ul class="pagehead-actions">
<li>
<a href="/login?return_to=%2Fyyang13%2Fovs_nsh_patches"
class="btn btn-sm btn-with-count tooltipped tooltipped-n"
aria-label="You must be signed in to watch a repository" rel="nofollow">
<svg aria-hidden="true" class="octicon octicon-eye" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path d="M8.06 2C3 2 0 8 0 8s3 6 8.06 6c4.94 0 7.94-6 7.94-6S13 2 8.06 2z m-0.06 10c-2.2 0-4-1.78-4-4 0-2.2 1.8-4 4-4 2.22 0 4 1.8 4 4 0 2.22-1.78 4-4 4z m2-4c0 1.11-0.89 2-2 2s-2-0.89-2-2 0.89-2 2-2 2 0.89 2 2z"></path></svg>
Watch
</a>
<a class="social-count" href="/yyang13/ovs_nsh_patches/watchers">
3
</a>
</li>
<li>
<a href="/login?return_to=%2Fyyang13%2Fovs_nsh_patches"
class="btn btn-sm btn-with-count tooltipped tooltipped-n"
aria-label="You must be signed in to star a repository" rel="nofollow">
<svg aria-hidden="true" class="octicon octicon-star" height="16" version="1.1" viewBox="0 0 14 16" width="14"><path d="M14 6l-4.9-0.64L7 1 4.9 5.36 0 6l3.6 3.26L2.67 14l4.33-2.33 4.33 2.33L10.4 9.26 14 6z"></path></svg>
Star
</a>
<a class="social-count js-social-count" href="/yyang13/ovs_nsh_patches/stargazers">
3
</a>
</li>
<li>
<a href="/login?return_to=%2Fyyang13%2Fovs_nsh_patches"
class="btn btn-sm btn-with-count tooltipped tooltipped-n"
aria-label="You must be signed in to fork a repository" rel="nofollow">
<svg aria-hidden="true" class="octicon octicon-repo-forked" height="16" version="1.1" viewBox="0 0 10 16" width="10"><path d="M8 1c-1.11 0-2 0.89-2 2 0 0.73 0.41 1.38 1 1.72v1.28L5 8 3 6v-1.28c0.59-0.34 1-0.98 1-1.72 0-1.11-0.89-2-2-2S0 1.89 0 3c0 0.73 0.41 1.38 1 1.72v1.78l3 3v1.78c-0.59 0.34-1 0.98-1 1.72 0 1.11 0.89 2 2 2s2-0.89 2-2c0-0.73-0.41-1.38-1-1.72V9.5l3-3V4.72c0.59-0.34 1-0.98 1-1.72 0-1.11-0.89-2-2-2zM2 4.2c-0.66 0-1.2-0.55-1.2-1.2s0.55-1.2 1.2-1.2 1.2 0.55 1.2 1.2-0.55 1.2-1.2 1.2z m3 10c-0.66 0-1.2-0.55-1.2-1.2s0.55-1.2 1.2-1.2 1.2 0.55 1.2 1.2-0.55 1.2-1.2 1.2z m3-10c-0.66 0-1.2-0.55-1.2-1.2s0.55-1.2 1.2-1.2 1.2 0.55 1.2 1.2-0.55 1.2-1.2 1.2z"></path></svg>
Fork
</a>
<a href="/yyang13/ovs_nsh_patches/network" class="social-count">
2
</a>
</li>
</ul>
<h1 class="entry-title public ">
<svg aria-hidden="true" class="octicon octicon-repo" height="16" version="1.1" viewBox="0 0 12 16" width="12"><path d="M4 9h-1v-1h1v1z m0-3h-1v1h1v-1z m0-2h-1v1h1v-1z m0-2h-1v1h1v-1z m8-1v12c0 0.55-0.45 1-1 1H6v2l-1.5-1.5-1.5 1.5V14H1c-0.55 0-1-0.45-1-1V1C0 0.45 0.45 0 1 0h10c0.55 0 1 0.45 1 1z m-1 10H1v2h2v-1h3v1h5V11z m0-10H2v9h9V1z"></path></svg>
<span class="author" itemprop="author"><a href="/yyang13" class="url fn" rel="author">yyang13</a></span><!--
--><span class="path-divider">/</span><!--
--><strong itemprop="name"><a href="/yyang13/ovs_nsh_patches" data-pjax="#js-repo-pjax-container">ovs_nsh_patches</a></strong>
</h1>
</div>
<div class="container">
<nav class="reponav js-repo-nav js-sidenav-container-pjax"
itemscope
itemtype="http://schema.org/BreadcrumbList"
role="navigation"
data-pjax="#js-repo-pjax-container">
<span itemscope itemtype="http://schema.org/ListItem" itemprop="itemListElement">
<a href="/yyang13/ovs_nsh_patches" aria-selected="true" class="js-selected-navigation-item selected reponav-item" data-hotkey="g c" data-selected-links="repo_source repo_downloads repo_commits repo_releases repo_tags repo_branches /yyang13/ovs_nsh_patches" itemprop="url">
<svg aria-hidden="true" class="octicon octicon-code" height="16" version="1.1" viewBox="0 0 14 16" width="14"><path d="M9.5 3l-1.5 1.5 3.5 3.5L8 11.5l1.5 1.5 4.5-5L9.5 3zM4.5 3L0 8l4.5 5 1.5-1.5L2.5 8l3.5-3.5L4.5 3z"></path></svg>
<span itemprop="name">Code</span>
<meta itemprop="position" content="1">
</a> </span>
<span itemscope itemtype="http://schema.org/ListItem" itemprop="itemListElement">
<a href="/yyang13/ovs_nsh_patches/issues" class="js-selected-navigation-item reponav-item" data-hotkey="g i" data-selected-links="repo_issues repo_labels repo_milestones /yyang13/ovs_nsh_patches/issues" itemprop="url">
<svg aria-hidden="true" class="octicon octicon-issue-opened" height="16" version="1.1" viewBox="0 0 14 16" width="14"><path d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7S10.14 13.7 7 13.7 1.3 11.14 1.3 8s2.56-5.7 5.7-5.7m0-1.3C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7S10.86 1 7 1z m1 3H6v5h2V4z m0 6H6v2h2V10z"></path></svg>
<span itemprop="name">Issues</span>
<span class="counter">1</span>
<meta itemprop="position" content="2">
</a> </span>
<span itemscope itemtype="http://schema.org/ListItem" itemprop="itemListElement">
<a href="/yyang13/ovs_nsh_patches/pulls" class="js-selected-navigation-item reponav-item" data-hotkey="g p" data-selected-links="repo_pulls /yyang13/ovs_nsh_patches/pulls" itemprop="url">
<svg aria-hidden="true" class="octicon octicon-git-pull-request" height="16" version="1.1" viewBox="0 0 12 16" width="12"><path d="M11 11.28c0-1.73 0-6.28 0-6.28-0.03-0.78-0.34-1.47-0.94-2.06s-1.28-0.91-2.06-0.94c0 0-1.02 0-1 0V0L4 3l3 3V4h1c0.27 0.02 0.48 0.11 0.69 0.31s0.3 0.42 0.31 0.69v6.28c-0.59 0.34-1 0.98-1 1.72 0 1.11 0.89 2 2 2s2-0.89 2-2c0-0.73-0.41-1.38-1-1.72z m-1 2.92c-0.66 0-1.2-0.55-1.2-1.2s0.55-1.2 1.2-1.2 1.2 0.55 1.2 1.2-0.55 1.2-1.2 1.2zM4 3c0-1.11-0.89-2-2-2S0 1.89 0 3c0 0.73 0.41 1.38 1 1.72 0 1.55 0 5.56 0 6.56-0.59 0.34-1 0.98-1 1.72 0 1.11 0.89 2 2 2s2-0.89 2-2c0-0.73-0.41-1.38-1-1.72V4.72c0.59-0.34 1-0.98 1-1.72z m-0.8 10c0 0.66-0.55 1.2-1.2 1.2s-1.2-0.55-1.2-1.2 0.55-1.2 1.2-1.2 1.2 0.55 1.2 1.2z m-1.2-8.8c-0.66 0-1.2-0.55-1.2-1.2s0.55-1.2 1.2-1.2 1.2 0.55 1.2 1.2-0.55 1.2-1.2 1.2z"></path></svg>
<span itemprop="name">Pull requests</span>
<span class="counter">0</span>
<meta itemprop="position" content="3">
</a> </span>
<a href="/yyang13/ovs_nsh_patches/pulse" class="js-selected-navigation-item reponav-item" data-selected-links="pulse /yyang13/ovs_nsh_patches/pulse">
<svg aria-hidden="true" class="octicon octicon-pulse" height="16" version="1.1" viewBox="0 0 14 16" width="14"><path d="M11.5 8L8.8 5.4 6.6 8.5 5.5 1.6 2.38 8H0V10h3.6L4.5 8.2l0.9 5.4L9 8.5l1.6 1.5H14V8H11.5z"></path></svg>
Pulse
</a>
<a href="/yyang13/ovs_nsh_patches/graphs" class="js-selected-navigation-item reponav-item" data-selected-links="repo_graphs repo_contributors /yyang13/ovs_nsh_patches/graphs">
<svg aria-hidden="true" class="octicon octicon-graph" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path d="M16 14v1H0V0h1v14h15z m-11-1H3V8h2v5z m4 0H7V3h2v10z m4 0H11V6h2v7z"></path></svg>
Graphs
</a>
</nav>
</div>
</div>
<div class="container new-discussion-timeline experiment-repo-nav">
<div class="repository-content">
<a href="/yyang13/ovs_nsh_patches/blob/98e1d3d6b1ed49d902edaede11820853b0ad5037/0005-Ethernet-header-must-be-kept-in-VxLAN-gpe-eth-NSH-fo.patch" class="hidden js-permalink-shortcut" data-hotkey="y">Permalink</a>
<!-- blob contrib key: blob_contributors:v21:9e16b7492ae4319416c7dc2e26b52f73 -->
<div class="file-navigation js-zeroclipboard-container">
<div class="select-menu branch-select-menu js-menu-container js-select-menu left">
<button class="btn btn-sm select-menu-button js-menu-target css-truncate" data-hotkey="w"
title="master"
type="button" aria-label="Switch branches or tags" tabindex="0" aria-haspopup="true">
<i>Branch:</i>
<span class="js-select-button css-truncate-target">master</span>
</button>
<div class="select-menu-modal-holder js-menu-content js-navigation-container" data-pjax aria-hidden="true">
<div class="select-menu-modal">
<div class="select-menu-header">
<svg aria-label="Close" class="octicon octicon-x js-menu-close" height="16" role="img" version="1.1" viewBox="0 0 12 16" width="12"><path d="M7.48 8l3.75 3.75-1.48 1.48-3.75-3.75-3.75 3.75-1.48-1.48 3.75-3.75L0.77 4.25l1.48-1.48 3.75 3.75 3.75-3.75 1.48 1.48-3.75 3.75z"></path></svg>
<span class="select-menu-title">Switch branches/tags</span>
</div>
<div class="select-menu-filters">
<div class="select-menu-text-filter">
<input type="text" aria-label="Filter branches/tags" id="context-commitish-filter-field" class="form-control js-filterable-field js-navigation-enable" placeholder="Filter branches/tags">
</div>
<div class="select-menu-tabs">
<ul>
<li class="select-menu-tab">
<a href="#" data-tab-filter="branches" data-filter-placeholder="Filter branches/tags" class="js-select-menu-tab" role="tab">Branches</a>
</li>
<li class="select-menu-tab">
<a href="#" data-tab-filter="tags" data-filter-placeholder="Find a tag…" class="js-select-menu-tab" role="tab">Tags</a>
</li>
</ul>
</div>
</div>
<div class="select-menu-list select-menu-tab-bucket js-select-menu-tab-bucket" data-tab-filter="branches" role="menu">
<div data-filterable-for="context-commitish-filter-field" data-filterable-type="substring">
<a class="select-menu-item js-navigation-item js-navigation-open selected"
href="/yyang13/ovs_nsh_patches/blob/master/0005-Ethernet-header-must-be-kept-in-VxLAN-gpe-eth-NSH-fo.patch"
data-name="master"
data-skip-pjax="true"
rel="nofollow">
<svg aria-hidden="true" class="octicon octicon-check select-menu-item-icon" height="16" version="1.1" viewBox="0 0 12 16" width="12"><path d="M12 5L4 13 0 9l1.5-1.5 2.5 2.5 6.5-6.5 1.5 1.5z"></path></svg>
<span class="select-menu-item-text css-truncate-target js-select-menu-filter-text" title="master">
master
</span>
</a>
</div>
<div class="select-menu-no-results">Nothing to show</div>
</div>
<div class="select-menu-list select-menu-tab-bucket js-select-menu-tab-bucket" data-tab-filter="tags">
<div data-filterable-for="context-commitish-filter-field" data-filterable-type="substring">
</div>
<div class="select-menu-no-results">Nothing to show</div>
</div>
</div>
</div>
</div>
<div class="btn-group right">
<a href="/yyang13/ovs_nsh_patches/find/master"
class="js-pjax-capture-input btn btn-sm"
data-pjax
data-hotkey="t">
Find file
</a>
<button aria-label="Copy file path to clipboard" class="js-zeroclipboard btn btn-sm zeroclipboard-button tooltipped tooltipped-s" data-copied-hint="Copied!" type="button">Copy path</button>
</div>
<div class="breadcrumb js-zeroclipboard-target">
<span class="repo-root js-repo-root"><span class="js-path-segment"><a href="/yyang13/ovs_nsh_patches"><span>ovs_nsh_patches</span></a></span></span><span class="separator">/</span><strong class="final-path">0005-Ethernet-header-must-be-kept-in-VxLAN-gpe-eth-NSH-fo.patch</strong>
</div>
</div>
<div class="commit-tease">
<span class="right">
<a class="commit-tease-sha" href="/yyang13/ovs_nsh_patches/commit/9f8ad552bbfb7f9678f1b6195b2d2c0f34a38352" data-pjax>
9f8ad55
</a>
<relative-time datetime="2016-04-15T07:18:08Z">Apr 15, 2016</relative-time>
</span>
<div>
<img alt="" class="avatar" height="20" src="https://1.gravatar.com/avatar/4dbafb666390db3bde85995883557645?d=https%3A%2F%2Fassets-cdn.github.com%2Fimages%2Fgravatars%2Fgravatar-user-420.png&amp;r=x&amp;s=140" width="20" />
<span class="user-mention">Yi Yang</span>
<a href="/yyang13/ovs_nsh_patches/commit/9f8ad552bbfb7f9678f1b6195b2d2c0f34a38352" class="message" data-pjax="true" title="ovs nsh patches
Signed-off-by: Yi Yang &lt;yi.y.yang@intel.com&gt;">ovs nsh patches</a>
</div>
<div class="commit-tease-contributors">
<button type="button" class="btn-link muted-link contributors-toggle" data-facebox="#blob_contributors_box">
<strong>0</strong>
contributors
</button>
</div>
<div id="blob_contributors_box" style="display:none">
<h2 class="facebox-header" data-facebox-id="facebox-header">Users who have contributed to this file</h2>
<ul class="facebox-user-list" data-facebox-id="facebox-description">
</ul>
</div>
</div>
<div class="file">
<div class="file-header">
<div class="file-actions">
<div class="btn-group">
<a href="/yyang13/ovs_nsh_patches/raw/master/0005-Ethernet-header-must-be-kept-in-VxLAN-gpe-eth-NSH-fo.patch" class="btn btn-sm " id="raw-url">Raw</a>
<a href="/yyang13/ovs_nsh_patches/blame/master/0005-Ethernet-header-must-be-kept-in-VxLAN-gpe-eth-NSH-fo.patch" class="btn btn-sm js-update-url-with-hash">Blame</a>
<a href="/yyang13/ovs_nsh_patches/commits/master/0005-Ethernet-header-must-be-kept-in-VxLAN-gpe-eth-NSH-fo.patch" class="btn btn-sm " rel="nofollow">History</a>
</div>
<button type="button" class="btn-octicon disabled tooltipped tooltipped-nw"
aria-label="You must be signed in to make or propose changes">
<svg aria-hidden="true" class="octicon octicon-pencil" height="16" version="1.1" viewBox="0 0 14 16" width="14"><path d="M0 12v3h3l8-8-3-3L0 12z m3 2H1V12h1v1h1v1z m10.3-9.3l-1.3 1.3-3-3 1.3-1.3c0.39-0.39 1.02-0.39 1.41 0l1.59 1.59c0.39 0.39 0.39 1.02 0 1.41z"></path></svg>
</button>
<button type="button" class="btn-octicon btn-octicon-danger disabled tooltipped tooltipped-nw"
aria-label="You must be signed in to make or propose changes">
<svg aria-hidden="true" class="octicon octicon-trashcan" height="16" version="1.1" viewBox="0 0 12 16" width="12"><path d="M10 2H8c0-0.55-0.45-1-1-1H4c-0.55 0-1 0.45-1 1H1c-0.55 0-1 0.45-1 1v1c0 0.55 0.45 1 1 1v9c0 0.55 0.45 1 1 1h7c0.55 0 1-0.45 1-1V5c0.55 0 1-0.45 1-1v-1c0-0.55-0.45-1-1-1z m-1 12H2V5h1v8h1V5h1v8h1V5h1v8h1V5h1v9z m1-10H1v-1h9v1z"></path></svg>
</button>
</div>
<div class="file-info">
75 lines (61 sloc)
<span class="file-info-divider"></span>
2.85 KB
</div>
</div>
<div itemprop="text" class="blob-wrapper data type-diff">
<table class="highlight tab-size js-file-line-container" data-tab-size="8">
<tr>
<td id="L1" class="blob-num js-line-number" data-line-number="1"></td>
<td id="LC1" class="blob-code blob-code-inner js-file-line">From 604bcfaf5211513f665ca05a370bc7f0c0dab39f Mon Sep 17 00:00:00 2001</td>
</tr>
<tr>
<td id="L2" class="blob-num js-line-number" data-line-number="2"></td>
<td id="LC2" class="blob-code blob-code-inner js-file-line">From: Yi Yang &lt;yi.y.yang@intel.com&gt;</td>
</tr>
<tr>
<td id="L3" class="blob-num js-line-number" data-line-number="3"></td>
<td id="LC3" class="blob-code blob-code-inner js-file-line">Date: Fri, 15 Apr 2016 14:17:54 +0800</td>
</tr>
<tr>
<td id="L4" class="blob-num js-line-number" data-line-number="4"></td>
<td id="LC4" class="blob-code blob-code-inner js-file-line">Subject: [PATCH 5/5] Ethernet header must be kept in VxLAN-gpe + eth + NSH for</td>
</tr>
<tr>
<td id="L5" class="blob-num js-line-number" data-line-number="5"></td>
<td id="LC5" class="blob-code blob-code-inner js-file-line"> new ovs lwtunnel implementation</td>
</tr>
<tr>
<td id="L6" class="blob-num js-line-number" data-line-number="6"></td>
<td id="LC6" class="blob-code blob-code-inner js-file-line">
</td>
</tr>
<tr>
<td id="L7" class="blob-num js-line-number" data-line-number="7"></td>
<td id="LC7" class="blob-code blob-code-inner js-file-line">Signed-off-by: Yi Yang &lt;yi.y.yang@intel.com&gt;</td>
</tr>
<tr>
<td id="L8" class="blob-num js-line-number" data-line-number="8"></td>
<td id="LC8" class="blob-code blob-code-inner js-file-line"><span class="pl-ms">---</span></td>
</tr>
<tr>
<td id="L9" class="blob-num js-line-number" data-line-number="9"></td>
<td id="LC9" class="blob-code blob-code-inner js-file-line"> datapath/linux/compat/vxlan.c | 16 ++++++++++------</td>
</tr>
<tr>
<td id="L10" class="blob-num js-line-number" data-line-number="10"></td>
<td id="LC10" class="blob-code blob-code-inner js-file-line"> 1 file changed, 10 insertions(+), 6 deletions(-)</td>
</tr>
<tr>
<td id="L11" class="blob-num js-line-number" data-line-number="11"></td>
<td id="LC11" class="blob-code blob-code-inner js-file-line">
</td>
</tr>
<tr>
<td id="L12" class="blob-num js-line-number" data-line-number="12"></td>
<td id="LC12" class="blob-code blob-code-inner js-file-line"><span class="pl-c1">diff --git a/datapath/linux/compat/vxlan.c b/datapath/linux/compat/vxlan.c</span></td>
</tr>
<tr>
<td id="L13" class="blob-num js-line-number" data-line-number="13"></td>
<td id="LC13" class="blob-code blob-code-inner js-file-line">index 888d431..3c05141 100644</td>
</tr>
<tr>
<td id="L14" class="blob-num js-line-number" data-line-number="14"></td>
<td id="LC14" class="blob-code blob-code-inner js-file-line"><span class="pl-md">--- a/datapath/linux/compat/vxlan.c</span></td>
</tr>
<tr>
<td id="L15" class="blob-num js-line-number" data-line-number="15"></td>
<td id="LC15" class="blob-code blob-code-inner js-file-line"><span class="pl-mi1">+++ b/datapath/linux/compat/vxlan.c</span></td>
</tr>
<tr>
<td id="L16" class="blob-num js-line-number" data-line-number="16"></td>
<td id="LC16" class="blob-code blob-code-inner js-file-line"><span class="pl-mdr">@@ -821,7 +821,7 @@</span> static void vxlan_rcv(struct vxlan_sock *vs, struct sk_buff *skb,</td>
</tr>
<tr>
<td id="L17" class="blob-num js-line-number" data-line-number="17"></td>
<td id="LC17" class="blob-code blob-code-inner js-file-line"> struct vxlan_dev *vxlan;</td>
</tr>
<tr>
<td id="L18" class="blob-num js-line-number" data-line-number="18"></td>
<td id="LC18" class="blob-code blob-code-inner js-file-line"> struct pcpu_sw_netstats *stats;</td>
</tr>
<tr>
<td id="L19" class="blob-num js-line-number" data-line-number="19"></td>
<td id="LC19" class="blob-code blob-code-inner js-file-line"> union vxlan_addr saddr;</td>
</tr>
<tr>
<td id="L20" class="blob-num js-line-number" data-line-number="20"></td>
<td id="LC20" class="blob-code blob-code-inner js-file-line"><span class="pl-md">- struct eth_nsh_hdr *eth_nsh_header = NULL;</span></td>
</tr>
<tr>
<td id="L21" class="blob-num js-line-number" data-line-number="21"></td>
<td id="LC21" class="blob-code blob-code-inner js-file-line"><span class="pl-mi1">+ //struct eth_nsh_hdr *eth_nsh_header = NULL;</span></td>
</tr>
<tr>
<td id="L22" class="blob-num js-line-number" data-line-number="22"></td>
<td id="LC22" class="blob-code blob-code-inner js-file-line"> int err = 0;</td>
</tr>
<tr>
<td id="L23" class="blob-num js-line-number" data-line-number="23"></td>
<td id="LC23" class="blob-code blob-code-inner js-file-line"> </td>
</tr>
<tr>
<td id="L24" class="blob-num js-line-number" data-line-number="24"></td>
<td id="LC24" class="blob-code blob-code-inner js-file-line"> /* For flow based devices, map all packets to VNI 0 */</td>
</tr>
<tr>
<td id="L25" class="blob-num js-line-number" data-line-number="25"></td>
<td id="LC25" class="blob-code blob-code-inner js-file-line"><span class="pl-mdr">@@ -891,12 +891,13 @@</span> static void vxlan_rcv(struct vxlan_sock *vs, struct sk_buff *skb,</td>
</tr>
<tr>
<td id="L26" class="blob-num js-line-number" data-line-number="26"></td>
<td id="LC26" class="blob-code blob-code-inner js-file-line"> u64_stats_update_end(&amp;stats-&gt;syncp);</td>
</tr>
<tr>
<td id="L27" class="blob-num js-line-number" data-line-number="27"></td>
<td id="LC27" class="blob-code blob-code-inner js-file-line"> </td>
</tr>
<tr>
<td id="L28" class="blob-num js-line-number" data-line-number="28"></td>
<td id="LC28" class="blob-code blob-code-inner js-file-line"> /* Add a faked encap_eth_header for NSH */</td>
</tr>
<tr>
<td id="L29" class="blob-num js-line-number" data-line-number="29"></td>
<td id="LC29" class="blob-code blob-code-inner js-file-line"><span class="pl-md">- if (md &amp;&amp; ((md-&gt;gpe &amp; VXLAN_GPE_NP_MASK) == VXLAN_GPE_NP_NSH)) {</span></td>
</tr>
<tr>
<td id="L30" class="blob-num js-line-number" data-line-number="30"></td>
<td id="LC30" class="blob-code blob-code-inner js-file-line"><span class="pl-mi1">+ /* ovs changes have ensured it is here, so needn&#39;t add it any more */</span></td>
</tr>
<tr>
<td id="L31" class="blob-num js-line-number" data-line-number="31"></td>
<td id="LC31" class="blob-code blob-code-inner js-file-line"><span class="pl-mi1">+ /*if (md &amp;&amp; ((md-&gt;gpe &amp; VXLAN_GPE_NP_MASK) == VXLAN_GPE_NP_NSH)) {</span></td>
</tr>
<tr>
<td id="L32" class="blob-num js-line-number" data-line-number="32"></td>
<td id="LC32" class="blob-code blob-code-inner js-file-line"> skb_push(skb, ENCAP_ETH_LEN);</td>
</tr>
<tr>
<td id="L33" class="blob-num js-line-number" data-line-number="33"></td>
<td id="LC33" class="blob-code blob-code-inner js-file-line"> eth_nsh_header = (struct eth_nsh_hdr *)skb-&gt;data;</td>
</tr>
<tr>
<td id="L34" class="blob-num js-line-number" data-line-number="34"></td>
<td id="LC34" class="blob-code blob-code-inner js-file-line"> memmove(eth_nsh_header-&gt;encap_eth_header.encap_eth_dst, skb_mac_header(skb), ENCAP_ETH_LEN);</td>
</tr>
<tr>
<td id="L35" class="blob-num js-line-number" data-line-number="35"></td>
<td id="LC35" class="blob-code blob-code-inner js-file-line"> eth_nsh_header-&gt;encap_eth_header.encap_eth_type = htons(ETH_P_NSH);</td>
</tr>
<tr>
<td id="L36" class="blob-num js-line-number" data-line-number="36"></td>
<td id="LC36" class="blob-code blob-code-inner js-file-line"><span class="pl-md">- }</span></td>
</tr>
<tr>
<td id="L37" class="blob-num js-line-number" data-line-number="37"></td>
<td id="LC37" class="blob-code blob-code-inner js-file-line"><span class="pl-mi1">+ }*/</span></td>
</tr>
<tr>
<td id="L38" class="blob-num js-line-number" data-line-number="38"></td>
<td id="LC38" class="blob-code blob-code-inner js-file-line"> </td>
</tr>
<tr>
<td id="L39" class="blob-num js-line-number" data-line-number="39"></td>
<td id="LC39" class="blob-code blob-code-inner js-file-line"> netdev_port_receive(skb, skb_tunnel_info(skb));</td>
</tr>
<tr>
<td id="L40" class="blob-num js-line-number" data-line-number="40"></td>
<td id="LC40" class="blob-code blob-code-inner js-file-line"> return;</td>
</tr>
<tr>
<td id="L41" class="blob-num js-line-number" data-line-number="41"></td>
<td id="LC41" class="blob-code blob-code-inner js-file-line"><span class="pl-mdr">@@ -985,7 +986,7 @@</span> static int vxlan_udp_encap_recv(struct sock *sk, struct sk_buff *skb)</td>
</tr>
<tr>
<td id="L42" class="blob-num js-line-number" data-line-number="42"></td>
<td id="LC42" class="blob-code blob-code-inner js-file-line"> struct vxlanhdr_gpe *gpe;</td>
</tr>
<tr>
<td id="L43" class="blob-num js-line-number" data-line-number="43"></td>
<td id="LC43" class="blob-code blob-code-inner js-file-line"> </td>
</tr>
<tr>
<td id="L44" class="blob-num js-line-number" data-line-number="44"></td>
<td id="LC44" class="blob-code blob-code-inner js-file-line"> gpe = (struct vxlanhdr_gpe *)vxh;</td>
</tr>
<tr>
<td id="L45" class="blob-num js-line-number" data-line-number="45"></td>
<td id="LC45" class="blob-code blob-code-inner js-file-line"><span class="pl-md">- md-&gt;gpe = ntohs(gpe-&gt;next_proto);</span></td>
</tr>
<tr>
<td id="L46" class="blob-num js-line-number" data-line-number="46"></td>
<td id="LC46" class="blob-code blob-code-inner js-file-line"><span class="pl-mi1">+ md-&gt;gpe = gpe-&gt;next_proto;</span></td>
</tr>
<tr>
<td id="L47" class="blob-num js-line-number" data-line-number="47"></td>
<td id="LC47" class="blob-code blob-code-inner js-file-line"> </td>
</tr>
<tr>
<td id="L48" class="blob-num js-line-number" data-line-number="48"></td>
<td id="LC48" class="blob-code blob-code-inner js-file-line"> buf.dst.u.tun_info.key.tun_flags |= TUNNEL_VXLAN_OPT;</td>
</tr>
<tr>
<td id="L49" class="blob-num js-line-number" data-line-number="49"></td>
<td id="LC49" class="blob-code blob-code-inner js-file-line"> </td>
</tr>
<tr>
<td id="L50" class="blob-num js-line-number" data-line-number="50"></td>
<td id="LC50" class="blob-code blob-code-inner js-file-line"><span class="pl-mdr">@@ -1189,9 +1190,10 @@</span> static int vxlan_xmit_skb(struct rtable *rt, struct sock *sk, struct sk_buff *sk</td>
</tr>
<tr>
<td id="L51" class="blob-num js-line-number" data-line-number="51"></td>
<td id="LC51" class="blob-code blob-code-inner js-file-line"> }</td>
</tr>
<tr>
<td id="L52" class="blob-num js-line-number" data-line-number="52"></td>
<td id="LC52" class="blob-code blob-code-inner js-file-line"> </td>
</tr>
<tr>
<td id="L53" class="blob-num js-line-number" data-line-number="53"></td>
<td id="LC53" class="blob-code blob-code-inner js-file-line"> /* Skip encap_eth_header on sending Eth+NSH to vxlan-gpe port */</td>
</tr>
<tr>
<td id="L54" class="blob-num js-line-number" data-line-number="54"></td>
<td id="LC54" class="blob-code blob-code-inner js-file-line"><span class="pl-md">- if (md &amp;&amp; ((md-&gt;gpe &amp; VXLAN_GPE_NP_MASK) == VXLAN_GPE_NP_NSH)) {</span></td>
</tr>
<tr>
<td id="L55" class="blob-num js-line-number" data-line-number="55"></td>
<td id="LC55" class="blob-code blob-code-inner js-file-line"><span class="pl-mi1">+ /* ovs needs to keep eth header here */</span></td>
</tr>
<tr>
<td id="L56" class="blob-num js-line-number" data-line-number="56"></td>
<td id="LC56" class="blob-code blob-code-inner js-file-line"><span class="pl-mi1">+ /*if (md &amp;&amp; ((md-&gt;gpe &amp; VXLAN_GPE_NP_MASK) == VXLAN_GPE_NP_NSH)) {</span></td>
</tr>
<tr>
<td id="L57" class="blob-num js-line-number" data-line-number="57"></td>
<td id="LC57" class="blob-code blob-code-inner js-file-line"> skb_pull(skb, ENCAP_ETH_LEN);</td>
</tr>
<tr>
<td id="L58" class="blob-num js-line-number" data-line-number="58"></td>
<td id="LC58" class="blob-code blob-code-inner js-file-line"><span class="pl-md">- }</span></td>
</tr>
<tr>
<td id="L59" class="blob-num js-line-number" data-line-number="59"></td>
<td id="LC59" class="blob-code blob-code-inner js-file-line"><span class="pl-mi1">+ }*/</span></td>
</tr>
<tr>
<td id="L60" class="blob-num js-line-number" data-line-number="60"></td>
<td id="LC60" class="blob-code blob-code-inner js-file-line"> </td>
</tr>
<tr>
<td id="L61" class="blob-num js-line-number" data-line-number="61"></td>
<td id="LC61" class="blob-code blob-code-inner js-file-line"> min_headroom = LL_RESERVED_SPACE(rt-&gt;dst.dev) + rt-&gt;dst.header_len</td>
</tr>
<tr>
<td id="L62" class="blob-num js-line-number" data-line-number="62"></td>
<td id="LC62" class="blob-code blob-code-inner js-file-line"> + VXLAN_HLEN + sizeof(struct iphdr)</td>
</tr>
<tr>
<td id="L63" class="blob-num js-line-number" data-line-number="63"></td>
<td id="LC63" class="blob-code blob-code-inner js-file-line"><span class="pl-mdr">@@ -1236,6 +1238,8 @@</span> static int vxlan_xmit_skb(struct rtable *rt, struct sock *sk, struct sk_buff *sk</td>
</tr>
<tr>
<td id="L64" class="blob-num js-line-number" data-line-number="64"></td>
<td id="LC64" class="blob-code blob-code-inner js-file-line"> }</td>
</tr>
<tr>
<td id="L65" class="blob-num js-line-number" data-line-number="65"></td>
<td id="LC65" class="blob-code blob-code-inner js-file-line"> if (vxflags &amp; VXLAN_F_GBP)</td>
</tr>
<tr>
<td id="L66" class="blob-num js-line-number" data-line-number="66"></td>
<td id="LC66" class="blob-code blob-code-inner js-file-line"> vxlan_build_gbp_hdr(vxh, vxflags, md);</td>
</tr>
<tr>
<td id="L67" class="blob-num js-line-number" data-line-number="67"></td>
<td id="LC67" class="blob-code blob-code-inner js-file-line"><span class="pl-mi1">+ else if (vxflags &amp; VXLAN_F_GPE)</span></td>
</tr>
<tr>
<td id="L68" class="blob-num js-line-number" data-line-number="68"></td>
<td id="LC68" class="blob-code blob-code-inner js-file-line"><span class="pl-mi1">+ vxlan_build_gpe_hdr(vxh, vxflags, md);</span></td>
</tr>
<tr>
<td id="L69" class="blob-num js-line-number" data-line-number="69"></td>
<td id="LC69" class="blob-code blob-code-inner js-file-line"> </td>
</tr>
<tr>
<td id="L70" class="blob-num js-line-number" data-line-number="70"></td>
<td id="LC70" class="blob-code blob-code-inner js-file-line"> ovs_skb_set_inner_protocol(skb, htons(ETH_P_TEB));</td>
</tr>
<tr>
<td id="L71" class="blob-num js-line-number" data-line-number="71"></td>
<td id="LC71" class="blob-code blob-code-inner js-file-line"> </td>
</tr>
<tr>
<td id="L72" class="blob-num js-line-number" data-line-number="72"></td>
<td id="LC72" class="blob-code blob-code-inner js-file-line"><span class="pl-md">-- </span></td>
</tr>
<tr>
<td id="L73" class="blob-num js-line-number" data-line-number="73"></td>
<td id="LC73" class="blob-code blob-code-inner js-file-line">1.9.3</td>
</tr>
<tr>
<td id="L74" class="blob-num js-line-number" data-line-number="74"></td>
<td id="LC74" class="blob-code blob-code-inner js-file-line">
</td>
</tr>
</table>
</div>
</div>
<button type="button" data-facebox="#jump-to-line" data-facebox-class="linejump" data-hotkey="l" class="hidden">Jump to Line</button>
<div id="jump-to-line" style="display:none">
<!-- </textarea> --><!-- '"` --><form accept-charset="UTF-8" action="" class="js-jump-to-line-form" method="get"><div style="margin:0;padding:0;display:inline"><input name="utf8" type="hidden" value="&#x2713;" /></div>
<input class="form-control linejump-input js-jump-to-line-field" type="text" placeholder="Jump to line&hellip;" aria-label="Jump to line" autofocus>
<button type="submit" class="btn">Go</button>
</form></div>
</div>
<div class="modal-backdrop"></div>
</div>
</div>
</div>
</div>
<div class="container site-footer-container">
<div class="site-footer" role="contentinfo">
<ul class="site-footer-links right">
<li><a href="https://status.github.com/" data-ga-click="Footer, go to status, text:status">Status</a></li>
<li><a href="https://developer.github.com" data-ga-click="Footer, go to api, text:api">API</a></li>
<li><a href="https://training.github.com" data-ga-click="Footer, go to training, text:training">Training</a></li>
<li><a href="https://shop.github.com" data-ga-click="Footer, go to shop, text:shop">Shop</a></li>
<li><a href="https://github.com/blog" data-ga-click="Footer, go to blog, text:blog">Blog</a></li>
<li><a href="https://github.com/about" data-ga-click="Footer, go to about, text:about">About</a></li>
</ul>
<a href="https://github.com" aria-label="Homepage" class="site-footer-mark" title="GitHub">
<svg aria-hidden="true" class="octicon octicon-mark-github" height="24" version="1.1" viewBox="0 0 16 16" width="24"><path d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59 0.4 0.07 0.55-0.17 0.55-0.38 0-0.19-0.01-0.82-0.01-1.49-2.01 0.37-2.53-0.49-2.69-0.94-0.09-0.23-0.48-0.94-0.82-1.13-0.28-0.15-0.68-0.52-0.01-0.53 0.63-0.01 1.08 0.58 1.23 0.82 0.72 1.21 1.87 0.87 2.33 0.66 0.07-0.52 0.28-0.87 0.51-1.07-1.78-0.2-3.64-0.89-3.64-3.95 0-0.87 0.31-1.59 0.82-2.15-0.08-0.2-0.36-1.02 0.08-2.12 0 0 0.67-0.21 2.2 0.82 0.64-0.18 1.32-0.27 2-0.27 0.68 0 1.36 0.09 2 0.27 1.53-1.04 2.2-0.82 2.2-0.82 0.44 1.1 0.16 1.92 0.08 2.12 0.51 0.56 0.82 1.27 0.82 2.15 0 3.07-1.87 3.75-3.65 3.95 0.29 0.25 0.54 0.73 0.54 1.48 0 1.07-0.01 1.93-0.01 2.2 0 0.21 0.15 0.46 0.55 0.38C13.71 14.53 16 11.53 16 8 16 3.58 12.42 0 8 0z"></path></svg>
</a>
<ul class="site-footer-links">
<li>&copy; 2016 <span title="0.04211s from github-fe139-cp1-prd.iad.github.net">GitHub</span>, Inc.</li>
<li><a href="https://github.com/site/terms" data-ga-click="Footer, go to terms, text:terms">Terms</a></li>
<li><a href="https://github.com/site/privacy" data-ga-click="Footer, go to privacy, text:privacy">Privacy</a></li>
<li><a href="https://github.com/security" data-ga-click="Footer, go to security, text:security">Security</a></li>
<li><a href="https://github.com/contact" data-ga-click="Footer, go to contact, text:contact">Contact</a></li>
<li><a href="https://help.github.com" data-ga-click="Footer, go to help, text:help">Help</a></li>
</ul>
</div>
</div>
<div id="ajax-error-message" class="ajax-error-message flash flash-error">
<svg aria-hidden="true" class="octicon octicon-alert" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path d="M15.72 12.5l-6.85-11.98C8.69 0.21 8.36 0.02 8 0.02s-0.69 0.19-0.87 0.5l-6.85 11.98c-0.18 0.31-0.18 0.69 0 1C0.47 13.81 0.8 14 1.15 14h13.7c0.36 0 0.69-0.19 0.86-0.5S15.89 12.81 15.72 12.5zM9 12H7V10h2V12zM9 9H7V5h2V9z"></path></svg>
<button type="button" class="flash-close js-flash-close js-ajax-error-dismiss" aria-label="Dismiss error">
<svg aria-hidden="true" class="octicon octicon-x" height="16" version="1.1" viewBox="0 0 12 16" width="12"><path d="M7.48 8l3.75 3.75-1.48 1.48-3.75-3.75-3.75 3.75-1.48-1.48 3.75-3.75L0.77 4.25l1.48-1.48 3.75 3.75 3.75-3.75 1.48 1.48-3.75 3.75z"></path></svg>
</button>
Something went wrong with that request. Please try again.
</div>
<script crossorigin="anonymous" src="https://assets-cdn.github.com/assets/compat-7db58f8b7b91111107fac755dd8b178fe7db0f209ced51fc339c446ad3f8da2b.js"></script>
<script crossorigin="anonymous" src="https://assets-cdn.github.com/assets/frameworks-b0aaa1e644508a5d5c3f7509d91f5f950c180e1d933a999f21747c5ec5411d92.js"></script>
<script async="async" crossorigin="anonymous" src="https://assets-cdn.github.com/assets/github-7c9ed6fd84382ad236d74c9ec5853f75fca061537cb1914241807b12c289216e.js"></script>
<div class="js-stale-session-flash stale-session-flash flash flash-warn flash-banner hidden">
<svg aria-hidden="true" class="octicon octicon-alert" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path d="M15.72 12.5l-6.85-11.98C8.69 0.21 8.36 0.02 8 0.02s-0.69 0.19-0.87 0.5l-6.85 11.98c-0.18 0.31-0.18 0.69 0 1C0.47 13.81 0.8 14 1.15 14h13.7c0.36 0 0.69-0.19 0.86-0.5S15.89 12.81 15.72 12.5zM9 12H7V10h2V12zM9 9H7V5h2V9z"></path></svg>
<span class="signed-in-tab-flash">You signed in with another tab or window. <a href="">Reload</a> to refresh your session.</span>
<span class="signed-out-tab-flash">You signed out in another tab or window. <a href="">Reload</a> to refresh your session.</span>
</div>
<div class="facebox" id="facebox" style="display:none;">
<div class="facebox-popup">
<div class="facebox-content" role="dialog" aria-labelledby="facebox-header" aria-describedby="facebox-description">
</div>
<button type="button" class="facebox-close js-facebox-close" aria-label="Close modal">
<svg aria-hidden="true" class="octicon octicon-x" height="16" version="1.1" viewBox="0 0 12 16" width="12"><path d="M7.48 8l3.75 3.75-1.48 1.48-3.75-3.75-3.75 3.75-1.48-1.48 3.75-3.75L0.77 4.25l1.48-1.48 3.75 3.75 3.75-3.75 1.48 1.48-3.75 3.75z"></path></svg>
</button>
</div>
</div>
</body>
</html>

File diff suppressed because it is too large Load Diff

View File

@ -1,788 +0,0 @@
at data plane level in user space and modify the related codes at control plane
level in user space.
The design is based on basic VxLAN impletation. When packets are received at
data plane level in user space, function 'dp_netdev_input' will be called for
processing the packets at data plane level in user space.
When VXLAN-GPE NSH packets are received, decapsulation will be implemented. For
the first time, the packets are sent to control plane by function 'upcall_cb',
and tunnel port will be lookuped by matching the UDP port which is 4790 for
VxLAN-GPE NSH port, if VxLAN-GPE NSH tunnel port are matched
successfully, the tunnel pop action will be appended and implemented at data
plane level, and the NSH related field will be parsed, then packets will be
reprocessed by function 'dp_netdev_input'.
When original packets are sent to VxLAN-GPE NSH port, the encapsulation will
be implemented. For the first time, in the control plane the tunnel
tunnel_push_data are built according to VxLAN-GPE NSH port configuration and
related rules, then the tunnel push actions are appended and implemented at
data plane level. Finally packets will be reprocessed by function
'dp_netdev_input'.
Signed-off-by: Ricky Li <<A HREF="http://openvswitch.org/mailman/listinfo/dev">ricky.li at intel.com</A>>
Signed-off-by: Mengke Liu <<A HREF="http://openvswitch.org/mailman/listinfo/dev">mengke.liu at intel.com</A>>
---
lib/netdev-vport.c | 166 +++++++++++++++++++++++++++++++++++-----
lib/odp-util.c | 175 ++++++++++++++++++++++++++++++-------------
lib/packets.h | 115 +++++++++++++++++++++++++++-
ofproto/ofproto-dpif-xlate.c | 1 -
tests/tunnel.at | 118 +++++++++++++++++++++++++++++
5 files changed, 500 insertions(+), 75 deletions(-)
diff --git a/lib/netdev-vport.c b/lib/netdev-vport.c
index 3f85386..a0a4da2 100644
--- a/lib/netdev-vport.c
+++ b/lib/netdev-vport.c
@@ -67,6 +67,12 @@ static struct vlog_rate_limit err_rl = VLOG_RATE_LIMIT_INIT(60, 5);
sizeof(struct udp_header) + \
sizeof(struct genevehdr))
+#define VXNSH_HLEN (sizeof(struct eth_header) + \
+ sizeof(struct ip_header) + \
+ sizeof(struct udp_header) + \
+ sizeof(struct vxgpehdr) + \
+ sizeof(struct nshhdr))
+
#define DEFAULT_TTL 64
struct netdev_vport {
@@ -1462,29 +1468,69 @@ netdev_vxlan_pop_header(struct dp_packet *packet)
{
struct pkt_metadata *md = &packet->md;
struct flow_tnl *tnl = &md->tunnel;
- struct vxlanhdr *vxh;
+ struct udp_header *udp;
pkt_metadata_init_tnl(md);
if (VXLAN_HLEN > dp_packet_size(packet)) {
return EINVAL;
}
- vxh = udp_extract_tnl_md(packet, tnl);
- if (!vxh) {
- return EINVAL;
+ udp = ip_extract_tnl_md(packet, tnl);
+ if (!udp) {
+ return EINVAL;;
}
- if (get_16aligned_be32(&vxh->vx_flags) != htonl(VXLAN_FLAGS) ||
- (get_16aligned_be32(&vxh->vx_vni) & htonl(0xff))) {
- VLOG_WARN_RL(&err_rl, "invalid vxlan flags=%#x vni=%#x\n",
- ntohl(get_16aligned_be32(&vxh->vx_flags)),
- ntohl(get_16aligned_be32(&vxh->vx_vni)));
- return EINVAL;
- }
- tnl->tun_id = htonll(ntohl(get_16aligned_be32(&vxh->vx_vni)) >> 8);
- tnl->flags |= FLOW_TNL_F_KEY;
+ if (ntohs(udp->udp_dst) == VXGPE_DST_PORT) {
+
+ struct vxgpehdr *vxg = (struct vxgpehdr *) (udp + 1);
+
+ if (get_16aligned_be32(&vxg->vx_vni) & htonl(0xff)) {
+ VLOG_WARN_RL(&err_rl, "invalid vxlan-gpe vni=%#x\n",
+ ntohl(get_16aligned_be32(&vxg->vx_vni)));
+ return EINVAL;;
+ }
+
+ tnl->tp_src = udp->udp_src;
+ tnl->tp_dst = udp->udp_dst;
+ tnl->tun_id = htonll(ntohl(get_16aligned_be32(&vxg->vx_vni)) >> 8);
+
+ if (vxg->p == 0x01 && vxg->proto == VXG_P_NSH) {
+ struct nshhdr *nsh = (struct nshhdr *) (vxg + 1);
+
+ tnl->nsp = nsh->b.b2 << 8;
+ tnl->nsi = nsh->b.svc_idx;
+ tnl->nshc1 = nsh->c.nshc1;
+ tnl->nshc2 = nsh->c.nshc2;
+ tnl->nshc3 = nsh->c.nshc3;
+ tnl->nshc4 = nsh->c.nshc4;
+ tnl->flags |= FLOW_TNL_F_NSP;
+ tnl->flags |= FLOW_TNL_F_NSI;
+ tnl->flags |= FLOW_TNL_F_NSH_C1 | FLOW_TNL_F_NSH_C2 | \
+ FLOW_TNL_F_NSH_C3 | FLOW_TNL_F_NSH_C4;
+
+ dp_packet_reset_packet(packet, VXNSH_HLEN);
+ } else {
+ VLOG_WARN("Unsupported vxlan GPE + NSH format!");
+ return EINVAL;;
+ }
+
+ } else {
+
+ struct vxlanhdr *vxh = (struct vxlanhdr *) (udp + 1);
- dp_packet_reset_packet(packet, VXLAN_HLEN);
+ if (get_16aligned_be32(&vxh->vx_flags) != htonl(VXLAN_FLAGS) ||
+ (get_16aligned_be32(&vxh->vx_vni) & htonl(0xff))) {
+ VLOG_WARN_RL(&err_rl, "invalid vxlan flags=%#x vni=%#x\n",
+ ntohl(get_16aligned_be32(&vxh->vx_flags)),
+ ntohl(get_16aligned_be32(&vxh->vx_vni)));
+ return EINVAL;;
+ }
+
+ tnl->tp_src = udp->udp_src;
+ tnl->tp_dst = udp->udp_dst;
+ tnl->tun_id = htonll(ntohl(get_16aligned_be32(&vxh->vx_vni)) >> 8);
+ dp_packet_reset_packet(packet, VXLAN_HLEN);
+ }
return 0;
}
@@ -1496,23 +1542,103 @@ netdev_vxlan_build_header(const struct netdev *netdev,
{
struct netdev_vport *dev = netdev_vport_cast(netdev);
struct netdev_tunnel_config *tnl_cfg;
- struct vxlanhdr *vxh;
+ struct ip_header *ip;
+ struct udp_header *udp;
+ bool isnsh = false;
/* XXX: RCUfy tnl_cfg. */
ovs_mutex_lock(&dev->mutex);
tnl_cfg = &dev->tnl_cfg;
- vxh = udp_build_header(tnl_cfg, tnl_flow, data);
+ ip = ip_hdr(data->header);
+ ip->ip_proto = IPPROTO_UDP;
+
+ udp = (struct udp_header *) (ip + 1);
+ udp->udp_dst = tnl_cfg->dst_port;
+
+ if (tnl_flow->tunnel.flags & FLOW_TNL_F_CSUM) {
+ /* Write a value in now to mark that we should compute the checksum
+ * later. 0xffff is handy because it is transparent to the
+ * calculation. */
+ udp->udp_csum = htons(0xffff);
+ }
+
+ if (ntohs(udp->udp_dst) == VXGPE_DST_PORT){
+ struct vxgpehdr *vxg = (struct vxgpehdr *) (udp + 1);
- put_16aligned_be32(&vxh->vx_flags, htonl(VXLAN_FLAGS));
- put_16aligned_be32(&vxh->vx_vni, htonl(ntohll(tnl_flow->tunnel.tun_id) << 8));
+ memset(vxg, 0, sizeof *vxg);
+ vxg->i = 0x01;
+ vxg->p = 0x01;
+ vxg->ver = 0x01;
+ vxg->proto = VXG_P_NSH;
+ put_16aligned_be32(&vxg->vx_vni, htonl(ntohll(tnl_flow->tunnel.tun_id) << 8));
+
+ if (vxg->p && vxg->proto == VXG_P_NSH){
+ struct nshhdr *nsh = (struct nshhdr *) (vxg + 1);
+
+ memset(nsh, 0, sizeof *nsh);
+ nsh->b.ver = 0x01;
+ nsh->b.len = 6;
+ nsh->b.mdtype = NSH_M_TYPE1;
+ nsh->b.proto = NSH_P_ETHERNET;
+
+ nsh->b.b2 = tnl_flow->tunnel.nsp >> 8;
+ nsh->b.svc_idx = tnl_flow->tunnel.nsi;
+
+ nsh->c.nshc1 = tnl_flow->tunnel.nshc1;
+ nsh->c.nshc2 = tnl_flow->tunnel.nshc2;
+ nsh->c.nshc3 = tnl_flow->tunnel.nshc3;
+ nsh->c.nshc4 = tnl_flow->tunnel.nshc4;
+
+ isnsh = true;
+ }
+
+ } else {
+ struct vxlanhdr *vxh = (struct vxlanhdr *) (udp + 1);
+ put_16aligned_be32(&vxh->vx_flags, htonl(VXLAN_FLAGS));
+ put_16aligned_be32(&vxh->vx_vni, htonl(ntohll(tnl_flow->tunnel.tun_id) << 8));
+ }
ovs_mutex_unlock(&dev->mutex);
- data->header_len = VXLAN_HLEN;
+
+ if(isnsh)
+ data->header_len = VXNSH_HLEN;
+ else
+ data->header_len = VXLAN_HLEN;
data->tnl_type = OVS_VPORT_TYPE_VXLAN;
+
return 0;
}
+static void
+netdev_vxlan_push_header(struct dp_packet *packet,
+ const struct ovs_action_push_tnl *data)
+{
+ int ip_tot_size;
+ int size = data->header_len;
+ const void *header = data->header;
+ struct udp_header *udp;
+
+ udp = push_ip_header(packet, header, size, &ip_tot_size);
+
+ /* set udp src port */
+ udp->udp_src = get_src_port(packet);
+ udp->udp_len = htons(ip_tot_size - sizeof (struct ip_header));
+ /* udp_csum is zero */
+
+ if (udp->udp_csum) {
+ uint32_t csum = packet_csum_pseudoheader(ip_hdr(dp_packet_data(packet)));
+
+ csum = csum_continue(csum, udp,
+ ip_tot_size - sizeof (struct ip_header));
+ udp->udp_csum = csum_finish(csum);
+
+ if (!udp->udp_csum) {
+ udp->udp_csum = htons(0xffff);
+ }
+ }
+}
+
static int
netdev_geneve_pop_header(struct dp_packet *packet)
{
@@ -1736,7 +1862,7 @@ netdev_vport_tunnel_register(void)
netdev_gre_pop_header),
TUNNEL_CLASS("ipsec_gre", "gre_sys", NULL, NULL, NULL),
TUNNEL_CLASS("vxlan", "vxlan_sys", netdev_vxlan_build_header,
- push_udp_header,
+ netdev_vxlan_push_header,
netdev_vxlan_pop_header),
TUNNEL_CLASS("lisp", "lisp_sys", NULL, NULL, NULL),
TUNNEL_CLASS("stt", "stt_sys", NULL, NULL, NULL),
diff --git a/lib/odp-util.c b/lib/odp-util.c
index e8bc86d..1696f77 100644
--- a/lib/odp-util.c
+++ b/lib/odp-util.c
@@ -468,12 +468,42 @@ format_odp_tnl_push_header(struct ds *ds, struct ovs_action_push_tnl *data)
if (data->tnl_type == OVS_VPORT_TYPE_VXLAN) {
const struct vxlanhdr *vxh;
-
- vxh = format_udp_tnl_push_header(ds, ip);
-
- ds_put_format(ds, "vxlan(flags=0x%"PRIx32",vni=0x%"PRIx32")",
- ntohl(get_16aligned_be32(&vxh->vx_flags)),
- ntohl(get_16aligned_be32(&vxh->vx_vni)) >> 8);
+ const struct udp_header *udp;
+ const struct vxgpehdr *vxg;
+
+ /* UDP */
+ udp = (const struct udp_header *) (ip + 1);
+ ds_put_format(ds, "udp(src=%"PRIu16",dst=%"PRIu16",csum=0x%"PRIx16"),",
+ ntohs(udp->udp_src), ntohs(udp->udp_dst),
+ ntohs(udp->udp_csum));
+
+ /* VxLan & VxLan GPE(UDP port: 4790) */
+ if (ntohs(udp->udp_dst) == 4790) {
+ vxg = (const struct vxgpehdr *) (udp + 1);
+
+ ds_put_format(ds, "vxlangpe(vni=0x%"PRIx32",",
+ ntohl(get_16aligned_be32(&vxg->vx_vni)));
+ ds_put_format(ds, "proto=%"PRIu8"),", vxg->proto);
+ if (vxg->p == 0x01 && vxg->proto == VXG_P_NSH) {
+ const struct nshhdr *nsh = (struct nshhdr *) (vxg + 1);
+
+ /* NSH */
+ ds_put_format(ds, "nsh(mdtype=%"PRIu8",proto=%"PRIu8",",
+ nsh->b.mdtype, nsh->b.proto);
+ ds_put_format(ds, "nsp=%"PRIx32",nsi=%"PRIu8",",
+ nsh->b.b2 & 0x00FFFFFF, nsh->b.svc_idx);
+ ds_put_format(ds, "nshc1=%"PRIx32",nshc2=%"PRIx32",",
+ ntohl(nsh->c.nshc1), ntohl(nsh->c.nshc2));
+ ds_put_format(ds, "nshc3=%"PRIx32",nshc4=%"PRIx32",",
+ ntohl(nsh->c.nshc3), ntohl(nsh->c.nshc4));
+ ds_put_format(ds, ")");
+ }
+ } else {
+ vxh = (const struct vxlanhdr *) (udp + 1);
+ ds_put_format(ds, "vxlan(flags=0x%"PRIx32",vni=0x%"PRIx32")",
+ ntohl(get_16aligned_be32(&vxh->vx_flags)),
+ ntohl(get_16aligned_be32(&vxh->vx_vni))>>8);
+ }
} else if (data->tnl_type == OVS_VPORT_TYPE_GENEVE) {
const struct genevehdr *gnh;
@@ -490,8 +520,8 @@ format_odp_tnl_push_header(struct ds *ds, struct ovs_action_push_tnl *data)
ds, false);
ds_put_char(ds, ')');
}
-
ds_put_char(ds, ')');
+
} else if (data->tnl_type == OVS_VPORT_TYPE_GRE) {
const struct gre_base_hdr *greh;
ovs_16aligned_be32 *options;
@@ -504,7 +534,7 @@ format_odp_tnl_push_header(struct ds *ds, struct ovs_action_push_tnl *data)
ntohs(greh->flags), ntohs(greh->protocol));
options = (ovs_16aligned_be32 *)(greh + 1);
if (greh->flags & htons(GRE_CSUM)) {
- ds_put_format(ds, ",csum=0x%"PRIx16, ntohs(*((ovs_be16 *)options)));
+ ds_put_format(ds, ",csum=0x%"PRIx32, ntohl(get_16aligned_be32(options)));
options++;
}
if (greh->flags & htons(GRE_KEY)) {
@@ -791,8 +821,10 @@ ovs_parse_tnl_push(const char *s, struct ovs_action_push_tnl *data)
struct ip_header *ip;
struct udp_header *udp;
struct gre_base_hdr *greh;
+ struct nshhdr *nsh;
uint16_t gre_proto, gre_flags, dl_type, udp_src, udp_dst, csum;
- ovs_be32 sip, dip;
+ ovs_be32 sip, dip, nsp, nshc1,nshc2,nshc3,nshc4;
+ uint8_t nsi;
uint32_t tnl_type = 0, header_len = 0;
void *l3, *l4;
int n = 0;
@@ -837,71 +869,108 @@ ovs_parse_tnl_push(const char *s, struct ovs_action_push_tnl *data)
udp = (struct udp_header *) l4;
greh = (struct gre_base_hdr *) l4;
if (ovs_scan_len(s, &n, "udp(src=%"SCNi16",dst=%"SCNi16",csum=0x%"SCNx16"),",
- &udp_src, &udp_dst, &csum)) {
- uint32_t vx_flags, vni;
+ &udp_src, &udp_dst, &csum)) {
+ struct vxlanhdr *vxh;
+ struct vxgpehdr *vxg;
+ uint32_t vx_flags, vx_vni;
+ uint32_t geneve_vni;
udp->udp_src = htons(udp_src);
udp->udp_dst = htons(udp_dst);
udp->udp_len = 0;
udp->udp_csum = htons(csum);
+ vxh = (struct vxlanhdr *) (udp + 1);
+ vxg = (struct vxgpehdr *) (udp + 1);
+
if (ovs_scan_len(s, &n, "vxlan(flags=0x%"SCNx32",vni=0x%"SCNx32"))",
- &vx_flags, &vni)) {
- struct vxlanhdr *vxh = (struct vxlanhdr *) (udp + 1);
+ &vx_flags, &vx_vni)) {
+ tnl_type = OVS_VPORT_TYPE_VXLAN;
put_16aligned_be32(&vxh->vx_flags, htonl(vx_flags));
- put_16aligned_be32(&vxh->vx_vni, htonl(vni << 8));
- tnl_type = OVS_VPORT_TYPE_VXLAN;
+ put_16aligned_be32(&vxh->vx_vni, htonl(vx_vni<<8));
+
header_len = sizeof *eth + sizeof *ip +
sizeof *udp + sizeof *vxh;
- } else if (ovs_scan_len(s, &n, "geneve(")) {
- struct genevehdr *gnh = (struct genevehdr *) (udp + 1);
- memset(gnh, 0, sizeof *gnh);
- header_len = sizeof *eth + sizeof *ip +
- sizeof *udp + sizeof *gnh;
+ } else if (ovs_scan_len(s, &n, "vxlangpe(vni=0x%"SCNx32",proto="SCNi8"),",
+ &vx_vni, &vxg->proto)) {
+ struct nshhdr *nsh = (struct nshhdr *) (vxg + 1);
- if (ovs_scan_len(s, &n, "oam,")) {
- gnh->oam = 1;
- }
- if (ovs_scan_len(s, &n, "crit,")) {
- gnh->critical = 1;
- }
- if (!ovs_scan_len(s, &n, "vni=%"SCNi32, &vni)) {
+ tnl_type = OVS_VPORT_TYPE_VXLAN;
+ vxg->i = 0x01;
+ vxg->p = 0x01;
+ vxg->ver = 0x01;
+ put_16aligned_be32(&vxg->vx_vni, htonl(vx_vni));
+
+ if (ovs_scan_len(s, &n, "nsh(mdtype=%"SCNi8",proto=%"SCNi8",nsp=0x%"SCNx32
+ ",nsi=%"SCNi8",nshc1=0x%"SCNx32",nshc2=0x%"SCNx32
+ ",nshc3=0x%"SCNx32",nshc4=0x%"SCNx32"))",
+ &nsh->b.mdtype, &nsh->b.proto,
+ &nsp, &nsi,
+ &nshc1, &nshc2,
+ &nshc3, &nshc4)) {
+ nsh->b.ver = 0x01;
+ nsh->b.len = 6;
+ nsh->b.b2 = nsp;
+ nsh->b.svc_idx = nsi;
+ nsh->c.nshc1=nshc1;
+ nsh->c.nshc2=nshc2;
+ nsh->c.nshc3=nshc3;
+ nsh->c.nshc4=nshc4;
+ header_len = sizeof *eth + sizeof *ip +
+ sizeof *udp + sizeof *vxh + sizeof *nsh;
+ } else {
return -EINVAL;
}
- if (ovs_scan_len(s, &n, ",options(")) {
- struct geneve_scan options;
- int len;
-
- memset(&options, 0, sizeof options);
- len = scan_geneve(s + n, &options, NULL);
- if (!len) {
- return -EINVAL;
- }
+ } else if (ovs_scan_len(s, &n, "geneve(")) {
+ struct genevehdr *gnh = (struct genevehdr *) (udp + 1);
- memcpy(gnh->options, options.d, options.len);
- gnh->opt_len = options.len / 4;
- header_len += options.len;
+ memset(gnh, 0, sizeof *gnh);
+ header_len = sizeof *eth + sizeof *ip +
+ sizeof *udp + sizeof *gnh;
- n += len;
- }
- if (!ovs_scan_len(s, &n, "))")) {
+ if (ovs_scan_len(s, &n, "oam,")) {
+ gnh->oam = 1;
+ }
+ if (ovs_scan_len(s, &n, "crit,")) {
+ gnh->critical = 1;
+ }
+ if (!ovs_scan_len(s, &n, "vni=%"SCNi32, &geneve_vni)) {
+ return -EINVAL;
+ }
+ if (ovs_scan_len(s, &n, ",options(")) {
+ struct geneve_scan options;
+ int len;
+
+ memset(&options, 0, sizeof options);
+ len = scan_geneve(s + n, &options, NULL);
+ if (!len) {
return -EINVAL;
}
- gnh->proto_type = htons(ETH_TYPE_TEB);
- put_16aligned_be32(&gnh->vni, htonl(vni << 8));
- tnl_type = OVS_VPORT_TYPE_GENEVE;
- } else {
+ memcpy(gnh->options, options.d, options.len);
+ gnh->opt_len = options.len / 4;
+ header_len += options.len;
+
+ n += len;
+ }
+ if (!ovs_scan_len(s, &n, "))")) {
return -EINVAL;
}
- } else if (ovs_scan_len(s, &n, "gre((flags=0x%"SCNx16",proto=0x%"SCNx16")",
- &gre_flags, &gre_proto)){
- tnl_type = OVS_VPORT_TYPE_GRE;
- greh->flags = htons(gre_flags);
- greh->protocol = htons(gre_proto);
+ gnh->proto_type = htons(ETH_TYPE_TEB);
+ put_16aligned_be32(&gnh->vni, htonl(geneve_vni << 8));
+ tnl_type = OVS_VPORT_TYPE_GENEVE;
+ } else {
+ return -EINVAL;
+ }
+} else if (ovs_scan_len(s, &n, "gre((flags=0x%"SCNx16",proto=0x%"SCNx16")",
+ &gre_flags, &gre_proto)){
+
+ tnl_type = OVS_VPORT_TYPE_GRE;
+ greh->flags = htons(gre_flags);
+ greh->protocol = htons(gre_proto);
ovs_16aligned_be32 *options = (ovs_16aligned_be32 *) (greh + 1);
if (greh->flags & htons(GRE_CSUM)) {
@@ -941,7 +1010,7 @@ ovs_parse_tnl_push(const char *s, struct ovs_action_push_tnl *data)
((uint8_t *) options - (uint8_t *) greh);
} else {
return -EINVAL;
- }
+ }
/* check tunnel meta data. */
if (data->tnl_type != tnl_type) {
@@ -1120,6 +1189,7 @@ parse_odp_action(const char *s, const struct simap *port_names,
struct ovs_action_push_tnl data;
int n;
+ memset(&data, 0, sizeof data);
n = ovs_parse_tnl_push(s, &data);
if (n > 0) {
odp_put_tnl_push_action(actions, &data);
@@ -3285,7 +3355,6 @@ parse_odp_key_mask_attr(const char *s, const struct simap *port_names,
SCAN_FIELD_NESTED_FUNC("flags(", uint16_t, tun_flags, tun_flags_to_attr);
} SCAN_END_NESTED();
-
SCAN_SINGLE_PORT("in_port(", uint32_t, OVS_KEY_ATTR_IN_PORT);
SCAN_BEGIN("eth(", struct ovs_key_ethernet) {
diff --git a/lib/packets.h b/lib/packets.h
index 12f2239..7f9ab98 100644
--- a/lib/packets.h
+++ b/lib/packets.h
@@ -33,7 +33,6 @@
struct dp_packet;
struct ds;
-/* Tunnel information used in flow key and metadata. */
struct flow_tnl {
ovs_be32 ip_dst;
ovs_be32 ip_src;
@@ -913,6 +912,120 @@ struct vxlanhdr {
/* VXLAN GPE UDP DST PORT */
#define VXGPE_DST_PORT 4790
+/**
+ * struct vxlan_gpehdr - Generic Protocol Extension for VXLAN header.
+ * @p: Next Protocol field indicator bit
+ * @o: Operations and Management Packet indicator bit.
+ * @proto: IEEE Ethertypes to indicate the frame within.
+ * @vni: VXLAN Network Identifier.
+ */
+struct vxgpehdr {
+#ifdef WORDS_BIGENDIAN
+ uint8_t res1:4;
+ uint8_t i:1;
+ uint8_t p:1;
+ uint8_t res2:1;
+ uint8_t o:1;
+
+ uint8_t ver:2;
+ uint8_t res3:6;
+#else
+ uint8_t o:1;
+ uint8_t res2:1;
+ uint8_t p:1;
+ uint8_t i:1;
+ uint8_t res1:4;
+
+ uint8_t res3:6;
+ uint8_t ver:2;
+#endif
+ uint8_t res4;
+ uint8_t proto;
+ ovs_16aligned_be32 vx_vni;
+};
+
+/* VxLAN-GPE Header Next Protocol */
+#define VXG_P_IPV4 0x01
+#define VXG_P_IPV6 0x02
+#define VXG_P_ETHERNET 0x03
+#define VXG_P_NSH 0x04
+
+/**
+ * struct nsh_bhdr - Network Service Base Header.
+ * @o: Operations and Management Packet indicator bit
+ * @c: If this bit is set then one or more contexts are in use.
+ * @proto: IEEE Ethertypes to indicate the frame within.
+ * @svc_idx: TTL functionality and location within service path.
+ * @svc_path: To uniquely identify service path.
+ */
+struct nsh_base {
+#ifdef WORDS_BIGENDIAN
+ uint8_t ver:2;
+ uint8_t o:1;
+ uint8_t c:1;
+ uint8_t res1:4;
+
+ uint8_t res2:2;
+ uint8_t len:6;
+#else
+ uint8_t res1:4;
+ uint8_t c:1;
+ uint8_t o:1;
+ uint8_t ver:2;
+
+ uint8_t len:6;
+ uint8_t res2:2;
+#endif
+ uint8_t mdtype;
+ uint8_t proto;
+ union {
+ struct {
+ uint8_t svc_path[3];
+ uint8_t svc_idx;
+ };
+ ovs_be32 b2;
+ };
+};
+
+/**
+ * struct nsh_ctx - Keeps track of NSH context data
+ * @npc: NSH network platform context
+ * @nsc: NSH network shared context
+ * @spc: NSH service platform context
+ * @ssc: NSH service shared context
+ */
+struct nsh_ctx {
+ ovs_be32 nshc1;
+ ovs_be32 nshc2;
+ ovs_be32 nshc3;
+ ovs_be32 nshc4;
+};
+
+/**
+ * struct nshdr - Network Service header
+ * @nsh_base: Network Service Base Header.
+ * @nsh_ctx: Network Service Context Header.
+ */
+struct nshhdr {
+ struct nsh_base b;
+ struct nsh_ctx c;
+};
+
+/* NSH Base Header Next Protocol */
+#define NSH_P_IPV4 0x01
+#define NSH_P_IPV6 0x02
+#define NSH_P_ETHERNET 0x03
+
+/* MD Type Registry */
+#define NSH_M_TYPE1 0x01
+#define NSH_M_TYPE2 0x02
+#define NSH_M_EXP1 0xFE
+#define NSH_M_EXP2 0xFF
+
+/* Used for masking nsp and nsi values in field nsp below */
+#define NSH_M_NSP 0xFFFFFF00 //uncertain
+#define NSH_M_NSI 0x000000FF
+
#define VXLAN_FLAGS 0x08000000 /* struct vxlanhdr.vx_flags required value. */
void format_ipv6_addr(char *addr_str, const struct in6_addr *addr);
diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c
index 4bb9801..9c64c24 100644
--- a/ofproto/ofproto-dpif-xlate.c
+++ b/ofproto/ofproto-dpif-xlate.c
@@ -4780,7 +4780,6 @@ xlate_actions(struct xlate_in *xin, struct xlate_out *xout)
if (!xbridge) {
return;
}
-
struct flow *flow = &xin->flow;
union mf_subvalue stack_stub[1024 / sizeof(union mf_subvalue)];
diff --git a/tests/tunnel.at b/tests/tunnel.at
index f43a07d..5ec5e6c 100644
--- a/tests/tunnel.at
+++ b/tests/tunnel.at
@@ -527,6 +527,124 @@ AT_CHECK([tail -1 stdout], [0],
OVS_VSWITCHD_STOP(["/receive tunnel port not found/d"])
AT_CLEANUP
+AT_SETUP([tunnel - VXLAN-GPE NSH user space])
+OVS_VSWITCHD_START([add-port br0 p1 -- set Interface p1 type=vxlan \
+ options:remote_ip=1.1.1.1 ofport_request=1 options:dst_port=4790])
+
+AT_CHECK([ovs-appctl dpif/show | tail -n +3], [0], [dnl
+ br0 65534/100: (dummy)
+ p1 1/4790: (vxlan: dst_port=4790, remote_ip=1.1.1.1)
+])
+OVS_VSWITCHD_STOP(["/The Open vSwitch kernel module is probably not loaded/d"])
+AT_CLEANUP
+
+AT_SETUP([tunnel VXLAN-GPE NSH - encap - nsh/nsi/nshc user space])
+OVS_VSWITCHD_START([add-port br0 p1 -- set Interface p1 type=vxlan options:key=flow \
+ options:remote_ip=1.1.1.1 options:dst_port=4790 ofport_request=1 \
+ -- add-port br0 p2 -- set Interface p2 type=vxlan options:key=flow \
+ options:remote_ip=flow options:dst_port=4790 ofport_request=2 \
+ -- add-port br0 p3 -- set Interface p3 type=vxlan options:key=flow \
+ options:remote_ip=2.2.2.2 options:dst_port=4790 options:nsp=111 options:nsi=11 options:nshc1=11 options:nshc2=12 options:nshc3=13 options:nshc4=14 ofport_request=3 \
+ -- add-port br0 p4 -- set Interface p4 type=vxlan options:key=flow \
+ options:remote_ip=3.3.3.3 options:dst_port=4790 options:nsp=222 options:nsi=22 options:nshc1=flow options:nshc2=flow options:nshc3=flow options:nshc4=flow ofport_request=4 \
+ -- add-port br0 p5 -- set Interface p5 type=vxlan options:key=flow \
+ options:remote_ip=4.4.4.4 options:dst_port=4790 options:nsp=flow options:nsi=flow options:nshc1=flow options:nshc2=flow options:nshc3=flow options:nshc4=flow ofport_request=5 \
+ -- add-port br0 p6 -- set Interface p6 type=vxlan options:key=flow \
+ options:remote_ip=flow options:dst_port=4790 options:nsp=flow options:nsi=flow options:nshc1=flow options:nshc2=flow options:nshc3=flow options:nshc4=flow ofport_request=6])
+
+AT_CHECK([ovs-appctl netdev-dummy/ip4addr br0 2.2.2.22/24], [0], [OK
+])
+AT_CHECK([ovs-vsctl add-port br0 p7 -- set Interface p7 type=dummy ofport_request=7])
+AT_CHECK([ovs-vsctl add-port br0 p8 -- set Interface p8 type=dummy ofport_request=8])
+
+AT_CHECK([
+ovs-appctl ovs/route/add 1.1.1.1/24 br0
+ovs-appctl tnl/arp/set br0 1.1.1.1 68:05:ca:30:6b:d1
+ovs-appctl ovs/route/add 2.2.2.2/24 br0
+ovs-appctl tnl/arp/set br0 2.2.2.2 68:05:ca:30:6b:d2
+ovs-appctl ovs/route/add 3.3.3.3/24 br0
+ovs-appctl tnl/arp/set br0 3.3.3.3 68:05:ca:30:6b:d3
+ovs-appctl ovs/route/add 4.4.4.4/24 br0
+ovs-appctl tnl/arp/set br0 4.4.4.4 68:05:ca:30:6b:d4
+ovs-appctl ovs/route/add 5.5.5.5/24 br0
+ovs-appctl tnl/arp/set br0 5.5.5.5 68:05:ca:30:6b:d5
+],[0],[stdout])
+
+AT_DATA([flows.txt], [dnl
+in_port=7 actions=resubmit:1,resubmit:2,resubmit:3
+in_port=1 actions=output:1
+in_port=2 actions=set_field:3.3.3.3->tun_dst,output:2
+in_port=3 actions=output:3
+])
+AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
+AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(7),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=1,tos=0,ttl=128,frag=no), icmp(type=8,code=0)'], [0], [stdout])
+AT_CHECK([tail -1 stdout], [0],
+ [Datapath actions: tnl_push(tnl_port(4790),header(size=74,type=4,eth(dst=68:05:ca:30:6b:d1,src=aa:55:aa:55:00:00,dl_type=0x0800),ipv4(src=2.2.2.22,dst=1.1.1.1,proto=17,tos=0,ttl=64,frag=0x40),udp(src=0,dst=4790,csum=0x0),vxlangpe(vni=0x0,proto=4),nsh(mdtype=1,proto=3,nsp=0,nsi=1,nshc1=0,nshc2=0,nshc3=0,nshc4=0,)),out_port(100)),tnl_push(tnl_port(4790),header(size=74,type=4,eth(dst=68:05:ca:30:6b:d3,src=aa:55:aa:55:00:00,dl_type=0x0800),ipv4(src=2.2.2.22,dst=3.3.3.3,proto=17,tos=0,ttl=64,frag=0x40),udp(src=0,dst=4790,csum=0x0),vxlangpe(vni=0x0,proto=4),nsh(mdtype=1,proto=3,nsp=0,nsi=1,nshc1=0,nshc2=0,nshc3=0,nshc4=0,)),out_port(100)),tnl_push(tnl_port(4790),header(size=74,type=4,eth(dst=68:05:ca:30:6b:d2,src=aa:55:aa:55:00:00,dl_type=0x0800),ipv4(src=2.2.2.22,dst=2.2.2.2,proto=17,tos=0,ttl=64,frag=0x40),udp(src=0,dst=4790,csum=0x0),vxlangpe(vni=0x0,proto=4),nsh(mdtype=1,proto=3,nsp=6f0000,nsi=11,nshc1=b,nshc2=c,nshc3=d,nshc4=e,)),out_port(100))
+])
+
+AT_DATA([flows.txt], [dnl
+in_port=8 actions=resubmit:4,resubmit:5,resubmit:6
+in_port=4 actions=set_nshc1:22,set_nshc2:23,set_nshc3:24,set_nshc4:25,output:4
+in_port=5 actions=set_nsp:333,set_nsi:33,set_nshc1:33,set_nshc2:34,set_nshc3:35,set_nshc4:36,output:5
+in_port=6 actions=set_field:5.5.5.5->tun_dst,set_nsp:444,set_nsi:44,set_nshc1:44,set_nshc2:45,set_nshc3:46,set_nshc4:47,output:6
+])
+AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
+AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(8),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=1,tos=0,ttl=128,frag=no), icmp(type=8,code=0)'], [0], [stdout])
+AT_CHECK([tail -1 stdout], [0],
+ [Datapath actions: tnl_push(tnl_port(4790),header(size=74,type=4,eth(dst=68:05:ca:30:6b:d3,src=aa:55:aa:55:00:00,dl_type=0x0800),ipv4(src=2.2.2.22,dst=3.3.3.3,proto=17,tos=0,ttl=64,frag=0x40),udp(src=0,dst=4790,csum=0x0),vxlangpe(vni=0x0,proto=4),nsh(mdtype=1,proto=3,nsp=de0000,nsi=22,nshc1=16,nshc2=17,nshc3=18,nshc4=19,)),out_port(100)),tnl_push(tnl_port(4790),header(size=74,type=4,eth(dst=68:05:ca:30:6b:d4,src=aa:55:aa:55:00:00,dl_type=0x0800),ipv4(src=2.2.2.22,dst=4.4.4.4,proto=17,tos=0,ttl=64,frag=0x40),udp(src=0,dst=4790,csum=0x0),vxlangpe(vni=0x0,proto=4),nsh(mdtype=1,proto=3,nsp=4d0100,nsi=33,nshc1=21,nshc2=22,nshc3=23,nshc4=24,)),out_port(100)),tnl_push(tnl_port(4790),header(size=74,type=4,eth(dst=68:05:ca:30:6b:d5,src=aa:55:aa:55:00:00,dl_type=0x0800),ipv4(src=2.2.2.22,dst=5.5.5.5,proto=17,tos=0,ttl=64,frag=0x40),udp(src=0,dst=4790,csum=0x0),vxlangpe(vni=0x0,proto=4),nsh(mdtype=1,proto=3,nsp=bc0100,nsi=44,nshc1=2c,nshc2=2d,nshc3=2e,nshc4=2f,)),out_port(100))
+])
+OVS_VSWITCHD_STOP(["/The Open vSwitch kernel module is probably not loaded/d"])
+AT_CLEANUP
+
+AT_SETUP([tunnel VXLAN-GPE NSH - decap - nsh/nsi/nshc user space])
+OVS_VSWITCHD_START([add-port br0 p0 -- set Interface p0 type=dummy ofport_request=1 other-config:hwaddr=aa:55:aa:55:00:00])
+AT_CHECK([ovs-vsctl add-br int-br -- set bridge int-br datapath_type=dummy], [0])
+AT_CHECK([ovs-vsctl add-port int-br p1 -- set Interface p1 type=vxlan options:key=flow \
+ options:remote_ip=1.1.1.1 options:dst_port=4790 options:nsp=111 options:nsi=11 options:nshc1=11 options:nshc2=12 options:nshc3=13 options:nshc4=14 ofport_request=2 \
+ -- add-port int-br p2 -- set Interface p2 type=vxlan options:key=flow \
+ options:remote_ip=2.2.2.2 options:dst_port=4790 options:nsp=flow options:nsi=flow options:nshc1=flow options:nshc2=flow options:nshc3=flow options:nshc4=flow ofport_request=3 \
+ -- add-port int-br p3 -- set Interface p3 type=vxlan options:key=flow \
+ options:remote_ip=flow options:dst_port=4790 options:nsp=flow options:nsi=flow options:nshc1=flow options:nshc2=flow options:nshc3=flow options:nshc4=flow ofport_request=4], [0])
+
+AT_CHECK([ovs-appctl netdev-dummy/ip4addr br0 2.2.2.22/24], [0], [OK
+])
+AT_CHECK([ovs-appctl ovs/route/add 1.1.1.1/24 br0], [0], [OK
+])
+AT_CHECK([ovs-ofctl add-flow br0 action=normal])
+
+AT_CHECK([ovs-appctl dpif/show | tail -n +3], [0], [dnl
+ br0 65534/100: (dummy)
+ p0 1/1: (dummy)
+ int-br:
+ int-br 65534/2: (dummy)
+ p1 2/4790: (vxlan: dst_port=4790, key=flow, nshc1=0xb, nshc2=0xc, nshc3=0xd, nshc4=0xe, nsi=11, nsp=0x6f, remote_ip=1.1.1.1)
+ p2 3/4790: (vxlan: dst_port=4790, key=flow, nshc1=flow, nshc2=flow, nshc3=flow, nshc4=flow, nsi=flow, nsp=flow, remote_ip=2.2.2.2)
+ p3 4/4790: (vxlan: dst_port=4790, key=flow, nshc1=flow, nshc2=flow, nshc3=flow, nshc4=flow, nsi=flow, nsp=flow, remote_ip=flow)
+])
+
+AT_CHECK([ovs-appctl tnl/ports/show |sort], [0], [dnl
+Listening ports:
+vxlan_sys_4790 (4790)
+])
+
+AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(1),eth(src=50:54:00:00:00:05,dst=aa:55:aa:55:00:00),eth_type(0x0800),ipv4(src=1.1.1.1,dst=2.2.2.22,proto=17,tos=0,ttl=64,frag=no),udp(src=51283,dst=4790)'], [0], [stdout])
+AT_CHECK([tail -1 stdout], [0],
+ [Datapath actions: tnl_pop(4790)
+])
+
+AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(1),eth(src=50:54:00:00:00:05,dst=aa:55:aa:55:00:00),eth_type(0x0800),ipv4(src=2.2.2.2,dst=2.2.2.22,proto=17,tos=0,ttl=64,frag=no),udp(src=51283,dst=4790)'], [0], [stdout])
+AT_CHECK([tail -1 stdout], [0],
+ [Datapath actions: tnl_pop(4790)
+])
+
+AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(1),eth(src=50:54:00:00:00:05,dst=aa:55:aa:55:00:00),eth_type(0x0800),ipv4(src=3.4.5.6,dst=2.2.2.22,proto=17,tos=0,ttl=64,frag=no),udp(src=51283,dst=4790)'], [0], [stdout])
+AT_CHECK([tail -1 stdout], [0],
+ [Datapath actions: tnl_pop(4790)
+])
+
+OVS_VSWITCHD_STOP(["/The Open vSwitch kernel module is probably not loaded/d"])
+AT_CLEANUP
+
AT_SETUP([tunnel - Geneve metadata])
OVS_VSWITCHD_START([add-port br0 p1 -- set Interface p1 type=geneve \
options:remote_ip=1.1.1.1 ofport_request=1 \
--
1.9.3

File diff suppressed because it is too large Load Diff

View File

@ -1,730 +0,0 @@
Ethernet-NSH packet.
With this feature(options:nsh-convert=true),when VxLAN-GPE NSH packets (Outer
MAC header + Outer IP header + UDP header + VxLAN-GPE + NSH + original packet)
are received by VxLAN-GPE NSH port, the vport will remove Outer MAC header,
Outer IP header, UDP header, VxLAN-GPE header, and then modify and push the
outer MAC header. Then the packet with VxLAN-GPE+NSH format is converted to
Outer MAC header + NSH header + original packet.
Signed-off-by: Ricky Li <<A HREF="http://openvswitch.org/mailman/listinfo/dev">ricky.li at intel.com</A>>
Signed-off-by: Mengke Liu <<A HREF="http://openvswitch.org/mailman/listinfo/dev">mengke.liu at intel.com</A>>
---
datapath/linux/compat/include/linux/openvswitch.h | 6 +-
lib/netdev-vport.c | 109 +++++++++++++++++++++-
lib/netdev.h | 6 ++
lib/odp-util.c | 80 ++++++++++++++--
lib/ovs-router.c | 64 +++++++++++++
lib/ovs-router.h | 1 +
lib/packets.h | 13 ++-
ofproto/ofproto-dpif-xlate.c | 64 ++++++++++++-
ofproto/tunnel.c | 37 ++++++++
ofproto/tunnel.h | 5 +
tests/tunnel.at | 32 +++++++
11 files changed, 398 insertions(+), 19 deletions(-)
diff --git a/datapath/linux/compat/include/linux/openvswitch.h b/datapath/linux/compat/include/linux/openvswitch.h
index b8ac152..3d588bb 100644
--- a/datapath/linux/compat/include/linux/openvswitch.h
+++ b/datapath/linux/compat/include/linux/openvswitch.h
@@ -230,6 +230,7 @@ enum ovs_vport_type {
OVS_VPORT_TYPE_GENEVE, /* Geneve tunnel. */
OVS_VPORT_TYPE_LISP = 105, /* LISP tunnel */
OVS_VPORT_TYPE_STT = 106, /* STT tunnel */
+ OVS_VPORT_TYPE_NSH, /* L2+NSH ENCAP tunnel. */
__OVS_VPORT_TYPE_MAX
};
@@ -646,7 +647,10 @@ struct ovs_action_push_tnl {
uint8_t header[TNL_PUSH_HEADER_SIZE];
};
-#define OVS_POP_SPEC_ACTION_NO_DECAP 2
+enum ovs_pop_spec_action_type {
+ OVS_POP_SPEC_ACTION_CONVERT_TO_ETH_NSH,
+ OVS_POP_SPEC_ACTION_NO_DECAP = 2,
+};
/*
* struct ovs_action_pop_tnl - %OVS_ACTION_ATTR_TUNNEL_POP_SPEC
diff --git a/lib/netdev-vport.c b/lib/netdev-vport.c
index d926c00..6e0d5ba 100644
--- a/lib/netdev-vport.c
+++ b/lib/netdev-vport.c
@@ -561,6 +561,23 @@ set_tunnel_config(struct netdev *dev_, const struct smap *args)
} else {
tnl_cfg.ip_dst = in_addr.s_addr;
}
+ } else if (!strcmp(node->key, "remote_mac")) {
+ if (!strcmp(node->value, "flow")) {
+ tnl_cfg.eth_dst_flow = true;
+ VLOG_ERR("remote_mac doesn't support setting by flow");
+ return EINVAL;
+ } else if (eth_addr_from_string(node->value,&tnl_cfg.eth_dst)){
+ tnl_cfg.eth_dst_present = true;
+ } else {
+ VLOG_WARN("%s: bad %s 'remote_mac'", name, type);
+ return EINVAL;
+ }
+ } else if (!strcmp(node->key, "nsh_convert")) {
+ if (!strcmp(node->value, "true")) {
+ tnl_cfg.nsh_convert = true;
+ } else {
+ tnl_cfg.nsh_convert = false;
+ }
} else if (!strcmp(node->key, "tun_nodecap")) {
if (!strcmp(node->value, "true")) {
tnl_cfg.tun_nodecap = true;
@@ -883,6 +900,13 @@ get_tunnel_config(const struct netdev *dev, struct smap *args)
if (!tnl_cfg.dont_fragment) {
smap_add(args, "df_default", "false");
}
+ if (tnl_cfg.eth_dst_present) {
+ smap_add_format(args, "remote_mac", ETH_ADDR_FMT, ETH_ADDR_ARGS(tnl_cfg.eth_dst));
+ }
+
+ if (tnl_cfg.nsh_convert) {
+ smap_add(args, "nsh_convert", "true");
+ }
if (tnl_cfg.tun_nodecap) {
smap_add(args, "tun_nodecap", "true");
@@ -1546,6 +1570,84 @@ netdev_vxlan_pop_header(struct dp_packet *packet)
}
static int
+vxlan_extract_md_convert_to_eth_nsh(struct dp_packet *packet, const struct ovs_action_pop_tnl *data)
+{
+ struct pkt_metadata *md = &packet->md;
+ struct flow_tnl *tnl = &md->tunnel;
+ struct udp_header *udp;
+
+ memset(md, 0, sizeof *md);
+ if (VXLAN_HLEN > dp_packet_size(packet)) {
+ return EINVAL;
+ }
+
+ udp = ip_extract_tnl_md(packet, tnl);
+ if (!udp) {
+ return EINVAL;
+ }
+
+ if (ntohs(udp->udp_dst) == VXGPE_DST_PORT) {
+
+ struct vxgpehdr *vxg = (struct vxgpehdr *) (udp + 1);
+
+ if (get_16aligned_be32(&vxg->vx_vni) & htonl(0xff)) {
+ VLOG_WARN_RL(&err_rl, "invalid vxlan-gpe vni=%#x\n",
+ ntohl(get_16aligned_be32(&vxg->vx_vni)));
+ return EINVAL;
+ }
+
+ tnl->tp_src = udp->udp_src;
+ tnl->tp_dst = udp->udp_dst;
+ tnl->tun_id = htonll(ntohl(get_16aligned_be32(&vxg->vx_vni)) >> 8);
+
+ if (vxg->p == 0x01 && vxg->proto == VXG_P_NSH) {
+ struct nshhdr *nsh = (struct nshhdr *) (vxg + 1);
+ struct eth_header *eth = NULL;
+
+ tnl->nsp = nsh->b.b2 << 8;
+ tnl->nsi = nsh->b.svc_idx;
+ tnl->nshc1 = nsh->c.nshc1;
+ tnl->nshc2 = nsh->c.nshc2;
+ tnl->nshc3 = nsh->c.nshc3;
+ tnl->nshc4 = nsh->c.nshc4;
+ tnl->flags |= FLOW_TNL_F_NSP;
+ tnl->flags |= FLOW_TNL_F_NSI;
+ tnl->flags |= FLOW_TNL_F_NSH_C1 | FLOW_TNL_F_NSH_C2 | \
+ FLOW_TNL_F_NSH_C3 | FLOW_TNL_F_NSH_C4;
+ tnl->nsh_flags = NSH_TNL_F_ETHERNET;
+
+ dp_packet_reset_packet(packet, VXNSH_HLEN - sizeof (struct nshhdr));
+ eth = (struct eth_header *) dp_packet_push_uninit(packet, data->header_len);
+ memcpy(eth, data->header, data->header_len);
+ eth->eth_type = htons(ETH_TYPE_NSH);
+ } else {
+ VLOG_WARN("Unsupported vxlan GPE + NSH format!");
+ return EINVAL;
+ }
+
+ } else {
+
+ struct vxlanhdr *vxh = (struct vxlanhdr *) (udp + 1);
+
+ if (get_16aligned_be32(&vxh->vx_flags) != htonl(VXLAN_FLAGS) ||
+ (get_16aligned_be32(&vxh->vx_vni) & htonl(0xff))) {
+ VLOG_WARN_RL(&err_rl, "invalid vxlan flags=%#x vni=%#x\n",
+ ntohl(get_16aligned_be32(&vxh->vx_flags)),
+ ntohl(get_16aligned_be32(&vxh->vx_vni)));
+ return EINVAL;
+ }
+
+ tnl->tp_src = udp->udp_src;
+ tnl->tp_dst = udp->udp_dst;
+ tnl->tun_id = htonll(ntohl(get_16aligned_be32(&vxh->vx_vni)) >> 8);
+ dp_packet_reset_packet(packet, VXLAN_HLEN);
+ }
+
+ return 0;
+
+}
+
+static int
vxlan_extract_md_no_decap(struct dp_packet *packet)
{
struct pkt_metadata *md = &packet->md;
@@ -1595,6 +1697,7 @@ vxlan_extract_md_no_decap(struct dp_packet *packet)
tnl->flags |= FLOW_TNL_F_NSI;
tnl->flags |= FLOW_TNL_F_NSH_C1 | FLOW_TNL_F_NSH_C2 | \
FLOW_TNL_F_NSH_C3 | FLOW_TNL_F_NSH_C4;
+ tnl->tun_len = VXNSH_HLEN;
tnl->nsh_flags = NSH_TNL_F_NODECAP;
} else {
VLOG_WARN("Unsupported vxlan GPE + NSH format!");
@@ -1606,19 +1709,19 @@ vxlan_extract_md_no_decap(struct dp_packet *packet)
return 0;
}
-
static int
netdev_vxlan_pop_header_spec(struct dp_packet *packet,
const struct ovs_action_pop_tnl *data)
{
- if (data->pop_type == OVS_POP_SPEC_ACTION_NO_DECAP) {
+ if (data->pop_type == OVS_POP_SPEC_ACTION_CONVERT_TO_ETH_NSH) {
+ return vxlan_extract_md_convert_to_eth_nsh(packet, data);
+ } else if (data->pop_type == OVS_POP_SPEC_ACTION_NO_DECAP) {
return vxlan_extract_md_no_decap(packet);
}
return EINVAL;
}
-
static int
netdev_vxlan_build_header(const struct netdev *netdev,
struct ovs_action_push_tnl *data,
diff --git a/lib/netdev.h b/lib/netdev.h
index b30c932..26013ef 100644
--- a/lib/netdev.h
+++ b/lib/netdev.h
@@ -150,6 +150,10 @@ struct netdev_tunnel_config {
bool ipsec;
bool dont_fragment;
+ bool eth_dst_present;
+ bool eth_dst_flow;
+ struct eth_addr eth_dst;
+
bool in_nshc1_present;
bool in_nshc1_flow;
ovs_be32 in_nshc1; /* incoming NSH context c1 */
@@ -182,6 +186,7 @@ struct netdev_tunnel_config {
bool out_nshc4_flow;
ovs_be32 out_nshc4; /* outgoing NSH context c4 */
+ bool nsh_convert;
bool tun_nodecap;
};
@@ -247,6 +252,7 @@ int netdev_pop_header(struct netdev *netdev, struct dp_packet **buffers,
int netdev_pop_header_spec(struct netdev *netdev,
struct dp_packet **buffers, int cnt,
const struct ovs_action_pop_tnl *data);
+
/* Hardware address. */
int netdev_set_etheraddr(struct netdev *, const struct eth_addr mac);
int netdev_get_etheraddr(const struct netdev *, struct eth_addr *mac);
diff --git a/lib/odp-util.c b/lib/odp-util.c
index 190117f..6da2d5b 100644
--- a/lib/odp-util.c
+++ b/lib/odp-util.c
@@ -552,16 +552,22 @@ format_odp_tnl_push_header(struct ds *ds, struct ovs_action_push_tnl *data)
}
static void
-format_odp_tnl_pop_spec_action(struct ds *ds, const struct nlattr *attr)
+format_odp_tnl_pop_header(struct ds *ds, struct ovs_action_pop_tnl *data)
{
- struct ovs_action_pop_tnl *data;
+ const struct eth_header *eth;
- data = (struct ovs_action_pop_tnl *) nl_attr_get(attr);
+ eth = (const struct eth_header *)data->header;
+ if (data->tnl_type == OVS_VPORT_TYPE_NSH) {
+ const struct nshhdr *nsh = (const struct nshhdr *) (eth + 1);
- ds_put_format(ds, "tnl_pop_spec(tnl_port(%"PRIu32"),", data->tnl_port);
- if (data->pop_type == OVS_POP_SPEC_ACTION_NO_DECAP) {
- ds_put_format(ds, "pop_type=%"PRIu16")",
- OVS_POP_SPEC_ACTION_NO_DECAP);
+ /* Ethernet */
+ ds_put_format(ds, "header(size=%"PRIu8",type=%"PRIu8",eth(dst=",
+ data->header_len, data->tnl_type);
+ ds_put_format(ds, ETH_ADDR_FMT, ETH_ADDR_ARGS(eth->eth_dst));
+ ds_put_format(ds, ",src=");
+ ds_put_format(ds, ETH_ADDR_FMT, ETH_ADDR_ARGS(eth->eth_src));
+ ds_put_format(ds, ",dl_type=0x%04"PRIx16")", ntohs(eth->eth_type));
+ ds_put_format(ds, "),");
}
}
@@ -578,6 +584,26 @@ format_odp_tnl_push_action(struct ds *ds, const struct nlattr *attr)
}
static void
+format_odp_tnl_pop_spec_action(struct ds *ds, const struct nlattr *attr)
+{
+ struct ovs_action_pop_tnl *data;
+
+ data = (struct ovs_action_pop_tnl *) nl_attr_get(attr);
+
+ ds_put_format(ds, "tnl_pop_spec(tnl_port(%"PRIu32"),", data->tnl_port);
+ if (data->pop_type == OVS_POP_SPEC_ACTION_CONVERT_TO_ETH_NSH) {
+ ds_put_format(ds, "pop_type=%"PRIu16",",
+ OVS_POP_SPEC_ACTION_CONVERT_TO_ETH_NSH);
+ format_odp_tnl_pop_header(ds, data);
+ ds_put_format(ds, "out_port(%"PRIu32"))", data->out_port);
+
+ } else if (data->pop_type == OVS_POP_SPEC_ACTION_NO_DECAP) {
+ ds_put_format(ds, "pop_type=%"PRIu16")",
+ OVS_POP_SPEC_ACTION_NO_DECAP);
+ }
+}
+
+static void
format_odp_action(struct ds *ds, const struct nlattr *a)
{
int expected_len;
@@ -1050,11 +1076,8 @@ static int
ovs_parse_tnl_pop_spec(const char *s, struct ovs_action_pop_tnl *data)
{
struct eth_header *eth;
- struct nshhdr *nsh;
uint32_t tnl_type = 0, header_len = 0;
uint16_t dl_type;
- ovs_be32 nsp, nshc1, nshc2, nshc3, nshc4;
- uint8_t nsi;
int n = 0;
if (!ovs_scan_len(s, &n, "tnl_pop_spec(tnl_port(%"SCNi32"),",
&data->tnl_port)) {
@@ -1068,6 +1091,42 @@ ovs_parse_tnl_pop_spec(const char *s, struct ovs_action_pop_tnl *data)
if (data->pop_type == OVS_POP_SPEC_ACTION_NO_DECAP) {
return n;
+
+ } else if (data->pop_type == OVS_POP_SPEC_ACTION_CONVERT_TO_ETH_NSH) {
+
+ eth = (struct eth_header *) data->header;
+
+ if (!ovs_scan_len(s, &n, ",header(size=%"SCNi32",type=%"SCNi32","
+ "eth(dst="ETH_ADDR_SCAN_FMT",",
+ &data->header_len,
+ &data->tnl_type,
+ ETH_ADDR_SCAN_ARGS(eth->eth_dst))) {
+ return -EINVAL;
+ }
+ if (!ovs_scan_len(s, &n, "src="ETH_ADDR_SCAN_FMT",",
+ ETH_ADDR_SCAN_ARGS(eth->eth_src))) {
+ return -EINVAL;
+ }
+ if (!ovs_scan_len(s, &n, "dl_type=0x%"SCNx16"),", &dl_type)) {
+ return -EINVAL;
+ }
+ eth->eth_type = htons(dl_type);
+
+ tnl_type = OVS_VPORT_TYPE_NSH;
+ header_len = sizeof *eth;
+
+ /* check tunnel meta data. */
+ if (data->tnl_type != tnl_type) {
+ return -EINVAL;
+ }
+ if (data->header_len != header_len) {
+ return -EINVAL;
+ }
+
+ /* Out port */
+ if (!ovs_scan_len(s, &n, ",out_port(%"SCNi32"))", &data->out_port)) {
+ return -EINVAL;
+ }
} else {
return -EINVAL;
}
@@ -1075,6 +1134,7 @@ ovs_parse_tnl_pop_spec(const char *s, struct ovs_action_pop_tnl *data)
return n;
}
+
static int
parse_odp_action(const char *s, const struct simap *port_names,
struct ofpbuf *actions)
diff --git a/lib/ovs-router.c b/lib/ovs-router.c
index d6c7652..9f61bac 100644
--- a/lib/ovs-router.c
+++ b/lib/ovs-router.c
@@ -82,6 +82,24 @@ ovs_router_lookup(ovs_be32 ip_dst, char output_bridge[], ovs_be32 *gw)
return route_table_fallback_lookup(ip_dst, output_bridge, gw);
}
+bool
+ovs_router_lookup_mac(const struct eth_addr *mac, char output_bridge[])
+{
+ const struct cls_rule *cr;
+ struct flow s_flow;
+
+ memset(&s_flow, 0, sizeof (struct flow));
+ memcpy(s_flow.dl_dst.ea, mac->ea, ETH_ADDR_LEN);
+ cr = classifier_lookup(&cls,CLS_MAX_VERSION, &s_flow, NULL);
+ if (cr) {
+ struct ovs_router_entry *p = ovs_router_entry_cast(cr);
+
+ strncpy(output_bridge, p->output_bridge, IFNAMSIZ);
+ return true;
+ }
+ return false;
+}
+
static void
rt_entry_free(struct ovs_router_entry *p)
{
@@ -133,6 +151,36 @@ ovs_router_insert__(uint8_t priority, ovs_be32 ip_dst, uint8_t plen,
seq_change(tnl_conf_seq);
}
+static void
+ovs_router_insert_mac__(uint8_t priority, struct eth_addr *mac,
+ const char output_bridge[])
+{
+ const struct cls_rule *cr;
+ struct ovs_router_entry *p;
+ struct match s_match;
+
+ memset(&s_match, 0, sizeof (struct match));
+ memcpy(s_match.flow.dl_dst.ea, mac->ea, ETH_ADDR_LEN);
+
+ p = xzalloc(sizeof *p);
+ strncpy(p->output_bridge, output_bridge, IFNAMSIZ);
+ p->gw = 0;
+ p->nw_addr = 0;
+ p->plen = 32;
+ p->priority = priority;
+ cls_rule_init(&p->cr, &s_match, priority); /* Longest prefix matches first. */
+
+ ovs_mutex_lock(&mutex);
+ cr = classifier_replace(&cls, &p->cr, CLS_MIN_VERSION, NULL, 0);
+ ovs_mutex_unlock(&mutex);
+
+ if (cr) {
+ /* An old rule with the same match was displaced. */
+ ovsrcu_postpone(rt_entry_free, ovs_router_entry_cast(cr));
+ }
+ seq_change(tnl_conf_seq);
+}
+
void
ovs_router_insert(ovs_be32 ip_dst, uint8_t plen, const char output_bridge[],
ovs_be32 gw)
@@ -231,6 +279,20 @@ ovs_router_add(struct unixctl_conn *conn, int argc,
}
static void
+ovs_router_add_mac(struct unixctl_conn *conn, int argc OVS_UNUSED,
+ const char *argv[], void *aux OVS_UNUSED)
+{
+ struct eth_addr mac;
+
+ if (eth_addr_from_string(argv[1], &mac)) {
+ ovs_router_insert_mac__(48, &mac, argv[2]);
+ unixctl_command_reply(conn, "OK");
+ } else {
+ unixctl_command_reply(conn, "Invalid parameters");
+ }
+}
+
+static void
ovs_router_del(struct unixctl_conn *conn, int argc OVS_UNUSED,
const char *argv[], void *aux OVS_UNUSED)
{
@@ -326,6 +388,8 @@ ovs_router_init(void)
classifier_init(&cls, NULL);
unixctl_command_register("ovs/route/add", "ipv4_addr/prefix_len out_br_name gw", 2, 3,
ovs_router_add, NULL);
+ unixctl_command_register("ovs/route/addmac", "mac_addr out_br_name", 2, 2,
+ ovs_router_add_mac, NULL);
unixctl_command_register("ovs/route/show", "", 0, 0, ovs_router_show, NULL);
unixctl_command_register("ovs/route/del", "ipv4_addr/prefix_len", 1, 1, ovs_router_del,
NULL);
diff --git a/lib/ovs-router.h b/lib/ovs-router.h
index cc0ebc2..3f5a504 100644
--- a/lib/ovs-router.h
+++ b/lib/ovs-router.h
@@ -23,6 +23,7 @@
extern "C" {
#endif
+bool ovs_router_lookup_mac(const struct eth_addr *mac, char output_bridge[]);
bool ovs_router_lookup(ovs_be32 ip_dst, char out_dev[], ovs_be32 *gw);
void ovs_router_init(void);
void ovs_router_insert(ovs_be32 ip_dst, uint8_t plen,
diff --git a/lib/packets.h b/lib/packets.h
index 87c955a..c586390 100644
--- a/lib/packets.h
+++ b/lib/packets.h
@@ -33,6 +33,8 @@
struct dp_packet;
struct ds;
+#define ETH_ADDR_LEN 6
+
/* Tunnel information used in flow key and metadata. */
struct flow_tnl {
ovs_be32 ip_dst;
@@ -52,7 +54,9 @@ struct flow_tnl {
ovs_be32 nshc2;
ovs_be32 nshc3;
ovs_be32 nshc4;
- uint8_t pad1[7]; /* Pad to 64 bits. */
+ struct eth_addr eth_dst;
+ uint8_t tun_len;
+ uint8_t pad1[4]; /* Pad to 64 bits. */
struct tun_metadata metadata;
};
@@ -83,7 +87,9 @@ struct flow_tnl {
#define FLOW_TNL_F_NSH_C3 (1 << 9)
#define FLOW_TNL_F_NSH_C4 (1 << 10)
-#define NSH_TNL_F_NODECAP (1 << 1)
+#define NSH_TNL_F_ETHERNET (1 << 0)
+#define NSH_TNL_F_VXLAN (1 << 1)
+#define NSH_TNL_F_NODECAP (1 << 2)
/* Returns an offset to 'src' covering all the meaningful fields in 'src'. */
static inline size_t
@@ -160,8 +166,6 @@ pkt_metadata_init(struct pkt_metadata *md, odp_port_t port)
bool dpid_from_string(const char *s, uint64_t *dpidp);
-#define ETH_ADDR_LEN 6
-
static const struct eth_addr eth_addr_broadcast OVS_UNUSED
= { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff } } };
@@ -352,6 +356,7 @@ ovs_be32 set_mpls_lse_values(uint8_t ttl, uint8_t tc, uint8_t bos,
#define ETH_TYPE_RARP 0x8035
#define ETH_TYPE_MPLS 0x8847
#define ETH_TYPE_MPLS_MCAST 0x8848
+#define ETH_TYPE_NSH 0x894f
static inline bool eth_type_mpls(ovs_be16 eth_type)
{
diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c
index 71e255e..bff0a83 100644
--- a/ofproto/ofproto-dpif-xlate.c
+++ b/ofproto/ofproto-dpif-xlate.c
@@ -2690,6 +2690,36 @@ tnl_route_lookup_flow(const struct flow *oflow,
}
static int
+tnl_outdev_lookup_mac(const struct eth_addr *mac,
+ struct xport **out_port)
+{
+ char out_dev[IFNAMSIZ];
+ struct xbridge *xbridge;
+ struct xlate_cfg *xcfg;
+
+ if (!ovs_router_lookup_mac(mac, out_dev)) {
+ return -ENOENT;
+ }
+
+ xcfg = ovsrcu_get(struct xlate_cfg *, &xcfgp);
+ ovs_assert(xcfg);
+
+ HMAP_FOR_EACH (xbridge, hmap_node, &xcfg->xbridges) {
+ if (!strncmp(xbridge->name, out_dev, IFNAMSIZ)) {
+ struct xport *port;
+
+ HMAP_FOR_EACH (port, ofp_node, &xbridge->xports) {
+ if (!strncmp(netdev_get_name(port->netdev), out_dev, IFNAMSIZ)) {
+ *out_port = port;
+ return 0;
+ }
+ }
+ }
+ }
+ return -ENOENT;
+}
+
+static int
compose_table_xlate(struct xlate_ctx *ctx, const struct xport *out_dev,
struct dp_packet *packet)
{
@@ -2795,7 +2825,39 @@ build_tunnel_pop(const struct xlate_ctx *ctx, odp_port_t tunnel_odp_port, struct
cfg = tnl_port_cfg(tunnel_odp_port, flow);
if (cfg) {
- if (cfg->tun_nodecap) {
+ if (cfg->nsh_convert && (ntohs(cfg->dst_port) == VXGPE_DST_PORT)) {
+ struct ovs_action_pop_tnl tnl_pop_data;
+ struct xport *out_dev = NULL;
+ struct eth_addr smac;
+
+ int err;
+
+ err = tnl_outdev_lookup_mac(&cfg->eth_dst, &out_dev);
+ if (err) {
+ VLOG_WARN("tnl_outdev_lookup_mac failed...");
+ return err;
+ }
+
+ /* Use mac addr of bridge port of the peer. */
+ err = netdev_get_etheraddr(out_dev->netdev, &smac);
+ if (err) {
+ VLOG_WARN("netdev_get_etheraddr failed...");
+ return err;
+ }
+
+ err = tnl_port_build_nsh_header_odport_popspec(tunnel_odp_port, flow,
+ &cfg->eth_dst, &smac, &tnl_pop_data);
+ if (err) {
+ VLOG_WARN("tnl_port_build_nsh_header failed...");
+ return err;
+ }
+ tnl_pop_data.tnl_port = odp_to_u32(tunnel_odp_port);
+ tnl_pop_data.out_port = odp_to_u32(out_dev->odp_port);
+ tnl_pop_data.pop_type = OVS_POP_SPEC_ACTION_CONVERT_TO_ETH_NSH;
+ tnl_pop_data.tnl_type = OVS_VPORT_TYPE_NSH;
+ odp_put_tnl_pop_spec_action(ctx->odp_actions, &tnl_pop_data);
+
+ } else if (cfg->tun_nodecap) {
struct ovs_action_pop_tnl tnl_pop_data;
memset(&tnl_pop_data, 0, sizeof tnl_pop_data);
diff --git a/ofproto/tunnel.c b/ofproto/tunnel.c
index 4606fb6..b0e46e6 100644
--- a/ofproto/tunnel.c
+++ b/ofproto/tunnel.c
@@ -45,6 +45,8 @@ VLOG_DEFINE_THIS_MODULE(tunnel);
/* skb mark used for IPsec tunnel packets */
#define IPSEC_MARK 1
+#define ETH_NSH_HLEN (sizeof(struct eth_header) + \
+ sizeof(struct nshhdr))
struct tnl_match {
ovs_be64 in_key;
ovs_be32 in_nsp;
@@ -568,6 +570,9 @@ tnl_port_cfg(odp_port_t odp_port, struct flow *flow) OVS_EXCLUDED(rwlock)
cfg = netdev_get_tunnel_config(tnl_port->netdev);
ovs_assert(cfg);
+ if (!cfg->eth_dst_flow) {
+ memcpy(flow->tunnel.eth_dst.ea, cfg->eth_dst.ea, ETH_ADDR_LEN);
+ }
if (!cfg->out_nsp_flow) {
flow->tunnel.nsp = cfg->out_nsp;
}
@@ -602,6 +607,7 @@ out:
return cfg;
}
+
static uint32_t
tnl_hash(struct tnl_match *match)
{
@@ -1063,3 +1069,34 @@ tnl_port_build_header(const struct ofport_dpif *ofport,
return res;
}
+
+int
+tnl_port_build_nsh_header_odport_popspec(const odp_port_t odp_port,
+ const struct flow *tnl_flow OVS_UNUSED,
+ const struct eth_addr *dmac,
+ const struct eth_addr *smac,
+ struct ovs_action_pop_tnl *data)
+{
+ struct tnl_port *tnl_port;
+ struct eth_header *eth;
+ int res = 0;
+
+ fat_rwlock_rdlock(&rwlock);
+ tnl_port = tnl_find_odp_port(odp_port);
+ ovs_assert(tnl_port);
+
+ /* Build Ethernet and IP headers. */
+ memset(data->header, 0, sizeof data->header);
+
+ eth = (struct eth_header *)data->header;
+ memcpy(eth->eth_dst.ea, dmac->ea, ETH_ADDR_LEN);
+ memcpy(eth->eth_src.ea, smac->ea, ETH_ADDR_LEN);
+ eth->eth_type = htons(ETH_TYPE_NSH);
+
+ data->header_len = ETH_NSH_HLEN - sizeof (struct nshhdr);
+ data->tnl_type = OVS_VPORT_TYPE_NSH;
+
+ fat_rwlock_unlock(&rwlock);
+
+ return res;
+}
diff --git a/ofproto/tunnel.h b/ofproto/tunnel.h
index 2b608ce..0c51a4e 100644
--- a/ofproto/tunnel.h
+++ b/ofproto/tunnel.h
@@ -59,4 +59,9 @@ int tnl_port_build_header(const struct ofport_dpif *ofport,
const struct eth_addr dmac,
const struct eth_addr smac,
ovs_be32 ip_src, struct ovs_action_push_tnl *data);
+int tnl_port_build_nsh_header_odport_popspec(const odp_port_t odp_port,
+ const struct flow *tnl_flow OVS_UNUSED,
+ const struct eth_addr *dmac,
+ const struct eth_addr *smac,
+ struct ovs_action_pop_tnl *data);
#endif /* tunnel.h */
diff --git a/tests/tunnel.at b/tests/tunnel.at
index 851afdc..dc35809 100644
--- a/tests/tunnel.at
+++ b/tests/tunnel.at
@@ -673,6 +673,38 @@ AT_CHECK([tail -1 stdout], [0],
OVS_VSWITCHD_STOP(["/The Open vSwitch kernel module is probably not loaded/d"])
AT_CLEANUP
+AT_SETUP([tunnel - VXLAN-GPE NSH - nsh_convert from VXLAN-GPE NSH to Ethernet NSH - user space])
+OVS_VSWITCHD_START([add-port br0 p0 -- set Interface p0 type=dummy ofport_request=1 other-config:hwaddr=aa:55:aa:55:00:00])
+AT_CHECK([ovs-vsctl add-br int-br -- set bridge int-br datapath_type=dummy], [0])
+AT_CHECK([ovs-vsctl add-port int-br p1 -- set interface p1 type=vxlan options:remote_ip=1.1.1.1 options:dst_port=4790 \
+ options:nsh_convert=true options:nsi=flow options:nsp=flow options:nshc1=flow options:in_key=flow options:remote_mac=00:00:00:11:11:22 ofport_request=2])
+AT_CHECK([ovs-vsctl add-port int-br p2 -- set Interface p2 type=dummy ofport_request=3])
+
+AT_CHECK([ovs-appctl netdev-dummy/ip4addr br0 2.2.2.22/24], [0], [OK
+])
+AT_CHECK([ovs-appctl ovs/route/add 1.1.1.1/24 br0], [0], [OK
+])
+AT_CHECK([ovs-appctl ovs/route/addmac 00:00:00:11:11:22 br0],[0],[dnl
+OK
+])
+
+AT_CHECK([ovs-ofctl add-flow br0 action=normal])
+
+AT_CHECK([ovs-appctl tnl/ports/show |sort], [0], [dnl
+Listening ports:
+vxlan_sys_4790 (4790)
+])
+
+dnl remote_ip p0
+AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(3),eth(src=50:54:00:00:00:05,dst=aa:55:aa:55:00:00),eth_type(0x0800),ipv4(src=1.1.1.1,dst=2.2.2.22,proto=17,tos=0,ttl=64,frag=no),udp(src=8,dst=4790)'], [0], [stdout])
+
+AT_CHECK([tail -1 stdout], [0],
+ [Datapath actions: tnl_pop_spec(tnl_port(4790),pop_type=0,header(size=14,type=107,eth(dst=00:00:00:11:11:22,src=aa:55:aa:55:00:00,dl_type=0x894f)),out_port(100))
+])
+
+OVS_VSWITCHD_STOP(["/The Open vSwitch kernel module is probably not loaded/d"])
+AT_CLEANUP
+
AT_SETUP([tunnel - Geneve metadata])
OVS_VSWITCHD_START([add-port br0 p1 -- set Interface p1 type=geneve \
options:remote_ip=1.1.1.1 ofport_request=1 \
--
1.9.3

File diff suppressed because it is too large Load Diff

View File

@ -1,151 +0,0 @@
decapsulation-reencapsulation case.
When Ethernet NSH packets are received and then resent to Ethernet NSH port.
The decapsulation and encapsulation will be implemented. However, tunnel pop
and tunnel push actions are very time-consuming when decapsulation and
encapsulation.
With this feature (options:tun_nodecap=true), tunnel port will parse the input
tunnel packets, but the tunnel header will be kept. And the tunnel header can
be modified by the set field actions. This feature can improve performance.
Signed-off-by: Ricky Li <<A HREF="http://openvswitch.org/mailman/listinfo/dev">ricky.li at intel.com</A>>
Signed-off-by: Mengke Liu <<A HREF="http://openvswitch.org/mailman/listinfo/dev">mengke.liu at intel.com</A>>
---
lib/netdev-vport.c | 43 ++++++++++++++++++++++++++++++++++++++++++-
lib/odp-util.c | 3 ++-
lib/packets.c | 10 +++++++++-
tests/tunnel.at | 21 +++++++++++++++++++++
4 files changed, 74 insertions(+), 3 deletions(-)
diff --git a/lib/netdev-vport.c b/lib/netdev-vport.c
index 0a3da8d..038f1e1 100644
--- a/lib/netdev-vport.c
+++ b/lib/netdev-vport.c
@@ -1865,6 +1865,47 @@ netdev_nsh_pop_header(struct dp_packet *packet)
}
static int
+netdev_nsh_pop_header_spec(struct dp_packet *packet,
+ const struct ovs_action_pop_tnl *data)
+{
+ struct pkt_metadata *md = &packet->md;
+ struct flow_tnl *tnl = &md->tunnel;
+ struct eth_header *eth;
+ struct nshhdr *nsh;
+
+ if (data->pop_type == OVS_POP_SPEC_ACTION_NO_DECAP) {
+
+ pkt_metadata_init_tnl(md);
+ if (ETH_NSH_HLEN > dp_packet_size(packet)) {
+ return EINVAL;
+ }
+
+ eth = (struct eth_header *) dp_packet_data(packet);
+ memcpy(tnl->eth_dst.ea, eth->eth_dst.ea, ETH_ADDR_LEN);
+ memcpy(tnl->eth_src.ea, eth->eth_src.ea, ETH_ADDR_LEN);
+
+ nsh = (struct nshhdr *) (eth + 1);
+ tnl->nsp = nsh->b.b2 << 8;
+ tnl->nsi = nsh->b.svc_idx;
+ tnl->nshc1 = nsh->c.nshc1;
+ tnl->nshc2 = nsh->c.nshc2;
+ tnl->nshc3 = nsh->c.nshc3;
+ tnl->nshc4 = nsh->c.nshc4;
+ tnl->flags |= FLOW_TNL_F_NSP;
+ tnl->flags |= FLOW_TNL_F_NSI;
+ tnl->flags |= FLOW_TNL_F_NSH_C1 | FLOW_TNL_F_NSH_C2 | \
+ FLOW_TNL_F_NSH_C3 | FLOW_TNL_F_NSH_C4;
+
+ tnl->nsh_flags = NSH_TNL_F_ETHERNET_PARSED | NSH_TNL_F_ETHERNET_PRST| NSH_TNL_F_NODECAP;
+ tnl->tun_len = ETH_NSH_HLEN;
+
+ return 0;
+ }
+
+ return EINVAL;
+}
+
+static int
netdev_nsh_build_header(const struct netdev *netdev,
struct ovs_action_push_tnl *data,
const struct flow *tnl_flow)
@@ -2144,7 +2185,7 @@ netdev_vport_tunnel_register(void)
TUNNEL_CLASS("eth_nsh", "nsh_sys", netdev_nsh_build_header,
netdev_nsh_push_header,
netdev_nsh_pop_header,
- NULL),
+ netdev_nsh_pop_header_spec),
};
static struct ovsthread_once once = OVSTHREAD_ONCE_INITIALIZER;
diff --git a/lib/odp-util.c b/lib/odp-util.c
index c2af063..a87b3be 100644
--- a/lib/odp-util.c
+++ b/lib/odp-util.c
@@ -4837,7 +4837,8 @@ commit_odp_tunnel_set_action(const struct flow_tnl *tunnel, struct flow_tnl *bas
struct ofpbuf *odp_actions)
{
/* A valid IPV4_TUNNEL must have non-zero ip_dst. */
- if (tunnel->ip_dst) {
+ if (tunnel->ip_dst ||
+ tunnel->nsh_flags & NSH_TNL_F_ETHERNET_PARSED) {
if (!memcmp(tunnel, base, sizeof *tunnel)) {
return;
diff --git a/lib/packets.c b/lib/packets.c
index 7dab4b5..14a19b1 100644
--- a/lib/packets.c
+++ b/lib/packets.c
@@ -934,7 +934,15 @@ packet_set_nsh(struct dp_packet *packet, struct flow_tnl *tun_key)
eth = (struct eth_header *) dp_packet_data(packet);
- if (tun_key->nsh_flags & NSH_TNL_F_VXLAN_PRST) {
+ if (tun_key->nsh_flags & NSH_TNL_F_ETHERNET_PRST) {
+ nsh = (struct nshhdr *) (eth + 1);
+ nsh->b.b2 = tun_key->nsp >> 8;
+ nsh->b.svc_idx = tun_key->nsi;
+ nsh->c.nshc1 = tun_key->nshc1;
+ nsh->c.nshc2 = tun_key->nshc2;
+ nsh->c.nshc3 = tun_key->nshc3;
+ nsh->c.nshc4 = tun_key->nshc4;
+ } else if (tun_key->nsh_flags & NSH_TNL_F_VXLAN_PRST) {
struct ip_header *ip = (struct ip_header *) (eth + 1);
struct udp_header *udp = (struct udp_header *) (ip + 1);
struct vxgpehdr *vxg = (struct vxgpehdr *) (udp + 1);
diff --git a/tests/tunnel.at b/tests/tunnel.at
index 19221fb..1bbf5e2 100644
--- a/tests/tunnel.at
+++ b/tests/tunnel.at
@@ -765,6 +765,27 @@ AT_CHECK([tail -1 stdout], [0],
OVS_VSWITCHD_STOP(["/The Open vSwitch kernel module is probably not loaded/d"])
AT_CLEANUP
+AT_SETUP([tunnel - ETHERNET NSH tun_nodecap - user space])
+OVS_VSWITCHD_START([add-port br0 p0 -- set Interface p0 type=dummy ofport_request=1 other-config:hwaddr=aa:55:aa:55:00:00])
+AT_CHECK([ovs-vsctl add-port br0 p1 -- set interface p1 type=eth_nsh options:tun_nodecap=true options:remote_mac=00:00:00:11:11:22 \
+options:out_nsp=flow options:out_nsi=flow options:in_nshc1=flow options:in_nshc2=flow options:in_nshc3=flow options:in_nshc4=flow ofport_request=2], [0])
+
+AT_CHECK([ovs-ofctl add-flow br0 "priority=16, in_port=1, action=local"])
+
+AT_CHECK([ovs-appctl dpif/show | tail -n +3], [0], [dnl
+ br0 65534/100: (dummy)
+ p0 1/1: (dummy)
+ p1 2/2: (eth_nsh: in_nshc1=flow, in_nshc2=flow, in_nshc3=flow, in_nshc4=flow, out_nsi=flow, out_nsp=flow, remote_mac=00:00:00:11:11:22, tun_nodecap=true)
+])
+
+AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(1),eth(src=00:00:00:11:11:22,dst=50:54:00:00:00:07),eth_type(0x894f)'], [0], [stdout])
+AT_CHECK([tail -1 stdout], [0],
+ [Datapath actions: tnl_pop_spec(tnl_port(2),pop_type=2)
+])
+
+OVS_VSWITCHD_STOP(["/The Open vSwitch kernel module is probably not loaded/d"])
+AT_CLEANUP
+
AT_SETUP([tunnel - Geneve metadata])
OVS_VSWITCHD_START([add-port br0 p1 -- set Interface p1 type=geneve \
options:remote_ip=1.1.1.1 ofport_request=1 \
--
1.9.3

View File

@ -1,675 +0,0 @@
VxLAN-GPE NSH packet.
With this feature (options:nsh-convert=true),when Ethernet-NSH packet (Outer
MAC header + original packet) are received by Ethernet-NSH port, the vport
will remove Outer MAC header, and then modify and push the
outer MAC header + Outer IP header + UDP header + VxLAN-GPE. Then the packet
with Ethernet+NSH format is converted to VxLAN-GPE NSH packet.
Signed-off-by: Ricky Li <<A HREF="http://openvswitch.org/mailman/listinfo/dev">ricky.li at intel.com</A>>
Signed-off-by: Mengke Liu <<A HREF="http://openvswitch.org/mailman/listinfo/dev">mengke.liu at intel.com</A>>
---
datapath/linux/compat/include/linux/openvswitch.h | 3 +-
lib/netdev-vport.c | 128 +++++++++++++++++-----
lib/odp-util.c | 121 +++++++++++++++++++-
ofproto/ofproto-dpif-xlate.c | 113 ++++++++++++++++++-
ofproto/tunnel.c | 75 +++++++++++++
ofproto/tunnel.h | 7 ++
tests/tunnel.at | 29 +++++
7 files changed, 440 insertions(+), 36 deletions(-)
diff --git a/datapath/linux/compat/include/linux/openvswitch.h b/datapath/linux/compat/include/linux/openvswitch.h
index 045a1f4..916aeae 100644
--- a/datapath/linux/compat/include/linux/openvswitch.h
+++ b/datapath/linux/compat/include/linux/openvswitch.h
@@ -651,7 +651,8 @@ struct ovs_action_push_tnl {
enum ovs_pop_spec_action_type {
OVS_POP_SPEC_ACTION_CONVERT_TO_ETH_NSH,
- OVS_POP_SPEC_ACTION_NO_DECAP = 2,
+ OVS_POP_SPEC_ACTION_CONVERT_TO_VXLAN_GPE_NSH,
+ OVS_POP_SPEC_ACTION_NO_DECAP,
};
/*
diff --git a/lib/netdev-vport.c b/lib/netdev-vport.c
index 038f1e1..6142935 100644
--- a/lib/netdev-vport.c
+++ b/lib/netdev-vport.c
@@ -167,7 +167,8 @@ netdev_vport_needs_dst_port(const struct netdev *dev)
return (class->get_config == get_tunnel_config &&
(!strcmp("geneve", type) || !strcmp("vxlan", type) ||
- !strcmp("lisp", type) || !strcmp("stt", type)) );
+ !strcmp("lisp", type) || !strcmp("stt", type) ||
+ !strcmp("eth_nsh", type)) );
}
const char *
@@ -890,7 +891,8 @@ get_tunnel_config(const struct netdev *dev, struct smap *args)
if ((!strcmp("geneve", type) && dst_port != GENEVE_DST_PORT) ||
(!strcmp("vxlan", type) && dst_port != VXLAN_DST_PORT) ||
(!strcmp("lisp", type) && dst_port != LISP_DST_PORT) ||
- (!strcmp("stt", type) && dst_port != STT_DST_PORT)) {
+ (!strcmp("stt", type) && dst_port != STT_DST_PORT) ||
+ (!strcmp("eth_nsh", type) && tnl_cfg.nsh_convert)) {
smap_add_format(args, "dst_port", "%d", dst_port);
}
}
@@ -1864,42 +1866,116 @@ netdev_nsh_pop_header(struct dp_packet *packet)
return 0;
}
+
static int
-netdev_nsh_pop_header_spec(struct dp_packet *packet,
- const struct ovs_action_pop_tnl *data)
+eth_nsh_extract_md_no_decap(struct dp_packet *packet)
{
struct pkt_metadata *md = &packet->md;
struct flow_tnl *tnl = &md->tunnel;
struct eth_header *eth;
struct nshhdr *nsh;
- if (data->pop_type == OVS_POP_SPEC_ACTION_NO_DECAP) {
+ pkt_metadata_init_tnl(md);
+ if (ETH_NSH_HLEN > dp_packet_size(packet)) {
+ return EINVAL;
+ }
- pkt_metadata_init_tnl(md);
- if (ETH_NSH_HLEN > dp_packet_size(packet)) {
- return EINVAL;
- }
+ eth = (struct eth_header *) dp_packet_data(packet);
+ memcpy(tnl->eth_src.ea, eth->eth_src.ea, ETH_ADDR_LEN);
+ memcpy(tnl->eth_dst.ea, eth->eth_dst.ea, ETH_ADDR_LEN);
+
+ nsh = (struct nshhdr *) (eth + 1);
+ tnl->nsp = nsh->b.b2 << 8;
+ tnl->nsi = nsh->b.svc_idx;
+ tnl->nshc1 = nsh->c.nshc1;
+ tnl->nshc2 = nsh->c.nshc2;
+ tnl->nshc3 = nsh->c.nshc3;
+ tnl->nshc4 = nsh->c.nshc4;
+ tnl->flags |= FLOW_TNL_F_NSP;
+ tnl->flags |= FLOW_TNL_F_NSI;
+ tnl->flags |= FLOW_TNL_F_NSH_C1 | FLOW_TNL_F_NSH_C2 | \
+ FLOW_TNL_F_NSH_C3 | FLOW_TNL_F_NSH_C4;
+ tnl->nsh_flags = NSH_TNL_F_ETHERNET_PARSED | NSH_TNL_F_ETHERNET_PRST| NSH_TNL_F_NODECAP;
+ tnl->tun_len = ETH_NSH_HLEN;
+
+ return 0;
+}
+
+static int
+eth_nsh_extract_md_convert_to_vxlan_gpe_nsh(struct dp_packet *packet,
+ const struct ovs_action_pop_tnl *data)
+{
+ struct pkt_metadata *md = &packet->md;
+ struct flow_tnl *tnl = &md->tunnel;
+ struct eth_header *eth;
+ struct ip_header *ip;
+ struct udp_header *udp;
+ struct nshhdr *nsh;
+
+ pkt_metadata_init_tnl(md);
+ if (ETH_NSH_HLEN > dp_packet_size(packet)) {
+ return EINVAL;
+ }
+
+ eth = (struct eth_header *) dp_packet_data(packet);
+ memcpy(tnl->eth_src.ea, eth->eth_src.ea, ETH_ADDR_LEN);
+ memcpy(tnl->eth_dst.ea, eth->eth_dst.ea, ETH_ADDR_LEN);
- eth = (struct eth_header *) dp_packet_data(packet);
- memcpy(tnl->eth_dst.ea, eth->eth_dst.ea, ETH_ADDR_LEN);
- memcpy(tnl->eth_src.ea, eth->eth_src.ea, ETH_ADDR_LEN);
-
- nsh = (struct nshhdr *) (eth + 1);
- tnl->nsp = nsh->b.b2 << 8;
- tnl->nsi = nsh->b.svc_idx;
- tnl->nshc1 = nsh->c.nshc1;
- tnl->nshc2 = nsh->c.nshc2;
- tnl->nshc3 = nsh->c.nshc3;
- tnl->nshc4 = nsh->c.nshc4;
- tnl->flags |= FLOW_TNL_F_NSP;
- tnl->flags |= FLOW_TNL_F_NSI;
- tnl->flags |= FLOW_TNL_F_NSH_C1 | FLOW_TNL_F_NSH_C2 | \
+ nsh = (struct nshhdr *) (eth + 1);
+ tnl->nsp = nsh->b.b2 << 8;
+ tnl->nsi = nsh->b.svc_idx;
+ tnl->nshc1 = nsh->c.nshc1;
+ tnl->nshc2 = nsh->c.nshc2;
+ tnl->nshc3 = nsh->c.nshc3;
+ tnl->nshc4 = nsh->c.nshc4;
+
+ tnl->flags |= FLOW_TNL_F_NSP;
+ tnl->flags |= FLOW_TNL_F_NSI;
+ tnl->flags |= FLOW_TNL_F_NSH_C1 | FLOW_TNL_F_NSH_C2 | \
FLOW_TNL_F_NSH_C3 | FLOW_TNL_F_NSH_C4;
- tnl->nsh_flags = NSH_TNL_F_ETHERNET_PARSED | NSH_TNL_F_ETHERNET_PRST| NSH_TNL_F_NODECAP;
- tnl->tun_len = ETH_NSH_HLEN;
+ tnl->nsh_flags = NSH_TNL_F_ETHERNET_PARSED | NSH_TNL_F_VXLAN_PRST;
- return 0;
+ dp_packet_reset_packet(packet, ETH_NSH_HLEN - sizeof (struct nshhdr));
+ eth = (struct eth_header *) dp_packet_push_uninit(packet, data->header_len);
+ memcpy(eth, data->header, data->header_len);
+
+
+ /* set IP length, csum */
+ int ip_tot_size = dp_packet_size(packet) - sizeof (struct eth_header);
+ ip = ip_hdr(eth);
+ ip->ip_tot_len = htons(ip_tot_size);
+ ip->ip_csum = recalc_csum16(ip->ip_csum, 0, ip->ip_tot_len);
+
+ /* set udp src port */
+ udp = (struct udp_header *) (ip + 1);
+ udp->udp_src = get_src_port(packet);
+ udp->udp_len = htons(ip_tot_size - sizeof (struct ip_header));
+
+ /* udp_csum is zero */
+ if (udp->udp_csum) {
+ uint32_t csum = packet_csum_pseudoheader(ip);
+
+ csum = csum_continue(csum, udp,
+ ip_tot_size - sizeof (struct ip_header));
+ udp->udp_csum = csum_finish(csum);
+
+ if (!udp->udp_csum) {
+ udp->udp_csum = htons(0xffff);
+ }
+ }
+
+ return 0;
+}
+
+static int
+netdev_nsh_pop_header_spec(struct dp_packet *packet,
+ const struct ovs_action_pop_tnl *data)
+{
+ if (data->pop_type == OVS_POP_SPEC_ACTION_CONVERT_TO_VXLAN_GPE_NSH) {
+ return eth_nsh_extract_md_convert_to_vxlan_gpe_nsh(packet, data);
+ } else if (data->pop_type == OVS_POP_SPEC_ACTION_NO_DECAP) {
+ return eth_nsh_extract_md_no_decap(packet);
}
return EINVAL;
diff --git a/lib/odp-util.c b/lib/odp-util.c
index a87b3be..183844f 100644
--- a/lib/odp-util.c
+++ b/lib/odp-util.c
@@ -515,7 +515,7 @@ format_odp_tnl_push_header(struct ds *ds, struct ovs_action_push_tnl *data)
gnh->oam ? "oam," : "",
gnh->critical ? "crit," : "",
ntohl(get_16aligned_be32(&gnh->vni)) >> 8);
-
+
if (gnh->opt_len) {
ds_put_cstr(ds, ",options(");
format_geneve_opts(gnh->options, NULL, gnh->opt_len * 4,
@@ -579,10 +579,11 @@ static void
format_odp_tnl_pop_header(struct ds *ds, struct ovs_action_pop_tnl *data)
{
const struct eth_header *eth;
+ const struct ip_header *ip;
+ const void *l3;
eth = (const struct eth_header *)data->header;
if (data->tnl_type == OVS_VPORT_TYPE_NSH) {
- const struct nshhdr *nsh = (const struct nshhdr *) (eth + 1);
/* Ethernet */
ds_put_format(ds, "header(size=%"PRIu8",type=%"PRIu8",eth(dst=",
@@ -591,7 +592,37 @@ format_odp_tnl_pop_header(struct ds *ds, struct ovs_action_pop_tnl *data)
ds_put_format(ds, ",src=");
ds_put_format(ds, ETH_ADDR_FMT, ETH_ADDR_ARGS(eth->eth_src));
ds_put_format(ds, ",dl_type=0x%04"PRIx16")", ntohs(eth->eth_type));
- ds_put_format(ds, "),");
+ ds_put_format(ds, "),");
+ } else if (data->tnl_type == OVS_VPORT_TYPE_VXLAN) {
+ l3 = eth + 1;
+ ip = (const struct ip_header *)l3;
+
+ /* Ethernet */
+ ds_put_format(ds, "header(size=%"PRIu8",type=%"PRIu8",eth(dst=",
+ data->header_len, data->tnl_type);
+ ds_put_format(ds, ETH_ADDR_FMT, ETH_ADDR_ARGS(eth->eth_dst));
+ ds_put_format(ds, ",src=");
+ ds_put_format(ds, ETH_ADDR_FMT, ETH_ADDR_ARGS(eth->eth_src));
+ ds_put_format(ds, ",dl_type=0x%04"PRIx16"),", ntohs(eth->eth_type));
+
+ /* IPv4 */
+ ds_put_format(ds, "ipv4(src="IP_FMT",dst="IP_FMT",proto=%"PRIu8
+ ",tos=%#"PRIx8",ttl=%"PRIu8",frag=0x%"PRIx16"),",
+ IP_ARGS(get_16aligned_be32(&ip->ip_src)),
+ IP_ARGS(get_16aligned_be32(&ip->ip_dst)),
+ ip->ip_proto, ip->ip_tos,
+ ip->ip_ttl,
+ ip->ip_frag_off);
+ if (data->tnl_type == OVS_VPORT_TYPE_VXLAN) {
+ const struct vxlanhdr *vxh;
+
+ vxh = format_udp_tnl_push_header(ds, ip);
+
+ ds_put_format(ds, "vxlan(flags=0x%"PRIx32",vni=0x%"PRIx32")",
+ ntohl(get_16aligned_be32(&vxh->vx_flags)),
+ ntohl(get_16aligned_be32(&vxh->vx_vni)) >> 8);
+ }
+ ds_put_format(ds, "),");
}
}
@@ -615,9 +646,10 @@ format_odp_tnl_pop_spec_action(struct ds *ds, const struct nlattr *attr)
data = (struct ovs_action_pop_tnl *) nl_attr_get(attr);
ds_put_format(ds, "tnl_pop_spec(tnl_port(%"PRIu32"),", data->tnl_port);
- if (data->pop_type == OVS_POP_SPEC_ACTION_CONVERT_TO_ETH_NSH) {
+ if (data->pop_type == OVS_POP_SPEC_ACTION_CONVERT_TO_ETH_NSH ||
+ data->pop_type == OVS_POP_SPEC_ACTION_CONVERT_TO_VXLAN_GPE_NSH) {
ds_put_format(ds, "pop_type=%"PRIu16",",
- OVS_POP_SPEC_ACTION_CONVERT_TO_ETH_NSH);
+ data->pop_type);
format_odp_tnl_pop_header(ds, data);
ds_put_format(ds, "out_port(%"PRIu32"))", data->out_port);
@@ -1174,6 +1206,85 @@ ovs_parse_tnl_pop_spec(const char *s, struct ovs_action_pop_tnl *data)
if (!ovs_scan_len(s, &n, ",out_port(%"SCNi32"))", &data->out_port)) {
return -EINVAL;
}
+ } else if (data->pop_type == OVS_POP_SPEC_ACTION_CONVERT_TO_VXLAN_GPE_NSH) {
+ struct eth_header *eth;
+ struct ip_header *ip;
+ struct udp_header *udp;
+ uint16_t dl_type, udp_src, udp_dst, csum;
+ ovs_be32 sip, dip;
+ uint32_t tnl_type = 0, header_len = 0;
+ void *l3, *l4;
+ int n = 0;
+
+ eth = (struct eth_header *) data->header;
+ l3 = (data->header + sizeof *eth);
+ l4 = ((uint8_t *) l3 + sizeof (struct ip_header));
+ ip = (struct ip_header *) l3;
+ if (!ovs_scan_len(s, &n, "header(size=%"SCNi32",type=%"SCNi32","
+ "eth(dst="ETH_ADDR_SCAN_FMT",",
+ &data->header_len,
+ &data->tnl_type,
+ ETH_ADDR_SCAN_ARGS(eth->eth_dst))) {
+ return -EINVAL;
+ }
+
+ if (!ovs_scan_len(s, &n, "src="ETH_ADDR_SCAN_FMT",",
+ ETH_ADDR_SCAN_ARGS(eth->eth_src))) {
+ return -EINVAL;
+ }
+ if (!ovs_scan_len(s, &n, "dl_type=0x%"SCNx16"),", &dl_type)) {
+ return -EINVAL;
+ }
+ eth->eth_type = htons(dl_type);
+
+ /* IPv4 */
+ if (!ovs_scan_len(s, &n, "ipv4(src="IP_SCAN_FMT",dst="IP_SCAN_FMT",proto=%"SCNi8
+ ",tos=%"SCNi8",ttl=%"SCNi8",frag=0x%"SCNx16"),",
+ IP_SCAN_ARGS(&sip),
+ IP_SCAN_ARGS(&dip),
+ &ip->ip_proto, &ip->ip_tos,
+ &ip->ip_ttl, &ip->ip_frag_off)) {
+ return -EINVAL;
+ }
+ put_16aligned_be32(&ip->ip_src, sip);
+ put_16aligned_be32(&ip->ip_dst, dip);
+
+ /* Tunnel header */
+ udp = (struct udp_header *) l4;
+ if (ovs_scan_len(s, &n, "udp(src=%"SCNi16",dst=%"SCNi16",csum=0x%"SCNx16"),",
+ &udp_src, &udp_dst, &csum)) {
+ uint32_t vx_flags, vni;
+
+ udp->udp_src = htons(udp_src);
+ udp->udp_dst = htons(udp_dst);
+ udp->udp_len = 0;
+ udp->udp_csum = htons(csum);
+
+ if (ovs_scan_len(s, &n, "vxlan(flags=0x%"SCNx32",vni=0x%"SCNx32"))",
+ &vx_flags, &vni)) {
+ struct vxlanhdr *vxh = (struct vxlanhdr *) (udp + 1);
+
+ put_16aligned_be32(&vxh->vx_flags, htonl(vx_flags));
+ put_16aligned_be32(&vxh->vx_vni, htonl(vni << 8));
+ tnl_type = OVS_VPORT_TYPE_VXLAN;
+ header_len = sizeof *eth + sizeof *ip +
+ sizeof *udp + sizeof *vxh;
+ } else {
+ return -EINVAL;
+ }
+ /* check tunnel meta data. */
+ if (data->tnl_type != tnl_type) {
+ return -EINVAL;
+ }
+ if (data->header_len != header_len) {
+ return -EINVAL;
+ }
+
+ /* Out port */
+ if (!ovs_scan_len(s, &n, ",out_port(%"SCNi32"))", &data->out_port)) {
+ return -EINVAL;
+ }
+ }
} else {
return -EINVAL;
}
diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c
index 90b5a95..1578a0c 100644
--- a/ofproto/ofproto-dpif-xlate.c
+++ b/ofproto/ofproto-dpif-xlate.c
@@ -2653,7 +2653,7 @@ process_special(struct xlate_ctx *ctx, const struct xport *xport)
}
static int
-tnl_route_lookup_flow(const struct flow *oflow,
+tnl_route_lookup_flow__(ovs_be32 ip_dst,
ovs_be32 *ip, struct xport **out_port)
{
char out_dev[IFNAMSIZ];
@@ -2661,14 +2661,14 @@ tnl_route_lookup_flow(const struct flow *oflow,
struct xlate_cfg *xcfg;
ovs_be32 gw;
- if (!ovs_router_lookup(oflow->tunnel.ip_dst, out_dev, &gw)) {
+ if (!ovs_router_lookup(ip_dst, out_dev, &gw)) {
return -ENOENT;
}
if (gw) {
*ip = gw;
} else {
- *ip = oflow->tunnel.ip_dst;
+ *ip = ip_dst;
}
xcfg = ovsrcu_get(struct xlate_cfg *, &xcfgp);
@@ -2690,6 +2690,12 @@ tnl_route_lookup_flow(const struct flow *oflow,
}
static int
+tnl_route_lookup_flow(const struct flow *oflow,
+ ovs_be32 *ip, struct xport **out_port){
+ return tnl_route_lookup_flow__(oflow->tunnel.ip_dst, ip, out_port);
+}
+
+static int
tnl_outdev_lookup_mac(const struct eth_addr *mac,
struct xport **out_port)
{
@@ -2818,6 +2824,100 @@ build_tunnel_send(struct xlate_ctx *ctx, const struct xport *xport,
}
static int
+build_eth_nsh_tunnel_pop(struct xlate_ctx *ctx, odp_port_t tunnel_odp_port, struct flow *flow)
+{
+ const struct netdev_tunnel_config * cfg;
+
+ cfg = tnl_port_cfg(tunnel_odp_port, flow);
+
+ if (cfg) {
+ if (cfg->nsh_convert && (ntohs(cfg->dst_port) == VXGPE_DST_PORT)) {
+
+ struct ovs_action_pop_tnl tnl_pop_data;
+ struct xport *out_dev = NULL;
+ ovs_be32 s_ip, d_ip = 0;
+ struct eth_addr smac;
+ struct eth_addr dmac;
+ int err;
+
+ err = tnl_route_lookup_flow__(cfg->ip_dst, &d_ip, &out_dev);
+ if (err) {
+ xlate_report(ctx, "native tunnel routing failed");
+ return err;
+ }
+ xlate_report(ctx, "tunneling to "IP_FMT" via %s",
+ IP_ARGS(d_ip), netdev_get_name(out_dev->netdev));
+
+ /* Use mac addr of bridge port of the peer. */
+ err = netdev_get_etheraddr(out_dev->netdev, &smac);
+ if (err) {
+ xlate_report(ctx, "tunnel output device lacks Ethernet address");
+ return err;
+ }
+
+ err = netdev_get_in4(out_dev->netdev, (struct in_addr *) &s_ip, NULL);
+ if (err) {
+ xlate_report(ctx, "tunnel output device lacks IPv4 address");
+ return err;
+ }
+
+ err = tnl_arp_lookup(out_dev->xbridge->name, d_ip, &dmac);
+ if (err) {
+ xlate_report(ctx, "ARP cache miss for "IP_FMT" on bridge %s, "
+ "sending ARP request",
+ IP_ARGS(d_ip), out_dev->xbridge->name);
+ tnl_send_arp_request(ctx, out_dev, smac, s_ip, d_ip);
+ return err;
+ }
+ if (ctx->xin->xcache) {
+ struct xc_entry *entry;
+
+ entry = xlate_cache_add_entry(ctx->xin->xcache, XC_TNL_ARP);
+ ovs_strlcpy(entry->u.tnl_arp_cache.br_name, out_dev->xbridge->name,
+ sizeof entry->u.tnl_arp_cache.br_name);
+ entry->u.tnl_arp_cache.d_ip = d_ip;
+ }
+
+ xlate_report(ctx, "tunneling from "ETH_ADDR_FMT" "IP_FMT
+ " to "ETH_ADDR_FMT" "IP_FMT,
+ ETH_ADDR_ARGS(smac), IP_ARGS(s_ip),
+ ETH_ADDR_ARGS(dmac), IP_ARGS(d_ip));
+ err = tnl_port_build_header_odport_popspec(tunnel_odp_port, cfg,
+ dmac, smac, s_ip, &tnl_pop_data);
+ if (err) {
+ return err;
+ }
+ tnl_pop_data.tnl_port = odp_to_u32(tunnel_odp_port);
+ tnl_pop_data.out_port = odp_to_u32(out_dev->odp_port);
+ tnl_pop_data.tnl_type = OVS_VPORT_TYPE_VXLAN;
+ tnl_pop_data.pop_type = OVS_POP_SPEC_ACTION_CONVERT_TO_VXLAN_GPE_NSH;
+ odp_put_tnl_pop_spec_action(ctx->odp_actions, &tnl_pop_data);
+
+ } else if (cfg->tun_nodecap) {
+ struct ovs_action_pop_tnl tnl_pop_data;
+ memset(&tnl_pop_data, 0, sizeof tnl_pop_data);
+
+ tnl_pop_data.tnl_port = odp_to_u32(tunnel_odp_port);
+ tnl_pop_data.pop_type = OVS_POP_SPEC_ACTION_NO_DECAP;
+ odp_put_tnl_pop_spec_action(ctx->odp_actions, &tnl_pop_data);
+
+ } else {
+ nl_msg_put_odp_port(ctx->odp_actions,
+ OVS_ACTION_ATTR_TUNNEL_POP,
+ tunnel_odp_port);
+ }
+
+ } else {
+ nl_msg_put_odp_port(ctx->odp_actions,
+ OVS_ACTION_ATTR_TUNNEL_POP,
+ tunnel_odp_port);
+ }
+
+ return 0;
+}
+
+
+static int
build_tunnel_pop(const struct xlate_ctx *ctx, odp_port_t tunnel_odp_port, struct flow *flow)
{
const struct netdev_tunnel_config * cfg;
@@ -3185,7 +3285,12 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port,
if (odp_tnl_port != ODPP_NONE &&
!(flow->tunnel.nsh_flags & NSH_TNL_F_NODECAP)) {
flow_tnl = flow->tunnel;
- build_tunnel_pop(ctx, odp_tnl_port, flow);
+ if(flow->dl_type == htons(ETH_TYPE_NSH)) {
+ build_eth_nsh_tunnel_pop(ctx, odp_tnl_port, flow);
+ }
+ else {
+ build_tunnel_pop(ctx, odp_tnl_port, flow);
+ }
flow->tunnel = flow_tnl;
} else {
/* Tunnel push-pop action is not compatible with
diff --git a/ofproto/tunnel.c b/ofproto/tunnel.c
index cc0c91a..e279e92 100644
--- a/ofproto/tunnel.c
+++ b/ofproto/tunnel.c
@@ -47,6 +47,13 @@ VLOG_DEFINE_THIS_MODULE(tunnel);
#define ETH_NSH_HLEN (sizeof(struct eth_header) + \
sizeof(struct nshhdr))
+
+#define VXNSH_HLEN (sizeof(struct eth_header) + \
+ sizeof(struct ip_header) + \
+ sizeof(struct udp_header) + \
+ sizeof(struct vxgpehdr) + \
+ sizeof(struct nshhdr))
+
struct tnl_match {
ovs_be64 in_key;
ovs_be32 in_nsp;
@@ -1044,6 +1051,74 @@ tnl_port_get_name(const struct tnl_port *tnl_port) OVS_REQ_RDLOCK(rwlock)
}
int
+tnl_port_build_header_odport_popspec(const odp_port_t odp_port,
+ const struct netdev_tunnel_config *cfg,
+ const struct eth_addr dmac,
+ const struct eth_addr smac,
+ ovs_be32 ip_src, struct ovs_action_pop_tnl *data)
+{
+ struct tnl_port *tnl_port;
+ struct eth_header *eth;
+ struct ip_header *ip;
+ struct udp_header *udp;
+ void *l3;
+
+ fat_rwlock_rdlock(&rwlock);
+ tnl_port = tnl_find_odp_port(odp_port);
+ ovs_assert(tnl_port);
+
+ /* Build Ethernet headers. */
+ memset(data->header, 0, sizeof data->header);
+
+ eth = (struct eth_header *)data->header;
+ eth->eth_dst = dmac;
+ eth->eth_src = smac;
+ eth->eth_type = htons(ETH_TYPE_IP);
+
+ l3 = (eth + 1);
+ ip = (struct ip_header *) l3;
+
+ /* Build IP header */
+ ip->ip_ihl_ver = IP_IHL_VER(5, 4);
+ ip->ip_tos = cfg->tos;
+ ip->ip_ttl = cfg->ttl;
+ ip->ip_frag_off = cfg->dont_fragment ? htons(IP_DF) : 0;
+ put_16aligned_be32(&ip->ip_src, ip_src);
+ put_16aligned_be32(&ip->ip_dst, cfg->ip_dst);
+ ip->ip_proto = IPPROTO_UDP;
+ ip->ip_csum = csum(ip, sizeof *ip);
+
+ /* Build UDP header */
+ udp = (struct udp_header *) (ip + 1);
+ udp->udp_dst = cfg->dst_port;
+
+ if (cfg->csum) {
+ /* Write a value in now to mark that we should compute the checksum
+ * later. 0xffff is handy because it is transparent to the
+ * calculation. */
+ udp->udp_csum = htons(0xffff);
+ }
+ /* Build VxLAN-GPE header */
+ if (ntohs(udp->udp_dst) == VXGPE_DST_PORT){
+ struct vxgpehdr *vxg = (struct vxgpehdr *) (udp + 1);
+
+ memset(vxg, 0, sizeof *vxg);
+ vxg->i = 0x01;
+ vxg->p = 0x01;
+ vxg->ver = 0x01;
+ vxg->proto = VXG_P_NSH;
+ put_16aligned_be32(&vxg->vx_vni, htonl(ntohll(cfg->out_key) << 8));
+
+ }
+
+ data->header_len = VXNSH_HLEN - sizeof (struct nshhdr);
+ data->tnl_type = OVS_VPORT_TYPE_VXLAN;
+
+ fat_rwlock_unlock(&rwlock);
+ return 0;
+}
+
+int
tnl_port_build_header(const struct ofport_dpif *ofport,
const struct flow *tnl_flow,
const struct eth_addr dmac,
diff --git a/ofproto/tunnel.h b/ofproto/tunnel.h
index d771476..9f2f11d 100644
--- a/ofproto/tunnel.h
+++ b/ofproto/tunnel.h
@@ -55,6 +55,13 @@ tnl_port_should_receive(const struct flow *flow)
memcmp(flow->tunnel.eth_dst.ea, &eth_addr_zero, ETH_ADDR_LEN));
}
+int
+tnl_port_build_header_odport_popspec(const odp_port_t odp_port,
+ const struct netdev_tunnel_config *cfg,
+ const struct eth_addr dmac,
+ const struct eth_addr smac,
+ ovs_be32 ip_src, struct ovs_action_pop_tnl *data);
+
int tnl_port_build_header(const struct ofport_dpif *ofport,
const struct flow *tnl_flow,
const struct eth_addr dmac,
diff --git a/tests/tunnel.at b/tests/tunnel.at
index 1bbf5e2..c740966 100644
--- a/tests/tunnel.at
+++ b/tests/tunnel.at
@@ -786,6 +786,35 @@ AT_CHECK([tail -1 stdout], [0],
OVS_VSWITCHD_STOP(["/The Open vSwitch kernel module is probably not loaded/d"])
AT_CLEANUP
+AT_SETUP([tunnel - ETHERNET - nsh_convert from Ethernet NSH to VXLAN-GPE NSH - user space])
+OVS_VSWITCHD_START([add-port br0 p0 -- set Interface p0 type=dummy ofport_request=1 other-config:hwaddr=aa:55:aa:55:00:00])
+AT_CHECK([ovs-vsctl add-port br0 p1 -- set interface p1 type=eth_nsh options:remote_mac=00:00:00:11:11:22 options:nsh_convert=true \
+options:nsi=flow options:nsp=flow options:nshc1=flow options:in_key=flow options:remote_ip=1.1.1.1 options:dst_port=4790 ofport_request=2], [0])
+
+AT_CHECK([ovs-appctl netdev-dummy/ip4addr br0 2.2.2.22/24], [0], [OK
+])
+
+AT_CHECK([
+ovs-appctl ovs/route/add 1.1.1.1/24 br0
+ovs-appctl tnl/arp/set br0 1.1.1.1 68:05:ca:30:6b:d1
+],[0],[stdout])
+
+AT_CHECK([ovs-ofctl add-flow br0 "priority=16, in_port=1, action=local"])
+
+AT_CHECK([ovs-appctl dpif/show | tail -n +3], [0], [dnl
+ br0 65534/100: (dummy)
+ p0 1/1: (dummy)
+ p1 2/4790: (eth_nsh: dst_port=4790, in_key=flow, nsh_convert=true, nshc1=flow, nsi=flow, nsp=flow, remote_ip=1.1.1.1, remote_mac=00:00:00:11:11:22)
+])
+
+AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(1),eth(src=00:00:00:11:11:22,dst=50:54:00:00:00:07),eth_type(0x894f)'], [0], [stdout])
+AT_CHECK([tail -1 stdout], [0],
+ [Datapath actions: tnl_pop_spec(tnl_port(4790),pop_type=1,header(size=50,type=4,eth(dst=68:05:ca:30:6b:d1,src=aa:55:aa:55:00:00,dl_type=0x0800),ipv4(src=2.2.2.22,dst=1.1.1.1,proto=17,tos=0,ttl=64,frag=0x40),udp(src=0,dst=4790,csum=0x0),vxlan(flags=0xc400004,vni=0x0)),out_port(100))
+])
+
+OVS_VSWITCHD_STOP(["/The Open vSwitch kernel module is probably not loaded/d"])
+AT_CLEANUP
+
AT_SETUP([tunnel - Geneve metadata])
OVS_VSWITCHD_START([add-port br0 p1 -- set Interface p1 type=geneve \
options:remote_ip=1.1.1.1 ofport_request=1 \
--
1.9.3

1
ovs_build/patches/README Normal file
View File

@ -0,0 +1 @@
The patches were copied from https://github.com/yyang13/ovs_nsh_patches

View File

@ -5,26 +5,23 @@ set -eux
BUILD_FOR=${BUILD_FOR:-ubuntu}
DIR="$(dirname `readlink -f $0`)"
INCLUDE_DEPENDENCIES=${INCLUDE_DEPENDENCIES:-true}
function download_dependencies {
if [ "$INCLUDE_DEPENDENCIES" = true ]
then
wget --content-disposition -N -i "${DIR}/ovs_package/${1}/dependencies.txt"
fi
}
function build_pkg {
case $1 in
ubuntu)
pushd "${DIR}/repositories/${1}/"
download_dependencies ${1}
popd
cd ${DIR}/ovs_build
sudo docker build -t ovs_build .
sudo docker run -v ${DIR}/repositories/ubuntu/:/deb -t ovs_build /ovs_build/build-ovs-nsh.sh
sudo docker run -v ${DIR}/repositories/ubuntu/:/deb -t ovs_build /ovs_build/build-ovs-dpdk.sh
sudo docker run -v ${DIR}/repositories/ubuntu/:/deb -t ovs_build /ovs_build/build-ovs-nsh-dpdk.sh
rm -rf ${DIR}/repositories/ubuntu; mkdir -p ${DIR}/repositories/ubuntu
rm -rf ${DIR}/tmp/; mkdir -p ${DIR}/tmp/; chmod 777 ${DIR}/tmp
sudo docker run -v ${DIR}/tmp:/deb -t ovs_build /ovs_build/build-ovs-dpdk.sh
cp -r ${DIR}/tmp/*.deb ${DIR}/repositories/ubuntu
rm -rf ${DIR}/ovs_package/ubuntu; mkdir -p ${DIR}/ovs_package/ubuntu
rm -rf ${DIR}/tmp/; mkdir -p ${DIR}/tmp/; chmod 777 ${DIR}/tmp
sudo docker run -v ${DIR}/tmp:/deb -t ovs_build /ovs_build/build-ovs-nsh-dpdk.sh
cp -r ${DIR}/tmp/*.deb ${DIR}/ovs_package/ubuntu
rm -rf ${DIR}/tmp/;
;;
*) echo "Not supported system"; exit 1;;
esac

View File

@ -1,25 +0,0 @@
#!/bin/bash
set -eux
INSTALL_HOME=/tmp/ovs-nshdpdk
rm -rf $INSTALL_HOME; mkdir -p $INSTALL_HOME
cd $INSTALL_HOME
wget -r -nd -np http://10.20.0.2:8080/plugins/fuel-plugin-ovs-0.9/repositories/ubuntu
if [ $1 = 'nshdpdk' ]
then
dpkg -i openvswitch-datapath-dkms_2.4.90.nshdpdk-1_all.deb
dpkg -i openvswitch-common_2.4.90.nshdpdk-1_amd64.deb
dpkg -i openvswitch-switch_2.4.90.nshdpdk-1_amd64.deb
elif [ $1 = 'nsh' ]
then
dpkg -i openvswitch-datapath-dkms_2.4.90.nsh-1_all.deb
dpkg -i openvswitch-common_2.4.90.nsh-1_amd64.deb
dpkg -i openvswitch-switch_2.4.90.nsh-1_amd64.deb
elif [ $1 = 'dpdk' ]
then
dpkg -i openvswitch-datapath-dkms_2.4.90.dpdk-1_all.deb
dpkg -i openvswitch-common_2.4.90.dpdk-1_amd64.deb
dpkg -i openvswitch-switch_2.4.90.dpdk-1_amd64.deb
fi

View File

@ -1,8 +1 @@
- id: ovs_install_compute
role: ['compute']
stage: pre_deployment
type: puppet
parameters:
puppet_manifest: puppet/manifests/ovs-install-compute.pp
puppet_modules: puppet/modules:/etc/puppet/modules
timeout: 720
[]