diff mbox

[ovs-dev,RFC,v4,6/6] dpif-netlink: add GENEVE creation support

Message ID 20170118194515.1307-7-e@erig.me
State Superseded
Headers show

Commit Message

Eric Garver Jan. 18, 2017, 7:45 p.m. UTC
Creates GENEVE devices using rtnetlink and tunnel metadata.

Co-Authored-by: Thadeu Lima de Souza Cascardo <cascardo@redhat.com>
Co-Authored-by: Eric Garver <e@erig.me>
Signed-off-by: Eric Garver <e@erig.me>
---
 lib/dpif-netlink.c | 140 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 140 insertions(+)

Comments

Joe Stringer Feb. 2, 2017, 11:03 p.m. UTC | #1
On 18 January 2017 at 11:45, Eric Garver <e@erig.me> wrote:
> Creates GENEVE devices using rtnetlink and tunnel metadata.
>
> Co-Authored-by: Thadeu Lima de Souza Cascardo <cascardo@redhat.com>
> Co-Authored-by: Eric Garver <e@erig.me>
> Signed-off-by: Eric Garver <e@erig.me>

Same feedback as VXLAN.

You might consider adding this patch before the testing patch, but
don't expose the functionality until the probing commit. Then that
patch can compile.
diff mbox

Patch

diff --git a/lib/dpif-netlink.c b/lib/dpif-netlink.c
index f4ff6f516e75..95d70a429367 100644
--- a/lib/dpif-netlink.c
+++ b/lib/dpif-netlink.c
@@ -987,6 +987,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.
  */
@@ -1005,6 +1011,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 const struct nl_policy rtlink_policy[] = {
     [IFLA_LINKINFO] = { .type = NL_A_NESTED },
 };
@@ -1229,6 +1247,114 @@  netdev_gre_create(struct netdev *netdev)
     return netdev_gre_create_kind(netdev, "gretap");
 }
 
+static int
+netdev_geneve_verify(struct netdev *netdev, const char *name, const char *kind)
+{
+    int err;
+    struct ofpbuf request, *reply;
+    struct ifinfomsg *ifmsg;
+    const struct netdev_tunnel_config *tnl_cfg;
+
+    static const struct nl_policy geneve_policy[] = {
+        [IFLA_GENEVE_COLLECT_METADATA] = { .type = NL_A_FLAG },
+        [IFLA_GENEVE_UDP_ZERO_CSUM6_RX] = { .type = NL_A_U8 },
+        [IFLA_GENEVE_PORT] = { .type = NL_A_U16 },
+    };
+
+    tnl_cfg = netdev_get_tunnel_config(netdev);
+    if (!tnl_cfg) {
+        return EINVAL;
+    }
+
+    ofpbuf_init(&request, 0);
+    nl_msg_put_nlmsghdr(&request, 0, RTM_GETLINK,
+                        NLM_F_REQUEST);
+    ofpbuf_put_zeros(&request, sizeof(struct ifinfomsg));
+    nl_msg_put_string(&request, IFLA_IFNAME, name);
+
+    err = nl_transact(NETLINK_ROUTE, &request, &reply);
+    if (!err) {
+        struct nlattr *rtlink[ARRAY_SIZE(rtlink_policy)];
+        struct nlattr *linkinfo[ARRAY_SIZE(linkinfo_policy)];
+        struct nlattr *geneve[ARRAY_SIZE(geneve_policy)];
+
+        ifmsg = ofpbuf_at(reply, NLMSG_HDRLEN, sizeof *ifmsg);
+        if (!nl_policy_parse(reply, NLMSG_HDRLEN + sizeof *ifmsg,
+                             rtlink_policy, rtlink,
+                             ARRAY_SIZE(rtlink_policy)) ||
+            !nl_parse_nested(rtlink[IFLA_LINKINFO], linkinfo_policy,
+                             linkinfo, ARRAY_SIZE(linkinfo_policy)) ||
+            strcmp(nl_attr_get_string(linkinfo[IFLA_INFO_KIND]), kind) ||
+            !nl_parse_nested(linkinfo[IFLA_INFO_DATA], geneve_policy, geneve,
+                             ARRAY_SIZE(geneve_policy))) {
+            err = EINVAL;
+        }
+        if (!err) {
+            if (!nl_attr_get_flag(geneve[IFLA_GENEVE_COLLECT_METADATA]) ||
+                1 != nl_attr_get_u8(geneve[IFLA_GENEVE_UDP_ZERO_CSUM6_RX]) ||
+                tnl_cfg->dst_port !=
+                    nl_attr_get_u16(geneve[IFLA_GENEVE_PORT])) {
+                err = EINVAL;
+            }
+        }
+        ofpbuf_uninit(reply);
+    }
+    ofpbuf_uninit(&request);
+    return err;
+}
+
+static int
+netdev_geneve_create_kind(struct netdev *netdev, const char *kind)
+{
+    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) {
+        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, kind);
+        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);
+    }
+
+    if (!err && (err = netdev_geneve_verify(netdev, name, kind))) {
+        netdev_geneve_destroy(name);
+    }
+
+    ofpbuf_uninit(&request);
+    return err;
+}
+
+static int
+netdev_geneve_create(struct netdev *netdev)
+{
+    return netdev_geneve_create_kind(netdev, "geneve");
+}
+
 #else
 
 static int
@@ -1244,6 +1370,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;
@@ -1255,6 +1387,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
@@ -1270,6 +1408,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:
@@ -1291,6 +1430,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: