[ovs-dev] [PATCH v7 3/3] userspace: add vxlan gpe support to vport

Zoltán Balogh zoltan.balogh at ericsson.com
Thu May 25 15:37:49 UTC 2017


From: Georg Schmuecking <georg.schmuecking at 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. Description of vxlan gpe protocoll was added to header
file lib/packets.h. In the vxlan specific methods the different packet are
introduced and handled.

Added VXLAN GPE tunnel push test.

Signed-off-by: Yi Yang <yi.y.yang at intel.com>
Signed-off-by: Georg Schmuecking <georg.schmuecking at ericsson.com>
---
 datapath/linux/compat/include/linux/openvswitch.h |  1 +
 include/openvswitch/automake.mk                   |  1 -
 lib/netdev-native-tnl.c                           | 59 +++++++++++++++++++++--
 lib/netdev-vport.c                                | 22 +++++++--
 lib/packets.h                                     | 54 ++++++++++++++++++++-
 tests/tunnel-push-pop.at                          | 10 ++++
 6 files changed, 135 insertions(+), 12 deletions(-)

diff --git a/datapath/linux/compat/include/linux/openvswitch.h b/datapath/linux/compat/include/linux/openvswitch.h
index 7990638..2ae1797 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..699d9d7 100644
--- a/include/openvswitch/automake.mk
+++ b/include/openvswitch/automake.mk
@@ -30,4 +30,3 @@ openvswitchinclude_HEADERS = \
 	include/openvswitch/version.h \
 	include/openvswitch/vconn.h \
 	include/openvswitch/vlog.h
-
diff --git a/lib/netdev-native-tnl.c b/lib/netdev-native-tnl.c
index 0651322..8ae8893 100644
--- a/lib/netdev-native-tnl.c
+++ b/lib/netdev-native-tnl.c
@@ -499,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)) {
@@ -510,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);
+        /* Drop the OAM packets */
+        if (vxh->vx_pge.flags & VXLAN_GPE_FLAGS_O) {
+            goto err;
+        }
+        switch (vxh->vx_pge.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:
@@ -544,8 +571,30 @@ 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)) {
+        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:
+                vxh->vx_pge.next_protocol = VXLAN_GPE_NP_IPV4;
+                break;
+            case ETH_TYPE_IPV6:
+                vxh->vx_pge.next_protocol = VXLAN_GPE_NP_IPV6;
+                break;
+            case ETH_TYPE_TEB:
+                vxh->vx_pge.next_protocol = VXLAN_GPE_NP_ETHERNET;
+                break;
+            }
+        } else {
+            vxh->vx_pge.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 ba69461..d390f37 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,16 +524,23 @@ 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",
-                          name, type, node->key);
+            ds_put_format(&errors, "%s: unknown %s argument '%s'\n", name,
+                          type, node->key);
         }
     }
 
+    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");
     }
 
