fuel-plugin-ovs with Yi Y Yang NSH patches

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>
This commit is contained in:
Ferenc Cserepkei 2016-05-21 17:22:12 +02:00
parent 27eaf16ac1
commit ea5194730b
19 changed files with 6135 additions and 7955 deletions

View File

@ -2,26 +2,31 @@
FROM ubuntu:14.04.3
ENV HOME /root
RUN rm -rf /lib/modules
RUN apt-get update
RUN apt-get install -y software-properties-common python-software-properties \
make python-setuptools python-all dpkg-dev debhelper \
fuseiso git genisoimage bind9-host wget curl lintian tmux lxc iptables \
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
RUN apt-get install -y software-properties-common python-software-properties\
make python-setuptools apt-utils autoconf automake bind9-host\
build-essential bzip2 ca-certificates curl debhelper dh-autoreconf\
dpkg-dev fakeroot fuseiso genisoimage git graphviz iptables\
libssl-dev libtool lintian python-flake8 dh-python\
lsb-release lxc openssl procps python-all python-qt4 python-setuptools\
python-six python-twisted-conch python-zopeinterface python3-six\
sudo tmux wget linux-headers-3.13.0-85-generic
RUN ln -s /lib/modules/3.13.0-76-generic /lib/modules/`uname -r`
RUN ln -s /lib/modules/3.13.0-85-generic /lib/modules/$(uname -r)
RUN apt-get install -y pkg-config unzip liblua5.2-dev libpcap-dev libedit-dev libncurses5-dev libncursesw5-dev
RUN apt-get install -y pkg-config unzip liblua5.2-dev libpcap0.8-dev libcap-ng-dev libedit-dev libncurses5-dev libncursesw5-dev
RUN echo "ALL ALL=NOPASSWD: ALL" > /etc/sudoers.d/open-sudo
RUN chmod 0440 /etc/sudoers.d/open-sudo
ADD ./patches /patches
ADD ./patches /root/patches
ADD ./build-ovs-nsh.sh /build-ovs-nsh.sh
RUN chmod +x /build-ovs-nsh.sh
RUN /build-ovs-nsh.sh
ADD ./build-ovs-nsh.sh /root/build-ovs-nsh.sh
RUN chmod +x /root/build-ovs-nsh.sh
RUN /root/build-ovs-nsh.sh
ADD ./build-ovs-nsh-dpdk.sh /build-ovs-nsh-dpdk.sh
RUN chmod +x /build-ovs-nsh-dpdk.sh
RUN /build-ovs-nsh-dpdk.sh
ADD ./build-ovs-nsh-dpdk.sh /root/build-ovs-nsh-dpdk.sh
RUN chmod +x /root/build-ovs-nsh-dpdk.sh
RUN /root/build-ovs-nsh-dpdk.sh

View File

