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 b48fccd..e8ac078 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);
@@ -498,6 +499,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)) {
@@ -509,18 +512,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:
@@ -541,10 +569,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

Reply via email to