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:
parent
27eaf16ac1
commit
ea5194730b
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
||||
|
|
@ -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, ð_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
|
||||
|
|
@ -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
|
@ -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
|
@ -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' \
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
|
Loading…
Reference in New Issue