diff mbox

[ovs-dev,v3,5/5] dpif-netlink: add GENEVE creation support

Message ID 1466610462-32116-6-git-send-email-cascardo@redhat.com
State Changes Requested
Headers show

Commit Message

Thadeu Lima de Souza Cascardo June 22, 2016, 3:47 p.m. UTC
Creates GENEVE devices using rtnetlink and tunnel metadata. If the kernel does
not support tunnel metadata, it will return EINVAL because of the missing ID and
REMOTE attributes.

This was tested on kernels 4.2.3, 4.3.6, 4.4.9 and 4.5.5. All of them worked
with the system traffic test "datapath - ping over geneve tunnel".

Signed-off-by: Thadeu Lima de Souza Cascardo <cascardo@redhat.com>
---
 lib/dpif-netlink.c | 82 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 82 insertions(+)
diff mbox

Patch

diff --git a/lib/dpif-netlink.c b/lib/dpif-netlink.c
index 5f1b867..c99d7da 100644
--- a/lib/dpif-netlink.c
+++ b/lib/dpif-netlink.c
@@ -970,6 +970,12 @@  netdev_gre_destroy(const char *name)
     return netdev_linux_destroy(name);
 }
 
+static int
+netdev_geneve_destroy(const char *name)
+{
+    return netdev_linux_destroy(name);
+}
+
 /*
  * On some older systems, these enums are not defined.
  */
@@ -988,6 +994,18 @@  netdev_gre_destroy(const char *name)
 #define IFLA_GRE_COLLECT_METADATA 18
 #endif
 
+#ifndef IFLA_GENEVE_MAX
+#define IFLA_GENEVE_MAX 0
+#define IFLA_GENEVE_PORT 5
+#endif
+
+#if IFLA_GENEVE_MAX < 6
+#define IFLA_GENEVE_COLLECT_METADATA 6
+#endif
+#if IFLA_GENEVE_MAX < 10
+#define IFLA_GENEVE_UDP_ZERO_CSUM6_RX 10
+#endif
+
 static int
 netdev_vxlan_create(struct netdev *netdev)
 {
@@ -1151,6 +1169,56 @@  netdev_gre_create(struct netdev *netdev)
     return err;
 }
 
+static int
+netdev_geneve_create(struct netdev *netdev)
+{
+    int err;
+    struct ofpbuf request, *reply;
+    size_t linkinfo_off, infodata_off;
+    char namebuf[NETDEV_VPORT_NAME_BUFSIZE];
+    const char *name = netdev_vport_get_dpif_port(netdev,
+                                                  namebuf, sizeof namebuf);
+    struct ifinfomsg *ifinfo;
+    const struct netdev_tunnel_config *tnl_cfg;
+    tnl_cfg = netdev_get_tunnel_config(netdev);
+    if (!tnl_cfg) { /* or assert? */
+        return EINVAL;
+    }
+
+    ofpbuf_init(&request, 0);
+    nl_msg_put_nlmsghdr(&request, 0, RTM_NEWLINK,
+                        NLM_F_REQUEST | NLM_F_ACK | NLM_F_CREATE);
+    ifinfo = ofpbuf_put_zeros(&request, sizeof(struct ifinfomsg));
+    ifinfo->ifi_change = ifinfo->ifi_flags = IFF_UP;
+    nl_msg_put_string(&request, IFLA_IFNAME, name);
+    nl_msg_put_u32(&request, IFLA_MTU, UINT16_MAX);
+    linkinfo_off = nl_msg_start_nested(&request, IFLA_LINKINFO);
+        nl_msg_put_string(&request, IFLA_INFO_KIND, "geneve");
+        infodata_off = nl_msg_start_nested(&request, IFLA_INFO_DATA);
+            nl_msg_put_flag(&request, IFLA_GENEVE_COLLECT_METADATA);
+            nl_msg_put_u8(&request, IFLA_GENEVE_UDP_ZERO_CSUM6_RX, 1);
+            nl_msg_put_be16(&request, IFLA_GENEVE_PORT, tnl_cfg->dst_port);
+        nl_msg_end_nested(&request, infodata_off);
+    nl_msg_end_nested(&request, linkinfo_off);
+
+    err = nl_transact(NETLINK_ROUTE, &request, &reply);
+
+    if (!err) {
+        ofpbuf_uninit(reply);
+    }
+
+    /*
+     * Linux versions older than 4.3 will return EINVAL in case the GENEVE_ID is
+     * not set, which is sufficient to verify COLLECT_METADATA is supported.
+     */
+    if (err == EINVAL) {
+        err = EOPNOTSUPP;
+    }
+
+    ofpbuf_uninit(&request);
+    return err;
+}
+
 #else
 
 static int
@@ -1166,6 +1234,12 @@  netdev_gre_create(struct netdev *netdev OVS_UNUSED)
 }
 
 static int
+netdev_geneve_create(struct netdev *netdev OVS_UNUSED)
+{
+    return EOPNOTSUPP;
+}
+
+static int
 netdev_vxlan_destroy(const char *name OVS_UNUSED)
 {
     return EOPNOTSUPP;
@@ -1177,6 +1251,12 @@  netdev_gre_destroy(const char *name OVS_UNUSED)
     return EOPNOTSUPP;
 }
 
+static int
+netdev_geneve_destroy(const char *name OVS_UNUSED)
+{
+    return EOPNOTSUPP;
+}
+
 #endif
 
 static int
@@ -1192,6 +1272,7 @@  dpif_netlink_port_create(struct netdev *netdev)
     case OVS_VPORT_TYPE_GRE:
         return netdev_gre_create(netdev);
     case OVS_VPORT_TYPE_GENEVE:
+        return netdev_geneve_create(netdev);
     case OVS_VPORT_TYPE_NETDEV:
     case OVS_VPORT_TYPE_INTERNAL:
     case OVS_VPORT_TYPE_LISP:
@@ -1213,6 +1294,7 @@  dpif_netlink_port_destroy(const char *name, const char *type)
     case OVS_VPORT_TYPE_GRE:
         return netdev_gre_destroy(name);
     case OVS_VPORT_TYPE_GENEVE:
+        return netdev_geneve_destroy(name);
     case OVS_VPORT_TYPE_NETDEV:
     case OVS_VPORT_TYPE_INTERNAL:
     case OVS_VPORT_TYPE_LISP: