diff --git a/deployment_scripts/install.sh b/deployment_scripts/install.sh index 5e4d269..c6c1d62 100644 --- a/deployment_scripts/install.sh +++ b/deployment_scripts/install.sh @@ -10,19 +10,21 @@ nsh=$2 dpdk=$3 dpdk_socket_mem=${4:-''} +apt-get install -y dkms + if [ $nsh = 'true' ] then curl http://$host:8080/plugins/fuel-plugin-ovs-1.0/repositories/ubuntu/ovs-nsh-dpdk.tar.gz | tar -xzv - dpkg -i openvswitch-datapath-dkms_2.5.90-1.nsh_all.deb - dpkg -i openvswitch-common_2.5.90-1.nsh_amd64.deb - dpkg -i openvswitch-switch_2.5.90-1.nsh_amd64.deb - dpkg -i python-openvswitch_2.5.90-1.nsh_all.deb + dpkg -i openvswitch-datapath-dkms_2.6.1-1.nsh_all.deb + dpkg -i openvswitch-common_2.6.1-1.nsh_amd64.deb + dpkg -i openvswitch-switch_2.6.1-1.nsh_amd64.deb + dpkg -i python-openvswitch_2.6.1-1.nsh_all.deb if [ $dpdk = 'true' ] then dpkg -i libxenstore3.0*.deb dpkg -i libdpdk0_2.2.0-1_amd64.deb dpkg -i dpdk_2.2.0-1_amd64.deb - dpkg -i openvswitch-switch-dpdk_2.5.90-1.nsh_amd64.deb + dpkg -i openvswitch-switch-dpdk_2.6.1-1.nsh_amd64.deb fi else curl http://$host:8080/plugins/fuel-plugin-ovs-1.0/repositories/ubuntu/ovs-dpdk.tar.gz | tar -xzv diff --git a/ovs_build/build-ovs-nsh-dpdk.sh b/ovs_build/build-ovs-nsh-dpdk.sh index 1b42df1..f80d081 100755 --- a/ovs_build/build-ovs-nsh-dpdk.sh +++ b/ovs_build/build-ovs-nsh-dpdk.sh @@ -2,100 +2,47 @@ set -eux -OVS_COMMIT=7d433ae57ebb90cd68e8fa948a096f619ac4e2d8 +OVS_COMMIT=f4b0e64cffb4777ff03d48621c3eadcf1d8c19f3 URL_OVS=https://github.com/openvswitch/ovs.git -OVS_VER=${OVS_VER:-2.5.90} +OVS_VER=${OVS_VER:-2.6.1} BUILD_HOME=$HOME/nsh BUILD_DEST=${BUILD_DEST:-/deb} DIR="$(dirname `readlink -f $0`)" export DEB_BUILD_OPTIONS='parallel=8 nocheck' -sudo apt-get build-dep openvswitch -y sudo apt-get -y install devscripts dpkg-dev git wget rm -rf ${BUILD_HOME}; mkdir -p ${BUILD_HOME} cd ${BUILD_HOME} -wget -c https://launchpad.net/ubuntu/+archive/primary/+files/dpdk_2.2.0-0ubuntu8.dsc -wget -c https://launchpad.net/ubuntu/+archive/primary/+files/dpdk_2.2.0.orig.tar.gz -wget -c https://launchpad.net/ubuntu/+archive/primary/+files/dpdk_2.2.0-0ubuntu8.debian.tar.xz -dpkg-source -x dpdk_2.2.0-0ubuntu8.dsc # copy from debian/control -sudo apt-get install -y debhelper \ - dh-python \ - dh-systemd \ - doxygen \ - graphviz \ - inkscape \ - libcap-dev \ - libpcap-dev \ - libxen-dev \ - libxenstore3.0 \ - python \ - python-sphinx \ - texlive-fonts-recommended \ - texlive-latex-extra - -cd dpdk-2.2.0; rm -rf debian/patches/; -cat << EOF > debian/changelog -dpdk (2.2.0-1) unstable; urgency=low - * DPDK 2.2.0 - -- DPDK team $(date --rfc-2822) -EOF -debian/rules build; fakeroot debian/rules binary -cd ${BUILD_HOME}; sudo dpkg -i *.deb -apt-get download libxenstore3.0 - -cd ${BUILD_HOME} -wget -c https://launchpad.net/ubuntu/+archive/primary/+files/openvswitch-dpdk_2.4.0.orig.tar.gz -wget -c https://launchpad.net/ubuntu/+archive/primary/+files/openvswitch-dpdk_2.4.0-0ubuntu1.dsc -wget -c https://launchpad.net/ubuntu/+archive/primary/+files/openvswitch-dpdk_2.4.0-0ubuntu1.debian.tar.xz -dpkg-source -x openvswitch-dpdk_2.4.0-0ubuntu1.dsc - -# copy from debian/control -sudo apt-get install -y autoconf \ +sudo apt-get install -y \ + graphviz \ + autoconf \ automake \ bzip2 \ debhelper \ dh-autoreconf \ - dh-systemd \ - graphviz \ - libdpdk-dev \ - libfuse-dev \ libssl-dev \ libtool \ openssl \ procps \ python-all \ - python-qt4 \ python-twisted-conch \ python-zopeinterface \ python-six git clone https://github.com/openvswitch/ovs.git cd ovs; git checkout ${OVS_COMMIT} -PATCHES=$(cd ${DIR}/patches; echo *patch) +PATCHES=$(cd ${DIR}/ovs_nsh_patches/v2.6.1/; echo *patch) for patch in ${PATCHES} do - patch -p1 < ${DIR}/patches/${patch} + patch -p1 < ${DIR}/ovs_nsh_patches/v2.6.1/${patch} done -cd ${BUILD_HOME}; tar czvf ovs.tar.gz ovs -rm -rf openvswitch-dpdk-${OVS_VER}* -cd openvswitch-dpdk-2.4.0; uupdate -v ${OVS_VER} ../ovs.tar.gz -cd ../openvswitch-dpdk-${OVS_VER} -sed -i "s/include\/rte_config.h/include\/dpdk\/rte_config.h/" acinclude.m4 -sed -i 's/DPDK_INCLUDE=.*/DPDK_INCLUDE=$RTE_SDK\/include\/dpdk/' acinclude.m4 -autoreconf --install -rm -rf debian/patches/ .git; -cat << EOF > debian/changelog -openvswitch-dpdk (${OVS_VER}-1.nsh) unstable; urgency=low - * Support NSH - -- Open vSwitch team $(date --rfc-2822) -EOF -debian/rules build; fakeroot debian/rules binary +# build ovs cd ${BUILD_HOME}/ovs cat << EOF > debian/changelog openvswitch (${OVS_VER}-1.nsh) unstable; urgency=low diff --git a/ovs_build/patches/0001-ovs-vxlan-gpe-vxlan-extension-to-support-vxlan-gpe-t.patch b/ovs_build/ovs_nsh_patches/v2.6.1/0001-Enable-current-VxLAN-gpe-work-and-meet-NSH-requireme.patch similarity index 68% rename from ovs_build/patches/0001-ovs-vxlan-gpe-vxlan-extension-to-support-vxlan-gpe-t.patch rename to ovs_build/ovs_nsh_patches/v2.6.1/0001-Enable-current-VxLAN-gpe-work-and-meet-NSH-requireme.patch index c172320..63b7597 100644 --- a/ovs_build/patches/0001-ovs-vxlan-gpe-vxlan-extension-to-support-vxlan-gpe-t.patch +++ b/ovs_build/ovs_nsh_patches/v2.6.1/0001-Enable-current-VxLAN-gpe-work-and-meet-NSH-requireme.patch @@ -1,34 +1,31 @@ -From 5d79831435ec4e5bea20cc36c3f83eacf6fd065c Mon Sep 17 00:00:00 2001 +From 9f7148f9dc03053a4a3231a7cf819c447a178a17 Mon Sep 17 00:00:00 2001 From: Yi Yang -Date: Mon, 11 Apr 2016 15:58:14 +0800 -Subject: [PATCH 1/6] ovs-vxlan-gpe: vxlan extension to support vxlan-gpe - tunnel port +Date: Fri, 11 Nov 2016 11:13:18 +0800 +Subject: [PATCH 1/8] Enable current VxLAN-gpe work and meet NSH requirements -Signed-off-by: Mengke Liu -Signed-off-by: Ricky Li -Signed-off-by: Johnson Li Signed-off-by: Yi Yang --- datapath/flow_netlink.c | 8 +- datapath/linux/compat/include/linux/openvswitch.h | 1 + - datapath/linux/compat/include/net/vxlan.h | 73 +++++++++++++++++++ - datapath/linux/compat/vxlan.c | 30 ++++++++ + datapath/linux/compat/include/net/vxlan.h | 1 + + datapath/linux/compat/vxlan.c | 4 +- + datapath/vport-netdev.c | 3 +- datapath/vport-vxlan.c | 15 ++++ + include/openvswitch/match.h | 4 + + include/openvswitch/meta-flow.h | 28 +++++++ + include/openvswitch/packets.h | 4 +- lib/flow.c | 8 ++ lib/match.c | 34 +++++++++ - lib/match.h | 4 + lib/meta-flow.c | 36 +++++++++ - lib/meta-flow.h | 28 +++++++ lib/netdev-vport.c | 2 + lib/nx-match.c | 4 + lib/odp-util.c | 89 ++++++++++++++++++++++- - lib/packets.h | 4 +- tests/ofproto.at | 4 +- tests/ovs-ofctl.at | 4 + - 16 files changed, 340 insertions(+), 4 deletions(-) + 17 files changed, 241 insertions(+), 8 deletions(-) diff --git a/datapath/flow_netlink.c b/datapath/flow_netlink.c -index 6ffcc53..351a504 100644 +index 0f32664..2dcae07 100644 --- a/datapath/flow_netlink.c +++ b/datapath/flow_netlink.c @@ -309,6 +309,7 @@ size_t ovs_key_attr_size(void) @@ -39,7 +36,7 @@ index 6ffcc53..351a504 100644 }; 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, +@@ -523,6 +524,9 @@ static int vxlan_tun_opt_from_nlattr(const struct nlattr *attr, case OVS_VXLAN_EXT_GBP: opts.gbp = nla_get_u32(a); break; @@ -49,7 +46,7 @@ index 6ffcc53..351a504 100644 default: OVS_NLERR(log, "Unknown VXLAN extension attribute %d", type); -@@ -677,7 +681,9 @@ static int vxlan_opt_to_nlattr(struct sk_buff *skb, +@@ -709,7 +713,9 @@ static int vxlan_opt_to_nlattr(struct sk_buff *skb, if (!nla) return -EMSGSIZE; @@ -61,10 +58,10 @@ index 6ffcc53..351a504 100644 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 +index 12260d8..44b7ce4 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 { +@@ -291,6 +291,7 @@ enum ovs_vport_attr { enum { OVS_VXLAN_EXT_UNSPEC, OVS_VXLAN_EXT_GBP, /* Flag or __u32 */ @@ -73,172 +70,57 @@ index 3b39ebb..44adb81 100644 }; diff --git a/datapath/linux/compat/include/net/vxlan.h b/datapath/linux/compat/include/net/vxlan.h -index 75a5a7a..2bfc3f8 100644 +index 5bc8969..5a994b2 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) +@@ -201,6 +201,7 @@ reserved_flags2:2; -+/* -+ * 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 " -+#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; + 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 | \ + /* per UDP socket information */ diff --git a/datapath/linux/compat/vxlan.c b/datapath/linux/compat/vxlan.c -index 4faa18f..7ef051c 100644 +index d5dbe8d..a80610b 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; +@@ -705,7 +705,6 @@ static int vxlan_rcv(struct sock *sk, struct sk_buff *skb) + if (vs->flags & VXLAN_F_GPE) { + if (!vxlan_parse_gpe_hdr(&unparsed, &protocol, skb, vs->flags)) + goto drop; +- raw_proto = true; } - 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 (__iptunnel_pull_header(skb, VXLAN_HLEN, protocol, raw_proto, +@@ -896,10 +895,9 @@ static int vxlan_build_skb(struct sk_buff *skb, struct dst_entry *dst, 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); + if (vxflags & VXLAN_F_GPE) { +- err = vxlan_build_gpe_hdr(vxh, vxflags, skb->protocol); ++ err = vxlan_build_gpe_hdr(vxh, vxflags, inner_protocol); + if (err < 0) + goto out_free; +- inner_protocol = skb->protocol; + } - ovs_skb_set_inner_protocol(skb, htons(ETH_P_TEB)); + ovs_skb_set_inner_protocol(skb, inner_protocol); +diff --git a/datapath/vport-netdev.c b/datapath/vport-netdev.c +index 970f7d3..0ee076b 100644 +--- a/datapath/vport-netdev.c ++++ b/datapath/vport-netdev.c +@@ -102,7 +102,8 @@ struct vport *ovs_netdev_link(struct vport *vport, const char *name) + } + if (vport->dev->flags & IFF_LOOPBACK || +- vport->dev->type != ARPHRD_ETHER || ++ (vport->dev->type != ARPHRD_ETHER && ++ vport->dev->type != ARPHRD_NONE) || + ovs_is_internal_dev(vport->dev)) { + err = -EINVAL; + goto error_put; diff --git a/datapath/vport-vxlan.c b/datapath/vport-vxlan.c -index c05f5d4..5d775cc 100644 +index 11965c0..e32c970 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) @@ -277,11 +159,80 @@ index c05f5d4..5d775cc 100644 return 0; } +diff --git a/include/openvswitch/match.h b/include/openvswitch/match.h +index 3b7f32f..93af1b8 100644 +--- a/include/openvswitch/match.h ++++ b/include/openvswitch/match.h +@@ -89,6 +89,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/include/openvswitch/meta-flow.h b/include/openvswitch/meta-flow.h +index b091c1b..9e569ef 100644 +--- a/include/openvswitch/meta-flow.h ++++ b/include/openvswitch/meta-flow.h +@@ -493,6 +493,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(200) 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(201) since v2.4. ++ * OXM: none. ++ */ ++ MFF_TUN_GPE_FLAGS, ++ + #if TUN_METADATA_NUM_OPTS == 64 + /* "tun_metadata". + * +diff --git a/include/openvswitch/packets.h b/include/openvswitch/packets.h +index 5d97309..1e82df0 100644 +--- a/include/openvswitch/packets.h ++++ b/include/openvswitch/packets.h +@@ -34,7 +34,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/lib/flow.c b/lib/flow.c -index b9ce331..d24bdc9 100644 +index ba4f8c7..375979b 100644 --- a/lib/flow.c +++ b/lib/flow.c -@@ -870,6 +870,12 @@ flow_get_metadata(const struct flow *flow, struct match *flow_metadata) +@@ -897,6 +897,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); } @@ -294,7 +245,7 @@ index b9ce331..d24bdc9 100644 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, +@@ -1292,6 +1298,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); @@ -304,10 +255,10 @@ index b9ce331..d24bdc9 100644 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 +index d78e6a1..f19648d 100644 --- a/lib/match.c +++ b/lib/match.c -@@ -289,6 +289,32 @@ match_set_tun_gbp_flags(struct match *match, uint8_t flags) +@@ -305,6 +305,32 @@ match_set_tun_gbp_flags(struct match *match, uint8_t flags) } void @@ -340,7 +291,7 @@ index fd571d9..52437c9 100644 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) +@@ -1029,6 +1055,14 @@ format_flow_tunnel(struct ds *s, const struct match *match) ds_put_format(s, "tun_gbp_flags=%#"PRIx8",", tnl->gbp_flags); } @@ -355,23 +306,8 @@ index fd571d9..52437c9 100644 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 +index d07f927..5d0721f 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) @@ -385,7 +321,7 @@ index 721152c..ab77fca 100644 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) +@@ -434,6 +438,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: @@ -394,7 +330,7 @@ index 721152c..ab77fca 100644 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, +@@ -568,6 +574,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; @@ -407,7 +343,7 @@ index 721152c..ab77fca 100644 case MFF_TUN_TTL: value->u8 = flow->tunnel.ip_ttl; break; -@@ -899,6 +911,12 @@ mf_set_value(const struct mf_field *mf, +@@ -823,6 +835,12 @@ mf_set_value(const struct mf_field *mf, case MFF_TUN_GBP_FLAGS: match_set_tun_gbp_flags(match, value->u8); break; @@ -420,7 +356,7 @@ index 721152c..ab77fca 100644 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, +@@ -1161,6 +1179,12 @@ mf_set_flow_value(const struct mf_field *mf, case MFF_TUN_GBP_FLAGS: flow->tunnel.gbp_flags = value->u8; break; @@ -433,7 +369,7 @@ index 721152c..ab77fca 100644 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) +@@ -1484,6 +1508,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; @@ -446,7 +382,7 @@ index 721152c..ab77fca 100644 case MFF_TUN_TOS: match_set_tun_tos_masked(match, 0, 0); break; -@@ -1838,6 +1868,12 @@ mf_set(const struct mf_field *mf, +@@ -1793,6 +1823,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; @@ -459,50 +395,11 @@ index 721152c..ab77fca 100644 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". - * diff --git a/lib/netdev-vport.c b/lib/netdev-vport.c -index e398562..92ceec1 100644 +index ac31da6..cff0f5c 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) +@@ -526,6 +526,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); @@ -512,10 +409,10 @@ index e398562..92ceec1 100644 VLOG_WARN("%s: unknown extension '%s'", name, ext); } diff --git a/lib/nx-match.c b/lib/nx-match.c -index 9f0f452..0eecac7 100644 +index b03ccf2..65d7ee3 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, +@@ -1036,6 +1036,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); @@ -527,10 +424,10 @@ index 9f0f452..0eecac7 100644 /* Registers. */ diff --git a/lib/odp-util.c b/lib/odp-util.c -index b4689cc..7983720 100644 +index 6d29b67..b9e8aa7 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, +@@ -1755,6 +1755,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 }, @@ -538,7 +435,7 @@ index b4689cc..7983720 100644 }; 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, +@@ -1916,7 +1917,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[] = { @@ -550,7 +447,7 @@ index b4689cc..7983720 100644 }; struct nlattr *ext[ARRAY_SIZE(vxlan_opts_policy)]; -@@ -1902,6 +1906,12 @@ odp_tun_key_from_attr__(const struct nlattr *attr, +@@ -1930,6 +1934,12 @@ odp_tun_key_from_attr__(const struct nlattr *attr, tun->gbp_id = htons(gbp & 0xFFFF); tun->gbp_flags = (gbp >> 16) & 0xFF; } @@ -563,7 +460,7 @@ index b4689cc..7983720 100644 break; } -@@ -1988,6 +1998,13 @@ tun_key_to_attr(struct ofpbuf *a, const struct flow_tnl *tun_key, +@@ -2016,6 +2026,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); @@ -577,7 +474,7 @@ index b4689cc..7983720 100644 } 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, +@@ -2410,6 +2427,26 @@ format_odp_tun_vxlan_opt(const struct nlattr *attr, ds_put_cstr(ds, "),"); break; } @@ -604,7 +501,7 @@ index b4689cc..7983720 100644 default: format_unknown_key(ds, a, ma); -@@ -3670,6 +3707,40 @@ scan_vxlan_gbp(const char *s, uint32_t *key, uint32_t *mask) +@@ -3705,6 +3742,40 @@ scan_vxlan_gbp(const char *s, uint32_t *key, uint32_t *mask) } static int @@ -645,7 +542,7 @@ index b4689cc..7983720 100644 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_) +@@ -3831,6 +3902,21 @@ vxlan_gbp_to_attr(struct ofpbuf *a, const void *data_) } static void @@ -667,7 +564,7 @@ index b4689cc..7983720 100644 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, +@@ -4066,6 +4152,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); @@ -675,35 +572,20 @@ index b4689cc..7983720 100644 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 +index 6e55270..7b7f02b 100644 --- a/tests/ofproto.at +++ b/tests/ofproto.at -@@ -1775,7 +1775,7 @@ head_table () { +@@ -2190,7 +2190,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 + metadata in_port in_port_oxm pkt_mark ct_mark ct_label reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 reg9 reg10 reg11 reg12 reg13 reg14 reg15 xreg0 xreg1 xreg2 xreg3 xreg4 xreg5 xreg6 xreg7 xxreg0 xxreg1 xxreg2 xxreg3 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 +@@ -2205,6 +2205,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 @@ -713,7 +595,7 @@ index fbb6d71..6c7217d 100644 tun_metadata1: arbitrary mask tun_metadata2: arbitrary mask diff --git a/tests/ovs-ofctl.at b/tests/ovs-ofctl.at -index f26f622..dde603d 100644 +index cbb818e..2267be0 100644 --- a/tests/ovs-ofctl.at +++ b/tests/ovs-ofctl.at @@ -17,6 +17,10 @@ for test_case in \ @@ -728,5 +610,5 @@ index f26f622..dde603d 100644 'tun_metadata0=0/0x1 NXM,OXM' \ 'tun_metadata0 NXM,OXM' \ -- -1.9.3 +2.1.0 diff --git a/ovs_build/patches/0002-ovs-nsh-support-push-and-pop-actions-for-vxlan-gpe-a.patch b/ovs_build/ovs_nsh_patches/v2.6.1/0002-Add-NSH-support-in-kernel-and-userspace-data-planes.patch similarity index 56% rename from ovs_build/patches/0002-ovs-nsh-support-push-and-pop-actions-for-vxlan-gpe-a.patch rename to ovs_build/ovs_nsh_patches/v2.6.1/0002-Add-NSH-support-in-kernel-and-userspace-data-planes.patch index 24f8e59..f22e8de 100644 --- a/ovs_build/patches/0002-ovs-nsh-support-push-and-pop-actions-for-vxlan-gpe-a.patch +++ b/ovs_build/ovs_nsh_patches/v2.6.1/0002-Add-NSH-support-in-kernel-and-userspace-data-planes.patch @@ -1,57 +1,68 @@ -From bd251cb247ac44e4362215da826e9bf1d6c61f27 Mon Sep 17 00:00:00 2001 +From 653c2f6777a6c4f3559a55c8f5a88f4aca313788 Mon Sep 17 00:00:00 2001 From: Yi Yang -Date: Wed, 13 Apr 2016 11:15:42 +0800 -Subject: [PATCH 2/6] ovs-nsh: support push and pop actions for vxlan-gpe and - Ethernet nsh +Date: Mon, 14 Nov 2016 12:08:14 +0800 +Subject: [PATCH 2/8] Add NSH support in kernel and userspace data planes + +features includes: + * push_nsh and pop_nsh actions + * support Ethernet+NSH and VxLAN-gpe+NSH + * support the same features in DPDK netdev + * news match fields: nsp, nsi, nshc1, nshc2, nshc3, nshc4, nsh_mdtype, + nsh_np, encap_eth_src, encap_eth_dst, encap_eth_type, gpe_np -Signed-off-by: Mengke Liu -Signed-off-by: Ricky Li -Signed-off-by: Johnson Li Signed-off-by: Yi Yang --- - datapath/actions.c | 73 ++++ + datapath/actions.c | 39 +++ datapath/datapath.h | 2 + - datapath/flow.c | 107 ++++++ - datapath/flow.h | 15 + - datapath/flow_netlink.c | 81 ++++- - datapath/linux/compat/include/linux/openvswitch.h | 174 +++++++++ - datapath/linux/compat/include/net/vxlan.h | 5 +- - lib/dpif-netdev.c | 4 + - lib/dpif.c | 4 + - lib/flow.c | 19 + - lib/flow.h | 21 +- - lib/match.c | 190 ++++++++++ - lib/match.h | 24 ++ - lib/meta-flow.c | 256 ++++++++++++- - lib/meta-flow.h | 174 +++++++++ + datapath/flow.c | 101 +++++++ + datapath/flow.h | 1 + + datapath/flow_netlink.c | 59 +++- + datapath/linux/compat/include/linux/openvswitch.h | 166 ++++++++++++ + include/openvswitch/automake.mk | 3 +- + include/openvswitch/flow.h | 19 +- + include/openvswitch/match.h | 24 ++ + include/openvswitch/meta-flow.h | 174 ++++++++++++ + include/openvswitch/ofp-actions.h | 4 + + include/openvswitch/vxlangpe.h | 76 ++++++ + lib/dpif-netdev.c | 39 ++- + lib/dpif.c | 2 + + lib/flow.c | 106 +++++++- + lib/match.c | 189 +++++++++++++ + lib/meta-flow.c | 256 +++++++++++++++++- + lib/netdev-native-tnl.c | 91 ++++++- lib/netdev-vport.c | 10 +- - lib/nx-match.c | 19 + - lib/odp-execute.c | 10 + - lib/odp-util.c | 417 +++++++++++++++++++++- - lib/odp-util.h | 10 +- - lib/ofp-actions.c | 154 +++++++- - lib/ofp-actions.h | 6 + - ofproto/ofproto-dpif-sflow.c | 2 + - ofproto/ofproto-dpif-upcall.c | 19 + - ofproto/ofproto-dpif-xlate.c | 22 ++ - tests/ofproto.at | 13 +- - tests/tunnel.at | 157 ++++++++ - 27 files changed, 1976 insertions(+), 12 deletions(-) + lib/netdev-vport.h | 6 + + lib/nx-match.c | 18 ++ + lib/odp-execute.c | 19 ++ + lib/odp-util.c | 279 ++++++++++++++++++- + lib/odp-util.h | 6 +- + lib/ofp-actions.c | 80 +++++- + lib/packets.c | 23 ++ + lib/packets.h | 3 + + ofproto/ofproto-dpif-sflow.c | 1 + + ofproto/ofproto-dpif-upcall.c | 11 + + ofproto/ofproto-dpif-xlate.c | 13 + + ofproto/ofproto-dpif.h | 1 - + ofproto/tunnel.c | 1 + + tests/ofproto.at | 12 +- + tests/tunnel.at | 316 ++++++++++++++++++++++ + 34 files changed, 2115 insertions(+), 35 deletions(-) + create mode 100644 include/openvswitch/vxlangpe.h diff --git a/datapath/actions.c b/datapath/actions.c -index dcf8591..16fc58f 100644 +index 82833d0..c979596 100644 --- a/datapath/actions.c +++ b/datapath/actions.c -@@ -252,6 +252,63 @@ static int push_vlan(struct sk_buff *skb, struct sw_flow_key *key, +@@ -265,6 +265,37 @@ static int push_vlan(struct sk_buff *skb, struct sw_flow_key *key, ntohs(vlan->vlan_tci) & ~VLAN_TAG_PRESENT); } +static int pop_nsh(struct sk_buff *skb, struct sw_flow_key *key) +{ -+ if (!pskb_may_pull(skb, NSH_M_TYPE1_LEN)) ++ if (!pskb_may_pull(skb, ETH_NSH_TYPE1_HEADER_SIZE)) + return -ENOMEM; + else -+ __skb_pull(skb, NSH_M_TYPE1_LEN); ++ __skb_pull(skb, ETH_NSH_TYPE1_HEADER_SIZE); + + return 0; +} @@ -61,52 +72,26 @@ index dcf8591..16fc58f 100644 +{ + + if (nsh->nsh_mdtype == NSH_M_TYPE1) { -+ if (skb_cow_head(skb, NSH_M_TYPE1_LEN) < 0) -+ return -ENOMEM; -+ -+ skb_push(skb, NSH_M_TYPE1_LEN); -+ OVS_CB(skb)->nsh_header = skb->data; -+ memcpy(OVS_CB(skb)->nsh_header, nsh->header, NSH_M_TYPE1_LEN); -+ } -+ else -+ return -EINVAL; -+ -+ return 0; -+} -+ -+static int pop_eth(struct sk_buff *skb, struct sw_flow_key *key) -+{ -+ if (!pskb_may_pull(skb, ENCAP_ETH_PUSH_HEADER_SIZE)) -+ return -ENOMEM; -+ else -+ __skb_pull(skb, ENCAP_ETH_PUSH_HEADER_SIZE); -+ -+ return 0; -+} -+ -+static int push_eth(struct sk_buff *skb, struct sw_flow_key *key, -+ const struct ovs_action_push_eth *encap_eth) -+{ -+ if (encap_eth->encap_eth_type == htons(ETH_P_NSH)) { -+ if (skb_cow_head(skb, ENCAP_ETH_PUSH_HEADER_SIZE) < 0) ++ if (skb_cow_head(skb, ETH_NSH_TYPE1_HEADER_SIZE) < 0) { + return -ENOMEM; ++ } + -+ skb_push(skb, ENCAP_ETH_PUSH_HEADER_SIZE); -+ OVS_CB(skb)->encap_eth_header = skb->data; -+ memcpy(OVS_CB(skb)->encap_eth_header, encap_eth->header, ENCAP_ETH_PUSH_HEADER_SIZE); ++ skb_push(skb, ETH_NSH_TYPE1_HEADER_SIZE); ++ OVS_CB(skb)->encap_eth_header = (struct encap_eth_hdr *)skb->data; ++ OVS_CB(skb)->nsh_header = (struct nsh_hdr *)(skb->data + ENCAP_ETH_LEN); ++ memcpy(skb->data, nsh->header, ETH_NSH_TYPE1_HEADER_SIZE); ++ OVS_CB(skb)->encap_eth_header->encap_eth_type = htons(ETH_P_NSH); + } -+ else { ++ else + return -EINVAL; -+ } + + return 0; +} -+ + /* 'src' is already properly masked. */ static void ether_addr_copy_masked(u8 *dst_, const u8 *src_, const u8 *mask_) { -@@ -1079,6 +1136,22 @@ static int do_execute_actions(struct datapath *dp, struct sk_buff *skb, +@@ -1140,6 +1171,14 @@ static int do_execute_actions(struct datapath *dp, struct sk_buff *skb, err = pop_vlan(skb, key); break; @@ -117,33 +102,25 @@ index dcf8591..16fc58f 100644 + case OVS_ACTION_ATTR_POP_NSH: + err = pop_nsh(skb, key); + break; -+ -+ case OVS_ACTION_ATTR_PUSH_ETH: -+ err = push_eth(skb, key, nla_data(a)); -+ break; -+ -+ case OVS_ACTION_ATTR_POP_ETH: -+ err = pop_eth(skb, key); -+ break; + case OVS_ACTION_ATTR_RECIRC: err = execute_recirc(dp, skb, key, a, rem); if (nla_is_last(a, rem)) { diff --git a/datapath/datapath.h b/datapath/datapath.h -index ceb3372..b2d5fcd 100644 +index 22bbaac..a6b2a44 100644 --- a/datapath/datapath.h +++ b/datapath/datapath.h -@@ -102,6 +102,8 @@ struct datapath { - struct ovs_skb_cb { +@@ -108,6 +108,8 @@ struct ovs_skb_cb { struct vport *input_vport; u16 mru; -+ struct nsh_hdr *nsh_header; -+ struct encap_eth_hdr *encap_eth_header; + u32 cutlen; ++ struct nsh_hdr *nsh_header; ++ struct encap_eth_hdr *encap_eth_header; }; #define OVS_CB(skb) ((struct ovs_skb_cb *)(skb)->cb) diff --git a/datapath/flow.c b/datapath/flow.c -index c97c9c9..67b2f1d 100644 +index 390286c..8c4d583 100644 --- a/datapath/flow.c +++ b/datapath/flow.c @@ -44,6 +44,7 @@ @@ -154,13 +131,17 @@ index c97c9c9..67b2f1d 100644 #include "datapath.h" #include "conntrack.h" -@@ -318,6 +319,32 @@ static int parse_vlan(struct sk_buff *skb, struct sw_flow_key *key) +@@ -323,6 +324,26 @@ static int parse_vlan(struct sk_buff *skb, struct sw_flow_key *key) return 0; } +static int parse_nsh(struct sk_buff *skb, struct sw_flow_key *key){ -+ struct nsh_hdr *nsh_hdr = (struct nsh_hdr *)skb->data; ++ struct nsh_hdr *nsh_hdr = NULL; ++ ++ OVS_CB(skb)->encap_eth_header = (struct encap_eth_hdr *)skb->data; ++ nsh_hdr = (struct nsh_hdr *)((const char *)skb->data + ENCAP_ETH_LEN); + OVS_CB(skb)->nsh_header = nsh_hdr; ++ memcpy(&key->nsh.encap_eth_dst, skb->data, ENCAP_ETH_LEN); + key->nsh.nsh_mdtype = nsh_hdr->base.mdtype; + if (key->nsh.nsh_mdtype != NSH_M_TYPE1) + return -EPERM; @@ -173,59 +154,47 @@ index c97c9c9..67b2f1d 100644 + key->nsh.nshc4 = nsh_hdr->ctx.nshc4; + return 0; +} -+ -+static void parse_encap_eth(struct sk_buff *skb, struct sw_flow_key *key){ -+ struct encap_eth_hdr *encap_eth_header = (struct encap_eth_hdr *)skb->data; -+ OVS_CB(skb)->encap_eth_header = encap_eth_header; -+ key->encap_eth.encap_eth_type = encap_eth_header->encap_eth_type; -+ ether_addr_copy(key->encap_eth.encap_eth_src, encap_eth_header->encap_eth_src); -+ ether_addr_copy(key->encap_eth.encap_eth_dst, encap_eth_header->encap_eth_dst); -+ -+ return; -+} + static __be16 parse_ethertype(struct sk_buff *skb) { struct llc_snap_hdr { -@@ -457,6 +484,24 @@ static int key_extract(struct sk_buff *skb, struct sw_flow_key *key) +@@ -461,6 +482,22 @@ static int key_extract(struct sk_buff *skb, struct sw_flow_key *key) + { int error; struct ethhdr *eth; - ++ int is_eth_nsh = 0; ++ + /* Extract ethernet+nsh if ethernet type is 0x894F */ + eth = (struct ethhdr *)skb->data; + if (eth->h_proto == htons(ETH_P_NSH)) { -+ parse_encap_eth(skb, key); -+ __skb_pull(skb, ENCAP_ETH_LEN); -+ + if (unlikely(parse_nsh(skb, key))) + return -EINVAL; + if (key->nsh.nsh_mdtype == NSH_M_TYPE1 && key->nsh.nsh_np == NSH_P_ETHERNET) { -+ __skb_pull(skb, NSH_M_TYPE1_LEN); ++ __skb_pull(skb, ENCAP_ETH_LEN + NSH_M_TYPE1_LEN); ++ is_eth_nsh = 1; + } else { + return -EINVAL; + } + } else { -+ void *encap_eth_hdr = &(key->encap_eth); -+ memset(encap_eth_hdr, 0, ENCAP_ETH_LEN); ++ memset(&key->nsh, 0, sizeof(key->nsh)); + } -+ + /* Flags are always used as part of stats */ key->tp.flags = 0; - -@@ -676,11 +721,54 @@ static int key_extract(struct sk_buff *skb, struct sw_flow_key *key) +@@ -685,11 +722,56 @@ static int key_extract(struct sk_buff *skb, struct sw_flow_key *key) } } } + -+ if (key->encap_eth.encap_eth_type == htons(ETH_P_NSH)) ++ if (is_eth_nsh == 1) { + __skb_push(skb, ENCAP_ETH_LEN + NSH_M_TYPE1_LEN); ++ } + -+ return 0; -+} -+ -+static void ovs_key_nsh_init(struct sw_flow_key *key, __u16 len) { -+ void *nsh_hdr = &(key->nsh); -+ memset(nsh_hdr, 0, len); + return 0; + } + ++static void ovs_key_nsh_init(struct sw_flow_key *key) { ++ memset(&key->nsh, 0, sizeof(key->nsh)); +} + +static int nsh_extract(struct sk_buff *skb, struct sw_flow_key *key) { @@ -235,98 +204,86 @@ index c97c9c9..67b2f1d 100644 + if (unlikely(parse_nsh(skb, key))) + return -EINVAL; + if (key->nsh.nsh_mdtype == NSH_M_TYPE1) { -+ __skb_pull(skb, NSH_M_TYPE1_LEN); ++ __skb_pull(skb, ENCAP_ETH_LEN + NSH_M_TYPE1_LEN); + if(key->nsh.nsh_np == NSH_P_ETHERNET) + ret = key_extract(skb, key); + else + return -EINVAL; -+ __skb_push(skb, NSH_M_TYPE1_LEN); ++ __skb_push(skb, ENCAP_ETH_LEN + NSH_M_TYPE1_LEN); + + return ret; + } else { -+ ovs_key_nsh_init(key, NSH_M_TYPE1_LEN); ++ ovs_key_nsh_init(key); + } + - return 0; - } - -+static bool is_nsh_header(const void *tun_opts, __be16 tun_flags) { -+ struct vxlan_metadata *md = NULL; -+ if (tun_opts && (tun_flags & TUNNEL_VXLAN_OPT)) -+ md = (struct vxlan_metadata *)tun_opts; ++ return 0; ++} + -+ if (md && (md->gpe & VXLAN_GPE_NP_MASK) == VXLAN_GPE_NP_NSH) ++static bool is_nsh_header(const void *tun_opts, __be16 tun_flags, struct sk_buff *skb) { ++ if (tun_opts && (tun_flags & TUNNEL_VXLAN_OPT)) { ++ /* ethernet+nsh if ethernet type is 0x894F */ ++ struct ethhdr * eth = (struct ethhdr *)skb->data; ++ if (eth->h_proto == htons(ETH_P_NSH)) { + return true; -+ else ++ } else { + return false; ++ } ++ } ++ return false; +} + int ovs_flow_key_update(struct sk_buff *skb, struct sw_flow_key *key) { -+ ovs_key_nsh_init(key, NSH_M_TYPE1_LEN); ++ ovs_key_nsh_init(key); return key_extract(skb, key); } -@@ -715,6 +803,15 @@ int ovs_flow_key_extract(const struct ip_tunnel_info *tun_info, +@@ -723,6 +805,15 @@ int ovs_flow_key_extract(const struct ip_tunnel_info *tun_info, key->ovs_flow_hash = 0; key->recirc_id = 0; + /* Extract NSH and inner Ethernet if NSH header exists */ -+ if (tun_info && is_nsh_header(ip_tunnel_info_opts(tun_info), key->tun_key.tun_flags)) { ++ if (tun_info && is_nsh_header(TUN_METADATA_OPTS(key, key->tun_opts_len), key->tun_key.tun_flags, skb)) { + int ret ; + ret = nsh_extract(skb, key); + if (key->nsh.nsh_mdtype) + return ret; + } else { -+ ovs_key_nsh_init(key, NSH_M_TYPE1_LEN); ++ ovs_key_nsh_init(key); + } return key_extract(skb, key); } -@@ -729,5 +826,15 @@ int ovs_flow_key_extract_userspace(struct net *net, const struct nlattr *attr, +@@ -739,5 +830,15 @@ int ovs_flow_key_extract_userspace(struct net *net, const struct nlattr *attr, if (err) return err; + /* Extract NSH and inner Ethernet if NSH header exists */ -+ if (key && is_nsh_header(key->tun_opts, key->tun_key.tun_flags)) { ++ if (key && is_nsh_header(key->tun_opts, key->tun_key.tun_flags, skb)) { + int ret ; + ret = nsh_extract(skb, key); + if (key->nsh.nsh_mdtype) + return ret; + } else { -+ ovs_key_nsh_init(key, NSH_M_TYPE1_LEN); ++ ovs_key_nsh_init(key); + } + return key_extract(skb, key); } diff --git a/datapath/flow.h b/datapath/flow.h -index c0b628a..c8ccd5f 100644 +index 2dd0696..bfe3423 100644 --- a/datapath/flow.h +++ b/datapath/flow.h -@@ -63,6 +63,21 @@ struct sw_flow_key { - u32 skb_mark; /* SKB mark. */ +@@ -64,6 +64,7 @@ struct sw_flow_key { u16 in_port; /* Input switch port (or DP_MAX_PORTS). */ } __packed phy; /* Safe when right after 'tun_key'. */ -+ struct { -+ u32 nshc1; /* NSH context C1-C4 */ -+ u32 nshc2; -+ u32 nshc3; -+ u32 nshc4; -+ u32 nsp; /* NSH path id */ -+ u8 nsi; /* NSH index */ -+ u8 nsh_mdtype; /* NSH metadata type */ -+ u8 nsh_np; /* NSH next protocol */ -+ }__packed nsh; /* network service header */ -+ struct { -+ u8 encap_eth_src[ETH_ALEN]; /* ENCAP ethernet source address. */ -+ u8 encap_eth_dst[ETH_ALEN]; /* ENCAP ethernet destination address. */ -+ u16 encap_eth_type; /* ENCAP ethernet type. */ -+ } encap_eth; + u8 tun_proto; /* Protocol of encapsulating tunnel. */ ++ struct ovs_key_nsh nsh; /* network service header */ u32 ovs_flow_hash; /* Datapath computed hash value. */ u32 recirc_id; /* Recirculation ID. */ struct { diff --git a/datapath/flow_netlink.c b/datapath/flow_netlink.c -index 351a504..ebfae37 100644 +index 2dcae07..6952380 100644 --- a/datapath/flow_netlink.c +++ b/datapath/flow_netlink.c @@ -284,7 +284,7 @@ size_t ovs_key_attr_size(void) @@ -334,72 +291,63 @@ index 351a504..ebfae37 100644 * updating this function. */ - BUILD_BUG_ON(OVS_KEY_ATTR_TUNNEL_INFO != 26); -+ BUILD_BUG_ON(OVS_KEY_ATTR_TUNNEL_INFO != 28); ++ BUILD_BUG_ON(OVS_KEY_ATTR_TUNNEL_INFO != 27); return nla_total_size(4) /* OVS_KEY_ATTR_PRIORITY */ + nla_total_size(0) /* OVS_KEY_ATTR_TUNNEL */ -@@ -297,6 +297,8 @@ size_t ovs_key_attr_size(void) +@@ -297,6 +297,7 @@ size_t ovs_key_attr_size(void) + nla_total_size(2) /* OVS_KEY_ATTR_CT_ZONE */ + nla_total_size(4) /* OVS_KEY_ATTR_CT_MARK */ + nla_total_size(16) /* OVS_KEY_ATTR_CT_LABELS */ -+ + nla_total_size(24) /* OVS_KEY_ATTR_NSH */ -+ + nla_total_size(14) /* OVS_KEY_ATTR_ENCAP_ETH */ ++ + nla_total_size(40) /* OVS_KEY_ATTR_NSH */ + nla_total_size(12) /* OVS_KEY_ATTR_ETHERNET */ + nla_total_size(2) /* OVS_KEY_ATTR_ETHERTYPE */ + nla_total_size(4) /* OVS_KEY_ATTR_VLAN */ -@@ -334,6 +336,8 @@ static const struct ovs_len_tbl ovs_key_lens[OVS_KEY_ATTR_MAX + 1] = { +@@ -336,6 +337,7 @@ static const struct ovs_len_tbl ovs_key_lens[OVS_KEY_ATTR_MAX + 1] = { [OVS_KEY_ATTR_PRIORITY] = { .len = sizeof(u32) }, [OVS_KEY_ATTR_IN_PORT] = { .len = sizeof(u32) }, [OVS_KEY_ATTR_SKB_MARK] = { .len = sizeof(u32) }, + [OVS_KEY_ATTR_NSH] = { .len = sizeof(struct ovs_key_nsh) }, -+ [OVS_KEY_ATTR_ENCAP_ETH] = { .len = sizeof(struct ovs_key_encap_eth) }, [OVS_KEY_ATTR_ETHERNET] = { .len = sizeof(struct ovs_key_ethernet) }, [OVS_KEY_ATTR_VLAN] = { .len = sizeof(__be16) }, [OVS_KEY_ATTR_ETHERTYPE] = { .len = sizeof(__be16) }, -@@ -869,6 +873,42 @@ static int ovs_key_from_nlattrs(struct net *net, struct sw_flow_match *match, +@@ -919,6 +921,35 @@ static int ovs_key_from_nlattrs(struct net *net, struct sw_flow_match *match, if (err) return err; + if (attrs & (1ULL << OVS_KEY_ATTR_NSH)) { + const struct ovs_key_nsh *nsh_key; + -+ nsh_key = nla_data(a[OVS_KEY_ATTR_NSH]); -+ SW_FLOW_KEY_PUT(match, nsh.nshc1, ++ nsh_key = nla_data(a[OVS_KEY_ATTR_NSH]); ++ SW_FLOW_KEY_MEMCPY(match, nsh.encap_eth_src, ++ nsh_key->encap_eth_src, ETH_ALEN, is_mask); ++ SW_FLOW_KEY_MEMCPY(match, nsh.encap_eth_dst, ++ nsh_key->encap_eth_dst, ETH_ALEN, is_mask); ++ SW_FLOW_KEY_PUT(match, nsh.encap_eth_type, ++ nsh_key->encap_eth_type, is_mask); ++ SW_FLOW_KEY_PUT(match, nsh.nshc1, + nsh_key->nshc1, is_mask); -+ SW_FLOW_KEY_PUT(match, nsh.nshc2, ++ SW_FLOW_KEY_PUT(match, nsh.nshc2, + nsh_key->nshc2, is_mask); -+ SW_FLOW_KEY_PUT(match, nsh.nshc3, ++ SW_FLOW_KEY_PUT(match, nsh.nshc3, + nsh_key->nshc3, is_mask); -+ SW_FLOW_KEY_PUT(match, nsh.nshc4, ++ SW_FLOW_KEY_PUT(match, nsh.nshc4, + nsh_key->nshc4, is_mask); -+ SW_FLOW_KEY_PUT(match, nsh.nsh_mdtype, ++ SW_FLOW_KEY_PUT(match, nsh.nsh_mdtype, + nsh_key->nsh_mdtype, is_mask); -+ SW_FLOW_KEY_PUT(match, nsh.nsh_np, ++ SW_FLOW_KEY_PUT(match, nsh.nsh_np, + nsh_key->nsh_np, is_mask); -+ SW_FLOW_KEY_PUT(match, nsh.nsp, ++ SW_FLOW_KEY_PUT(match, nsh.nsp, + nsh_key->nsp, is_mask); -+ SW_FLOW_KEY_PUT(match, nsh.nsi, ++ SW_FLOW_KEY_PUT(match, nsh.nsi, + nsh_key->nsi, is_mask); + attrs &= ~(1ULL << OVS_KEY_ATTR_NSH); + } -+ -+ if (attrs & (1ULL << OVS_KEY_ATTR_ENCAP_ETH)) { -+ const struct ovs_key_encap_eth *encap_eth_key; -+ -+ encap_eth_key = nla_data(a[OVS_KEY_ATTR_ENCAP_ETH]); -+ SW_FLOW_KEY_MEMCPY(match, encap_eth.encap_eth_src, -+ encap_eth_key->encap_eth_src, ETH_ALEN, is_mask); -+ SW_FLOW_KEY_MEMCPY(match, encap_eth.encap_eth_dst, -+ encap_eth_key->encap_eth_dst, ETH_ALEN, is_mask); -+ SW_FLOW_KEY_PUT(match, encap_eth.encap_eth_type, -+ encap_eth_key->encap_eth_type, is_mask); -+ attrs &= ~(1ULL << OVS_KEY_ATTR_ENCAP_ETH); -+ } + if (attrs & (1ULL << OVS_KEY_ATTR_ETHERNET)) { const struct ovs_key_ethernet *eth_key; -@@ -1386,6 +1426,35 @@ static int __ovs_nla_put_key(const struct sw_flow_key *swkey, +@@ -1434,6 +1465,26 @@ static int __ovs_nla_put_key(const struct sw_flow_key *swkey, if (nla_put_u32(skb, OVS_KEY_ATTR_PRIORITY, output->phy.priority)) goto nla_put_failure; @@ -410,6 +358,9 @@ index 351a504..ebfae37 100644 + if (!nla) + goto nla_put_failure; + nsh_key = nla_data(nla); ++ memcpy(nsh_key->encap_eth_dst, output->nsh.encap_eth_dst, ETH_ALEN); ++ memcpy(nsh_key->encap_eth_src, output->nsh.encap_eth_src, ETH_ALEN); ++ nsh_key->encap_eth_type = output->nsh.encap_eth_type; + nsh_key->nsi = output->nsh.nsi; + nsh_key->nsp = output->nsh.nsp; + nsh_key->nsh_mdtype= output->nsh.nsh_mdtype; @@ -420,47 +371,31 @@ index 351a504..ebfae37 100644 + nsh_key->nshc4 = output->nsh.nshc4; + } + -+ if ((swkey->encap_eth.encap_eth_type || is_mask)) { -+ struct ovs_key_encap_eth *encap_eth_key; -+ -+ nla = nla_reserve(skb, OVS_KEY_ATTR_ENCAP_ETH, sizeof(*encap_eth_key)); -+ if (!nla) -+ goto nla_put_failure; -+ encap_eth_key = nla_data(nla); -+ memcpy(encap_eth_key->encap_eth_src, output->encap_eth.encap_eth_src, ETH_ALEN); -+ memcpy(encap_eth_key->encap_eth_dst, output->encap_eth.encap_eth_dst, ETH_ALEN); -+ encap_eth_key->encap_eth_type= output->encap_eth.encap_eth_type; -+ } -+ - if ((swkey->tun_key.u.ipv4.dst || is_mask)) { + if ((swkey->tun_proto || is_mask)) { const void *opts = NULL; -@@ -2182,6 +2251,10 @@ static int __ovs_nla_copy_actions(struct net *net, const struct nlattr *attr, +@@ -2235,6 +2286,8 @@ static int __ovs_nla_copy_actions(struct net *net, const struct nlattr *attr, [OVS_ACTION_ATTR_POP_MPLS] = sizeof(__be16), [OVS_ACTION_ATTR_PUSH_VLAN] = sizeof(struct ovs_action_push_vlan), [OVS_ACTION_ATTR_POP_VLAN] = 0, + [OVS_ACTION_ATTR_PUSH_NSH] = sizeof(struct ovs_action_push_nsh), + [OVS_ACTION_ATTR_POP_NSH] = 0, -+ [OVS_ACTION_ATTR_PUSH_ETH] = sizeof(struct ovs_action_push_eth), -+ [OVS_ACTION_ATTR_POP_ETH] = 0, [OVS_ACTION_ATTR_SET] = (u32)-1, [OVS_ACTION_ATTR_SET_MASKED] = (u32)-1, [OVS_ACTION_ATTR_SAMPLE] = (u32)-1, -@@ -2226,6 +2299,12 @@ static int __ovs_nla_copy_actions(struct net *net, const struct nlattr *attr, +@@ -2288,6 +2341,10 @@ static int __ovs_nla_copy_actions(struct net *net, const struct nlattr *attr, break; } + case OVS_ACTION_ATTR_PUSH_NSH: + case OVS_ACTION_ATTR_POP_NSH: -+ case OVS_ACTION_ATTR_PUSH_ETH: -+ case OVS_ACTION_ATTR_POP_ETH: + break; + case OVS_ACTION_ATTR_POP_VLAN: vlan_tci = htons(0); break; diff --git a/datapath/linux/compat/include/linux/openvswitch.h b/datapath/linux/compat/include/linux/openvswitch.h -index 44adb81..187bb9b 100644 +index 44b7ce4..090843a 100644 --- a/datapath/linux/compat/include/linux/openvswitch.h +++ b/datapath/linux/compat/include/linux/openvswitch.h @@ -42,6 +42,7 @@ @@ -471,42 +406,38 @@ index 44adb81..187bb9b 100644 /** * struct ovs_header - header for OVS Generic Netlink messages. -@@ -328,6 +329,9 @@ enum ovs_key_attr { +@@ -332,6 +333,7 @@ enum ovs_key_attr { OVS_KEY_ATTR_ENCAP, /* Nested set of encapsulated attributes. */ OVS_KEY_ATTR_PRIORITY, /* u32 skb->priority */ OVS_KEY_ATTR_IN_PORT, /* u32 OVS dp port number */ -+ OVS_KEY_ATTR_NSH, /* struct ovs_key_nsh. Only support NSH MD -+ type 1 now */ -+ OVS_KEY_ATTR_ENCAP_ETH, /* struct ovs_key_encap_eth */ ++ OVS_KEY_ATTR_NSH, /* struct ovs_key_nsh, MD type 1 only */ OVS_KEY_ATTR_ETHERNET, /* struct ovs_key_ethernet */ OVS_KEY_ATTR_VLAN, /* be16 VLAN TCI */ OVS_KEY_ATTR_ETHERTYPE, /* be16 Ethernet type */ -@@ -401,6 +405,24 @@ enum ovs_frag_type { +@@ -406,6 +408,22 @@ enum ovs_frag_type { #define OVS_FRAG_TYPE_MAX (__OVS_FRAG_TYPE_MAX - 1) +struct ovs_key_nsh { -+ __u32 nshc1; -+ __u32 nshc2; -+ __u32 nshc3; -+ __u32 nshc4; -+ __u32 nsp; -+ __u8 nsi; -+ __u8 nsh_mdtype; -+ __u8 nsh_np; -+ __u8 reserved; -+}; -+ -+struct ovs_key_encap_eth { -+ __u8 encap_eth_src[ETH_ALEN]; -+ __u8 encap_eth_dst[ETH_ALEN]; -+ __u16 encap_eth_type; -+}; ++ __u8 encap_eth_dst[ETH_ALEN]; ++ __u8 encap_eth_src[ETH_ALEN]; ++ __u16 encap_eth_type; ++ __u16 pad1; ++ __u32 nshc1; ++ __u32 nshc2; ++ __u32 nshc3; ++ __u32 nshc4; ++ __u32 nsp; ++ __u8 nsi; ++ __u8 nsh_mdtype; ++ __u8 nsh_np; ++ __u8 pad2; ++} __packed; + struct ovs_key_ethernet { __u8 eth_src[ETH_ALEN]; __u8 eth_dst[ETH_ALEN]; -@@ -630,6 +652,154 @@ struct ovs_action_push_vlan { +@@ -640,6 +658,151 @@ struct ovs_action_push_vlan { __be16 vlan_tci; /* 802.1Q TCI (VLAN ID and priority). */ }; @@ -627,6 +558,7 @@ index 44adb81..187bb9b 100644 + +#define ENCAP_ETH_LEN 14 + ++#define ETH_NSH_TYPE1_HEADER_SIZE (NSH_PUSH_TYPE1_HEADER_SIZE + ENCAP_ETH_LEN) +/** + * struct encap_eth - encap ethernet header for ethernet NSH + * @encap_eth_src: encap ethernet source address. @@ -639,6 +571,11 @@ index 44adb81..187bb9b 100644 + __u16 encap_eth_type; +}; + ++struct eth_nsh_hdr { ++ struct encap_eth_hdr encap_eth_header; ++ struct nsh_hdr nsh_hdr __attribute__((packed)); ++}; ++ +#define ENCAP_ETH_PUSH_HEADER_SIZE 14 +/** + * struct ovs_action_push_nsh - %OVS_ACTION_ATTR_PUSH_NSH action argument. @@ -648,122 +585,52 @@ index 44adb81..187bb9b 100644 + uint8_t nsh_mdtype; + uint8_t header[NSH_PUSH_HEADER_SIZE]; +}; -+ -+/** -+ * struct ovs_action_push_nsh - %OVS_ACTION_ATTR_PUSH_NSH action argument. -+ * @header -+ */ -+struct ovs_action_push_eth { -+ uint16_t encap_eth_type; -+ uint8_t header[ENCAP_ETH_PUSH_HEADER_SIZE]; -+}; + /* Data path hash algorithm for computing Datapath hash. * * The algorithm type only specifies the fields in a flow -@@ -793,6 +963,10 @@ enum ovs_action_attr { +@@ -679,6 +842,7 @@ struct ovs_action_push_tnl { + uint32_t out_port; + uint32_t header_len; + uint32_t tnl_type; /* For logging. */ ++ uint32_t exts; + uint8_t header[TNL_PUSH_HEADER_SIZE]; + }; + #endif +@@ -804,6 +968,8 @@ enum ovs_action_attr { OVS_ACTION_ATTR_SET, /* One nested OVS_KEY_ATTR_*. */ OVS_ACTION_ATTR_PUSH_VLAN, /* struct ovs_action_push_vlan. */ OVS_ACTION_ATTR_POP_VLAN, /* No argument. */ + OVS_ACTION_ATTR_PUSH_NSH, /* struct ovs_action_push_nsh. */ + OVS_ACTION_ATTR_POP_NSH, /* No argument. */ -+ OVS_ACTION_ATTR_PUSH_ETH, /* struct ovs_action_push_eth. */ -+ OVS_ACTION_ATTR_POP_ETH, /* No argument. */ OVS_ACTION_ATTR_SAMPLE, /* Nested OVS_SAMPLE_ATTR_*. */ OVS_ACTION_ATTR_RECIRC, /* u32 recirc_id. */ OVS_ACTION_ATTR_HASH, /* struct ovs_action_hash. */ -diff --git a/datapath/linux/compat/include/net/vxlan.h b/datapath/linux/compat/include/net/vxlan.h -index 2bfc3f8..3aeac88 100644 ---- a/datapath/linux/compat/include/net/vxlan.h -+++ b/datapath/linux/compat/include/net/vxlan.h -@@ -85,7 +85,7 @@ struct vxlanhdr_gbp { - #define VXLAN_GBP_ID_MASK (0xFFFF) +diff --git a/include/openvswitch/automake.mk b/include/openvswitch/automake.mk +index c0e276f..732b775 100644 +--- a/include/openvswitch/automake.mk ++++ b/include/openvswitch/automake.mk +@@ -29,5 +29,6 @@ openvswitchinclude_HEADERS = \ + include/openvswitch/uuid.h \ + include/openvswitch/version.h \ + include/openvswitch/vconn.h \ +- include/openvswitch/vlog.h ++ include/openvswitch/vlog.h \ ++ include/openvswitch/vxlangpe.h - /* -- * VXLAN Generic Protocol Extension Extension: -+ * VXLAN Generic Protocol 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 | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -@@ -103,6 +103,9 @@ struct vxlanhdr_gbp { - * O = OAM Flag Bit. The O bit is set to indicate that the packet - * is an OAM packet. - * -+ * Next Protocol = This 8 bit field indicates the protocol header -+ * immediately following the VXLAN GPE header. -+ * - * [1] https://www.ietf.org/id/draft-ietf-nvo3-vxlan-gpe-01.txt - */ - -diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c -index 119dc2d..8e67bfd 100644 ---- a/lib/dpif-netdev.c -+++ b/lib/dpif-netdev.c -@@ -3874,6 +3874,10 @@ dp_execute_cb(void *aux_, struct dp_packet **packets, int cnt, - VLOG_WARN("Cannot execute conntrack action in userspace."); - break; - -+ case OVS_ACTION_ATTR_PUSH_NSH: -+ case OVS_ACTION_ATTR_POP_NSH: -+ case OVS_ACTION_ATTR_PUSH_ETH: -+ case OVS_ACTION_ATTR_POP_ETH: - case OVS_ACTION_ATTR_PUSH_VLAN: - case OVS_ACTION_ATTR_POP_VLAN: - case OVS_ACTION_ATTR_PUSH_MPLS: -diff --git a/lib/dpif.c b/lib/dpif.c -index a784de7..b5265c4 100644 ---- a/lib/dpif.c -+++ b/lib/dpif.c -@@ -1139,6 +1139,10 @@ dpif_execute_helper_cb(void *aux_, struct dp_packet **packets, int cnt, - } - - case OVS_ACTION_ATTR_HASH: -+ case OVS_ACTION_ATTR_PUSH_NSH: -+ case OVS_ACTION_ATTR_POP_NSH: -+ case OVS_ACTION_ATTR_PUSH_ETH: -+ case OVS_ACTION_ATTR_POP_ETH: - case OVS_ACTION_ATTR_PUSH_VLAN: - case OVS_ACTION_ATTR_POP_VLAN: - case OVS_ACTION_ATTR_PUSH_MPLS: -diff --git a/lib/flow.c b/lib/flow.c -index d24bdc9..fc8b98c 100644 ---- a/lib/flow.c -+++ b/lib/flow.c -@@ -1289,6 +1289,25 @@ void flow_wildcards_init_for_packet(struct flow_wildcards *wc, - WC_MASK_FIELD(wc, tunnel.tun_id); - } - -+ /* NSH fields wildcarded */ -+ if (flow->nsh_mdtype) { -+ WC_MASK_FIELD(wc, nshc1); -+ WC_MASK_FIELD(wc, nshc2); -+ WC_MASK_FIELD(wc, nshc3); -+ WC_MASK_FIELD(wc, nshc4); -+ WC_MASK_FIELD(wc, nsh_mdtype); -+ WC_MASK_FIELD(wc, nsh_np); -+ WC_MASK_FIELD(wc, nsp); -+ WC_MASK_FIELD(wc, nsi); -+ } -+ -+ /* ENCAP Eth wildcarded */ -+ if (flow->encap_eth_type) { -+ WC_MASK_FIELD(wc, encap_eth_src); -+ WC_MASK_FIELD(wc, encap_eth_dst); -+ WC_MASK_FIELD(wc, encap_eth_type); -+ } -+ - /* metadata, regs, and conj_id wildcarded. */ - - WC_MASK_FIELD(wc, skb_priority); -diff --git a/lib/flow.h b/lib/flow.h -index dc7130d..a8677b1 100644 ---- a/lib/flow.h -+++ b/lib/flow.h -@@ -111,6 +111,23 @@ struct flow { +diff --git a/include/openvswitch/flow.h b/include/openvswitch/flow.h +index df80dfe..84c7997 100644 +--- a/include/openvswitch/flow.h ++++ b/include/openvswitch/flow.h +@@ -99,6 +99,21 @@ struct flow { + uint32_t conj_id; /* Conjunction ID. */ ofp_port_t actset_output; /* Output port in action set. */ - uint8_t pad2[2]; /* Pad to 64 bits. */ -+ /* NSH (64-bit aligned) */ ++ /* ETH + NSH (64-bit aligned) */ ++ struct eth_addr encap_eth_dst; /* Encap eth destination address. */ ++ struct eth_addr encap_eth_src; /* Encap eth source address. */ ++ ovs_be16 encap_eth_type; /* Encap eth frame type. */ ++ uint8_t pad2[2]; /* Pad to 64 bits. */ + ovs_be32 nshc1; + ovs_be32 nshc2; + ovs_be32 nshc3; @@ -773,39 +640,638 @@ index dc7130d..a8677b1 100644 + uint8_t nsh_mdtype; + uint8_t nsh_np; + uint8_t pad3; -+ -+ /* ENCAP_ETH (64-bit aligned) */ -+ struct eth_addr encap_eth_src; /* Encap ethernet source address. */ -+ struct eth_addr encap_eth_dst; /* Encap ethernet destination address. */ -+ ovs_be16 encap_eth_type; /* Encap ethernet frame type. */ -+ uint8_t pad4[2]; + /* L2, Order the same as in the Ethernet header! (64-bit aligned) */ struct eth_addr dl_dst; /* Ethernet destination address. */ struct eth_addr dl_src; /* Ethernet source address. */ -@@ -132,7 +149,7 @@ struct flow { +@@ -120,7 +135,7 @@ struct flow { struct eth_addr arp_sha; /* ARP/ND source hardware address. */ struct eth_addr arp_tha; /* ARP/ND target hardware address. */ ovs_be16 tcp_flags; /* TCP flags. With L3 to avoid matching L4. */ - ovs_be16 pad3; /* Pad to 64 bits. */ -+ ovs_be16 pad5; /* Pad to 64 bits. */ ++ ovs_be16 pad4; /* Pad to 64 bits. */ /* L4 (64-bit aligned) */ ovs_be16 tp_src; /* TCP/UDP/SCTP source port/ICMP type. */ -@@ -158,7 +175,7 @@ BUILD_ASSERT_DECL(sizeof(struct flow_tnl) % sizeof(uint64_t) == 0); +@@ -135,7 +150,7 @@ BUILD_ASSERT_DECL(sizeof(struct flow_tnl) % sizeof(uint64_t) == 0); /* Remember to update FLOW_WC_SEQ when changing 'struct flow'. */ BUILD_ASSERT_DECL(offsetof(struct flow, igmp_group_ip4) + sizeof(uint32_t) -- == sizeof(struct flow_tnl) + 216 -+ == sizeof(struct flow_tnl) + 256 - && FLOW_WC_SEQ == 35); +- == sizeof(struct flow_tnl) + 248 ++ == sizeof(struct flow_tnl) + 288 + && FLOW_WC_SEQ == 36); /* Incremental points at which flow classification may be performed in +diff --git a/include/openvswitch/match.h b/include/openvswitch/match.h +index 93af1b8..c5fa48a 100644 +--- a/include/openvswitch/match.h ++++ b/include/openvswitch/match.h +@@ -168,6 +168,30 @@ void match_set_nd_target(struct match *, const struct in6_addr *); + void match_set_nd_target_masked(struct match *, const struct in6_addr *, + const struct in6_addr *); + ++void match_set_nsp_masked(struct match *, ovs_be32 nsp, ovs_be32 mask); ++void match_set_nsi_masked(struct match *match, uint8_t nsi, uint8_t mask); ++void match_set_nsh_mdtype_masked(struct match *match, uint8_t nsh_mdtype, uint8_t mask); ++void match_set_nsh_np_masked(struct match *match, uint8_t nsh_np, uint8_t mask); ++void match_set_nshc1_masked(struct match *, ovs_be32 nshc1, ovs_be32 mask); ++void match_set_nshc2_masked(struct match *, ovs_be32 nshc2, ovs_be32 mask); ++void match_set_nshc3_masked(struct match *, ovs_be32 nshc3, ovs_be32 mask); ++void match_set_nshc4_masked(struct match *, ovs_be32 nshc4, ovs_be32 mask); ++void match_set_encap_eth_src_masked(struct match *match, const struct eth_addr encap_eth_src, const struct eth_addr mask); ++void match_set_encap_eth_dst_masked(struct match *match, const struct eth_addr encap_eth_dst, const struct eth_addr mask); ++void match_set_encap_eth_type_masked(struct match *match, ovs_be16 encap_eth_type, ovs_be16 mask); ++ ++void match_set_nsp(struct match *, ovs_be32 nsp); ++void match_set_nsi(struct match *match, uint8_t nsi); ++void match_set_nsh_mdtype(struct match *match, uint8_t nsh_mdtype); ++void match_set_nsh_np(struct match *match, uint8_t nsh_np); ++void match_set_nshc1(struct match *, ovs_be32 nshc1); ++void match_set_nshc2(struct match *, ovs_be32 nshc2); ++void match_set_nshc3(struct match *, ovs_be32 nshc3); ++void match_set_nshc4(struct match *, ovs_be32 nshc4); ++void match_set_encap_eth_src(struct match *match, const struct eth_addr encap_eth_src); ++void match_set_encap_eth_dst(struct match *match, const struct eth_addr encap_eth_dst); ++void match_set_encap_eth_type(struct match *match, ovs_be16 encap_eth_type); ++ + bool match_equal(const struct match *, const struct match *); + uint32_t match_hash(const struct match *, uint32_t basis); + +diff --git a/include/openvswitch/meta-flow.h b/include/openvswitch/meta-flow.h +index 9e569ef..fa4129c 100644 +--- a/include/openvswitch/meta-flow.h ++++ b/include/openvswitch/meta-flow.h +@@ -1801,6 +1801,180 @@ enum OVS_PACKED_ENUM mf_field_id { + */ + MFF_ND_TLL, + ++ /* "nsp". ++ * ++ * For a packet received including a (32-bit) ++ * network service header service path (nsp), the nsp is stored ++ * in the low 24-bits and the high bits are zeroed. For ++ * other packets, the value is 0. ++ * ++ * Type: be32. ++ * Maskable: bitwise. ++ * Formatting: hexadecimal. ++ * Prerequisites: none. ++ * Access: read/write. ++ * NXM: NXM_NX_NSP(202) since v1.1. ++ * OXM: none. ++ * Prefix lookup member: nsp. ++ */ ++ MFF_NSP, ++ ++ /* "nsi". ++ * ++ * For a packet received, it includes a (8-bit) ++ * network service header service index (nsi). ++ * ++ * Type: u8. ++ * Maskable: bitwise. ++ * Formatting: decimal. ++ * Prerequisites: none. ++ * Access: read/write. ++ * NXM: NXM_NX_NSI(203) since v1.1. ++ * OXM: none. ++ * Prefix lookup member: nsi. ++ */ ++ MFF_NSI, ++ ++ /* "nshc1". ++ * ++ * For a packet received including a (32-bit) ++ * Network Platform Context (nshc1), the nshc1 is stored ++ * in the 32-bits. For other packets, the value is 0. ++ * ++ * Type: be32. ++ * Maskable: bitwise. ++ * Formatting: hexadecimal. ++ * Prerequisites: none. ++ * Access: read/write. ++ * NXM: NXM_NX_NSH_C1(204) since v1.1. ++ * OXM: none. ++ * Prefix lookup member: nshc1. ++ */ ++ MFF_NSH_C1, ++ ++ /* "nshc2". ++ * ++ * For a packet received including a (32-bit) ++ * Network Shared Context (nshc2), the nshc2 is stored ++ * in the 32-bits. For other packets, the value is 0. ++ * ++ * Type: be32. ++ * Maskable: bitwise. ++ * Formatting: hexadecimal. ++ * Prerequisites: none. ++ * Access: read/write. ++ * NXM: NXM_NX_NSH_C2(205) since v1.1. ++ * OXM: none. ++ * Prefix lookup member: nshc2. ++ */ ++ MFF_NSH_C2, ++ ++ /* "nshc3". ++ * ++ * For a packet received via including a (32-bit) ++ * Service Platform Context (nshc3), the nshc3 is stored ++ * in the 32-bits. For other packets, the value is 0. ++ * ++ * Type: be32. ++ * Maskable: bitwise. ++ * Formatting: hexadecimal. ++ * Prerequisites: none. ++ * Access: read/write. ++ * NXM: NXM_NX_NSH_C3(206) since v1.1. ++ * OXM: none. ++ * Prefix lookup member: nshc3. ++ */ ++ MFF_NSH_C3, ++ ++ /* "nshc4". ++ * ++ * For a packet received including a (32-bit) ++ * Service Shared Context (nshc4), the nshc4 is stored ++ * in the 32-bits. For other packets, the value is 0. ++ * ++ * Type: be32. ++ * Maskable: bitwise. ++ * Formatting: hexadecimal. ++ * Prerequisites: none. ++ * Access: read/write. ++ * NXM: NXM_NX_NSH_C4(207) since v1.1. ++ * OXM: none. ++ * Prefix lookup member: nshc4. ++ */ ++ MFF_NSH_C4, ++ ++ /* "nsh_mdtype". ++ * ++ * For a packet received, it includes a (8-bit) ++ * nsh md-type field (md-type). ++ * ++ * Type: u8. ++ * Maskable: bitwise. ++ * Formatting: decimal. ++ * Prerequisites: none. ++ * Access: read/write. ++ * NXM: NXM_NX_NSH_MDTYPE(208) since v1.1. ++ * OXM: none. ++ */ ++ MFF_NSH_MDTYPE, ++ ++ /* "nsh_np". ++ * ++ * For a packet received, it includes a (8-bit) ++ * nsh next protocol field (np). ++ * ++ * Type: u8. ++ * Maskable: bitwise. ++ * Formatting: decimal. ++ * Prerequisites: none. ++ * Access: read/write. ++ * NXM: NXM_NX_NSH_NP(209) since v1.1. ++ * OXM: none. ++ */ ++ MFF_NSH_NP, ++ ++ /* "encap_eth_src". ++ * ++ * encap eth source address for Ethernet+NSH ++ * ++ * Type: MAC. ++ * Maskable: bitwise. ++ * Formatting: Ethernet. ++ * Prerequisites: none. ++ * Access: read/write. ++ * NXM: NXM_NX_ENCAP_ETH_SRC(210) since v1.1. ++ * OXM: none. ++ */ ++ MFF_ENCAP_ETH_SRC, ++ ++ /* "encap_eth_dst". ++ * ++ * encap eth destination address for Ethernet+NSH ++ * ++ * Type: MAC. ++ * Maskable: bitwise. ++ * Formatting: Ethernet. ++ * Prerequisites: none. ++ * Access: read/write. ++ * NXM: NXM_NX_ENCAP_ETH_DST(211) since v1.1. ++ * OXM: none. ++ */ ++ MFF_ENCAP_ETH_DST, ++ ++ /* "encap_eth_type". ++ * ++ * Encap Ethernet type. ++ * ++ * Type: be16. ++ * Maskable: no. ++ * Formatting: hexadecimal. ++ * Prerequisites: none. ++ * Access: read-only. ++ * NXM: NXM_NX_ENCAP_ETH_TYPE(212) since v1.1. ++ * OXM: none. ++ */ ++ MFF_ENCAP_ETH_TYPE, ++ + MFF_N_IDS + }; + +diff --git a/include/openvswitch/ofp-actions.h b/include/openvswitch/ofp-actions.h +index 01b1790..8bef529 100644 +--- a/include/openvswitch/ofp-actions.h ++++ b/include/openvswitch/ofp-actions.h +@@ -93,6 +93,10 @@ + OFPACT(POP_QUEUE, ofpact_null, ofpact, "pop_queue") \ + OFPACT(FIN_TIMEOUT, ofpact_fin_timeout, ofpact, "fin_timeout") \ + \ ++ /* NSH */ \ ++ OFPACT(PUSH_NSH, ofpact_null, ofpact, "push_nsh") \ ++ OFPACT(POP_NSH, ofpact_null, ofpact, "pop_nsh") \ ++ \ + /* Flow table interaction. */ \ + OFPACT(RESUBMIT, ofpact_resubmit, ofpact, "resubmit") \ + OFPACT(LEARN, ofpact_learn, specs, "learn") \ +diff --git a/include/openvswitch/vxlangpe.h b/include/openvswitch/vxlangpe.h +new file mode 100644 +index 0000000..b5ab7e0 +--- /dev/null ++++ b/include/openvswitch/vxlangpe.h +@@ -0,0 +1,76 @@ ++#ifndef __OPENVSWITCH_VXLANGPE_H ++#define __OPENVSWITCH_VXLANGPE_H 1 ++ ++#include "openvswitch/types.h" ++ ++#define u8 uint8_t ++#define u32 uint8_t ++#define __be32 ovs_be32 ++ ++/* ++ * VXLAN Generic Protocol Extension (VXLAN_F_GPE): ++ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ++ * |R|R|Ver|I|P|R|O| Reserved |Next Protocol | ++ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ++ * | VXLAN Network Identifier (VNI) | Reserved | ++ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ++ * ++ * Ver = Version. Indicates VXLAN GPE protocol version. ++ * ++ * 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. ++ * ++ * Next Protocol = This 8 bit field indicates the protocol header ++ * immediately following the VXLAN GPE header. ++ * ++ * https://tools.ietf.org/html/draft-ietf-nvo3-vxlan-gpe-01 ++ */ ++ ++struct vxlanhdr_gpe { ++#ifdef WORDS_BIGENDIAN ++ u8 reserved_flags2:2, ++ version:2, ++ instance_applied:1, ++ np_applied:1, ++ reserved_flags1:1, ++ oam_flag:1; ++#else ++ u8 oam_flag:1, ++ reserved_flags1:1, ++ np_applied:1, ++ instance_applied:1, ++ version:2, ++ reserved_flags2:2; ++#endif ++ u8 reserved_flags3; ++ u8 reserved_flags4; ++ u8 next_protocol; ++ __be32 vx_vni; ++}; ++ ++/* VXLAN-GPE header flags. */ ++#define VXLAN_HF_VER ((1UL <<29) | (1UL <<28)) ++#define VXLAN_HF_NP (1UL <<26) ++#define VXLAN_HF_OAM (1UL <<24) ++ ++#define VXLAN_GPE_USED_BITS (VXLAN_HF_VER | VXLAN_HF_NP | VXLAN_HF_OAM | \ ++ 0xff) ++ ++/* 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 ++ ++struct vxlan_metadata { ++ u32 gbp; ++ u32 gpe; ++}; ++ ++#define VXLAN_F_GPE 0x4000 ++#define VXLAN_HF_GPE 0x04000000 ++ ++#endif /* __OPENVSWITCH_VXLANGPE_H */ +diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c +index 44ec1a0..c779c78 100644 +--- a/lib/dpif-netdev.c ++++ b/lib/dpif-netdev.c +@@ -533,7 +533,7 @@ static int get_port_by_name(struct dp_netdev *dp, const char *devname, + static void dp_netdev_free(struct dp_netdev *) + OVS_REQUIRES(dp_netdev_mutex); + static int do_add_port(struct dp_netdev *dp, const char *devname, +- const char *type, odp_port_t port_no) ++ const char *type, odp_port_t port_no, uint32_t exts) + OVS_REQUIRES(dp->port_mutex); + static void do_del_port(struct dp_netdev *dp, struct dp_netdev_port *) + OVS_REQUIRES(dp->port_mutex); +@@ -1010,7 +1010,7 @@ create_dp_netdev(const char *name, const struct dpif_class *class, + + error = do_add_port(dp, name, dpif_netdev_port_open_type(dp->class, + "internal"), +- ODPP_LOCAL); ++ ODPP_LOCAL, 0); + ovs_mutex_unlock(&dp->port_mutex); + if (error) { + dp_netdev_free(dp); +@@ -1213,9 +1213,21 @@ hash_port_no(odp_port_t port_no) + return hash_int(odp_to_u32(port_no), 0); + } + ++static void add_vxlan_gpe_exts(struct netdev *netdev, uint32_t exts) ++{ ++ const char *type = netdev_get_type(netdev); ++ if (!strcmp(type, "vxlan")) { ++ struct netdev_tunnel_config *cfg; ++ cfg = netdev_get_tunnel_config(netdev); ++ ++ if(exts & (1 << OVS_VXLAN_EXT_GPE)) ++ cfg->exts |= (1 << OVS_VXLAN_EXT_GPE); ++ } ++} ++ + static int + port_create(const char *devname, const char *type, +- odp_port_t port_no, struct dp_netdev_port **portp) ++ odp_port_t port_no, struct dp_netdev_port **portp, uint32_t exts) + { + struct netdev_saved_flags *sf; + struct dp_netdev_port *port; +@@ -1273,6 +1285,7 @@ port_create(const char *devname, const char *type, + } + } + ++ add_vxlan_gpe_exts(netdev, exts); + port = xzalloc(sizeof *port); + port->port_no = port_no; + port->netdev = netdev; +@@ -1321,7 +1334,7 @@ out: + + static int + do_add_port(struct dp_netdev *dp, const char *devname, const char *type, +- odp_port_t port_no) ++ odp_port_t port_no, uint32_t exts) + OVS_REQUIRES(dp->port_mutex) + { + struct dp_netdev_port *port; +@@ -1332,7 +1345,7 @@ do_add_port(struct dp_netdev *dp, const char *devname, const char *type, + return EEXIST; + } + +- error = port_create(devname, type, port_no, &port); ++ error = port_create(devname, type, port_no, &port, exts); + if (error) { + return error; + } +@@ -1373,7 +1386,12 @@ dpif_netdev_port_add(struct dpif *dpif, struct netdev *netdev, + } + if (!error) { + *port_nop = port_no; +- error = do_add_port(dp, dpif_port, netdev_get_type(netdev), port_no); ++ const struct netdev_tunnel_config *cfg; ++ uint32_t exts = 0; ++ cfg = netdev_get_tunnel_config(netdev); ++ if (cfg) ++ exts = cfg->exts; ++ error = do_add_port(dp, dpif_port, netdev_get_type(netdev), port_no, exts); + } + ovs_mutex_unlock(&dp->port_mutex); + +@@ -2148,8 +2166,11 @@ dpif_netdev_flow_from_nlattrs(const struct nlattr *key, uint32_t key_len, + struct flow *flow) + { + odp_port_t in_port; ++ enum odp_key_fitness fitness; + +- if (odp_flow_key_to_flow_udpif(key, key_len, flow)) { ++ fitness = odp_flow_key_to_flow_udpif(key, key_len, flow); ++ ++ if (fitness) { + /* This should not happen: it indicates that odp_flow_key_from_flow() + * and odp_flow_key_to_flow() disagree on the acceptable form of a + * flow. Log the problem as an error, with enough details to enable +@@ -2161,7 +2182,7 @@ dpif_netdev_flow_from_nlattrs(const struct nlattr *key, uint32_t key_len, + + ds_init(&s); + odp_flow_format(key, key_len, NULL, 0, NULL, &s, true); +- VLOG_ERR("internal error parsing flow key %s", ds_cstr(&s)); ++ VLOG_ERR("internal error parsing flow key %s (%s)", ds_cstr(&s), odp_key_fitness_to_string(fitness)); + ds_destroy(&s); + } + +@@ -4612,6 +4633,8 @@ dp_execute_cb(void *aux_, struct dp_packet_batch *packets_, + break; + } + ++ case OVS_ACTION_ATTR_PUSH_NSH: ++ case OVS_ACTION_ATTR_POP_NSH: + case OVS_ACTION_ATTR_PUSH_VLAN: + case OVS_ACTION_ATTR_POP_VLAN: + case OVS_ACTION_ATTR_PUSH_MPLS: +diff --git a/lib/dpif.c b/lib/dpif.c +index 53958c5..86e30e0 100644 +--- a/lib/dpif.c ++++ b/lib/dpif.c +@@ -1178,6 +1178,8 @@ dpif_execute_helper_cb(void *aux_, struct dp_packet_batch *packets_, + } + + case OVS_ACTION_ATTR_HASH: ++ case OVS_ACTION_ATTR_PUSH_NSH: ++ case OVS_ACTION_ATTR_POP_NSH: + case OVS_ACTION_ATTR_PUSH_VLAN: + case OVS_ACTION_ATTR_POP_VLAN: + case OVS_ACTION_ATTR_PUSH_MPLS: +diff --git a/lib/flow.c b/lib/flow.c +index 375979b..e387c8b 100644 +--- a/lib/flow.c ++++ b/lib/flow.c +@@ -547,6 +547,25 @@ flow_extract(struct dp_packet *packet, struct flow *flow) + miniflow_expand(&m.mf, flow); + } + ++/* parse Ethernet+NSH */ ++static int parse_nsh(const void *data, struct ovs_key_nsh *nsh) ++{ ++ memcpy(&nsh->encap_eth_dst, data, ENCAP_ETH_LEN); ++ const struct nsh_hdr *nsh_hdr = (const struct nsh_hdr *)((const char *)data + ENCAP_ETH_LEN); ++ ++ nsh->nsh_mdtype = nsh_hdr->base.mdtype; ++ if (nsh->nsh_mdtype != NSH_M_TYPE1) ++ return -1; ++ nsh->nsh_np = nsh_hdr->base.proto; ++ nsh->nsi = nsh_hdr->base.svc_idx; ++ nsh->nsp = nsh_hdr->base.path_hdr << 8; ++ nsh->nshc1 = nsh_hdr->ctx.nshc1; ++ nsh->nshc2 = nsh_hdr->ctx.nshc2; ++ nsh->nshc3 = nsh_hdr->ctx.nshc3; ++ nsh->nshc4 = nsh_hdr->ctx.nshc4; ++ return 0; ++} ++ + /* Caller is responsible for initializing 'dst' with enough storage for + * FLOW_U64S * 8 bytes. */ + void +@@ -607,6 +626,32 @@ miniflow_extract(struct dp_packet *packet, struct miniflow *dst) + } + } + ++ /* Extract Etherenet + NSH if the Ethernet type is 0x894F in packet */ ++ if (OVS_UNLIKELY(size < sizeof(struct eth_header))) ++ goto out; ++ else { ++ const struct eth_header *eth = data; ++ if (eth->eth_type == htons(ETH_P_NSH)) { ++ /* extract Ethernet+nsh */ ++ struct ovs_key_nsh nsh; ++ if (OVS_UNLIKELY(parse_nsh(data, &nsh))) ++ goto out; ++ ++ /* Now only support NSH mdtype 1 */ ++ if (nsh.nsh_mdtype == NSH_M_TYPE1){ ++ /* Push all field related with Ethernet+nsh at once. */ ++ miniflow_push_words(mf, encap_eth_dst, &nsh, ++ (sizeof (struct ovs_key_nsh)+sizeof(uint64_t) - 1) / ++ sizeof(uint64_t)); ++ data = (const char *)data + NSH_M_TYPE1_LEN + ENCAP_ETH_LEN; ++ } else ++ goto out; ++ ++ if(nsh.nsh_np != NSH_P_ETHERNET) ++ goto out; ++ } ++ } ++ + /* Initialize packet's layer pointer and offsets. */ + l2 = data; + dp_packet_reset_offsets(packet); +@@ -897,7 +942,7 @@ 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)) { ++ if (flow->tunnel.gpe_np != 0) { + match_set_tun_gpe_np(flow_metadata, flow->tunnel.gpe_np); + } + if (flow->tunnel.gpe_flags) { +@@ -1316,6 +1361,21 @@ void flow_wildcards_init_for_packet(struct flow_wildcards *wc, + WC_MASK_FIELD(wc, tunnel.tun_id); + } + ++ /* NSH fields wildcarded */ ++ if (flow->nsh_mdtype) { ++ WC_MASK_FIELD(wc, encap_eth_src); ++ WC_MASK_FIELD(wc, encap_eth_dst); ++ WC_MASK_FIELD(wc, encap_eth_type); ++ WC_MASK_FIELD(wc, nshc1); ++ WC_MASK_FIELD(wc, nshc2); ++ WC_MASK_FIELD(wc, nshc3); ++ WC_MASK_FIELD(wc, nshc4); ++ WC_MASK_FIELD(wc, nsh_mdtype); ++ WC_MASK_FIELD(wc, nsh_np); ++ WC_MASK_FIELD(wc, nsp); ++ WC_MASK_FIELD(wc, nsi); ++ } ++ + /* metadata, regs, and conj_id wildcarded. */ + + WC_MASK_FIELD(wc, skb_priority); +@@ -1432,6 +1492,19 @@ flow_wc_map(const struct flow *flow, struct flowmap *map) + FLOWMAP_SET(map, ct_mark); + FLOWMAP_SET(map, ct_label); + ++ /* NSH fields */ ++ FLOWMAP_SET(map, encap_eth_src); ++ FLOWMAP_SET(map, encap_eth_dst); ++ FLOWMAP_SET(map, encap_eth_type); ++ FLOWMAP_SET(map, nshc1); ++ FLOWMAP_SET(map, nshc2); ++ FLOWMAP_SET(map, nshc3); ++ FLOWMAP_SET(map, nshc4); ++ FLOWMAP_SET(map, nsp); ++ FLOWMAP_SET(map, nsi); ++ FLOWMAP_SET(map, nsh_mdtype); ++ FLOWMAP_SET(map, nsh_np); ++ + /* Ethertype-dependent fields. */ + if (OVS_LIKELY(flow->dl_type == htons(ETH_TYPE_IP))) { + FLOWMAP_SET(map, nw_src); +@@ -2352,6 +2425,33 @@ flow_compose_l4_csum(struct dp_packet *p, const struct flow *flow, + } + } + ++/* push ethernet+nsh header at the beginning of packets */ ++static void ++flow_compose_nsh(struct dp_packet *p, const struct flow *flow) ++{ ++ struct eth_nsh_hdr *eth_nsh_header; ++ ++ /* Now only support mdtype1 */ ++ if (flow->nsh_mdtype != NSH_M_TYPE1) ++ return; ++ ++ eth_nsh_header = dp_packet_push_uninit(p, ETH_NSH_TYPE1_HEADER_SIZE); ++ eth_nsh_header->encap_eth_header.encap_eth_dst = flow->encap_eth_dst; ++ eth_nsh_header->encap_eth_header.encap_eth_src = flow->encap_eth_src; ++ eth_nsh_header->encap_eth_header.encap_eth_type = htons(ETH_P_NSH); ++ ++ memset(ð_nsh_header->nsh_hdr, 0, sizeof (struct nsh_hdr)); ++ eth_nsh_header->nsh_hdr.base.length = 6; ++ eth_nsh_header->nsh_hdr.base.proto = flow->nsh_np; ++ eth_nsh_header->nsh_hdr.base.mdtype = flow->nsh_mdtype; ++ eth_nsh_header->nsh_hdr.base.proto = flow->nsh_np; ++ eth_nsh_header->nsh_hdr.base.path_hdr = flow->nsp >> 8 | flow->nsi << 24; ++ eth_nsh_header->nsh_hdr.ctx.nshc1 = flow->nshc1; ++ eth_nsh_header->nsh_hdr.ctx.nshc2 = flow->nshc2; ++ eth_nsh_header->nsh_hdr.ctx.nshc3 = flow->nshc3; ++ eth_nsh_header->nsh_hdr.ctx.nshc4 = flow->nshc4; ++} ++ + /* Puts into 'b' a packet that flow_extract() would parse as having the given + * 'flow'. + * +@@ -2459,6 +2559,10 @@ flow_compose(struct dp_packet *p, const struct flow *flow) + push_mpls(p, flow->dl_type, flow->mpls_lse[--n]); + } + } ++ ++ if (flow->nsh_mdtype) { ++ flow_compose_nsh(p, flow); ++ } + } + + /* Compressed flow. */ diff --git a/lib/match.c b/lib/match.c -index 52437c9..3db2a2b 100644 +index f19648d..daf0b87 100644 --- a/lib/match.c +++ b/lib/match.c -@@ -862,6 +862,152 @@ match_set_nd_target_masked(struct match *match, +@@ -878,6 +878,152 @@ match_set_nd_target_masked(struct match *match, match->wc.masks.nd_target = *mask; } @@ -949,16 +1415,16 @@ index 52437c9..3db2a2b 100644 +} + +void -+match_set_encap_eth_type(struct match *match, uint16_t encap_eth_type) ++match_set_encap_eth_type(struct match *match, ovs_be16 encap_eth_type) +{ -+ match_set_encap_eth_type_masked(match, encap_eth_type, UINT16_MAX); ++ match->wc.masks.encap_eth_type = OVS_BE16_MAX; ++ match->flow.encap_eth_type = encap_eth_type; +} -+ + /* Returns true if 'a' and 'b' wildcard the same fields and have the same * values for fixed fields, otherwise false. */ bool -@@ -1155,6 +1301,50 @@ match_format(const struct match *match, struct ds *s, int priority) +@@ -1171,6 +1317,49 @@ match_format(const struct match *match, struct ds *s, int priority) format_ct_label_masked(s, &f->ct_label, &wc->masks.ct_label); } @@ -999,57 +1465,21 @@ index 52437c9..3db2a2b 100644 + wc->masks.nshc4); + } + -+ if (wc->masks.encap_eth_type) { -+ ds_put_format(s, "encap_eth_type=%"PRIu16",", f->encap_eth_type); -+ } -+ + format_eth_masked(s, "encap_eth_src", f->encap_eth_src, wc->masks.encap_eth_src); + format_eth_masked(s, "encap_eth_dst", f->encap_eth_dst, wc->masks.encap_eth_dst); ++ if (wc->masks.encap_eth_type) { ++ ds_put_format(s, "encap_eth_type=0x%04"PRIx16",", ntohs(f->encap_eth_type)); ++ } + if (wc->masks.dl_type) { skip_type = true; if (f->dl_type == htons(ETH_TYPE_IP)) { -diff --git a/lib/match.h b/lib/match.h -index 48aa0b1..529350e 100644 ---- a/lib/match.h -+++ b/lib/match.h -@@ -165,6 +165,30 @@ void match_set_nd_target(struct match *, const struct in6_addr *); - void match_set_nd_target_masked(struct match *, const struct in6_addr *, - const struct in6_addr *); - -+void match_set_nsp_masked(struct match *, ovs_be32 nsp, ovs_be32 mask); -+void match_set_nsi_masked(struct match *match, uint8_t nsi, uint8_t mask); -+void match_set_nsh_mdtype_masked(struct match *match, uint8_t nsh_mdtype, uint8_t mask); -+void match_set_nsh_np_masked(struct match *match, uint8_t nsh_np, uint8_t mask); -+void match_set_nshc1_masked(struct match *, ovs_be32 nshc1, ovs_be32 mask); -+void match_set_nshc2_masked(struct match *, ovs_be32 nshc2, ovs_be32 mask); -+void match_set_nshc3_masked(struct match *, ovs_be32 nshc3, ovs_be32 mask); -+void match_set_nshc4_masked(struct match *, ovs_be32 nshc4, ovs_be32 mask); -+void match_set_encap_eth_src_masked(struct match *match, const struct eth_addr encap_eth_src, const struct eth_addr mask); -+void match_set_encap_eth_dst_masked(struct match *match, const struct eth_addr encap_eth_dst, const struct eth_addr mask); -+void match_set_encap_eth_type_masked(struct match *match, ovs_be16 encap_eth_type, ovs_be16 mask); -+ -+void match_set_nsp(struct match *, ovs_be32 nsp); -+void match_set_nsi(struct match *match, uint8_t nsi); -+void match_set_nsh_mdtype(struct match *match, uint8_t nsh_mdtype); -+void match_set_nsh_np(struct match *match, uint8_t nsh_np); -+void match_set_nshc1(struct match *, ovs_be32 nshc1); -+void match_set_nshc2(struct match *, ovs_be32 nshc2); -+void match_set_nshc3(struct match *, ovs_be32 nshc3); -+void match_set_nshc4(struct match *, ovs_be32 nshc4); -+void match_set_encap_eth_src(struct match *match, const struct eth_addr encap_eth_src); -+void match_set_encap_eth_dst(struct match *match, const struct eth_addr encap_eth_dst); -+void match_set_encap_eth_type(struct match *match, uint16_t encap_eth_type); -+ - bool match_equal(const struct match *, const struct match *); - uint32_t match_hash(const struct match *, uint32_t basis); - diff --git a/lib/meta-flow.c b/lib/meta-flow.c -index ab77fca..648a753 100644 +index 5d0721f..cf2e7b6 100644 --- a/lib/meta-flow.c +++ b/lib/meta-flow.c -@@ -243,7 +243,28 @@ mf_is_all_wild(const struct mf_field *mf, const struct flow_wildcards *wc) - return !flow_get_xreg(&wc->masks, mf->id - MFF_XREG0); +@@ -247,7 +247,28 @@ mf_is_all_wild(const struct mf_field *mf, const struct flow_wildcards *wc) + } case MFF_ACTSET_OUTPUT: return !wc->masks.actset_output; - @@ -1078,7 +1508,7 @@ index ab77fca..648a753 100644 case MFF_ETH_SRC: return eth_addr_is_zero(wc->masks.dl_src); case MFF_ETH_DST: -@@ -557,6 +578,17 @@ mf_is_value_valid(const struct mf_field *mf, const union mf_value *value) +@@ -477,6 +498,17 @@ mf_is_value_valid(const struct mf_field *mf, const union mf_value *value) case MFF_ICMPV6_TYPE: case MFF_ICMPV6_CODE: case MFF_ND_TARGET: @@ -1096,8 +1526,8 @@ index ab77fca..648a753 100644 case MFF_ND_SLL: case MFF_ND_TLL: return true; -@@ -716,6 +748,50 @@ mf_get_value(const struct mf_field *mf, const struct flow *flow, - value->be64 = htonll(flow_get_xreg(flow, mf->id - MFF_XREG0)); +@@ -640,6 +672,50 @@ mf_get_value(const struct mf_field *mf, const struct flow *flow, + value->be128 = hton128(flow_get_xxreg(flow, mf->id - MFF_XXREG0)); break; + case MFF_NSP: @@ -1147,7 +1577,7 @@ index ab77fca..648a753 100644 case MFF_ETH_SRC: value->mac = flow->dl_src; break; -@@ -1085,6 +1161,50 @@ mf_set_value(const struct mf_field *mf, +@@ -1013,6 +1089,50 @@ mf_set_value(const struct mf_field *mf, match_set_arp_sha(match, value->mac); break; @@ -1198,8 +1628,8 @@ index ab77fca..648a753 100644 case MFF_ARP_THA: case MFF_ND_TLL: match_set_arp_tha(match, value->mac); -@@ -1296,6 +1416,50 @@ mf_set_flow_value(const struct mf_field *mf, - flow_set_xreg(flow, mf->id - MFF_XREG0, ntohll(value->be64)); +@@ -1245,6 +1365,50 @@ mf_set_flow_value(const struct mf_field *mf, + flow_set_xxreg(flow, mf->id - MFF_XXREG0, ntoh128(value->be128)); break; + case MFF_NSP: @@ -1249,7 +1679,7 @@ index ab77fca..648a753 100644 case MFF_ETH_SRC: flow->dl_src = value->mac; break; -@@ -1734,6 +1898,52 @@ mf_set_wild(const struct mf_field *mf, struct match *match, char **err_str) +@@ -1689,6 +1853,52 @@ mf_set_wild(const struct mf_field *mf, struct match *match, char **err_str) match->wc.masks.arp_sha = eth_addr_zero; break; @@ -1302,7 +1732,7 @@ index ab77fca..648a753 100644 case MFF_ARP_THA: case MFF_ND_TLL: match->flow.arp_tha = eth_addr_zero; -@@ -1929,6 +2139,50 @@ mf_set(const struct mf_field *mf, +@@ -1890,6 +2100,50 @@ mf_set(const struct mf_field *mf, match_set_arp_sha_masked(match, value->mac, mask->mac); break; @@ -1353,218 +1783,181 @@ index ab77fca..648a753 100644 case MFF_ARP_THA: case MFF_ND_TLL: match_set_arp_tha_masked(match, value->mac, mask->mac); -diff --git a/lib/meta-flow.h b/lib/meta-flow.h -index 4bd9ff6..a226b79 100644 ---- a/lib/meta-flow.h -+++ b/lib/meta-flow.h -@@ -1747,6 +1747,180 @@ enum OVS_PACKED_ENUM mf_field_id { - */ - MFF_ND_TLL, +diff --git a/lib/netdev-native-tnl.c b/lib/netdev-native-tnl.c +index ce2582f..2fe2722 100644 +--- a/lib/netdev-native-tnl.c ++++ b/lib/netdev-native-tnl.c +@@ -44,6 +44,7 @@ + #include "unaligned.h" + #include "unixctl.h" + #include "openvswitch/vlog.h" ++#include "openvswitch/vxlangpe.h" -+ /* "nsp". -+ * -+ * For a packet received including a (32-bit) -+ * network service header service path (nsp), the nsp is stored -+ * in the low 24-bits and the high bits are zeroed. For -+ * other packets, the value is 0. -+ * -+ * Type: be32. -+ * Maskable: bitwise. -+ * Formatting: hexadecimal. -+ * Prerequisites: none. -+ * Access: read/write. -+ * NXM: NXM_NX_NSP(113) since v1.1. -+ * OXM: none. -+ * Prefix lookup member: nsp. -+ */ -+ MFF_NSP, -+ -+ /* "nsi". -+ * -+ * For a packet received, it includes a (8-bit) -+ * network service header service index (nsi). -+ * -+ * Type: u8. -+ * Maskable: bitwise. -+ * Formatting: decimal. -+ * Prerequisites: none. -+ * Access: read/write. -+ * NXM: NXM_NX_NSI(114) since v1.1. -+ * OXM: none. -+ * Prefix lookup member: nsi. -+ */ -+ MFF_NSI, -+ -+ /* "nshc1". -+ * -+ * For a packet received including a (32-bit) -+ * Network Platform Context (nshc1), the nshc1 is stored -+ * in the 32-bits. For other packets, the value is 0. -+ * -+ * Type: be32. -+ * Maskable: bitwise. -+ * Formatting: hexadecimal. -+ * Prerequisites: none. -+ * Access: read/write. -+ * NXM: NXM_NX_NSH_C1(115) since v1.1. -+ * OXM: none. -+ * Prefix lookup member: nshc1. -+ */ -+ MFF_NSH_C1, -+ -+ /* "nshc2". -+ * -+ * For a packet received including a (32-bit) -+ * Network Shared Context (nshc2), the nshc2 is stored -+ * in the 32-bits. For other packets, the value is 0. -+ * -+ * Type: be32. -+ * Maskable: bitwise. -+ * Formatting: hexadecimal. -+ * Prerequisites: none. -+ * Access: read/write. -+ * NXM: NXM_NX_NSH_C2(116) since v1.1. -+ * OXM: none. -+ * Prefix lookup member: nshc2. -+ */ -+ MFF_NSH_C2, -+ -+ /* "nshc3". -+ * -+ * For a packet received via including a (32-bit) -+ * Service Platform Context (nshc3), the nshc3 is stored -+ * in the 32-bits. For other packets, the value is 0. -+ * -+ * Type: be32. -+ * Maskable: bitwise. -+ * Formatting: hexadecimal. -+ * Prerequisites: none. -+ * Access: read/write. -+ * NXM: NXM_NX_NSH_C3(117) since v1.1. -+ * OXM: none. -+ * Prefix lookup member: nshc3. -+ */ -+ MFF_NSH_C3, -+ -+ /* "nshc4". -+ * -+ * For a packet received including a (32-bit) -+ * Service Shared Context (nshc4), the nshc4 is stored -+ * in the 32-bits. For other packets, the value is 0. -+ * -+ * Type: be32. -+ * Maskable: bitwise. -+ * Formatting: hexadecimal. -+ * Prerequisites: none. -+ * Access: read/write. -+ * NXM: NXM_NX_NSH_C4(118) since v1.1. -+ * OXM: none. -+ * Prefix lookup member: nshc4. -+ */ -+ MFF_NSH_C4, -+ -+ /* "nsh_mdtype". -+ * -+ * For a packet received, it includes a (8-bit) -+ * nsh md-type field (md-type). -+ * -+ * Type: u8. -+ * Maskable: bitwise. -+ * Formatting: decimal. -+ * Prerequisites: none. -+ * Access: read/write. -+ * NXM: NXM_NX_NSH_MDTYPE(119) since v1.1. -+ * OXM: none. -+ */ -+ MFF_NSH_MDTYPE, -+ -+ /* "nsh_np". -+ * -+ * For a packet received, it includes a (8-bit) -+ * nsh next protocol field (np). -+ * -+ * Type: u8. -+ * Maskable: bitwise. -+ * Formatting: decimal. -+ * Prerequisites: none. -+ * Access: read/write. -+ * NXM: NXM_NX_NSH_NP(120) since v1.1. -+ * OXM: none. -+ */ -+ MFF_NSH_NP, -+ -+ /* "encap_eth_src". -+ * -+ * encap eth source address for Ethernet+NSH -+ * -+ * Type: MAC. -+ * Maskable: bitwise. -+ * Formatting: Ethernet. -+ * Prerequisites: none. -+ * Access: read/write. -+ * NXM: NXM_NX_ENCAP_ETH_SRC(121) since v1.1. -+ * OXM: none. -+ */ -+ MFF_ENCAP_ETH_SRC, -+ -+ /* "encap_eth_dst". -+ * -+ * encap eth destination address for Ethernet+NSH -+ * -+ * Type: MAC. -+ * Maskable: bitwise. -+ * Formatting: Ethernet. -+ * Prerequisites: none. -+ * Access: read/write. -+ * NXM: NXM_NX_ENCAP_ETH_DST(122) since v1.1. -+ * OXM: none. -+ */ -+ MFF_ENCAP_ETH_DST, -+ -+ /* "encap_eth_type". -+ * -+ * Encap Ethernet type. -+ * -+ * Type: be16. -+ * Maskable: no. -+ * Formatting: hexadecimal. -+ * Prerequisites: none. -+ * Access: read/write. -+ * NXM: NXM_NX_ENCAP_ETH_TYPE(123) since v1.1. -+ * OXM: none. -+ */ -+ MFF_ENCAP_ETH_TYPE, -+ - MFF_N_IDS - }; + VLOG_DEFINE_THIS_MODULE(native_tnl); + static struct vlog_rate_limit err_rl = VLOG_RATE_LIMIT_INIT(60, 5); +@@ -209,6 +210,9 @@ netdev_tnl_push_udp_header(struct dp_packet *packet, + struct udp_header *udp; + int ip_tot_size; ++ if ((data->tnl_type == OVS_VPORT_TYPE_VXLAN) && (data->exts & (1 << VXLAN_GPE_POP_ETH))) ++ dp_packet_reset_packet(packet, ENCAP_ETH_LEN); ++ + udp = netdev_tnl_push_ip_header(packet, data->header, data->header_len, &ip_tot_size); + + /* set udp src port */ +@@ -478,6 +482,8 @@ netdev_vxlan_pop_header(struct dp_packet *packet) + struct flow_tnl *tnl = &md->tunnel; + struct vxlanhdr *vxh; + unsigned int hlen; ++ ovs_be32 flag; ++ ovs_be32 vni; + + pkt_metadata_init_tnl(md); + if (VXLAN_HLEN > dp_packet_l4_size(packet)) { +@@ -489,17 +495,59 @@ netdev_vxlan_pop_header(struct dp_packet *packet) + goto err; + } + +- 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))); +- goto err; +- } +- tnl->tun_id = htonll(ntohl(get_16aligned_be32(&vxh->vx_vni)) >> 8); +- tnl->flags |= FLOW_TNL_F_KEY; ++ /* vxlan-gpe packets*/ ++ flag = get_16aligned_be32(&vxh->vx_flags); ++ vni = get_16aligned_be32(&vxh->vx_vni); ++ ++ if (flag & VXLAN_HF_GPE) { ++ flag &= ~VXLAN_GPE_USED_BITS; ++ if ((flag & ~VXLAN_GPE_USED_BITS) || ++ (vni & htonl(0xff))) { ++ ++ VLOG_WARN_RL(&err_rl, "invalid vxlan flags=%#x vni=%#x\n for vxlan-gpe", ++ ntohl(flag), ++ ntohl(vni)); ++ goto err; ++ } ++ ++ struct vxlanhdr_gpe *gpe; ++ ++ gpe = (struct vxlanhdr_gpe *)vxh; ++ tnl->gpe_np = gpe->next_protocol; + +- dp_packet_reset_packet(packet, hlen + VXLAN_HLEN); ++ /* Drop the OAM packets */ ++ if (gpe->oam_flag) ++ goto err; ++ ++ tnl->tun_id = htonll(ntohl(vni) >> 8); ++ tnl->flags |= FLOW_TNL_F_KEY; ++ ++ if (tnl->gpe_np == VXLAN_GPE_NP_NSH) { ++ /* Add a faked ethernet header which type is 0x894F, so the OVS ++ * can receive frame starting with ethernet header. ++ */ ++ struct eth_header * encap_eth; ++ struct eth_header * eth = dp_packet_l2(packet); ++ ++ memmove((char *)eth + hlen + VXLAN_HLEN - ENCAP_ETH_LEN, (char *)eth + hlen + VXLAN_HLEN + NSH_PUSH_TYPE1_HEADER_SIZE, 2 * ETH_ADDR_LEN); ++ dp_packet_reset_packet(packet, hlen + VXLAN_HLEN - ENCAP_ETH_LEN); ++ encap_eth = dp_packet_data(packet); ++ encap_eth->eth_type = htons(ETH_P_NSH); ++ } else ++ dp_packet_reset_packet(packet, hlen + VXLAN_HLEN); ++ } else { ++ if (flag != htonl(VXLAN_FLAGS) || ++ (vni & htonl(0xff))) { ++ VLOG_WARN_RL(&err_rl, "invalid vxlan flags=%#x vni=%#x\n", ++ ntohl(flag), ++ ntohl(vni)); ++ goto err; ++ } ++ tnl->tun_id = htonll(ntohl(vni) >> 8); ++ tnl->flags |= FLOW_TNL_F_KEY; ++ ++ dp_packet_reset_packet(packet, hlen + VXLAN_HLEN); ++ } + + return packet; + err: +@@ -522,8 +570,27 @@ netdev_vxlan_build_header(const struct netdev *netdev, + + vxh = udp_build_header(tnl_cfg, data, params); + +- put_16aligned_be32(&vxh->vx_flags, htonl(VXLAN_FLAGS)); +- put_16aligned_be32(&vxh->vx_vni, htonl(ntohll(params->flow->tunnel.tun_id) << 8)); ++ if(tnl_cfg->exts & (1 << OVS_VXLAN_EXT_GPE)) { ++ struct vxlanhdr_gpe *gpe; ++ ++ gpe = (struct vxlanhdr_gpe *)vxh; ++ put_16aligned_be32(&vxh->vx_flags, htonl(VXLAN_FLAGS | VXLAN_HF_GPE)); ++ put_16aligned_be32(&vxh->vx_vni, htonl(ntohll(params->flow->tunnel.tun_id) << 8)); ++ ++ if (!params->flow->tunnel.gpe_np) ++ return -1; ++ else ++ gpe->next_protocol = params->flow->tunnel.gpe_np; ++ ++ if (params->flow->tunnel.gpe_flags & 0x01) ++ gpe->oam_flag = 1; ++ ++ if (params->flow->tunnel.gpe_np == VXLAN_GPE_NP_NSH) ++ data->exts |= 1 << VXLAN_GPE_POP_ETH; ++ } else { ++ put_16aligned_be32(&vxh->vx_flags, htonl(VXLAN_FLAGS)); ++ put_16aligned_be32(&vxh->vx_vni, htonl(ntohll(params->flow->tunnel.tun_id) << 8)); ++ } + + ovs_mutex_unlock(&dev->mutex); + data->header_len += sizeof *vxh; diff --git a/lib/netdev-vport.c b/lib/netdev-vport.c -index 92ceec1..406a492 100644 +index cff0f5c..841a070 100644 --- a/lib/netdev-vport.c +++ b/lib/netdev-vport.c -@@ -582,9 +582,15 @@ set_tunnel_config(struct netdev *dev_, const struct smap *args) +@@ -525,9 +525,15 @@ set_tunnel_config(struct netdev *dev_, const struct smap *args) ext = strtok_r(str, ",", &save_ptr); while (ext) { if (!strcmp(type, "vxlan") && !strcmp(ext, "gbp")) { - tnl_cfg.exts |= (1 << OVS_VXLAN_EXT_GBP); + if (tnl_cfg.exts & (1 << OVS_VXLAN_EXT_GPE)) + VLOG_WARN("VXLAN_GPE extension exists, VxLAN_GBP extension can't be added."); -+ else ++ else + tnl_cfg.exts |= (1 << OVS_VXLAN_EXT_GBP); } else if (!strcmp(type, "vxlan") && !strcmp(ext, "gpe")) { - tnl_cfg.exts |= (1 << OVS_VXLAN_EXT_GPE); + if (tnl_cfg.exts & (1 << OVS_VXLAN_EXT_GBP)) + VLOG_WARN("VXLAN_GBP extension exists, VxLAN_GPE extension can't be added."); -+ else ++ else + tnl_cfg.exts |= (1 << OVS_VXLAN_EXT_GPE); } else { VLOG_WARN("%s: unknown extension '%s'", name, ext); } +diff --git a/lib/netdev-vport.h b/lib/netdev-vport.h +index 048aa6e..b19cbd2 100644 +--- a/lib/netdev-vport.h ++++ b/lib/netdev-vport.h +@@ -48,6 +48,12 @@ enum { NETDEV_VPORT_NAME_BUFSIZE = 16 }; + #else + enum { NETDEV_VPORT_NAME_BUFSIZE = 256 }; + #endif ++ ++enum OVS_ACTION_PUSH_VXLAN_EXTS { ++ VXLAN_GPE_POP_ETH, /* Pop ethernet header when the field next_proto ++ * is 4 in vxlan-gpe header ++ */ ++}; + const char *netdev_vport_get_dpif_port(const struct netdev *, + char namebuf[], size_t bufsize) + OVS_WARN_UNUSED_RESULT; diff --git a/lib/nx-match.c b/lib/nx-match.c -index 0eecac7..8d2bc4b 100644 +index 65d7ee3..0c108f4 100644 --- a/lib/nx-match.c +++ b/lib/nx-match.c -@@ -949,6 +949,25 @@ nx_put_raw(struct ofpbuf *b, enum ofp_version oxm, const struct match *match, +@@ -948,6 +948,24 @@ nx_put_raw(struct ofpbuf *b, enum ofp_version oxm, const struct match *match, ofputil_port_to_ofp11(flow->actset_output)); } @@ -1578,55 +1971,70 @@ index 0eecac7..8d2bc4b 100644 + nxm_put_32m(b, MFF_NSH_C3, oxm, flow->nshc3, match->wc.masks.nshc3); + nxm_put_32m(b, MFF_NSH_C4, oxm, flow->nshc4, match->wc.masks.nshc4); + -+ /* ENCAP Eth */ + nxm_put_eth_masked(b, MFF_ENCAP_ETH_SRC, oxm, + flow->encap_eth_src, match->wc.masks.encap_eth_src); + nxm_put_eth_masked(b, MFF_ENCAP_ETH_DST, oxm, + flow->encap_eth_dst, match->wc.masks.encap_eth_dst); + nxm_put_16m(b, MFF_ENCAP_ETH_TYPE, oxm, + ofputil_dl_type_to_openflow(flow->encap_eth_type), -+ match->wc.masks.encap_eth_type); //uncertain ++ match->wc.masks.encap_eth_type); + /* Ethernet. */ nxm_put_eth_masked(b, MFF_ETH_SRC, oxm, flow->dl_src, match->wc.masks.dl_src); diff --git a/lib/odp-execute.c b/lib/odp-execute.c -index b5204b2..b6dcd98 100644 +index 5a43904..20e3106 100644 --- a/lib/odp-execute.c +++ b/lib/odp-execute.c -@@ -434,6 +434,8 @@ odp_execute_masked_set_action(struct dp_packet *packet, +@@ -336,6 +336,7 @@ odp_execute_set_action(struct dp_packet *packet, const struct nlattr *a) + case OVS_KEY_ATTR_CT_ZONE: + case OVS_KEY_ATTR_CT_MARK: + case OVS_KEY_ATTR_CT_LABELS: ++ case OVS_KEY_ATTR_NSH: + case __OVS_KEY_ATTR_MAX: + default: + OVS_NOT_REACHED(); +@@ -432,6 +433,7 @@ odp_execute_masked_set_action(struct dp_packet *packet, case OVS_KEY_ATTR_ETHERTYPE: case OVS_KEY_ATTR_IN_PORT: case OVS_KEY_ATTR_VLAN: + case OVS_KEY_ATTR_NSH: -+ case OVS_KEY_ATTR_ENCAP_ETH: case OVS_KEY_ATTR_ICMP: case OVS_KEY_ATTR_ICMPV6: case OVS_KEY_ATTR_TCP_FLAGS: -@@ -497,6 +499,10 @@ requires_datapath_assistance(const struct nlattr *a) +@@ -497,6 +499,8 @@ requires_datapath_assistance(const struct nlattr *a) case OVS_ACTION_ATTR_SET: case OVS_ACTION_ATTR_SET_MASKED: + case OVS_ACTION_ATTR_PUSH_NSH: + case OVS_ACTION_ATTR_POP_NSH: -+ case OVS_ACTION_ATTR_PUSH_ETH: -+ case OVS_ACTION_ATTR_POP_ETH: case OVS_ACTION_ATTR_PUSH_VLAN: case OVS_ACTION_ATTR_POP_VLAN: case OVS_ACTION_ATTR_SAMPLE: -@@ -623,6 +629,10 @@ odp_execute_actions(void *dp, struct dp_packet **packets, int cnt, bool steal, +@@ -586,6 +590,21 @@ odp_execute_actions(void *dp, struct dp_packet_batch *batch, bool steal, } break; -+ case OVS_ACTION_ATTR_PUSH_NSH: ++ case OVS_ACTION_ATTR_PUSH_NSH: { ++ const void *push_nsh_hdr = nl_attr_get(a); ++ ++ for (i = 0; i < cnt; i++) { ++ push_nsh(packets[i], push_nsh_hdr); ++ } ++ break; ++ } ++ + case OVS_ACTION_ATTR_POP_NSH: -+ case OVS_ACTION_ATTR_PUSH_ETH: -+ case OVS_ACTION_ATTR_POP_ETH: - case OVS_ACTION_ATTR_OUTPUT: - case OVS_ACTION_ATTR_TUNNEL_PUSH: - case OVS_ACTION_ATTR_TUNNEL_POP: ++ for (i = 0; i < cnt; i++) { ++ pop_nsh(packets[i]); ++ } ++ break; ++ + case OVS_ACTION_ATTR_PUSH_MPLS: { + const struct ovs_action_push_mpls *mpls = nl_attr_get(a); + diff --git a/lib/odp-util.c b/lib/odp-util.c -index 7983720..102dfd7 100644 +index b9e8aa7..97b4e94 100644 --- a/lib/odp-util.c +++ b/lib/odp-util.c @@ -70,7 +70,8 @@ static void format_odp_key_attr(const struct nlattr *a, @@ -1639,64 +2047,56 @@ index 7983720..102dfd7 100644 struct geneve_scan { struct geneve_opt d[63]; int len; -@@ -112,6 +113,10 @@ odp_action_len(uint16_t type) +@@ -113,6 +114,8 @@ odp_action_len(uint16_t type) case OVS_ACTION_ATTR_USERSPACE: return ATTR_LEN_VARIABLE; case OVS_ACTION_ATTR_PUSH_VLAN: return sizeof(struct ovs_action_push_vlan); case OVS_ACTION_ATTR_POP_VLAN: return 0; + case OVS_ACTION_ATTR_PUSH_NSH: return sizeof(struct ovs_action_push_nsh); + case OVS_ACTION_ATTR_POP_NSH: return 0; -+ case OVS_ACTION_ATTR_PUSH_ETH: return sizeof(struct ovs_action_push_eth); -+ case OVS_ACTION_ATTR_POP_ETH: return 0; case OVS_ACTION_ATTR_PUSH_MPLS: return sizeof(struct ovs_action_push_mpls); case OVS_ACTION_ATTR_POP_MPLS: return sizeof(ovs_be16); case OVS_ACTION_ATTR_RECIRC: return sizeof(uint32_t); -@@ -147,6 +152,8 @@ ovs_key_attr_to_string(enum ovs_key_attr attr, char *namebuf, size_t bufsize) +@@ -148,6 +151,7 @@ ovs_key_attr_to_string(enum ovs_key_attr attr, char *namebuf, size_t bufsize) case OVS_KEY_ATTR_CT_LABELS: return "ct_label"; case OVS_KEY_ATTR_TUNNEL: return "tunnel"; case OVS_KEY_ATTR_IN_PORT: return "in_port"; -+ case OVS_KEY_ATTR_ENCAP_ETH: return "encap_eth"; + case OVS_KEY_ATTR_NSH: return "nsh"; case OVS_KEY_ATTR_ETHERNET: return "eth"; case OVS_KEY_ATTR_VLAN: return "vlan"; case OVS_KEY_ATTR_ETHERTYPE: return "eth_type"; -@@ -373,6 +380,36 @@ format_vlan_tci(struct ds *ds, ovs_be16 tci, ovs_be16 mask, bool verbose) +@@ -376,6 +380,31 @@ format_vlan_tci(struct ds *ds, ovs_be16 tci, ovs_be16 mask, bool verbose) } static void +format_nsh(struct ds *ds, const struct ovs_action_push_nsh * nsh) +{ -+ const struct nsh_hdr *nsh_hdr =(struct nsh_hdr *)nsh->header; ++ const struct eth_nsh_hdr *eth_nsh_header = (struct eth_nsh_hdr *)nsh->header; ++ format_eth(ds, "encap_eth_src", ++ eth_nsh_header->encap_eth_header.encap_eth_src, ++ NULL, true); ++ format_eth(ds, "encap_eth_dst", ++ eth_nsh_header->encap_eth_header.encap_eth_dst, ++ NULL, true); ++ ds_put_format(ds, "encap_eth_type=0x%04"PRIx16",", ++ ntohs(eth_nsh_header->encap_eth_header.encap_eth_type)); + ds_put_format(ds, "nsh_mdtype=%"PRIu8",nsh_np=%"PRIu8",nsp=%"PRIu32 + ",nsi=%"PRIu8",nshc1=%"PRIu32",nshc2=%"PRIu32 + ",nshc3=%"PRIu32",nshc4=%"PRIu32")", -+ nsh_hdr->base.mdtype, -+ nsh_hdr->base.proto, -+ ntohl(nsh_hdr->base.path_hdr << 8), -+ ntohl(nsh_hdr->base.path_hdr >> 24), -+ ntohl(nsh_hdr->ctx.nshc1), -+ ntohl(nsh_hdr->ctx.nshc2), -+ ntohl(nsh_hdr->ctx.nshc3), -+ ntohl(nsh_hdr->ctx.nshc4)); -+} -+ -+static void -+format_encap_eth(struct ds *ds, const struct ovs_action_push_eth *encap_eth) -+{ -+ const struct encap_eth_hdr *encap_eth_hdr = (struct encap_eth_hdr *)encap_eth->header; -+ ds_put_format(ds, "encap_eth_type=%"PRIu16",", -+ ntohs(encap_eth_hdr->encap_eth_type)); -+ format_eth(ds, "encap_eth_src", encap_eth_hdr->encap_eth_src, -+ NULL, true); -+ format_eth(ds, "encap_eth_dst", encap_eth_hdr->encap_eth_dst, -+ NULL, true); -+ ds_put_format(ds, ")"); ++ eth_nsh_header->nsh_hdr.base.mdtype, ++ eth_nsh_header->nsh_hdr.base.proto, ++ ntohl(eth_nsh_header->nsh_hdr.base.path_hdr) >> 8, ++ ntohl(eth_nsh_header->nsh_hdr.base.path_hdr) & 0xFF, ++ ntohl(eth_nsh_header->nsh_hdr.ctx.nshc1), ++ ntohl(eth_nsh_header->nsh_hdr.ctx.nshc2), ++ ntohl(eth_nsh_header->nsh_hdr.ctx.nshc3), ++ ntohl(eth_nsh_header->nsh_hdr.ctx.nshc4)); +} + +static void format_mpls_lse(struct ds *ds, ovs_be32 mpls_lse) { ds_put_format(ds, "label=%"PRIu32",tc=%d,ttl=%d,bos=%d", -@@ -500,7 +537,7 @@ format_odp_tnl_push_header(struct ds *ds, struct ovs_action_push_tnl *data) +@@ -503,7 +532,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); @@ -1705,16 +2105,15 @@ index 7983720..102dfd7 100644 if (gnh->opt_len) { ds_put_cstr(ds, ",options("); format_geneve_opts(gnh->options, NULL, gnh->opt_len * 4, -@@ -760,6 +797,8 @@ format_odp_action(struct ds *ds, const struct nlattr *a) +@@ -763,6 +792,7 @@ format_odp_action(struct ds *ds, const struct nlattr *a) { int expected_len; enum ovs_action_attr type = nl_attr_type(a); + const struct ovs_action_push_nsh *nsh; -+ const struct ovs_action_push_eth *encap_eth; size_t size; expected_len = odp_action_len(nl_attr_type(a)); -@@ -830,6 +869,23 @@ format_odp_action(struct ds *ds, const struct nlattr *a) +@@ -841,6 +871,14 @@ format_odp_action(struct ds *ds, const struct nlattr *a) case OVS_ACTION_ATTR_POP_VLAN: ds_put_cstr(ds, "pop_vlan"); break; @@ -1725,47 +2124,46 @@ index 7983720..102dfd7 100644 + break; + case OVS_ACTION_ATTR_POP_NSH: + ds_put_cstr(ds, "pop_nsh"); -+ break; -+ -+ case OVS_ACTION_ATTR_PUSH_ETH: -+ encap_eth = nl_attr_get(a); -+ ds_put_cstr(ds, "push_eth("); -+ format_encap_eth(ds, encap_eth); -+ break; -+ case OVS_ACTION_ATTR_POP_ETH: -+ ds_put_cstr(ds, "pop_eth"); + break; case OVS_ACTION_ATTR_PUSH_MPLS: { const struct ovs_action_push_mpls *mpls = nl_attr_get(a); ds_put_cstr(ds, "push_mpls("); -@@ -1618,6 +1674,72 @@ parse_odp_action(const char *s, const struct simap *port_names, +@@ -1646,6 +1684,53 @@ parse_odp_action(const char *s, const struct simap *port_names, } { + struct ovs_action_push_nsh push; -+ struct nsh_hdr *nsh = (struct nsh_hdr *)push.header; ++ struct eth_nsh_hdr *eth_nsh_header = (struct eth_nsh_hdr *)push.header; + ovs_be32 nsp, nshc1,nshc2,nshc3,nshc4; + uint8_t nsi, nsh_mdtype, nsh_np; + int n = -1; + -+ if (ovs_scan_len(s, &n, "push_nsh(nsh_mdtype=%"SCNi8",nsh_np=%"SCNi8",nsp=0x%"SCNx32 ++ if (ovs_scan_len(s, &n, "push_nsh(encap_eth_dst="ETH_ADDR_SCAN_FMT ++ ",encap_eth_src="ETH_ADDR_SCAN_FMT ++ ",encap_eth_type=0x%"SCNx16 ++ ",nsh_mdtype=%"SCNi8",nsh_np=%"SCNi8",nsp=0x%"SCNx32 + ",nsi=%"SCNi8",nshc1=0x%"SCNx32",nshc2=0x%"SCNx32 + ",nshc3=0x%"SCNx32",nshc4=0x%"SCNx32"))", ++ ETH_ADDR_SCAN_ARGS(eth_nsh_header->encap_eth_header.encap_eth_dst), ++ ETH_ADDR_SCAN_ARGS(eth_nsh_header->encap_eth_header.encap_eth_src), ++ ð_nsh_header->encap_eth_header.encap_eth_type, + &nsh_mdtype, &nsh_np, + &nsp, &nsi, + &nshc1, &nshc2, + &nshc3, &nshc4)) { ++ eth_nsh_header->encap_eth_header.encap_eth_type = htons(eth_nsh_header->encap_eth_header.encap_eth_type); + if (nsh_mdtype == NSH_M_TYPE1) { -+ nsh->base.mdtype = NSH_M_TYPE1; -+ nsh->base.version = 0x01; -+ nsh->base.length = 6; -+ nsh->base.proto = nsh_np; -+ nsh->base.path_hdr= nsp; -+ nsh->base.svc_idx = nsi; -+ nsh->ctx.nshc1=nshc1; -+ nsh->ctx.nshc2=nshc2; -+ nsh->ctx.nshc3=nshc3; -+ nsh->ctx.nshc4=nshc4; ++ eth_nsh_header->encap_eth_header.encap_eth_type = htons(ETH_P_NSH); ++ eth_nsh_header->nsh_hdr.base.mdtype = NSH_M_TYPE1; ++ eth_nsh_header->nsh_hdr.base.version = 0x01; ++ eth_nsh_header->nsh_hdr.base.length = 6; ++ eth_nsh_header->nsh_hdr.base.proto = nsh_np; ++ eth_nsh_header->nsh_hdr.base.path_hdr= nsp; ++ eth_nsh_header->nsh_hdr.base.svc_idx = nsi; ++ eth_nsh_header->nsh_hdr.ctx.nshc1=nshc1; ++ eth_nsh_header->nsh_hdr.ctx.nshc2=nshc2; ++ eth_nsh_header->nsh_hdr.ctx.nshc3=nshc3; ++ eth_nsh_header->nsh_hdr.ctx.nshc4=nshc4; + push.nsh_mdtype = NSH_M_TYPE1; + nl_msg_put_unspec(actions, OVS_ACTION_ATTR_PUSH_NSH, + &push, sizeof push); @@ -1780,47 +2178,28 @@ index 7983720..102dfd7 100644 + return 7; + } + -+ { -+ struct ovs_action_push_eth push; -+ struct encap_eth_hdr *encap_eth = (struct encap_eth_hdr *)push.header; -+ uint16_t encap_eth_type; -+ int n = -1; -+ -+ if (ovs_scan_len(s, &n, "push_eth(encap_eth_type=0x%"SCNx16",encap_eth_dst="ETH_ADDR_SCAN_FMT",encap_eth_src="ETH_ADDR_SCAN_FMT")", -+ &encap_eth_type, -+ ETH_ADDR_SCAN_ARGS(encap_eth->encap_eth_dst), -+ ETH_ADDR_SCAN_ARGS(encap_eth->encap_eth_src))) { -+ if (encap_eth->encap_eth_type == ETH_P_NSH) { -+ push.encap_eth_type = ETH_P_NSH; -+ encap_eth->encap_eth_type = htons(ETH_P_NSH); -+ nl_msg_put_unspec(actions, OVS_ACTION_ATTR_PUSH_ETH, -+ &push, sizeof push); -+ } -+ -+ return n; -+ } -+ -+ } -+ -+ if (!strncmp(s, "pop_eth", 7)) { -+ nl_msg_put_flag(actions, OVS_ACTION_ATTR_POP_ETH); -+ return 7; -+ } -+ + { double percentage; int n = -1; -@@ -1759,6 +1881,8 @@ static const struct attr_len_tbl ovs_flow_key_attr_lens[OVS_KEY_ATTR_MAX + 1] = +@@ -1787,6 +1872,7 @@ static const struct attr_len_tbl ovs_flow_key_attr_lens[OVS_KEY_ATTR_MAX + 1] = .next = ovs_tun_key_attr_lens, .next_max = OVS_TUNNEL_KEY_ATTR_MAX }, [OVS_KEY_ATTR_IN_PORT] = { .len = 4 }, -+ [OVS_KEY_ATTR_ENCAP_ETH] = { .len = 14 }, -+ [OVS_KEY_ATTR_NSH] = { .len = 24 }, ++ [OVS_KEY_ATTR_NSH] = { .len = sizeof(struct ovs_key_nsh) }, [OVS_KEY_ATTR_ETHERNET] = { .len = sizeof(struct ovs_key_ethernet) }, [OVS_KEY_ATTR_VLAN] = { .len = 2 }, [OVS_KEY_ATTR_ETHERTYPE] = { .len = 2 }, -@@ -2146,6 +2270,23 @@ format_be64(struct ds *ds, const char *name, ovs_be64 key, +@@ -1924,7 +2010,7 @@ odp_tun_key_from_attr__(const struct nlattr *attr, + }; + struct nlattr *ext[ARRAY_SIZE(vxlan_opts_policy)]; + +- if (!nl_parse_nested(a, vxlan_opts_policy, ext, ARRAY_SIZE(ext))) { ++ if (!nl_parse_nested(a, vxlan_opts_policy, ext, ARRAY_SIZE(vxlan_opts_policy))) { + return ODP_FIT_ERROR; + } + +@@ -2173,6 +2259,23 @@ format_be64(struct ds *ds, const char *name, ovs_be64 key, } static void @@ -1844,7 +2223,7 @@ index 7983720..102dfd7 100644 format_ipv4(struct ds *ds, const char *name, ovs_be32 key, const ovs_be32 *mask, bool verbose) { -@@ -2798,6 +2939,34 @@ format_odp_key_attr(const struct nlattr *a, const struct nlattr *ma, +@@ -2827,6 +2930,25 @@ format_odp_key_attr(const struct nlattr *a, const struct nlattr *ma, } break; @@ -1852,6 +2231,9 @@ index 7983720..102dfd7 100644 + const struct ovs_key_nsh *mask = ma ? nl_attr_get(ma) : NULL; + const struct ovs_key_nsh *key = nl_attr_get(a); + ++ format_eth(ds, "encap_eth_src", key->encap_eth_src, MASK(mask, encap_eth_src), verbose); ++ format_eth(ds, "encap_eth_dst", key->encap_eth_dst, MASK(mask, encap_eth_dst), verbose); ++ format_be16x(ds, "encap_eth_type", key->encap_eth_type, MASK(mask, encap_eth_type), verbose); + format_u8u(ds, "nsi", key->nsi, MASK(mask, nsi), verbose); + format_be32(ds, "nsp", key->nsp, MASK(mask, nsp), verbose); + format_u8u(ds, "nsh_mdtype", key->nsh_mdtype, MASK(mask, nsh_mdtype), verbose); @@ -1863,23 +2245,11 @@ index 7983720..102dfd7 100644 + ds_chomp(ds, ','); + break; + } -+ -+ case OVS_KEY_ATTR_ENCAP_ETH: { -+ const struct ovs_key_encap_eth *mask = ma ? nl_attr_get(ma) : NULL; -+ const struct ovs_key_encap_eth *key = nl_attr_get(a); -+ -+ format_be16(ds, "encap_eth_type", key->encap_eth_type, MASK(mask, encap_eth_type), verbose); -+ format_eth(ds, "encap_eth_src", key->encap_eth_src, MASK(mask, encap_eth_src), verbose); -+ format_eth(ds, "encap_eth_dst", key->encap_eth_dst, MASK(mask, encap_eth_dst), verbose); -+ ds_chomp(ds, ','); -+ -+ break; -+ } + case OVS_KEY_ATTR_ETHERNET: { const struct ovs_key_ethernet *mask = ma ? nl_attr_get(ma) : NULL; const struct ovs_key_ethernet *key = nl_attr_get(a); -@@ -3184,6 +3353,48 @@ scan_eth(const char *s, struct eth_addr *key, struct eth_addr *mask) +@@ -3219,6 +3341,27 @@ scan_eth(const char *s, struct eth_addr *key, struct eth_addr *mask) } static int @@ -1903,36 +2273,18 @@ index 7983720..102dfd7 100644 + return 0; +} + -+static int -+scan_encap_eth_type(const char *s, uint16_t *key, uint16_t *mask) -+{ -+ int n; -+ -+ if (ovs_scan(s, "%"SCNi16"%n", key, &n)) { -+ int len = n; -+ *key = htons(*key); -+ if (mask) { -+ if (ovs_scan(s + len, "/%"SCNi16"%n", mask, &n)) { -+ len += n; -+ *mask = htons(*mask); -+ } else { -+ *mask = UINT16_MAX; -+ } -+ } -+ return len; -+ } -+ return 0; -+} -+ +static int scan_ipv4(const char *s, ovs_be32 *key, ovs_be32 *mask) { int n; -@@ -4123,6 +4334,23 @@ parse_odp_key_mask_attr(const char *s, const struct simap *port_names, +@@ -4158,6 +4301,20 @@ 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_BEGIN("nsh(", struct ovs_key_nsh) { ++ SCAN_FIELD("encap_eth_dst=", eth, encap_eth_dst); ++ SCAN_FIELD("encap_eth_src=", eth, encap_eth_src); ++ SCAN_FIELD("encap_eth_type=", be16, encap_eth_type); + SCAN_FIELD("nsh_mdtype=", u8, nsh_mdtype); + SCAN_FIELD("nsh_np=", u8, nsh_np); + SCAN_FIELD("nsp=", nsp, nsp); @@ -1942,17 +2294,11 @@ index 7983720..102dfd7 100644 + SCAN_FIELD("nshc3=", u32, nshc3); + SCAN_FIELD("nshc4=", u32, nshc4); + } SCAN_END(OVS_KEY_ATTR_NSH); -+ -+ SCAN_BEGIN("encap_eth(", struct ovs_key_encap_eth) { -+ SCAN_FIELD("encap_eth_src=", eth, encap_eth_src); -+ SCAN_FIELD("encap_eth_dst=", eth, encap_eth_dst); -+ SCAN_FIELD("encap_eth_type=", encap_eth_type, encap_eth_type); -+ } SCAN_END(OVS_KEY_ATTR_ENCAP_ETH); + SCAN_SINGLE_PORT("in_port(", uint32_t, OVS_KEY_ATTR_IN_PORT); SCAN_BEGIN("eth(", struct ovs_key_ethernet) { -@@ -4325,11 +4553,35 @@ union ovs_key_tp { +@@ -4360,11 +4517,30 @@ union ovs_key_tp { static void get_tp_key(const struct flow *, union ovs_key_tp *); static void put_tp_key(const union ovs_key_tp *, struct flow *); @@ -1963,19 +2309,15 @@ index 7983720..102dfd7 100644 + nsh->nsp = flow->nsp; + nsh->nsh_mdtype = flow->nsh_mdtype; + nsh->nsh_np = flow->nsh_np; -+ nsh->reserved = 0; + nsh->nshc1 = flow->nshc1; + nsh->nshc2 = flow->nshc2; + nsh->nshc3 = flow->nshc3; + nsh->nshc4 = flow->nshc4; -+} -+ -+void -+get_encap_eth_key(const struct flow *flow, struct ovs_key_encap_eth *encap_eth) -+{ -+ encap_eth->encap_eth_type = flow->encap_eth_type; -+ encap_eth->encap_eth_src = flow->encap_eth_src; -+ encap_eth->encap_eth_dst = flow->encap_eth_dst; ++ nsh->pad2 = 0; ++ nsh->encap_eth_src = flow->encap_eth_src; ++ nsh->encap_eth_dst = flow->encap_eth_dst; ++ nsh->encap_eth_type = flow->encap_eth_type; ++ nsh->pad1 = 0; +} + static void @@ -1984,12 +2326,11 @@ index 7983720..102dfd7 100644 { struct ovs_key_ethernet *eth_key; + struct ovs_key_nsh *nsh_key; -+ struct ovs_key_encap_eth *encap_eth_key; size_t encap; const struct flow *flow = parms->flow; const struct flow *data = export_mask ? parms->mask : parms->flow; -@@ -4368,6 +4620,18 @@ odp_flow_key_from_flow__(const struct odp_flow_key_parms *parms, - nl_msg_put_odp_port(buf, OVS_KEY_ATTR_IN_PORT, parms->odp_in_port); +@@ -4403,6 +4579,12 @@ odp_flow_key_from_flow__(const struct odp_flow_key_parms *parms, + nl_msg_put_odp_port(buf, OVS_KEY_ATTR_IN_PORT, data->in_port.odp_port); } + if (flow->nsh_mdtype) { @@ -1997,17 +2338,11 @@ index 7983720..102dfd7 100644 + sizeof *nsh_key); + get_nsh_key(data, nsh_key); + } -+ -+ if (flow->encap_eth_type) { -+ encap_eth_key = nl_msg_put_unspec_uninit(buf, OVS_KEY_ATTR_ENCAP_ETH, -+ sizeof *encap_eth_key); -+ get_encap_eth_key(data, encap_eth_key); -+ } + eth_key = nl_msg_put_unspec_uninit(buf, OVS_KEY_ATTR_ETHERNET, sizeof *eth_key); get_ethernet_key(data, eth_key); -@@ -5225,6 +5489,28 @@ odp_flow_key_to_flow__(const struct nlattr *key, size_t key_len, +@@ -5256,6 +5438,15 @@ odp_flow_key_to_flow__(const struct nlattr *key, size_t key_len, flow->in_port.odp_port = ODPP_NONE; } @@ -2017,26 +2352,13 @@ index 7983720..102dfd7 100644 + + nsh_key = nl_attr_get(attrs[OVS_KEY_ATTR_NSH]); + put_nsh_key(nsh_key, flow); -+ if (is_mask) { -+ expected_attrs |= UINT64_C(1) << OVS_KEY_ATTR_NSH; -+ } -+ } -+ -+ /* ENCAP Eth header. */ -+ if (present_attrs & (UINT64_C(1) << OVS_KEY_ATTR_ENCAP_ETH)) { -+ const struct ovs_key_encap_eth *encap_eth_key; -+ -+ encap_eth_key = nl_attr_get(attrs[OVS_KEY_ATTR_ENCAP_ETH]); -+ put_encap_eth_key(encap_eth_key, flow); -+ if (is_mask) { -+ expected_attrs |= UINT64_C(1) << OVS_KEY_ATTR_ENCAP_ETH; -+ } ++ expected_attrs |= UINT64_C(1) << OVS_KEY_ATTR_NSH; + } + /* Ethernet header. */ if (present_attrs & (UINT64_C(1) << OVS_KEY_ATTR_ETHERNET)) { const struct ovs_key_ethernet *eth_key; -@@ -5526,6 +5812,41 @@ put_ethernet_key(const struct ovs_key_ethernet *eth, struct flow *flow) +@@ -5557,6 +5748,29 @@ put_ethernet_key(const struct ovs_key_ethernet *eth, struct flow *flow) flow->dl_dst = eth->eth_dst; } @@ -2051,77 +2373,65 @@ index 7983720..102dfd7 100644 + flow->nshc2 = nsh->nshc2; + flow->nshc3 = nsh->nshc3; + flow->nshc4 = nsh->nshc4; ++ flow->encap_eth_src = nsh->encap_eth_src; ++ flow->encap_eth_dst = nsh->encap_eth_dst; ++ flow->encap_eth_type = nsh->encap_eth_type; +} + +void +flow_zero_nsh(struct flow *flow) +{ -+ void *dst_p = &(flow->nshc1); -+ memset(dst_p, 0, 24); -+} -+ -+void -+flow_zero_encap_eth(struct flow *flow) -+{ -+ void *dst_p = &flow->encap_eth_src; -+ memset(dst_p, 0, 16); -+} -+ -+void -+put_encap_eth_key(const struct ovs_key_encap_eth *encap_eth, struct flow *flow) -+{ -+ flow->encap_eth_type = encap_eth->encap_eth_type; -+ flow->encap_eth_src = encap_eth->encap_eth_src; -+ flow->encap_eth_dst = encap_eth->encap_eth_dst; ++ void *dst_p = &(flow->encap_eth_dst); ++ memset(dst_p, 0, 40); +} + static void commit_set_ether_addr_action(const struct flow *flow, struct flow *base_flow, struct ofpbuf *odp_actions, -@@ -5577,6 +5898,94 @@ commit_vlan_action(ovs_be16 vlan_tci, struct flow *base, +@@ -5608,6 +5822,64 @@ commit_vlan_action(ovs_be16 vlan_tci, struct flow *base, base->vlan_tci = vlan_tci; } +static void -+commit_nsh_pop_action(const struct flow *flow, struct flow *base, -+ struct ofpbuf *odp_actions, struct flow_wildcards *wc) ++commit_nsh_pop_action(const struct ovs_key_nsh *flow_key, ++ const struct ovs_key_nsh *base_key, ++ struct ofpbuf *odp_actions, struct flow_wildcards *wc) +{ -+ struct ovs_key_nsh flow_key, base_key; -+ get_nsh_key(flow, &flow_key); -+ get_nsh_key(base, &base_key); + -+ if (memcmp(&flow_key, &base_key, sizeof flow_key)) { ++ if (memcmp(flow_key, base_key, sizeof (struct ovs_key_nsh))) { + memset(&wc->masks.nsh_mdtype, 0xff, sizeof wc->masks.nsh_mdtype); + -+ if (base->nsh_mdtype) { ++ if (base_key->nsh_mdtype) { + nl_msg_put_flag(odp_actions, OVS_ACTION_ATTR_POP_NSH); + } + } +} + +static void -+commit_nsh_push_action(const struct flow *flow, struct flow *base, -+ struct ofpbuf *odp_actions) ++commit_nsh_push_action(const struct ovs_key_nsh *flow_key, ++ const struct ovs_key_nsh *base_key, ++ struct ofpbuf *odp_actions) +{ -+ struct ovs_key_nsh flow_key, base_key; -+ get_nsh_key(flow, &flow_key); -+ get_nsh_key(base, &base_key); -+ -+ if (memcmp(&flow_key, &base_key, sizeof flow_key)) { -+ if (flow->nsh_mdtype) { ++ if (memcmp(flow_key, base_key, sizeof (struct ovs_key_nsh))) { ++ if (flow_key->nsh_mdtype) { + struct ovs_action_push_nsh nsh; -+ nsh.nsh_mdtype = flow->nsh_mdtype; -+ struct nsh_hdr *nsh_hdr = (struct nsh_hdr *)nsh.header; -+ memset(nsh_hdr, 0, sizeof *nsh_hdr); -+ nsh_hdr->base.length = 6; -+ nsh_hdr->base.proto = flow->nsh_np; -+ nsh_hdr->base.mdtype = flow->nsh_mdtype; -+ nsh_hdr->base.proto = flow->nsh_np; -+ nsh_hdr->base.path_hdr = flow->nsp >> 8 | flow->nsi << 24; -+ nsh_hdr->ctx.nshc1 = flow->nshc1; -+ nsh_hdr->ctx.nshc2 = flow->nshc2; -+ nsh_hdr->ctx.nshc3 = flow->nshc3; -+ nsh_hdr->ctx.nshc4 = flow->nshc4; ++ nsh.nsh_mdtype = flow_key->nsh_mdtype; ++ struct eth_nsh_hdr *eth_nsh_header = (struct eth_nsh_hdr *)nsh.header; ++ memset(eth_nsh_header, 0, sizeof *eth_nsh_header); ++ eth_nsh_header->nsh_hdr.base.length = 6; ++ eth_nsh_header->nsh_hdr.base.proto = flow_key->nsh_np; ++ eth_nsh_header->nsh_hdr.base.mdtype = flow_key->nsh_mdtype; ++ eth_nsh_header->nsh_hdr.base.proto = flow_key->nsh_np; ++ eth_nsh_header->nsh_hdr.base.path_hdr = flow_key->nsp >> 8 | flow_key->nsi << 24; ++ eth_nsh_header->nsh_hdr.ctx.nshc1 = flow_key->nshc1; ++ eth_nsh_header->nsh_hdr.ctx.nshc2 = flow_key->nshc2; ++ eth_nsh_header->nsh_hdr.ctx.nshc3 = flow_key->nshc3; ++ eth_nsh_header->nsh_hdr.ctx.nshc4 = flow_key->nshc4; ++ ++ eth_nsh_header->encap_eth_header.encap_eth_type = htons(ETH_P_NSH); ++ eth_nsh_header->encap_eth_header.encap_eth_dst = flow_key->encap_eth_dst; ++ eth_nsh_header->encap_eth_header.encap_eth_src = flow_key->encap_eth_src; ++ + nl_msg_put_unspec(odp_actions, OVS_ACTION_ATTR_PUSH_NSH, + &nsh, sizeof nsh); + } @@ -2129,63 +2439,30 @@ index 7983720..102dfd7 100644 +} + +static void -+commit_encap_eth_pop_action(const struct flow *flow, struct flow *base, ++commit_nsh_action(const struct flow *flow, struct flow *base, + struct ofpbuf *odp_actions, struct flow_wildcards *wc) +{ -+ struct ovs_key_encap_eth flow_key, base_key; -+ get_encap_eth_key(flow, &flow_key); -+ get_encap_eth_key(base, &base_key); -+ -+ if (memcmp(&flow_key, &base_key, sizeof flow_key)) { -+ memset(&wc->masks.encap_eth_type, 0xff, sizeof wc->masks.encap_eth_type); -+ -+ if (base->encap_eth_type) { -+ nl_msg_put_flag(odp_actions, OVS_ACTION_ATTR_POP_ETH); -+ } -+ } ++ struct ovs_key_nsh flow_key, base_key; ++ get_nsh_key(flow, &flow_key); ++ get_nsh_key(base, &base_key); ++ commit_nsh_pop_action(&flow_key, &base_key, odp_actions, wc); ++ commit_nsh_push_action(&flow_key, &base_key, odp_actions); +} + -+static void -+commit_encap_eth_push_action(const struct flow *flow, struct flow *base, -+ struct ofpbuf *odp_actions) -+{ -+ struct ovs_key_encap_eth flow_key, base_key; -+ get_encap_eth_key(flow, &flow_key); -+ get_encap_eth_key(base, &base_key); -+ -+ if (memcmp(&flow_key, &base_key, sizeof flow_key)) { -+ if (flow->encap_eth_type) { -+ struct ovs_action_push_eth encap_eth; -+ encap_eth.encap_eth_type = flow->encap_eth_type; -+ struct encap_eth_hdr *encap_eth_header = -+ (struct encap_eth_hdr *)encap_eth.header; -+ void *dst_p = encap_eth_header->encap_eth_dst.ea; -+ void *src_p = encap_eth_header->encap_eth_src.ea; -+ memcpy(dst_p, flow->encap_eth_dst.ea, sizeof flow->encap_eth_dst); -+ memcpy(src_p, flow->encap_eth_src.ea, sizeof flow->encap_eth_src); -+ encap_eth_header->encap_eth_type = htons(ETH_P_NSH); -+ nl_msg_put_unspec(odp_actions, OVS_ACTION_ATTR_PUSH_ETH, -+ &encap_eth, sizeof encap_eth); -+ } -+ } -+} + /* Wildcarding already done at action translation time. */ static void commit_mpls_action(const struct flow *flow, struct flow *base, -@@ -6008,6 +6417,10 @@ commit_odp_actions(const struct flow *flow, struct flow *base, +@@ -6039,6 +6311,7 @@ commit_odp_actions(const struct flow *flow, struct flow *base, slow2 = commit_set_icmp_action(flow, base, odp_actions, wc); commit_mpls_action(flow, base, odp_actions); commit_vlan_action(flow->vlan_tci, base, odp_actions, wc); -+ commit_encap_eth_pop_action(flow, base, odp_actions, wc); -+ commit_nsh_pop_action(flow, base, odp_actions, wc); -+ commit_nsh_push_action(flow, base, odp_actions); -+ commit_encap_eth_push_action(flow, base, odp_actions); ++ commit_nsh_action(flow, base, odp_actions, wc); commit_set_priority_action(flow, base, odp_actions, wc, use_masked); commit_set_pkt_mark_action(flow, base, odp_actions, wc, use_masked); diff --git a/lib/odp-util.h b/lib/odp-util.h -index 51cf5c3..2cb04f1 100644 +index a41bc76..c701482 100644 --- a/lib/odp-util.h +++ b/lib/odp-util.h @@ -66,7 +66,7 @@ enum slow_path_reason { @@ -2197,52 +2474,51 @@ index 51cf5c3..2cb04f1 100644 SLOW_PATH_REASONS #undef SPR }; -@@ -126,6 +126,8 @@ void odp_portno_names_destroy(struct hmap *portno_names); +@@ -126,6 +126,7 @@ void odp_portno_names_destroy(struct hmap *portno_names); * OVS_KEY_ATTR_CT_ZONE 2 2 4 8 * OVS_KEY_ATTR_CT_MARK 4 -- 4 8 * OVS_KEY_ATTR_CT_LABEL 16 -- 4 20 -+ * OVS_KEY_ATTR_NSH 24 -- 4 28 -+ * OVS_KEY_ATTR_ENCAP 14 -- 4 18 ++ * OVS_KEY_ATTR_NSH 40 -- 4 44 * OVS_KEY_ATTR_ETHERNET 12 -- 4 16 * OVS_KEY_ATTR_ETHERTYPE 2 2 4 8 (outer VLAN ethertype) * OVS_KEY_ATTR_VLAN 2 2 4 8 -@@ -150,6 +152,12 @@ struct odputil_keybuf { +@@ -150,6 +151,9 @@ struct odputil_keybuf { uint32_t keybuf[DIV_ROUND_UP(ODPUTIL_FLOW_KEY_BYTES, 4)]; }; +void put_nsh_key(const struct ovs_key_nsh *, struct flow *); +void get_nsh_key(const struct flow *flow, struct ovs_key_nsh *nsh); -+void put_encap_eth_key(const struct ovs_key_encap_eth *encap_eth, struct flow *flow); -+void get_encap_eth_key(const struct flow *flow, struct ovs_key_encap_eth *encap_eth); +void flow_zero_nsh(struct flow *); -+void flow_zero_encap_eth(struct flow *); enum odp_key_fitness odp_tun_key_from_attr(const struct nlattr *, bool udpif, struct flow_tnl *); diff --git a/lib/ofp-actions.c b/lib/ofp-actions.c -index aac4ff0..f4062b2 100644 +index 15dbdec..2935ca6 100644 --- a/lib/ofp-actions.c +++ b/lib/ofp-actions.c -@@ -299,6 +299,18 @@ enum ofp_raw_action_type { - /* NX1.0+(36): struct nx_action_nat, ... */ - NXAST_RAW_NAT, +@@ -304,6 +304,12 @@ enum ofp_raw_action_type { + /* NX1.0+(39): struct nx_action_output_trunc. */ + NXAST_RAW_OUTPUT_TRUNC, -+ /* NX1.0+(38): void. */ ++ /* NX1.0+(200): void. */ + NXAST_RAW_PUSH_NSH, + -+ /* NX1.0+(39): void. */ ++ /* NX1.0+(201): void. */ + NXAST_RAW_POP_NSH, -+ -+ /* NX1.0+(40): void. */ -+ NXAST_RAW_PUSH_ETH, -+ -+ /* NX1.0+(41): void. */ -+ NXAST_RAW_POP_ETH, + /* ## ------------------ ## */ /* ## Debugging actions. ## */ /* ## ------------------ ## */ -@@ -1624,7 +1636,127 @@ format_PUSH_VLAN(const struct ofpact_null *a OVS_UNUSED, struct ds *s) +@@ -394,6 +400,8 @@ ofpact_next_flattened(const struct ofpact *ofpact) + case OFPACT_SET_VLAN_PCP: + case OFPACT_STRIP_VLAN: + case OFPACT_PUSH_VLAN: ++ case OFPACT_PUSH_NSH: ++ case OFPACT_POP_NSH: + case OFPACT_SET_ETH_SRC: + case OFPACT_SET_ETH_DST: + case OFPACT_SET_IPV4_SRC: +@@ -1673,7 +1681,67 @@ format_PUSH_VLAN(const struct ofpact_null *a OVS_UNUSED, struct ds *s) ds_put_format(s, "%spush_vlan:%s%#"PRIx16, colors.param, colors.end, ETH_TYPE_VLAN_8021Q); } @@ -2307,157 +2583,117 @@ index aac4ff0..f4062b2 100644 +{ + ds_put_format(s, "pop_nsh"); +} -+ -+/* Push ENCAP Eth header actions. */ -+static enum ofperr -+decode_NXAST_RAW_PUSH_ETH(struct ofpbuf * out) -+{ -+ ofpact_put_PUSH_ETH(out)->ofpact.raw = NXAST_RAW_PUSH_ETH; -+ -+ return 0; -+} -+ -+static void -+encode_PUSH_ETH(const struct ofpact_null *null OVS_UNUSED, -+ enum ofp_version ofp_version OVS_UNUSED, struct ofpbuf *out) -+{ -+ put_NXAST_PUSH_ETH(out); -+} -+ -+static char * OVS_WARN_UNUSED_RESULT -+parse_PUSH_ETH(char *arg OVS_UNUSED, struct ofpbuf *ofpacts, -+ enum ofputil_protocol *usable_protocols OVS_UNUSED) -+{ -+ ofpact_put_PUSH_ETH(ofpacts)->ofpact.raw = NXAST_RAW_PUSH_ETH;; -+ return NULL; -+} -+ -+static void -+format_PUSH_ETH(const struct ofpact_null *a OVS_UNUSED, struct ds *s) -+{ -+ ds_put_format(s, "push_eth"); -+} -+ -+/* Pop ENCAP ETH header actions. */ -+static enum ofperr -+decode_NXAST_RAW_POP_ETH(struct ofpbuf * out) -+{ -+ ofpact_put_POP_ETH(out)->ofpact.raw = NXAST_RAW_POP_ETH; -+ -+ return 0; -+} -+ -+static void -+encode_POP_ETH(const struct ofpact_null *null OVS_UNUSED, -+ enum ofp_version ofp_version OVS_UNUSED, struct ofpbuf *out) -+{ -+ put_NXAST_POP_ETH(out); -+} -+ -+static char * OVS_WARN_UNUSED_RESULT -+parse_POP_ETH(char *arg OVS_UNUSED, struct ofpbuf *ofpacts, -+ enum ofputil_protocol *usable_protocols OVS_UNUSED) -+{ -+ ofpact_put_POP_ETH(ofpacts)->ofpact.raw = NXAST_RAW_POP_ETH; -+ return NULL; -+} -+ -+static void -+format_POP_ETH(const struct ofpact_null *a OVS_UNUSED, struct ds *s) -+{ -+ ds_put_format(s, "pop_eth"); -+} + /* Action structure for OFPAT10_SET_DL_SRC/DST and OFPAT11_SET_DL_SRC/DST. */ struct ofp_action_dl_addr { ovs_be16 type; /* Type. */ -@@ -5910,6 +6042,10 @@ ofpact_is_set_or_move_action(const struct ofpact *a) +@@ -6181,6 +6249,8 @@ ofpact_is_set_or_move_action(const struct ofpact *a) case OFPACT_POP_QUEUE: case OFPACT_PUSH_MPLS: case OFPACT_PUSH_VLAN: + case OFPACT_PUSH_NSH: + case OFPACT_POP_NSH: -+ case OFPACT_PUSH_ETH: -+ case OFPACT_POP_ETH: case OFPACT_RESUBMIT: case OFPACT_SAMPLE: case OFPACT_STACK_POP: -@@ -5937,6 +6073,10 @@ ofpact_is_allowed_in_actions_set(const struct ofpact *a) +@@ -6209,6 +6279,8 @@ ofpact_is_allowed_in_actions_set(const struct ofpact *a) case OFPACT_POP_MPLS: case OFPACT_PUSH_MPLS: case OFPACT_PUSH_VLAN: + case OFPACT_PUSH_NSH: + case OFPACT_POP_NSH: -+ case OFPACT_PUSH_ETH: -+ case OFPACT_POP_ETH: case OFPACT_REG_MOVE: case OFPACT_SET_FIELD: case OFPACT_SET_ETH_DST: -@@ -6162,6 +6302,10 @@ ovs_instruction_type_from_ofpact_type(enum ofpact_type type) +@@ -6436,6 +6508,8 @@ ovs_instruction_type_from_ofpact_type(enum ofpact_type type) case OFPACT_SET_VLAN_PCP: case OFPACT_STRIP_VLAN: case OFPACT_PUSH_VLAN: + case OFPACT_PUSH_NSH: + case OFPACT_POP_NSH: -+ case OFPACT_PUSH_ETH: -+ case OFPACT_POP_ETH: case OFPACT_SET_ETH_SRC: case OFPACT_SET_ETH_DST: case OFPACT_SET_IPV4_SRC: -@@ -6709,6 +6853,10 @@ ofpact_check__(enum ofputil_protocol *usable_protocols, struct ofpact *a, - case OFPACT_SET_TUNNEL: - case OFPACT_SET_QUEUE: - case OFPACT_POP_QUEUE: -+ case OFPACT_PUSH_NSH: -+ case OFPACT_POP_NSH: -+ case OFPACT_PUSH_ETH: -+ case OFPACT_POP_ETH: - case OFPACT_RESUBMIT: +@@ -6909,6 +6983,8 @@ ofpact_check__(enum ofputil_protocol *usable_protocols, struct ofpact *a, + flow->vlan_tci |= htons(VLAN_CFI); return 0; -@@ -7266,6 +7414,10 @@ ofpact_outputs_to_port(const struct ofpact *ofpact, ofp_port_t port) ++ case OFPACT_PUSH_NSH: ++ case OFPACT_POP_NSH: + case OFPACT_SET_ETH_SRC: + case OFPACT_SET_ETH_DST: + return 0; +@@ -7548,6 +7624,8 @@ ofpact_outputs_to_port(const struct ofpact *ofpact, ofp_port_t port) case OFPACT_SET_VLAN_PCP: case OFPACT_STRIP_VLAN: case OFPACT_PUSH_VLAN: + case OFPACT_PUSH_NSH: + case OFPACT_POP_NSH: -+ case OFPACT_PUSH_ETH: -+ case OFPACT_POP_ETH: case OFPACT_SET_ETH_SRC: case OFPACT_SET_ETH_DST: case OFPACT_SET_IPV4_SRC: -diff --git a/lib/ofp-actions.h b/lib/ofp-actions.h -index 4bd8854..3897c0b 100644 ---- a/lib/ofp-actions.h -+++ b/lib/ofp-actions.h -@@ -93,6 +93,12 @@ - OFPACT(POP_QUEUE, ofpact_null, ofpact, "pop_queue") \ - OFPACT(FIN_TIMEOUT, ofpact_fin_timeout, ofpact, "fin_timeout") \ - \ -+ /* NSH */ \ -+ OFPACT(PUSH_NSH, ofpact_null, ofpact, "push_nsh") \ -+ OFPACT(POP_NSH, ofpact_null, ofpact, "pop_nsh") \ -+ OFPACT(PUSH_ETH, ofpact_null, ofpact, "push_eth") \ -+ OFPACT(POP_ETH, ofpact_null, ofpact, "pop_eth") \ -+ \ - /* Flow table interaction. */ \ - OFPACT(RESUBMIT, ofpact_resubmit, ofpact, "resubmit") \ - OFPACT(LEARN, ofpact_learn, specs, "learn") \ +diff --git a/lib/packets.c b/lib/packets.c +index e4c29d5..59afd0c 100644 +--- a/lib/packets.c ++++ b/lib/packets.c +@@ -245,6 +245,29 @@ set_ethertype(struct dp_packet *packet, ovs_be16 eth_type) + } + } + ++void ++push_nsh(struct dp_packet *packet, const void *nsh) ++{ ++ void *header; ++ const struct ovs_action_push_nsh *push_nsh_hdr = (const struct ovs_action_push_nsh *)nsh; ++ const uint8_t *pdata = push_nsh_hdr->header; ++ /* Now only support MD type1 */ ++ if (push_nsh_hdr->nsh_mdtype != NSH_M_TYPE1) ++ return; ++ header = dp_packet_push_uninit(packet, ETH_NSH_TYPE1_HEADER_SIZE); ++ ++ memcpy(header, pdata, ETH_NSH_TYPE1_HEADER_SIZE); ++} ++ ++void ++pop_nsh(struct dp_packet *packet) ++{ ++ if (ETH_NSH_TYPE1_HEADER_SIZE > dp_packet_size(packet)) { ++ return; ++ } ++ dp_packet_reset_packet(packet, ETH_NSH_TYPE1_HEADER_SIZE); ++} ++ + static bool is_mpls(struct dp_packet *packet) + { + return packet->l2_5_ofs != UINT16_MAX; +diff --git a/lib/packets.h b/lib/packets.h +index dcfcd04..9d97a8a 100644 +--- a/lib/packets.h ++++ b/lib/packets.h +@@ -279,6 +279,9 @@ void compose_rarp(struct dp_packet *, const struct eth_addr); + void eth_push_vlan(struct dp_packet *, ovs_be16 tpid, ovs_be16 tci); + void eth_pop_vlan(struct dp_packet *); + ++void push_nsh(struct dp_packet *packet, const void *nsh); ++void pop_nsh(struct dp_packet *packet); ++ + const char *eth_from_hex(const char *hex, struct dp_packet **packetp); + void eth_format_masked(const struct eth_addr ea, + const struct eth_addr *mask, struct ds *s); diff --git a/ofproto/ofproto-dpif-sflow.c b/ofproto/ofproto-dpif-sflow.c -index fbc82b7..e15e8d2 100644 +index c3234ee..faf5c76 100644 --- a/ofproto/ofproto-dpif-sflow.c +++ b/ofproto/ofproto-dpif-sflow.c -@@ -976,6 +976,8 @@ sflow_read_set_action(const struct nlattr *attr, +@@ -970,6 +970,7 @@ sflow_read_set_action(const struct nlattr *attr, case OVS_KEY_ATTR_IN_PORT: case OVS_KEY_ATTR_ETHERNET: case OVS_KEY_ATTR_VLAN: + case OVS_KEY_ATTR_NSH: -+ case OVS_KEY_ATTR_ENCAP_ETH: break; case OVS_KEY_ATTR_MPLS: { diff --git a/ofproto/ofproto-dpif-upcall.c b/ofproto/ofproto-dpif-upcall.c -index 2612b7d..f59eed8 100644 +index bffbf35..f673ced 100644 --- a/ofproto/ofproto-dpif-upcall.c +++ b/ofproto/ofproto-dpif-upcall.c @@ -39,6 +39,7 @@ @@ -2468,94 +2704,101 @@ index 2612b7d..f59eed8 100644 #define MAX_QUEUE_LENGTH 512 #define UPCALL_MAX_BATCH 64 -@@ -746,6 +747,9 @@ recv_upcalls(struct handler *handler) +@@ -746,6 +747,8 @@ recv_upcalls(struct handler *handler) struct upcall *upcall = &upcalls[n_upcalls]; struct flow *flow = &flows[n_upcalls]; unsigned int mru; + struct ovs_key_nsh reserve_nsh; -+ struct ovs_key_encap_eth reserve_encap_eth; + bool nsh_mdtype_flag, encap_eth_type_flag; int error; ofpbuf_use_stub(recv_buf, recv_stubs[n_upcalls], -@@ -796,8 +800,23 @@ recv_upcalls(struct handler *handler) - } +@@ -792,8 +795,16 @@ recv_upcalls(struct handler *handler) + upcall->actions = dupcall->actions; pkt_metadata_from_flow(&dupcall->packet.md, flow); + + nsh_mdtype_flag = !!(flow->nsh_mdtype); -+ encap_eth_type_flag = !!(flow->encap_eth_type); + if(nsh_mdtype_flag) + get_nsh_key(flow, &reserve_nsh); -+ -+ if(encap_eth_type_flag) -+ get_encap_eth_key(flow, &reserve_encap_eth); + flow_extract(&dupcall->packet, flow); + if(nsh_mdtype_flag) + put_nsh_key(&reserve_nsh, flow); -+ -+ if(encap_eth_type_flag) -+ put_encap_eth_key(&reserve_encap_eth, flow); + error = process_upcall(udpif, upcall, &upcall->odp_actions, &upcall->wc); if (error) { diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c -index a02dc24..4f91d0a 100644 +index a17047d..c1166de 100644 --- a/ofproto/ofproto-dpif-xlate.c +++ b/ofproto/ofproto-dpif-xlate.c -@@ -4240,6 +4240,10 @@ freeze_unroll_actions(const struct ofpact *a, const struct ofpact *end, +@@ -4451,6 +4451,8 @@ freeze_unroll_actions(const struct ofpact *a, const struct ofpact *end, case OFPACT_SET_VLAN_PCP: case OFPACT_STRIP_VLAN: case OFPACT_PUSH_VLAN: + case OFPACT_PUSH_NSH: + case OFPACT_POP_NSH: -+ case OFPACT_PUSH_ETH: -+ case OFPACT_POP_ETH: case OFPACT_SET_ETH_SRC: case OFPACT_SET_ETH_DST: case OFPACT_SET_IPV4_SRC: -@@ -4524,6 +4528,24 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len, +@@ -4834,6 +4836,17 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len, } break; + case OFPACT_PUSH_NSH: + memset(&wc->masks.nsh_mdtype, 0xff, sizeof wc->masks.nsh_mdtype); ++ flow->encap_eth_dst = flow->dl_dst; ++ flow->encap_eth_src = flow->dl_src; + break; + + case OFPACT_POP_NSH: + memset(&wc->masks.nsh_mdtype, 0xff, sizeof wc->masks.nsh_mdtype); + flow_zero_nsh(flow); + break; -+ -+ case OFPACT_PUSH_ETH: -+ memset(&wc->masks.encap_eth_type, 0xff, sizeof wc->masks.encap_eth_type); -+ break; -+ -+ case OFPACT_POP_ETH: -+ memset(&wc->masks.encap_eth_type, 0xff, sizeof wc->masks.encap_eth_type); -+ flow_zero_encap_eth(flow); -+ break; + case OFPACT_STRIP_VLAN: memset(&wc->masks.vlan_tci, 0xff, sizeof wc->masks.vlan_tci); flow->vlan_tci = htons(0); +diff --git a/ofproto/ofproto-dpif.h b/ofproto/ofproto-dpif.h +index f1e1209..0e30e6e 100644 +--- a/ofproto/ofproto-dpif.h ++++ b/ofproto/ofproto-dpif.h +@@ -96,7 +96,6 @@ struct dpif_backer_support { + /* Each member represents support for related OVS_KEY_ATTR_* fields. */ + struct odp_support odp; + }; +- + bool ofproto_dpif_get_enable_ufid(const struct dpif_backer *backer); + struct dpif_backer_support *ofproto_dpif_get_support(const struct ofproto_dpif *); + +diff --git a/ofproto/tunnel.c b/ofproto/tunnel.c +index 9a69071..acaec82 100644 +--- a/ofproto/tunnel.c ++++ b/ofproto/tunnel.c +@@ -701,6 +701,7 @@ tnl_port_build_header(const struct ofport_dpif *ofport, + tnl_port = tnl_find_ofport(ofport); + ovs_assert(tnl_port); + res = netdev_build_header(tnl_port->netdev, data, params); ++ data->exts = 0; + fat_rwlock_unlock(&rwlock); + + return res; diff --git a/tests/ofproto.at b/tests/ofproto.at -index 6c7217d..7141e39 100644 +index 7b7f02b..431181a 100644 --- a/tests/ofproto.at +++ b/tests/ofproto.at -@@ -1777,7 +1777,7 @@ head_table () { +@@ -2192,7 +2192,7 @@ head_table () { 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_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 -+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 nsp nsi nshc1 nshc2 nshc3 nshc4 nsh_mdtype nsh_np encap_eth_src encap_eth_dst encap_eth_type +-metadata in_port in_port_oxm pkt_mark ct_mark ct_label reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 reg9 reg10 reg11 reg12 reg13 reg14 reg15 xreg0 xreg1 xreg2 xreg3 xreg4 xreg5 xreg6 xreg7 xxreg0 xxreg1 xxreg2 xxreg3 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 ++metadata in_port in_port_oxm pkt_mark ct_mark ct_label reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 reg9 reg10 reg11 reg12 reg13 reg14 reg15 xreg0 xreg1 xreg2 xreg3 xreg4 xreg5 xreg6 xreg7 xxreg0 xxreg1 xxreg2 xxreg3 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 nsp nsi nshc1 nshc2 nshc3 nshc4 nsh_mdtype nsh_np encap_eth_src encap_eth_dst encap_eth_type matching: dp_hash: arbitrary mask recirc_id: exact match or wildcard -@@ -1917,6 +1917,17 @@ metadata in_port in_port_oxm pkt_mark ct_mark ct_label reg0 reg1 reg2 reg3 reg4 +@@ -2348,6 +2348,16 @@ metadata in_port in_port_oxm pkt_mark ct_mark ct_label reg0 reg1 reg2 reg3 reg4 nd_target: arbitrary mask nd_sll: arbitrary mask nd_tll: arbitrary mask @@ -2569,15 +2812,14 @@ index 6c7217d..7141e39 100644 + nsh_np: arbitrary mask + encap_eth_src: arbitrary mask + encap_eth_dst: arbitrary mask -+ encap_eth_type: exact match or wildcard ' $1 } diff --git a/tests/tunnel.at b/tests/tunnel.at -index 0c033da..d957574 100644 +index 477517e..eb429d3 100644 --- a/tests/tunnel.at +++ b/tests/tunnel.at -@@ -412,6 +412,163 @@ AT_CHECK([tail -1 stdout], [0], +@@ -532,6 +532,322 @@ AT_CHECK([tail -1 stdout], [0], OVS_VSWITCHD_STOP AT_CLEANUP @@ -2596,6 +2838,14 @@ index 0c033da..d957574 100644 +in_port=2 actions=push_nsh,set_field:1->nsh_mdtype,set_field:0x3->nsh_np,set_field:0x112233->nsp,set_field:0x44->nsi,set_field:0x11223344->nshc1,set_field:0x55667788->nshc2,set_field:0x99aabbcc->nshc3,set_field:0xddeeff00->nshc4,set_field:4->tun_gpe_np,output:2 +]) +AT_CHECK([ovs-ofctl add-flows br0 flows.txt]) ++ ++AT_CHECK([ovs-appctl dpif/show | tail -n +3], [0], [dnl ++ br0 65534/100: (dummy) ++ p1 1/1: (dummy) ++ p2 2/4790: (vxlan: dst_port=4790, key=flow, remote_ip=1.1.1.1) ++ p90 90/90: (dummy) ++]) ++ +AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(90),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=1,tos=0,ttl=128,frag=no),icmp(type=8,code=0)'], [0], [stdout]) +AT_CHECK([tail -1 stdout], [0], + [Datapath actions: push_nsh(nsh_mdtype=1,nsh_np=3,nsp=1122867,nsi=1140850688,nshc1=287454020,nshc2=1432778632,nshc3=2578103244,nshc4=3723427584),1,set(tunnel(tun_id=0x0,dst=1.1.1.1,ttl=64,vxlan(gpe(np=0x4,flags=0)),flags(df|key))),push_nsh(nsh_mdtype=1,nsh_np=3,nsp=1122867,nsi=1140850688,nshc1=287454020,nshc2=1432778632,nshc3=2578103244,nshc4=3723427584),4790 @@ -2665,12 +2915,6 @@ index 0c033da..d957574 100644 + +AT_CHECK([ovs-ofctl add-flows br0 flows.txt]) + -+AT_CHECK([ovs-appctl dpif/show | tail -n +3], [0], [dnl -+ br0 65534/100: (dummy) -+ p1 1/1: (dummy) -+ p2 2/2: (dummy) -+]) -+ +AT_CHECK([ovs-appctl ofproto/trace ovs-dummy ',in_port(2),encap_eth(encap_eth_type=0x894f,encap_eth_dst=00:11:22:33:44:55,encap_eth_src=00:66:77:88:99:aa),nsh(nsh_mdtype=1,nsh_np=3,nsp=0x112233,nsi=0x44,nshc1=0x11223344,nshc2=0x55667788,nshc3=0x99aabbcc,nshc4=0xddeeff00),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no),tcp(src=8,dst=9)'], [0], [stdout]) +AT_CHECK([tail -1 stdout], [0], + [Datapath actions: pop_eth,pop_nsh,1 @@ -2694,12 +2938,6 @@ index 0c033da..d957574 100644 + +AT_CHECK([ovs-ofctl add-flows br0 flows.txt]) + -+AT_CHECK([ovs-appctl dpif/show | tail -n +3], [0], [dnl -+ br0 65534/100: (dummy) -+ p1 1/1: (dummy) -+ p2 2/4790: (vxlan: dst_port=4790, key=flow, remote_ip=1.1.1.1) -+]) -+ +AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'tunnel(src=1.1.1.1,dst=1.2.3.4,ttl=64,flags(),vxlan(gpe(np=4,flags=0x0c))),in_port(4790),nsh(nsh_mdtype=1,nsh_np=3,nsp=0x112233,nsi=0x44,nshc1=0x11223344,nshc2=0x55667788,nshc3=0x99aabbcc,nshc4=0xddeeff00),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no),tcp(src=8,dst=9)'], [0], [stdout]) +AT_CHECK([tail -1 stdout], [0], + [Datapath actions: push_eth(encap_eth_type=35151,encap_eth_src=00:66:77:88:99:aa,encap_eth_dst=00:11:22:33:44:55,),1 @@ -2722,12 +2960,6 @@ index 0c033da..d957574 100644 + +AT_CHECK([ovs-ofctl add-flows br0 flows.txt]) + -+AT_CHECK([ovs-appctl dpif/show | tail -n +3], [0], [dnl -+ br0 65534/100: (dummy) -+ p1 1/1: (dummy) -+ p2 2/4790: (vxlan: dst_port=4790, key=flow, remote_ip=1.1.1.1) -+]) -+ +AT_CHECK([ovs-appctl ofproto/trace ovs-dummy ',in_port(1),encap_eth(encap_eth_type=0x894f,encap_eth_dst=00:11:22:33:44:55,encap_eth_src=00:66:77:88:99:aa),,nsh(nsh_mdtype=1,nsh_np=3,nsp=0x112233,nsi=0x44,nshc1=0x11223344,nshc2=0x55667788,nshc3=0x99aabbcc,nshc4=0xddeeff00),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no),tcp(src=8,dst=9)'], [0], [stdout]) +AT_CHECK([tail -1 stdout], [0], + [Datapath actions: set(tunnel(tun_id=0x0,dst=1.1.1.1,ttl=64,vxlan(gpe(np=0x4,flags=0)),flags(df|key))),pop_eth,4790 @@ -2736,11 +2968,180 @@ index 0c033da..d957574 100644 +OVS_VSWITCHD_STOP +AT_CLEANUP + ++AT_SETUP([tunnel - VXLAN-GPE and NSH - Encapsulation - user space]) ++OVS_VSWITCHD_START([dnl ++ add-port br0 p1 -- set Interface p1 type=dummy ofport_request=1 \ ++ -- add-port br0 p2 -- set Interface p2 type=vxlan options:key=flow \ ++ options:remote_ip=1.1.1.1 options:dst_port=4790 ofport_request=2 \ ++ options:exts=gpe]) + ++ADD_OF_PORTS([br0], [90]) ++ ++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 00:11:11:11:11:11 ++],[0],[stdout]) ++ ++AT_DATA([flows.txt], [dnl ++in_port=90 actions=resubmit:1,resubmit:2 ++in_port=1 actions=push_nsh,set_field:1->nsh_mdtype,set_field:0x3->nsh_np,set_field:0x112233->nsp,set_field:0x44->nsi,set_field:0x11223344->nshc1,set_field:0x55667788->nshc2,set_field:0x99aabbcc->nshc3,set_field:0xddeeff00->nshc4,output:1 ++in_port=2 actions=push_nsh,set_field:1->nsh_mdtype,set_field:0x3->nsh_np,set_field:0x112233->nsp,set_field:0x44->nsi,set_field:0x11223344->nshc1,set_field:0x55667788->nshc2,set_field:0x99aabbcc->nshc3,set_field:0xddeeff00->nshc4,set_field:4->tun_gpe_np,output:2 ++]) ++AT_CHECK([ovs-ofctl add-flows br0 flows.txt]) ++AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(90),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=1,tos=0,ttl=128,frag=no),icmp(type=8,code=0)'], [0], [stdout]) ++AT_CHECK([tail -1 stdout], [0], ++ [Datapath actions: push_nsh(encap_eth_src=00:00:00:00:00:00,encap_eth_dst=00:00:00:00:00:00,nsh_mdtype=1,nsh_np=3,nsp=1122867,nsi=1140850688,nshc1=287454020,nshc2=1432778632,nshc3=2578103244,nshc4=3723427584),1,push_nsh(encap_eth_src=00:00:00:00:00:00,encap_eth_dst=00:00:00:00:00:00,nsh_mdtype=1,nsh_np=3,nsp=1122867,nsi=1140850688,nshc1=287454020,nshc2=1432778632,nshc3=2578103244,nshc4=3723427584),tnl_push(tnl_port(4790),header(size=50,type=4,eth(dst=00:11:11:11:11:11,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=0xc000004,vni=0x0)),out_port(100)) ++]) ++ ++OVS_VSWITCHD_STOP ++AT_CLEANUP ++ ++AT_SETUP([tunnel - VXLAN-GPE and NSH - Decapsulation - user space]) ++OVS_VSWITCHD_START([dnl ++ add-port br0 p1 -- set Interface p1 type=dummy ofport_request=1 \ ++ -- add-port br0 p2 -- set Interface p2 type=vxlan options:key=flow \ ++ options:remote_ip=1.1.1.1 options:dst_port=4790 ofport_request=2 \ ++ options:exts=gpe]) ++ ++AT_DATA([flows.txt], [dnl ++priority=200,in_port=2,tun_gpe_np=4,nsh_mdtype=1,nsh_np=3,nsi=0x44,nsp=0x112233,actions=pop_nsh,output=1 ++priority=100,in_port=1,actions=local ++]) ++ ++AT_CHECK([ovs-ofctl add-flows br0 flows.txt]) ++ ++AT_CHECK([ovs-appctl netdev-dummy/ip4addr br0 1.1.1.2/24], [0], [OK ++]) ++ ++AT_CHECK([ovs-appctl ovs/route/add 1.1.1.1/24 br0], [0], [OK ++]) ++ ++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=1.1.1.2,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 'tunnel(src=1.1.1.1,dst=1.2.3.4,ttl=64,flags(),vxlan(gpe(np=4,flags=0x0c))),in_port(4790),nsh(nsh_mdtype=1,nsh_np=3,nsp=0x112233,nsi=0x44,nshc1=0x11223344,nshc2=0x55667788,nshc3=0x99aabbcc,nshc4=0xddeeff00),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no),tcp(src=8,dst=9)'], [0], [stdout]) ++AT_CHECK([tail -1 stdout], [0], ++ [Datapath actions: pop_nsh,1 ++]) ++ ++OVS_VSWITCHD_STOP ++AT_CLEANUP ++ ++AT_SETUP([Eth and NSH - Encapsulation - user space]) ++OVS_VSWITCHD_START([dnl ++ add-port br0 p1 -- set Interface p1 type=dummy ofport_request=1 \ ++ -- add-port br0 p2 -- set Interface p2 type=dummy ofport_request=2]) ++ ++ADD_OF_PORTS([br0], [90]) ++AT_DATA([flows.txt], [dnl ++in_port=90 actions=resubmit:1,resubmit:2 ++in_port=1 actions=push_nsh,set_field:1->nsh_mdtype,set_field:0x3->nsh_np,set_field:0x112233->nsp,set_field:0x44->nsi,set_field:0x11223344->nshc1,set_field:0x55667788->nshc2,set_field:0x99aabbcc->nshc3,set_field:00:11:22:33:44:55->encap_eth_dst,set_field:00:66:77:88:99:aa->encap_eth_src,output:1 ++]) ++AT_CHECK([ovs-ofctl add-flows br0 flows.txt]) ++AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(90),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=1,tos=0,ttl=128,frag=no),icmp(type=8,code=0)'], [0], [stdout]) ++AT_CHECK([tail -1 stdout], [0], ++[Datapath actions: push_nsh(encap_eth_src=00:66:77:88:99:aa,encap_eth_dst=00:11:22:33:44:55,nsh_mdtype=1,nsh_np=3,nsp=1122867,nsi=1140850688,nshc1=287454020,nshc2=1432778632,nshc3=2578103244,nshc4=0),1 ++]) ++ ++OVS_VSWITCHD_STOP ++AT_CLEANUP ++ ++AT_SETUP([Eth and NSH - Decapsulation - user space]) ++OVS_VSWITCHD_START([dnl ++ add-port br0 p1 -- set Interface p1 type=dummy ofport_request=1 \ ++ -- add-port br0 p2 -- set Interface p2 type=dummy ofport_request=2]) ++ ++AT_DATA([flows.txt], [dnl ++priority=200,in_port=2,nsh_mdtype=1,nsh_np=3,nsi=0x44,nsp=0x112233,encap_eth_dst=00:11:22:33:44:55,encap_eth_src=00:66:77:88:99:aa,actions=pop_nsh,output=1 ++]) ++ ++AT_CHECK([ovs-ofctl add-flows br0 flows.txt]) ++ ++AT_CHECK([ovs-appctl dpif/show | tail -n +3], [0], [dnl ++ br0 65534/100: (dummy) ++ p1 1/1: (dummy) ++ p2 2/2: (dummy) ++]) ++ ++AT_CHECK([ovs-appctl ofproto/trace ovs-dummy ',in_port(2),nsh(encap_eth_dst=00:11:22:33:44:55,encap_eth_src=00:66:77:88:99:aa,nsh_mdtype=1,nsh_np=3,nsp=0x112233,nsi=0x44,nshc1=0x11223344,nshc2=0x55667788,nshc3=0x99aabbcc,nshc4=0xddeeff00),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no),tcp(src=8,dst=9)'], [0], [stdout]) ++AT_CHECK([tail -1 stdout], [0], ++ [Datapath actions: pop_nsh,1 ++]) ++ ++OVS_VSWITCHD_STOP ++AT_CLEANUP ++ ++AT_SETUP([VXLANGPE+NSH to Eth+NSH - user space]) ++OVS_VSWITCHD_START([dnl ++ add-port br0 p1 -- set Interface p1 type=dummy ofport_request=1 \ ++ -- add-port br0 p2 -- set Interface p2 type=dummy ofport_request=2 \ ++ -- add-port br0 p3 -- set Interface p3 type=vxlan options:key=flow \ ++ options:remote_ip=1.1.1.1 options:dst_port=4790 ofport_request=3 \ ++ options:exts=gpe]) ++ ++AT_DATA([flows.txt], [dnl ++priority=200,in_port=3,tun_gpe_np=4,nsh_mdtype=1,nsh_np=3,nsi=0x44,nsp=0x112233,actions=set_field:00:11:22:33:44:55->encap_eth_dst,set_field:00:66:77:88:99:aa->encap_eth_src,output:2 ++priority=100,in_port=1,actions=local ++]) ++ ++AT_CHECK([ovs-ofctl add-flows br0 flows.txt]) ++ ++AT_CHECK([ovs-appctl netdev-dummy/ip4addr br0 1.1.1.2/24], [0], [OK ++]) ++ ++AT_CHECK([ovs-appctl ovs/route/add 1.1.1.1/24 br0], [0], [OK ++]) ++ ++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=1.1.1.2,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 'tunnel(src=1.1.1.1,dst=1.2.3.4,ttl=64,flags(),vxlan(gpe(np=4,flags=0x0c))),in_port(4790),nsh(nsh_mdtype=1,nsh_np=3,nsp=0x112233,nsi=0x44,nshc1=0x11223344,nshc2=0x55667788,nshc3=0x99aabbcc,nshc4=0xddeeff00),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no),tcp(src=8,dst=9)'], [0], [stdout]) ++AT_CHECK([tail -1 stdout], [0], ++ [Datapath actions: pop_nsh,push_nsh(encap_eth_src=00:66:77:88:99:aa,encap_eth_dst=00:11:22:33:44:55,nsh_mdtype=1,nsh_np=3,nsp=1122867,nsi=1140850688,nshc1=1144201745,nshc2=2289526357,nshc3=3434850969,nshc4=16772829),2 ++]) ++ ++OVS_VSWITCHD_STOP ++AT_CLEANUP ++ ++AT_SETUP([Eth+NSH to VXLANGPE+NSH - user space]) ++OVS_VSWITCHD_START([dnl ++ add-port br0 p1 -- set Interface p1 type=dummy ofport_request=1 \ ++ -- add-port br0 p2 -- set Interface p2 type=vxlan options:key=flow \ ++ options:remote_ip=1.1.1.1 options:dst_port=4790 ofport_request=2 \ ++ options:exts=gpe]) ++ ++AT_CHECK([ovs-appctl netdev-dummy/ip4addr br0 1.1.1.2/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 00:11:11:11:11:11 ++],[0],[stdout]) ++ ++AT_DATA([flows.txt], [dnl ++priority=200,in_port=1,nsh_mdtype=1,nsh_np=3,nsi=0x44,nsp=0x112233,encap_eth_dst=00:11:22:33:44:55,encap_eth_src=00:66:77:88:99:aa,actions=set_field:0x4->tun_gpe_np,output=2 ++]) ++ ++AT_CHECK([ovs-ofctl add-flows br0 flows.txt]) ++ ++ ++AT_CHECK([ovs-appctl ofproto/trace ovs-dummy ',in_port(1),nsh(encap_eth_dst=00:11:22:33:44:55,encap_eth_src=00:66:77:88:99:aa,nsh_mdtype=1,nsh_np=3,nsp=0x112233,nsi=0x44,nshc1=0x11223344,nshc2=0x55667788,nshc3=0x99aabbcc,nshc4=0xddeeff00),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no),tcp(src=8,dst=9)'], [0], [stdout]) ++ ++AT_CHECK([tail -1 stdout], [0], ++ [Datapath actions: tnl_push(tnl_port(4790),header(size=50,type=4,eth(dst=00:11:11:11:11:11,src=aa:55:aa:55:00:00,dl_type=0x0800),ipv4(src=1.1.1.2,dst=1.1.1.1,proto=17,tos=0,ttl=64,frag=0x40),udp(src=0,dst=4790,csum=0x0),vxlan(flags=0xc000004,vni=0x0)),out_port(100)) ++]) ++ ++OVS_VSWITCHD_STOP ++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 +2.1.0 diff --git a/ovs_build/patches/0004-Fix-too-large-stack-frame-size.patch b/ovs_build/ovs_nsh_patches/v2.6.1/0003-Fix-too-large-stack-frame-size.patch similarity index 78% rename from ovs_build/patches/0004-Fix-too-large-stack-frame-size.patch rename to ovs_build/ovs_nsh_patches/v2.6.1/0003-Fix-too-large-stack-frame-size.patch index 08faf9e..7a0dc01 100644 --- a/ovs_build/patches/0004-Fix-too-large-stack-frame-size.patch +++ b/ovs_build/ovs_nsh_patches/v2.6.1/0003-Fix-too-large-stack-frame-size.patch @@ -1,7 +1,7 @@ -From e6f9b1f96a3ac4066c9d7d4c0a9da7e8abb1597f Mon Sep 17 00:00:00 2001 +From 9bd18a89542f910ce12b09fe3e03f08a22b691dd Mon Sep 17 00:00:00 2001 From: Yi Yang -Date: Wed, 13 Apr 2016 18:17:21 +0800 -Subject: [PATCH 4/6] Fix too large stack frame size +Date: Mon, 14 Nov 2016 13:12:51 +0800 +Subject: [PATCH 3/8] Fix too large stack frame size Signed-off-by: Yi Yang --- @@ -9,10 +9,10 @@ Signed-off-by: Yi Yang 1 file changed, 78 insertions(+), 14 deletions(-) diff --git a/datapath/datapath.c b/datapath/datapath.c -index 5bec072..4baf242 100644 +index db8a18a..ae6555f 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) +@@ -939,7 +939,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; @@ -21,7 +21,7 @@ index 5bec072..4baf242 100644 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) +@@ -957,6 +957,12 @@ static int ovs_flow_cmd_new(struct sk_buff *skb, struct genl_info *info) goto error; } @@ -34,7 +34,7 @@ index 5bec072..4baf242 100644 /* 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) +@@ -967,17 +973,17 @@ static int ovs_flow_cmd_new(struct sk_buff *skb, struct genl_info *info) } /* Extract key. */ @@ -55,7 +55,7 @@ index 5bec072..4baf242 100644 if (error) goto err_kfree_flow; -@@ -996,7 +1002,7 @@ static int ovs_flow_cmd_new(struct sk_buff *skb, struct genl_info *info) +@@ -1007,7 +1013,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) @@ -64,7 +64,7 @@ index 5bec072..4baf242 100644 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) +@@ -1077,6 +1083,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); @@ -75,7 +75,7 @@ index 5bec072..4baf242 100644 return 0; err_unlock_ovs: -@@ -1076,6 +1086,10 @@ err_kfree_acts: +@@ -1087,6 +1097,10 @@ err_kfree_acts: err_kfree_flow: ovs_flow_free(new_flow, false); error: @@ -86,7 +86,7 @@ index 5bec072..4baf242 100644 return error; } -@@ -1106,7 +1120,7 @@ static int ovs_flow_cmd_set(struct sk_buff *skb, struct genl_info *info) +@@ -1117,7 +1131,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; @@ -95,7 +95,7 @@ index 5bec072..4baf242 100644 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) +@@ -1130,9 +1144,15 @@ static int ovs_flow_cmd_set(struct sk_buff *skb, struct genl_info *info) bool log = !a[OVS_FLOW_ATTR_PROBE]; bool ufid_present; @@ -105,28 +105,23 @@ index 5bec072..4baf242 100644 + 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) + if (a[OVS_FLOW_ATTR_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); + } else if (!ufid_present) { +@@ -1152,7 +1172,7 @@ static int ovs_flow_cmd_set(struct sk_buff *skb, struct genl_info *info) + goto error; + } - /* 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) +@@ -1220,6 +1240,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); @@ -137,7 +132,7 @@ index 5bec072..4baf242 100644 return 0; err_unlock_ovs: -@@ -1211,6 +1235,10 @@ err_unlock_ovs: +@@ -1228,6 +1252,10 @@ err_unlock_ovs: err_kfree_acts: ovs_nla_free_flow_actions(acts); error: @@ -148,7 +143,7 @@ index 5bec072..4baf242 100644 return error; } -@@ -1219,7 +1247,7 @@ static int ovs_flow_cmd_get(struct sk_buff *skb, struct genl_info *info) +@@ -1236,7 +1264,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); @@ -157,7 +152,7 @@ index 5bec072..4baf242 100644 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) +@@ -1247,9 +1275,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; @@ -174,7 +169,7 @@ index 5bec072..4baf242 100644 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) +@@ -1257,9 +1291,13 @@ static int ovs_flow_cmd_get(struct sk_buff *skb, struct genl_info *info) "Flow get message rejected, Key attribute missing."); err = -EINVAL; } @@ -190,7 +185,7 @@ index 5bec072..4baf242 100644 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) +@@ -1284,9 +1322,17 @@ static int ovs_flow_cmd_get(struct sk_buff *skb, struct genl_info *info) } ovs_unlock(); @@ -208,7 +203,7 @@ index 5bec072..4baf242 100644 return err; } -@@ -1278,7 +1324,7 @@ static int ovs_flow_cmd_del(struct sk_buff *skb, struct genl_info *info) +@@ -1295,7 +1341,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); @@ -217,7 +212,7 @@ index 5bec072..4baf242 100644 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) +@@ -1306,12 +1352,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; @@ -241,7 +236,7 @@ index 5bec072..4baf242 100644 return err; } -@@ -1344,9 +1400,17 @@ static int ovs_flow_cmd_del(struct sk_buff *skb, struct genl_info *info) +@@ -1361,9 +1417,17 @@ static int ovs_flow_cmd_del(struct sk_buff *skb, struct genl_info *info) } ovs_flow_free(flow, true); @@ -260,5 +255,5 @@ index 5bec072..4baf242 100644 } -- -1.9.3 +2.1.0 diff --git a/ovs_build/ovs_nsh_patches/v2.6.1/0004-Fix-vxlangpe-issues-on-DPDK-netdev.patch b/ovs_build/ovs_nsh_patches/v2.6.1/0004-Fix-vxlangpe-issues-on-DPDK-netdev.patch new file mode 100644 index 0000000..3b89a42 --- /dev/null +++ b/ovs_build/ovs_nsh_patches/v2.6.1/0004-Fix-vxlangpe-issues-on-DPDK-netdev.patch @@ -0,0 +1,127 @@ +From 861f91c172c97b3ea787a1ad30617f31d77f1379 Mon Sep 17 00:00:00 2001 +From: Yi Yang +Date: Wed, 30 Nov 2016 10:22:57 +0800 +Subject: [PATCH 4/8] Fix vxlangpe issues on DPDK netdev + + - Fix a potential deadlock issue + - Use Ethernet header before NSH header in VxLAN-gpe + to ensure we have uniform behaviour in OVS DPDK and + OVS + - Correct VxLAN-gpe check in netdev_vxlan_pop_header + +Signed-off-by: Yi Yang +--- + lib/dpif-netdev.c | 5 +---- + lib/netdev-native-tnl.c | 9 +++++---- + lib/netdev-vport.c | 10 ++++++++++ + lib/netdev-vport.h | 2 ++ + ofproto/tunnel.c | 1 - + 5 files changed, 18 insertions(+), 9 deletions(-) + +diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c +index c779c78..257a174 100644 +--- a/lib/dpif-netdev.c ++++ b/lib/dpif-netdev.c +@@ -1217,11 +1217,8 @@ static void add_vxlan_gpe_exts(struct netdev *netdev, uint32_t exts) + { + const char *type = netdev_get_type(netdev); + if (!strcmp(type, "vxlan")) { +- struct netdev_tunnel_config *cfg; +- cfg = netdev_get_tunnel_config(netdev); +- + if(exts & (1 << OVS_VXLAN_EXT_GPE)) +- cfg->exts |= (1 << OVS_VXLAN_EXT_GPE); ++ netdev_set_tunnel_config_exts(netdev, exts); + } + } + +diff --git a/lib/netdev-native-tnl.c b/lib/netdev-native-tnl.c +index 2fe2722..a677ec8 100644 +--- a/lib/netdev-native-tnl.c ++++ b/lib/netdev-native-tnl.c +@@ -243,6 +243,7 @@ eth_build_header(struct ovs_action_push_tnl *data, + uint16_t eth_proto = params->is_ipv6 ? ETH_TYPE_IPV6 : ETH_TYPE_IP; + struct eth_header *eth; + ++ data->exts = 0; + memset(data->header, 0, sizeof data->header); + + eth = (struct eth_header *)data->header; +@@ -499,9 +500,9 @@ netdev_vxlan_pop_header(struct dp_packet *packet) + flag = get_16aligned_be32(&vxh->vx_flags); + vni = get_16aligned_be32(&vxh->vx_vni); + +- if (flag & VXLAN_HF_GPE) { +- flag &= ~VXLAN_GPE_USED_BITS; +- if ((flag & ~VXLAN_GPE_USED_BITS) || ++ if (flag & htonl(VXLAN_HF_GPE)) { ++ flag &= htonl(~VXLAN_GPE_USED_BITS); ++ if ((flag != htonl(VXLAN_FLAGS)) || + (vni & htonl(0xff))) { + + VLOG_WARN_RL(&err_rl, "invalid vxlan flags=%#x vni=%#x\n for vxlan-gpe", +@@ -578,7 +579,7 @@ netdev_vxlan_build_header(const struct netdev *netdev, + put_16aligned_be32(&vxh->vx_vni, htonl(ntohll(params->flow->tunnel.tun_id) << 8)); + + if (!params->flow->tunnel.gpe_np) +- return -1; ++ gpe->next_protocol = VXLAN_GPE_NP_ETHERNET; + else + gpe->next_protocol = params->flow->tunnel.gpe_np; + +diff --git a/lib/netdev-vport.c b/lib/netdev-vport.c +index 841a070..0aca632 100644 +--- a/lib/netdev-vport.c ++++ b/lib/netdev-vport.c +@@ -85,6 +85,16 @@ get_netdev_tunnel_config(const struct netdev *netdev) + return &netdev_vport_cast(netdev)->tnl_cfg; + } + ++void netdev_set_tunnel_config_exts(struct netdev *netdev, uint32_t exts) ++{ ++ struct netdev_vport *dev = netdev_vport_cast(netdev); ++ dev->tnl_cfg.exts = exts; ++ ovs_mutex_lock(&dev->mutex); ++ tunnel_check_status_change__(dev); ++ netdev_change_seq_changed(netdev); ++ ovs_mutex_unlock(&dev->mutex); ++} ++ + bool + netdev_vport_is_patch(const struct netdev *netdev) + { +diff --git a/lib/netdev-vport.h b/lib/netdev-vport.h +index b19cbd2..e093dde 100644 +--- a/lib/netdev-vport.h ++++ b/lib/netdev-vport.h +@@ -19,6 +19,7 @@ + + #include + #include ++#include + #include "compiler.h" + + struct dpif_netlink_vport; +@@ -42,6 +43,7 @@ void netdev_vport_inc_tx(const struct netdev *, + + bool netdev_vport_is_vport_class(const struct netdev_class *); + const char *netdev_vport_class_get_dpif_port(const struct netdev_class *); ++void netdev_set_tunnel_config_exts(struct netdev *netdev, uint32_t exts); + + #ifndef _WIN32 + enum { NETDEV_VPORT_NAME_BUFSIZE = 16 }; +diff --git a/ofproto/tunnel.c b/ofproto/tunnel.c +index acaec82..9a69071 100644 +--- a/ofproto/tunnel.c ++++ b/ofproto/tunnel.c +@@ -701,7 +701,6 @@ tnl_port_build_header(const struct ofport_dpif *ofport, + tnl_port = tnl_find_ofport(ofport); + ovs_assert(tnl_port); + res = netdev_build_header(tnl_port->netdev, data, params); +- data->exts = 0; + fat_rwlock_unlock(&rwlock); + + return res; +-- +2.1.0 + diff --git a/ovs_build/ovs_nsh_patches/v2.6.1/0005-Change-match-field-IDs-and-action-IDs-to-adapt-to-OD.patch b/ovs_build/ovs_nsh_patches/v2.6.1/0005-Change-match-field-IDs-and-action-IDs-to-adapt-to-OD.patch new file mode 100644 index 0000000..592abe6 --- /dev/null +++ b/ovs_build/ovs_nsh_patches/v2.6.1/0005-Change-match-field-IDs-and-action-IDs-to-adapt-to-OD.patch @@ -0,0 +1,197 @@ +From b6fb68aaf672af71e60ecff9b6b03f1d5f42be0c Mon Sep 17 00:00:00 2001 +From: Yi Yang +Date: Wed, 30 Nov 2016 12:22:19 +0800 +Subject: [PATCH 5/8] Change match field IDs and action IDs to adapt to ODL + +Signed-off-by: Yi Yang +--- + include/openvswitch/meta-flow.h | 42 ++++++++++++++++++++--------------------- + lib/ofp-actions.c | 10 +++++----- + 2 files changed, 26 insertions(+), 26 deletions(-) + +diff --git a/include/openvswitch/meta-flow.h b/include/openvswitch/meta-flow.h +index fa4129c..190c3d6 100644 +--- a/include/openvswitch/meta-flow.h ++++ b/include/openvswitch/meta-flow.h +@@ -502,7 +502,7 @@ enum OVS_PACKED_ENUM mf_field_id { + * Formatting: hexadecimal. + * Prerequisites: none. + * Access: read/write. +- * NXM: NXM_NX_TUN_GPE_NP(200) since v2.4. ++ * NXM: NXM_NX_TUN_GPE_NP(111) since v2.4. + * OXM: none. + */ + MFF_TUN_GPE_NP, +@@ -516,7 +516,7 @@ enum OVS_PACKED_ENUM mf_field_id { + * Formatting: hexadecimal. + * Prerequisites: none. + * Access: read/write. +- * NXM: NXM_NX_TUN_GPE_FLAGS(201) since v2.4. ++ * NXM: NXM_NX_TUN_GPE_FLAGS(112) since v2.4. + * OXM: none. + */ + MFF_TUN_GPE_FLAGS, +@@ -966,14 +966,14 @@ enum OVS_PACKED_ENUM mf_field_id { + * Formatting: hexadecimal. + * Prerequisites: none. + * Access: read/write. +- * NXM: NXM_NX_XXREG0(111) since v2.6. <0> +- * NXM: NXM_NX_XXREG1(112) since v2.6. <1> +- * NXM: NXM_NX_XXREG2(113) since v2.6. <2> +- * NXM: NXM_NX_XXREG3(114) since v2.6. <3> +- * NXM: NXM_NX_XXREG4(115) since vX.Y. <4> +- * NXM: NXM_NX_XXREG5(116) since vX.Y. <5> +- * NXM: NXM_NX_XXREG6(117) since vX.Y. <6> +- * NXM: NXM_NX_XXREG7(118) since vX.Y. <7> ++ * NXM: NXM_NX_XXREG0(124) since v2.6. <0> ++ * NXM: NXM_NX_XXREG1(125) since v2.6. <1> ++ * NXM: NXM_NX_XXREG2(126) since v2.6. <2> ++ * NXM: NXM_NX_XXREG3(127) since v2.6. <3> ++ * NXM: NXM_NX_XXREG4(128) since vX.Y. <4> ++ * NXM: NXM_NX_XXREG5(129) since vX.Y. <5> ++ * NXM: NXM_NX_XXREG6(130) since vX.Y. <6> ++ * NXM: NXM_NX_XXREG7(131) since vX.Y. <7> + * OXM: none. + */ + MFF_XXREG0, +@@ -1813,7 +1813,7 @@ enum OVS_PACKED_ENUM mf_field_id { + * Formatting: hexadecimal. + * Prerequisites: none. + * Access: read/write. +- * NXM: NXM_NX_NSP(202) since v1.1. ++ * NXM: NXM_NX_NSP(113) since v1.1. + * OXM: none. + * Prefix lookup member: nsp. + */ +@@ -1829,7 +1829,7 @@ enum OVS_PACKED_ENUM mf_field_id { + * Formatting: decimal. + * Prerequisites: none. + * Access: read/write. +- * NXM: NXM_NX_NSI(203) since v1.1. ++ * NXM: NXM_NX_NSI(114) since v1.1. + * OXM: none. + * Prefix lookup member: nsi. + */ +@@ -1846,7 +1846,7 @@ enum OVS_PACKED_ENUM mf_field_id { + * Formatting: hexadecimal. + * Prerequisites: none. + * Access: read/write. +- * NXM: NXM_NX_NSH_C1(204) since v1.1. ++ * NXM: NXM_NX_NSH_C1(115) since v1.1. + * OXM: none. + * Prefix lookup member: nshc1. + */ +@@ -1863,7 +1863,7 @@ enum OVS_PACKED_ENUM mf_field_id { + * Formatting: hexadecimal. + * Prerequisites: none. + * Access: read/write. +- * NXM: NXM_NX_NSH_C2(205) since v1.1. ++ * NXM: NXM_NX_NSH_C2(116) since v1.1. + * OXM: none. + * Prefix lookup member: nshc2. + */ +@@ -1880,7 +1880,7 @@ enum OVS_PACKED_ENUM mf_field_id { + * Formatting: hexadecimal. + * Prerequisites: none. + * Access: read/write. +- * NXM: NXM_NX_NSH_C3(206) since v1.1. ++ * NXM: NXM_NX_NSH_C3(117) since v1.1. + * OXM: none. + * Prefix lookup member: nshc3. + */ +@@ -1897,7 +1897,7 @@ enum OVS_PACKED_ENUM mf_field_id { + * Formatting: hexadecimal. + * Prerequisites: none. + * Access: read/write. +- * NXM: NXM_NX_NSH_C4(207) since v1.1. ++ * NXM: NXM_NX_NSH_C4(118) since v1.1. + * OXM: none. + * Prefix lookup member: nshc4. + */ +@@ -1913,7 +1913,7 @@ enum OVS_PACKED_ENUM mf_field_id { + * Formatting: decimal. + * Prerequisites: none. + * Access: read/write. +- * NXM: NXM_NX_NSH_MDTYPE(208) since v1.1. ++ * NXM: NXM_NX_NSH_MDTYPE(119) since v1.1. + * OXM: none. + */ + MFF_NSH_MDTYPE, +@@ -1928,7 +1928,7 @@ enum OVS_PACKED_ENUM mf_field_id { + * Formatting: decimal. + * Prerequisites: none. + * Access: read/write. +- * NXM: NXM_NX_NSH_NP(209) since v1.1. ++ * NXM: NXM_NX_NSH_NP(120) since v1.1. + * OXM: none. + */ + MFF_NSH_NP, +@@ -1942,7 +1942,7 @@ enum OVS_PACKED_ENUM mf_field_id { + * Formatting: Ethernet. + * Prerequisites: none. + * Access: read/write. +- * NXM: NXM_NX_ENCAP_ETH_SRC(210) since v1.1. ++ * NXM: NXM_NX_ENCAP_ETH_SRC(121) since v1.1. + * OXM: none. + */ + MFF_ENCAP_ETH_SRC, +@@ -1956,7 +1956,7 @@ enum OVS_PACKED_ENUM mf_field_id { + * Formatting: Ethernet. + * Prerequisites: none. + * Access: read/write. +- * NXM: NXM_NX_ENCAP_ETH_DST(211) since v1.1. ++ * NXM: NXM_NX_ENCAP_ETH_DST(122) since v1.1. + * OXM: none. + */ + MFF_ENCAP_ETH_DST, +@@ -1970,7 +1970,7 @@ enum OVS_PACKED_ENUM mf_field_id { + * Formatting: hexadecimal. + * Prerequisites: none. + * Access: read-only. +- * NXM: NXM_NX_ENCAP_ETH_TYPE(212) since v1.1. ++ * NXM: NXM_NX_ENCAP_ETH_TYPE(123) since v1.1. + * OXM: none. + */ + MFF_ENCAP_ETH_TYPE, +diff --git a/lib/ofp-actions.c b/lib/ofp-actions.c +index 2935ca6..4939ef2 100644 +--- a/lib/ofp-actions.c ++++ b/lib/ofp-actions.c +@@ -196,7 +196,7 @@ enum ofp_raw_action_type { + /* NX1.0(4), OF1.1+(21): uint32_t. */ + OFPAT_RAW_SET_QUEUE, + +- /* NX1.0(40), OF1.1+(22): uint32_t. */ ++ /* NX1.0(42), OF1.1+(22): uint32_t. */ + OFPAT_RAW_GROUP, + + /* OF1.1+(23): uint8_t. */ +@@ -289,7 +289,7 @@ enum ofp_raw_action_type { + + /* NX1.0+(29): struct nx_action_sample. */ + NXAST_RAW_SAMPLE, +- /* NX1.0+(38): struct nx_action_sample2. */ ++ /* NX1.0+(40): struct nx_action_sample2. */ + NXAST_RAW_SAMPLE2, + + /* NX1.0+(34): struct nx_action_conjunction. */ +@@ -301,13 +301,13 @@ enum ofp_raw_action_type { + /* NX1.0+(36): struct nx_action_nat, ... */ + NXAST_RAW_NAT, + +- /* NX1.0+(39): struct nx_action_output_trunc. */ ++ /* NX1.0+(41): struct nx_action_output_trunc. */ + NXAST_RAW_OUTPUT_TRUNC, + +- /* NX1.0+(200): void. */ ++ /* NX1.0+(38): void. */ + NXAST_RAW_PUSH_NSH, + +- /* NX1.0+(201): void. */ ++ /* NX1.0+(39): void. */ + NXAST_RAW_POP_NSH, + + /* ## ------------------ ## */ +-- +2.1.0 + diff --git a/ovs_build/ovs_nsh_patches/v2.6.1/0006-To-be-compatible-with-vpp_nsh.patch b/ovs_build/ovs_nsh_patches/v2.6.1/0006-To-be-compatible-with-vpp_nsh.patch new file mode 100644 index 0000000..570cb2d --- /dev/null +++ b/ovs_build/ovs_nsh_patches/v2.6.1/0006-To-be-compatible-with-vpp_nsh.patch @@ -0,0 +1,31 @@ +From 622fe1bb00d38a70110d838eecc9e10c0d62cf7c Mon Sep 17 00:00:00 2001 +From: Yi Yang +Date: Wed, 30 Nov 2016 17:27:11 +0800 +Subject: [PATCH 6/8] To be compatible with vpp_nsh + +Signed-off-by: Yi Yang +--- + lib/netdev-native-tnl.c | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +diff --git a/lib/netdev-native-tnl.c b/lib/netdev-native-tnl.c +index a677ec8..2dd4954 100644 +--- a/lib/netdev-native-tnl.c ++++ b/lib/netdev-native-tnl.c +@@ -578,9 +578,10 @@ netdev_vxlan_build_header(const struct netdev *netdev, + put_16aligned_be32(&vxh->vx_flags, htonl(VXLAN_FLAGS | VXLAN_HF_GPE)); + put_16aligned_be32(&vxh->vx_vni, htonl(ntohll(params->flow->tunnel.tun_id) << 8)); + +- if (!params->flow->tunnel.gpe_np) +- gpe->next_protocol = VXLAN_GPE_NP_ETHERNET; +- else ++ if (!params->flow->tunnel.gpe_np) { ++ gpe->next_protocol = VXLAN_GPE_NP_NSH; ++ data->exts |= 1 << VXLAN_GPE_POP_ETH; ++ } else + gpe->next_protocol = params->flow->tunnel.gpe_np; + + if (params->flow->tunnel.gpe_flags & 0x01) +-- +2.1.0 + diff --git a/ovs_build/ovs_nsh_patches/v2.6.1/0007-Fix-struct-ovs_gso_cb-size-issue.patch b/ovs_build/ovs_nsh_patches/v2.6.1/0007-Fix-struct-ovs_gso_cb-size-issue.patch new file mode 100644 index 0000000..621e901 --- /dev/null +++ b/ovs_build/ovs_nsh_patches/v2.6.1/0007-Fix-struct-ovs_gso_cb-size-issue.patch @@ -0,0 +1,67 @@ +From dfbdc2b4e12dd5e2aff617e1bc2757e9fc39d1f6 Mon Sep 17 00:00:00 2001 +From: Yi Yang +Date: Thu, 1 Dec 2016 13:36:23 +0800 +Subject: [PATCH 7/8] Fix struct ovs_gso_cb size issue + +Signed-off-by: Yi Yang +--- + datapath/actions.c | 6 +++--- + datapath/datapath.h | 2 -- + datapath/flow.c | 2 -- + 3 files changed, 3 insertions(+), 7 deletions(-) + +diff --git a/datapath/actions.c b/datapath/actions.c +index c979596..936a015 100644 +--- a/datapath/actions.c ++++ b/datapath/actions.c +@@ -278,6 +278,7 @@ static int pop_nsh(struct sk_buff *skb, struct sw_flow_key *key) + static int push_nsh(struct sk_buff *skb, struct sw_flow_key *key, + const struct ovs_action_push_nsh *nsh) + { ++ struct encap_eth_hdr *encap_eth_header = NULL; + + if (nsh->nsh_mdtype == NSH_M_TYPE1) { + if (skb_cow_head(skb, ETH_NSH_TYPE1_HEADER_SIZE) < 0) { +@@ -285,10 +286,9 @@ static int push_nsh(struct sk_buff *skb, struct sw_flow_key *key, + } + + skb_push(skb, ETH_NSH_TYPE1_HEADER_SIZE); +- OVS_CB(skb)->encap_eth_header = (struct encap_eth_hdr *)skb->data; +- OVS_CB(skb)->nsh_header = (struct nsh_hdr *)(skb->data + ENCAP_ETH_LEN); ++ encap_eth_header = (struct encap_eth_hdr *)skb->data; + memcpy(skb->data, nsh->header, ETH_NSH_TYPE1_HEADER_SIZE); +- OVS_CB(skb)->encap_eth_header->encap_eth_type = htons(ETH_P_NSH); ++ encap_eth_header->encap_eth_type = htons(ETH_P_NSH); + } + else + return -EINVAL; +diff --git a/datapath/datapath.h b/datapath/datapath.h +index a6b2a44..22bbaac 100644 +--- a/datapath/datapath.h ++++ b/datapath/datapath.h +@@ -108,8 +108,6 @@ struct ovs_skb_cb { + struct vport *input_vport; + u16 mru; + u32 cutlen; +- struct nsh_hdr *nsh_header; +- struct encap_eth_hdr *encap_eth_header; + }; + #define OVS_CB(skb) ((struct ovs_skb_cb *)(skb)->cb) + +diff --git a/datapath/flow.c b/datapath/flow.c +index 8c4d583..c712517 100644 +--- a/datapath/flow.c ++++ b/datapath/flow.c +@@ -327,9 +327,7 @@ static int parse_vlan(struct sk_buff *skb, struct sw_flow_key *key) + static int parse_nsh(struct sk_buff *skb, struct sw_flow_key *key){ + struct nsh_hdr *nsh_hdr = NULL; + +- OVS_CB(skb)->encap_eth_header = (struct encap_eth_hdr *)skb->data; + nsh_hdr = (struct nsh_hdr *)((const char *)skb->data + ENCAP_ETH_LEN); +- OVS_CB(skb)->nsh_header = nsh_hdr; + memcpy(&key->nsh.encap_eth_dst, skb->data, ENCAP_ETH_LEN); + key->nsh.nsh_mdtype = nsh_hdr->base.mdtype; + if (key->nsh.nsh_mdtype != NSH_M_TYPE1) +-- +2.1.0 + diff --git a/ovs_build/ovs_nsh_patches/v2.6.1/0008-tunnel-set-udp-dst-port-in-tunnel-metadata.patch b/ovs_build/ovs_nsh_patches/v2.6.1/0008-tunnel-set-udp-dst-port-in-tunnel-metadata.patch new file mode 100644 index 0000000..2fe0507 --- /dev/null +++ b/ovs_build/ovs_nsh_patches/v2.6.1/0008-tunnel-set-udp-dst-port-in-tunnel-metadata.patch @@ -0,0 +1,84 @@ +From add8faa9d4e0b93ea2828d8932ccbc9b740518ae Mon Sep 17 00:00:00 2001 +From: Pravin B Shelar +Date: Mon, 5 Dec 2016 18:22:11 -0800 +Subject: [PATCH 8/8] tunnel: set udp dst-port in tunnel metadata + +VxLan device expect valid tp-dst in tunnel metadata. +Following patch sets consistent tp-dst with respect to +the egress tunnel port. + +Reported-by: Gerhard Stenzel +Tested-by: Gerhard Stenzel +Signed-off-by: Pravin B Shelar +Acked-by: Jarno Rajahalme +--- + ofproto/tunnel.c | 1 + + tests/ofproto-dpif.at | 2 +- + tests/tunnel.at | 8 ++++---- + 3 files changed, 6 insertions(+), 5 deletions(-) + +diff --git a/ofproto/tunnel.c b/ofproto/tunnel.c +index 9a69071..7277fa0 100644 +--- a/ofproto/tunnel.c ++++ b/ofproto/tunnel.c +@@ -438,6 +438,7 @@ tnl_port_send(const struct ofport_dpif *ofport, struct flow *flow, + flow->pkt_mark |= tnl_port->match.pkt_mark; + wc->masks.pkt_mark |= tnl_port->match.pkt_mark; + ++ flow->tunnel.tp_dst = cfg->dst_port; + if (!cfg->out_key_flow) { + flow->tunnel.tun_id = cfg->out_key; + } +diff --git a/tests/ofproto-dpif.at b/tests/ofproto-dpif.at +index a71282c..99db282 100644 +--- a/tests/ofproto-dpif.at ++++ b/tests/ofproto-dpif.at +@@ -6340,7 +6340,7 @@ AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(3),eth(src=50:54:00:00:00: + dnl Make sure flow sample action in datapath is behind set tunnel + dnl action at egress point of tunnel port. + AT_CHECK([tail -1 stdout], [0], [dnl +-Datapath actions: set(tunnel(tun_id=0x5,src=2.2.2.2,dst=1.1.1.1,tos=0x1,ttl=64,flags(df|key))),sample(sample=100.0%,actions(userspace(pid=0,flow_sample(probability=65535,collector_set_id=1,obs_domain_id=0,obs_point_id=0,output_port=1),tunnel_out_port=1))),1,set(tunnel(tun_id=0x6,src=2.2.2.3,dst=1.1.1.2,tos=0x1,ttl=64,flags(df|key))),sample(sample=100.0%,actions(userspace(pid=0,flow_sample(probability=65535,collector_set_id=1,obs_domain_id=0,obs_point_id=0,output_port=7471),tunnel_out_port=7471))),7471 ++Datapath actions: set(tunnel(tun_id=0x5,src=2.2.2.2,dst=1.1.1.1,tos=0x1,ttl=64,flags(df|key))),sample(sample=100.0%,actions(userspace(pid=0,flow_sample(probability=65535,collector_set_id=1,obs_domain_id=0,obs_point_id=0,output_port=1),tunnel_out_port=1))),1,set(tunnel(tun_id=0x6,src=2.2.2.3,dst=1.1.1.2,tos=0x1,ttl=64,tp_dst=7471,flags(df|key))),sample(sample=100.0%,actions(userspace(pid=0,flow_sample(probability=65535,collector_set_id=1,obs_domain_id=0,obs_point_id=0,output_port=7471),tunnel_out_port=7471))),7471 + ]) + + dnl Remove the flow which contains sample action. +diff --git a/tests/tunnel.at b/tests/tunnel.at +index eb429d3..03119bd 100644 +--- a/tests/tunnel.at ++++ b/tests/tunnel.at +@@ -866,7 +866,7 @@ AT_CHECK([ovs-ofctl add-flows br0 flows.txt]) + dnl Option generation + AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(2),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: set(tunnel(dst=1.1.1.1,ttl=64,geneve({class=0xffff,type=0,len=4,0xa}{class=0xffff,type=0x1,len=8,0x1234567890abcdef}),flags(df))),6081 ++ [Datapath actions: set(tunnel(dst=1.1.1.1,ttl=64,tp_dst=6081,geneve({class=0xffff,type=0,len=4,0xa}{class=0xffff,type=0x1,len=8,0x1234567890abcdef}),flags(df))),6081 + ]) + + dnl Option match +@@ -955,7 +955,7 @@ Datapath actions: 2 + AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'recirc_id(0),tunnel(tun_id=0x0,src=1.1.1.1,dst=1.1.1.2,ttl=64,geneve({class=0xffff,type=1,len=0}),flags(df|key)),in_port(6081),skb_mark(0),eth_type(0x0800),ipv4(frag=no)'], [0], [stdout]) + AT_CHECK([tail -2 stdout], [0], + [Megaflow: pkt_mark=0,recirc_id=0,ip,tun_id=0,tun_src=1.1.1.1,tun_dst=1.1.1.2,tun_tos=0,tun_flags=+df-csum+key,tun_metadata1,tun_metadata2=NP,in_port=1,nw_ecn=0,nw_frag=no +-Datapath actions: set(tunnel(tun_id=0x0,dst=1.1.1.1,ttl=64,geneve({class=0xffff,type=0x1,len=0}),flags(df|key))),6081 ++Datapath actions: set(tunnel(tun_id=0x0,dst=1.1.1.1,ttl=64,tp_dst=6081,geneve({class=0xffff,type=0x1,len=0}),flags(df|key))),6081 + ]) + + OVS_VSWITCHD_STOP +@@ -976,12 +976,12 @@ AT_CHECK([ovs-ofctl add-flows br0 flows.txt]) + + AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'tunnel(tun_id=0,src=1.1.1.1,dst=1.1.1.2,ttl=64),in_port(4789)'], [0], [stdout]) + AT_CHECK([tail -1 stdout], [0], +- [Datapath actions: set(tunnel(tun_id=0x0,ipv6_dst=2001:cafe::1,ttl=64,flags(df|key))),4789 ++ [Datapath actions: set(tunnel(tun_id=0x0,ipv6_dst=2001:cafe::1,ttl=64,tp_dst=4789,flags(df|key))),4789 + ]) + + AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'tunnel(tun_id=0x0,ipv6_src=2001:cafe::1,ipv6_dst=2001:cafe::2,ttl=64),in_port(4789)'], [0], [stdout]) + AT_CHECK([tail -1 stdout], [0], +- [Datapath actions: set(tunnel(tun_id=0x0,dst=1.1.1.1,ttl=64,flags(df|key))),4789 ++ [Datapath actions: set(tunnel(tun_id=0x0,dst=1.1.1.1,ttl=64,tp_dst=4789,flags(df|key))),4789 + ]) + + +-- +2.1.0 + diff --git a/ovs_build/patches/0003-Add-userspace-dataplane-nsh-support-and-remove-push_.patch b/ovs_build/patches/0003-Add-userspace-dataplane-nsh-support-and-remove-push_.patch deleted file mode 100644 index 905eccd..0000000 --- a/ovs_build/patches/0003-Add-userspace-dataplane-nsh-support-and-remove-push_.patch +++ /dev/null @@ -1,2327 +0,0 @@ -From ec5272ed6684bbd0ae8c38a5e6488414347a941f Mon Sep 17 00:00:00 2001 -From: Yi Yang -Date: Wed, 13 Apr 2016 16:39:27 +0800 -Subject: [PATCH 3/6] Add userspace dataplane nsh support and remove push_eth - and pop_eth actions - -Signed-off-by: Mengke Liu -Signed-off-by: Ricky Li -Signed-off-by: Johnson Li -Signed-off-by: Yi Yang ---- - datapath/actions.c | 53 +--- - datapath/flow.c | 50 ++-- - datapath/flow.h | 16 +- - datapath/flow_netlink.c | 44 +-- - datapath/linux/compat/include/linux/openvswitch.h | 112 ++++++-- - datapath/linux/compat/include/net/vxlan.h | 9 +- - datapath/linux/compat/vxlan.c | 15 ++ - lib/dpif-netdev.c | 30 ++- - lib/dpif.c | 2 - - lib/flow.c | 99 ++++++- - lib/flow.h | 14 +- - lib/match.c | 13 +- - lib/match.h | 2 +- - lib/meta-flow.h | 2 +- - lib/netdev-vport.c | 76 +++++- - lib/netdev-vport.h | 6 + - lib/nx-match.c | 3 +- - lib/odp-execute.c | 23 +- - lib/odp-util.c | 314 ++++++---------------- - lib/odp-util.h | 6 +- - lib/ofp-actions.c | 82 +----- - lib/ofp-actions.h | 2 - - lib/packets.c | 23 ++ - lib/packets.h | 3 + - ofproto/ofproto-dpif-sflow.c | 1 - - ofproto/ofproto-dpif-upcall.c | 8 - - ofproto/ofproto-dpif-xlate.c | 13 +- - ofproto/ofproto-dpif.h | 1 - - ofproto/tunnel.c | 1 + - tests/ofproto.at | 1 - - tests/tunnel.at | 189 +++++++++++-- - 31 files changed, 666 insertions(+), 547 deletions(-) - -diff --git a/datapath/actions.c b/datapath/actions.c -index 16fc58f..7072638 100644 ---- a/datapath/actions.c -+++ b/datapath/actions.c -@@ -254,10 +254,10 @@ static int push_vlan(struct sk_buff *skb, struct sw_flow_key *key, - - static int pop_nsh(struct sk_buff *skb, struct sw_flow_key *key) - { -- if (!pskb_may_pull(skb, NSH_M_TYPE1_LEN)) -+ if (!pskb_may_pull(skb, ETH_NSH_TYPE1_HEADER_SIZE)) - return -ENOMEM; - else -- __skb_pull(skb, NSH_M_TYPE1_LEN); -+ __skb_pull(skb, ETH_NSH_TYPE1_HEADER_SIZE); - - return 0; - } -@@ -267,48 +267,21 @@ static int push_nsh(struct sk_buff *skb, struct sw_flow_key *key, - { - - if (nsh->nsh_mdtype == NSH_M_TYPE1) { -- if (skb_cow_head(skb, NSH_M_TYPE1_LEN) < 0) -- return -ENOMEM; -- -- skb_push(skb, NSH_M_TYPE1_LEN); -- OVS_CB(skb)->nsh_header = skb->data; -- memcpy(OVS_CB(skb)->nsh_header, nsh->header, NSH_M_TYPE1_LEN); -- } -- else -- return -EINVAL; -- -- return 0; --} -- --static int pop_eth(struct sk_buff *skb, struct sw_flow_key *key) --{ -- if (!pskb_may_pull(skb, ENCAP_ETH_PUSH_HEADER_SIZE)) -- return -ENOMEM; -- else -- __skb_pull(skb, ENCAP_ETH_PUSH_HEADER_SIZE); -- -- return 0; --} -- --static int push_eth(struct sk_buff *skb, struct sw_flow_key *key, -- const struct ovs_action_push_eth *encap_eth) --{ -- if (encap_eth->encap_eth_type == htons(ETH_P_NSH)) { -- if (skb_cow_head(skb, ENCAP_ETH_PUSH_HEADER_SIZE) < 0) -+ if (skb_cow_head(skb, ETH_NSH_TYPE1_HEADER_SIZE) < 0) { - return -ENOMEM; -+ } - -- skb_push(skb, ENCAP_ETH_PUSH_HEADER_SIZE); -- OVS_CB(skb)->encap_eth_header = skb->data; -- memcpy(OVS_CB(skb)->encap_eth_header, encap_eth->header, ENCAP_ETH_PUSH_HEADER_SIZE); -+ skb_push(skb, ETH_NSH_TYPE1_HEADER_SIZE); -+ OVS_CB(skb)->encap_eth_header = (struct encap_eth_hdr *)skb->data; -+ OVS_CB(skb)->nsh_header = (struct nsh_hdr *)(skb->data + ENCAP_ETH_LEN); -+ memcpy(skb->data, nsh->header, ETH_NSH_TYPE1_HEADER_SIZE); - } -- else { -+ else - return -EINVAL; -- } - - return 0; - } - -- - /* 'src' is already properly masked. */ - static void ether_addr_copy_masked(u8 *dst_, const u8 *src_, const u8 *mask_) - { -@@ -1144,14 +1117,6 @@ static int do_execute_actions(struct datapath *dp, struct sk_buff *skb, - err = pop_nsh(skb, key); - break; - -- case OVS_ACTION_ATTR_PUSH_ETH: -- err = push_eth(skb, key, nla_data(a)); -- break; -- -- case OVS_ACTION_ATTR_POP_ETH: -- err = pop_eth(skb, key); -- break; -- - case OVS_ACTION_ATTR_RECIRC: - err = execute_recirc(dp, skb, key, a, rem); - if (nla_is_last(a, rem)) { -diff --git a/datapath/flow.c b/datapath/flow.c -index 67b2f1d..e3f33f8 100644 ---- a/datapath/flow.c -+++ b/datapath/flow.c -@@ -320,8 +320,12 @@ static int parse_vlan(struct sk_buff *skb, struct sw_flow_key *key) - } - - static int parse_nsh(struct sk_buff *skb, struct sw_flow_key *key){ -- struct nsh_hdr *nsh_hdr = (struct nsh_hdr *)skb->data; -+ struct nsh_hdr *nsh_hdr = NULL; -+ -+ OVS_CB(skb)->encap_eth_header = (struct encap_eth_hdr *)skb->data; -+ nsh_hdr = (struct nsh_hdr *)((const char *)skb->data + ENCAP_ETH_LEN); - OVS_CB(skb)->nsh_header = nsh_hdr; -+ memcpy(&key->nsh.encap_eth_dst, skb->data, ENCAP_ETH_LEN); - key->nsh.nsh_mdtype = nsh_hdr->base.mdtype; - if (key->nsh.nsh_mdtype != NSH_M_TYPE1) - return -EPERM; -@@ -335,16 +339,6 @@ static int parse_nsh(struct sk_buff *skb, struct sw_flow_key *key){ - return 0; - } - --static void parse_encap_eth(struct sk_buff *skb, struct sw_flow_key *key){ -- struct encap_eth_hdr *encap_eth_header = (struct encap_eth_hdr *)skb->data; -- OVS_CB(skb)->encap_eth_header = encap_eth_header; -- key->encap_eth.encap_eth_type = encap_eth_header->encap_eth_type; -- ether_addr_copy(key->encap_eth.encap_eth_src, encap_eth_header->encap_eth_src); -- ether_addr_copy(key->encap_eth.encap_eth_dst, encap_eth_header->encap_eth_dst); -- -- return; --} -- - static __be16 parse_ethertype(struct sk_buff *skb) - { - struct llc_snap_hdr { -@@ -483,23 +477,21 @@ static int key_extract(struct sk_buff *skb, struct sw_flow_key *key) - { - int error; - struct ethhdr *eth; -+ int is_eth_nsh = 0; - - /* Extract ethernet+nsh if ethernet type is 0x894F */ - eth = (struct ethhdr *)skb->data; - if (eth->h_proto == htons(ETH_P_NSH)) { -- parse_encap_eth(skb, key); -- __skb_pull(skb, ENCAP_ETH_LEN); -- - if (unlikely(parse_nsh(skb, key))) - return -EINVAL; - if (key->nsh.nsh_mdtype == NSH_M_TYPE1 && key->nsh.nsh_np == NSH_P_ETHERNET) { -- __skb_pull(skb, NSH_M_TYPE1_LEN); -+ __skb_pull(skb, ENCAP_ETH_LEN + NSH_M_TYPE1_LEN); -+ is_eth_nsh = 1; - } else { - return -EINVAL; - } - } else { -- void *encap_eth_hdr = &(key->encap_eth); -- memset(encap_eth_hdr, 0, ENCAP_ETH_LEN); -+ memset(&key->nsh, 0, sizeof(key->nsh)); - } - - /* Flags are always used as part of stats */ -@@ -722,15 +714,15 @@ static int key_extract(struct sk_buff *skb, struct sw_flow_key *key) - } - } - -- if (key->encap_eth.encap_eth_type == htons(ETH_P_NSH)) -+ if (is_eth_nsh == 1) { - __skb_push(skb, ENCAP_ETH_LEN + NSH_M_TYPE1_LEN); -+ } - - return 0; - } - --static void ovs_key_nsh_init(struct sw_flow_key *key, __u16 len) { -- void *nsh_hdr = &(key->nsh); -- memset(nsh_hdr, 0, len); -+static void ovs_key_nsh_init(struct sw_flow_key *key) { -+ memset(&key->nsh, 0, sizeof(key->nsh)); - } - - static int nsh_extract(struct sk_buff *skb, struct sw_flow_key *key) { -@@ -740,16 +732,16 @@ static int nsh_extract(struct sk_buff *skb, struct sw_flow_key *key) { - if (unlikely(parse_nsh(skb, key))) - return -EINVAL; - if (key->nsh.nsh_mdtype == NSH_M_TYPE1) { -- __skb_pull(skb, NSH_M_TYPE1_LEN); -+ __skb_pull(skb, ENCAP_ETH_LEN + NSH_M_TYPE1_LEN); - if(key->nsh.nsh_np == NSH_P_ETHERNET) - ret = key_extract(skb, key); - else - return -EINVAL; -- __skb_push(skb, NSH_M_TYPE1_LEN); -+ __skb_push(skb, ENCAP_ETH_LEN + NSH_M_TYPE1_LEN); - - return ret; - } else { -- ovs_key_nsh_init(key, NSH_M_TYPE1_LEN); -+ ovs_key_nsh_init(key); - } - - return 0; -@@ -760,7 +752,7 @@ static bool is_nsh_header(const void *tun_opts, __be16 tun_flags) { - if (tun_opts && (tun_flags & TUNNEL_VXLAN_OPT)) - md = (struct vxlan_metadata *)tun_opts; - -- if (md && (md->gpe & VXLAN_GPE_NP_MASK) == VXLAN_GPE_NP_NSH) -+ if (md && ((md->gpe & VXLAN_GPE_NP_MASK) == VXLAN_GPE_NP_NSH)) - return true; - else - return false; -@@ -768,7 +760,7 @@ static bool is_nsh_header(const void *tun_opts, __be16 tun_flags) { - - int ovs_flow_key_update(struct sk_buff *skb, struct sw_flow_key *key) - { -- ovs_key_nsh_init(key, NSH_M_TYPE1_LEN); -+ ovs_key_nsh_init(key); - return key_extract(skb, key); - } - -@@ -804,13 +796,13 @@ int ovs_flow_key_extract(const struct ip_tunnel_info *tun_info, - key->recirc_id = 0; - - /* Extract NSH and inner Ethernet if NSH header exists */ -- if (tun_info && is_nsh_header(ip_tunnel_info_opts(tun_info), key->tun_key.tun_flags)) { -+ if (tun_info && is_nsh_header(TUN_METADATA_OPTS(key, key->tun_opts_len), key->tun_key.tun_flags)) { - int ret ; - ret = nsh_extract(skb, key); - if (key->nsh.nsh_mdtype) - return ret; - } else { -- ovs_key_nsh_init(key, NSH_M_TYPE1_LEN); -+ ovs_key_nsh_init(key); - } - return key_extract(skb, key); - } -@@ -833,7 +825,7 @@ int ovs_flow_key_extract_userspace(struct net *net, const struct nlattr *attr, - if (key->nsh.nsh_mdtype) - return ret; - } else { -- ovs_key_nsh_init(key, NSH_M_TYPE1_LEN); -+ ovs_key_nsh_init(key); - } - - return key_extract(skb, key); -diff --git a/datapath/flow.h b/datapath/flow.h -index c8ccd5f..c00144a 100644 ---- a/datapath/flow.h -+++ b/datapath/flow.h -@@ -63,21 +63,7 @@ struct sw_flow_key { - u32 skb_mark; /* SKB mark. */ - u16 in_port; /* Input switch port (or DP_MAX_PORTS). */ - } __packed phy; /* Safe when right after 'tun_key'. */ -- struct { -- u32 nshc1; /* NSH context C1-C4 */ -- u32 nshc2; -- u32 nshc3; -- u32 nshc4; -- u32 nsp; /* NSH path id */ -- u8 nsi; /* NSH index */ -- u8 nsh_mdtype; /* NSH metadata type */ -- u8 nsh_np; /* NSH next protocol */ -- }__packed nsh; /* network service header */ -- struct { -- u8 encap_eth_src[ETH_ALEN]; /* ENCAP ethernet source address. */ -- u8 encap_eth_dst[ETH_ALEN]; /* ENCAP ethernet destination address. */ -- u16 encap_eth_type; /* ENCAP ethernet type. */ -- } encap_eth; -+ struct ovs_key_nsh nsh; /* network service header */ - u32 ovs_flow_hash; /* Datapath computed hash value. */ - u32 recirc_id; /* Recirculation ID. */ - struct { -diff --git a/datapath/flow_netlink.c b/datapath/flow_netlink.c -index ebfae37..3e26ac5 100644 ---- a/datapath/flow_netlink.c -+++ b/datapath/flow_netlink.c -@@ -284,7 +284,7 @@ size_t ovs_key_attr_size(void) - /* Whenever adding new OVS_KEY_ FIELDS, we should consider - * updating this function. - */ -- BUILD_BUG_ON(OVS_KEY_ATTR_TUNNEL_INFO != 28); -+ BUILD_BUG_ON(OVS_KEY_ATTR_TUNNEL_INFO != 27); - - return nla_total_size(4) /* OVS_KEY_ATTR_PRIORITY */ - + nla_total_size(0) /* OVS_KEY_ATTR_TUNNEL */ -@@ -297,8 +297,7 @@ size_t ovs_key_attr_size(void) - + nla_total_size(2) /* OVS_KEY_ATTR_CT_ZONE */ - + nla_total_size(4) /* OVS_KEY_ATTR_CT_MARK */ - + nla_total_size(16) /* OVS_KEY_ATTR_CT_LABELS */ -- + nla_total_size(24) /* OVS_KEY_ATTR_NSH */ -- + nla_total_size(14) /* OVS_KEY_ATTR_ENCAP_ETH */ -+ + nla_total_size(40) /* OVS_KEY_ATTR_NSH */ - + nla_total_size(12) /* OVS_KEY_ATTR_ETHERNET */ - + nla_total_size(2) /* OVS_KEY_ATTR_ETHERTYPE */ - + nla_total_size(4) /* OVS_KEY_ATTR_VLAN */ -@@ -337,7 +336,6 @@ static const struct ovs_len_tbl ovs_key_lens[OVS_KEY_ATTR_MAX + 1] = { - [OVS_KEY_ATTR_IN_PORT] = { .len = sizeof(u32) }, - [OVS_KEY_ATTR_SKB_MARK] = { .len = sizeof(u32) }, - [OVS_KEY_ATTR_NSH] = { .len = sizeof(struct ovs_key_nsh) }, -- [OVS_KEY_ATTR_ENCAP_ETH] = { .len = sizeof(struct ovs_key_encap_eth) }, - [OVS_KEY_ATTR_ETHERNET] = { .len = sizeof(struct ovs_key_ethernet) }, - [OVS_KEY_ATTR_VLAN] = { .len = sizeof(__be16) }, - [OVS_KEY_ATTR_ETHERTYPE] = { .len = sizeof(__be16) }, -@@ -877,6 +875,12 @@ static int ovs_key_from_nlattrs(struct net *net, struct sw_flow_match *match, - const struct ovs_key_nsh *nsh_key; - - nsh_key = nla_data(a[OVS_KEY_ATTR_NSH]); -+ SW_FLOW_KEY_MEMCPY(match, nsh.encap_eth_src, -+ nsh_key->encap_eth_src, ETH_ALEN, is_mask); -+ SW_FLOW_KEY_MEMCPY(match, nsh.encap_eth_dst, -+ nsh_key->encap_eth_dst, ETH_ALEN, is_mask); -+ SW_FLOW_KEY_PUT(match, nsh.encap_eth_type, -+ nsh_key->encap_eth_type, is_mask); - SW_FLOW_KEY_PUT(match, nsh.nshc1, - nsh_key->nshc1, is_mask); - SW_FLOW_KEY_PUT(match, nsh.nshc2, -@@ -896,19 +900,6 @@ static int ovs_key_from_nlattrs(struct net *net, struct sw_flow_match *match, - attrs &= ~(1ULL << OVS_KEY_ATTR_NSH); - } - -- if (attrs & (1ULL << OVS_KEY_ATTR_ENCAP_ETH)) { -- const struct ovs_key_encap_eth *encap_eth_key; -- -- encap_eth_key = nla_data(a[OVS_KEY_ATTR_ENCAP_ETH]); -- SW_FLOW_KEY_MEMCPY(match, encap_eth.encap_eth_src, -- encap_eth_key->encap_eth_src, ETH_ALEN, is_mask); -- SW_FLOW_KEY_MEMCPY(match, encap_eth.encap_eth_dst, -- encap_eth_key->encap_eth_dst, ETH_ALEN, is_mask); -- SW_FLOW_KEY_PUT(match, encap_eth.encap_eth_type, -- encap_eth_key->encap_eth_type, is_mask); -- attrs &= ~(1ULL << OVS_KEY_ATTR_ENCAP_ETH); -- } -- - if (attrs & (1ULL << OVS_KEY_ATTR_ETHERNET)) { - const struct ovs_key_ethernet *eth_key; - -@@ -1433,6 +1424,9 @@ static int __ovs_nla_put_key(const struct sw_flow_key *swkey, - if (!nla) - goto nla_put_failure; - nsh_key = nla_data(nla); -+ memcpy(nsh_key->encap_eth_dst, output->nsh.encap_eth_dst, ETH_ALEN); -+ memcpy(nsh_key->encap_eth_src, output->nsh.encap_eth_src, ETH_ALEN); -+ nsh_key->encap_eth_type = output->nsh.encap_eth_type; - nsh_key->nsi = output->nsh.nsi; - nsh_key->nsp = output->nsh.nsp; - nsh_key->nsh_mdtype= output->nsh.nsh_mdtype; -@@ -1443,18 +1437,6 @@ static int __ovs_nla_put_key(const struct sw_flow_key *swkey, - nsh_key->nshc4 = output->nsh.nshc4; - } - -- if ((swkey->encap_eth.encap_eth_type || is_mask)) { -- struct ovs_key_encap_eth *encap_eth_key; -- -- nla = nla_reserve(skb, OVS_KEY_ATTR_ENCAP_ETH, sizeof(*encap_eth_key)); -- if (!nla) -- goto nla_put_failure; -- encap_eth_key = nla_data(nla); -- memcpy(encap_eth_key->encap_eth_src, output->encap_eth.encap_eth_src, ETH_ALEN); -- memcpy(encap_eth_key->encap_eth_dst, output->encap_eth.encap_eth_dst, ETH_ALEN); -- encap_eth_key->encap_eth_type= output->encap_eth.encap_eth_type; -- } -- - if ((swkey->tun_key.u.ipv4.dst || is_mask)) { - const void *opts = NULL; - -@@ -2253,8 +2235,6 @@ static int __ovs_nla_copy_actions(struct net *net, const struct nlattr *attr, - [OVS_ACTION_ATTR_POP_VLAN] = 0, - [OVS_ACTION_ATTR_PUSH_NSH] = sizeof(struct ovs_action_push_nsh), - [OVS_ACTION_ATTR_POP_NSH] = 0, -- [OVS_ACTION_ATTR_PUSH_ETH] = sizeof(struct ovs_action_push_eth), -- [OVS_ACTION_ATTR_POP_ETH] = 0, - [OVS_ACTION_ATTR_SET] = (u32)-1, - [OVS_ACTION_ATTR_SET_MASKED] = (u32)-1, - [OVS_ACTION_ATTR_SAMPLE] = (u32)-1, -@@ -2301,8 +2281,6 @@ static int __ovs_nla_copy_actions(struct net *net, const struct nlattr *attr, - - case OVS_ACTION_ATTR_PUSH_NSH: - case OVS_ACTION_ATTR_POP_NSH: -- case OVS_ACTION_ATTR_PUSH_ETH: -- case OVS_ACTION_ATTR_POP_ETH: - break; - - case OVS_ACTION_ATTR_POP_VLAN: -diff --git a/datapath/linux/compat/include/linux/openvswitch.h b/datapath/linux/compat/include/linux/openvswitch.h -index 187bb9b..bf1be4e 100644 ---- a/datapath/linux/compat/include/linux/openvswitch.h -+++ b/datapath/linux/compat/include/linux/openvswitch.h -@@ -331,7 +331,6 @@ enum ovs_key_attr { - OVS_KEY_ATTR_IN_PORT, /* u32 OVS dp port number */ - OVS_KEY_ATTR_NSH, /* struct ovs_key_nsh. Only support NSH MD - type 1 now */ -- OVS_KEY_ATTR_ENCAP_ETH, /* struct ovs_key_encap_eth */ - OVS_KEY_ATTR_ETHERNET, /* struct ovs_key_ethernet */ - OVS_KEY_ATTR_VLAN, /* be16 VLAN TCI */ - OVS_KEY_ATTR_ETHERTYPE, /* be16 Ethernet type */ -@@ -406,6 +405,10 @@ enum ovs_frag_type { - #define OVS_FRAG_TYPE_MAX (__OVS_FRAG_TYPE_MAX - 1) - - struct ovs_key_nsh { -+ __u8 encap_eth_dst[ETH_ALEN]; -+ __u8 encap_eth_src[ETH_ALEN]; -+ __u16 encap_eth_type; -+ __u16 pad1; - __u32 nshc1; - __u32 nshc2; - __u32 nshc3; -@@ -414,14 +417,8 @@ struct ovs_key_nsh { - __u8 nsi; - __u8 nsh_mdtype; - __u8 nsh_np; -- __u8 reserved; --}; -- --struct ovs_key_encap_eth { -- __u8 encap_eth_src[ETH_ALEN]; -- __u8 encap_eth_dst[ETH_ALEN]; -- __u16 encap_eth_type; --}; -+ __u8 pad2; -+} __packed; - - struct ovs_key_ethernet { - __u8 eth_src[ETH_ALEN]; -@@ -652,6 +649,85 @@ struct ovs_action_push_vlan { - __be16 vlan_tci; /* 802.1Q TCI (VLAN ID and priority). */ - }; - -+#ifndef __VXLAN_GPE_HEADER -+#define __VXLAN_GPE_HEADER 1 -+ -+/* -+ * VXLAN Generic Protocol 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. -+ * -+ * Next Protocol = This 8 bit field indicates the protocol header -+ * immediately following the VXLAN GPE header. -+ * -+ * [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 " -+#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 (1UL << 24) -+#define VXLAN_GPE_NP_APPLIED (1UL << 26) -+#define VXLAN_GPE_INSTANCE_APPLIED (1UL << 27) -+#define VXLAN_GPE_VERSION ((1UL << 28) | (1UL << 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) -+ -+#define VXLAN_F_GPE 0x4000 -+#define VXLAN_HF_GPE 0x04000000 -+ -+#endif /* __VXLAN_GPE_HEADER */ -+ - /* - * Network Service Header: - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -@@ -769,6 +845,7 @@ struct nsh_hdr { - - #define ENCAP_ETH_LEN 14 - -+#define ETH_NSH_TYPE1_HEADER_SIZE (NSH_PUSH_TYPE1_HEADER_SIZE + ENCAP_ETH_LEN) - /** - * struct encap_eth - encap ethernet header for ethernet NSH - * @encap_eth_src: encap ethernet source address. -@@ -781,6 +858,11 @@ struct encap_eth_hdr { - __u16 encap_eth_type; - }; - -+struct eth_nsh_hdr { -+ struct encap_eth_hdr encap_eth_header; -+ struct nsh_hdr nsh_hdr __attribute__((packed)); -+}; -+ - #define ENCAP_ETH_PUSH_HEADER_SIZE 14 - /** - * struct ovs_action_push_nsh - %OVS_ACTION_ATTR_PUSH_NSH action argument. -@@ -791,15 +873,6 @@ struct ovs_action_push_nsh { - uint8_t header[NSH_PUSH_HEADER_SIZE]; - }; - --/** -- * struct ovs_action_push_nsh - %OVS_ACTION_ATTR_PUSH_NSH action argument. -- * @header -- */ --struct ovs_action_push_eth { -- uint16_t encap_eth_type; -- uint8_t header[ENCAP_ETH_PUSH_HEADER_SIZE]; --}; -- - /* Data path hash algorithm for computing Datapath hash. - * - * The algorithm type only specifies the fields in a flow -@@ -839,6 +912,7 @@ struct ovs_action_push_tnl { - uint32_t out_port; - uint32_t header_len; - uint32_t tnl_type; /* For logging. */ -+ uint32_t exts; - uint8_t header[TNL_PUSH_HEADER_SIZE]; - }; - #endif -@@ -965,8 +1039,6 @@ enum ovs_action_attr { - OVS_ACTION_ATTR_POP_VLAN, /* No argument. */ - OVS_ACTION_ATTR_PUSH_NSH, /* struct ovs_action_push_nsh. */ - OVS_ACTION_ATTR_POP_NSH, /* No argument. */ -- OVS_ACTION_ATTR_PUSH_ETH, /* struct ovs_action_push_eth. */ -- OVS_ACTION_ATTR_POP_ETH, /* No argument. */ - OVS_ACTION_ATTR_SAMPLE, /* Nested OVS_SAMPLE_ATTR_*. */ - OVS_ACTION_ATTR_RECIRC, /* u32 recirc_id. */ - OVS_ACTION_ATTR_HASH, /* struct ovs_action_hash. */ -diff --git a/datapath/linux/compat/include/net/vxlan.h b/datapath/linux/compat/include/net/vxlan.h -index 3aeac88..31f9e5e 100644 ---- a/datapath/linux/compat/include/net/vxlan.h -+++ b/datapath/linux/compat/include/net/vxlan.h -@@ -84,6 +84,8 @@ struct vxlanhdr_gbp { - #define VXLAN_GBP_POLICY_APPLIED (BIT(3) << 16) - #define VXLAN_GBP_ID_MASK (0xFFFF) - -+#ifndef __VXLAN_GPE_HEADER -+#define __VXLAN_GPE_HEADER 1 - /* - * VXLAN Generic Protocol Extension: - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -@@ -156,6 +158,11 @@ struct vxlanhdr_gpe { - #define VXLAN_GPE_USED_BITS (VXLAN_GPE_OAM_FLAG | VXLAN_GPE_NP_APPLIED \ - | VXLAN_GPE_INSTANCE_APPLIED | VXLAN_GPE_VERSION | 0xFF) - -+#define VXLAN_HF_GPE BIT(26) -+#define VXLAN_F_GPE 0x4000 -+ -+#endif /* __VXLAN_GPE_HEADER */ -+ - /* VXLAN protocol header: - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * |G|R|R|R|I|R|R|C| Reserved | -@@ -176,7 +183,6 @@ 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 */ -@@ -279,7 +285,6 @@ 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 -diff --git a/datapath/linux/compat/vxlan.c b/datapath/linux/compat/vxlan.c -index 7ef051c..888d431 100644 ---- a/datapath/linux/compat/vxlan.c -+++ b/datapath/linux/compat/vxlan.c -@@ -821,6 +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; - int err = 0; - - /* For flow based devices, map all packets to VNI 0 */ -@@ -888,6 +889,15 @@ static void vxlan_rcv(struct vxlan_sock *vs, struct sk_buff *skb, - stats->rx_packets++; - stats->rx_bytes += skb->len; - 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)) { -+ 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; - drop: -@@ -1178,6 +1188,11 @@ 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)) { -+ skb_pull(skb, ENCAP_ETH_LEN); -+ } -+ - min_headroom = LL_RESERVED_SPACE(rt->dst.dev) + rt->dst.header_len - + VXLAN_HLEN + sizeof(struct iphdr) - + (skb_vlan_tag_present(skb) ? VLAN_HLEN : 0); -diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c -index 8e67bfd..d40cae4 100644 ---- a/lib/dpif-netdev.c -+++ b/lib/dpif-netdev.c -@@ -467,7 +467,7 @@ static int get_port_by_name(struct dp_netdev *dp, const char *devname, - static void dp_netdev_free(struct dp_netdev *) - OVS_REQUIRES(dp_netdev_mutex); - static int do_add_port(struct dp_netdev *dp, const char *devname, -- const char *type, odp_port_t port_no) -+ const char *type, odp_port_t port_no, uint32_t exts) - OVS_REQUIRES(dp->port_mutex); - static void do_del_port(struct dp_netdev *dp, struct dp_netdev_port *) - OVS_REQUIRES(dp->port_mutex); -@@ -914,7 +914,7 @@ create_dp_netdev(const char *name, const struct dpif_class *class, - dp_netdev_set_nonpmd(dp); - - ovs_mutex_lock(&dp->port_mutex); -- error = do_add_port(dp, name, "internal", ODPP_LOCAL); -+ error = do_add_port(dp, name, "internal", ODPP_LOCAL, 0); - ovs_mutex_unlock(&dp->port_mutex); - if (error) { - dp_netdev_free(dp); -@@ -1096,9 +1096,21 @@ hash_port_no(odp_port_t port_no) - return hash_int(odp_to_u32(port_no), 0); - } - -+static void add_vxlan_gpe_exts(struct netdev *netdev, uint32_t exts) -+{ -+ const char *type = netdev_get_type(netdev); -+ if (!strcmp(type, "vxlan")) { -+ struct netdev_tunnel_config *cfg; -+ cfg = netdev_get_tunnel_config(netdev); -+ -+ if(exts & (1 << OVS_VXLAN_EXT_GPE)) -+ cfg->exts |= (1 << OVS_VXLAN_EXT_GPE); -+ } -+} -+ - static int - do_add_port(struct dp_netdev *dp, const char *devname, const char *type, -- odp_port_t port_no) -+ odp_port_t port_no, uint32_t exts) - OVS_REQUIRES(dp->port_mutex) - { - struct netdev_saved_flags *sf; -@@ -1145,7 +1157,8 @@ do_add_port(struct dp_netdev *dp, const char *devname, const char *type, - VLOG_ERR("%s, cannot set multiq", devname); - return errno; - } -- } -+ } -+ add_vxlan_gpe_exts(netdev, exts); - port = xzalloc(sizeof *port); - port->port_no = port_no; - port->netdev = netdev; -@@ -1211,7 +1224,12 @@ dpif_netdev_port_add(struct dpif *dpif, struct netdev *netdev, - } - if (!error) { - *port_nop = port_no; -- error = do_add_port(dp, dpif_port, netdev_get_type(netdev), port_no); -+ const struct netdev_tunnel_config *cfg; -+ uint32_t exts = 0; -+ cfg = netdev_get_tunnel_config(netdev); -+ if (cfg) -+ exts = cfg->exts; -+ error = do_add_port(dp, dpif_port, netdev_get_type(netdev), port_no, exts); - } - ovs_mutex_unlock(&dp->port_mutex); - -@@ -3876,8 +3894,6 @@ dp_execute_cb(void *aux_, struct dp_packet **packets, int cnt, - - case OVS_ACTION_ATTR_PUSH_NSH: - case OVS_ACTION_ATTR_POP_NSH: -- case OVS_ACTION_ATTR_PUSH_ETH: -- case OVS_ACTION_ATTR_POP_ETH: - case OVS_ACTION_ATTR_PUSH_VLAN: - case OVS_ACTION_ATTR_POP_VLAN: - case OVS_ACTION_ATTR_PUSH_MPLS: -diff --git a/lib/dpif.c b/lib/dpif.c -index b5265c4..481f0f9 100644 ---- a/lib/dpif.c -+++ b/lib/dpif.c -@@ -1141,8 +1141,6 @@ dpif_execute_helper_cb(void *aux_, struct dp_packet **packets, int cnt, - case OVS_ACTION_ATTR_HASH: - case OVS_ACTION_ATTR_PUSH_NSH: - case OVS_ACTION_ATTR_POP_NSH: -- case OVS_ACTION_ATTR_PUSH_ETH: -- case OVS_ACTION_ATTR_POP_ETH: - case OVS_ACTION_ATTR_PUSH_VLAN: - case OVS_ACTION_ATTR_POP_VLAN: - case OVS_ACTION_ATTR_PUSH_MPLS: -diff --git a/lib/flow.c b/lib/flow.c -index fc8b98c..887b023 100644 ---- a/lib/flow.c -+++ b/lib/flow.c -@@ -470,6 +470,25 @@ flow_extract(struct dp_packet *packet, struct flow *flow) - miniflow_expand(&m.mf, flow); - } - -+/* parse Ethernet+NSH */ -+static int parse_nsh(const void *data, struct ovs_key_nsh *nsh) -+{ -+ memcpy(&nsh->encap_eth_dst, data, ENCAP_ETH_LEN); -+ const struct nsh_hdr *nsh_hdr = (const struct nsh_hdr *)((const char *)data + ENCAP_ETH_LEN); -+ -+ nsh->nsh_mdtype = nsh_hdr->base.mdtype; -+ if (nsh->nsh_mdtype != NSH_M_TYPE1) -+ return -1; -+ nsh->nsh_np = nsh_hdr->base.proto; -+ nsh->nsi = nsh_hdr->base.svc_idx; -+ nsh->nsp = nsh_hdr->base.path_hdr << 8; -+ nsh->nshc1 = nsh_hdr->ctx.nshc1; -+ nsh->nshc2 = nsh_hdr->ctx.nshc2; -+ nsh->nshc3 = nsh_hdr->ctx.nshc3; -+ nsh->nshc4 = nsh_hdr->ctx.nshc4; -+ return 0; -+} -+ - /* Caller is responsible for initializing 'dst' with enough storage for - * FLOW_U64S * 8 bytes. */ - void -@@ -530,6 +549,32 @@ miniflow_extract(struct dp_packet *packet, struct miniflow *dst) - } - } - -+ /* Extract Etherenet + NSH if the Ethernet type is 0x894F in packet */ -+ if (OVS_UNLIKELY(size < sizeof(struct eth_header))) -+ goto out; -+ else { -+ const struct eth_header *eth = data; -+ if (eth->eth_type == htons(ETH_P_NSH)) { -+ /* extract Ethernet+nsh */ -+ struct ovs_key_nsh nsh; -+ if (OVS_UNLIKELY(parse_nsh(data, &nsh))) -+ goto out; -+ -+ /* Now only support NSH mdtype 1 */ -+ if (nsh.nsh_mdtype == NSH_M_TYPE1){ -+ /* Push all field related with Ethernet+nsh at once. */ -+ miniflow_push_words(mf, encap_eth_dst, &nsh, -+ (sizeof (struct ovs_key_nsh)+sizeof(uint64_t) - 1) / -+ sizeof(uint64_t)); -+ data = (const char *)data + NSH_M_TYPE1_LEN + ENCAP_ETH_LEN; -+ } else -+ goto out; -+ -+ if(nsh.nsh_np != NSH_P_ETHERNET) -+ goto out; -+ } -+ } -+ - /* Initialize packet's layer pointer and offsets. */ - l2 = data; - dp_packet_reset_offsets(packet); -@@ -1291,6 +1336,9 @@ void flow_wildcards_init_for_packet(struct flow_wildcards *wc, - - /* NSH fields wildcarded */ - if (flow->nsh_mdtype) { -+ WC_MASK_FIELD(wc, encap_eth_src); -+ WC_MASK_FIELD(wc, encap_eth_dst); -+ WC_MASK_FIELD(wc, encap_eth_type); - WC_MASK_FIELD(wc, nshc1); - WC_MASK_FIELD(wc, nshc2); - WC_MASK_FIELD(wc, nshc3); -@@ -1301,13 +1349,6 @@ void flow_wildcards_init_for_packet(struct flow_wildcards *wc, - WC_MASK_FIELD(wc, nsi); - } - -- /* ENCAP Eth wildcarded */ -- if (flow->encap_eth_type) { -- WC_MASK_FIELD(wc, encap_eth_src); -- WC_MASK_FIELD(wc, encap_eth_dst); -- WC_MASK_FIELD(wc, encap_eth_type); -- } -- - /* metadata, regs, and conj_id wildcarded. */ - - WC_MASK_FIELD(wc, skb_priority); -@@ -1424,6 +1465,19 @@ flow_wc_map(const struct flow *flow, struct flowmap *map) - FLOWMAP_SET(map, ct_mark); - FLOWMAP_SET(map, ct_label); - -+ /* NSH fields */ -+ FLOWMAP_SET(map, encap_eth_src); -+ FLOWMAP_SET(map, encap_eth_dst); -+ FLOWMAP_SET(map, encap_eth_type); -+ FLOWMAP_SET(map, nshc1); -+ FLOWMAP_SET(map, nshc2); -+ FLOWMAP_SET(map, nshc3); -+ FLOWMAP_SET(map, nshc4); -+ FLOWMAP_SET(map, nsp); -+ FLOWMAP_SET(map, nsi); -+ FLOWMAP_SET(map, nsh_mdtype); -+ FLOWMAP_SET(map, nsh_np); -+ - /* Ethertype-dependent fields. */ - if (OVS_LIKELY(flow->dl_type == htons(ETH_TYPE_IP))) { - FLOWMAP_SET(map, nw_src); -@@ -2271,6 +2325,33 @@ flow_compose_l4(struct dp_packet *p, const struct flow *flow) - return l4_len; - } - -+/* push ethernet+nsh header at the beginning of packets */ -+static void -+flow_compose_nsh(struct dp_packet *p, const struct flow *flow) -+{ -+ struct eth_nsh_hdr *eth_nsh_header; -+ -+ /* Now only support mdtype1 */ -+ if (flow->nsh_mdtype != NSH_M_TYPE1) -+ return; -+ -+ eth_nsh_header = dp_packet_push_uninit(p, ETH_NSH_TYPE1_HEADER_SIZE); -+ eth_nsh_header->encap_eth_header.encap_eth_dst = flow->encap_eth_dst; -+ eth_nsh_header->encap_eth_header.encap_eth_src = flow->encap_eth_src; -+ eth_nsh_header->encap_eth_header.encap_eth_type = htons(ETH_P_NSH); -+ -+ memset(ð_nsh_header->nsh_hdr, 0, sizeof (struct nsh_hdr)); -+ eth_nsh_header->nsh_hdr.base.length = 6; -+ eth_nsh_header->nsh_hdr.base.proto = flow->nsh_np; -+ eth_nsh_header->nsh_hdr.base.mdtype = flow->nsh_mdtype; -+ eth_nsh_header->nsh_hdr.base.proto = flow->nsh_np; -+ eth_nsh_header->nsh_hdr.base.path_hdr = flow->nsp >> 8 | flow->nsi << 24; -+ eth_nsh_header->nsh_hdr.ctx.nshc1 = flow->nshc1; -+ eth_nsh_header->nsh_hdr.ctx.nshc2 = flow->nshc2; -+ eth_nsh_header->nsh_hdr.ctx.nshc3 = flow->nshc3; -+ eth_nsh_header->nsh_hdr.ctx.nshc4 = flow->nshc4; -+} -+ - /* Puts into 'b' a packet that flow_extract() would parse as having the given - * 'flow'. - * -@@ -2371,6 +2452,10 @@ flow_compose(struct dp_packet *p, const struct flow *flow) - push_mpls(p, flow->dl_type, flow->mpls_lse[--n]); - } - } -+ -+ if (flow->nsh_mdtype) { -+ flow_compose_nsh(p, flow); -+ } - } - - /* Compressed flow. */ -diff --git a/lib/flow.h b/lib/flow.h -index a8677b1..31a2a16 100644 ---- a/lib/flow.h -+++ b/lib/flow.h -@@ -111,7 +111,11 @@ struct flow { - ofp_port_t actset_output; /* Output port in action set. */ - uint8_t pad2[2]; /* Pad to 64 bits. */ - -- /* NSH (64-bit aligned) */ -+ /* ETH + NSH (64-bit aligned) */ -+ struct eth_addr encap_eth_dst; /* Encap ethernet destination address. */ -+ struct eth_addr encap_eth_src; /* Encap ethernet source address. */ -+ ovs_be16 encap_eth_type; /* Encap ethernet frame type. */ -+ uint8_t pad3[2]; /* Pad to 64 bits. */ - ovs_be32 nshc1; - ovs_be32 nshc2; - ovs_be32 nshc3; -@@ -120,13 +124,7 @@ struct flow { - uint8_t nsi; - uint8_t nsh_mdtype; - uint8_t nsh_np; -- uint8_t pad3; -- -- /* ENCAP_ETH (64-bit aligned) */ -- struct eth_addr encap_eth_src; /* Encap ethernet source address. */ -- struct eth_addr encap_eth_dst; /* Encap ethernet destination address. */ -- ovs_be16 encap_eth_type; /* Encap ethernet frame type. */ -- uint8_t pad4[2]; -+ uint8_t pad4; - - /* L2, Order the same as in the Ethernet header! (64-bit aligned) */ - struct eth_addr dl_dst; /* Ethernet destination address. */ -diff --git a/lib/match.c b/lib/match.c -index 3db2a2b..2b6648d 100644 ---- a/lib/match.c -+++ b/lib/match.c -@@ -1002,12 +1002,12 @@ match_set_encap_eth_dst(struct match *match, const struct eth_addr encap_eth_dst - } - - void --match_set_encap_eth_type(struct match *match, uint16_t encap_eth_type) -+match_set_encap_eth_type(struct match *match, ovs_be16 encap_eth_type) - { -- match_set_encap_eth_type_masked(match, encap_eth_type, UINT16_MAX); -+ match->wc.masks.encap_eth_type = OVS_BE16_MAX; -+ match->flow.encap_eth_type = encap_eth_type; - } - -- - /* Returns true if 'a' and 'b' wildcard the same fields and have the same - * values for fixed fields, otherwise false. */ - bool -@@ -1338,12 +1338,11 @@ match_format(const struct match *match, struct ds *s, int priority) - wc->masks.nshc4); - } - -- if (wc->masks.encap_eth_type) { -- ds_put_format(s, "encap_eth_type=%"PRIu16",", f->encap_eth_type); -- } -- - format_eth_masked(s, "encap_eth_src", f->encap_eth_src, wc->masks.encap_eth_src); - format_eth_masked(s, "encap_eth_dst", f->encap_eth_dst, wc->masks.encap_eth_dst); -+ if (wc->masks.encap_eth_type) { -+ ds_put_format(s, "encap_eth_type=0x%04"PRIx16",", ntohs(f->encap_eth_type)); -+ } - - if (wc->masks.dl_type) { - skip_type = true; -diff --git a/lib/match.h b/lib/match.h -index 529350e..bf27d38 100644 ---- a/lib/match.h -+++ b/lib/match.h -@@ -187,7 +187,7 @@ void match_set_nshc3(struct match *, ovs_be32 nshc3); - void match_set_nshc4(struct match *, ovs_be32 nshc4); - void match_set_encap_eth_src(struct match *match, const struct eth_addr encap_eth_src); - void match_set_encap_eth_dst(struct match *match, const struct eth_addr encap_eth_dst); --void match_set_encap_eth_type(struct match *match, uint16_t encap_eth_type); -+void match_set_encap_eth_type(struct match *match, ovs_be16 encap_eth_type); - - bool match_equal(const struct match *, const struct match *); - uint32_t match_hash(const struct match *, uint32_t basis); -diff --git a/lib/meta-flow.h b/lib/meta-flow.h -index a226b79..4c49adb 100644 ---- a/lib/meta-flow.h -+++ b/lib/meta-flow.h -@@ -1915,7 +1915,7 @@ enum OVS_PACKED_ENUM mf_field_id { - * Maskable: no. - * Formatting: hexadecimal. - * Prerequisites: none. -- * Access: read/write. -+ * Access: read-only. - * NXM: NXM_NX_ENCAP_ETH_TYPE(123) since v1.1. - * OXM: none. - */ -diff --git a/lib/netdev-vport.c b/lib/netdev-vport.c -index 406a492..67a020a 100644 ---- a/lib/netdev-vport.c -+++ b/lib/netdev-vport.c -@@ -584,12 +584,12 @@ set_tunnel_config(struct netdev *dev_, const struct smap *args) - if (!strcmp(type, "vxlan") && !strcmp(ext, "gbp")) { - if (tnl_cfg.exts & (1 << OVS_VXLAN_EXT_GPE)) - VLOG_WARN("VXLAN_GPE extension exists, VxLAN_GBP extension can't be added."); -- else -+ else - tnl_cfg.exts |= (1 << OVS_VXLAN_EXT_GBP); - } else if (!strcmp(type, "vxlan") && !strcmp(ext, "gpe")) { - if (tnl_cfg.exts & (1 << OVS_VXLAN_EXT_GBP)) - VLOG_WARN("VXLAN_GBP extension exists, VxLAN_GPE extension can't be added."); -- else -+ else - tnl_cfg.exts |= (1 << OVS_VXLAN_EXT_GPE); - } else { - VLOG_WARN("%s: unknown extension '%s'", name, ext); -@@ -1048,6 +1048,9 @@ push_udp_header(struct dp_packet *packet, - struct udp_header *udp; - int ip_tot_size; - -+ if (data->tnl_type == OVS_VPORT_TYPE_VXLAN && data->exts & 1 << VXLAN_GPE_POP_ETH) -+ dp_packet_reset_packet(packet, ENCAP_ETH_LEN); -+ - udp = push_ip_header(packet, data->header, data->header_len, &ip_tot_size); - - /* set udp src port */ -@@ -1294,6 +1297,7 @@ netdev_vxlan_pop_header(struct dp_packet *packet) - struct flow_tnl *tnl = &md->tunnel; - struct vxlanhdr *vxh; - unsigned int hlen; -+ ovs_be32 flag; - - pkt_metadata_init_tnl(md); - if (VXLAN_HLEN > dp_packet_l4_size(packet)) { -@@ -1305,17 +1309,42 @@ netdev_vxlan_pop_header(struct dp_packet *packet) - 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; - -- dp_packet_reset_packet(packet, hlen + VXLAN_HLEN); -+ /* vxlan-gpe packets*/ -+ flag = get_16aligned_be32(&vxh->vx_flags); -+ -+ if (flag & VXLAN_HF_GPE) { -+ flag &= ~VXLAN_GPE_USED_BITS; -+ if ((flag & ~VXLAN_GPE_USED_BITS) || -+ get_16aligned_be32(&vxh->vx_vni) & htonl(0xff)) { -+ -+ VLOG_WARN_RL(&err_rl, "invalid vxlan flags=%#x vni=%#x\n for vxlan-gpe", -+ ntohl(get_16aligned_be32(&vxh->vx_flags)), -+ ntohl(get_16aligned_be32(&vxh->vx_vni))); -+ return EINVAL; -+ } -+ -+ struct vxlanhdr_gpe *gpe; -+ -+ gpe = (struct vxlanhdr_gpe *)vxh; -+ tnl->gpe_np = gpe->next_proto; -+ -+ /* Drop the OAM packets */ -+ if (gpe->oam_flag) -+ return EINVAL; -+ } else { -+ if (flag != 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; -+ -+ dp_packet_reset_packet(packet, hlen + VXLAN_HLEN); -+ } - - return 0; - } -@@ -1336,8 +1365,27 @@ netdev_vxlan_build_header(const struct netdev *netdev, - - vxh = udp_build_header(tnl_cfg, tnl_flow, data, &hlen); - -- put_16aligned_be32(&vxh->vx_flags, htonl(VXLAN_FLAGS)); -- put_16aligned_be32(&vxh->vx_vni, htonl(ntohll(tnl_flow->tunnel.tun_id) << 8)); -+ if(tnl_cfg->exts & (1 << OVS_VXLAN_EXT_GPE)) { -+ struct vxlanhdr_gpe *gpe; -+ -+ gpe = (struct vxlanhdr_gpe *)vxh; -+ put_16aligned_be32(&vxh->vx_flags, htonl(VXLAN_FLAGS | VXLAN_HF_GPE)); -+ put_16aligned_be32(&vxh->vx_vni, htonl(ntohll(tnl_flow->tunnel.tun_id) << 8)); -+ -+ if (!tnl_flow->tunnel.gpe_np) -+ return -1; -+ else -+ gpe->next_proto = tnl_flow->tunnel.gpe_np; -+ -+ if (tnl_flow->tunnel.gpe_flags & 0x01) -+ gpe->oam_flag = 1; -+ -+ if (tnl_flow->tunnel.gpe_np == VXLAN_GPE_NP_NSH) -+ data->exts |= 1 << VXLAN_GPE_POP_ETH; -+ } else { -+ 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 = hlen + VXLAN_HLEN; -diff --git a/lib/netdev-vport.h b/lib/netdev-vport.h -index be02cb5..a6975de 100644 ---- a/lib/netdev-vport.h -+++ b/lib/netdev-vport.h -@@ -48,6 +48,12 @@ enum { NETDEV_VPORT_NAME_BUFSIZE = 16 }; - #else - enum { NETDEV_VPORT_NAME_BUFSIZE = 256 }; - #endif -+ -+enum OVS_ACTION_PUSH_VXLAN_EXTS { -+ VXLAN_GPE_POP_ETH, /* Pop ethernet header when the field next_proto -+ * is 4 in vxlan-gpe header -+ */ -+}; - const char *netdev_vport_get_dpif_port(const struct netdev *, - char namebuf[], size_t bufsize) - OVS_WARN_UNUSED_RESULT; -diff --git a/lib/nx-match.c b/lib/nx-match.c -index 8d2bc4b..c17057f 100644 ---- a/lib/nx-match.c -+++ b/lib/nx-match.c -@@ -959,14 +959,13 @@ nx_put_raw(struct ofpbuf *b, enum ofp_version oxm, const struct match *match, - nxm_put_32m(b, MFF_NSH_C3, oxm, flow->nshc3, match->wc.masks.nshc3); - nxm_put_32m(b, MFF_NSH_C4, oxm, flow->nshc4, match->wc.masks.nshc4); - -- /* ENCAP Eth */ - nxm_put_eth_masked(b, MFF_ENCAP_ETH_SRC, oxm, - flow->encap_eth_src, match->wc.masks.encap_eth_src); - nxm_put_eth_masked(b, MFF_ENCAP_ETH_DST, oxm, - flow->encap_eth_dst, match->wc.masks.encap_eth_dst); - nxm_put_16m(b, MFF_ENCAP_ETH_TYPE, oxm, - ofputil_dl_type_to_openflow(flow->encap_eth_type), -- match->wc.masks.encap_eth_type); //uncertain -+ match->wc.masks.encap_eth_type); - - /* Ethernet. */ - nxm_put_eth_masked(b, MFF_ETH_SRC, oxm, -diff --git a/lib/odp-execute.c b/lib/odp-execute.c -index b6dcd98..342bbaf 100644 ---- a/lib/odp-execute.c -+++ b/lib/odp-execute.c -@@ -338,6 +338,7 @@ odp_execute_set_action(struct dp_packet *packet, const struct nlattr *a) - case OVS_KEY_ATTR_CT_ZONE: - case OVS_KEY_ATTR_CT_MARK: - case OVS_KEY_ATTR_CT_LABELS: -+ case OVS_KEY_ATTR_NSH: - case __OVS_KEY_ATTR_MAX: - default: - OVS_NOT_REACHED(); -@@ -435,7 +436,6 @@ odp_execute_masked_set_action(struct dp_packet *packet, - case OVS_KEY_ATTR_IN_PORT: - case OVS_KEY_ATTR_VLAN: - case OVS_KEY_ATTR_NSH: -- case OVS_KEY_ATTR_ENCAP_ETH: - case OVS_KEY_ATTR_ICMP: - case OVS_KEY_ATTR_ICMPV6: - case OVS_KEY_ATTR_TCP_FLAGS: -@@ -501,8 +501,6 @@ requires_datapath_assistance(const struct nlattr *a) - case OVS_ACTION_ATTR_SET_MASKED: - case OVS_ACTION_ATTR_PUSH_NSH: - case OVS_ACTION_ATTR_POP_NSH: -- case OVS_ACTION_ATTR_PUSH_ETH: -- case OVS_ACTION_ATTR_POP_ETH: - case OVS_ACTION_ATTR_PUSH_VLAN: - case OVS_ACTION_ATTR_POP_VLAN: - case OVS_ACTION_ATTR_SAMPLE: -@@ -589,6 +587,21 @@ odp_execute_actions(void *dp, struct dp_packet **packets, int cnt, bool steal, - } - break; - -+ case OVS_ACTION_ATTR_PUSH_NSH: { -+ const void *push_nsh_hdr = nl_attr_get(a); -+ -+ for (i = 0; i < cnt; i++) { -+ push_nsh(packets[i], push_nsh_hdr); -+ } -+ break; -+ } -+ -+ case OVS_ACTION_ATTR_POP_NSH: -+ for (i = 0; i < cnt; i++) { -+ pop_nsh(packets[i]); -+ } -+ break; -+ - case OVS_ACTION_ATTR_PUSH_MPLS: { - const struct ovs_action_push_mpls *mpls = nl_attr_get(a); - -@@ -629,10 +642,6 @@ odp_execute_actions(void *dp, struct dp_packet **packets, int cnt, bool steal, - } - break; - -- case OVS_ACTION_ATTR_PUSH_NSH: -- case OVS_ACTION_ATTR_POP_NSH: -- case OVS_ACTION_ATTR_PUSH_ETH: -- case OVS_ACTION_ATTR_POP_ETH: - case OVS_ACTION_ATTR_OUTPUT: - case OVS_ACTION_ATTR_TUNNEL_PUSH: - case OVS_ACTION_ATTR_TUNNEL_POP: -diff --git a/lib/odp-util.c b/lib/odp-util.c -index 102dfd7..7721cc4 100644 ---- a/lib/odp-util.c -+++ b/lib/odp-util.c -@@ -115,8 +115,6 @@ odp_action_len(uint16_t type) - case OVS_ACTION_ATTR_POP_VLAN: return 0; - case OVS_ACTION_ATTR_PUSH_NSH: return sizeof(struct ovs_action_push_nsh); - case OVS_ACTION_ATTR_POP_NSH: return 0; -- case OVS_ACTION_ATTR_PUSH_ETH: return sizeof(struct ovs_action_push_eth); -- case OVS_ACTION_ATTR_POP_ETH: return 0; - case OVS_ACTION_ATTR_PUSH_MPLS: return sizeof(struct ovs_action_push_mpls); - case OVS_ACTION_ATTR_POP_MPLS: return sizeof(ovs_be16); - case OVS_ACTION_ATTR_RECIRC: return sizeof(uint32_t); -@@ -152,7 +150,6 @@ ovs_key_attr_to_string(enum ovs_key_attr attr, char *namebuf, size_t bufsize) - case OVS_KEY_ATTR_CT_LABELS: return "ct_label"; - case OVS_KEY_ATTR_TUNNEL: return "tunnel"; - case OVS_KEY_ATTR_IN_PORT: return "in_port"; -- case OVS_KEY_ATTR_ENCAP_ETH: return "encap_eth"; - case OVS_KEY_ATTR_NSH: return "nsh"; - case OVS_KEY_ATTR_ETHERNET: return "eth"; - case OVS_KEY_ATTR_VLAN: return "vlan"; -@@ -382,31 +379,26 @@ format_vlan_tci(struct ds *ds, ovs_be16 tci, ovs_be16 mask, bool verbose) - static void - format_nsh(struct ds *ds, const struct ovs_action_push_nsh * nsh) - { -- const struct nsh_hdr *nsh_hdr =(struct nsh_hdr *)nsh->header; -+ const struct eth_nsh_hdr *eth_nsh_header = (struct eth_nsh_hdr *)nsh->header; -+ format_eth(ds, "encap_eth_src", -+ eth_nsh_header->encap_eth_header.encap_eth_src, -+ NULL, true); -+ format_eth(ds, "encap_eth_dst", -+ eth_nsh_header->encap_eth_header.encap_eth_dst, -+ NULL, true); -+ ds_put_format(ds, "encap_eth_type=0x%04"PRIx16",", -+ ntohs(eth_nsh_header->encap_eth_header.encap_eth_type)); - ds_put_format(ds, "nsh_mdtype=%"PRIu8",nsh_np=%"PRIu8",nsp=%"PRIu32 - ",nsi=%"PRIu8",nshc1=%"PRIu32",nshc2=%"PRIu32 - ",nshc3=%"PRIu32",nshc4=%"PRIu32")", -- nsh_hdr->base.mdtype, -- nsh_hdr->base.proto, -- ntohl(nsh_hdr->base.path_hdr << 8), -- ntohl(nsh_hdr->base.path_hdr >> 24), -- ntohl(nsh_hdr->ctx.nshc1), -- ntohl(nsh_hdr->ctx.nshc2), -- ntohl(nsh_hdr->ctx.nshc3), -- ntohl(nsh_hdr->ctx.nshc4)); --} -- --static void --format_encap_eth(struct ds *ds, const struct ovs_action_push_eth *encap_eth) --{ -- const struct encap_eth_hdr *encap_eth_hdr = (struct encap_eth_hdr *)encap_eth->header; -- ds_put_format(ds, "encap_eth_type=%"PRIu16",", -- ntohs(encap_eth_hdr->encap_eth_type)); -- format_eth(ds, "encap_eth_src", encap_eth_hdr->encap_eth_src, -- NULL, true); -- format_eth(ds, "encap_eth_dst", encap_eth_hdr->encap_eth_dst, -- NULL, true); -- ds_put_format(ds, ")"); -+ eth_nsh_header->nsh_hdr.base.mdtype, -+ eth_nsh_header->nsh_hdr.base.proto, -+ ntohl(eth_nsh_header->nsh_hdr.base.path_hdr << 8), -+ ntohl(eth_nsh_header->nsh_hdr.base.path_hdr >> 24), -+ ntohl(eth_nsh_header->nsh_hdr.ctx.nshc1), -+ ntohl(eth_nsh_header->nsh_hdr.ctx.nshc2), -+ ntohl(eth_nsh_header->nsh_hdr.ctx.nshc3), -+ ntohl(eth_nsh_header->nsh_hdr.ctx.nshc4)); - } - - static void -@@ -798,7 +790,6 @@ format_odp_action(struct ds *ds, const struct nlattr *a) - int expected_len; - enum ovs_action_attr type = nl_attr_type(a); - const struct ovs_action_push_nsh *nsh; -- const struct ovs_action_push_eth *encap_eth; - size_t size; - - expected_len = odp_action_len(nl_attr_type(a)); -@@ -877,15 +868,6 @@ format_odp_action(struct ds *ds, const struct nlattr *a) - case OVS_ACTION_ATTR_POP_NSH: - ds_put_cstr(ds, "pop_nsh"); - break; -- -- case OVS_ACTION_ATTR_PUSH_ETH: -- encap_eth = nl_attr_get(a); -- ds_put_cstr(ds, "push_eth("); -- format_encap_eth(ds, encap_eth); -- break; -- case OVS_ACTION_ATTR_POP_ETH: -- ds_put_cstr(ds, "pop_eth"); -- break; - case OVS_ACTION_ATTR_PUSH_MPLS: { - const struct ovs_action_push_mpls *mpls = nl_attr_get(a); - ds_put_cstr(ds, "push_mpls("); -@@ -1675,29 +1657,37 @@ parse_odp_action(const char *s, const struct simap *port_names, - - { - struct ovs_action_push_nsh push; -- struct nsh_hdr *nsh = (struct nsh_hdr *)push.header; -+ struct eth_nsh_hdr *eth_nsh_header = (struct eth_nsh_hdr *)push.header; - ovs_be32 nsp, nshc1,nshc2,nshc3,nshc4; - uint8_t nsi, nsh_mdtype, nsh_np; - int n = -1; - -- if (ovs_scan_len(s, &n, "push_nsh(nsh_mdtype=%"SCNi8",nsh_np=%"SCNi8",nsp=0x%"SCNx32 -+ if (ovs_scan_len(s, &n, "push_nsh(encap_eth_dst="ETH_ADDR_SCAN_FMT -+ ",encap_eth_src="ETH_ADDR_SCAN_FMT -+ ",encap_eth_type=0x%"SCNx16 -+ ",nsh_mdtype=%"SCNi8",nsh_np=%"SCNi8",nsp=0x%"SCNx32 - ",nsi=%"SCNi8",nshc1=0x%"SCNx32",nshc2=0x%"SCNx32 - ",nshc3=0x%"SCNx32",nshc4=0x%"SCNx32"))", -+ ETH_ADDR_SCAN_ARGS(eth_nsh_header->encap_eth_header.encap_eth_dst), -+ ETH_ADDR_SCAN_ARGS(eth_nsh_header->encap_eth_header.encap_eth_src), -+ ð_nsh_header->encap_eth_header.encap_eth_type, - &nsh_mdtype, &nsh_np, - &nsp, &nsi, - &nshc1, &nshc2, - &nshc3, &nshc4)) { -+ eth_nsh_header->encap_eth_header.encap_eth_type = htons(eth_nsh_header->encap_eth_header.encap_eth_type); - if (nsh_mdtype == NSH_M_TYPE1) { -- nsh->base.mdtype = NSH_M_TYPE1; -- nsh->base.version = 0x01; -- nsh->base.length = 6; -- nsh->base.proto = nsh_np; -- nsh->base.path_hdr= nsp; -- nsh->base.svc_idx = nsi; -- nsh->ctx.nshc1=nshc1; -- nsh->ctx.nshc2=nshc2; -- nsh->ctx.nshc3=nshc3; -- nsh->ctx.nshc4=nshc4; -+ eth_nsh_header->encap_eth_header.encap_eth_type = htons(ETH_P_NSH); -+ eth_nsh_header->nsh_hdr.base.mdtype = NSH_M_TYPE1; -+ eth_nsh_header->nsh_hdr.base.version = 0x01; -+ eth_nsh_header->nsh_hdr.base.length = 6; -+ eth_nsh_header->nsh_hdr.base.proto = nsh_np; -+ eth_nsh_header->nsh_hdr.base.path_hdr= nsp; -+ eth_nsh_header->nsh_hdr.base.svc_idx = nsi; -+ eth_nsh_header->nsh_hdr.ctx.nshc1=nshc1; -+ eth_nsh_header->nsh_hdr.ctx.nshc2=nshc2; -+ eth_nsh_header->nsh_hdr.ctx.nshc3=nshc3; -+ eth_nsh_header->nsh_hdr.ctx.nshc4=nshc4; - push.nsh_mdtype = NSH_M_TYPE1; - nl_msg_put_unspec(actions, OVS_ACTION_ATTR_PUSH_NSH, - &push, sizeof push); -@@ -1713,33 +1703,6 @@ parse_odp_action(const char *s, const struct simap *port_names, - } - - { -- struct ovs_action_push_eth push; -- struct encap_eth_hdr *encap_eth = (struct encap_eth_hdr *)push.header; -- uint16_t encap_eth_type; -- int n = -1; -- -- if (ovs_scan_len(s, &n, "push_eth(encap_eth_type=0x%"SCNx16",encap_eth_dst="ETH_ADDR_SCAN_FMT",encap_eth_src="ETH_ADDR_SCAN_FMT")", -- &encap_eth_type, -- ETH_ADDR_SCAN_ARGS(encap_eth->encap_eth_dst), -- ETH_ADDR_SCAN_ARGS(encap_eth->encap_eth_src))) { -- if (encap_eth->encap_eth_type == ETH_P_NSH) { -- push.encap_eth_type = ETH_P_NSH; -- encap_eth->encap_eth_type = htons(ETH_P_NSH); -- nl_msg_put_unspec(actions, OVS_ACTION_ATTR_PUSH_ETH, -- &push, sizeof push); -- } -- -- return n; -- } -- -- } -- -- if (!strncmp(s, "pop_eth", 7)) { -- nl_msg_put_flag(actions, OVS_ACTION_ATTR_POP_ETH); -- return 7; -- } -- -- { - double percentage; - int n = -1; - -@@ -1881,8 +1844,7 @@ static const struct attr_len_tbl ovs_flow_key_attr_lens[OVS_KEY_ATTR_MAX + 1] = - .next = ovs_tun_key_attr_lens, - .next_max = OVS_TUNNEL_KEY_ATTR_MAX }, - [OVS_KEY_ATTR_IN_PORT] = { .len = 4 }, -- [OVS_KEY_ATTR_ENCAP_ETH] = { .len = 14 }, -- [OVS_KEY_ATTR_NSH] = { .len = 24 }, -+ [OVS_KEY_ATTR_NSH] = { .len = sizeof(struct ovs_key_nsh) }, - [OVS_KEY_ATTR_ETHERNET] = { .len = sizeof(struct ovs_key_ethernet) }, - [OVS_KEY_ATTR_VLAN] = { .len = 2 }, - [OVS_KEY_ATTR_ETHERTYPE] = { .len = 2 }, -@@ -2943,6 +2905,9 @@ format_odp_key_attr(const struct nlattr *a, const struct nlattr *ma, - const struct ovs_key_nsh *mask = ma ? nl_attr_get(ma) : NULL; - const struct ovs_key_nsh *key = nl_attr_get(a); - -+ format_eth(ds, "encap_eth_src", key->encap_eth_src, MASK(mask, encap_eth_src), verbose); -+ format_eth(ds, "encap_eth_dst", key->encap_eth_dst, MASK(mask, encap_eth_dst), verbose); -+ format_be16x(ds, "encap_eth_type", key->encap_eth_type, MASK(mask, encap_eth_type), verbose); - format_u8u(ds, "nsi", key->nsi, MASK(mask, nsi), verbose); - format_be32(ds, "nsp", key->nsp, MASK(mask, nsp), verbose); - format_u8u(ds, "nsh_mdtype", key->nsh_mdtype, MASK(mask, nsh_mdtype), verbose); -@@ -2955,18 +2920,6 @@ format_odp_key_attr(const struct nlattr *a, const struct nlattr *ma, - break; - } - -- case OVS_KEY_ATTR_ENCAP_ETH: { -- const struct ovs_key_encap_eth *mask = ma ? nl_attr_get(ma) : NULL; -- const struct ovs_key_encap_eth *key = nl_attr_get(a); -- -- format_be16(ds, "encap_eth_type", key->encap_eth_type, MASK(mask, encap_eth_type), verbose); -- format_eth(ds, "encap_eth_src", key->encap_eth_src, MASK(mask, encap_eth_src), verbose); -- format_eth(ds, "encap_eth_dst", key->encap_eth_dst, MASK(mask, encap_eth_dst), verbose); -- ds_chomp(ds, ','); -- -- break; -- } -- - case OVS_KEY_ATTR_ETHERNET: { - const struct ovs_key_ethernet *mask = ma ? nl_attr_get(ma) : NULL; - const struct ovs_key_ethernet *key = nl_attr_get(a); -@@ -3374,27 +3327,6 @@ scan_nsp(const char *s, uint32_t *key, uint32_t *mask) - } - - static int --scan_encap_eth_type(const char *s, uint16_t *key, uint16_t *mask) --{ -- int n; -- -- if (ovs_scan(s, "%"SCNi16"%n", key, &n)) { -- int len = n; -- *key = htons(*key); -- if (mask) { -- if (ovs_scan(s + len, "/%"SCNi16"%n", mask, &n)) { -- len += n; -- *mask = htons(*mask); -- } else { -- *mask = UINT16_MAX; -- } -- } -- return len; -- } -- return 0; --} -- --static int - scan_ipv4(const char *s, ovs_be32 *key, ovs_be32 *mask) - { - int n; -@@ -4335,6 +4267,9 @@ parse_odp_key_mask_attr(const char *s, const struct simap *port_names, - } SCAN_END_NESTED(); - - SCAN_BEGIN("nsh(", struct ovs_key_nsh) { -+ SCAN_FIELD("encap_eth_dst=", eth, encap_eth_dst); -+ SCAN_FIELD("encap_eth_src=", eth, encap_eth_src); -+ SCAN_FIELD("encap_eth_type=", be16, encap_eth_type); - SCAN_FIELD("nsh_mdtype=", u8, nsh_mdtype); - SCAN_FIELD("nsh_np=", u8, nsh_np); - SCAN_FIELD("nsp=", nsp, nsp); -@@ -4345,12 +4280,6 @@ parse_odp_key_mask_attr(const char *s, const struct simap *port_names, - SCAN_FIELD("nshc4=", u32, nshc4); - } SCAN_END(OVS_KEY_ATTR_NSH); - -- SCAN_BEGIN("encap_eth(", struct ovs_key_encap_eth) { -- SCAN_FIELD("encap_eth_src=", eth, encap_eth_src); -- SCAN_FIELD("encap_eth_dst=", eth, encap_eth_dst); -- SCAN_FIELD("encap_eth_type=", encap_eth_type, encap_eth_type); -- } SCAN_END(OVS_KEY_ATTR_ENCAP_ETH); -- - SCAN_SINGLE_PORT("in_port(", uint32_t, OVS_KEY_ATTR_IN_PORT); - - SCAN_BEGIN("eth(", struct ovs_key_ethernet) { -@@ -4560,19 +4489,15 @@ get_nsh_key(const struct flow *flow, struct ovs_key_nsh *nsh) - nsh->nsp = flow->nsp; - nsh->nsh_mdtype = flow->nsh_mdtype; - nsh->nsh_np = flow->nsh_np; -- nsh->reserved = 0; - nsh->nshc1 = flow->nshc1; - nsh->nshc2 = flow->nshc2; - nsh->nshc3 = flow->nshc3; - nsh->nshc4 = flow->nshc4; --} -- --void --get_encap_eth_key(const struct flow *flow, struct ovs_key_encap_eth *encap_eth) --{ -- encap_eth->encap_eth_type = flow->encap_eth_type; -- encap_eth->encap_eth_src = flow->encap_eth_src; -- encap_eth->encap_eth_dst = flow->encap_eth_dst; -+ nsh->pad2 = 0; -+ nsh->encap_eth_src = flow->encap_eth_src; -+ nsh->encap_eth_dst = flow->encap_eth_dst; -+ nsh->encap_eth_type = flow->encap_eth_type; -+ nsh->pad1 = 0; - } - - static void -@@ -4581,7 +4506,6 @@ odp_flow_key_from_flow__(const struct odp_flow_key_parms *parms, - { - struct ovs_key_ethernet *eth_key; - struct ovs_key_nsh *nsh_key; -- struct ovs_key_encap_eth *encap_eth_key; - size_t encap; - const struct flow *flow = parms->flow; - const struct flow *data = export_mask ? parms->mask : parms->flow; -@@ -4626,12 +4550,6 @@ odp_flow_key_from_flow__(const struct odp_flow_key_parms *parms, - get_nsh_key(data, nsh_key); - } - -- if (flow->encap_eth_type) { -- encap_eth_key = nl_msg_put_unspec_uninit(buf, OVS_KEY_ATTR_ENCAP_ETH, -- sizeof *encap_eth_key); -- get_encap_eth_key(data, encap_eth_key); -- } -- - eth_key = nl_msg_put_unspec_uninit(buf, OVS_KEY_ATTR_ETHERNET, - sizeof *eth_key); - get_ethernet_key(data, eth_key); -@@ -5500,17 +5418,6 @@ odp_flow_key_to_flow__(const struct nlattr *key, size_t key_len, - } - } - -- /* ENCAP Eth header. */ -- if (present_attrs & (UINT64_C(1) << OVS_KEY_ATTR_ENCAP_ETH)) { -- const struct ovs_key_encap_eth *encap_eth_key; -- -- encap_eth_key = nl_attr_get(attrs[OVS_KEY_ATTR_ENCAP_ETH]); -- put_encap_eth_key(encap_eth_key, flow); -- if (is_mask) { -- expected_attrs |= UINT64_C(1) << OVS_KEY_ATTR_ENCAP_ETH; -- } -- } -- - /* Ethernet header. */ - if (present_attrs & (UINT64_C(1) << OVS_KEY_ATTR_ETHERNET)) { - const struct ovs_key_ethernet *eth_key; -@@ -5823,28 +5730,16 @@ put_nsh_key(const struct ovs_key_nsh *nsh, struct flow *flow) - flow->nshc2 = nsh->nshc2; - flow->nshc3 = nsh->nshc3; - flow->nshc4 = nsh->nshc4; -+ flow->encap_eth_src = nsh->encap_eth_src; -+ flow->encap_eth_dst = nsh->encap_eth_dst; -+ flow->encap_eth_type = nsh->encap_eth_type; - } - - void - flow_zero_nsh(struct flow *flow) - { -- void *dst_p = &(flow->nshc1); -- memset(dst_p, 0, 24); --} -- --void --flow_zero_encap_eth(struct flow *flow) --{ -- void *dst_p = &flow->encap_eth_src; -- memset(dst_p, 0, 16); --} -- --void --put_encap_eth_key(const struct ovs_key_encap_eth *encap_eth, struct flow *flow) --{ -- flow->encap_eth_type = encap_eth->encap_eth_type; -- flow->encap_eth_src = encap_eth->encap_eth_src; -- flow->encap_eth_dst = encap_eth->encap_eth_dst; -+ void *dst_p = &(flow->encap_eth_dst); -+ memset(dst_p, 0, 40); - } - - static void -@@ -5899,45 +5794,45 @@ commit_vlan_action(ovs_be16 vlan_tci, struct flow *base, - } - - static void --commit_nsh_pop_action(const struct flow *flow, struct flow *base, -- struct ofpbuf *odp_actions, struct flow_wildcards *wc) -+commit_nsh_pop_action(const struct ovs_key_nsh *flow_key, -+ const struct ovs_key_nsh *base_key, -+ struct ofpbuf *odp_actions, struct flow_wildcards *wc) - { -- struct ovs_key_nsh flow_key, base_key; -- get_nsh_key(flow, &flow_key); -- get_nsh_key(base, &base_key); - -- if (memcmp(&flow_key, &base_key, sizeof flow_key)) { -+ if (memcmp(flow_key, base_key, sizeof (struct ovs_key_nsh))) { - memset(&wc->masks.nsh_mdtype, 0xff, sizeof wc->masks.nsh_mdtype); - -- if (base->nsh_mdtype) { -+ if (base_key->nsh_mdtype) { - nl_msg_put_flag(odp_actions, OVS_ACTION_ATTR_POP_NSH); - } - } - } - - static void --commit_nsh_push_action(const struct flow *flow, struct flow *base, -- struct ofpbuf *odp_actions) -+commit_nsh_push_action(const struct ovs_key_nsh *flow_key, -+ const struct ovs_key_nsh *base_key, -+ struct ofpbuf *odp_actions) - { -- struct ovs_key_nsh flow_key, base_key; -- get_nsh_key(flow, &flow_key); -- get_nsh_key(base, &base_key); -- -- if (memcmp(&flow_key, &base_key, sizeof flow_key)) { -- if (flow->nsh_mdtype) { -+ if (memcmp(flow_key, base_key, sizeof (struct ovs_key_nsh))) { -+ if (flow_key->nsh_mdtype) { - struct ovs_action_push_nsh nsh; -- nsh.nsh_mdtype = flow->nsh_mdtype; -- struct nsh_hdr *nsh_hdr = (struct nsh_hdr *)nsh.header; -- memset(nsh_hdr, 0, sizeof *nsh_hdr); -- nsh_hdr->base.length = 6; -- nsh_hdr->base.proto = flow->nsh_np; -- nsh_hdr->base.mdtype = flow->nsh_mdtype; -- nsh_hdr->base.proto = flow->nsh_np; -- nsh_hdr->base.path_hdr = flow->nsp >> 8 | flow->nsi << 24; -- nsh_hdr->ctx.nshc1 = flow->nshc1; -- nsh_hdr->ctx.nshc2 = flow->nshc2; -- nsh_hdr->ctx.nshc3 = flow->nshc3; -- nsh_hdr->ctx.nshc4 = flow->nshc4; -+ nsh.nsh_mdtype = flow_key->nsh_mdtype; -+ struct eth_nsh_hdr *eth_nsh_header = (struct eth_nsh_hdr *)nsh.header; -+ memset(eth_nsh_header, 0, sizeof *eth_nsh_header); -+ eth_nsh_header->nsh_hdr.base.length = 6; -+ eth_nsh_header->nsh_hdr.base.proto = flow_key->nsh_np; -+ eth_nsh_header->nsh_hdr.base.mdtype = flow_key->nsh_mdtype; -+ eth_nsh_header->nsh_hdr.base.proto = flow_key->nsh_np; -+ eth_nsh_header->nsh_hdr.base.path_hdr = flow_key->nsp >> 8 | flow_key->nsi << 24; -+ eth_nsh_header->nsh_hdr.ctx.nshc1 = flow_key->nshc1; -+ eth_nsh_header->nsh_hdr.ctx.nshc2 = flow_key->nshc2; -+ eth_nsh_header->nsh_hdr.ctx.nshc3 = flow_key->nshc3; -+ eth_nsh_header->nsh_hdr.ctx.nshc4 = flow_key->nshc4; -+ -+ eth_nsh_header->encap_eth_header.encap_eth_type = htons(ETH_P_NSH); -+ eth_nsh_header->encap_eth_header.encap_eth_dst = flow_key->encap_eth_dst; -+ eth_nsh_header->encap_eth_header.encap_eth_src = flow_key->encap_eth_src; -+ - nl_msg_put_unspec(odp_actions, OVS_ACTION_ATTR_PUSH_NSH, - &nsh, sizeof nsh); - } -@@ -5945,46 +5840,16 @@ commit_nsh_push_action(const struct flow *flow, struct flow *base, - } - - static void --commit_encap_eth_pop_action(const struct flow *flow, struct flow *base, -+commit_nsh_action(const struct flow *flow, struct flow *base, - struct ofpbuf *odp_actions, struct flow_wildcards *wc) - { -- struct ovs_key_encap_eth flow_key, base_key; -- get_encap_eth_key(flow, &flow_key); -- get_encap_eth_key(base, &base_key); -- -- if (memcmp(&flow_key, &base_key, sizeof flow_key)) { -- memset(&wc->masks.encap_eth_type, 0xff, sizeof wc->masks.encap_eth_type); -- -- if (base->encap_eth_type) { -- nl_msg_put_flag(odp_actions, OVS_ACTION_ATTR_POP_ETH); -- } -- } -+ struct ovs_key_nsh flow_key, base_key; -+ get_nsh_key(flow, &flow_key); -+ get_nsh_key(base, &base_key); -+ commit_nsh_pop_action(&flow_key, &base_key, odp_actions, wc); -+ commit_nsh_push_action(&flow_key, &base_key, odp_actions); - } - --static void --commit_encap_eth_push_action(const struct flow *flow, struct flow *base, -- struct ofpbuf *odp_actions) --{ -- struct ovs_key_encap_eth flow_key, base_key; -- get_encap_eth_key(flow, &flow_key); -- get_encap_eth_key(base, &base_key); -- -- if (memcmp(&flow_key, &base_key, sizeof flow_key)) { -- if (flow->encap_eth_type) { -- struct ovs_action_push_eth encap_eth; -- encap_eth.encap_eth_type = flow->encap_eth_type; -- struct encap_eth_hdr *encap_eth_header = -- (struct encap_eth_hdr *)encap_eth.header; -- void *dst_p = encap_eth_header->encap_eth_dst.ea; -- void *src_p = encap_eth_header->encap_eth_src.ea; -- memcpy(dst_p, flow->encap_eth_dst.ea, sizeof flow->encap_eth_dst); -- memcpy(src_p, flow->encap_eth_src.ea, sizeof flow->encap_eth_src); -- encap_eth_header->encap_eth_type = htons(ETH_P_NSH); -- nl_msg_put_unspec(odp_actions, OVS_ACTION_ATTR_PUSH_ETH, -- &encap_eth, sizeof encap_eth); -- } -- } --} - - /* Wildcarding already done at action translation time. */ - static void -@@ -6417,10 +6282,7 @@ commit_odp_actions(const struct flow *flow, struct flow *base, - slow2 = commit_set_icmp_action(flow, base, odp_actions, wc); - commit_mpls_action(flow, base, odp_actions); - commit_vlan_action(flow->vlan_tci, base, odp_actions, wc); -- commit_encap_eth_pop_action(flow, base, odp_actions, wc); -- commit_nsh_pop_action(flow, base, odp_actions, wc); -- commit_nsh_push_action(flow, base, odp_actions); -- commit_encap_eth_push_action(flow, base, odp_actions); -+ commit_nsh_action(flow, base, odp_actions, wc); - commit_set_priority_action(flow, base, odp_actions, wc, use_masked); - commit_set_pkt_mark_action(flow, base, odp_actions, wc, use_masked); - -diff --git a/lib/odp-util.h b/lib/odp-util.h -index 2cb04f1..26e036f 100644 ---- a/lib/odp-util.h -+++ b/lib/odp-util.h -@@ -126,8 +126,7 @@ void odp_portno_names_destroy(struct hmap *portno_names); - * OVS_KEY_ATTR_CT_ZONE 2 2 4 8 - * OVS_KEY_ATTR_CT_MARK 4 -- 4 8 - * OVS_KEY_ATTR_CT_LABEL 16 -- 4 20 -- * OVS_KEY_ATTR_NSH 24 -- 4 28 -- * OVS_KEY_ATTR_ENCAP 14 -- 4 18 -+ * OVS_KEY_ATTR_NSH 40 -- 4 44 - * OVS_KEY_ATTR_ETHERNET 12 -- 4 16 - * OVS_KEY_ATTR_ETHERTYPE 2 2 4 8 (outer VLAN ethertype) - * OVS_KEY_ATTR_VLAN 2 2 4 8 -@@ -154,10 +153,7 @@ struct odputil_keybuf { - - void put_nsh_key(const struct ovs_key_nsh *, struct flow *); - void get_nsh_key(const struct flow *flow, struct ovs_key_nsh *nsh); --void put_encap_eth_key(const struct ovs_key_encap_eth *encap_eth, struct flow *flow); --void get_encap_eth_key(const struct flow *flow, struct ovs_key_encap_eth *encap_eth); - void flow_zero_nsh(struct flow *); --void flow_zero_encap_eth(struct flow *); - enum odp_key_fitness odp_tun_key_from_attr(const struct nlattr *, bool udpif, - struct flow_tnl *); - -diff --git a/lib/ofp-actions.c b/lib/ofp-actions.c -index f4062b2..8cce6c9 100644 ---- a/lib/ofp-actions.c -+++ b/lib/ofp-actions.c -@@ -305,12 +305,6 @@ enum ofp_raw_action_type { - /* NX1.0+(39): void. */ - NXAST_RAW_POP_NSH, - -- /* NX1.0+(40): void. */ -- NXAST_RAW_PUSH_ETH, -- -- /* NX1.0+(41): void. */ -- NXAST_RAW_POP_ETH, -- - /* ## ------------------ ## */ - /* ## Debugging actions. ## */ - /* ## ------------------ ## */ -@@ -397,6 +391,8 @@ ofpact_next_flattened(const struct ofpact *ofpact) - case OFPACT_SET_VLAN_PCP: - case OFPACT_STRIP_VLAN: - case OFPACT_PUSH_VLAN: -+ case OFPACT_PUSH_NSH: -+ case OFPACT_POP_NSH: - case OFPACT_SET_ETH_SRC: - case OFPACT_SET_ETH_DST: - case OFPACT_SET_IPV4_SRC: -@@ -1697,66 +1693,6 @@ format_POP_NSH(const struct ofpact_null *a OVS_UNUSED, struct ds *s) - ds_put_format(s, "pop_nsh"); - } - --/* Push ENCAP Eth header actions. */ --static enum ofperr --decode_NXAST_RAW_PUSH_ETH(struct ofpbuf * out) --{ -- ofpact_put_PUSH_ETH(out)->ofpact.raw = NXAST_RAW_PUSH_ETH; -- -- return 0; --} -- --static void --encode_PUSH_ETH(const struct ofpact_null *null OVS_UNUSED, -- enum ofp_version ofp_version OVS_UNUSED, struct ofpbuf *out) --{ -- put_NXAST_PUSH_ETH(out); --} -- --static char * OVS_WARN_UNUSED_RESULT --parse_PUSH_ETH(char *arg OVS_UNUSED, struct ofpbuf *ofpacts, -- enum ofputil_protocol *usable_protocols OVS_UNUSED) --{ -- ofpact_put_PUSH_ETH(ofpacts)->ofpact.raw = NXAST_RAW_PUSH_ETH;; -- return NULL; --} -- --static void --format_PUSH_ETH(const struct ofpact_null *a OVS_UNUSED, struct ds *s) --{ -- ds_put_format(s, "push_eth"); --} -- --/* Pop ENCAP ETH header actions. */ --static enum ofperr --decode_NXAST_RAW_POP_ETH(struct ofpbuf * out) --{ -- ofpact_put_POP_ETH(out)->ofpact.raw = NXAST_RAW_POP_ETH; -- -- return 0; --} -- --static void --encode_POP_ETH(const struct ofpact_null *null OVS_UNUSED, -- enum ofp_version ofp_version OVS_UNUSED, struct ofpbuf *out) --{ -- put_NXAST_POP_ETH(out); --} -- --static char * OVS_WARN_UNUSED_RESULT --parse_POP_ETH(char *arg OVS_UNUSED, struct ofpbuf *ofpacts, -- enum ofputil_protocol *usable_protocols OVS_UNUSED) --{ -- ofpact_put_POP_ETH(ofpacts)->ofpact.raw = NXAST_RAW_POP_ETH; -- return NULL; --} -- --static void --format_POP_ETH(const struct ofpact_null *a OVS_UNUSED, struct ds *s) --{ -- ds_put_format(s, "pop_eth"); --} -- - /* Action structure for OFPAT10_SET_DL_SRC/DST and OFPAT11_SET_DL_SRC/DST. */ - struct ofp_action_dl_addr { - ovs_be16 type; /* Type. */ -@@ -6044,8 +5980,6 @@ ofpact_is_set_or_move_action(const struct ofpact *a) - case OFPACT_PUSH_VLAN: - case OFPACT_PUSH_NSH: - case OFPACT_POP_NSH: -- case OFPACT_PUSH_ETH: -- case OFPACT_POP_ETH: - case OFPACT_RESUBMIT: - case OFPACT_SAMPLE: - case OFPACT_STACK_POP: -@@ -6075,8 +6009,6 @@ ofpact_is_allowed_in_actions_set(const struct ofpact *a) - case OFPACT_PUSH_VLAN: - case OFPACT_PUSH_NSH: - case OFPACT_POP_NSH: -- case OFPACT_PUSH_ETH: -- case OFPACT_POP_ETH: - case OFPACT_REG_MOVE: - case OFPACT_SET_FIELD: - case OFPACT_SET_ETH_DST: -@@ -6304,8 +6236,6 @@ ovs_instruction_type_from_ofpact_type(enum ofpact_type type) - case OFPACT_PUSH_VLAN: - case OFPACT_PUSH_NSH: - case OFPACT_POP_NSH: -- case OFPACT_PUSH_ETH: -- case OFPACT_POP_ETH: - case OFPACT_SET_ETH_SRC: - case OFPACT_SET_ETH_DST: - case OFPACT_SET_IPV4_SRC: -@@ -6775,6 +6705,8 @@ ofpact_check__(enum ofputil_protocol *usable_protocols, struct ofpact *a, - flow->vlan_tci |= htons(VLAN_CFI); - return 0; - -+ case OFPACT_PUSH_NSH: -+ case OFPACT_POP_NSH: - case OFPACT_SET_ETH_SRC: - case OFPACT_SET_ETH_DST: - return 0; -@@ -6853,10 +6785,6 @@ ofpact_check__(enum ofputil_protocol *usable_protocols, struct ofpact *a, - case OFPACT_SET_TUNNEL: - case OFPACT_SET_QUEUE: - case OFPACT_POP_QUEUE: -- case OFPACT_PUSH_NSH: -- case OFPACT_POP_NSH: -- case OFPACT_PUSH_ETH: -- case OFPACT_POP_ETH: - case OFPACT_RESUBMIT: - return 0; - -@@ -7416,8 +7344,6 @@ ofpact_outputs_to_port(const struct ofpact *ofpact, ofp_port_t port) - case OFPACT_PUSH_VLAN: - case OFPACT_PUSH_NSH: - case OFPACT_POP_NSH: -- case OFPACT_PUSH_ETH: -- case OFPACT_POP_ETH: - case OFPACT_SET_ETH_SRC: - case OFPACT_SET_ETH_DST: - case OFPACT_SET_IPV4_SRC: -diff --git a/lib/ofp-actions.h b/lib/ofp-actions.h -index 3897c0b..e212f87 100644 ---- a/lib/ofp-actions.h -+++ b/lib/ofp-actions.h -@@ -96,8 +96,6 @@ - /* NSH */ \ - OFPACT(PUSH_NSH, ofpact_null, ofpact, "push_nsh") \ - OFPACT(POP_NSH, ofpact_null, ofpact, "pop_nsh") \ -- OFPACT(PUSH_ETH, ofpact_null, ofpact, "push_eth") \ -- OFPACT(POP_ETH, ofpact_null, ofpact, "pop_eth") \ - \ - /* Flow table interaction. */ \ - OFPACT(RESUBMIT, ofpact_resubmit, ofpact, "resubmit") \ -diff --git a/lib/packets.c b/lib/packets.c -index d0c0e68..d314b2d 100644 ---- a/lib/packets.c -+++ b/lib/packets.c -@@ -242,6 +242,29 @@ set_ethertype(struct dp_packet *packet, ovs_be16 eth_type) - } - } - -+void -+push_nsh(struct dp_packet *packet, const void *nsh) -+{ -+ void *header; -+ const struct ovs_action_push_nsh *push_nsh_hdr = (const struct ovs_action_push_nsh *)nsh; -+ const uint8_t *pdata = push_nsh_hdr->header; -+ /* Now only support MD type1 */ -+ if (push_nsh_hdr->nsh_mdtype != NSH_M_TYPE1) -+ return; -+ header = dp_packet_push_uninit(packet, ETH_NSH_TYPE1_HEADER_SIZE); -+ -+ memcpy(header, pdata, ETH_NSH_TYPE1_HEADER_SIZE); -+} -+ -+void -+pop_nsh(struct dp_packet *packet) -+{ -+ if (ETH_NSH_TYPE1_HEADER_SIZE > dp_packet_size(packet)) { -+ return; -+ } -+ dp_packet_reset_packet(packet, ETH_NSH_TYPE1_HEADER_SIZE); -+} -+ - static bool is_mpls(struct dp_packet *packet) - { - return packet->l2_5_ofs != UINT16_MAX; -diff --git a/lib/packets.h b/lib/packets.h -index dc97333..057efab 100644 ---- a/lib/packets.h -+++ b/lib/packets.h -@@ -313,6 +313,9 @@ void compose_rarp(struct dp_packet *, const struct eth_addr); - void eth_push_vlan(struct dp_packet *, ovs_be16 tpid, ovs_be16 tci); - void eth_pop_vlan(struct dp_packet *); - -+void push_nsh(struct dp_packet *packet, const void *nsh); -+void pop_nsh(struct dp_packet *packet); -+ - const char *eth_from_hex(const char *hex, struct dp_packet **packetp); - void eth_format_masked(const struct eth_addr ea, - const struct eth_addr *mask, struct ds *s); -diff --git a/ofproto/ofproto-dpif-sflow.c b/ofproto/ofproto-dpif-sflow.c -index e15e8d2..511e20a 100644 ---- a/ofproto/ofproto-dpif-sflow.c -+++ b/ofproto/ofproto-dpif-sflow.c -@@ -977,7 +977,6 @@ sflow_read_set_action(const struct nlattr *attr, - case OVS_KEY_ATTR_ETHERNET: - case OVS_KEY_ATTR_VLAN: - case OVS_KEY_ATTR_NSH: -- case OVS_KEY_ATTR_ENCAP_ETH: - break; - - case OVS_KEY_ATTR_MPLS: { -diff --git a/ofproto/ofproto-dpif-upcall.c b/ofproto/ofproto-dpif-upcall.c -index f59eed8..ec19739 100644 ---- a/ofproto/ofproto-dpif-upcall.c -+++ b/ofproto/ofproto-dpif-upcall.c -@@ -748,7 +748,6 @@ recv_upcalls(struct handler *handler) - struct flow *flow = &flows[n_upcalls]; - unsigned int mru; - struct ovs_key_nsh reserve_nsh; -- struct ovs_key_encap_eth reserve_encap_eth; - bool nsh_mdtype_flag, encap_eth_type_flag; - int error; - -@@ -802,21 +801,14 @@ recv_upcalls(struct handler *handler) - pkt_metadata_from_flow(&dupcall->packet.md, flow); - - nsh_mdtype_flag = !!(flow->nsh_mdtype); -- encap_eth_type_flag = !!(flow->encap_eth_type); - if(nsh_mdtype_flag) - get_nsh_key(flow, &reserve_nsh); - -- if(encap_eth_type_flag) -- get_encap_eth_key(flow, &reserve_encap_eth); -- - flow_extract(&dupcall->packet, flow); - - if(nsh_mdtype_flag) - put_nsh_key(&reserve_nsh, flow); - -- if(encap_eth_type_flag) -- put_encap_eth_key(&reserve_encap_eth, flow); -- - error = process_upcall(udpif, upcall, - &upcall->odp_actions, &upcall->wc); - if (error) { -diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c -index 4f91d0a..221c17d 100644 ---- a/ofproto/ofproto-dpif-xlate.c -+++ b/ofproto/ofproto-dpif-xlate.c -@@ -4242,8 +4242,6 @@ freeze_unroll_actions(const struct ofpact *a, const struct ofpact *end, - case OFPACT_PUSH_VLAN: - case OFPACT_PUSH_NSH: - case OFPACT_POP_NSH: -- case OFPACT_PUSH_ETH: -- case OFPACT_POP_ETH: - case OFPACT_SET_ETH_SRC: - case OFPACT_SET_ETH_DST: - case OFPACT_SET_IPV4_SRC: -@@ -4530,6 +4528,8 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len, - - case OFPACT_PUSH_NSH: - memset(&wc->masks.nsh_mdtype, 0xff, sizeof wc->masks.nsh_mdtype); -+ flow->encap_eth_dst = flow->dl_dst; -+ flow->encap_eth_src = flow->dl_src; - break; - - case OFPACT_POP_NSH: -@@ -4537,15 +4537,6 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len, - flow_zero_nsh(flow); - break; - -- case OFPACT_PUSH_ETH: -- memset(&wc->masks.encap_eth_type, 0xff, sizeof wc->masks.encap_eth_type); -- break; -- -- case OFPACT_POP_ETH: -- memset(&wc->masks.encap_eth_type, 0xff, sizeof wc->masks.encap_eth_type); -- flow_zero_encap_eth(flow); -- break; -- - case OFPACT_STRIP_VLAN: - memset(&wc->masks.vlan_tci, 0xff, sizeof wc->masks.vlan_tci); - flow->vlan_tci = htons(0); -diff --git a/ofproto/ofproto-dpif.h b/ofproto/ofproto-dpif.h -index 0064178..aee8ff5 100644 ---- a/ofproto/ofproto-dpif.h -+++ b/ofproto/ofproto-dpif.h -@@ -93,7 +93,6 @@ struct dpif_backer_support { - /* Each member represents support for related OVS_KEY_ATTR_* fields. */ - struct odp_support odp; - }; -- - bool ofproto_dpif_get_enable_ufid(const struct dpif_backer *backer); - struct dpif_backer_support *ofproto_dpif_get_support(const struct ofproto_dpif *); - -diff --git a/ofproto/tunnel.c b/ofproto/tunnel.c -index 7430994..bc92b40 100644 ---- a/ofproto/tunnel.c -+++ b/ofproto/tunnel.c -@@ -704,6 +704,7 @@ tnl_port_build_header(const struct ofport_dpif *ofport, - - /* Build Ethernet and IP headers. */ - memset(data->header, 0, sizeof data->header); -+ data->exts = 0; - - eth = (struct eth_header *)data->header; - eth->eth_dst = dmac; -diff --git a/tests/ofproto.at b/tests/ofproto.at -index 7141e39..98f4872 100644 ---- a/tests/ofproto.at -+++ b/tests/ofproto.at -@@ -1927,7 +1927,6 @@ metadata in_port in_port_oxm pkt_mark ct_mark ct_label reg0 reg1 reg2 reg3 reg4 - nsh_np: arbitrary mask - encap_eth_src: arbitrary mask - encap_eth_dst: arbitrary mask -- encap_eth_type: exact match or wildcard - - ' $1 - } -diff --git a/tests/tunnel.at b/tests/tunnel.at -index d957574..7162ef0 100644 ---- a/tests/tunnel.at -+++ b/tests/tunnel.at -@@ -427,6 +427,14 @@ in_port=1 actions=push_nsh,set_field:1->nsh_mdtype,set_field:0x3->nsh_np,set_fie - in_port=2 actions=push_nsh,set_field:1->nsh_mdtype,set_field:0x3->nsh_np,set_field:0x112233->nsp,set_field:0x44->nsi,set_field:0x11223344->nshc1,set_field:0x55667788->nshc2,set_field:0x99aabbcc->nshc3,set_field:0xddeeff00->nshc4,set_field:4->tun_gpe_np,output:2 - ]) - AT_CHECK([ovs-ofctl add-flows br0 flows.txt]) -+ -+AT_CHECK([ovs-appctl dpif/show | tail -n +3], [0], [dnl -+ br0 65534/100: (dummy) -+ p1 1/1: (dummy) -+ p2 2/4790: (vxlan: dst_port=4790, key=flow, remote_ip=1.1.1.1) -+ p90 90/90: (dummy) -+]) -+ - AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(90),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=1,tos=0,ttl=128,frag=no),icmp(type=8,code=0)'], [0], [stdout]) - AT_CHECK([tail -1 stdout], [0], - [Datapath actions: push_nsh(nsh_mdtype=1,nsh_np=3,nsp=1122867,nsi=1140850688,nshc1=287454020,nshc2=1432778632,nshc3=2578103244,nshc4=3723427584),1,set(tunnel(tun_id=0x0,dst=1.1.1.1,ttl=64,vxlan(gpe(np=0x4,flags=0)),flags(df|key))),push_nsh(nsh_mdtype=1,nsh_np=3,nsp=1122867,nsi=1140850688,nshc1=287454020,nshc2=1432778632,nshc3=2578103244,nshc4=3723427584),4790 -@@ -496,12 +504,6 @@ priority=200,in_port=2,nsh_mdtype=1,nsh_np=3,nsi=0x44,nsp=0x112233,encap_eth_typ - - AT_CHECK([ovs-ofctl add-flows br0 flows.txt]) - --AT_CHECK([ovs-appctl dpif/show | tail -n +3], [0], [dnl -- br0 65534/100: (dummy) -- p1 1/1: (dummy) -- p2 2/2: (dummy) --]) -- - AT_CHECK([ovs-appctl ofproto/trace ovs-dummy ',in_port(2),encap_eth(encap_eth_type=0x894f,encap_eth_dst=00:11:22:33:44:55,encap_eth_src=00:66:77:88:99:aa),nsh(nsh_mdtype=1,nsh_np=3,nsp=0x112233,nsi=0x44,nshc1=0x11223344,nshc2=0x55667788,nshc3=0x99aabbcc,nshc4=0xddeeff00),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no),tcp(src=8,dst=9)'], [0], [stdout]) - AT_CHECK([tail -1 stdout], [0], - [Datapath actions: pop_eth,pop_nsh,1 -@@ -525,12 +527,6 @@ priority=200,in_port=2,tun_gpe_np=4,nsh_mdtype=1,nsh_np=3,nsi=0x44,nsp=0x112233, - - AT_CHECK([ovs-ofctl add-flows br0 flows.txt]) - --AT_CHECK([ovs-appctl dpif/show | tail -n +3], [0], [dnl -- br0 65534/100: (dummy) -- p1 1/1: (dummy) -- p2 2/4790: (vxlan: dst_port=4790, key=flow, remote_ip=1.1.1.1) --]) -- - AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'tunnel(src=1.1.1.1,dst=1.2.3.4,ttl=64,flags(),vxlan(gpe(np=4,flags=0x0c))),in_port(4790),nsh(nsh_mdtype=1,nsh_np=3,nsp=0x112233,nsi=0x44,nshc1=0x11223344,nshc2=0x55667788,nshc3=0x99aabbcc,nshc4=0xddeeff00),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no),tcp(src=8,dst=9)'], [0], [stdout]) - AT_CHECK([tail -1 stdout], [0], - [Datapath actions: push_eth(encap_eth_type=35151,encap_eth_src=00:66:77:88:99:aa,encap_eth_dst=00:11:22:33:44:55,),1 -@@ -553,21 +549,184 @@ priority=200,in_port=1,nsh_mdtype=1,nsh_np=3,nsi=0x44,nsp=0x112233,encap_eth_typ - - AT_CHECK([ovs-ofctl add-flows br0 flows.txt]) - -+AT_CHECK([ovs-appctl ofproto/trace ovs-dummy ',in_port(1),encap_eth(encap_eth_type=0x894f,encap_eth_dst=00:11:22:33:44:55,encap_eth_src=00:66:77:88:99:aa),,nsh(nsh_mdtype=1,nsh_np=3,nsp=0x112233,nsi=0x44,nshc1=0x11223344,nshc2=0x55667788,nshc3=0x99aabbcc,nshc4=0xddeeff00),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no),tcp(src=8,dst=9)'], [0], [stdout]) -+AT_CHECK([tail -1 stdout], [0], -+ [Datapath actions: set(tunnel(tun_id=0x0,dst=1.1.1.1,ttl=64,vxlan(gpe(np=0x4,flags=0)),flags(df|key))),pop_eth,4790 -+]) -+ -+OVS_VSWITCHD_STOP -+AT_CLEANUP -+ -+AT_SETUP([tunnel - VXLAN-GPE and NSH - Encapsulation - user space]) -+OVS_VSWITCHD_START([dnl -+ add-port br0 p1 -- set Interface p1 type=dummy ofport_request=1 \ -+ -- add-port br0 p2 -- set Interface p2 type=vxlan options:key=flow \ -+ options:remote_ip=1.1.1.1 options:dst_port=4790 ofport_request=2 \ -+ options:exts=gpe]) -+ -+ADD_OF_PORTS([br0], [90]) -+ -+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 00:11:11:11:11:11 -+],[0],[stdout]) -+ -+AT_DATA([flows.txt], [dnl -+in_port=90 actions=resubmit:1,resubmit:2 -+in_port=1 actions=push_nsh,set_field:1->nsh_mdtype,set_field:0x3->nsh_np,set_field:0x112233->nsp,set_field:0x44->nsi,set_field:0x11223344->nshc1,set_field:0x55667788->nshc2,set_field:0x99aabbcc->nshc3,set_field:0xddeeff00->nshc4,output:1 -+in_port=2 actions=push_nsh,set_field:1->nsh_mdtype,set_field:0x3->nsh_np,set_field:0x112233->nsp,set_field:0x44->nsi,set_field:0x11223344->nshc1,set_field:0x55667788->nshc2,set_field:0x99aabbcc->nshc3,set_field:0xddeeff00->nshc4,set_field:4->tun_gpe_np,output:2 -+]) -+AT_CHECK([ovs-ofctl add-flows br0 flows.txt]) -+AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(90),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=1,tos=0,ttl=128,frag=no),icmp(type=8,code=0)'], [0], [stdout]) -+AT_CHECK([tail -1 stdout], [0], -+ [Datapath actions: push_nsh(encap_eth_src=00:00:00:00:00:00,encap_eth_dst=00:00:00:00:00:00,nsh_mdtype=1,nsh_np=3,nsp=1122867,nsi=1140850688,nshc1=287454020,nshc2=1432778632,nshc3=2578103244,nshc4=3723427584),1,push_nsh(encap_eth_src=00:00:00:00:00:00,encap_eth_dst=00:00:00:00:00:00,nsh_mdtype=1,nsh_np=3,nsp=1122867,nsi=1140850688,nshc1=287454020,nshc2=1432778632,nshc3=2578103244,nshc4=3723427584),tnl_push(tnl_port(4790),header(size=50,type=4,eth(dst=00:11:11:11:11:11,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=0xc000004,vni=0x0)),out_port(100)) -+]) -+ -+OVS_VSWITCHD_STOP -+AT_CLEANUP -+ -+AT_SETUP([tunnel - VXLAN-GPE and NSH - Decapsulation - user space]) -+OVS_VSWITCHD_START([dnl -+ add-port br0 p1 -- set Interface p1 type=dummy ofport_request=1 \ -+ -- add-port br0 p2 -- set Interface p2 type=vxlan options:key=flow \ -+ options:remote_ip=1.1.1.1 options:dst_port=4790 ofport_request=2 \ -+ options:exts=gpe]) -+ -+AT_DATA([flows.txt], [dnl -+priority=200,in_port=2,tun_gpe_np=4,nsh_mdtype=1,nsh_np=3,nsi=0x44,nsp=0x112233,actions=pop_nsh,output=1 -+priority=100,in_port=1,actions=local -+]) -+ -+AT_CHECK([ovs-ofctl add-flows br0 flows.txt]) -+ -+AT_CHECK([ovs-appctl netdev-dummy/ip4addr br0 1.1.1.2/24], [0], [OK -+]) -+ -+AT_CHECK([ovs-appctl ovs/route/add 1.1.1.1/24 br0], [0], [OK -+]) -+ -+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=1.1.1.2,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 'tunnel(src=1.1.1.1,dst=1.2.3.4,ttl=64,flags(),vxlan(gpe(np=4,flags=0x0c))),in_port(4790),nsh(nsh_mdtype=1,nsh_np=3,nsp=0x112233,nsi=0x44,nshc1=0x11223344,nshc2=0x55667788,nshc3=0x99aabbcc,nshc4=0xddeeff00),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no),tcp(src=8,dst=9)'], [0], [stdout]) -+AT_CHECK([tail -1 stdout], [0], -+ [Datapath actions: pop_nsh,1 -+]) -+ -+OVS_VSWITCHD_STOP -+AT_CLEANUP -+ -+AT_SETUP([Eth and NSH - Encapsulation - user space]) -+OVS_VSWITCHD_START([dnl -+ add-port br0 p1 -- set Interface p1 type=dummy ofport_request=1 \ -+ -- add-port br0 p2 -- set Interface p2 type=dummy ofport_request=2]) -+ -+ADD_OF_PORTS([br0], [90]) -+AT_DATA([flows.txt], [dnl -+in_port=90 actions=resubmit:1,resubmit:2 -+in_port=1 actions=push_nsh,set_field:1->nsh_mdtype,set_field:0x3->nsh_np,set_field:0x112233->nsp,set_field:0x44->nsi,set_field:0x11223344->nshc1,set_field:0x55667788->nshc2,set_field:0x99aabbcc->nshc3,set_field:00:11:22:33:44:55->encap_eth_dst,set_field:00:66:77:88:99:aa->encap_eth_src,output:1 -+]) -+AT_CHECK([ovs-ofctl add-flows br0 flows.txt]) -+AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(90),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=1,tos=0,ttl=128,frag=no),icmp(type=8,code=0)'], [0], [stdout]) -+AT_CHECK([tail -1 stdout], [0], -+[Datapath actions: push_nsh(encap_eth_src=00:66:77:88:99:aa,encap_eth_dst=00:11:22:33:44:55,nsh_mdtype=1,nsh_np=3,nsp=1122867,nsi=1140850688,nshc1=287454020,nshc2=1432778632,nshc3=2578103244,nshc4=0),1 -+]) -+ -+OVS_VSWITCHD_STOP -+AT_CLEANUP -+ -+AT_SETUP([Eth and NSH - Decapsulation - user space]) -+OVS_VSWITCHD_START([dnl -+ add-port br0 p1 -- set Interface p1 type=dummy ofport_request=1 \ -+ -- add-port br0 p2 -- set Interface p2 type=dummy ofport_request=2]) -+ -+AT_DATA([flows.txt], [dnl -+priority=200,in_port=2,nsh_mdtype=1,nsh_np=3,nsi=0x44,nsp=0x112233,encap_eth_dst=00:11:22:33:44:55,encap_eth_src=00:66:77:88:99:aa,actions=pop_nsh,output=1 -+]) -+ -+AT_CHECK([ovs-ofctl add-flows br0 flows.txt]) -+ - AT_CHECK([ovs-appctl dpif/show | tail -n +3], [0], [dnl - br0 65534/100: (dummy) - p1 1/1: (dummy) -- p2 2/4790: (vxlan: dst_port=4790, key=flow, remote_ip=1.1.1.1) -+ p2 2/2: (dummy) - ]) - --AT_CHECK([ovs-appctl ofproto/trace ovs-dummy ',in_port(1),encap_eth(encap_eth_type=0x894f,encap_eth_dst=00:11:22:33:44:55,encap_eth_src=00:66:77:88:99:aa),,nsh(nsh_mdtype=1,nsh_np=3,nsp=0x112233,nsi=0x44,nshc1=0x11223344,nshc2=0x55667788,nshc3=0x99aabbcc,nshc4=0xddeeff00),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no),tcp(src=8,dst=9)'], [0], [stdout]) -+AT_CHECK([ovs-appctl ofproto/trace ovs-dummy ',in_port(2),nsh(encap_eth_dst=00:11:22:33:44:55,encap_eth_src=00:66:77:88:99:aa,nsh_mdtype=1,nsh_np=3,nsp=0x112233,nsi=0x44,nshc1=0x11223344,nshc2=0x55667788,nshc3=0x99aabbcc,nshc4=0xddeeff00),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no),tcp(src=8,dst=9)'], [0], [stdout]) - AT_CHECK([tail -1 stdout], [0], -- [Datapath actions: set(tunnel(tun_id=0x0,dst=1.1.1.1,ttl=64,vxlan(gpe(np=0x4,flags=0)),flags(df|key))),pop_eth,4790 -+ [Datapath actions: pop_nsh,1 -+]) -+ -+OVS_VSWITCHD_STOP -+AT_CLEANUP -+ -+AT_SETUP([VXLANGPE+NSH to Eth+NSH - user space]) -+OVS_VSWITCHD_START([dnl -+ add-port br0 p1 -- set Interface p1 type=dummy ofport_request=1 \ -+ -- add-port br0 p2 -- set Interface p2 type=dummy ofport_request=2 \ -+ -- add-port br0 p3 -- set Interface p3 type=vxlan options:key=flow \ -+ options:remote_ip=1.1.1.1 options:dst_port=4790 ofport_request=3 \ -+ options:exts=gpe]) -+ -+AT_DATA([flows.txt], [dnl -+priority=200,in_port=3,tun_gpe_np=4,nsh_mdtype=1,nsh_np=3,nsi=0x44,nsp=0x112233,actions=set_field:00:11:22:33:44:55->encap_eth_dst,set_field:00:66:77:88:99:aa->encap_eth_src,output:2 -+priority=100,in_port=1,actions=local -+]) -+ -+AT_CHECK([ovs-ofctl add-flows br0 flows.txt]) -+ -+AT_CHECK([ovs-appctl netdev-dummy/ip4addr br0 1.1.1.2/24], [0], [OK -+]) -+ -+AT_CHECK([ovs-appctl ovs/route/add 1.1.1.1/24 br0], [0], [OK -+]) -+ -+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=1.1.1.2,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 'tunnel(src=1.1.1.1,dst=1.2.3.4,ttl=64,flags(),vxlan(gpe(np=4,flags=0x0c))),in_port(4790),nsh(nsh_mdtype=1,nsh_np=3,nsp=0x112233,nsi=0x44,nshc1=0x11223344,nshc2=0x55667788,nshc3=0x99aabbcc,nshc4=0xddeeff00),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no),tcp(src=8,dst=9)'], [0], [stdout]) -+AT_CHECK([tail -1 stdout], [0], -+ [Datapath actions: pop_nsh,push_nsh(encap_eth_src=00:66:77:88:99:aa,encap_eth_dst=00:11:22:33:44:55,nsh_mdtype=1,nsh_np=3,nsp=1122867,nsi=1140850688,nshc1=1144201745,nshc2=2289526357,nshc3=3434850969,nshc4=16772829),2 - ]) - - OVS_VSWITCHD_STOP - AT_CLEANUP - -+AT_SETUP([Eth+NSH to VXLANGPE+NSH - user space]) -+OVS_VSWITCHD_START([dnl -+ add-port br0 p1 -- set Interface p1 type=dummy ofport_request=1 \ -+ -- add-port br0 p2 -- set Interface p2 type=vxlan options:key=flow \ -+ options:remote_ip=1.1.1.1 options:dst_port=4790 ofport_request=2 \ -+ options:exts=gpe]) -+ -+AT_CHECK([ovs-appctl netdev-dummy/ip4addr br0 1.1.1.2/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 00:11:11:11:11:11 -+],[0],[stdout]) -+ -+AT_DATA([flows.txt], [dnl -+priority=200,in_port=1,nsh_mdtype=1,nsh_np=3,nsi=0x44,nsp=0x112233,encap_eth_dst=00:11:22:33:44:55,encap_eth_src=00:66:77:88:99:aa,actions=set_field:0x4->tun_gpe_np,output=2 -+]) - -+AT_CHECK([ovs-ofctl add-flows br0 flows.txt]) -+ -+ -+AT_CHECK([ovs-appctl ofproto/trace ovs-dummy ',in_port(1),nsh(encap_eth_dst=00:11:22:33:44:55,encap_eth_src=00:66:77:88:99:aa,nsh_mdtype=1,nsh_np=3,nsp=0x112233,nsi=0x44,nshc1=0x11223344,nshc2=0x55667788,nshc3=0x99aabbcc,nshc4=0xddeeff00),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no),tcp(src=8,dst=9)'], [0], [stdout]) -+ -+AT_CHECK([tail -1 stdout], [0], -+ [Datapath actions: tnl_push(tnl_port(4790),header(size=50,type=4,eth(dst=00:11:11:11:11:11,src=aa:55:aa:55:00:00,dl_type=0x0800),ipv4(src=1.1.1.2,dst=1.1.1.1,proto=17,tos=0,ttl=64,frag=0x40),udp(src=0,dst=4790,csum=0x0),vxlan(flags=0xc000004,vni=0x0)),out_port(100)) -+]) -+ -+OVS_VSWITCHD_STOP -+AT_CLEANUP - - AT_SETUP([tunnel - Geneve metadata]) - OVS_VSWITCHD_START([add-port br0 p1 -- set Interface p1 type=geneve \ --- -1.9.3 - diff --git a/ovs_build/patches/0005-Ethernet-header-must-be-kept-in-VxLAN-gpe-eth-NSH-fo.patch b/ovs_build/patches/0005-Ethernet-header-must-be-kept-in-VxLAN-gpe-eth-NSH-fo.patch deleted file mode 100644 index 80c5628..0000000 --- a/ovs_build/patches/0005-Ethernet-header-must-be-kept-in-VxLAN-gpe-eth-NSH-fo.patch +++ /dev/null @@ -1,74 +0,0 @@ -From 604bcfaf5211513f665ca05a370bc7f0c0dab39f Mon Sep 17 00:00:00 2001 -From: Yi Yang -Date: Fri, 15 Apr 2016 14:17:54 +0800 -Subject: [PATCH 5/6] Ethernet header must be kept in VxLAN-gpe + eth + NSH for - new ovs lwtunnel implementation - -Signed-off-by: Yi Yang ---- - datapath/linux/compat/vxlan.c | 16 ++++++++++------ - 1 file changed, 10 insertions(+), 6 deletions(-) - -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)); - --- -1.9.3 - diff --git a/ovs_build/patches/0006-Fix-VxLAN-gpe-Eth-NSH-issues.patch b/ovs_build/patches/0006-Fix-VxLAN-gpe-Eth-NSH-issues.patch deleted file mode 100644 index d7d9365..0000000 --- a/ovs_build/patches/0006-Fix-VxLAN-gpe-Eth-NSH-issues.patch +++ /dev/null @@ -1,82 +0,0 @@ -From 16982ccaf9249550d01d1ef5d298f97ee6537eb0 Mon Sep 17 00:00:00 2001 -From: Yi Yang -Date: Wed, 27 Apr 2016 14:50:29 +0800 -Subject: [PATCH 6/6] Fix VxLAN-gpe + Eth + NSH issues - - - Set encap_eth_type to 0x894F on doing push_nsh - in kernel data path - - Set VxLAN-gpe next protocol present bit - -Signed-off-by: Yi Yang ---- - datapath/actions.c | 1 + - datapath/linux/compat/vxlan.c | 8 ++++---- - lib/flow.c | 2 +- - lib/odp-util.c | 2 +- - 4 files changed, 7 insertions(+), 6 deletions(-) - -diff --git a/datapath/actions.c b/datapath/actions.c -index 7072638..ffa1f04 100644 ---- a/datapath/actions.c -+++ b/datapath/actions.c -@@ -275,6 +275,7 @@ static int push_nsh(struct sk_buff *skb, struct sw_flow_key *key, - OVS_CB(skb)->encap_eth_header = (struct encap_eth_hdr *)skb->data; - OVS_CB(skb)->nsh_header = (struct nsh_hdr *)(skb->data + ENCAP_ETH_LEN); - memcpy(skb->data, nsh->header, ETH_NSH_TYPE1_HEADER_SIZE); -+ OVS_CB(skb)->encap_eth_header->encap_eth_type = htons(ETH_P_NSH); - } - else - return -EINVAL; -diff --git a/datapath/linux/compat/vxlan.c b/datapath/linux/compat/vxlan.c -index 3c05141..05fb226 100644 ---- a/datapath/linux/compat/vxlan.c -+++ b/datapath/linux/compat/vxlan.c -@@ -1051,15 +1051,15 @@ static void vxlan_build_gpe_hdr(struct vxlanhdr *vxh, u32 vxflags, - { - 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 (md->gpe == 0) -+ gpe->next_proto = VXLAN_GPE_NP_NSH; -+ else -+ gpe->next_proto = md->gpe & VXLAN_GPE_NP_MASK; - } - - #if IS_ENABLED(CONFIG_IPV6) -diff --git a/lib/flow.c b/lib/flow.c -index 887b023..6710e20 100644 ---- a/lib/flow.c -+++ b/lib/flow.c -@@ -915,7 +915,7 @@ 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)) { -+ if (flow->tunnel.gpe_np != 0) { - match_set_tun_gpe_np(flow_metadata, flow->tunnel.gpe_np); - } - if (flow->tunnel.gpe_flags) { -diff --git a/lib/odp-util.c b/lib/odp-util.c -index 7721cc4..51f0545 100644 ---- a/lib/odp-util.c -+++ b/lib/odp-util.c -@@ -1982,7 +1982,7 @@ odp_tun_key_from_attr__(const struct nlattr *attr, - }; - struct nlattr *ext[ARRAY_SIZE(vxlan_opts_policy)]; - -- if (!nl_parse_nested(a, vxlan_opts_policy, ext, ARRAY_SIZE(ext))) { -+ if (!nl_parse_nested(a, vxlan_opts_policy, ext, ARRAY_SIZE(vxlan_opts_policy))) { - return ODP_FIT_ERROR; - } - --- -1.9.3 - diff --git a/ovs_build/patches/README b/ovs_build/patches/README deleted file mode 100644 index be28380..0000000 --- a/ovs_build/patches/README +++ /dev/null @@ -1 +0,0 @@ -The patches were copied from commit id 307b06d986a49698c01caa3d6ed62fd7dac83e87 in https://github.com/yyang13/ovs_nsh_patches