diff --git a/lib/packets.h b/lib/packets.h
index d53e0b7..a00792d 100644
--- a/lib/packets.h
+++ b/lib/packets.h
@@ -1174,12 +1174,64 @@ struct gre_base_hdr {
 
 /* VXLAN protocol header */
 struct vxlanhdr {
-    ovs_16aligned_be32 vx_flags;
+    union {
+        ovs_16aligned_be32 vx_flags; /* VXLAN flags. */
+        struct {
+            uint8_t flags;           /* VXLAN GPE flags. */
+            uint8_t reserved_1;      /* 16 bits reserved. */
+            uint8_t reserved_2;
+            uint8_t next_protocol;   /* Next Protocol field for VXLAN GPE. */
+        } vx_pge;
+    };
     ovs_16aligned_be32 vx_vni;
 };
 
 #define VXLAN_FLAGS 0x08000000  /* struct vxlanhdr.vx_flags required value. */
 
+/*
+ * 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
+ */
+
+/* Fields in struct vxlanhdr.vx_gpe.flags */
+#define VXLAN_GPE_FLAGS_VER     0x30    /* Version. */
+#define VLXAN_GPE_FLAGS_P       0x04    /* Next Protocol Bit. */
+#define VXLAN_GPE_FLAGS_O       0x01    /* OAM Bit. */
+
+/* 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
+
+#define VXLAN_F_GPE  0x4000
+#define VXLAN_HF_GPE 0x04000000
+
 /* Input values for PACKET_TYPE macros have to be in host byte order.
  * The _BE postfix indicates result is in network byte order. Otherwise result
  * is in host byte order. */
diff --git a/tests/tunnel-push-pop.at b/tests/tunnel-push-pop.at
index afa345e..e3aecb4 100644
--- a/tests/tunnel-push-pop.at
+++ b/tests/tunnel-push-pop.at
@@ -16,6 +16,8 @@ AT_CHECK([ovs-vsctl add-port int-br t2 -- set Interface t2 type=vxlan \
                        options:remote_ip=1.1.2.93 options:out_key=flow options:egress_pkt_mark=1234 ofport_request=6\
                     -- add-port int-br t6 -- set Interface t6 type=gre \
                        options:remote_ip=1.1.2.92 options:key=456 options:layer3=true ofport_request=7\
+                    -- add-port int-br t7 -- set Interface t7 type=vxlan \
+                       options:remote_ip=1.1.2.92 options:key=345 options:exts=gpe ofport_request=8\
                        ], [0])
 
 AT_CHECK([ovs-appctl dpif/show], [0], [dnl
@@ -31,6 +33,7 @@ dummy at ovs-dummy: hit:0 missed:0
 		t4 5/6081: (geneve: key=123, remote_ip=flow)
 		t5 6/6081: (geneve: egress_pkt_mark=1234, out_key=flow, remote_ip=1.1.2.93)
 		t6 7/3: (gre: key=456, layer3=true, remote_ip=1.1.2.92)
+		t7 8/4789: (vxlan: key=345, remote_ip=1.1.2.92)
 ])
 
 dnl First setup dummy interface IP address, then add the route
@@ -113,6 +116,13 @@ AT_CHECK([tail -1 stdout], [0],
   [Datapath actions: tnl_push(tnl_port(4789),header(size=50,type=4,eth(dst=f8:bc:12:44:34:b6,src=aa:55:aa:55:00:00,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.92,proto=17,tos=0,ttl=64,frag=0x4000),udp(src=0,dst=4789,csum=0x0),vxlan(flags=0x8000000,vni=0x7b)),out_port(100))
 ])
 
+dnl Check VXLAN GPE tunnel push
+AT_CHECK([ovs-ofctl add-flow int-br action=8])
+AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(2),eth(src=f8:bc:12:44:34:b6,dst=aa:55:aa:55:00:01),eth_type(0x0800),ipv4(src=1.1.3.88,dst=1.1.3.112,proto=47,tos=0,ttl=64,frag=no)'], [0], [stdout])
+AT_CHECK([tail -1 stdout], [0],
+  [Datapath actions: tnl_push(tnl_port(4789),header(size=50,type=4,eth(dst=f8:bc:12:44:34:b6,src=aa:55:aa:55:00:00,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.92,proto=17,tos=0,ttl=64,frag=0x4000),udp(src=0,dst=4789,csum=0x0),vxlan(flags=0xc000003,vni=0x159)),out_port(100))
+])
+
 dnl Check VXLAN tunnel push set tunnel id by flow and checksum
 AT_CHECK([ovs-ofctl add-flow int-br "actions=set_tunnel:124,4"])
 AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(2),eth(src=f8:bc:12:44:34:b6,dst=aa:55:aa:55:00:00),eth_type(0x0800),ipv4(src=1.1.3.88,dst=1.1.3.112,proto=47,tos=0,ttl=64,frag=no)'], [0], [stdout])
-- 
2.7.4



More information about the dev mailing list