@ -1,13 +1,17 @@
#!/bin/bash
DPDK_VER=2.1.0
OVS_COMMIT=121daded51b9798fe3722824b27a05c16806cbd1
RTE_TARGET=x86_64-native-linuxapp-gcc
PATCHES="060679 060680 060681 060682 060683 060684 060685"
URL_OVS=https://github.com/openvswitch/ovs.git
DPDK_VER=2.2.0
URL_DPDK=http://dpdk.org/browse/dpdk/snapshot/dpdk-${DPDK_VER}.tar.gz
export RTE_SDK=/root/dpdk-${DPDK_VER}
export RTE_TARGET=x86_64-native-linuxapp-gcc
export DPDK_BUILD=${RTE_SDK}/${RTE_TARGET}
OVS_COMMIT=7d433ae57ebb90cd68e8fa948a096f619ac4e2d8
URL_OVS=https://github.com/openvswitch/ovs.git
PATCHES="eeaf57e bf1e7ff 21bd423 17a6124 299fc5b"
cd $HOME
wget ${URL_DPDK}
tar -xzvf dpdk-${DPDK_VER}.tar.gz
cd dpdk-${DPDK_VER}
@ -15,36 +19,37 @@ sed -i -e 's/CONFIG_RTE_LIBRTE_VHOST=n/CONFIG_RTE_LIBRTE_VHOST=y/' \
-e 's/CONFIG_RTE_BUILD_COMBINE_LIBS=n/CONFIG_RTE_BUILD_COMBINE_LIBS=y/' \
-e 's/CONFIG_RTE_PKTMBUF_HEADROOM=128/CONFIG_RTE_PKTMBUF_HEADROOM=256/' \
config/common_linuxapp
cd /
cd $HOME
tar -czvf dpdk-${DPDK_VER}.tar.gz dpdk-${DPDK_VER}
cd dpdk-${DPDK_VER}
make install T=${RTE_TARGET}
find . | grep "\.o$" | xargs rm -rf
cd /
cd $HOME
tar czvf dpdk-${DPDK_VER}.bin.tar.gz dpdk-${DPDK_VER}
cd $HOME
git clone ${URL_OVS} openvswitch-dpdk
cd openvswitch-dpdk
git checkout ${OVS_COMMIT} -b development
git checkout ${OVS_COMMIT} -b yyang13
for patch in ${PATCHES}
do
patch -p1 < /patches/${patch}.patch
patch -p1 < ${HOME}/patches/${patch}.patch
done
export RTE_SDK=/dpdk-${DPDK_VER}
export DPDK_BUILD=${RTE_SDK}/${RTE_TARGET}
./boot.sh
./configure --with-dpdk=$DPDK_BUILD
sed -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;
cd openvswitch-2.4.90;DEB_BUILD_OPTIONS='parallel=8 nocheck' fakeroot debian/rules binary
sed -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;
cd openvswitch-2.5.90;DEB_BUILD_OPTIONS='parallel=8 nocheck' fakeroot debian/rules binary
cd /
cd $HOME
wget https://01.org/sites/default/files/downloads/intel-data-plane-performance-demonstrators/dppd-prox-v021.zip
unzip dppd-prox-v021.zip
export RTE_SDK=/dpdk-${DPDK_VER}
export RTE_TARGET=x86_64-native-linuxapp-gcc
cd /dppd-PROX-v021
export DPPD_DIR=`pwd`; make
cd dppd-PROX-v021
export DPPD_DIR=$(pwd); make
find . | grep "\.o$" | xargs rm -rf
cd /
tar czvf dppd-prox-v021.bin.tar.gz dppd-PROX-v021
cd $HOME
tar -czvf dppd-prox-v021.bin.tar.gz dppd-PROX-v021

View File

@ -1,16 +1,30 @@
#!/bin/bash
OVS_COMMIT=121daded51b9798fe3722824b27a05c16806cbd1
PATCHES="060679 060680 060681 060682 060683 060684 060685"
OVS_COMMIT=7d433ae57ebb90cd68e8fa948a096f619ac4e2d8
URL_OVS=https://github.com/openvswitch/ovs.git
PATCHES="eeaf57e bf1e7ff 21bd423 17a6124 299fc5b"
cd $HOME
git clone ${URL_OVS} openvswitch
cd openvswitch
git checkout ${OVS_COMMIT} -b development
git checkout ${OVS_COMMIT} -b yyang13
for patch in ${PATCHES}
do
patch -p1 < /patches/${patch}.patch
patch -p1 < ${HOME}/patches/${patch}.patch
done
./boot.sh;./configure;make dist;tar -xzf openvswitch-2.4.90.tar.gz
cd openvswitch-2.4.90;dpkg-checkbuilddeps;DEB_BUILD_OPTIONS='parallel=8 nocheck' fakeroot debian/rules binary
./boot.sh
./configure --prefix=/usr --sysconfdir=/etc --localstatedir=/var --with-linux=/lib/modules/$(uname -r)/build
make dist
OVSTBALL=$(echo openvswitch-*.tar.gz)
OVSART='openvswitch-2.5.90'
tar -xzf ${HOME}/openvswitch/$OVSTBALL
cd $OVSART
dpkg-checkbuilddeps
DEB_BUILD_OPTIONS='parallel=8 nocheck' fakeroot debian/rules binary

File diff suppressed because it is too large Load Diff

View File

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

