From: Georg Schmuecking <georg.schmueck...@ericsson.com> This patch is based on the "datapath: enable vxlangpe creation in compat mode" from Yi Yang. It introduces an extension option "gpe" to the vxlan port in the netdev-dpdk datapath. Furthermore it introduces a new protocol header file vxlangpe.h in which the vxlan gpe protocoll is described. In the vxlan specific methods the different packet are introduced and handled.
Signed-off-by: Yi Yang <yi.y.yang at intel.com> Signed-off-by: Georg Schmuecking <georg.schmueck...@ericsson.com> --- datapath/linux/compat/include/linux/openvswitch.h | 1 + include/openvswitch/automake.mk | 4 +- include/openvswitch/vxlangpe.h | 76 +++++++++++++++++++++++ lib/netdev-native-tnl.c | 61 ++++++++++++++++-- lib/netdev-vport.c | 18 +++++- 5 files changed, 150 insertions(+), 10 deletions(-) create mode 100755 include/openvswitch/vxlangpe.h diff --git a/datapath/linux/compat/include/linux/openvswitch.h b/datapath/linux/compat/include/linux/openvswitch.h index 61f9e22..0146d23 100644 --- a/datapath/linux/compat/include/linux/openvswitch.h +++ b/datapath/linux/compat/include/linux/openvswitch.h @@ -291,6 +291,7 @@ enum ovs_vport_attr { enum { OVS_VXLAN_EXT_UNSPEC, OVS_VXLAN_EXT_GBP, /* Flag or __u32 */ + OVS_VXLAN_EXT_GPE = 8, /* Flag or __u32 */ __OVS_VXLAN_EXT_MAX, }; diff --git a/include/openvswitch/automake.mk b/include/openvswitch/automake.mk index c0e276f..c125f1e 100644 --- a/include/openvswitch/automake.mk +++ b/include/openvswitch/automake.mk @@ -29,5 +29,5 @@ 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 diff --git a/include/openvswitch/vxlangpe.h b/include/openvswitch/vxlangpe.h new file mode 100755 index 0000000..4c18d90 --- /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 ((1U <<29) | (1U <<28)) +#define VXLAN_HF_NP (1U <<26) +#define VXLAN_HF_OAM (1U <<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/netdev-native-tnl.c b/lib/netdev-native-tnl.c index 4590e25..2d947c2 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" VLOG_DEFINE_THIS_MODULE(native_tnl); static struct vlog_rate_limit err_rl = VLOG_RATE_LIMIT_INIT(60, 5); @@ -497,6 +498,8 @@ netdev_vxlan_pop_header(struct dp_packet *packet) struct flow_tnl *tnl = &md->tunnel; struct vxlanhdr *vxh; unsigned int hlen; + ovs_be32 vx_flags; + enum packet_type next_pt = PT_ETH; pkt_metadata_init_tnl(md); if (VXLAN_HLEN > dp_packet_l4_size(packet)) { @@ -508,18 +511,43 @@ netdev_vxlan_pop_header(struct dp_packet *packet) goto err; } - if (get_16aligned_be32(&vxh->vx_flags) != htonl(VXLAN_FLAGS) || + vx_flags = get_16aligned_be32(&vxh->vx_flags); + if (vx_flags & htonl(VXLAN_HF_GPE)) { + vx_flags &= htonl(~VXLAN_GPE_USED_BITS); + struct vxlanhdr_gpe *gpe = (struct vxlanhdr_gpe *)vxh; + /* Drop the OAM packets */ + if (gpe->oam_flag) + goto err; + switch (gpe->next_protocol) { + case VXLAN_GPE_NP_IPV4: + next_pt = PT_IPV4; + break; + case VXLAN_GPE_NP_IPV6: + next_pt = PT_IPV6; + break; + case VXLAN_GPE_NP_ETHERNET: + next_pt = PT_ETH; + break; + default: + goto err; + } + } + + if (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(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; - packet->packet_type = htonl(PT_ETH); + packet->packet_type = htonl(next_pt); dp_packet_reset_packet(packet, hlen + VXLAN_HLEN); + if (next_pt != PT_ETH) { + packet->l3_ofs = 0; + } return packet; err: @@ -540,10 +568,33 @@ netdev_vxlan_build_header(const struct netdev *netdev, ovs_mutex_lock(&dev->mutex); tnl_cfg = &dev->tnl_cfg; + 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 (tnl_cfg->is_layer3) { + switch (ntohs(params->flow->dl_type)) { + case ETH_TYPE_IP: + gpe->next_protocol = VXLAN_GPE_NP_IPV4; + break; + case ETH_TYPE_IPV6: + gpe->next_protocol = VXLAN_GPE_NP_IPV6; + break; + case ETH_TYPE_TEB: + gpe->next_protocol = VXLAN_GPE_NP_ETHERNET; + break; + } + } else { + gpe->next_protocol = VXLAN_GPE_NP_ETHERNET; + } + } 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 8653e96..8123f32 100644 --- a/lib/netdev-vport.c +++ b/lib/netdev-vport.c @@ -414,6 +414,7 @@ set_tunnel_config(struct netdev *dev_, const struct smap *args, char **errp) uint16_t dst_proto = 0, src_proto = 0; struct netdev_tunnel_config tnl_cfg; struct smap_node *node; + bool is_layer3 = false; int err; has_csum = strstr(type, "gre") || strstr(type, "geneve") || @@ -508,6 +509,9 @@ set_tunnel_config(struct netdev *dev_, const struct smap *args, char **errp) while (ext) { if (!strcmp(type, "vxlan") && !strcmp(ext, "gbp")) { tnl_cfg.exts |= (1 << OVS_VXLAN_EXT_GBP); + } else if (!strcmp(type, "vxlan") && !strcmp(ext, "gpe")) { + tnl_cfg.exts |= (1 << OVS_VXLAN_EXT_GPE); + optional_layer3 = true; } else { ds_put_format(&errors, "%s: unknown extension '%s'\n", name, ext); @@ -520,9 +524,9 @@ set_tunnel_config(struct netdev *dev_, const struct smap *args, char **errp) } else if (!strcmp(node->key, "egress_pkt_mark")) { tnl_cfg.egress_pkt_mark = strtoul(node->value, NULL, 10); tnl_cfg.set_egress_pkt_mark = true; - } else if (!strcmp(node->key, "layer3") && optional_layer3) { + } else if (!strcmp(node->key, "layer3")) { if (!strcmp(node->value, "true")) { - tnl_cfg.is_layer3 = true; + is_layer3 = true; } } else { ds_put_format(&errors, "%s: unknown %s argument '%s'\n", @@ -530,6 +534,13 @@ set_tunnel_config(struct netdev *dev_, const struct smap *args, char **errp) } } + if (optional_layer3 && is_layer3) { + tnl_cfg.is_layer3 = is_layer3; + } else if (!optional_layer3 && is_layer3) { + ds_put_format(&errors, "%s: unknown %s argument '%s'\n", + name, type, "layer3"); + } + if (!ipv6_addr_is_set(&tnl_cfg.ipv6_dst) && !tnl_cfg.ip_dst_flow) { ds_put_format(&errors, "%s: %s type requires valid 'remote_ip' argument\n", @@ -660,7 +671,8 @@ get_tunnel_config(const struct netdev *dev, struct smap *args) smap_add(args, "csum", "true"); } - if (tnl_cfg.is_layer3 && !strcmp("gre", type)) { + if (tnl_cfg.is_layer3 && (!strcmp("gre", type) || + !strcmp("vxlan", type))) { smap_add(args, "layer3", "true"); } -- 2.7.4 _______________________________________________ dev mailing list d...@openvswitch.org https://mail.openvswitch.org/mailman/listinfo/ovs-dev