summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFerenc Cserepkei <ferenc.cserepkei@ericsson.com>2016-05-21 17:22:12 +0200
committerFerenc Cserepkei <ferenc.cserepkei@ericsson.com>2016-05-23 10:40:49 +0200
commitea5194730b935a5364ac5719ee9a88800b08f329 (patch)
treed64d5da394c7fbc49956d747d3e5f8855404d54a
parent27eaf16ac1ca2849f85e85e969c6e322c8cb42ae (diff)
fuel-plugin-ovs with Yi Y Yang NSH patchesstable/8.0
This change applies Yi's patchset https://github.com/yyang13/ovs_nsh_patches in fuel-plugin-ovs instead of the aging Pritesh NSH v8 patchset. Besides that upgrades Openvswith used from 2.4-rc1 to 2.5 LTS in the plugin hence the deployed OPNFV/Fuel Brahmaputra SR-2 cluster. Change-Id: Ia6a71664228979f56575d37ca9f1e28c0bb6cf46 Signed-off-by: Ferenc Cserepkei <ferenc.cserepkei@ericsson.com>
Notes
Notes (review): Code-Review+2: Ruijing <ruijing.guo@intel.com> Workflow+1: Ruijing <ruijing.guo@intel.com> Verified+2: Jenkins Submitted-by: Jenkins Submitted-at: Thu, 26 May 2016 01:15:50 +0000 Reviewed-on: https://review.openstack.org/319580 Project: openstack/fuel-plugin-ovs Branch: refs/heads/stable/8.0
-rw-r--r--ovs-nsh/Dockerfile31
-rwxr-xr-xovs-nsh/build-ovs-nsh-dpdk.sh45
-rwxr-xr-xovs-nsh/build-ovs-nsh.sh26
-rw-r--r--ovs-nsh/patches/060679.patch3187
-rw-r--r--ovs-nsh/patches/060680.patch788
-rw-r--r--ovs-nsh/patches/060681.patch1025
-rw-r--r--ovs-nsh/patches/060682.patch730
-rw-r--r--ovs-nsh/patches/060683.patch1334
-rw-r--r--ovs-nsh/patches/060684.patch151
-rw-r--r--ovs-nsh/patches/060685.patch675
-rw-r--r--ovs-nsh/patches/17a6124.patch259
-rw-r--r--ovs-nsh/patches/21bd423.patch2291
-rw-r--r--ovs-nsh/patches/299fc5b.patch68
-rw-r--r--ovs-nsh/patches/bf1e7ff.patch2714
-rw-r--r--ovs-nsh/patches/eeaf57e.patch711
-rwxr-xr-xpre_build_hook18
-rwxr-xr-xrepositories/ubuntu/dpdk/dpdk-install.sh20
-rw-r--r--repositories/ubuntu/dpdk/dpdk.init2
-rwxr-xr-xrepositories/ubuntu/ovs/ovs-install.sh13
19 files changed, 6134 insertions, 7954 deletions
diff --git a/ovs-nsh/Dockerfile b/ovs-nsh/Dockerfile
index 9d23652..54e54a9 100644
--- a/ovs-nsh/Dockerfile
+++ b/ovs-nsh/Dockerfile
@@ -2,26 +2,31 @@
2 2
3FROM ubuntu:14.04.3 3FROM ubuntu:14.04.3
4 4
5ENV HOME /root
5RUN rm -rf /lib/modules 6RUN rm -rf /lib/modules
6RUN apt-get update 7RUN apt-get update
7RUN apt-get install -y software-properties-common python-software-properties \ 8RUN apt-get install -y software-properties-common python-software-properties\
8 make python-setuptools python-all dpkg-dev debhelper \ 9 make python-setuptools apt-utils autoconf automake bind9-host\
9 fuseiso git genisoimage bind9-host wget curl lintian tmux lxc iptables \ 10 build-essential bzip2 ca-certificates curl debhelper dh-autoreconf\
10 ca-certificates sudo apt-utils lsb-release libtool autoconf automake build-essential fakeroot libssl-dev graphviz dh-autoreconf python-qt4 python-twisted-conch python-zopeinterface linux-headers-3.13.0-76-generic 11 dpkg-dev fakeroot fuseiso genisoimage git graphviz iptables\
12 libssl-dev libtool lintian python-flake8 dh-python\
13 lsb-release lxc openssl procps python-all python-qt4 python-setuptools\
14 python-six python-twisted-conch python-zopeinterface python3-six\
15 sudo tmux wget linux-headers-3.13.0-85-generic
11 16
12RUN ln -s /lib/modules/3.13.0-76-generic /lib/modules/`uname -r` 17RUN ln -s /lib/modules/3.13.0-85-generic /lib/modules/$(uname -r)
13 18
14RUN apt-get install -y pkg-config unzip liblua5.2-dev libpcap-dev libedit-dev libncurses5-dev libncursesw5-dev 19RUN apt-get install -y pkg-config unzip liblua5.2-dev libpcap0.8-dev libcap-ng-dev libedit-dev libncurses5-dev libncursesw5-dev
15 20
16RUN echo "ALL ALL=NOPASSWD: ALL" > /etc/sudoers.d/open-sudo 21RUN echo "ALL ALL=NOPASSWD: ALL" > /etc/sudoers.d/open-sudo
17RUN chmod 0440 /etc/sudoers.d/open-sudo 22RUN chmod 0440 /etc/sudoers.d/open-sudo
18 23
19ADD ./patches /patches 24ADD ./patches /root/patches
20 25
21ADD ./build-ovs-nsh.sh /build-ovs-nsh.sh 26ADD ./build-ovs-nsh.sh /root/build-ovs-nsh.sh
22RUN chmod +x /build-ovs-nsh.sh 27RUN chmod +x /root/build-ovs-nsh.sh
23RUN /build-ovs-nsh.sh 28RUN /root/build-ovs-nsh.sh
24 29
25ADD ./build-ovs-nsh-dpdk.sh /build-ovs-nsh-dpdk.sh 30ADD ./build-ovs-nsh-dpdk.sh /root/build-ovs-nsh-dpdk.sh
26RUN chmod +x /build-ovs-nsh-dpdk.sh 31RUN chmod +x /root/build-ovs-nsh-dpdk.sh
27RUN /build-ovs-nsh-dpdk.sh 32RUN /root/build-ovs-nsh-dpdk.sh
diff --git a/ovs-nsh/build-ovs-nsh-dpdk.sh b/ovs-nsh/build-ovs-nsh-dpdk.sh
index 1f9e7cc..481ec4b 100755
--- a/ovs-nsh/build-ovs-nsh-dpdk.sh
+++ b/ovs-nsh/build-ovs-nsh-dpdk.sh
@@ -1,13 +1,17 @@
1#!/bin/bash 1#!/bin/bash
2 2
3DPDK_VER=2.1.0 3DPDK_VER=2.2.0
4URL_DPDK=http://dpdk.org/browse/dpdk/snapshot/dpdk-${DPDK_VER}.tar.gz
5export RTE_SDK=/root/dpdk-${DPDK_VER}
6export RTE_TARGET=x86_64-native-linuxapp-gcc
7export DPDK_BUILD=${RTE_SDK}/${RTE_TARGET}
4 8
5OVS_COMMIT=121daded51b9798fe3722824b27a05c16806cbd1 9
6RTE_TARGET=x86_64-native-linuxapp-gcc 10OVS_COMMIT=7d433ae57ebb90cd68e8fa948a096f619ac4e2d8
7PATCHES="060679 060680 060681 060682 060683 060684 060685"
8URL_OVS=https://github.com/openvswitch/ovs.git 11URL_OVS=https://github.com/openvswitch/ovs.git
9URL_DPDK=http://dpdk.org/browse/dpdk/snapshot/dpdk-${DPDK_VER}.tar.gz 12PATCHES="eeaf57e bf1e7ff 21bd423 17a6124 299fc5b"
10 13
14cd $HOME
11wget ${URL_DPDK} 15wget ${URL_DPDK}
12tar -xzvf dpdk-${DPDK_VER}.tar.gz 16tar -xzvf dpdk-${DPDK_VER}.tar.gz
13cd dpdk-${DPDK_VER} 17cd dpdk-${DPDK_VER}
@@ -15,36 +19,37 @@ sed -i -e 's/CONFIG_RTE_LIBRTE_VHOST=n/CONFIG_RTE_LIBRTE_VHOST=y/' \
15 -e 's/CONFIG_RTE_BUILD_COMBINE_LIBS=n/CONFIG_RTE_BUILD_COMBINE_LIBS=y/' \ 19 -e 's/CONFIG_RTE_BUILD_COMBINE_LIBS=n/CONFIG_RTE_BUILD_COMBINE_LIBS=y/' \
16 -e 's/CONFIG_RTE_PKTMBUF_HEADROOM=128/CONFIG_RTE_PKTMBUF_HEADROOM=256/' \ 20 -e 's/CONFIG_RTE_PKTMBUF_HEADROOM=128/CONFIG_RTE_PKTMBUF_HEADROOM=256/' \
17 config/common_linuxapp 21 config/common_linuxapp
18cd / 22cd $HOME
19tar -czvf dpdk-${DPDK_VER}.tar.gz dpdk-${DPDK_VER} 23tar -czvf dpdk-${DPDK_VER}.tar.gz dpdk-${DPDK_VER}
20cd dpdk-${DPDK_VER} 24cd dpdk-${DPDK_VER}
21make install T=${RTE_TARGET} 25make install T=${RTE_TARGET}
22find . | grep "\.o$" | xargs rm -rf 26find . | grep "\.o$" | xargs rm -rf
23cd / 27cd $HOME
24tar czvf dpdk-${DPDK_VER}.bin.tar.gz dpdk-${DPDK_VER} 28tar czvf dpdk-${DPDK_VER}.bin.tar.gz dpdk-${DPDK_VER}
25 29
30cd $HOME
31
26git clone ${URL_OVS} openvswitch-dpdk 32git clone ${URL_OVS} openvswitch-dpdk
33
27cd openvswitch-dpdk 34cd openvswitch-dpdk
28git checkout ${OVS_COMMIT} -b development 35git checkout ${OVS_COMMIT} -b yyang13
29for patch in ${PATCHES} 36for patch in ${PATCHES}
30do 37do
31 patch -p1 < /patches/${patch}.patch 38 patch -p1 < ${HOME}/patches/${patch}.patch
32done 39done
33export RTE_SDK=/dpdk-${DPDK_VER} 40
34export DPDK_BUILD=${RTE_SDK}/${RTE_TARGET}
35./boot.sh 41./boot.sh
36./configure --with-dpdk=$DPDK_BUILD 42./configure --with-dpdk=$DPDK_BUILD
37sed -i "s?set ovs-vswitchd unix?set ovs-vswitchd --dpdk -c 0x1 -n 4 -- unix?" utilities/ovs-ctl.in;sed -i "s?configure --with-linux?configure --with-dpdk=/dpdk-2.1.0/x86_64-native-linuxapp-gcc --with-linux?" debian/dkms.conf.in;sed -i "s?configure --with-linux?configure --with-dpdk=/dpdk-2.1.0/x86_64-native-linuxapp-gcc --with-linux?" debian/rules.modules;sed -i "s?configure --?configure -- --with-dpdk=/dpdk-2.1.0/x86_64-native-linuxapp-gcc?" debian/rules;make dist;tar -xzf openvswitch-2.4.90.tar.gz; 43sed -i "s?set ovs-vswitchd unix?set ovs-vswitchd --dpdk -c 0x1 -n 4 -- unix?" utilities/ovs-ctl.in;sed -i "s?configure --with-linux?configure --with-dpdk=$DPDK_BUILD --with-linux?" debian/dkms.conf.in;sed -i "s?configure --with-linux?configure --with-dpdk=$DPDK_BUILD --with-linux?" debian/rules.modules;sed -i "s?configure --?configure -- --with-dpdk=$DPDK_BUILD?" debian/rules;make dist;tar -xzf openvswitch-2.5.90.tar.gz;
38cd openvswitch-2.4.90;DEB_BUILD_OPTIONS='parallel=8 nocheck' fakeroot debian/rules binary 44cd openvswitch-2.5.90;DEB_BUILD_OPTIONS='parallel=8 nocheck' fakeroot debian/rules binary
39 45
40 46
41cd / 47cd $HOME
42wget https://01.org/sites/default/files/downloads/intel-data-plane-performance-demonstrators/dppd-prox-v021.zip 48wget https://01.org/sites/default/files/downloads/intel-data-plane-performance-demonstrators/dppd-prox-v021.zip
43unzip dppd-prox-v021.zip 49unzip dppd-prox-v021.zip
44export RTE_SDK=/dpdk-${DPDK_VER} 50
45export RTE_TARGET=x86_64-native-linuxapp-gcc 51cd dppd-PROX-v021
46cd /dppd-PROX-v021 52export DPPD_DIR=$(pwd); make
47export DPPD_DIR=`pwd`; make
48find . | grep "\.o$" | xargs rm -rf 53find . | grep "\.o$" | xargs rm -rf
49cd / 54cd $HOME
50tar czvf dppd-prox-v021.bin.tar.gz dppd-PROX-v021 55tar -czvf dppd-prox-v021.bin.tar.gz dppd-PROX-v021
diff --git a/ovs-nsh/build-ovs-nsh.sh b/ovs-nsh/build-ovs-nsh.sh
index 9a5fc9c..b0aede6 100755
--- a/ovs-nsh/build-ovs-nsh.sh
+++ b/ovs-nsh/build-ovs-nsh.sh
@@ -1,16 +1,30 @@
1#!/bin/bash 1#!/bin/bash
2 2
3OVS_COMMIT=121daded51b9798fe3722824b27a05c16806cbd1 3OVS_COMMIT=7d433ae57ebb90cd68e8fa948a096f619ac4e2d8
4PATCHES="060679 060680 060681 060682 060683 060684 060685"
5URL_OVS=https://github.com/openvswitch/ovs.git 4URL_OVS=https://github.com/openvswitch/ovs.git
6 5
6PATCHES="eeaf57e bf1e7ff 21bd423 17a6124 299fc5b"
7
8cd $HOME
9
7git clone ${URL_OVS} openvswitch 10git clone ${URL_OVS} openvswitch
11
8cd openvswitch 12cd openvswitch
9git checkout ${OVS_COMMIT} -b development 13git checkout ${OVS_COMMIT} -b yyang13
10for patch in ${PATCHES} 14for patch in ${PATCHES}
11do 15do
12 patch -p1 < /patches/${patch}.patch 16 patch -p1 < ${HOME}/patches/${patch}.patch
13done 17done
14 18
15./boot.sh;./configure;make dist;tar -xzf openvswitch-2.4.90.tar.gz 19./boot.sh
16cd openvswitch-2.4.90;dpkg-checkbuilddeps;DEB_BUILD_OPTIONS='parallel=8 nocheck' fakeroot debian/rules binary 20./configure --prefix=/usr --sysconfdir=/etc --localstatedir=/var --with-linux=/lib/modules/$(uname -r)/build
21make dist
22OVSTBALL=$(echo openvswitch-*.tar.gz)
23OVSART='openvswitch-2.5.90'
24
25
26tar -xzf ${HOME}/openvswitch/$OVSTBALL
27cd $OVSART
28dpkg-checkbuilddeps
29DEB_BUILD_OPTIONS='parallel=8 nocheck' fakeroot debian/rules binary
30
diff --git a/ovs-nsh/patches/060679.patch b/ovs-nsh/patches/060679.patch
deleted file mode 100644
index 635cf1d..0000000
--- a/ovs-nsh/patches/060679.patch
+++ /dev/null
@@ -1,3187 +0,0 @@
1VxLAN-GPE NSH decapsulation and encapsulation implementation at data plane
2level in kernel space and rules related with NSH match and actions at control
3plane level.
4
5The VXLAN-GPE NSH type are enabled in this patch. The design is based on basic
6VxLAN implementation. The UDP port 4790 is used for VXLAN-GPE NSH type. When
7VxLAN-GPE NSH packets are received from VxLAN-GPE NSH port, the decapsulation
8will be implemented and the fields related with NSH will be parsed. When
9packets are sent to VxLAN-GPE NSH port, the encapsulation will be implemented
10according to the VxLAN-GPE NSH configuration and related rules.
11
12Notes:
13(1) port 4790 is for VxLAN-GPE NSH extension.
14(2) new options for VxLAN-GPE NSH: service path header(nsp, nsi) and context
15header with NSH MD-type 1(nshc1, nshc2, nshc3, nshc4). These fields have
16fixed/flow setting: fixed value indicates input value in related field must be
17fixed value detected by this port and output value in related field will be set
18as fixed value when encapsulation is implemented; flow value indicates the
19input value is checked by the openflow rule and output value is set by the
20openflow rule.
21(3) new related actions: Add 6 new actions for NSH set fields: set_nsp,
22set_nsi,set_nshc1,set_nshc1,set_nshc3,set_nshc4
23
24Signed-off-by: Pritesh Kothari <<A HREF="http://openvswitch.org/mailman/listinfo/dev">pritkoth at cisco.com</A>>
25Signed-off-by: Ricky Li <<A HREF="http://openvswitch.org/mailman/listinfo/dev">ricky.li at intel.com</A>>
26Signed-off-by: Mengke Liu <<A HREF="http://openvswitch.org/mailman/listinfo/dev">mengke.liu at intel.com</A>>
27---
28 datapath/flow.h | 30 +-
29 datapath/flow_netlink.c | 70 ++++
30 datapath/linux/Modules.mk | 1 +
31 datapath/linux/compat/include/linux/openvswitch.h | 6 +
32 datapath/linux/compat/include/net/ip_tunnels.h | 8 +
33 datapath/linux/compat/include/net/nsh.h | 103 ++++++
34 datapath/linux/compat/include/net/vxlan.h | 20 +-
35 datapath/linux/compat/vxlan.c | 97 +++++-
36 datapath/vport-geneve.c | 2 +-
37 datapath/vport-gre.c | 2 +-
38 datapath/vport-lisp.c | 2 +-
39 datapath/vport-stt.c | 2 +-
40 datapath/vport-vxlan.c | 15 +-
41 datapath/vport.c | 5 +
42 lib/flow.c | 48 +++
43 lib/match.c | 90 ++++++
44 lib/match.h | 14 +
45 lib/meta-flow.c | 135 ++++++++
46 lib/meta-flow.h | 102 ++++++
47 lib/netdev-vport.c | 289 ++++++++++++++++-
48 lib/netdev.h | 49 +++
49 lib/nx-match.c | 6 +
50 lib/odp-util.c | 147 ++++++++-
51 lib/odp-util.h | 8 +-
52 lib/ofp-actions.c | 353 +++++++++++++++++++-
53 lib/ofp-actions.h | 48 +++
54 lib/ofp-parse.c | 13 +
55 lib/ofp-parse.h | 1 +
56 lib/packets.h | 16 +-
57 ofproto/ofproto-dpif-xlate.c | 31 +-
58 ofproto/tunnel.c | 374 +++++++++++++++++++---
59 ofproto/tunnel.h | 1 -
60 tests/ofproto.at | 10 +-
61 tests/tunnel.at | 115 +++++++
62 34 files changed, 2126 insertions(+), 87 deletions(-)
63 create mode 100644 datapath/linux/compat/include/net/nsh.h
64
65diff --git a/datapath/flow.h b/datapath/flow.h
66index 2433436..78774a1 100644
67--- a/datapath/flow.h
68+++ b/datapath/flow.h
69@@ -39,9 +39,18 @@ struct sk_buff;
70 #define OVS_TUNNEL_KEY_SIZE \
71 (offsetof(struct ovs_key_ipv4_tunnel, tp_dst) + \
72 FIELD_SIZEOF(struct ovs_key_ipv4_tunnel, tp_dst))
73+/* Used for masking nsp and nsi values in field nsp below */
74+#define NSH_M_NSP 0xFFFFFF00
75+#define NSH_M_NSI 0x000000FF
76+
77
78 struct ovs_key_ipv4_tunnel {
79 __be64 tun_id;
80+ __be32 nsp; /* it contains (nsp - 24 bits | nsi - 8 bits) here */
81+ __be32 nshc1; /* NSH context headers */
82+ __be32 nshc2;
83+ __be32 nshc3;
84+ __be32 nshc4;
85 __be32 ipv4_src;
86 __be32 ipv4_dst;
87 __be16 tun_flags;
88@@ -72,11 +81,21 @@ static inline void __ovs_flow_tun_info_init(struct ovs_tunnel_info *tun_info,
89 __be16 tp_src,
90 __be16 tp_dst,
91 __be64 tun_id,
92+ __be32 nsp,
93+ __be32 nshc1,
94+ __be32 nshc2,
95+ __be32 nshc3,
96+ __be32 nshc4,
97 __be16 tun_flags,
98 const void *opts,
99 u8 opts_len)
100 {
101 tun_info->tunnel.tun_id = tun_id;
102+ tun_info->tunnel.nsp = nsp;
103+ tun_info->tunnel.nshc1 = nshc1;
104+ tun_info->tunnel.nshc2 = nshc2;
105+ tun_info->tunnel.nshc3 = nshc3;
106+ tun_info->tunnel.nshc4 = nshc4;
107 tun_info->tunnel.ipv4_src = saddr;
108 tun_info->tunnel.ipv4_dst = daddr;
109 tun_info->tunnel.ipv4_tos = tos;
110@@ -104,6 +123,11 @@ static inline void ovs_flow_tun_info_init(struct ovs_tunnel_info *tun_info,
111 __be16 tp_src,
112 __be16 tp_dst,
113 __be64 tun_id,
114+ __be32 nsp,
115+ __be32 nshc1,
116+ __be32 nshc2,
117+ __be32 nshc3,
118+ __be32 nshc4,
119 __be16 tun_flags,
120 const void *opts,
121 u8 opts_len)
122@@ -111,8 +135,10 @@ static inline void ovs_flow_tun_info_init(struct ovs_tunnel_info *tun_info,
123 __ovs_flow_tun_info_init(tun_info, iph->saddr, iph->daddr,
124 iph->tos, iph->ttl,
125 tp_src, tp_dst,
126- tun_id, tun_flags,
127- opts, opts_len);
128+ tun_id, nsp,
129+ nshc1, nshc2,
130+ nshc3, nshc4,
131+ tun_flags,opts, opts_len);
132 }
133
134 #define OVS_SW_FLOW_KEY_METADATA_SIZE \
135diff --git a/datapath/flow_netlink.c b/datapath/flow_netlink.c
136index d835a00..c979156 100644
137--- a/datapath/flow_netlink.c
138+++ b/datapath/flow_netlink.c
139@@ -51,6 +51,8 @@
140 #include "flow_netlink.h"
141 #include "vport-vxlan.h"
142
143+#define NSH_M_NSI 0x000000FF
144+
145 struct ovs_len_tbl {
146 int len;
147 const struct ovs_len_tbl *next;
148@@ -269,6 +271,12 @@ size_t ovs_tun_key_attr_size(void)
149 + nla_total_size(0) /* OVS_TUNNEL_KEY_ATTR_DONT_FRAGMENT */
150 + nla_total_size(0) /* OVS_TUNNEL_KEY_ATTR_CSUM */
151 + nla_total_size(0) /* OVS_TUNNEL_KEY_ATTR_OAM */
152+ + nla_total_size(4) /* OVS_TUNNEL_KEY_ATTR_NSP */
153+ + nla_total_size(1) /* OVS_TUNNEL_KEY_ATTR_NSI */
154+ + nla_total_size(4) /* OVS_TUNNEL_KEY_ATTR_NC1 */
155+ + nla_total_size(4) /* OVS_TUNNEL_KEY_ATTR_NC2 */
156+ + nla_total_size(4) /* OVS_TUNNEL_KEY_ATTR_NC3 */
157+ + nla_total_size(4) /* OVS_TUNNEL_KEY_ATTR_NC4 */
158 + nla_total_size(256) /* OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS */
159 /* OVS_TUNNEL_KEY_ATTR_VXLAN_OPTS is mutually exclusive with
160 * OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS and covered by it.
161@@ -316,6 +324,12 @@ static const struct ovs_len_tbl ovs_tunnel_key_lens[OVS_TUNNEL_KEY_ATTR_MAX + 1]
162 [OVS_TUNNEL_KEY_ATTR_TP_SRC] = { .len = sizeof(u16) },
163 [OVS_TUNNEL_KEY_ATTR_TP_DST] = { .len = sizeof(u16) },
164 [OVS_TUNNEL_KEY_ATTR_OAM] = { .len = 0 },
165+ [OVS_TUNNEL_KEY_ATTR_NSP] = sizeof(u32),
166+ [OVS_TUNNEL_KEY_ATTR_NSI] = 1,
167+ [OVS_TUNNEL_KEY_ATTR_NSH_C1] = sizeof(u32),
168+ [OVS_TUNNEL_KEY_ATTR_NSH_C2] = sizeof(u32),
169+ [OVS_TUNNEL_KEY_ATTR_NSH_C3] = sizeof(u32),
170+ [OVS_TUNNEL_KEY_ATTR_NSH_C4] = sizeof(u32),
171 [OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS] = { .len = OVS_ATTR_VARIABLE },
172 [OVS_TUNNEL_KEY_ATTR_VXLAN_OPTS] = { .len = OVS_ATTR_NESTED,
173 .next = ovs_vxlan_ext_key_lens },
174@@ -543,6 +557,12 @@ static int ipv4_tun_from_nlattr(const struct nlattr *attr,
175 bool ttl = false;
176 __be16 tun_flags = 0;
177 int opts_type = 0;
178+ __be32 nsp = 0;
179+ __be32 nshc1 = 0;
180+ __be32 nshc2 = 0;
181+ __be32 nshc3 = 0;
182+ __be32 nshc4 = 0;
183+
184
185 nla_for_each_nested(a, attr, rem) {
186 int type = nla_type(a);
187@@ -601,6 +621,30 @@ static int ipv4_tun_from_nlattr(const struct nlattr *attr,
188 case OVS_TUNNEL_KEY_ATTR_OAM:
189 tun_flags |= TUNNEL_OAM;
190 break;
191+ case OVS_TUNNEL_KEY_ATTR_NSP:
192+ nsp |= htonl(be32_to_cpu(nla_get_be32(a)) << 8);
193+ tun_flags |= TUNNEL_NSP;
194+ break;
195+ case OVS_TUNNEL_KEY_ATTR_NSI:
196+ nsp |= htonl(nla_get_u8(a));
197+ tun_flags |= TUNNEL_NSI;
198+ break;
199+ case OVS_TUNNEL_KEY_ATTR_NSH_C1:
200+ nshc1 = nla_get_be32(a);
201+ tun_flags |= TUNNEL_NSHC;
202+ break;
203+ case OVS_TUNNEL_KEY_ATTR_NSH_C2:
204+ nshc2 = nla_get_be32(a);
205+ tun_flags |= TUNNEL_NSHC;
206+ break;
207+ case OVS_TUNNEL_KEY_ATTR_NSH_C3:
208+ nshc3 = nla_get_be32(a);
209+ tun_flags |= TUNNEL_NSHC;
210+ break;
211+ case OVS_TUNNEL_KEY_ATTR_NSH_C4:
212+ nshc4 = nla_get_be32(a);
213+ tun_flags |= TUNNEL_NSHC;
214+ break;
215 case OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS:
216 if (opts_type) {
217 OVS_NLERR(log, "Multiple metadata blocks provided");
218@@ -634,6 +678,11 @@ static int ipv4_tun_from_nlattr(const struct nlattr *attr,
219 }
220 }
221
222+ SW_FLOW_KEY_PUT(match, tun_key.nsp, nsp, is_mask);
223+ SW_FLOW_KEY_PUT(match, tun_key.nshc1, nshc1, is_mask);
224+ SW_FLOW_KEY_PUT(match, tun_key.nshc2, nshc2, is_mask);
225+ SW_FLOW_KEY_PUT(match, tun_key.nshc3, nshc3, is_mask);
226+ SW_FLOW_KEY_PUT(match, tun_key.nshc4, nshc4, is_mask);
227 SW_FLOW_KEY_PUT(match, tun_key.tun_flags, tun_flags, is_mask);
228
229 if (rem > 0) {
230@@ -678,6 +727,9 @@ static int __ipv4_tun_to_nlattr(struct sk_buff *skb,
231 const struct ovs_key_ipv4_tunnel *output,
232 const void *tun_opts, int swkey_tun_opts_len)
233 {
234+ __be32 nsp = cpu_to_be32(ntohl(output->nsp) >> 8);
235+ u8 nsi = ntohl(output->nsp) & NSH_M_NSI;
236+
237 if (output->tun_flags & TUNNEL_KEY &&
238 nla_put_be64(skb, OVS_TUNNEL_KEY_ATTR_ID, output->tun_id))
239 return -EMSGSIZE;
240@@ -707,6 +759,24 @@ static int __ipv4_tun_to_nlattr(struct sk_buff *skb,
241 if ((output->tun_flags & TUNNEL_OAM) &&
242 nla_put_flag(skb, OVS_TUNNEL_KEY_ATTR_OAM))
243 return -EMSGSIZE;
244+ if (output->tun_flags & TUNNEL_NSP &&
245+ nla_put_be32(skb, OVS_TUNNEL_KEY_ATTR_NSP, nsp))
246+ return -EMSGSIZE;
247+ if (output->tun_flags & TUNNEL_NSI &&
248+ nla_put_u8(skb, OVS_TUNNEL_KEY_ATTR_NSI, nsi))
249+ return -EMSGSIZE;
250+ if (output->tun_flags & TUNNEL_NSHC &&
251+ nla_put_be32(skb, OVS_TUNNEL_KEY_ATTR_NSH_C1, output->nshc1))
252+ return -EMSGSIZE;
253+ if (output->tun_flags & TUNNEL_NSHC &&
254+ nla_put_be32(skb, OVS_TUNNEL_KEY_ATTR_NSH_C2, output->nshc2))
255+ return -EMSGSIZE;
256+ if (output->tun_flags & TUNNEL_NSHC &&
257+ nla_put_be32(skb, OVS_TUNNEL_KEY_ATTR_NSH_C3, output->nshc3))
258+ return -EMSGSIZE;
259+ if (output->tun_flags & TUNNEL_NSHC &&
260+ nla_put_be32(skb, OVS_TUNNEL_KEY_ATTR_NSH_C4, output->nshc4))
261+ return -EMSGSIZE;
262 if (tun_opts) {
263 if (output->tun_flags & TUNNEL_GENEVE_OPT &&
264 nla_put(skb, OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS,
265diff --git a/datapath/linux/Modules.mk b/datapath/linux/Modules.mk
266index 96c3d55..98e95b2 100644
267--- a/datapath/linux/Modules.mk
268+++ b/datapath/linux/Modules.mk
269@@ -79,5 +79,6 @@ openvswitch_headers += \
270 linux/compat/include/net/sock.h \
271 linux/compat/include/net/stt.h \
272 linux/compat/include/net/vxlan.h \
273+ linux/compat/include/net/nsh.h \
274 linux/compat/include/net/sctp/checksum.h
275 EXTRA_DIST += linux/compat/build-aux/export-check-whitelist
276diff --git a/datapath/linux/compat/include/linux/openvswitch.h b/datapath/linux/compat/include/linux/openvswitch.h
277index 578cd88..aa5dfde 100644
278--- a/datapath/linux/compat/include/linux/openvswitch.h
279+++ b/datapath/linux/compat/include/linux/openvswitch.h
280@@ -366,6 +366,12 @@ enum ovs_tunnel_key_attr {
281 OVS_TUNNEL_KEY_ATTR_TP_SRC, /* be16 src Transport Port. */
282 OVS_TUNNEL_KEY_ATTR_TP_DST, /* be16 dst Transport Port. */
283 OVS_TUNNEL_KEY_ATTR_VXLAN_OPTS, /* Nested OVS_VXLAN_EXT_* */
284+ OVS_TUNNEL_KEY_ATTR_NSP, /* be32 NSH svc path (lower 24 bits) */
285+ OVS_TUNNEL_KEY_ATTR_NSI, /* u8 NSH service index*/
286+ OVS_TUNNEL_KEY_ATTR_NSH_C1, /* be32 nshc1 */
287+ OVS_TUNNEL_KEY_ATTR_NSH_C2, /* be32 nshc2 */
288+ OVS_TUNNEL_KEY_ATTR_NSH_C3, /* be32 nshc3 */
289+ OVS_TUNNEL_KEY_ATTR_NSH_C4, /* be32 nshc4 */
290 __OVS_TUNNEL_KEY_ATTR_MAX
291 };
292
293diff --git a/datapath/linux/compat/include/net/ip_tunnels.h b/datapath/linux/compat/include/net/ip_tunnels.h
294index 3ed6f91..f091209 100644
295--- a/datapath/linux/compat/include/net/ip_tunnels.h
296+++ b/datapath/linux/compat/include/net/ip_tunnels.h
297@@ -80,6 +80,14 @@ struct tnl_ptk_info {
298 #undef TUNNEL_OPTIONS_PRESENT
299 #define TUNNEL_OPTIONS_PRESENT (TUNNEL_GENEVE_OPT | TUNNEL_VXLAN_OPT)
300
301+#ifndef TUNNEL_NSP
302+#define TUNNEL_NSP __cpu_to_be16(0x2000)
303+#define TUNNEL_NSI __cpu_to_be16(0x4000)
304+#endif
305+#ifndef TUNNEL_NSHC
306+#define TUNNEL_NSHC __cpu_to_be16(0x8000)
307+#endif
308+
309 #define skb_is_encapsulated ovs_skb_is_encapsulated
310 bool ovs_skb_is_encapsulated(struct sk_buff *skb);
311
312diff --git a/datapath/linux/compat/include/net/nsh.h b/datapath/linux/compat/include/net/nsh.h
313new file mode 100644
314index 0000000..a143a83
315--- /dev/null
316+++ b/datapath/linux/compat/include/net/nsh.h
317@@ -0,0 +1,103 @@
318+/*
319+ * Copyright (c) 2013, 2014 Cisco Systems, Inc.
320+ *
321+ * This program is free software; you can redistribute it and/or
322+ * modify it under the terms of version 2 of the GNU General Public
323+ * License as published by the Free Software Foundation.
324+ *
325+ * This program is distributed in the hope that it will be useful, but
326+ * WITHOUT ANY WARRANTY; without even the implied warranty of
327+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
328+ * General Public License for more details.
329+ *
330+ * You should have received a copy of the GNU General Public License
331+ * along with this program; if not, write to the Free Software
332+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
333+ * 02110-1301, USA
334+ */
335+
336+#ifndef NSH_H
337+#define NSH_H 1
338+
339+#include <linux/types.h>
340+#include <asm/byteorder.h>
341+
342+
343+/**
344+ * struct nsh_bhdr - Network Service Base Header.
345+ * @o: Operations and Management Packet indicator bit
346+ * @c: If this bit is set then one or more contexts are in use.
347+ * @proto: IEEE Ethertypes to indicate the frame within.
348+ * @svc_idx: TTL functionality and location within service path.
349+ * @svc_path: To uniquely identify service path.
350+ */
351+struct nsh_base {
352+#if defined(__LITTLE_ENDIAN_BITFIELD)
353+ __u8 res1:4;
354+ __u8 c:1;
355+ __u8 o:1;
356+ __u8 ver:2;
357+
358+ __u8 len:6;
359+ __u8 res2:2;
360+#elif defined(__BIG_ENDIAN_BITFIELD)
361+ __u8 ver:2;
362+ __u8 o:1;
363+ __u8 c:1;
364+ __u8 res1:4;
365+
366+ __u8 res2:2;
367+ __u8 len:6;
368+#else
369+#error "Bitfield Endianess not defined."
370+#endif
371+ __u8 mdtype;
372+ __u8 proto;
373+ union {
374+ struct {
375+ __u8 svc_path[3];
376+ __u8 svc_idx;
377+ };
378+ __be32 b2;
379+ };
380+};
381+
382+/**
383+ * struct nsh_ctx - Keeps track of NSH context data
384+ * @c<1-4>: NSH Contexts.
385+ */
386+struct nsh_ctx {
387+ __be32 c1;
388+ __be32 c2;
389+ __be32 c3;
390+ __be32 c4;
391+};
392+
393+/**
394+ * struct nshdr - Network Service header
395+ * @nsh_base: Network Service Base Header.
396+ * @nsh_ctx: Network Service Context Header.
397+ */
398+struct nshhdr {
399+ struct nsh_base b;
400+ struct nsh_ctx c;
401+};
402+
403+
404+#define ETH_P_NSH 0x894F /* Ethertype for NSH */
405+
406+/* NSH Base Header Next Protocol */
407+#define NSH_P_IPV4 0x01
408+#define NSH_P_IPV6 0x02
409+#define NSH_P_ETHERNET 0x03
410+
411+/* MD Type Registry */
412+#define NSH_M_TYPE1 0x01
413+#define NSH_M_TYPE2 0x02
414+#define NSH_M_EXP1 0xFE
415+#define NSH_M_EXP2 0xFF
416+
417+#define NSH_DST_PORT 4790 /* UDP Port for NSH on VXLAN */
418+
419+
420+#endif /* nsh.h */
421diff --git a/datapath/linux/compat/include/net/vxlan.h b/datapath/linux/compat/include/net/vxlan.h
422index cafff79..ff63260 100644
423--- a/datapath/linux/compat/include/net/vxlan.h
424+++ b/datapath/linux/compat/include/net/vxlan.h
425@@ -4,8 +4,10 @@
426 #include <linux/skbuff.h>
427 #include <linux/netdevice.h>
428 #include <linux/udp.h>
429+#include <net/nsh.h>
430 #include <net/gre.h>
431
432+
433 #include <linux/version.h>
434
435 #ifdef HAVE_VXLAN_METADATA
436@@ -17,6 +19,14 @@
437 #ifndef VXLAN_HLEN
438 /* VXLAN header flags. */
439 #define VXLAN_HF_VNI 0x08000000
440+/* VXLAN-GPE header flags. */
441+#define VXLAN_GPE_HF_P 0x04000000
442+#define VXLAN_GPE_HF_O 0x01000000
443+#define VXLAN_GPE_HF_VER 0x00C00000
444+#define VXLAN_GPE_HF_NP 0x0000000F
445+
446+#define VXLAN_GPE_NP_IS_NSH 4
447+
448 #ifndef VXLAN_HF_GBP
449 #define VXLAN_HF_GBP 0x80000000
450 #endif
451@@ -24,6 +34,10 @@
452 #define VXLAN_N_VID (1u << 24)
453 #define VXLAN_VID_MASK (VXLAN_N_VID - 1)
454 #define VXLAN_HLEN (sizeof(struct udphdr) + sizeof(struct vxlanhdr))
455+#define NSH_HLEN (sizeof(struct udphdr) + \
456+ sizeof(struct vxlanhdr) + \
457+ sizeof(struct nshhdr))
458+
459 #endif
460
461 #ifndef VXLAN_GBP_USED_BITS
462@@ -119,7 +133,8 @@ struct rpl_vxlan_sock;
463
464 #define vxlan_rcv_t rpl_vxlan_rcv_t
465 typedef void (vxlan_rcv_t)(struct vxlan_sock *vh, struct sk_buff *skb,
466- struct vxlan_metadata *md);
467+ struct vxlan_metadata *md, __be32 nsp, __be32 nshc1, __be32 nshc2,
468+ __be32 nshc3, __be32 nshc4);
469
470 /* per UDP socket information */
471 struct vxlan_sock {
472@@ -144,7 +159,8 @@ void rpl_vxlan_sock_release(struct vxlan_sock *vs);
473 int rpl_vxlan_xmit_skb(struct rtable *rt, struct sock *sk, struct sk_buff *skb,
474 __be32 src, __be32 dst, __u8 tos, __u8 ttl, __be16 df,
475 __be16 src_port, __be16 dst_port,
476- struct vxlan_metadata *md, bool xnet, u32 vxflags);
477+ struct vxlan_metadata *md, bool xnet, u32 vxflags,
478+ __be32 nsp, __be32 nshc1, __be32 nshc2, __be32 nshc3, __be32 nshc4);
479
480 #endif /* !HAVE_VXLAN_METADATA */
481 #endif
482diff --git a/datapath/linux/compat/vxlan.c b/datapath/linux/compat/vxlan.c
483index fd454ae..41e202b 100644
484--- a/datapath/linux/compat/vxlan.c
485+++ b/datapath/linux/compat/vxlan.c
486@@ -54,6 +54,7 @@
487 #include <net/net_namespace.h>
488 #include <net/netns/generic.h>
489 #include <net/vxlan.h>
490+#include <net/nsh.h>
491
492 #include "compat.h"
493 #include "datapath.h"
494@@ -68,6 +69,16 @@ struct vxlanhdr {
495 __be32 vx_vni;
496 };
497
498+static inline struct vxlanhdr *vxlan_hdr(const struct sk_buff *skb)
499+{
500+ return (struct vxlanhdr *)(udp_hdr(skb) + 1);
501+}
502+
503+static inline struct nshhdr *nsh_hdr(const struct sk_buff *skb)
504+{
505+ return (struct nshhdr *)(vxlan_hdr(skb) + 1);
506+}
507+
508 /* Callback from net/ipv4/udp.c to receive packets */
509 static int vxlan_udp_encap_recv(struct sock *sk, struct sk_buff *skb)
510 {
511@@ -75,23 +86,62 @@ static int vxlan_udp_encap_recv(struct sock *sk, struct sk_buff *skb)
512 struct vxlanhdr *vxh;
513 u32 flags, vni;
514 struct vxlan_metadata md = {0};
515+ struct udphdr *udp;
516+ bool isnsh = false;
517+ __be32 nsp = 0;
518+ __be32 c1 = 0;
519+ __be32 c2 = 0;
520+ __be32 c3 = 0;
521+ __be32 c4 = 0;
522+
523+ udp = (struct udphdr *)udp_hdr(skb);
524+ if (udp->dest == htons(NSH_DST_PORT))
525+ isnsh = true;
526
527 /* Need Vxlan and inner Ethernet header to be present */
528- if (!pskb_may_pull(skb, VXLAN_HLEN))
529+ if (!pskb_may_pull(skb, isnsh ? NSH_HLEN : VXLAN_HLEN))
530 goto error;
531
532- vxh = (struct vxlanhdr *)(udp_hdr(skb) + 1);
533+ vxh = vxlan_hdr(skb);
534 flags = ntohl(vxh->vx_flags);
535 vni = ntohl(vxh->vx_vni);
536
537- if (flags & VXLAN_HF_VNI) {
538- flags &= ~VXLAN_HF_VNI;
539- } else {
540+ if (isnsh) {
541+ if((flags & VXLAN_GPE_HF_P) && ((flags & VXLAN_GPE_HF_NP) == VXLAN_GPE_NP_IS_NSH)){
542+ flags &= ~(VXLAN_HF_VNI | VXLAN_GPE_HF_P | VXLAN_GPE_HF_O | VXLAN_GPE_HF_VER | VXLAN_GPE_HF_NP);
543+ }
544+ else {
545+ /* need to set vxlan-gpe header flag for nsh correctly */
546+ goto bad_flags;
547+ }
548+ }
549+ else {
550+ if (flags & VXLAN_HF_VNI) {
551+ flags &= ~VXLAN_HF_VNI;
552+ }
553+ else {
554 /* VNI flag always required to be set */
555 goto bad_flags;
556- }
557-
558- if (iptunnel_pull_header(skb, VXLAN_HLEN, htons(ETH_P_TEB)))
559+ }
560+ }
561+
562+ if (isnsh) {
563+ struct nshhdr *nsh = nsh_hdr(skb);
564+ if (unlikely(nsh->b.svc_idx == 0 || nsh->b.ver ||
565+ nsh->b.len != 6 || nsh->b.mdtype != 0x01 ||
566+ nsh->b.proto != NSH_P_ETHERNET)) {
567+ pr_warn("NSH service index reached zero or not supported\n");
568+ goto drop;
569+ }
570+
571+ nsp = nsh->b.b2; /* same as svc_path | htonl(svc_idx) */
572+ c1 = nsh->c.c1; /* NSH Contexts */
573+ c2 = nsh->c.c2;
574+ c3 = nsh->c.c3;
575+ c4 = nsh->c.c4;
576+ }
577+
578+ if (iptunnel_pull_header(skb, isnsh ? NSH_HLEN : VXLAN_HLEN, htons(ETH_P_TEB)))
579 goto drop;
580
581 vs = rcu_dereference_sk_user_data(sk);
582@@ -101,7 +151,7 @@ static int vxlan_udp_encap_recv(struct sock *sk, struct sk_buff *skb)
583 /* For backwards compatibility, only allow reserved fields to be
584 * used by VXLAN extensions if explicitly requested.
585 */
586- if ((flags & VXLAN_HF_GBP) && (vs->flags & VXLAN_F_GBP)) {
587+ if (!isnsh && (flags & VXLAN_HF_GBP) && (vs->flags & VXLAN_F_GBP)) {
588 struct vxlanhdr_gbp *gbp;
589
590 gbp = (struct vxlanhdr_gbp *)vxh;
591@@ -130,7 +180,7 @@ static int vxlan_udp_encap_recv(struct sock *sk, struct sk_buff *skb)
592 }
593
594 md.vni = vxh->vx_vni;
595- vs->rcv(vs, skb, &md);
596+ vs->rcv(vs, skb, &md,nsp, c1, c2, c3, c4);
597 return 0;
598
599 drop:
600@@ -183,15 +233,17 @@ static void vxlan_build_gbp_hdr(struct vxlanhdr *vxh, u32 vxflags,
601 int rpl_vxlan_xmit_skb(struct rtable *rt, struct sock *sk, struct sk_buff *skb,
602 __be32 src, __be32 dst, __u8 tos, __u8 ttl, __be16 df,
603 __be16 src_port, __be16 dst_port,
604- struct vxlan_metadata *md, bool xnet, u32 vxflags)
605+ struct vxlan_metadata *md, bool xnet, u32 vxflags,
606+ __be32 nsp, __be32 nshc1, __be32 nshc2, __be32 nshc3, __be32 nshc4)
607 {
608+ bool isnsh = (dst_port == htons(NSH_DST_PORT));
609 struct vxlanhdr *vxh;
610 int min_headroom;
611 int err;
612 bool udp_sum = !!(vxflags & VXLAN_F_UDP_CSUM);
613
614 min_headroom = LL_RESERVED_SPACE(rt_dst(rt).dev) + rt_dst(rt).header_len
615- + VXLAN_HLEN + sizeof(struct iphdr)
616+ + (isnsh ? NSH_HLEN : VXLAN_HLEN) + sizeof(struct iphdr)
617 + (skb_vlan_tag_present(skb) ? VLAN_HLEN : 0);
618
619 /* Need space for new headers (invalidates iph ptr) */
620@@ -208,9 +260,28 @@ int rpl_vxlan_xmit_skb(struct rtable *rt, struct sock *sk, struct sk_buff *skb,
621 skb = udp_tunnel_handle_offloads(skb, udp_sum, true);
622 if (IS_ERR(skb))
623 return PTR_ERR(skb);
624+ if (isnsh) {
625+ struct nshhdr *nsh;
626+ uint8_t nsi = ntohl(nsp) & NSH_M_NSI;
627+ nsh = (struct nshhdr *) __skb_push(skb, sizeof(*nsh));
628+ memset(&nsh->b, 0, sizeof nsh->b);
629+ nsh->b.len = 6;
630+ nsh->b.mdtype = NSH_M_TYPE1;
631+ nsh->b.proto = NSH_P_ETHERNET;
632+ /* b2 should precede svc_idx, else svc_idx will be zero */
633+ nsh->b.b2 = nsp & htonl(NSH_M_NSP);
634+ nsh->b.svc_idx = nsi ? nsi : 0x01;
635+ nsh->c.c1 = nshc1;
636+ nsh->c.c2 = nshc2;
637+ nsh->c.c3 = nshc3;
638+ nsh->c.c4 = nshc4;
639+ }
640
641 vxh = (struct vxlanhdr *) __skb_push(skb, sizeof(*vxh));
642- vxh->vx_flags = htonl(VXLAN_HF_VNI);
643+ if(isnsh)
644+ vxh->vx_flags = htonl(VXLAN_GPE_HF_P | (VXLAN_GPE_HF_NP & VXLAN_GPE_NP_IS_NSH)); //set vxlan_gpe nsh header flag
645+ else
646+ vxh->vx_flags = htonl(VXLAN_HF_VNI);
647 vxh->vx_vni = md->vni;
648
649 if (vxflags & VXLAN_F_GBP)
650diff --git a/datapath/vport-geneve.c b/datapath/vport-geneve.c
651index 4ab224d..7ff24c5 100644
652--- a/datapath/vport-geneve.c
653+++ b/datapath/vport-geneve.c
654@@ -92,7 +92,7 @@ static void geneve_rcv(struct geneve_sock *gs, struct sk_buff *skb)
655
656 ovs_flow_tun_info_init(&tun_info, ip_hdr(skb),
657 udp_hdr(skb)->source, udp_hdr(skb)->dest,
658- key, flags,
659+ key, 0, 0, 0, 0, 0, flags,
660 geneveh->options, opts_len);
661
662 ovs_vport_receive(vport, skb, &tun_info);
663diff --git a/datapath/vport-gre.c b/datapath/vport-gre.c
664index 0328fe5..2fd4ea6 100644
665--- a/datapath/vport-gre.c
666+++ b/datapath/vport-gre.c
667@@ -111,7 +111,7 @@ static int gre_rcv(struct sk_buff *skb,
668 return PACKET_REJECT;
669
670 key = key_to_tunnel_id(tpi->key, tpi->seq);
671- ovs_flow_tun_info_init(&tun_info, ip_hdr(skb), 0, 0, key,
672+ ovs_flow_tun_info_init(&tun_info, ip_hdr(skb), 0, 0, key, 0, 0, 0, 0, 0,
673 filter_tnl_flags(tpi->flags), NULL, 0);
674
675 ovs_vport_receive(vport, skb, &tun_info);
676diff --git a/datapath/vport-lisp.c b/datapath/vport-lisp.c
677index 104a21d..1480ae7 100644
678--- a/datapath/vport-lisp.c
679+++ b/datapath/vport-lisp.c
680@@ -249,7 +249,7 @@ static int lisp_rcv(struct sock *sk, struct sk_buff *skb)
681 iph = ip_hdr(skb);
682 ovs_flow_tun_info_init(&tun_info, iph,
683 udp_hdr(skb)->source, udp_hdr(skb)->dest,
684- key, TUNNEL_KEY, NULL, 0);
685+ key, 0, 0, 0, 0, 0, TUNNEL_KEY, NULL, 0);
686
687 /* Drop non-IP inner packets */
688 inner_iph = (struct iphdr *)(lisph + 1);
689diff --git a/datapath/vport-stt.c b/datapath/vport-stt.c
690index 4eb0282..e9e48e6 100644
691--- a/datapath/vport-stt.c
692+++ b/datapath/vport-stt.c
693@@ -53,7 +53,7 @@ static void stt_rcv(struct stt_sock *stt_sock, struct sk_buff *skb)
694
695 ovs_flow_tun_info_init(&tun_info, ip_hdr(skb),
696 tcp_hdr(skb)->source, tcp_hdr(skb)->dest,
697- get_unaligned(&stth->key),
698+ get_unaligned(&stth->key), 0, 0, 0, 0, 0,
699 TUNNEL_KEY | TUNNEL_CSUM,
700 NULL, 0);
701 do {
702diff --git a/datapath/vport-vxlan.c b/datapath/vport-vxlan.c
703index fc9f350..9f93c52 100644
704--- a/datapath/vport-vxlan.c
705+++ b/datapath/vport-vxlan.c
706@@ -63,7 +63,8 @@ static inline struct vxlan_port *vxlan_vport(const struct vport *vport)
707 }
708
709 static void vxlan_rcv(struct vxlan_sock *vs, struct sk_buff *skb,
710- struct vxlan_metadata *md)
711+ struct vxlan_metadata *md, __be32 nsp, __be32 nshc1, __be32 nshc2,
712+ __be32 nshc3, __be32 nshc4)
713 {
714 struct ovs_tunnel_info tun_info;
715 struct vxlan_port *vxlan_port;
716@@ -75,7 +76,7 @@ static void vxlan_rcv(struct vxlan_sock *vs, struct sk_buff *skb,
717 __be64 key;
718 __be16 flags;
719
720- flags = TUNNEL_KEY | (udp_hdr(skb)->check != 0 ? TUNNEL_CSUM : 0);
721+ flags = TUNNEL_KEY |TUNNEL_NSP |TUNNEL_NSI |TUNNEL_NSHC | (udp_hdr(skb)->check != 0 ? TUNNEL_CSUM : 0);
722 vxlan_port = vxlan_vport(vport);
723 if (vxlan_port->exts & VXLAN_F_GBP && md->gbp)
724 flags |= TUNNEL_VXLAN_OPT;
725@@ -85,7 +86,8 @@ static void vxlan_rcv(struct vxlan_sock *vs, struct sk_buff *skb,
726 key = cpu_to_be64(ntohl(md->vni) >> 8);
727 ovs_flow_tun_info_init(&tun_info, iph,
728 udp_hdr(skb)->source, udp_hdr(skb)->dest,
729- key, flags, &opts, sizeof(opts));
730+ key, nsp, nshc1, nshc2, nshc3, nshc4,
731+ flags, &opts, sizeof(opts));
732
733 ovs_vport_receive(vport, skb, &tun_info);
734 }
735@@ -265,7 +267,12 @@ static int vxlan_tnl_send(struct vport *vport, struct sk_buff *skb)
736 tun_key->ipv4_tos,
737 tun_key->ipv4_ttl, df,
738 src_port, dst_port,
739- &md, false, vxflags);
740+ &md, false, vxflags,
741+ tun_key->nsp,
742+ tun_key->nshc1,
743+ tun_key->nshc2,
744+ tun_key->nshc3,
745+ tun_key->nshc4);
746 if (err < 0)
747 ip_rt_put(rt);
748 return err;
749diff --git a/datapath/vport.c b/datapath/vport.c
750index 024491f..9e2bd9c 100644
751--- a/datapath/vport.c
752+++ b/datapath/vport.c
753@@ -624,6 +624,11 @@ int ovs_tunnel_get_egress_info(struct ovs_tunnel_info *egress_tun_info,
754 tun_key->ipv4_ttl,
755 tp_src, tp_dst,
756 tun_key->tun_id,
757+ tun_key->nsp,
758+ tun_key->nshc1,
759+ tun_key->nshc2,
760+ tun_key->nshc3,
761+ tun_key->nshc4,
762 tun_key->tun_flags,
763 tun_info->options,
764 tun_info->options_len);
765diff --git a/lib/flow.c b/lib/flow.c
766index 84048e8..2cbfb6d 100644
767--- a/lib/flow.c
768+++ b/lib/flow.c
769@@ -854,6 +854,18 @@ flow_tun_flag_to_string(uint32_t flags)
770 return "key";
771 case FLOW_TNL_F_OAM:
772 return "oam";
773+ case FLOW_TNL_F_NSP:
774+ return "nsp";
775+ case FLOW_TNL_F_NSI:
776+ return "nsi";
777+ case FLOW_TNL_F_NSH_C1:
778+ return "nshc1";
779+ case FLOW_TNL_F_NSH_C2:
780+ return "nshc2";
781+ case FLOW_TNL_F_NSH_C3:
782+ return "nshc3";
783+ case FLOW_TNL_F_NSH_C4:
784+ return "nshc4";
785 default:
786 return NULL;
787 }
788@@ -1152,6 +1164,24 @@ void flow_wildcards_init_for_packet(struct flow_wildcards *wc,
789 if (flow->tunnel.flags & FLOW_TNL_F_KEY) {
790 WC_MASK_FIELD(wc, tunnel.tun_id);
791 }
792+ if (flow->tunnel.flags & FLOW_TNL_F_NSP) {
793+ WC_MASK_FIELD(wc, tunnel.nsp);
794+ }
795+ if (flow->tunnel.flags & FLOW_TNL_F_NSI) {
796+ WC_MASK_FIELD(wc, tunnel.nsi);
797+ }
798+ if (flow->tunnel.flags & FLOW_TNL_F_NSH_C1) {
799+ WC_MASK_FIELD(wc, tunnel.nshc1);
800+ }
801+ if (flow->tunnel.flags & FLOW_TNL_F_NSH_C2) {
802+ WC_MASK_FIELD(wc, tunnel.nshc2);
803+ }
804+ if (flow->tunnel.flags & FLOW_TNL_F_NSH_C3) {
805+ WC_MASK_FIELD(wc, tunnel.nshc3);
806+ }
807+ if (flow->tunnel.flags & FLOW_TNL_F_NSH_C4) {
808+ WC_MASK_FIELD(wc, tunnel.nshc4);
809+ }
810 WC_MASK_FIELD(wc, tunnel.ip_src);
811 WC_MASK_FIELD(wc, tunnel.ip_dst);
812 WC_MASK_FIELD(wc, tunnel.flags);
813@@ -1177,6 +1207,24 @@ void flow_wildcards_init_for_packet(struct flow_wildcards *wc,
814 WC_MASK_FIELD(wc, tunnel.tun_id);
815 }
816
817+ if (flow->tunnel.nsp) {
818+ WC_MASK_FIELD(wc, tunnel.nsp);
819+ }
820+ if (flow->tunnel.nsi) {
821+ WC_MASK_FIELD(wc, tunnel.nsi);
822+ }
823+ if (flow->tunnel.nshc1) {
824+ WC_MASK_FIELD(wc, tunnel.nshc1);
825+ }
826+ if (flow->tunnel.nshc2) {
827+ WC_MASK_FIELD(wc, tunnel.nshc2);
828+ }
829+ if (flow->tunnel.nshc3) {
830+ WC_MASK_FIELD(wc, tunnel.nshc3);
831+ }
832+ if (flow->tunnel.nshc4) {
833+ WC_MASK_FIELD(wc, tunnel.nshc4);
834+ }
835 /* metadata, regs, and conj_id wildcarded. */
836
837 WC_MASK_FIELD(wc, skb_priority);
838diff --git a/lib/match.c b/lib/match.c
839index 9e465d8..7f7bd4d 100644
840--- a/lib/match.c
841+++ b/lib/match.c
842@@ -736,6 +736,86 @@ match_set_nd_target_masked(struct match *match,
843 match->wc.masks.nd_target = *mask;
844 }
845
846+void
847+match_set_nsp_masked(struct match *match, ovs_be32 nsp, ovs_be32 mask)
848+{
849+ match->wc.masks.tunnel.nsp = mask;
850+ match->flow.tunnel.nsp = nsp & mask;
851+}
852+
853+void
854+match_set_nsi_masked(struct match *match, uint8_t nsi, uint8_t mask)
855+{
856+ match->wc.masks.tunnel.nsi = mask;
857+ match->flow.tunnel.nsi = nsi & mask;
858+}
859+
860+void
861+match_set_nshc1_masked(struct match *match, ovs_be32 nshc1, ovs_be32 mask)
862+{
863+ match->wc.masks.tunnel.nshc1 = mask;
864+ match->flow.tunnel.nshc1 = nshc1 & mask;
865+}
866+
867+void
868+match_set_nshc2_masked(struct match *match, ovs_be32 nshc2, ovs_be32 mask)
869+{
870+ match->wc.masks.tunnel.nshc2 = mask;
871+ match->flow.tunnel.nshc2 = nshc2 & mask;
872+}
873+
874+void
875+match_set_nshc3_masked(struct match *match, ovs_be32 nshc3, ovs_be32 mask)
876+{
877+ match->wc.masks.tunnel.nshc3 = mask;
878+ match->flow.tunnel.nshc3 = nshc3 & mask;
879+}
880+
881+void
882+match_set_nshc4_masked(struct match *match, ovs_be32 nshc4, ovs_be32 mask)
883+{
884+ match->wc.masks.tunnel.nshc4 = mask;
885+ match->flow.tunnel.nshc4 = nshc4 & mask;
886+}
887+
888+void
889+match_set_nsp(struct match *match, ovs_be32 nsp)
890+{
891+ match_set_nsp_masked(match, nsp, OVS_BE32_MAX);
892+}
893+
894+
895+void
896+match_set_nsi(struct match *match, uint8_t nsi)
897+{
898+ match_set_nsi_masked(match, nsi, UINT8_MAX);
899+}
900+
901+void
902+match_set_nshc1(struct match *match, ovs_be32 nshc1)
903+{
904+ match_set_nshc1_masked(match, nshc1, OVS_BE32_MAX);
905+}
906+
907+void
908+match_set_nshc2(struct match *match, ovs_be32 nshc2)
909+{
910+ match_set_nshc2_masked(match, nshc2, OVS_BE32_MAX);
911+}
912+
913+void
914+match_set_nshc3(struct match *match, ovs_be32 nshc3)
915+{
916+ match_set_nshc3_masked(match, nshc3, OVS_BE32_MAX);
917+}
918+
919+void
920+match_set_nshc4(struct match *match, ovs_be32 nshc4)
921+{
922+ match_set_nshc4_masked(match, nshc4, OVS_BE32_MAX);
923+}
924+
925+
926 /* Returns true if 'a' and 'b' wildcard the same fields and have the same
927 * values for fixed fields, otherwise false. */
928 bool
929@@ -880,6 +960,16 @@ format_flow_tunnel(struct ds *s, const struct match *match)
930 const struct flow_tnl *tnl = &match->flow.tunnel;
931
932 format_be64_masked(s, "tun_id", tnl->tun_id, wc->masks.tunnel.tun_id);
933+ format_be32_masked(s, "nsp", tnl->nsp, wc->masks.tunnel.nsp);
934+ format_be32_masked(s, "nshc1", tnl->nshc1, wc->masks.tunnel.nshc1);
935+ format_be32_masked(s, "nshc2", tnl->nshc2, wc->masks.tunnel.nshc2);
936+ format_be32_masked(s, "nshc3", tnl->nshc3, wc->masks.tunnel.nshc3);
937+ format_be32_masked(s, "nshc4", tnl->nshc4, wc->masks.tunnel.nshc4);
938+
939+ if (wc->masks.tunnel.nsi) {
940+ ds_put_format(s, "nsi=%"PRIu8",", tnl->nsi);
941+ }
942+
943 format_ip_netmask(s, "tun_src", tnl->ip_src, wc->masks.tunnel.ip_src);
944 format_ip_netmask(s, "tun_dst", tnl->ip_dst, wc->masks.tunnel.ip_dst);
945
946diff --git a/lib/match.h b/lib/match.h
947index 3e133e5..3d58c8e 100644
948--- a/lib/match.h
949+++ b/lib/match.h
950@@ -146,6 +146,20 @@ void match_set_nd_target(struct match *, const struct in6_addr *);
951 void match_set_nd_target_masked(struct match *, const struct in6_addr *,
952 const struct in6_addr *);
953
954+void match_set_nsp_masked(struct match *, ovs_be32 nsp, ovs_be32 mask);
955+void match_set_nsi_masked(struct match *match, uint8_t nsi, uint8_t mask);
956+void match_set_nshc1_masked(struct match *, ovs_be32 nshc1, ovs_be32 mask);
957+void match_set_nshc2_masked(struct match *, ovs_be32 nshc2, ovs_be32 mask);
958+void match_set_nshc3_masked(struct match *, ovs_be32 nshc3, ovs_be32 mask);
959+void match_set_nshc4_masked(struct match *, ovs_be32 nshc4, ovs_be32 mask);
960+
961+void match_set_nsp(struct match *, ovs_be32 nsp);
962+void match_set_nsi(struct match *match, uint8_t nsi);
963+void match_set_nshc1(struct match *, ovs_be32 nshc1);
964+void match_set_nshc2(struct match *, ovs_be32 nshc2);
965+void match_set_nshc3(struct match *, ovs_be32 nshc3);
966+void match_set_nshc4(struct match *, ovs_be32 nshc4);
967+
968 bool match_equal(const struct match *, const struct match *);
969 uint32_t match_hash(const struct match *, uint32_t basis);
970
971diff --git a/lib/meta-flow.c b/lib/meta-flow.c
972index 224ba53..0814a57 100644
973--- a/lib/meta-flow.c
974+++ b/lib/meta-flow.c
975@@ -205,6 +205,18 @@ mf_is_all_wild(const struct mf_field *mf, const struct flow_wildcards *wc)
976 CASE_MFF_TUN_METADATA:
977 return !ULLONG_GET(wc->masks.tunnel.metadata.present.map,
978 mf->id - MFF_TUN_METADATA0);
979+ case MFF_NSP:
980+ return !wc->masks.tunnel.nsp;
981+ case MFF_NSI:
982+ return !wc->masks.tunnel.nsi;
983+ case MFF_NSH_C1:
984+ return !wc->masks.tunnel.nshc1;
985+ case MFF_NSH_C2:
986+ return !wc->masks.tunnel.nshc2;
987+ case MFF_NSH_C3:
988+ return !wc->masks.tunnel.nshc3;
989+ case MFF_NSH_C4:
990+ return !wc->masks.tunnel.nshc4;
991 case MFF_METADATA:
992 return !wc->masks.metadata;
993 case MFF_IN_PORT:
994@@ -526,6 +538,12 @@ mf_is_value_valid(const struct mf_field *mf, const union mf_value *value)
995 case MFF_ND_TARGET:
996 case MFF_ND_SLL:
997 case MFF_ND_TLL:
998+ case MFF_NSP:
999+ case MFF_NSI:
1000+ case MFF_NSH_C1:
1001+ case MFF_NSH_C2:
1002+ case MFF_NSH_C3:
1003+ case MFF_NSH_C4:
1004 return true;
1005
1006 case MFF_IN_PORT_OXM:
1007@@ -788,6 +806,27 @@ mf_get_value(const struct mf_field *mf, const struct flow *flow,
1008 value->ipv6 = flow->nd_target;
1009 break;
1010
1011+ case MFF_NSP:
1012+ value->be32 = flow->tunnel.nsp;
1013+ break;
1014+
1015+ case MFF_NSI:
1016+ value->u8 = flow->tunnel.nsi;
1017+ break;
1018+
1019+ case MFF_NSH_C1:
1020+ value->be32 = flow->tunnel.nshc1;
1021+ break;
1022+ case MFF_NSH_C2:
1023+ value->be32 = flow->tunnel.nshc2;
1024+ break;
1025+ case MFF_NSH_C3:
1026+ value->be32 = flow->tunnel.nshc3;
1027+ break;
1028+ case MFF_NSH_C4:
1029+ value->be32 = flow->tunnel.nshc4;
1030+ break;
1031+
1032 case MFF_N_IDS:
1033 default:
1034 OVS_NOT_REACHED();
1035@@ -1020,6 +1059,30 @@ mf_set_value(const struct mf_field *mf,
1036 match_set_nd_target(match, &value->ipv6);
1037 break;
1038
1039+ case MFF_NSP:
1040+ match_set_nsp(match, value->be32);
1041+ break;
1042+
1043+ case MFF_NSI:
1044+ match_set_nsi(match, value->u8);
1045+ break;
1046+
1047+ case MFF_NSH_C1:
1048+ match_set_nshc1(match, value->be32);
1049+ break;
1050+
1051+ case MFF_NSH_C2:
1052+ match_set_nshc2(match, value->be32);
1053+ break;
1054+
1055+ case MFF_NSH_C3:
1056+ match_set_nshc3(match, value->be32);
1057+ break;
1058+
1059+ case MFF_NSH_C4:
1060+ match_set_nshc4(match, value->be32);
1061+ break;
1062+
1063 case MFF_N_IDS:
1064 default:
1065 OVS_NOT_REACHED();
1066@@ -1307,6 +1370,30 @@ mf_set_flow_value(const struct mf_field *mf,
1067 flow->nd_target = value->ipv6;
1068 break;
1069
1070+ case MFF_NSP:
1071+ flow->tunnel.nsp = value->be32;
1072+ break;
1073+
1074+ case MFF_NSI:
1075+ flow->tunnel.nsi = value->u8;
1076+ break;
1077+
1078+ case MFF_NSH_C1:
1079+ flow->tunnel.nshc1 = value->be32;
1080+ break;
1081+
1082+ case MFF_NSH_C2:
1083+ flow->tunnel.nshc2 = value->be32;
1084+ break;
1085+
1086+ case MFF_NSH_C3:
1087+ flow->tunnel.nshc3 = value->be32;
1088+ break;
1089+
1090+ case MFF_NSH_C4:
1091+ flow->tunnel.nshc4 = value->be32;
1092+ break;
1093+
1094 case MFF_N_IDS:
1095 default:
1096 OVS_NOT_REACHED();
1097@@ -1595,6 +1682,30 @@ mf_set_wild(const struct mf_field *mf, struct match *match, char **err_str)
1098 memset(&match->flow.nd_target, 0, sizeof match->flow.nd_target);
1099 break;
1100
1101+ case MFF_NSP:
1102+ match_set_nsp_masked(match, htonl(0), htonl(0));
1103+ break;
1104+
1105+ case MFF_NSI:
1106+ match_set_nsi_masked(match, 0, 0);
1107+ break;
1108+
1109+ case MFF_NSH_C1:
1110+ match_set_nshc1_masked(match, htonl(0), htonl(0));
1111+ break;
1112+
1113+ case MFF_NSH_C2:
1114+ match_set_nshc2_masked(match, htonl(0), htonl(0));
1115+ break;
1116+
1117+ case MFF_NSH_C3:
1118+ match_set_nshc3_masked(match, htonl(0), htonl(0));
1119+ break;
1120+
1121+ case MFF_NSH_C4:
1122+ match_set_nshc4_masked(match, htonl(0), htonl(0));
1123+ break;
1124+
1125 case MFF_N_IDS:
1126 default:
1127 OVS_NOT_REACHED();
1128@@ -1793,6 +1904,30 @@ mf_set(const struct mf_field *mf,
1129 match_set_tcp_flags_masked(match, value->be16, mask->be16);
1130 break;
1131
1132+ case MFF_NSP:
1133+ match_set_nsp_masked(match, value->be32, mask->be32);
1134+ break;
1135+
1136+ case MFF_NSI:
1137+ match_set_nsi_masked(match, value->u8, mask->u8);
1138+ break;
1139+
1140+ case MFF_NSH_C1:
1141+ match_set_nshc1_masked(match, value->be32, mask->be32);
1142+ break;
1143+
1144+ case MFF_NSH_C2:
1145+ match_set_nshc2_masked(match, value->be32, mask->be32);
1146+ break;
1147+
1148+ case MFF_NSH_C3:
1149+ match_set_nshc3_masked(match, value->be32, mask->be32);
1150+ break;
1151+
1152+ case MFF_NSH_C4:
1153+ match_set_nshc4_masked(match, value->be32, mask->be32);
1154+ break;
1155+
1156 case MFF_N_IDS:
1157 default:
1158 OVS_NOT_REACHED();
1159diff --git a/lib/meta-flow.h b/lib/meta-flow.h
1160index 02272ef..948b403 100644
1161--- a/lib/meta-flow.h
1162+++ b/lib/meta-flow.h
1163@@ -1566,6 +1566,108 @@ enum OVS_PACKED_ENUM mf_field_id {
1164 */
1165 MFF_ND_TLL,
1166
1167+ /* "nsp".
1168+ *
1169+ * For a packet received via a VXLAN tunnel including a (32-bit)
1170+ * network service header service path (nsp), the nsp is stored
1171+ * in the low 24-bits and the high bits are zeroed. For
1172+ * other packets, the value is 0.
1173+ *
1174+ * Type: be32.
1175+ * Maskable: bitwise.
1176+ * Formatting: hexadecimal.
1177+ * Prerequisites: none.
1178+ * Access: read/write.
1179+ * NXM: NXM_NX_NSP(105) since v1.1.
1180+ * OXM: none.
1181+ * Prefix lookup member: tunnel.nsp.
1182+ */
1183+ MFF_NSP,
1184+
1185+ /* "nsi".
1186+ *
1187+ * For a packet received via a VXLAN tunnel, it includes a (8-bit)
1188+ * network service header service index (nsi).
1189+ *
1190+ * Type: u8.
1191+ * Maskable: bitwise.
1192+ * Formatting: decimal.
1193+ * Prerequisites: none.
1194+ * Access: read/write.
1195+ * NXM: NXM_NX_NSI(106) since v1.1.
1196+ * OXM: none.
1197+ * Prefix lookup member: tunnel.nsi.
1198+ */
1199+ MFF_NSI,
1200+
1201+ /* "nshc1".
1202+ *
1203+ * For a packet received via a VXLAN tunnel including a (32-bit)
1204+ * Network Platform Context (nshc1), the nshc1 is stored
1205+ * in the 32-bits. For other packets, the value is 0.
1206+ *
1207+ * Type: be32.
1208+ * Maskable: bitwise.
1209+ * Formatting: hexadecimal.
1210+ * Prerequisites: none.
1211+ * Access: read/write.
1212+ * NXM: NXM_NX_NSH_C1(107) since v1.1.
1213+ * OXM: none.
1214+ * Prefix lookup member: tunnel.nshc1.
1215+ */
1216+ MFF_NSH_C1,
1217+
1218+ /* "nshc2".
1219+ *
1220+ * For a packet received via a VXLAN tunnel including a (32-bit)
1221+ * Network Shared Context (nshc2), the nshc2 is stored
1222+ * in the 32-bits. For other packets, the value is 0.
1223+ *
1224+ * Type: be32.
1225+ * Maskable: bitwise.
1226+ * Formatting: hexadecimal.
1227+ * Prerequisites: none.
1228+ * Access: read/write.
1229+ * NXM: NXM_NX_NSH_C2(108) since v1.1.
1230+ * OXM: none.
1231+ * Prefix lookup member: tunnel.nshc2.
1232+ */
1233+ MFF_NSH_C2,
1234+
1235+ /* "nshc3".
1236+ *
1237+ * For a packet received via a VXLAN tunnel including a (32-bit)
1238+ * Service Platform Context (nshc3), the nshc3 is stored
1239+ * in the 32-bits. For other packets, the value is 0.
1240+ *
1241+ * Type: be32.
1242+ * Maskable: bitwise.
1243+ * Formatting: hexadecimal.
1244+ * Prerequisites: none.
1245+ * Access: read/write.
1246+ * NXM: NXM_NX_NSH_C3(109) since v1.1.
1247+ * OXM: none.
1248+ * Prefix lookup member: tunnel.nshc3.
1249+ */
1250+ MFF_NSH_C3,
1251+
1252+ /* "nshc4".
1253+ *
1254+ * For a packet received via a VXLAN tunnel including a (32-bit)
1255+ * Service Shared Context (nshc4), the nshc4 is stored
1256+ * in the 32-bits. For other packets, the value is 0.
1257+ *
1258+ * Type: be32.
1259+ * Maskable: bitwise.
1260+ * Formatting: hexadecimal.
1261+ * Prerequisites: none.
1262+ * Access: read/write.
1263+ * NXM: NXM_NX_NSH_C4(110) since v1.1.
1264+ * OXM: none.
1265+ * Prefix lookup member: tunnel.nshc4.
1266+ */
1267+ MFF_NSH_C4,
1268+
1269 MFF_N_IDS
1270 };
1271
1272diff --git a/lib/netdev-vport.c b/lib/netdev-vport.c
1273index ff50563..3f85386 100644
1274--- a/lib/netdev-vport.c
1275+++ b/lib/netdev-vport.c
1276@@ -424,6 +424,86 @@ parse_key(const struct smap *args, const char *name,
1277 }
1278 }
1279
1280+static ovs_be32
1281+parse_nsp(const struct smap *args, const char *name,
1282+ bool *present, bool *flow)
1283+{
1284+ const char *s;
1285+
1286+ *present = false;
1287+ *flow = false;
1288+
1289+ s = smap_get(args, name);
1290+ if (!s) {
1291+ s = smap_get(args, "nsp");
1292+ if (!s) {
1293+ return 0;
1294+ }
1295+ }
1296+
1297+ *present = true;
1298+
1299+ if (!strcmp(s, "flow")) {
1300+ *flow = true;
1301+ return 0;
1302+ } else {
1303+ return htonl(strtoul(s, NULL, 0));
1304+ }
1305+}
1306+static uint8_t
1307+parse_nsi(const struct smap *args, const char *name,
1308+ bool *present, bool *flow)
1309+{
1310+ const char *s;
1311+
1312+ *present = false;
1313+ *flow = false;
1314+
1315+ s = smap_get(args, name);
1316+ if (!s) {
1317+ s = smap_get(args, "nsi");
1318+ if (!s) {
1319+ return 0;
1320+ }
1321+ }
1322+
1323+ *present = true;
1324+
1325+ if (!strcmp(s, "flow")) {
1326+ *flow = true;
1327+ return 0;
1328+ } else {
1329+ return strtoul(s, NULL, 0);
1330+ }
1331+}
1332+
1333+static ovs_be32
1334+parse_nshc(const struct smap *args, const char *nsh_ele,const char *name,
1335+ bool *present, bool *flow)
1336+{
1337+ const char *s;
1338+
1339+ *present = false;
1340+ *flow = false;
1341+
1342+ s = smap_get(args, name);
1343+ if (!s) {
1344+ s = smap_get(args, nsh_ele);
1345+ if (!s) {
1346+ return 0;
1347+ }
1348+ }
1349+
1350+ *present = true;
1351+
1352+ if (!strcmp(s, "flow")) {
1353+ *flow = true;
1354+ return 0;
1355+ } else {
1356+ return htonl(strtoul(s, NULL, 0));
1357+ }
1358+}
1359+
1360 static int
1361 set_tunnel_config(struct netdev *dev_, const struct smap *args)
1362 {
1363@@ -563,6 +643,30 @@ set_tunnel_config(struct netdev *dev_, const struct smap *args)
1364 }
1365
1366 free(str);
1367+ } else if (!strcmp(node->key, "nsp") ||
1368+ !strcmp(node->key, "in_nsp") ||
1369+ !strcmp(node->key, "out_nsp")) {
1370+ /* Handled separately below. */
1371+ } else if (!strcmp(node->key, "nsi") ||
1372+ !strcmp(node->key, "in_nsi") ||
1373+ !strcmp(node->key, "out_nsi")) {
1374+ /* Handled separately below. */
1375+ } else if (!strcmp(node->key, "nshc1") ||
1376+ !strcmp(node->key, "in_nshc1") ||
1377+ !strcmp(node->key, "out_nshc1")) {
1378+ /* Handled separately below. */
1379+ } else if (!strcmp(node->key, "nshc2") ||
1380+ !strcmp(node->key, "in_nshc2") ||
1381+ !strcmp(node->key, "out_nshc2")) {
1382+ /* Handled separately below. */
1383+ } else if (!strcmp(node->key, "nshc3") ||
1384+ !strcmp(node->key, "in_nshc3") ||
1385+ !strcmp(node->key, "out_nshc3")) {
1386+ /* Handled separately below. */
1387+ } else if (!strcmp(node->key, "nshc4") ||
1388+ !strcmp(node->key, "in_nshc4") ||
1389+ !strcmp(node->key, "out_nshc4")) {
1390+ /* Handled separately below. */
1391 } else {
1392 VLOG_WARN("%s: unknown %s argument '%s'", name, type, node->key);
1393 }
1394@@ -623,6 +727,65 @@ set_tunnel_config(struct netdev *dev_, const struct smap *args)
1395 &tnl_cfg.out_key_present,
1396 &tnl_cfg.out_key_flow);
1397
1398+ if (tnl_cfg.dst_port == htons(VXGPE_DST_PORT)) {
1399+ tnl_cfg.in_nsp = parse_nsp(args, "in_nsp",
1400+ &tnl_cfg.in_nsp_present,
1401+ &tnl_cfg.in_nsp_flow);
1402+
1403+ tnl_cfg.out_nsp = parse_nsp(args, "out_nsp",
1404+ &tnl_cfg.out_nsp_present,
1405+ &tnl_cfg.out_nsp_flow);
1406+
1407+ tnl_cfg.in_nsi = parse_nsi(args, "in_nsi",
1408+ &tnl_cfg.in_nsi_present,
1409+ &tnl_cfg.in_nsi_flow);
1410+
1411+ tnl_cfg.out_nsi = parse_nsi(args, "out_nsi",
1412+ &tnl_cfg.out_nsi_present,
1413+ &tnl_cfg.out_nsi_flow);
1414+
1415+ tnl_cfg.in_nshc1 = parse_nshc(args, "nshc1", "in_nshc1",
1416+ &tnl_cfg.in_nshc1_present,
1417+ &tnl_cfg.in_nshc1_flow);
1418+
1419+ tnl_cfg.out_nshc1 = parse_nshc(args, "nshc1", "out_nshc1",
1420+ &tnl_cfg.out_nshc1_present,
1421+ &tnl_cfg.out_nshc1_flow);
1422+
1423+ tnl_cfg.in_nshc2 = parse_nshc(args, "nshc2", "in_nshc2",
1424+ &tnl_cfg.in_nshc2_present,
1425+ &tnl_cfg.in_nshc2_flow);
1426+
1427+ tnl_cfg.out_nshc2 = parse_nshc(args, "nshc2", "out_nshc2",
1428+ &tnl_cfg.out_nshc2_present,
1429+ &tnl_cfg.out_nshc2_flow);
1430+
1431+ tnl_cfg.in_nshc3 = parse_nshc(args, "nshc3", "in_nshc3",
1432+ &tnl_cfg.in_nshc3_present,
1433+ &tnl_cfg.in_nshc3_flow);
1434+
1435+ tnl_cfg.out_nshc3 = parse_nshc(args, "nshc3", "out_nshc3",
1436+ &tnl_cfg.out_nshc3_present,
1437+ &tnl_cfg.out_nshc3_flow);
1438+
1439+ tnl_cfg.in_nshc4 = parse_nshc(args, "nshc4", "in_nshc4",
1440+ &tnl_cfg.in_nshc4_present,
1441+ &tnl_cfg.in_nshc4_flow);
1442+
1443+ tnl_cfg.out_nshc4 = parse_nshc(args, "nshc4", "out_nshc4",
1444+ &tnl_cfg.out_nshc4_present,
1445+ &tnl_cfg.out_nshc4_flow);
1446+
1447+ /* Default nsh service index is 1, if lower packet is dropped */
1448+ if (!tnl_cfg.in_nsi) {
1449+ tnl_cfg.in_nsi = 1;
1450+ }
1451+
1452+ if (!tnl_cfg.out_nsi) {
1453+ tnl_cfg.out_nsi = 1;
1454+ }
1455+ }
1456+
1457 ovs_mutex_lock(&dev->mutex);
1458 if (memcmp(&dev->tnl_cfg, &tnl_cfg, sizeof tnl_cfg)) {
1459 dev->tnl_cfg = tnl_cfg;
1460@@ -709,6 +872,130 @@ get_tunnel_config(const struct netdev *dev, struct smap *args)
1461 smap_add(args, "df_default", "false");
1462 }
1463
1464+ if (tnl_cfg.in_nsp_flow && tnl_cfg.out_nsp_flow) {
1465+ smap_add(args, "nsp", "flow");
1466+ } else if (tnl_cfg.in_nsp_present && tnl_cfg.out_nsp_present
1467+ && tnl_cfg.in_nsp == tnl_cfg.out_nsp) {
1468+ smap_add_format(args, "nsp", "%#"PRIx32, ntohl(tnl_cfg.in_nsp));
1469+ } else {
1470+ if (tnl_cfg.in_nsp_flow) {
1471+ smap_add(args, "in_nsp", "flow");
1472+ } else if (tnl_cfg.in_nsp_present) {
1473+ smap_add_format(args, "in_nsp", "%#"PRIx32,
1474+ ntohl(tnl_cfg.in_nsp));
1475+ }
1476+
1477+ if (tnl_cfg.out_nsp_flow) {
1478+ smap_add(args, "out_nsp", "flow");
1479+ } else if (tnl_cfg.out_nsp_present) {
1480+ smap_add_format(args, "out_nsp", "%#"PRIx32,
1481+ ntohl(tnl_cfg.out_nsp));
1482+ }
1483+ }
1484+
1485+ if (tnl_cfg.in_nsi_flow && tnl_cfg.out_nsi_flow) {
1486+ smap_add(args, "nsi", "flow");
1487+ } else if (tnl_cfg.in_nsi_present && tnl_cfg.out_nsi_present
1488+ && tnl_cfg.in_nsi == tnl_cfg.out_nsi) {
1489+ smap_add_format(args, "nsi", "%"PRIu8, tnl_cfg.in_nsi);
1490+ } else {
1491+ if (tnl_cfg.in_nsi_flow) {
1492+ smap_add(args, "in_nsi", "flow");
1493+ } else if (tnl_cfg.in_nsi_present) {
1494+ smap_add_format(args, "in_nsi", "%"PRIu8, tnl_cfg.in_nsi);
1495+ }
1496+
1497+ if (tnl_cfg.out_nsi_flow) {
1498+ smap_add(args, "out_nsi", "flow");
1499+ } else if (tnl_cfg.out_nsi_present) {
1500+ smap_add_format(args, "out_nsi", "%"PRIu8, tnl_cfg.out_nsi);
1501+ }
1502+ }
1503+
1504+ if (tnl_cfg.in_nshc1_flow && tnl_cfg.out_nshc1_flow) {
1505+ smap_add(args, "nshc1", "flow");
1506+ } else if (tnl_cfg.in_nshc1_present && tnl_cfg.out_nshc1_present
1507+ && tnl_cfg.in_nshc1 == tnl_cfg.out_nshc1) {
1508+ smap_add_format(args, "nshc1", "%#"PRIx32, ntohl(tnl_cfg.in_nshc1));
1509+ } else {
1510+ if (tnl_cfg.in_nshc1_flow) {
1511+ smap_add(args, "in_nshc1", "flow");
1512+ } else if (tnl_cfg.in_nshc1_present) {
1513+ smap_add_format(args, "in_nshc1", "%#"PRIx32,
1514+ ntohl(tnl_cfg.in_nshc1));
1515+ }
1516+
1517+ if (tnl_cfg.out_nshc1_flow) {
1518+ smap_add(args, "out_nshc1", "flow");
1519+ } else if (tnl_cfg.out_nshc1_present) {
1520+ smap_add_format(args, "out_nshc1", "%#"PRIx32,
1521+ ntohl(tnl_cfg.out_nshc1));
1522+ }
1523+ }
1524+
1525+ if (tnl_cfg.in_nshc2_flow && tnl_cfg.out_nshc2_flow) {
1526+ smap_add(args, "nshc2", "flow");
1527+ } else if (tnl_cfg.in_nshc2_present && tnl_cfg.out_nshc2_present
1528+ && tnl_cfg.in_nshc2 == tnl_cfg.out_nshc2) {
1529+ smap_add_format(args, "nshc2", "%#"PRIx32, ntohl(tnl_cfg.in_nshc2));
1530+ } else {
1531+ if (tnl_cfg.in_nshc2_flow) {
1532+ smap_add(args, "in_nshc2", "flow");
1533+ } else if (tnl_cfg.in_nshc2_present) {
1534+ smap_add_format(args, "in_nshc2", "%#"PRIx32,
1535+ ntohl(tnl_cfg.in_nshc2));
1536+ }
1537+
1538+ if (tnl_cfg.out_nshc2_flow) {
1539+ smap_add(args, "out_nshc2", "flow");
1540+ } else if (tnl_cfg.out_nshc2_present) {
1541+ smap_add_format(args, "out_nshc2", "%#"PRIx32,
1542+ ntohl(tnl_cfg.out_nshc2));
1543+ }
1544+ }
1545+
1546+ if (tnl_cfg.in_nshc3_flow && tnl_cfg.out_nshc3_flow) {
1547+ smap_add(args, "nshc3", "flow");
1548+ } else if (tnl_cfg.in_nshc3_present && tnl_cfg.out_nshc3_present
1549+ && tnl_cfg.in_nshc3 == tnl_cfg.out_nshc3) {
1550+ smap_add_format(args, "nshc3", "%#"PRIx32, ntohl(tnl_cfg.in_nshc3));
1551+ } else {
1552+ if (tnl_cfg.in_nshc3_flow) {
1553+ smap_add(args, "in_nshc3", "flow");
1554+ } else if (tnl_cfg.in_nshc3_present) {
1555+ smap_add_format(args, "in_nshc3", "%#"PRIx32,
1556+ ntohl(tnl_cfg.in_nshc3));
1557+ }
1558+
1559+ if (tnl_cfg.out_nshc3_flow) {
1560+ smap_add(args, "out_nshc3", "flow");
1561+ } else if (tnl_cfg.out_nshc3_present) {
1562+ smap_add_format(args, "out_nshc3", "%#"PRIx32,
1563+ ntohl(tnl_cfg.out_nshc3));
1564+ }
1565+ }
1566+
1567+ if (tnl_cfg.in_nshc4_flow && tnl_cfg.out_nshc4_flow) {
1568+ smap_add(args, "nshc4", "flow");
1569+ } else if (tnl_cfg.in_nshc4_present && tnl_cfg.out_nshc4_present
1570+ && tnl_cfg.in_nshc4 == tnl_cfg.out_nshc4) {
1571+ smap_add_format(args, "nshc4", "%#"PRIx32, ntohl(tnl_cfg.in_nshc4));
1572+ } else {
1573+ if (tnl_cfg.in_nshc4_flow) {
1574+ smap_add(args, "in_nshc4", "flow");
1575+ } else if (tnl_cfg.in_nshc4_present) {
1576+ smap_add_format(args, "in_nshc4", "%#"PRIx32,
1577+ ntohl(tnl_cfg.in_nshc4));
1578+ }
1579+
1580+ if (tnl_cfg.out_nshc4_flow) {
1581+ smap_add(args, "out_nshc4", "flow");
1582+ } else if (tnl_cfg.out_nshc4_present) {
1583+ smap_add_format(args, "out_nshc4", "%#"PRIx32,
1584+ ntohl(tnl_cfg.out_nshc4));
1585+ }
1586+ }
1587+
1588 return 0;
1589 }
1590
1591@@ -1356,7 +1643,6 @@ netdev_vport_range(struct unixctl_conn *conn, int argc,
1592 unixctl_command_reply(conn, "OK");
1593 }
1594
1595-
1596 #define VPORT_FUNCTIONS(GET_CONFIG, SET_CONFIG, \
1597 GET_TUNNEL_CONFIG, GET_STATUS, \
1598 BUILD_HEADER, \
1599@@ -1427,6 +1713,7 @@ netdev_vport_range(struct unixctl_conn *conn, int argc,
1600 NULL, /* rx_drain */
1601
1602
1603+
1604 #define TUNNEL_CLASS(NAME, DPIF_PORT, BUILD_HEADER, PUSH_HEADER, POP_HEADER) \
1605 { DPIF_PORT, \
1606 { NAME, VPORT_FUNCTIONS(get_tunnel_config, \
1607diff --git a/lib/netdev.h b/lib/netdev.h
1608index 0fbcb65..4dadf1c 100644
1609--- a/lib/netdev.h
1610+++ b/lib/netdev.h
1611@@ -106,6 +106,22 @@ struct netdev_stats {
1612
1613 /* Configuration specific to tunnels. */
1614 struct netdev_tunnel_config {
1615+ bool in_nsp_present;
1616+ bool in_nsp_flow;
1617+ ovs_be32 in_nsp; /* incoming NSH service path */
1618+
1619+ bool out_nsp_present;
1620+ bool out_nsp_flow;
1621+ ovs_be32 out_nsp; /* outgoing NSH service path */
1622+
1623+ bool in_nsi_present;
1624+ bool in_nsi_flow;
1625+ uint8_t in_nsi; /* incoming NSH service index */
1626+
1627+ bool out_nsi_present;
1628+ bool out_nsi_flow;
1629+ uint8_t out_nsi; /* outgoing NSH service index */
1630+
1631 bool in_key_present;
1632 bool in_key_flow;
1633 ovs_be64 in_key;
1634@@ -132,6 +148,39 @@ struct netdev_tunnel_config {
1635 bool csum;
1636 bool ipsec;
1637 bool dont_fragment;
1638+
1639+ bool in_nshc1_present;
1640+ bool in_nshc1_flow;
1641+ ovs_be32 in_nshc1; /* incoming NSH context c1 */
1642+
1643+ bool out_nshc1_present;
1644+ bool out_nshc1_flow;
1645+ ovs_be32 out_nshc1; /* outgoing NSH context c1 */
1646+
1647+ bool in_nshc2_present;
1648+ bool in_nshc2_flow;
1649+ ovs_be32 in_nshc2; /* incoming NSH context c2 */
1650+
1651+ bool out_nshc2_present;
1652+ bool out_nshc2_flow;
1653+ ovs_be32 out_nshc2; /* outgoing NSH context c2 */
1654+
1655+ bool in_nshc3_present;
1656+ bool in_nshc3_flow;
1657+ ovs_be32 in_nshc3; /* incoming NSH context c3 */
1658+
1659+ bool out_nshc3_present;
1660+ bool out_nshc3_flow;
1661+ ovs_be32 out_nshc3; /* outgoing NSH context c3 */
1662+
1663+ bool in_nshc4_present;
1664+ bool in_nshc4_flow;
1665+ ovs_be32 in_nshc4; /* incoming NSH context c4 */
1666+
1667+ bool out_nshc4_present;
1668+ bool out_nshc4_flow;
1669+ ovs_be32 out_nshc4; /* outgoing NSH context c4 */
1670+
1671 };
1672
1673 void netdev_run(void);
1674diff --git a/lib/nx-match.c b/lib/nx-match.c
1675index eef2c54..7b8f09b 100644
1676--- a/lib/nx-match.c
1677+++ b/lib/nx-match.c
1678@@ -1004,6 +1004,12 @@ nx_put_raw(struct ofpbuf *b, enum ofp_version oxm, const struct match *match,
1679 /* Tunnel ID. */
1680 nxm_put_64m(b, MFF_TUN_ID, oxm,
1681 flow->tunnel.tun_id, match->wc.masks.tunnel.tun_id);
1682+ nxm_put_32m(b, MFF_NSP, oxm, flow->tunnel.nsp, match->wc.masks.tunnel.nsp);
1683+ nxm_put_8m(b, MFF_NSI, oxm, flow->tunnel.nsi, match->wc.masks.tunnel.nsi);
1684+ nxm_put_32m(b, MFF_NSH_C1, oxm, flow->tunnel.nshc1, match->wc.masks.tunnel.nshc1);
1685+ nxm_put_32m(b, MFF_NSH_C2, oxm, flow->tunnel.nshc2, match->wc.masks.tunnel.nshc2);
1686+ nxm_put_32m(b, MFF_NSH_C3, oxm, flow->tunnel.nshc3, match->wc.masks.tunnel.nshc3);
1687+ nxm_put_32m(b, MFF_NSH_C4, oxm, flow->tunnel.nshc4, match->wc.masks.tunnel.nshc4);
1688
1689 /* Other tunnel metadata. */
1690 nxm_put_16m(b, MFF_TUN_FLAGS, oxm,
1691diff --git a/lib/odp-util.c b/lib/odp-util.c
1692index c173623..e8bc86d 100644
1693--- a/lib/odp-util.c
1694+++ b/lib/odp-util.c
1695@@ -1181,6 +1181,12 @@ static const struct attr_len_tbl ovs_tun_key_attr_lens[OVS_TUNNEL_KEY_ATTR_MAX +
1696 [OVS_TUNNEL_KEY_ATTR_TP_SRC] = { .len = 2 },
1697 [OVS_TUNNEL_KEY_ATTR_TP_DST] = { .len = 2 },
1698 [OVS_TUNNEL_KEY_ATTR_OAM] = { .len = 0 },
1699+ [OVS_TUNNEL_KEY_ATTR_NSP] = { .len = 4 },
1700+ [OVS_TUNNEL_KEY_ATTR_NSI] = { .len = 1 },
1701+ [OVS_TUNNEL_KEY_ATTR_NSH_C1] = { .len = 4 },
1702+ [OVS_TUNNEL_KEY_ATTR_NSH_C2] = { .len = 4 },
1703+ [OVS_TUNNEL_KEY_ATTR_NSH_C3] = { .len = 4 },
1704+ [OVS_TUNNEL_KEY_ATTR_NSH_C4] = { .len = 4 },
1705 [OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS] = { .len = ATTR_LEN_VARIABLE },
1706 [OVS_TUNNEL_KEY_ATTR_VXLAN_OPTS] = { .len = ATTR_LEN_NESTED,
1707 .next = ovs_vxlan_ext_attr_lens ,
1708@@ -1340,7 +1346,30 @@ odp_tun_key_from_attr__(const struct nlattr *attr,
1709 return ODP_FIT_ERROR;
1710 }
1711 break;
1712-
1713+ case OVS_TUNNEL_KEY_ATTR_NSP:
1714+ tun->nsp = nl_attr_get_be32(a);
1715+ tun->flags |= FLOW_TNL_F_NSP;
1716+ break;
1717+ case OVS_TUNNEL_KEY_ATTR_NSI:
1718+ tun->nsi = nl_attr_get_u8(a);
1719+ tun->flags |= FLOW_TNL_F_NSI;
1720+ break;
1721+ case OVS_TUNNEL_KEY_ATTR_NSH_C1:
1722+ tun->nshc1 = nl_attr_get_be32(a);
1723+ tun->flags |= FLOW_TNL_F_NSH_C1;
1724+ break;
1725+ case OVS_TUNNEL_KEY_ATTR_NSH_C2:
1726+ tun->nshc2 = nl_attr_get_be32(a);
1727+ tun->flags |= FLOW_TNL_F_NSH_C2;
1728+ break;
1729+ case OVS_TUNNEL_KEY_ATTR_NSH_C3:
1730+ tun->nshc3 = nl_attr_get_be32(a);
1731+ tun->flags |= FLOW_TNL_F_NSH_C3;
1732+ break;
1733+ case OVS_TUNNEL_KEY_ATTR_NSH_C4:
1734+ tun->nshc4 = nl_attr_get_be32(a);
1735+ tun->flags |= FLOW_TNL_F_NSH_C4;
1736+ break;
1737 default:
1738 /* Allow this to show up as unexpected, if there are unknown
1739 * tunnel attribute, eventually resulting in ODP_FIT_TOO_MUCH. */
1740@@ -1413,6 +1442,24 @@ tun_key_to_attr(struct ofpbuf *a, const struct flow_tnl *tun_key,
1741 nl_msg_end_nested(a, vxlan_opts_ofs);
1742 }
1743 tun_metadata_to_geneve_nlattr(tun_key, tun_flow_key, key_buf, a);
1744+ if (tun_key->nsp || tun_key->flags & FLOW_TNL_F_NSP) {
1745+ nl_msg_put_be32(a, OVS_TUNNEL_KEY_ATTR_NSP, tun_key->nsp);
1746+ }
1747+ if (tun_key->nsi || tun_key->flags & FLOW_TNL_F_NSI) {
1748+ nl_msg_put_u8(a, OVS_TUNNEL_KEY_ATTR_NSI, tun_key->nsi);
1749+ }
1750+ if (tun_key->nshc1 || tun_key->flags & FLOW_TNL_F_NSH_C1) {
1751+ nl_msg_put_be32(a, OVS_TUNNEL_KEY_ATTR_NSH_C1, tun_key->nshc1);
1752+ }
1753+ if (tun_key->nshc2 || tun_key->flags & FLOW_TNL_F_NSH_C2) {
1754+ nl_msg_put_be32(a, OVS_TUNNEL_KEY_ATTR_NSH_C2, tun_key->nshc2);
1755+ }
1756+ if (tun_key->nshc3 || tun_key->flags & FLOW_TNL_F_NSH_C3) {
1757+ nl_msg_put_be32(a, OVS_TUNNEL_KEY_ATTR_NSH_C3, tun_key->nshc3);
1758+ }
1759+ if (tun_key->nshc4 || tun_key->flags & FLOW_TNL_F_NSH_C4) {
1760+ nl_msg_put_be32(a, OVS_TUNNEL_KEY_ATTR_NSH_C4, tun_key->nshc4);
1761+ }
1762
1763 nl_msg_end_nested(a, tun_key_ofs);
1764 }
1765@@ -1677,6 +1724,24 @@ format_be16x(struct ds *ds, const char *name, ovs_be16 key,
1766 }
1767 }
1768
1769+
1770+static void
1771+format_be32(struct ds *ds, const char *name, ovs_be32 key,
1772+ const ovs_be32 *mask, bool verbose)
1773+{
1774+ bool mask_empty = mask && !*mask;
1775+
1776+ if (verbose || !mask_empty) {
1777+ bool mask_full = !mask || *mask == OVS_BE32_MAX;
1778+
1779+ ds_put_format(ds, "%s=%"PRIx32, name, ntohl(key));
1780+ if (!mask_full) { /* Partially masked. */
1781+ ds_put_format(ds, "/%#"PRIx32, ntohl(*mask));
1782+ }
1783+ ds_put_char(ds, ',');
1784+ }
1785+}
1786+
1787 static void
1788 format_tun_flags(struct ds *ds, const char *name, uint16_t key,
1789 const uint16_t *mask, bool verbose)
1790@@ -1953,6 +2018,54 @@ format_odp_tun_attr(const struct nlattr *attr, const struct nlattr *mask_attr,
1791 format_be16(ds, "tp_dst", nl_attr_get_be16(a),
1792 ma ? nl_attr_get(ma) : NULL, verbose);
1793 break;
1794+ case OVS_TUNNEL_KEY_ATTR_NSP:
1795+ format_be32(ds, "nsp", nl_attr_get_be32(a),
1796+ ma ? nl_attr_get(ma) : NULL, verbose);
1797+ flags |= FLOW_TNL_F_NSP;
1798+ if (ma) {
1799+ mask_flags |= FLOW_TNL_F_NSP;
1800+ }
1801+ break;
1802+ case OVS_TUNNEL_KEY_ATTR_NSI:
1803+ format_u8u(ds, "nsi", nl_attr_get_u8(a),
1804+ ma ? nl_attr_get(ma) : NULL, verbose);
1805+ flags |= FLOW_TNL_F_NSI;
1806+ if (ma) {
1807+ mask_flags |= FLOW_TNL_F_NSI;
1808+ }
1809+ break;
1810+ case OVS_TUNNEL_KEY_ATTR_NSH_C1:
1811+ format_be32(ds, "nshc1", nl_attr_get_be32(a),
1812+ ma ? nl_attr_get(ma) : NULL, verbose);
1813+ flags |= FLOW_TNL_F_NSH_C1;
1814+ if (ma) {
1815+ mask_flags |= FLOW_TNL_F_NSH_C1;
1816+ }
1817+ break;
1818+ case OVS_TUNNEL_KEY_ATTR_NSH_C2:
1819+ format_be32(ds, "nshc2", nl_attr_get_be32(a),
1820+ ma ? nl_attr_get(ma) : NULL, verbose);
1821+ flags |= FLOW_TNL_F_NSH_C2;
1822+ if (ma) {
1823+ mask_flags |= FLOW_TNL_F_NSH_C2;
1824+ }
1825+ break;
1826+ case OVS_TUNNEL_KEY_ATTR_NSH_C3:
1827+ format_be32(ds, "nshc3", nl_attr_get_be32(a),
1828+ ma ? nl_attr_get(ma) : NULL, verbose);
1829+ flags |= FLOW_TNL_F_NSH_C3;
1830+ if (ma) {
1831+ mask_flags |= FLOW_TNL_F_NSH_C3;
1832+ }
1833+ break;
1834+ case OVS_TUNNEL_KEY_ATTR_NSH_C4:
1835+ format_be32(ds, "nshc4", nl_attr_get_be32(a),
1836+ ma ? nl_attr_get(ma) : NULL, verbose);
1837+ flags |= FLOW_TNL_F_NSH_C4;
1838+ if (ma) {
1839+ mask_flags |= FLOW_TNL_F_NSH_C4;
1840+ }
1841+ break;
1842 case OVS_TUNNEL_KEY_ATTR_OAM:
1843 flags |= FLOW_TNL_F_OAM;
1844 break;
1845@@ -2016,6 +2129,8 @@ format_frag(struct ds *ds, const char *name, uint8_t key,
1846 }
1847 }
1848
1849+
1850+
1851 static void
1852 format_odp_key_attr(const struct nlattr *a, const struct nlattr *ma,
1853 const struct hmap *portno_names, struct ds *ds,
1854@@ -2546,6 +2661,29 @@ scan_be16(const char *s, ovs_be16 *key, ovs_be16 *mask)
1855 }
1856
1857 static int
1858+scan_be32(const char *s, ovs_be32 *key, ovs_be32 *mask)
1859+{
1860+ uint32_t key_, mask_;
1861+ int n;
1862+
1863+ if (ovs_scan(s, "%"SCNi32"%n", &key_, &n)) {
1864+ int len = n;
1865+
1866+ *key = htonl(key_);
1867+ if (mask) {
1868+ if (ovs_scan(s + len, "/%"SCNi32"%n", &mask_, &n)) {
1869+ len += n;
1870+ *mask = htonl(mask_);
1871+ } else {
1872+ *mask = OVS_BE32_MAX;
1873+ }
1874+ }
1875+ return len;
1876+ }
1877+ return 0;
1878+}
1879+
1880+static int
1881 scan_be64(const char *s, ovs_be64 *key, ovs_be64 *mask)
1882 {
1883 uint64_t key_, mask_;
1884@@ -3135,12 +3273,19 @@ parse_odp_key_mask_attr(const char *s, const struct simap *port_names,
1885 SCAN_FIELD_NESTED("ttl=", uint8_t, u8, OVS_TUNNEL_KEY_ATTR_TTL);
1886 SCAN_FIELD_NESTED("tp_src=", ovs_be16, be16, OVS_TUNNEL_KEY_ATTR_TP_SRC);
1887 SCAN_FIELD_NESTED("tp_dst=", ovs_be16, be16, OVS_TUNNEL_KEY_ATTR_TP_DST);
1888+ SCAN_FIELD_NESTED("nsi=", uint8_t, u8, OVS_TUNNEL_KEY_ATTR_NSI);
1889+ SCAN_FIELD_NESTED("nsp=", ovs_be32, be32, OVS_TUNNEL_KEY_ATTR_NSP);
1890+ SCAN_FIELD_NESTED("nshc1=", ovs_be32, be32, OVS_TUNNEL_KEY_ATTR_NSH_C1);
1891+ SCAN_FIELD_NESTED("nshc2=", ovs_be32, be32, OVS_TUNNEL_KEY_ATTR_NSH_C2);
1892+ SCAN_FIELD_NESTED("nshc3=", ovs_be32, be32, OVS_TUNNEL_KEY_ATTR_NSH_C3);
1893+ SCAN_FIELD_NESTED("nshc4=", ovs_be32, be32, OVS_TUNNEL_KEY_ATTR_NSH_C4);
1894 SCAN_FIELD_NESTED_FUNC("vxlan(gbp(", uint32_t, vxlan_gbp, vxlan_gbp_to_attr);
1895 SCAN_FIELD_NESTED_FUNC("geneve(", struct geneve_scan, geneve,
1896 geneve_to_attr);
1897 SCAN_FIELD_NESTED_FUNC("flags(", uint16_t, tun_flags, tun_flags_to_attr);
1898 } SCAN_END_NESTED();
1899
1900+
1901 SCAN_SINGLE_PORT("in_port(", uint32_t, OVS_KEY_ATTR_IN_PORT);
1902
1903 SCAN_BEGIN("eth(", struct ovs_key_ethernet) {
1904diff --git a/lib/odp-util.h b/lib/odp-util.h
1905index bc27794..9f8e741 100644
1906--- a/lib/odp-util.h
1907+++ b/lib/odp-util.h
1908@@ -116,6 +116,12 @@ void odp_portno_names_destroy(struct hmap *portno_names);
1909 * - OVS_TUNNEL_KEY_ATTR_OAM 0 -- 4 4
1910 * - OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS 256 -- 4 260
1911 * - OVS_TUNNEL_KEY_ATTR_VXLAN_OPTS - -- - - (shared with _GENEVE_OPTS)
1912+ * - OVS_TUNNEL_KEY_ATTR_NSP 4 -- 4 8
1913+ * - OVS_TUNNEL_KEY_ATTR_NSI 1 3 4 8
1914+ * - OVS_TUNNEL_KEY_ATTR_NSH_C1 4 -- 4 8
1915+ * - OVS_TUNNEL_KEY_ATTR_NSH_C2 4 -- 4 8
1916+ * - OVS_TUNNEL_KEY_ATTR_NSH_C3 4 -- 4 8
1917+ * - OVS_TUNNEL_KEY_ATTR_NSH_C4 4 -- 4 8
1918 * OVS_KEY_ATTR_IN_PORT 4 -- 4 8
1919 * OVS_KEY_ATTR_SKB_MARK 4 -- 4 8
1920 * OVS_KEY_ATTR_DP_HASH 4 -- 4 8
1921@@ -129,7 +135,7 @@ void odp_portno_names_destroy(struct hmap *portno_names);
1922 * OVS_KEY_ATTR_ICMPV6 2 2 4 8
1923 * OVS_KEY_ATTR_ND 28 -- 4 32
1924 * ----------------------------------------------------------
1925- * total 488
1926+ * total 536
1927 *
1928 * We include some slack space in case the calculation isn't quite right or we
1929 * add another field and forget to adjust this value.
1930diff --git a/lib/ofp-actions.c b/lib/ofp-actions.c
1931index 88f0f85..b35daa8 100644
1932--- a/lib/ofp-actions.c
1933+++ b/lib/ofp-actions.c
1934@@ -286,6 +286,24 @@ enum ofp_raw_action_type {
1935 /* NX1.0+(34): struct nx_action_conjunction. */
1936 NXAST_RAW_CONJUNCTION,
1937
1938+ /* NX1.0+(106): uint8_t. */
1939+ NXAST_RAW_SET_NSI,
1940+
1941+ /* NX1.0+(105): ovs_be32. */
1942+ NXAST_RAW_SET_NSP,
1943+
1944+ /* NX1.0+(107): ovs_be32. */
1945+ NXAST_RAW_SET_NSH_C1,
1946+
1947+ /* NX1.0+(108): ovs_be32. */
1948+ NXAST_RAW_SET_NSH_C2,
1949+
1950+ /* NX1.0+(109): ovs_be32. */
1951+ NXAST_RAW_SET_NSH_C3,
1952+
1953+ /* NX1.0+(110): ovs_be32. */
1954+ NXAST_RAW_SET_NSH_C4,
1955+
1956 /* ## ------------------ ## */
1957 /* ## Debugging actions. ## */
1958 /* ## ------------------ ## */
1959@@ -3179,7 +3197,310 @@ format_SET_TUNNEL(const struct ofpact_tunnel *a, struct ds *s)
1960 || a->ofpact.raw == NXAST_RAW_SET_TUNNEL64 ? "64" : ""),
1961 a->tun_id);
1962 }
1963-
1964+
1965+/* Action structure for NXAST_SET_NSP.
1966+ *
1967+ * Sets the encapsulating NSH service path ID to a 32-bit value. */
1968+
1969+/* Set NSI actions. */
1970+static enum ofperr
1971+decode_NXAST_RAW_SET_NSI(const uint8_t nsi, struct ofpbuf * out)
1972+{
1973+ struct ofpact_nsi *pnsi = ofpact_put_SET_NSI(out);
1974+ pnsi->ofpact.raw = NXAST_RAW_SET_NSI;
1975+ pnsi->nsi = nsi;
1976+
1977+ return 0;
1978+}
1979+
1980+static void
1981+encode_SET_NSI(const struct ofpact_nsi *pnsi,
1982+ enum ofp_version ofp_version, struct ofpbuf *out)
1983+{
1984+ uint8_t nsi = pnsi->nsi;
1985+
1986+ if (ofp_version < OFP12_VERSION) {
1987+ put_NXAST_SET_NSI(out, nsi);
1988+ } else {
1989+ ofpact_put_set_field(out, ofp_version, MFF_NSI, nsi);
1990+ }
1991+}
1992+
1993+static char * OVS_WARN_UNUSED_RESULT
1994+parse_set_nsi(char *arg, struct ofpbuf *ofpacts,
1995+ enum ofp_raw_action_type raw)
1996+{
1997+ struct ofpact_nsi *pnsi;
1998+
1999+ pnsi = ofpact_put_SET_NSI(ofpacts);
2000+ pnsi->ofpact.raw = raw;
2001+
2002+ return str_to_u8(arg, "nsi", &pnsi->nsi);
2003+}
2004+
2005+static char * OVS_WARN_UNUSED_RESULT
2006+parse_SET_NSI(char *arg, struct ofpbuf *ofpacts,
2007+ enum ofputil_protocol *usable_protocols OVS_UNUSED)
2008+{
2009+ return parse_set_nsi(arg, ofpacts, NXAST_RAW_SET_NSI);
2010+}
2011+
2012+static void
2013+format_SET_NSI(const struct ofpact_nsi *a, struct ds *s)
2014+{
2015+ ds_put_format(s, "set_nsi:%d", a->nsi);
2016+}
2017+
2018+/* Set NSP actions. */
2019+static enum ofperr
2020+decode_NXAST_RAW_SET_NSP(const ovs_be32 nsp, struct ofpbuf * out)
2021+{
2022+ struct ofpact_nsp *pnsp = ofpact_put_SET_NSP(out);
2023+ pnsp->ofpact.raw = NXAST_RAW_SET_NSP;
2024+ pnsp->nsp = nsp;
2025+
2026+ return 0;
2027+}
2028+
2029+static void
2030+encode_SET_NSP(const struct ofpact_nsp *pnsp,
2031+ enum ofp_version ofp_version, struct ofpbuf *out)
2032+{
2033+ uint32_t nsp = pnsp->nsp;
2034+
2035+ if (ofp_version < OFP12_VERSION) {
2036+ put_NXAST_SET_NSP(out, nsp);
2037+ } else {
2038+ ofpact_put_set_field(out, ofp_version, MFF_NSP, nsp);
2039+ }
2040+}
2041+
2042+static char * OVS_WARN_UNUSED_RESULT
2043+parse_set_nsp(char *arg, struct ofpbuf *ofpacts,
2044+ enum ofp_raw_action_type raw)
2045+{
2046+ struct ofpact_nsp *pnsp;
2047+
2048+ pnsp = ofpact_put_SET_NSP(ofpacts);
2049+ pnsp->ofpact.raw = raw;
2050+
2051+ return str_to_be32(arg, &pnsp->nsp);
2052+}
2053+
2054+static char * OVS_WARN_UNUSED_RESULT
2055+parse_SET_NSP(char *arg, struct ofpbuf *ofpacts,
2056+ enum ofputil_protocol *usable_protocols OVS_UNUSED)
2057+{
2058+ return parse_set_nsp(arg, ofpacts, NXAST_RAW_SET_NSP);
2059+}
2060+
2061+static void
2062+format_SET_NSP(const struct ofpact_nsp *a, struct ds *s)
2063+{
2064+ ds_put_format(s, "set_nsp:%#"PRIx32, ntohl(a->nsp));
2065+}
2066+
2067+
2068+/* Set NSH_C1 actions. */
2069+static enum ofperr
2070+decode_NXAST_RAW_SET_NSH_C1(const ovs_be32 nshc1, struct ofpbuf * out)
2071+{
2072+ struct ofpact_nshc1 *pnshc1= ofpact_put_SET_NSH_C1(out);
2073+ pnshc1->ofpact.raw = NXAST_RAW_SET_NSH_C1;
2074+ pnshc1->nshc1 = nshc1;
2075+
2076+ return 0;
2077+}
2078+
2079+static void
2080+encode_SET_NSH_C1(const struct ofpact_nshc1 *pnshc1,
2081+ enum ofp_version ofp_version, struct ofpbuf *out)
2082+{
2083+ uint32_t nshc1 = pnshc1->nshc1;
2084+
2085+ if (ofp_version < OFP12_VERSION) {
2086+ put_NXAST_SET_NSH_C1(out, nshc1);
2087+ } else {
2088+ ofpact_put_set_field(out, ofp_version, MFF_NSH_C1, nshc1);
2089+ }
2090+}
2091+
2092+static char * OVS_WARN_UNUSED_RESULT
2093+parse_set_nshc1(char *arg, struct ofpbuf *ofpacts,
2094+ enum ofp_raw_action_type raw)
2095+{
2096+ struct ofpact_nshc1 *pnshc1;
2097+
2098+ pnshc1 = ofpact_put_SET_NSH_C1(ofpacts);
2099+ pnshc1->ofpact.raw = raw;
2100+
2101+ return str_to_be32(arg, &pnshc1->nshc1);
2102+}
2103+
2104+static char * OVS_WARN_UNUSED_RESULT
2105+parse_SET_NSH_C1(char *arg, struct ofpbuf *ofpacts,
2106+ enum ofputil_protocol *usable_protocols OVS_UNUSED)
2107+{
2108+ return parse_set_nshc1(arg, ofpacts, NXAST_RAW_SET_NSH_C1);
2109+}
2110+
2111+static void
2112+format_SET_NSH_C1(const struct ofpact_nshc1 *a, struct ds *s)
2113+{
2114+ ds_put_format(s, "set_nshc1:%#"PRIx32, ntohl(a->nshc1));
2115+}
2116+
2117+
2118+/* Set NSH_C2 actions. */
2119+static enum ofperr
2120+decode_NXAST_RAW_SET_NSH_C2(const ovs_be32 nshc2, struct ofpbuf * out)
2121+{
2122+ struct ofpact_nshc2 *pnshc2= ofpact_put_SET_NSH_C2(out);
2123+ pnshc2->ofpact.raw = NXAST_RAW_SET_NSH_C2;
2124+ pnshc2->nshc2 = nshc2;
2125+
2126+ return 0;
2127+}
2128+
2129+static void
2130+encode_SET_NSH_C2(const struct ofpact_nshc2 *pnshc2,
2131+ enum ofp_version ofp_version, struct ofpbuf *out)
2132+{
2133+ uint32_t nshc2 = pnshc2->nshc2;
2134+
2135+ if (ofp_version < OFP12_VERSION) {
2136+ put_NXAST_SET_NSH_C2(out, nshc2);
2137+ } else {
2138+ ofpact_put_set_field(out, ofp_version, MFF_NSH_C2, nshc2);
2139+ }
2140+}
2141+
2142+static char * OVS_WARN_UNUSED_RESULT
2143+parse_set_nshc2(char *arg, struct ofpbuf *ofpacts,
2144+ enum ofp_raw_action_type raw)
2145+{
2146+ struct ofpact_nshc2 *pnshc2;
2147+
2148+ pnshc2 = ofpact_put_SET_NSH_C2(ofpacts);
2149+ pnshc2->ofpact.raw = raw;
2150+
2151+ return str_to_be32(arg, &pnshc2->nshc2);
2152+}
2153+
2154+static char * OVS_WARN_UNUSED_RESULT
2155+parse_SET_NSH_C2(char *arg, struct ofpbuf *ofpacts,
2156+ enum ofputil_protocol *usable_protocols OVS_UNUSED)
2157+{
2158+ return parse_set_nshc2(arg, ofpacts, NXAST_RAW_SET_NSH_C2);
2159+}
2160+
2161+static void
2162+format_SET_NSH_C2(const struct ofpact_nshc2 *a, struct ds *s)
2163+{
2164+ ds_put_format(s, "set_nshc2:%#"PRIx32, ntohl(a->nshc2));
2165+}
2166+
2167+
2168+/* Set NSH_C3 actions. */
2169+static enum ofperr
2170+decode_NXAST_RAW_SET_NSH_C3(const ovs_be32 nshc3, struct ofpbuf * out)
2171+{
2172+ struct ofpact_nshc3 *pnshc3= ofpact_put_SET_NSH_C3(out);
2173+ pnshc3->ofpact.raw = NXAST_RAW_SET_NSH_C3;
2174+ pnshc3->nshc3 = nshc3;
2175+
2176+ return 0;
2177+}
2178+
2179+static void
2180+encode_SET_NSH_C3(const struct ofpact_nshc3 *pnshc3,
2181+ enum ofp_version ofp_version, struct ofpbuf *out)
2182+{
2183+ uint32_t nshc3 = pnshc3->nshc3;
2184+
2185+ if (ofp_version < OFP12_VERSION) {
2186+ put_NXAST_SET_NSH_C3(out, nshc3);
2187+ } else {
2188+ ofpact_put_set_field(out, ofp_version, MFF_NSH_C3, nshc3);
2189+ }
2190+}
2191+
2192+static char * OVS_WARN_UNUSED_RESULT
2193+parse_set_nshc3(char *arg, struct ofpbuf *ofpacts,
2194+ enum ofp_raw_action_type raw)
2195+{
2196+ struct ofpact_nshc3 *pnshc3;
2197+
2198+ pnshc3 = ofpact_put_SET_NSH_C3(ofpacts);
2199+ pnshc3->ofpact.raw = raw;
2200+
2201+ return str_to_be32(arg, &pnshc3->nshc3);
2202+}
2203+
2204+static char * OVS_WARN_UNUSED_RESULT
2205+parse_SET_NSH_C3(char *arg, struct ofpbuf *ofpacts,
2206+ enum ofputil_protocol *usable_protocols OVS_UNUSED)
2207+{
2208+ return parse_set_nshc3(arg, ofpacts, NXAST_RAW_SET_NSH_C3);
2209+}
2210+
2211+static void
2212+format_SET_NSH_C3(const struct ofpact_nshc3 *a, struct ds *s)
2213+{
2214+ ds_put_format(s, "set_nshc3:%#"PRIx32, ntohl(a->nshc3));
2215+}
2216+
2217+
2218+
2219+/* Set NSH_C4 actions. */
2220+static enum ofperr
2221+decode_NXAST_RAW_SET_NSH_C4(const ovs_be32 nshc4, struct ofpbuf * out)
2222+{
2223+ struct ofpact_nshc4 *pnshc4= ofpact_put_SET_NSH_C4(out);
2224+ pnshc4->ofpact.raw = NXAST_RAW_SET_NSH_C4;
2225+ pnshc4->nshc4 = nshc4;
2226+
2227+ return 0;
2228+}
2229+
2230+static void
2231+encode_SET_NSH_C4(const struct ofpact_nshc4 *pnshc4,
2232+ enum ofp_version ofp_version, struct ofpbuf *out)
2233+{
2234+ uint32_t nshc4 = pnshc4->nshc4;
2235+
2236+ if (ofp_version < OFP12_VERSION) {
2237+ put_NXAST_SET_NSH_C4(out, nshc4);
2238+ } else {
2239+ ofpact_put_set_field(out, ofp_version, MFF_NSH_C4, nshc4);
2240+ }
2241+}
2242+
2243+static char * OVS_WARN_UNUSED_RESULT
2244+parse_set_nshc4(char *arg, struct ofpbuf *ofpacts,
2245+ enum ofp_raw_action_type raw)
2246+{
2247+ struct ofpact_nshc4 *pnshc4;
2248+
2249+ pnshc4 = ofpact_put_SET_NSH_C4(ofpacts);
2250+ pnshc4->ofpact.raw = raw;
2251+
2252+ return str_to_be32(arg, &pnshc4->nshc4);
2253+}
2254+
2255+static char * OVS_WARN_UNUSED_RESULT
2256+parse_SET_NSH_C4(char *arg, struct ofpbuf *ofpacts,
2257+ enum ofputil_protocol *usable_protocols OVS_UNUSED)
2258+{
2259+ return parse_set_nshc4(arg, ofpacts, NXAST_RAW_SET_NSH_C4);
2260+}
2261+
2262+static void
2263+format_SET_NSH_C4(const struct ofpact_nshc4 *a, struct ds *s)
2264+{
2265+ ds_put_format(s, "set_nshc4:%#"PRIx32, ntohl(a->nshc4));
2266+}
2267+
2268 /* Set queue action. */
2269
2270 static enum ofperr
2271@@ -4831,6 +5152,12 @@ ofpact_is_set_or_move_action(const struct ofpact *a)
2272 case OFPACT_SET_TUNNEL:
2273 case OFPACT_SET_VLAN_PCP:
2274 case OFPACT_SET_VLAN_VID:
2275+ case OFPACT_SET_NSP:
2276+ case OFPACT_SET_NSI:
2277+ case OFPACT_SET_NSH_C1:
2278+ case OFPACT_SET_NSH_C2:
2279+ case OFPACT_SET_NSH_C3:
2280+ case OFPACT_SET_NSH_C4:
2281 return true;
2282 case OFPACT_BUNDLE:
2283 case OFPACT_CLEAR_ACTIONS:
2284@@ -4900,6 +5227,12 @@ ofpact_is_allowed_in_actions_set(const struct ofpact *a)
2285 case OFPACT_SET_VLAN_PCP:
2286 case OFPACT_SET_VLAN_VID:
2287 case OFPACT_STRIP_VLAN:
2288+ case OFPACT_SET_NSP:
2289+ case OFPACT_SET_NSI:
2290+ case OFPACT_SET_NSH_C1:
2291+ case OFPACT_SET_NSH_C2:
2292+ case OFPACT_SET_NSH_C3:
2293+ case OFPACT_SET_NSH_C4:
2294 return true;
2295
2296 /* In general these actions are excluded because they are not part of
2297@@ -5136,6 +5469,12 @@ ovs_instruction_type_from_ofpact_type(enum ofpact_type type)
2298 case OFPACT_EXIT:
2299 case OFPACT_UNROLL_XLATE:
2300 case OFPACT_SAMPLE:
2301+ case OFPACT_SET_NSP:
2302+ case OFPACT_SET_NSI:
2303+ case OFPACT_SET_NSH_C1:
2304+ case OFPACT_SET_NSH_C2:
2305+ case OFPACT_SET_NSH_C3:
2306+ case OFPACT_SET_NSH_C4:
2307 case OFPACT_DEBUG_RECIRC:
2308 default:
2309 return OVSINST_OFPIT11_APPLY_ACTIONS;
2310@@ -5654,6 +5993,12 @@ ofpact_check__(enum ofputil_protocol *usable_protocols, struct ofpact *a,
2311 case OFPACT_SET_QUEUE:
2312 case OFPACT_POP_QUEUE:
2313 case OFPACT_RESUBMIT:
2314+ case OFPACT_SET_NSP:
2315+ case OFPACT_SET_NSI:
2316+ case OFPACT_SET_NSH_C1:
2317+ case OFPACT_SET_NSH_C2:
2318+ case OFPACT_SET_NSH_C3:
2319+ case OFPACT_SET_NSH_C4:
2320 return 0;
2321
2322 case OFPACT_FIN_TIMEOUT:
2323@@ -6161,6 +6506,12 @@ ofpact_outputs_to_port(const struct ofpact *ofpact, ofp_port_t port)
2324 case OFPACT_GOTO_TABLE:
2325 case OFPACT_METER:
2326 case OFPACT_GROUP:
2327+ case OFPACT_SET_NSI:
2328+ case OFPACT_SET_NSP:
2329+ case OFPACT_SET_NSH_C1:
2330+ case OFPACT_SET_NSH_C2:
2331+ case OFPACT_SET_NSH_C3:
2332+ case OFPACT_SET_NSH_C4:
2333 case OFPACT_DEBUG_RECIRC:
2334 default:
2335 return false;
2336diff --git a/lib/ofp-actions.h b/lib/ofp-actions.h
2337index 51b2963..876c457 100644
2338--- a/lib/ofp-actions.h
2339+++ b/lib/ofp-actions.h
2340@@ -92,6 +92,12 @@
2341 OFPACT(SET_QUEUE, ofpact_queue, ofpact, "set_queue") \
2342 OFPACT(POP_QUEUE, ofpact_null, ofpact, "pop_queue") \
2343 OFPACT(FIN_TIMEOUT, ofpact_fin_timeout, ofpact, "fin_timeout") \
2344+ OFPACT(SET_NSI, ofpact_nsi, ofpact, "set_nsi") \
2345+ OFPACT(SET_NSP, ofpact_nsp, ofpact, "set_nsp") \
2346+ OFPACT(SET_NSH_C1, ofpact_nshc1, ofpact, "set_nshc1") \
2347+ OFPACT(SET_NSH_C2, ofpact_nshc2, ofpact, "set_nshc2") \
2348+ OFPACT(SET_NSH_C3, ofpact_nshc3, ofpact, "set_nshc3") \
2349+ OFPACT(SET_NSH_C4, ofpact_nshc4, ofpact, "set_nshc4") \
2350 \
2351 /* Flow table interaction. */ \
2352 OFPACT(RESUBMIT, ofpact_resubmit, ofpact, "resubmit") \
2353@@ -425,6 +431,48 @@ struct ofpact_tunnel {
2354 uint64_t tun_id;
2355 };
2356
2357+/* OFPACT_SET_NSI.
2358+ * Used for NXAST_SET_NSI */
2359+struct ofpact_nsi {
2360+ struct ofpact ofpact;
2361+ uint8_t nsi;
2362+};
2363+
2364+/* OFPACT_SET_NSP.
2365+ * Used for NXAST_SET_NSP */
2366+struct ofpact_nsp {
2367+ struct ofpact ofpact;
2368+ ovs_be32 nsp;
2369+};
2370+
2371+/* OFPACT_SET_NSH_C1.
2372+ * Used for NXAST_SET_NSH_C1 */
2373+struct ofpact_nshc1 {
2374+ struct ofpact ofpact;
2375+ ovs_be32 nshc1;
2376+};
2377+
2378+/* OFPACT_SET_NSH_C2.
2379+ * Used for NXAST_SET_NSH_C2 */
2380+struct ofpact_nshc2 {
2381+ struct ofpact ofpact;
2382+ ovs_be32 nshc2;
2383+};
2384+
2385+/* OFPACT_SET_NSH_C3.
2386+ * Used for NXAST_SET_NSH_C3 */
2387+struct ofpact_nshc3 {
2388+ struct ofpact ofpact;
2389+ ovs_be32 nshc3;
2390+};
2391+
2392+/* OFPACT_SET_NSH_C4.
2393+ * Used for NXAST_SET_NSH_C4 */
2394+struct ofpact_nshc4 {
2395+ struct ofpact ofpact;
2396+ ovs_be32 nshc4;
2397+};
2398+
2399 /* OFPACT_SET_QUEUE.
2400 *
2401 * Used for NXAST_SET_QUEUE. */
2402diff --git a/lib/ofp-parse.c b/lib/ofp-parse.c
2403index 5950f06..099d3df 100644
2404--- a/lib/ofp-parse.c
2405+++ b/lib/ofp-parse.c
2406@@ -139,6 +139,19 @@ str_to_be64(const char *str, ovs_be64 *valuep)
2407 return error;
2408 }
2409
2410+char * OVS_WARN_UNUSED_RESULT
2411+str_to_be32(const char *str, ovs_be32 *valuep)
2412+{
2413+ uint32_t value = 0;
2414+ char *error;
2415+
2416+ error = str_to_u32(str, &value);
2417+ if (!error) {
2418+ *valuep = htonl(value);
2419+ }
2420+ return error;
2421+}
2422+
2423 /* Parses 'str' as an Ethernet address into 'mac'.
2424 *
2425 * Returns NULL if successful, otherwise a malloc()'d string describing the
2426diff --git a/lib/ofp-parse.h b/lib/ofp-parse.h
2427index b64a32e..47d385b 100644
2428--- a/lib/ofp-parse.h
2429+++ b/lib/ofp-parse.h
2430@@ -98,6 +98,7 @@ char *str_to_u32(const char *str, uint32_t *valuep) OVS_WARN_UNUSED_RESULT;
2431 char *str_to_u64(const char *str, uint64_t *valuep) OVS_WARN_UNUSED_RESULT;
2432 char *str_to_be64(const char *str, ovs_be64 *valuep) OVS_WARN_UNUSED_RESULT;
2433 char *str_to_mac(const char *str, struct eth_addr *mac) OVS_WARN_UNUSED_RESULT;
2434+char *str_to_be32(const char *str, ovs_be32 *valuep) OVS_WARN_UNUSED_RESULT;
2435 char *str_to_ip(const char *str, ovs_be32 *ip) OVS_WARN_UNUSED_RESULT;
2436
2437 #endif /* ofp-parse.h */
2438diff --git a/lib/packets.h b/lib/packets.h
2439index 4fb1427..12f2239 100644
2440--- a/lib/packets.h
2441+++ b/lib/packets.h
2442@@ -45,7 +45,12 @@ struct flow_tnl {
2443 ovs_be16 tp_dst;
2444 ovs_be16 gbp_id;
2445 uint8_t gbp_flags;
2446- uint8_t pad1[5]; /* Pad to 64 bits. */
2447+ uint8_t nsi;
2448+ ovs_be32 nsp;
2449+ ovs_be32 nshc1;
2450+ ovs_be32 nshc2;
2451+ ovs_be32 nshc3;
2452+ ovs_be32 nshc4;
2453 struct tun_metadata metadata;
2454 };
2455
2456@@ -69,6 +74,12 @@ struct flow_tnl {
2457
2458 /* Tunnel information is in userspace datapath format. */
2459 #define FLOW_TNL_F_UDPIF (1 << 4)
2460+#define FLOW_TNL_F_NSP (1 << 5)
2461+#define FLOW_TNL_F_NSI (1 << 6)
2462+#define FLOW_TNL_F_NSH_C1 (1 << 7)
2463+#define FLOW_TNL_F_NSH_C2 (1 << 8)
2464+#define FLOW_TNL_F_NSH_C3 (1 << 9)
2465+#define FLOW_TNL_F_NSH_C4 (1 << 10)
2466
2467 /* Returns an offset to 'src' covering all the meaningful fields in 'src'. */
2468 static inline size_t
2469@@ -899,6 +910,9 @@ struct vxlanhdr {
2470 ovs_16aligned_be32 vx_vni;
2471 };
2472
2473+/* VXLAN GPE UDP DST PORT */
2474+#define VXGPE_DST_PORT 4790
2475+
2476 #define VXLAN_FLAGS 0x08000000 /* struct vxlanhdr.vx_flags required value. */
2477
2478 void format_ipv6_addr(char *addr_str, const struct in6_addr *addr);
2479diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c
2480index 4ed73a3..4bb9801 100644
2481--- a/ofproto/ofproto-dpif-xlate.c
2482+++ b/ofproto/ofproto-dpif-xlate.c
2483@@ -4032,7 +4032,6 @@ recirc_put_unroll_xlate(struct xlate_ctx *ctx)
2484 }
2485 }
2486
2487-
2488 /* Copy remaining actions to the action_set to be executed after recirculation.
2489 * UNROLL_XLATE action is inserted, if not already done so, before actions that
2490 * may generate PACKET_INs from the current table and without matching another
2491@@ -4096,6 +4095,12 @@ recirc_unroll_actions(const struct ofpact *ofpacts, size_t ofpacts_len,
2492 case OFPACT_METER:
2493 case OFPACT_SAMPLE:
2494 case OFPACT_DEBUG_RECIRC:
2495+ case OFPACT_SET_NSP:
2496+ case OFPACT_SET_NSI:
2497+ case OFPACT_SET_NSH_C1:
2498+ case OFPACT_SET_NSH_C2:
2499+ case OFPACT_SET_NSH_C3:
2500+ case OFPACT_SET_NSH_C4:
2501 break;
2502
2503 /* These need not be copied for restoration. */
2504@@ -4284,6 +4289,30 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len,
2505 flow->tunnel.tun_id = htonll(ofpact_get_SET_TUNNEL(a)->tun_id);
2506 break;
2507
2508+ case OFPACT_SET_NSP:
2509+ flow->tunnel.nsp = ofpact_get_SET_NSP(a)->nsp;
2510+ break;
2511+
2512+ case OFPACT_SET_NSI:
2513+ flow->tunnel.nsi = ofpact_get_SET_NSI(a)->nsi;
2514+ break;
2515+
2516+ case OFPACT_SET_NSH_C1:
2517+ flow->tunnel.nshc1 = ofpact_get_SET_NSH_C1(a)->nshc1;
2518+ break;
2519+
2520+ case OFPACT_SET_NSH_C2:
2521+ flow->tunnel.nshc2 = ofpact_get_SET_NSH_C2(a)->nshc2;
2522+ break;
2523+
2524+ case OFPACT_SET_NSH_C3:
2525+ flow->tunnel.nshc3 = ofpact_get_SET_NSH_C3(a)->nshc3;
2526+ break;
2527+
2528+ case OFPACT_SET_NSH_C4:
2529+ flow->tunnel.nshc4 = ofpact_get_SET_NSH_C4(a)->nshc4;
2530+ break;
2531+
2532 case OFPACT_SET_QUEUE:
2533 memset(&wc->masks.skb_priority, 0xff,
2534 sizeof wc->masks.skb_priority);
2535diff --git a/ofproto/tunnel.c b/ofproto/tunnel.c
2536index b85c2b5..52e28fb 100644
2537--- a/ofproto/tunnel.c
2538+++ b/ofproto/tunnel.c
2539@@ -47,13 +47,25 @@ VLOG_DEFINE_THIS_MODULE(tunnel);
2540
2541 struct tnl_match {
2542 ovs_be64 in_key;
2543+ ovs_be32 in_nsp;
2544+ ovs_be32 in_nshc1;
2545+ ovs_be32 in_nshc2;
2546+ ovs_be32 in_nshc3;
2547+ ovs_be32 in_nshc4;
2548 ovs_be32 ip_src;
2549 ovs_be32 ip_dst;
2550 odp_port_t odp_port;
2551 uint32_t pkt_mark;
2552+ uint8_t in_nsi;
2553 bool in_key_flow;
2554+ bool in_nsp_flow;
2555+ bool in_nshc1_flow;
2556+ bool in_nshc2_flow;
2557+ bool in_nshc3_flow;
2558+ bool in_nshc4_flow;
2559 bool ip_src_flow;
2560 bool ip_dst_flow;
2561+ bool in_nsi_flow;
2562 };
2563
2564 struct tnl_port {
2565@@ -85,17 +97,41 @@ static struct fat_rwlock rwlock;
2566 * (ip_dst_flow == false) or arrange for the destination IP to be matched
2567 * as tunnel.ip_dst in the OpenFlow flow (ip_dst_flow == true).
2568 *
2569+ * - in_nsp: A vport may match a specific NSH service path (in_nsp_flow ==
2570+ * false) or arrange for the service path to be matched as tunnel.in_nsp
2571+ * in the OpenFlow flow (in_nsp_flow == true).
2572+ *
2573+ * - in_nsi: A vport may match a specific NSH service index (in_nsi_flow ==
2574+ * false) or arrange for the service index to be matched as tunnel.in_nsi
2575+ * in the OpenFlow flow (in_nsi_flow == true).
2576+ *
2577+ * - in_nshc1: A vport may match a specific NSH_C1 (in_nshc1_flow ==
2578+ * false) or arrange for the NSH_C1 to be matched as tunnel.in_nshc1
2579+ * in the OpenFlow flow (in_nshc1_flow == true).
2580+ *
2581+ * - in_nshc2: A vport may match a specific NSH_C2 (in_nshc1_flow ==
2582+ * false) or arrange for the NSH_C2 to be matched as tunnel.in_nshc2
2583+ * in the OpenFlow flow (in_nshc2_flow == true).
2584+ *
2585+ * - in_nshc3: A vport may match a specific NSH_C3 (in_nshc1_flow ==
2586+ * false) or arrange for the NSH_C3 to be matched as tunnel.in_nshc3
2587+ * in the OpenFlow flow (in_nshc3_flow == true).
2588+ *
2589+ * - in_nshc4: A vport may match a specific NSH_C4 (in_nshc1_flow ==
2590+ * false) or arrange for the NSH_C4 to be matched as tunnel.in_nshc4
2591+ * in the OpenFlow flow (in_nshc4_flow == true).
2592+ *
2593 * - ip_src: A vport may match a specific IP source address (ip_src_flow ==
2594 * false, ip_src != 0), wildcard all source addresses (ip_src_flow ==
2595 * false, ip_src == 0), or arrange for the IP source address to be
2596 * handled in the OpenFlow flow table (ip_src_flow == true).
2597 *
2598- * Thus, there are 2 * 2 * 3 == 12 possible ways a vport can match against a
2599- * tunnel packet. We number the possibilities for each field in increasing
2600- * order as listed in each bullet above. We order the 12 overall combinations
2601- * in lexicographic order considering in_key first, then ip_dst, then
2602- * ip_src. */
2603-#define N_MATCH_TYPES (2 * 2 * 3)
2604+ * Thus, there are 2 * 2 * 2 * 2 * 2 * 2 * 2 * 2 * 3 == 768 possible ways a vport can match
2605+ * against a tunnel packet. We number the possibilities for each field in
2606+ * increasing order as listed in each bullet above. We order the 768 overall
2607+ * combinations in lexicographic order considering in_key first, then ip_dst,
2608+ * then in_nsp, then in_nsi, then ip_src. */
2609+#define N_MATCH_TYPES (2 * 2 * 2 * 2 * 2 * 2 * 2 * 2 * 3)
2610
2611 /* The three possibilities (see above) for vport ip_src matches. */
2612 enum ip_src_type {
2613@@ -110,6 +146,10 @@ enum ip_src_type {
2614 static struct hmap *tnl_match_maps[N_MATCH_TYPES] OVS_GUARDED_BY(rwlock);
2615 static struct hmap **tnl_match_map(const struct tnl_match *);
2616
2617+static unsigned int tnl_match_m_to_idx(const struct tnl_match *);
2618+static void tnl_match_idx_to_m(const struct flow *, unsigned int,
2619+ struct tnl_match *);
2620+
2621 static struct hmap ofport_map__ = HMAP_INITIALIZER(&ofport_map__);
2622 static struct hmap *ofport_map OVS_GUARDED_BY(rwlock) = &ofport_map__;
2623
2624@@ -121,7 +161,10 @@ static struct tnl_port *tnl_find_exact(struct tnl_match *, struct hmap *)
2625 OVS_REQ_RDLOCK(rwlock);
2626 static struct tnl_port *tnl_find_ofport(const struct ofport_dpif *)
2627 OVS_REQ_RDLOCK(rwlock);
2628-
2629+static struct tnl_port *tnl_find_odp_port(odp_port_t odp_port)
2630+ OVS_REQ_RDLOCK(rwlock);
2631+static struct tnl_port *tnl_find_exact_odp_port(odp_port_t, struct hmap *)
2632+ OVS_REQ_RDLOCK(rwlock);
2633 static uint32_t tnl_hash(struct tnl_match *);
2634 static void tnl_match_fmt(const struct tnl_match *, struct ds *);
2635 static char *tnl_port_fmt(const struct tnl_port *) OVS_REQ_RDLOCK(rwlock);
2636@@ -161,12 +204,24 @@ tnl_port_add__(const struct ofport_dpif *ofport, const struct netdev *netdev,
2637 tnl_port->change_seq = netdev_get_change_seq(tnl_port->netdev);
2638
2639 tnl_port->match.in_key = cfg->in_key;
2640+ tnl_port->match.in_nsp = cfg->in_nsp;
2641+ tnl_port->match.in_nsi = cfg->in_nsi;
2642+ tnl_port->match.in_nshc1 = cfg->in_nshc1;
2643+ tnl_port->match.in_nshc2 = cfg->in_nshc2;
2644+ tnl_port->match.in_nshc3 = cfg->in_nshc3;
2645+ tnl_port->match.in_nshc4 = cfg->in_nshc4;
2646 tnl_port->match.ip_src = cfg->ip_src;
2647 tnl_port->match.ip_dst = cfg->ip_dst;
2648 tnl_port->match.ip_src_flow = cfg->ip_src_flow;
2649 tnl_port->match.ip_dst_flow = cfg->ip_dst_flow;
2650 tnl_port->match.pkt_mark = cfg->ipsec ? IPSEC_MARK : 0;
2651 tnl_port->match.in_key_flow = cfg->in_key_flow;
2652+ tnl_port->match.in_nsp_flow = cfg->in_nsp_flow;
2653+ tnl_port->match.in_nsi_flow = cfg->in_nsi_flow;
2654+ tnl_port->match.in_nshc1_flow = cfg->in_nshc1_flow;
2655+ tnl_port->match.in_nshc2_flow = cfg->in_nshc2_flow;
2656+ tnl_port->match.in_nshc3_flow = cfg->in_nshc3_flow;
2657+ tnl_port->match.in_nshc4_flow = cfg->in_nshc4_flow;
2658 tnl_port->match.odp_port = odp_port;
2659
2660 map = tnl_match_map(&tnl_port->match);
2661@@ -437,6 +492,28 @@ tnl_port_send(const struct ofport_dpif *ofport, struct flow *flow,
2662 flow->tunnel.ip_tos = cfg->tos;
2663 }
2664
2665+ if (!cfg->out_key_flow) {
2666+ flow->tunnel.tun_id = cfg->out_key;
2667+ }
2668+ if (!cfg->out_nsp_flow) {
2669+ flow->tunnel.nsp = cfg->out_nsp;
2670+ }
2671+ if (!cfg->out_nsi_flow) {
2672+ flow->tunnel.nsi = cfg->out_nsi;
2673+ }
2674+ if (!cfg->out_nshc1_flow) {
2675+ flow->tunnel.nshc1 = cfg->out_nshc1;
2676+ }
2677+ if (!cfg->out_nshc2_flow) {
2678+ flow->tunnel.nshc2 = cfg->out_nshc2;
2679+ }
2680+ if (!cfg->out_nshc3_flow) {
2681+ flow->tunnel.nshc3 = cfg->out_nshc3;
2682+ }
2683+ if (!cfg->out_nshc4_flow) {
2684+ flow->tunnel.nshc4 = cfg->out_nshc4;
2685+ }
2686+
2687 /* ECN fields are always inherited. */
2688 if (is_ip_any(flow)) {
2689 wc->masks.nw_tos |= IP_ECN_MASK;
2690@@ -450,6 +527,12 @@ tnl_port_send(const struct ofport_dpif *ofport, struct flow *flow,
2691
2692 flow->tunnel.flags |= (cfg->dont_fragment ? FLOW_TNL_F_DONT_FRAGMENT : 0)
2693 | (cfg->csum ? FLOW_TNL_F_CSUM : 0)
2694+ | (cfg->out_nsp_present ? FLOW_TNL_F_NSP : 0)
2695+ | (cfg->out_nsi_present ? FLOW_TNL_F_NSI : 0)
2696+ | (cfg->out_nshc1_present ? FLOW_TNL_F_NSH_C1 : 0)
2697+ | (cfg->out_nshc2_present ? FLOW_TNL_F_NSH_C2 : 0)
2698+ | (cfg->out_nshc3_present ? FLOW_TNL_F_NSH_C3 : 0)
2699+ | (cfg->out_nshc4_present ? FLOW_TNL_F_NSH_C4 : 0)
2700 | (cfg->out_key_present ? FLOW_TNL_F_KEY : 0);
2701
2702 if (pre_flow_str) {
2703@@ -512,57 +595,122 @@ tnl_find_exact(struct tnl_match *match, struct hmap *map)
2704 static struct tnl_port *
2705 tnl_find(const struct flow *flow) OVS_REQ_RDLOCK(rwlock)
2706 {
2707- enum ip_src_type ip_src;
2708- int in_key_flow;
2709- int ip_dst_flow;
2710- int i;
2711-
2712- i = 0;
2713- for (in_key_flow = 0; in_key_flow < 2; in_key_flow++) {
2714- for (ip_dst_flow = 0; ip_dst_flow < 2; ip_dst_flow++) {
2715- for (ip_src = 0; ip_src < 3; ip_src++) {
2716- struct hmap *map = tnl_match_maps[i];
2717-
2718- if (map) {
2719- struct tnl_port *tnl_port;
2720- struct tnl_match match;
2721-
2722- memset(&match, 0, sizeof match);
2723-
2724- /* The apparent mix-up of 'ip_dst' and 'ip_src' below is
2725- * correct, because "struct tnl_match" is expressed in
2726- * terms of packets being sent out, but we are using it
2727- * here as a description of how to treat received
2728- * packets. */
2729- match.in_key = in_key_flow ? 0 : flow->tunnel.tun_id;
2730- match.ip_src = (ip_src == IP_SRC_CFG
2731- ? flow->tunnel.ip_dst
2732- : 0);
2733- match.ip_dst = ip_dst_flow ? 0 : flow->tunnel.ip_src;
2734- match.odp_port = flow->in_port.odp_port;
2735- match.pkt_mark = flow->pkt_mark;
2736- match.in_key_flow = in_key_flow;
2737- match.ip_dst_flow = ip_dst_flow;
2738- match.ip_src_flow = ip_src == IP_SRC_FLOW;
2739-
2740- tnl_port = tnl_find_exact(&match, map);
2741- if (tnl_port) {
2742- return tnl_port;
2743- }
2744- }
2745-
2746- i++;
2747+ int i;
2748+
2749+ for (i = 0; i < N_MATCH_TYPES; i++) {
2750+ struct hmap *map = tnl_match_maps[i];
2751+
2752+ if (map) {
2753+ struct tnl_port *tnl_port;
2754+ struct tnl_match match;
2755+
2756+ memset(&match, 0, sizeof match);
2757+
2758+ tnl_match_idx_to_m(flow, i, &match);
2759+ tnl_port = tnl_find_exact(&match, map);
2760+ if (tnl_port) {
2761+ return tnl_port;
2762 }
2763 }
2764- }
2765+ }
2766
2767 return NULL;
2768 }
2769
2770-/* Returns a pointer to the 'tnl_match_maps' element corresponding to 'm''s
2771- * matching criteria. */
2772-static struct hmap **
2773-tnl_match_map(const struct tnl_match *m)
2774+/* Coverts a index to corresponding matching criteria 'm'. */
2775+static void
2776+tnl_match_idx_to_m(const struct flow *flow, unsigned int idx,
2777+ struct tnl_match *m)
2778+{
2779+ enum ip_src_type ip_src;
2780+ bool in_key_flow;
2781+ bool ip_dst_flow;
2782+ bool in_nsp_flow;
2783+ bool in_nsi_flow;
2784+ bool in_nshc1_flow;
2785+ bool in_nshc2_flow;
2786+ bool in_nshc3_flow;
2787+ bool in_nshc4_flow;
2788+
2789+ if (!m)
2790+ return;
2791+
2792+ in_key_flow = (idx < (N_MATCH_TYPES / 2)) ? false : true;
2793+
2794+ if (idx >= (N_MATCH_TYPES / 2))
2795+ idx -= (N_MATCH_TYPES / 2);
2796+
2797+ ip_dst_flow = (idx < (N_MATCH_TYPES / (2 * 2))) ? false : true;
2798+
2799+ if (idx >= (N_MATCH_TYPES / (2 * 2)))
2800+ idx -= (N_MATCH_TYPES / (2 * 2));
2801+
2802+ in_nsp_flow = (idx < (N_MATCH_TYPES / (2 * 2 * 2))) ? false : true;
2803+
2804+ if (idx >= (N_MATCH_TYPES / (2 * 2 * 2)))
2805+ idx -= (N_MATCH_TYPES / (2 * 2 * 2));
2806+
2807+ in_nsi_flow = (idx < (N_MATCH_TYPES / (2 * 2 * 2 * 2))) ? false : true;
2808+
2809+ if (idx >= (N_MATCH_TYPES / (2 * 2 * 2 * 2)))
2810+ idx -= (N_MATCH_TYPES / (2 * 2 * 2 * 2));
2811+
2812+ in_nshc1_flow = (idx < (N_MATCH_TYPES / (2 * 2 * 2 * 2 * 2))) ? false : true;
2813+
2814+ if (idx >= (N_MATCH_TYPES / (2 * 2 * 2 * 2 * 2)))
2815+ idx -= (N_MATCH_TYPES / (2 * 2 * 2 * 2 * 2));
2816+
2817+ in_nshc2_flow = (idx < (N_MATCH_TYPES / (2 * 2 * 2 * 2 * 2 * 2))) ? false : true;
2818+
2819+ if (idx >= (N_MATCH_TYPES / (2 * 2 * 2 * 2 * 2 * 2)))
2820+ idx -= (N_MATCH_TYPES / (2 * 2 * 2 * 2 * 2 * 2));
2821+
2822+ in_nshc3_flow = (idx < (N_MATCH_TYPES / (2 * 2 * 2 * 2 * 2 * 2 * 2))) ? false : true;
2823+
2824+ if (idx >= (N_MATCH_TYPES / (2 * 2 * 2 * 2 * 2 * 2 * 2)))
2825+ idx -= (N_MATCH_TYPES / (2 * 2 * 2 * 2 * 2 * 2 * 2));
2826+
2827+ in_nshc4_flow = (idx < (N_MATCH_TYPES / (2 * 2 * 2 * 2 * 2 * 2 * 2 * 2))) ? false : true;
2828+
2829+ if (idx >= (N_MATCH_TYPES / (2 * 2 * 2 * 2 * 2 * 2 * 2 * 2)))
2830+ idx -= (N_MATCH_TYPES / (2 * 2 * 2 * 2 * 2 * 2 * 2 * 2));
2831+
2832+ ip_src = idx;
2833+
2834+ /* The apparent mix-up of 'ip_dst' and 'ip_src' below is
2835+ * correct, because "struct tnl_match" is expressed in
2836+ * terms of packets being sent out, but we are using it
2837+ * here as a description of how to treat received
2838+ * packets. */
2839+ m->in_key = in_key_flow ? 0 : flow->tunnel.tun_id;
2840+ m->ip_src = (ip_src == IP_SRC_CFG
2841+ ? flow->tunnel.ip_dst
2842+ : 0);
2843+ m->in_nsp = in_nsp_flow ? 0 : flow->tunnel.nsp;
2844+ m->in_nsi = in_nsi_flow ? 1 : flow->tunnel.nsi;
2845+ m->in_nshc1 = in_nshc1_flow ? 0 : flow->tunnel.nshc1;
2846+ m->in_nshc2 = in_nshc2_flow ? 0 : flow->tunnel.nshc2;
2847+ m->in_nshc3 = in_nshc3_flow ? 0 : flow->tunnel.nshc3;
2848+ m->in_nshc4 = in_nshc4_flow ? 0 : flow->tunnel.nshc4;
2849+ m->ip_dst = ip_dst_flow ? 0 : flow->tunnel.ip_src;
2850+ m->odp_port = flow->in_port.odp_port;
2851+ m->pkt_mark = flow->pkt_mark;
2852+ m->in_key_flow = in_key_flow;
2853+ m->ip_dst_flow = ip_dst_flow;
2854+ m->in_nsp_flow = in_nsp_flow;
2855+ m->in_nsi_flow = in_nsi_flow;
2856+ m->in_nshc1_flow = in_nshc1_flow;
2857+ m->in_nshc2_flow = in_nshc2_flow;
2858+ m->in_nshc3_flow = in_nshc3_flow;
2859+ m->in_nshc4_flow = in_nshc4_flow;
2860+
2861+ m->ip_src_flow = ip_src == IP_SRC_FLOW;
2862+
2863+}
2864+
2865+/* Returns a index corresponding to 'm''s matching criteria. */
2866+static unsigned int
2867+tnl_match_m_to_idx(const struct tnl_match *m)
2868 {
2869 enum ip_src_type ip_src;
2870
2871@@ -570,7 +718,23 @@ tnl_match_map(const struct tnl_match *m)
2872 : m->ip_src ? IP_SRC_CFG
2873 : IP_SRC_ANY);
2874
2875- return &tnl_match_maps[6 * m->in_key_flow + 3 * m->ip_dst_flow + ip_src];
2876+ return (m->in_key_flow * (N_MATCH_TYPES / 2) +
2877+ m->ip_dst_flow * (N_MATCH_TYPES / (2 * 2)) +
2878+ m->in_nsp_flow * (N_MATCH_TYPES / (2 * 2 * 2)) +
2879+ m->in_nsi_flow * (N_MATCH_TYPES / (2 * 2 * 2 * 2)) +
2880+ m->in_nshc1_flow * (N_MATCH_TYPES / (2 * 2 * 2 * 2 * 2)) +
2881+ m->in_nshc2_flow * (N_MATCH_TYPES / (2 * 2 * 2 * 2 * 2 * 2)) +
2882+ m->in_nshc3_flow * (N_MATCH_TYPES / (2 * 2 * 2 * 2 * 2 * 2 * 2)) +
2883+ m->in_nshc4_flow * (N_MATCH_TYPES / (2 * 2 * 2 * 2 * 2 * 2 * 2 * 2)) +
2884+ ip_src);
2885+}
2886+
2887+/* Returns a pointer to the 'tnl_match_maps' element corresponding to 'm''s
2888+ * matching criteria. */
2889+static struct hmap **
2890+tnl_match_map(const struct tnl_match *m)
2891+{
2892+ return &tnl_match_maps[tnl_match_m_to_idx(m)];
2893 }
2894
2895 static void
2896@@ -592,6 +756,37 @@ tnl_match_fmt(const struct tnl_match *match, struct ds *ds)
2897 ds_put_format(ds, ", key=%#"PRIx64, ntohll(match->in_key));
2898 }
2899
2900+ if (match->in_nsp_flow) {
2901+ ds_put_cstr(ds, ", nsp=flow");
2902+ } else {
2903+ ds_put_format(ds, ", nsp=%#"PRIx32, ntohl(match->in_nsp));
2904+ }
2905+ if (match->in_nsi_flow) {
2906+ ds_put_cstr(ds, ", nsi=flow");
2907+ } else {
2908+ ds_put_format(ds, ", nsi=%"PRIu8, match->in_nsi);
2909+ }
2910+ if (match->in_nshc1_flow) {
2911+ ds_put_cstr(ds, ", nshc1=flow");
2912+ } else {
2913+ ds_put_format(ds, ", nshc1=%#"PRIx32, ntohl(match->in_nshc1));
2914+ }
2915+ if (match->in_nshc2_flow) {
2916+ ds_put_cstr(ds, ", nshc2=flow");
2917+ } else {
2918+ ds_put_format(ds, ", nshc2=%#"PRIx32, ntohl(match->in_nshc2));
2919+ }
2920+ if (match->in_nshc3_flow) {
2921+ ds_put_cstr(ds, ", nshc3=flow");
2922+ } else {
2923+ ds_put_format(ds, ", nshc3=%#"PRIx32, ntohl(match->in_nshc3));
2924+ }
2925+ if (match->in_nshc4_flow) {
2926+ ds_put_cstr(ds, ", nshc4=flow");
2927+ } else {
2928+ ds_put_format(ds, ", nshc4=%#"PRIx32, ntohl(match->in_nshc4));
2929+ }
2930+
2931 ds_put_format(ds, ", dp port=%"PRIu32, match->odp_port);
2932 ds_put_format(ds, ", pkt mark=%"PRIu32, match->pkt_mark);
2933 }
2934@@ -635,6 +830,79 @@ tnl_port_fmt(const struct tnl_port *tnl_port) OVS_REQ_RDLOCK(rwlock)
2935 }
2936 }
2937
2938+ if (cfg->out_nsp != cfg->in_nsp ||
2939+ cfg->out_nsp_present != cfg->in_nsp_present ||
2940+ cfg->out_nsp_flow != cfg->in_nsp_flow) {
2941+ ds_put_cstr(&ds, ", out_nsp=");
2942+ if (!cfg->out_nsp_present) {
2943+ ds_put_cstr(&ds, "none");
2944+ } else if (cfg->out_nsp_flow) {
2945+ ds_put_cstr(&ds, "flow");
2946+ } else {
2947+ ds_put_format(&ds, "%#"PRIx32, ntohl(cfg->out_nsp));
2948+ }
2949+ }
2950+ if (cfg->out_nsi != cfg->in_nsi ||
2951+ cfg->out_nsi_present != cfg->in_nsi_present ||
2952+ cfg->out_nsi_flow != cfg->in_nsi_flow) {
2953+ ds_put_cstr(&ds, ", out_nsi=");
2954+ if (!cfg->out_nsi_present) {
2955+ ds_put_cstr(&ds, "none");
2956+ } else if (cfg->out_nsi_flow) {
2957+ ds_put_cstr(&ds, "flow");
2958+ } else {
2959+ ds_put_format(&ds, "%"PRIu8, cfg->out_nsi);
2960+ }
2961+ }
2962+ if (cfg->out_nshc1 != cfg->in_nshc1 ||
2963+ cfg->out_nshc1_present != cfg->in_nshc1_present ||
2964+ cfg->out_nshc1_flow != cfg->in_nshc1_flow) {
2965+ ds_put_cstr(&ds, ", out_nshc1=");
2966+ if (!cfg->out_nshc1_present) {
2967+ ds_put_cstr(&ds, "none");
2968+ } else if (cfg->out_nshc1_flow) {
2969+ ds_put_cstr(&ds, "flow");
2970+ } else {
2971+ ds_put_format(&ds, "%#"PRIx32, ntohl(cfg->out_nshc1));
2972+ }
2973+ }
2974+ if (cfg->out_nshc2 != cfg->in_nshc2 ||
2975+ cfg->out_nshc2_present != cfg->in_nshc2_present ||
2976+ cfg->out_nshc2_flow != cfg->in_nshc2_flow) {
2977+ ds_put_cstr(&ds, ", out_nshc2=");
2978+ if (!cfg->out_nshc2_present) {
2979+ ds_put_cstr(&ds, "none");
2980+ } else if (cfg->out_nshc2_flow) {
2981+ ds_put_cstr(&ds, "flow");
2982+ } else {
2983+ ds_put_format(&ds, "%#"PRIx32, ntohl(cfg->out_nshc2));
2984+ }
2985+ }
2986+ if (cfg->out_nshc3 != cfg->in_nshc3 ||
2987+ cfg->out_nshc3_present != cfg->in_nshc3_present ||
2988+ cfg->out_nshc3_flow != cfg->in_nshc3_flow) {
2989+ ds_put_cstr(&ds, ", out_nshc3=");
2990+ if (!cfg->out_nshc3_present) {
2991+ ds_put_cstr(&ds, "none");
2992+ } else if (cfg->out_nshc3_flow) {
2993+ ds_put_cstr(&ds, "flow");
2994+ } else {
2995+ ds_put_format(&ds, "%#"PRIx32, ntohl(cfg->out_nshc3));
2996+ }
2997+ }
2998+ if (cfg->out_nshc4 != cfg->in_nshc4 ||
2999+ cfg->out_nshc4_present != cfg->in_nshc4_present ||
3000+ cfg->out_nshc4_flow != cfg->in_nshc4_flow) {
3001+ ds_put_cstr(&ds, ", out_nshc4=");
3002+ if (!cfg->out_nshc4_present) {
3003+ ds_put_cstr(&ds, "none");
3004+ } else if (cfg->out_nshc4_flow) {
3005+ ds_put_cstr(&ds, "flow");
3006+ } else {
3007+ ds_put_format(&ds, "%#"PRIx32, ntohl(cfg->out_nshc4));
3008+ }
3009+ }
3010+
3011 if (cfg->ttl_inherit) {
3012 ds_put_cstr(&ds, ", ttl=inherit");
3013 } else {
3014diff --git a/ofproto/tunnel.h b/ofproto/tunnel.h
3015index 3bb76c5..3e704fb 100644
3016--- a/ofproto/tunnel.h
3017+++ b/ofproto/tunnel.h
3018@@ -55,5 +55,4 @@ int tnl_port_build_header(const struct ofport_dpif *ofport,
3019 const struct eth_addr dmac,
3020 const struct eth_addr smac,
3021 ovs_be32 ip_src, struct ovs_action_push_tnl *data);
3022-
3023 #endif /* tunnel.h */
3024diff --git a/tests/ofproto.at b/tests/ofproto.at
3025index c012a34..fc19b10 100644
3026--- a/tests/ofproto.at
3027+++ b/tests/ofproto.at
3028@@ -1531,7 +1531,7 @@ head_table () {
3029 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
3030 supported on Set-Field: tun_id tun_src tun_dst tun_flags tun_gbp_id tun_gbp_flags tun_metadata0 dnl
3031 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
3032-metadata in_port in_port_oxm pkt_mark 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 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 nd_target nd_sll nd_tll
3033+metadata in_port in_port_oxm pkt_mark 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 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 nd_target nd_sll nd_tll nsp nsi nshc1 nshc2 nshc3 nshc4
3034 matching:
3035 dp_hash: arbitrary mask
3036 recirc_id: exact match or wildcard
3037@@ -1662,6 +1662,12 @@ metadata in_port in_port_oxm pkt_mark reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 xr
3038 nd_target: arbitrary mask
3039 nd_sll: arbitrary mask
3040 nd_tll: arbitrary mask
3041+ nsp: arbitrary mask
3042+ nsi: arbitrary mask
3043+ nshc1: arbitrary mask
3044+ nshc2: arbitrary mask
3045+ nshc3: arbitrary mask
3046+ nshc4: arbitrary mask
3047
3048 ' $1
3049 }
3050@@ -4068,7 +4074,7 @@ vconn|DBG|unix: negotiated OpenFlow version 0x01 (we support version 0x06 and ea
3051 vconn|DBG|unix: received: NXT_SET_FLOW_FORMAT: format=nxm
3052 vconn|DBG|unix: received: OFPT_BARRIER_REQUEST:
3053 vconn|DBG|unix: sent (Success): OFPT_BARRIER_REPLY:
3054-vconn|DBG|unix: received: NXST_FLOW request:
3055+vconn|DBG|unix: received: NXST_FLOW request:
3056 vconn|DBG|unix: sent (Success): NXST_FLOW reply:
3057 idle_timeout=60, in_port=2,dl_src=00:77:88:99:aa:bb actions=output:8
3058 in_port=2,dl_src=00:66:77:88:99:aa actions=drop
3059diff --git a/tests/tunnel.at b/tests/tunnel.at
3060index f277f27..f43a07d 100644
3061--- a/tests/tunnel.at
3062+++ b/tests/tunnel.at
3063@@ -412,6 +412,121 @@ AT_CHECK([tail -1 stdout], [0],
3064 OVS_VSWITCHD_STOP
3065 AT_CLEANUP
3066
3067+AT_SETUP([tunnel - VXLAN-GPE NSH kernel space])
3068+OVS_VSWITCHD_START([add-port br0 p1 -- set Interface p1 type=vxlan \
3069+ options:remote_ip=1.1.1.1 ofport_request=1 options:dst_port=4790])
3070+
3071+AT_CHECK([ovs-appctl dpif/show | tail -n +3], [0], [dnl
3072+ br0 65534/100: (dummy)
3073+ p1 1/4790: (vxlan: dst_port=4790, remote_ip=1.1.1.1)
3074+])
3075+OVS_VSWITCHD_STOP
3076+AT_CLEANUP
3077+
3078+AT_SETUP([tunnel VXLAN-GPE NSH - encap - nsh/nsi/nshc kernel space])
3079+OVS_VSWITCHD_START([dnl
3080+ add-port br0 p1 -- set Interface p1 type=vxlan options:key=flow \
3081+ options:remote_ip=1.1.1.1 options:dst_port=4790 ofport_request=1 \
3082+ -- add-port br0 p2 -- set Interface p2 type=vxlan options:key=flow \
3083+ options:remote_ip=flow options:dst_port=4790 ofport_request=2 \
3084+ -- add-port br0 p3 -- set Interface p3 type=vxlan options:key=flow \
3085+ 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 \
3086+ -- add-port br0 p4 -- set Interface p4 type=vxlan options:key=flow \
3087+ 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 \
3088+ -- add-port br0 p5 -- set Interface p5 type=vxlan options:key=flow \
3089+ 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 \
3090+ -- add-port br0 p6 -- set Interface p6 type=vxlan options:key=flow \
3091+ 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])
3092+
3093+OVS_VSWITCHD_DISABLE_TUNNEL_PUSH_POP
3094+ADD_OF_PORTS([br0], [90])
3095+AT_DATA([flows.txt], [dnl
3096+in_port=90 actions=resubmit:1,resubmit:2,resubmit:3,resubmit:4,resubmit:5
3097+in_port=1 actions=set_field:42->tun_id,output:1
3098+in_port=2 actions=set_field:3.3.3.3->tun_dst,output:2
3099+in_port=3 actions=output:3
3100+in_port=4 actions=set_nshc1:22,set_nshc2:23,set_nshc3:24,set_nshc4:25,output:4
3101+in_port=5 actions=set_nsp:333,set_nsi:33,set_nshc1:33,set_nshc2:34,set_nshc3:35,set_nshc4:36,output:5
3102+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
3103+])
3104+AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
3105+AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(90),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])
3106+AT_CHECK([tail -1 stdout], [0],
3107+ [Datapath actions: set(tunnel(tun_id=0x2a,dst=1.1.1.1,ttl=64,nsi=1,flags(df|key|nsi))),4790,set(tunnel(tun_id=0x2a,dst=3.3.3.3,ttl=64,nsi=1,flags(df|key|nsi))),4790,set(tunnel(tun_id=0x2a,dst=2.2.2.2,ttl=64,nsp=6f,nsi=11,nshc1=b,nshc2=c,nshc3=d,nshc4=e,flags(df|key|nsp|nsi|nshc1|nshc2|nshc3|nshc4))),4790,set(tunnel(tun_id=0x2a,dst=3.3.3.3,ttl=64,nsp=de,nsi=22,nshc1=16,nshc2=17,nshc3=18,nshc4=19,flags(df|key|nsp|nsi|nshc1|nshc2|nshc3|nshc4))),4790,set(tunnel(tun_id=0x2a,dst=4.4.4.4,ttl=64,nsp=14d,nsi=33,nshc1=21,nshc2=22,nshc3=23,nshc4=24,flags(df|key|nsp|nsi|nshc1|nshc2|nshc3|nshc4))),4790
3108+])
3109+OVS_VSWITCHD_STOP
3110+AT_CLEANUP
3111+
3112+AT_SETUP([tunnel - VXLAN-GPE NSH decap - decap-encap - remote_ip nsp nsi nshc* kernel space])
3113+OVS_VSWITCHD_START([add-port br0 p1 -- set Interface p1 type=vxlan options:key=flow \
3114+ options:remote_ip=1.1.1.1 options:dst_port=4790 ofport_request=1 \
3115+ -- add-port br0 p2 -- set Interface p2 type=vxlan options:key=flow \
3116+ 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=2 \
3117+ -- add-port br0 p3 -- set Interface p3 type=vxlan options:key=flow \
3118+ options:remote_ip=3.3.3.3 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 \
3119+ -- add-port br0 p4 -- set Interface p4 type=vxlan options:key=flow \
3120+ options:remote_ip=4.4.4.4 options:dst_port=4790 options:in_nsp=221 options:out_nsp=flow options:in_nsi=3 options:out_nsi=flow options:nshc1=flow options:nshc2=flow options:nshc3=flow options:nshc4=flow ofport_request=4 \
3121+ -- add-port br0 p5 -- set Interface p5 type=vxlan options:key=flow \
3122+ 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=5])
3123+AT_DATA([flows.txt], [dnl
3124+priority=16,in_port=1,actions=IN_PORT
3125+priority=16,in_port=2,actions=IN_PORT
3126+priority=16,in_port=3,actions=set_nsp:111,set_nsi=11,set_nshc1:22,set_nshc2:23,set_nshc3:24,set_nshc4:25,IN_PORT
3127+priority=16,in_port=4,actions=set_nsp:222,set_nsi=22,set_nshc1:32,set_nshc2:33,set_nshc3:34,set_nshc4:35,IN_PORT
3128+priority=16,in_port=5,nsp=311,nsi=31,actions=set_nsp:322,set_nsi=33,set_nshc1:42,set_nshc2:43,set_nshc3:44,set_nshc4:45,set_field:6.6.6.6->tun_dst,IN_PORT
3129+])
3130+OVS_VSWITCHD_DISABLE_TUNNEL_PUSH_POP
3131+
3132+AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
3133+
3134+AT_CHECK([ovs-appctl dpif/show | tail -n +3], [0], [dnl
3135+ br0 65534/100: (dummy)
3136+ p1 1/4790: (vxlan: dst_port=4790, key=flow, remote_ip=1.1.1.1)
3137+ p2 2/4790: (vxlan: dst_port=4790, key=flow, nshc1=0xb, nshc2=0xc, nshc3=0xd, nshc4=0xe, nsi=11, nsp=0x6f, remote_ip=2.2.2.2)
3138+ p3 3/4790: (vxlan: dst_port=4790, key=flow, nshc1=flow, nshc2=flow, nshc3=flow, nshc4=flow, nsi=flow, nsp=flow, remote_ip=3.3.3.3)
3139+ p4 4/4790: (vxlan: dst_port=4790, in_nsi=3, in_nsp=0xdd, key=flow, nshc1=flow, nshc2=flow, nshc3=flow, nshc4=flow, out_nsi=flow, out_nsp=flow, remote_ip=4.4.4.4)
3140+ p5 5/4790: (vxlan: dst_port=4790, key=flow, nshc1=flow, nshc2=flow, nshc3=flow, nshc4=flow, nsi=flow, nsp=flow, remote_ip=flow)
3141+])
3142+
3143+dnl remote_ip p1
3144+AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'tunnel(src=1.1.1.1,dst=1.2.3.4,nsi=1,ttl=64,flags()),in_port(4790),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=6,tos=0,ttl=64,frag=no),tcp(src=8,dst=9)'], [0], [stdout])
3145+AT_CHECK([tail -1 stdout], [0],
3146+ [Datapath actions: set(tunnel(tun_id=0x0,dst=1.1.1.1,ttl=64,nsi=1,flags(df|key|nsi))),4790
3147+])
3148+
3149+dnl remote_ip nsp nsi nshc* p2
3150+AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'tunnel(src=2.2.2.2,dst=1.2.3.4,nsi=11,nsp=111,nshc1=11,nshc2=12,nshc3=13,nshc4=14,ttl=64,flags()),in_port(4790),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=6,tos=0,ttl=64,frag=no),tcp(src=8,dst=9)'], [0], [stdout])
3151+AT_CHECK([tail -1 stdout], [0],
3152+ [Datapath actions: set(tunnel(tun_id=0x0,dst=2.2.2.2,ttl=64,nsp=6f,nsi=11,nshc1=b,nshc2=c,nshc3=d,nshc4=e,flags(df|key|nsp|nsi|nshc1|nshc2|nshc3|nshc4))),4790
3153+])
3154+
3155+dnl remote_ip nsp=flow nsi=flow nshc*=flow p3
3156+AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'tunnel(src=3.3.3.3,dst=1.2.3.4,ttl=64,flags()),in_port(4790),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=6,tos=0,ttl=64,frag=no),tcp(src=8,dst=9)'], [0], [stdout])
3157+AT_CHECK([tail -1 stdout], [0],
3158+ [Datapath actions: set(tunnel(tun_id=0x0,dst=3.3.3.3,ttl=64,nsp=6f,nsi=11,nshc1=16,nshc2=17,nshc3=18,nshc4=19,flags(df|key|nsp|nsi|nshc1|nshc2|nshc3|nshc4))),4790
3159+])
3160+
3161+dnl remote_ip nshc*=flow p4
3162+AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'tunnel(src=4.4.4.4,dst=1.2.3.4,nsp=221,nsi=3,ttl=64,flags()),in_port(4790),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=6,tos=0,ttl=64,frag=no),tcp(src=8,dst=9)'], [0], [stdout])
3163+AT_CHECK([tail -1 stdout], [0],
3164+ [Datapath actions: set(tunnel(tun_id=0x0,dst=4.4.4.4,ttl=64,nsp=de,nsi=22,nshc1=20,nshc2=21,nshc3=22,nshc4=23,flags(df|key|nsp|nsi|nshc1|nshc2|nshc3|nshc4))),4790
3165+])
3166+
3167+dnl remote_ip nshc*=flow p4 not matched
3168+AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'tunnel(src=4.4.4.4,dst=1.2.3.4,nsp=223,nsi=3,ttl=64,flags()),in_port(4790),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=6,tos=0,ttl=64,frag=no),tcp(src=8,dst=9)'], [0], [stdout])
3169+AT_CHECK([tail -1 stdout], [0],
3170+ [Datapath actions: drop
3171+])
3172+
3173+dnl remote_ip remote_ip=flow nsp=flow nsi=flow nshc*=flow p5
3174+AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'tunnel(src=5.5.5.5,dst=1.2.3.4,nsp=311,nsi=31,ttl=64,flags()),in_port(4790),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=6,tos=0,ttl=64,frag=no),tcp(src=8,dst=9)'], [0], [stdout])
3175+AT_CHECK([tail -1 stdout], [0],
3176+ [Datapath actions: set(tunnel(tun_id=0x0,dst=6.6.6.6,ttl=64,nsp=142,nsi=33,nshc1=2a,nshc2=2b,nshc3=2c,nshc4=2d,flags(df|key|nsp|nsi|nshc1|nshc2|nshc3|nshc4))),4790
3177+])
3178+
3179+OVS_VSWITCHD_STOP(["/receive tunnel port not found/d"])
3180+AT_CLEANUP
3181+
3182 AT_SETUP([tunnel - Geneve metadata])
3183 OVS_VSWITCHD_START([add-port br0 p1 -- set Interface p1 type=geneve \
3184 options:remote_ip=1.1.1.1 ofport_request=1 \
3185--
31861.9.3
3187
diff --git a/ovs-nsh/patches/060680.patch b/ovs-nsh/patches/060680.patch
deleted file mode 100644
index 538d2df..0000000
--- a/ovs-nsh/patches/060680.patch
+++ /dev/null
@@ -1,788 +0,0 @@
1at data plane level in user space and modify the related codes at control plane
2level in user space.
3
4The design is based on basic VxLAN impletation. When packets are received at
5data plane level in user space, function 'dp_netdev_input' will be called for
6processing the packets at data plane level in user space.
7
8When VXLAN-GPE NSH packets are received, decapsulation will be implemented. For
9the first time, the packets are sent to control plane by function 'upcall_cb',
10and tunnel port will be lookuped by matching the UDP port which is 4790 for
11VxLAN-GPE NSH port, if VxLAN-GPE NSH tunnel port are matched
12successfully, the tunnel pop action will be appended and implemented at data
13plane level, and the NSH related field will be parsed, then packets will be
14reprocessed by function 'dp_netdev_input'.
15
16When original packets are sent to VxLAN-GPE NSH port, the encapsulation will
17be implemented. For the first time, in the control plane the tunnel
18tunnel_push_data are built according to VxLAN-GPE NSH port configuration and
19related rules, then the tunnel push actions are appended and implemented at
20data plane level. Finally packets will be reprocessed by function
21'dp_netdev_input'.
22
23Signed-off-by: Ricky Li <<A HREF="http://openvswitch.org/mailman/listinfo/dev">ricky.li at intel.com</A>>
24Signed-off-by: Mengke Liu <<A HREF="http://openvswitch.org/mailman/listinfo/dev">mengke.liu at intel.com</A>>
25---
26 lib/netdev-vport.c | 166 +++++++++++++++++++++++++++++++++++-----
27 lib/odp-util.c | 175 ++++++++++++++++++++++++++++++-------------
28 lib/packets.h | 115 +++++++++++++++++++++++++++-
29 ofproto/ofproto-dpif-xlate.c | 1 -
30 tests/tunnel.at | 118 +++++++++++++++++++++++++++++
31 5 files changed, 500 insertions(+), 75 deletions(-)
32
33diff --git a/lib/netdev-vport.c b/lib/netdev-vport.c
34index 3f85386..a0a4da2 100644
35--- a/lib/netdev-vport.c
36+++ b/lib/netdev-vport.c
37@@ -67,6 +67,12 @@ static struct vlog_rate_limit err_rl = VLOG_RATE_LIMIT_INIT(60, 5);
38 sizeof(struct udp_header) + \
39 sizeof(struct genevehdr))
40
41+#define VXNSH_HLEN (sizeof(struct eth_header) + \
42+ sizeof(struct ip_header) + \
43+ sizeof(struct udp_header) + \
44+ sizeof(struct vxgpehdr) + \
45+ sizeof(struct nshhdr))
46+
47 #define DEFAULT_TTL 64
48
49 struct netdev_vport {
50@@ -1462,29 +1468,69 @@ netdev_vxlan_pop_header(struct dp_packet *packet)
51 {
52 struct pkt_metadata *md = &packet->md;
53 struct flow_tnl *tnl = &md->tunnel;
54- struct vxlanhdr *vxh;
55+ struct udp_header *udp;
56
57 pkt_metadata_init_tnl(md);
58 if (VXLAN_HLEN > dp_packet_size(packet)) {
59 return EINVAL;
60 }
61
62- vxh = udp_extract_tnl_md(packet, tnl);
63- if (!vxh) {
64- return EINVAL;
65+ udp = ip_extract_tnl_md(packet, tnl);
66+ if (!udp) {
67+ return EINVAL;;
68 }
69
70- if (get_16aligned_be32(&vxh->vx_flags) != htonl(VXLAN_FLAGS) ||
71- (get_16aligned_be32(&vxh->vx_vni) & htonl(0xff))) {
72- VLOG_WARN_RL(&err_rl, "invalid vxlan flags=%#x vni=%#x\n",
73- ntohl(get_16aligned_be32(&vxh->vx_flags)),
74- ntohl(get_16aligned_be32(&vxh->vx_vni)));
75- return EINVAL;
76- }
77- tnl->tun_id = htonll(ntohl(get_16aligned_be32(&vxh->vx_vni)) >> 8);
78- tnl->flags |= FLOW_TNL_F_KEY;
79+ if (ntohs(udp->udp_dst) == VXGPE_DST_PORT) {
80+
81+ struct vxgpehdr *vxg = (struct vxgpehdr *) (udp + 1);
82+
83+ if (get_16aligned_be32(&vxg->vx_vni) & htonl(0xff)) {
84+ VLOG_WARN_RL(&err_rl, "invalid vxlan-gpe vni=%#x\n",
85+ ntohl(get_16aligned_be32(&vxg->vx_vni)));
86+ return EINVAL;;
87+ }
88+
89+ tnl->tp_src = udp->udp_src;
90+ tnl->tp_dst = udp->udp_dst;
91+ tnl->tun_id = htonll(ntohl(get_16aligned_be32(&vxg->vx_vni)) >> 8);
92+
93+ if (vxg->p == 0x01 && vxg->proto == VXG_P_NSH) {
94+ struct nshhdr *nsh = (struct nshhdr *) (vxg + 1);
95+
96+ tnl->nsp = nsh->b.b2 << 8;
97+ tnl->nsi = nsh->b.svc_idx;
98+ tnl->nshc1 = nsh->c.nshc1;
99+ tnl->nshc2 = nsh->c.nshc2;
100+ tnl->nshc3 = nsh->c.nshc3;
101+ tnl->nshc4 = nsh->c.nshc4;
102+ tnl->flags |= FLOW_TNL_F_NSP;
103+ tnl->flags |= FLOW_TNL_F_NSI;
104+ tnl->flags |= FLOW_TNL_F_NSH_C1 | FLOW_TNL_F_NSH_C2 | \
105+ FLOW_TNL_F_NSH_C3 | FLOW_TNL_F_NSH_C4;
106+
107+ dp_packet_reset_packet(packet, VXNSH_HLEN);
108+ } else {
109+ VLOG_WARN("Unsupported vxlan GPE + NSH format!");
110+ return EINVAL;;
111+ }
112+
113+ } else {
114+
115+ struct vxlanhdr *vxh = (struct vxlanhdr *) (udp + 1);
116
117- dp_packet_reset_packet(packet, VXLAN_HLEN);
118+ if (get_16aligned_be32(&vxh->vx_flags) != htonl(VXLAN_FLAGS) ||
119+ (get_16aligned_be32(&vxh->vx_vni) & htonl(0xff))) {
120+ VLOG_WARN_RL(&err_rl, "invalid vxlan flags=%#x vni=%#x\n",
121+ ntohl(get_16aligned_be32(&vxh->vx_flags)),
122+ ntohl(get_16aligned_be32(&vxh->vx_vni)));
123+ return EINVAL;;
124+ }
125+
126+ tnl->tp_src = udp->udp_src;
127+ tnl->tp_dst = udp->udp_dst;
128+ tnl->tun_id = htonll(ntohl(get_16aligned_be32(&vxh->vx_vni)) >> 8);
129+ dp_packet_reset_packet(packet, VXLAN_HLEN);
130+ }
131
132 return 0;
133 }
134@@ -1496,23 +1542,103 @@ netdev_vxlan_build_header(const struct netdev *netdev,
135 {
136 struct netdev_vport *dev = netdev_vport_cast(netdev);
137 struct netdev_tunnel_config *tnl_cfg;
138- struct vxlanhdr *vxh;
139+ struct ip_header *ip;
140+ struct udp_header *udp;
141+ bool isnsh = false;
142
143 /* XXX: RCUfy tnl_cfg. */
144 ovs_mutex_lock(&dev->mutex);
145 tnl_cfg = &dev->tnl_cfg;
146
147- vxh = udp_build_header(tnl_cfg, tnl_flow, data);
148+ ip = ip_hdr(data->header);
149+ ip->ip_proto = IPPROTO_UDP;
150+
151+ udp = (struct udp_header *) (ip + 1);
152+ udp->udp_dst = tnl_cfg->dst_port;
153+
154+ if (tnl_flow->tunnel.flags & FLOW_TNL_F_CSUM) {
155+ /* Write a value in now to mark that we should compute the checksum
156+ * later. 0xffff is handy because it is transparent to the
157+ * calculation. */
158+ udp->udp_csum = htons(0xffff);
159+ }
160+
161+ if (ntohs(udp->udp_dst) == VXGPE_DST_PORT){
162+ struct vxgpehdr *vxg = (struct vxgpehdr *) (udp + 1);
163
164- put_16aligned_be32(&vxh->vx_flags, htonl(VXLAN_FLAGS));
165- put_16aligned_be32(&vxh->vx_vni, htonl(ntohll(tnl_flow->tunnel.tun_id) << 8));
166+ memset(vxg, 0, sizeof *vxg);
167+ vxg->i = 0x01;
168+ vxg->p = 0x01;
169+ vxg->ver = 0x01;
170+ vxg->proto = VXG_P_NSH;
171+ put_16aligned_be32(&vxg->vx_vni, htonl(ntohll(tnl_flow->tunnel.tun_id) << 8));
172+
173+ if (vxg->p && vxg->proto == VXG_P_NSH){
174+ struct nshhdr *nsh = (struct nshhdr *) (vxg + 1);
175+
176+ memset(nsh, 0, sizeof *nsh);
177+ nsh->b.ver = 0x01;
178+ nsh->b.len = 6;
179+ nsh->b.mdtype = NSH_M_TYPE1;
180+ nsh->b.proto = NSH_P_ETHERNET;
181+
182+ nsh->b.b2 = tnl_flow->tunnel.nsp >> 8;
183+ nsh->b.svc_idx = tnl_flow->tunnel.nsi;
184+
185+ nsh->c.nshc1 = tnl_flow->tunnel.nshc1;
186+ nsh->c.nshc2 = tnl_flow->tunnel.nshc2;
187+ nsh->c.nshc3 = tnl_flow->tunnel.nshc3;
188+ nsh->c.nshc4 = tnl_flow->tunnel.nshc4;
189+
190+ isnsh = true;
191+ }
192+
193+ } else {
194+ struct vxlanhdr *vxh = (struct vxlanhdr *) (udp + 1);
195+ put_16aligned_be32(&vxh->vx_flags, htonl(VXLAN_FLAGS));
196+ put_16aligned_be32(&vxh->vx_vni, htonl(ntohll(tnl_flow->tunnel.tun_id) << 8));
197+ }
198
199 ovs_mutex_unlock(&dev->mutex);
200- data->header_len = VXLAN_HLEN;
201+
202+ if(isnsh)
203+ data->header_len = VXNSH_HLEN;
204+ else
205+ data->header_len = VXLAN_HLEN;
206 data->tnl_type = OVS_VPORT_TYPE_VXLAN;
207+
208 return 0;
209 }
210
211+static void
212+netdev_vxlan_push_header(struct dp_packet *packet,
213+ const struct ovs_action_push_tnl *data)
214+{
215+ int ip_tot_size;
216+ int size = data->header_len;
217+ const void *header = data->header;
218+ struct udp_header *udp;
219+
220+ udp = push_ip_header(packet, header, size, &ip_tot_size);
221+
222+ /* set udp src port */
223+ udp->udp_src = get_src_port(packet);
224+ udp->udp_len = htons(ip_tot_size - sizeof (struct ip_header));
225+ /* udp_csum is zero */
226+
227+ if (udp->udp_csum) {
228+ uint32_t csum = packet_csum_pseudoheader(ip_hdr(dp_packet_data(packet)));
229+
230+ csum = csum_continue(csum, udp,
231+ ip_tot_size - sizeof (struct ip_header));
232+ udp->udp_csum = csum_finish(csum);
233+
234+ if (!udp->udp_csum) {
235+ udp->udp_csum = htons(0xffff);
236+ }
237+ }
238+}
239