File diff suppressed because it is too large Load Diff

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,68 @@
commit 299fc5b315e879258b024af98c9292565184b107
Author: Yi Yang <yi.y.yang@intel.com>
Date: Fri Apr 15 14:17:54 2016 +0800
Ethernet header must be kept in VxLAN-gpe + eth + NSH for new ovs lwtunnel implementation
Signed-off-by: Yi Yang <yi.y.yang@intel.com>
diff --git a/datapath/linux/compat/vxlan.c b/datapath/linux/compat/vxlan.c
index 888d431..3c05141 100644
--- a/datapath/linux/compat/vxlan.c
+++ b/datapath/linux/compat/vxlan.c
@@ -821,7 +821,7 @@ static void vxlan_rcv(struct vxlan_sock *vs, struct sk_buff *skb,
struct vxlan_dev *vxlan;
struct pcpu_sw_netstats *stats;
union vxlan_addr saddr;
- struct eth_nsh_hdr *eth_nsh_header = NULL;
+ //struct eth_nsh_hdr *eth_nsh_header = NULL;
int err = 0;
/* For flow based devices, map all packets to VNI 0 */
@@ -891,12 +891,13 @@ static void vxlan_rcv(struct vxlan_sock *vs, struct sk_buff *skb,
u64_stats_update_end(&stats->syncp);
/* Add a faked encap_eth_header for NSH */
- if (md && ((md->gpe & VXLAN_GPE_NP_MASK) == VXLAN_GPE_NP_NSH)) {
+ /* ovs changes have ensured it is here, so needn't add it any more */
+ /*if (md && ((md->gpe & VXLAN_GPE_NP_MASK) == VXLAN_GPE_NP_NSH)) {
skb_push(skb, ENCAP_ETH_LEN);
eth_nsh_header = (struct eth_nsh_hdr *)skb->data;
memmove(eth_nsh_header->encap_eth_header.encap_eth_dst, skb_mac_header(skb), ENCAP_ETH_LEN);
eth_nsh_header->encap_eth_header.encap_eth_type = htons(ETH_P_NSH);
- }
+ }*/
netdev_port_receive(skb, skb_tunnel_info(skb));
return;
@@ -985,7 +986,7 @@ static int vxlan_udp_encap_recv(struct sock *sk, struct sk_buff *skb)
struct vxlanhdr_gpe *gpe;
gpe = (struct vxlanhdr_gpe *)vxh;
- md->gpe = ntohs(gpe->next_proto);
+ md->gpe = gpe->next_proto;
buf.dst.u.tun_info.key.tun_flags |= TUNNEL_VXLAN_OPT;
@@ -1189,9 +1190,10 @@ static int vxlan_xmit_skb(struct rtable *rt, struct sock *sk, struct sk_buff *sk
}
/* Skip encap_eth_header on sending Eth+NSH to vxlan-gpe port */
- if (md && ((md->gpe & VXLAN_GPE_NP_MASK) == VXLAN_GPE_NP_NSH)) {
+ /* ovs needs to keep eth header here */
+ /*if (md && ((md->gpe & VXLAN_GPE_NP_MASK) == VXLAN_GPE_NP_NSH)) {
skb_pull(skb, ENCAP_ETH_LEN);
- }
+ }*/
min_headroom = LL_RESERVED_SPACE(rt->dst.dev) + rt->dst.header_len
+ VXLAN_HLEN + sizeof(struct iphdr)
@@ -1236,6 +1238,8 @@ static int vxlan_xmit_skb(struct rtable *rt, struct sock *sk, struct sk_buff *sk
}
if (vxflags & VXLAN_F_GBP)
vxlan_build_gbp_hdr(vxh, vxflags, md);
+ else if (vxflags & VXLAN_F_GPE)
+ vxlan_build_gpe_hdr(vxh, vxflags, md);
ovs_skb_set_inner_protocol(skb, htons(ETH_P_TEB));

File diff suppressed because it is too large Load Diff

View File

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

View File

@ -3,7 +3,7 @@
set -eux
BUILD_FOR=${BUILD_FOR:-ubuntu}
DIR="$(dirname `readlink -f $0`)"
DIR="$(dirname $(readlink -f "$0"))"
INCLUDE_DEPENDENCIES=${INCLUDE_DEPENDENCIES:-true}
@ -23,15 +23,15 @@ function build_pkg {
cd ${DIR}/ovs-nsh
sudo docker build -t ovs-nsh .
container_id=`sudo docker run -d ovs-nsh`
sudo docker cp $container_id:/openvswitch/openvswitch-common_2.4.90-1_amd64.deb ${DIR}/repositories/ubuntu/ovs/
sudo docker cp $container_id:/openvswitch/openvswitch-datapath-dkms_2.4.90-1_all.deb ${DIR}/repositories/ubuntu/ovs/
sudo docker cp $container_id:/openvswitch/openvswitch-switch_2.4.90-1_amd64.deb ${DIR}/repositories/ubuntu/ovs/
sudo docker cp $container_id:/root/openvswitch/openvswitch-common_2.5.90-1_amd64.deb ${DIR}/repositories/ubuntu/ovs/
sudo docker cp $container_id:/root/openvswitch/openvswitch-datapath-dkms_2.5.90-1_all.deb ${DIR}/repositories/ubuntu/ovs/
sudo docker cp $container_id:/root/openvswitch/openvswitch-switch_2.5.90-1_amd64.deb ${DIR}/repositories/ubuntu/ovs/
sudo docker cp $container_id:/openvswitch-dpdk/openvswitch-common_2.4.90-1_amd64.deb ${DIR}/repositories/ubuntu/dpdk
sudo docker cp $container_id:/openvswitch-dpdk/openvswitch-datapath-dkms_2.4.90-1_all.deb ${DIR}/repositories/ubuntu/dpdk
sudo docker cp $container_id:/openvswitch-dpdk/openvswitch-switch_2.4.90-1_amd64.deb ${DIR}/repositories/ubuntu/dpdk
sudo docker cp $container_id:/dpdk-2.1.0.bin.tar.gz ${DIR}/repositories/ubuntu/dpdk/
sudo docker cp $container_id:/dppd-prox-v021.bin.tar.gz ${DIR}/repositories/ubuntu/dppd/
sudo docker cp $container_id:/root/openvswitch-dpdk/openvswitch-common_2.5.90-1_amd64.deb ${DIR}/repositories/ubuntu/dpdk
sudo docker cp $container_id:/root/openvswitch-dpdk/openvswitch-datapath-dkms_2.5.90-1_all.deb ${DIR}/repositories/ubuntu/dpdk
sudo docker cp $container_id:/root/openvswitch-dpdk/openvswitch-switch_2.5.90-1_amd64.deb ${DIR}/repositories/ubuntu/dpdk
sudo docker cp $container_id:/root/dpdk-2.2.0.bin.tar.gz ${DIR}/repositories/ubuntu/dpdk/
sudo docker cp $container_id:/root/dppd-prox-v021.bin.tar.gz ${DIR}/repositories/ubuntu/dppd/
;;
*) echo "Not supported system"; exit 1;;
esac

View File

@ -2,11 +2,13 @@
NICS=$1
INSTALL_HOME=/usr/share/dpdk/
OVS_VER='2.5.90'
DPDK_VER='2.2.0'
rm -rf $INSTALL_HOME ; mkdir -p $INSTALL_HOME
cd $INSTALL_HOME
wget http://10.20.0.2:8080/plugins/fuel-plugin-ovs-0.5/repositories/ubuntu/dpdk/dpdk-2.1.0.bin.tar.gz
tar xzvf dpdk-2.1.0.bin.tar.gz
rm -rf dpdk-2.1.0.bin.tar.gz
wget "http://10.20.0.2:8080/plugins/fuel-plugin-ovs-0.5/repositories/ubuntu/dpdk/dpdk-${DPDK_VER}.bin.tar.gz"
tar xzvf "dpdk-${DPDK_VER}.bin.tar.gz"
rm -rf dpdk-${DPDK_VER}.bin.tar.gz
wget http://10.20.0.2:8080/plugins/fuel-plugin-ovs-0.5/repositories/ubuntu/dpdk/dpdk.init -O /etc/init.d/dpdk
chmod +x /etc/init.d/dpdk
wget http://10.20.0.2:8080/plugins/fuel-plugin-ovs-0.5/repositories/ubuntu/dpdk/dpdk.conf -O /etc/default/dpdk.conf
@ -16,9 +18,9 @@ service dpdk start
INSTALL_HOME=/usr/share/ovs-dpdk/
rm -rf $INSTALL_HOME ; mkdir -p $INSTALL_HOME
cd $INSTALL_HOME
wget http://10.20.0.2:8080/plugins/fuel-plugin-ovs-0.5/repositories/ubuntu/dpdk/openvswitch-datapath-dkms_2.4.90-1_all.deb
dpkg -i openvswitch-datapath-dkms_2.4.90-1_all.deb
wget http://10.20.0.2:8080/plugins/fuel-plugin-ovs-0.5/repositories/ubuntu/dpdk/openvswitch-common_2.4.90-1_amd64.deb
dpkg -i openvswitch-common_2.4.90-1_amd64.deb
wget http://10.20.0.2:8080/plugins/fuel-plugin-ovs-0.5/repositories/ubuntu/dpdk/openvswitch-switch_2.4.90-1_amd64.deb
dpkg -i openvswitch-switch_2.4.90-1_amd64.deb
wget "http://10.20.0.2:8080/plugins/fuel-plugin-ovs-0.5/repositories/ubuntu/dpdk/openvswitch-datapath-dkms_${OVS_VER}-1_all.deb"
dpkg -i "openvswitch-datapath-dkms_${OVS_VER}_all.deb"
wget "http://10.20.0.2:8080/plugins/fuel-plugin-ovs-0.5/repositories/ubuntu/dpdk/openvswitch-common_${OVS_VER}-1_amd64.deb"
dpkg -i "openvswitch-common_${OVS_VER}-1_amd64.deb"
wget "http://10.20.0.2:8080/plugins/fuel-plugin-ovs-0.5/repositories/ubuntu/dpdk/openvswitch-switch_${OVS_VER}-1_amd64.deb"
dpkg -i "openvswitch-switch_${OVS_VER}-1_amd64.deb"

View File

@ -17,7 +17,7 @@
echo "sourcing config"
source /etc/default/dpdk.conf
RTE_SDK=${RTE_SDK:-/usr/share/dpdk/dpdk-2.1.0}
RTE_SDK=${RTE_SDK:-/usr/share/dpdk/dpdk-2.2.0}
RTE_TARGET=${RTE_TARGET:-x86_64-native-linuxapp-gcc}
DPDK_DIR=$RTE_SDK

View File

@ -3,10 +3,11 @@ set -eux
INSTALL_HOME=/usr/share/ovs/
rm -rf $INSTALL_HOME ; mkdir -p $INSTALL_HOME
OVS_VER='2.5.90'
cd $INSTALL_HOME
wget http://10.20.0.2:8080/plugins/fuel-plugin-ovs-0.5/repositories/ubuntu/ovs/openvswitch-datapath-dkms_2.4.90-1_all.deb
dpkg -i openvswitch-datapath-dkms_2.4.90-1_all.deb
wget http://10.20.0.2:8080/plugins/fuel-plugin-ovs-0.5/repositories/ubuntu/ovs/openvswitch-common_2.4.90-1_amd64.deb
dpkg -i openvswitch-common_2.4.90-1_amd64.deb
wget http://10.20.0.2:8080/plugins/fuel-plugin-ovs-0.5/repositories/ubuntu/ovs/openvswitch-switch_2.4.90-1_amd64.deb
dpkg -i openvswitch-switch_2.4.90-1_amd64.deb
wget "http://10.20.0.2:8080/plugins/fuel-plugin-ovs-0.5/repositories/ubuntu/ovs/openvswitch-datapath-dkms_${OVS_VER}-1_all.deb"
dpkg -i "openvswitch-datapath-dkms_${OVS_VER}-1_all.deb"
wget "http://10.20.0.2:8080/plugins/fuel-plugin-ovs-0.5/repositories/ubuntu/ovs/openvswitch-common_${OVS_VER}-1_amd64.deb"
dpkg -i "openvswitch-common_${OVS_VER}-1_amd64.deb"
wget "http://10.20.0.2:8080/plugins/fuel-plugin-ovs-0.5/repositories/ubuntu/ovs/openvswitch-switch_${OVS_VER}-1_amd64.deb"
dpkg -i "openvswitch-switch_${OVS_VER}-1_amd64.deb"