[PATCH 1/1] link: add Geneve support.

Wang Jian jianjian.wang1 at gmail.com
Sat Feb 3 02:59:29 PST 2018


Signed-off-by: Wang Jian <jianjian.wang1 at gmail.com>
---
 Makefile.am                         |   7 +-
 include/netlink/route/link/geneve.h |  60 +++
 lib/route/link/geneve.c             | 810 ++++++++++++++++++++++++++++++++++++
 libnl-route-3.sym                   |  22 +
 tests/test-create-geneve.c          |  87 ++++
 5 files changed, 985 insertions(+), 1 deletion(-)
 create mode 100644 include/netlink/route/link/geneve.h
 create mode 100644 lib/route/link/geneve.c
 create mode 100644 tests/test-create-geneve.c

diff --git a/Makefile.am b/Makefile.am
index 1261b59..45a8fd5 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -151,7 +151,8 @@ libnlinclude_netlink_route_link_HEADERS = \
 	include/netlink/route/link/veth.h \
 	include/netlink/route/link/vlan.h \
 	include/netlink/route/link/vrf.h \
-	include/netlink/route/link/vxlan.h
+	include/netlink/route/link/vxlan.h \
+	include/netlink/route/link/geneve.h
 libnlinclude_netlink_route_qdiscdir = $(libnlincludedir)/netlink/route/qdisc
 libnlinclude_netlink_route_qdisc_HEADERS = \
 	include/netlink/route/qdisc/cbq.h \
@@ -386,6 +387,7 @@ lib_libnl_route_3_la_SOURCES = \
 	lib/route/link/vlan.c \
 	lib/route/link/vrf.c \
 	lib/route/link/vxlan.c \
+	lib/route/link/geneve.c \
 	lib/route/neigh.c \
 	lib/route/neightbl.c \
 	lib/route/netconf.c \
@@ -811,6 +813,7 @@ check_PROGRAMS += \
 	tests/test-create-vlan \
 	tests/test-create-vrf \
 	tests/test-create-vxlan \
+	tests/test-create-geneve \
 	tests/test-delete-link \
 	tests/test-socket-creation \
 	tests/test-u32-filter-with-actions \
@@ -822,6 +825,8 @@ tests_test_create_vlan_CPPFLAGS                   = $(tests_cppflags)
 tests_test_create_vlan_LDADD                      = $(tests_ldadd)
 tests_test_create_vxlan_CPPFLAGS                  = $(tests_cppflags)
 tests_test_create_vxlan_LDADD                     = $(tests_ldadd)
+tests_test_create_geneve_CPPFLAGS                  = $(tests_cppflags)
+tests_test_create_geneve_LDADD                     = $(tests_ldadd)
 tests_test_create_veth_CPPFLAGS                   = $(tests_cppflags)
 tests_test_create_veth_LDADD                      = $(tests_ldadd)
 tests_test_create_bridge_CPPFLAGS                 = $(tests_cppflags)
diff --git a/include/netlink/route/link/geneve.h b/include/netlink/route/link/geneve.h
new file mode 100644
index 0000000..abd9713
--- /dev/null
+++ b/include/netlink/route/link/geneve.h
@@ -0,0 +1,60 @@
+/*
+ * netlink/route/link/geneve.h          GENEVE interface
+ *      This library is free software; you can redistribute it and/or
+ *      modify it under the terms of the GNU Lesser General Public
+ *      License as published by the Free Software Foundation version 2.1
+ *      of the License.
+ */
+
+#ifndef NETLINK_LINK_GENEVE_H_
+#define NETLINK_LINK_GENEVE_H_
+
+#include <netlink/netlink.h>
+#include <netlink/route/link.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define GENEVE_ID_MAX 16777215
+
+#define RTNL_LINK_GENEVE_F_COLLECT_METADATA     (1<<0)
+
+extern struct rtnl_link *rtnl_link_geneve_alloc(void);
+extern int rtnl_link_is_geneve(struct rtnl_link *);
+
+extern int rtnl_link_geneve_set_id(struct rtnl_link *, uint32_t);
+extern int rtnl_link_geneve_get_id(struct rtnl_link *, uint32_t *);
+
+extern int rtnl_link_geneve_set_remote(struct rtnl_link *, struct nl_addr *);
+extern int rtnl_link_geneve_get_remote(struct rtnl_link *, struct nl_addr **);
+
+extern int rtnl_link_geneve_set_ttl(struct rtnl_link *, uint8_t);
+extern int rtnl_link_geneve_get_ttl(struct rtnl_link *);
+
+extern int rtnl_link_geneve_set_tos(struct rtnl_link *, uint8_t);
+extern int rtnl_link_geneve_get_tos(struct rtnl_link *);
+
+extern int rtnl_link_geneve_set_port(struct rtnl_link *, uint32_t);
+extern int rtnl_link_geneve_get_port(struct rtnl_link *, uint32_t *);
+
+extern int rtnl_link_geneve_set_label(struct rtnl_link *, uint32_t);
+extern int rtnl_link_geneve_get_label(struct rtnl_link *, uint32_t *);
+
+extern int rtnl_link_geneve_set_udp_csum(struct rtnl_link *, uint8_t);
+extern int rtnl_link_geneve_get_udp_csum(struct rtnl_link *);
+
+extern int rtnl_link_geneve_set_udp_zero_csum6_tx(struct rtnl_link *, uint8_t);
+extern int rtnl_link_geneve_get_udp_zero_csum6_tx(struct rtnl_link *);
+
+extern int rtnl_link_geneve_set_udp_zero_csum6_rx(struct rtnl_link *, uint8_t);
+extern int rtnl_link_geneve_get_udp_zero_csum6_rx(struct rtnl_link *);
+
+extern int rtnl_link_geneve_set_flags(struct rtnl_link *, uint8_t flags, int enable);
+extern int rtnl_link_geneve_get_flags(struct rtnl_link *, uint8_t *flags);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/lib/route/link/geneve.c b/lib/route/link/geneve.c
new file mode 100644
index 0000000..2afa0dc
--- /dev/null
+++ b/lib/route/link/geneve.c
@@ -0,0 +1,810 @@
+/*
+ * lib/route/link/geneve.c      Geneve Link Info
+ *         This library is free software; you can redistribute it and/or
+ *         modify it under the terms of the GNU Lesser General Public
+ *         License as published by the Free Software Foundation version 2.1
+ *         of the License.
+ *
+ * Copyright (c) 2018 Wang Jian <jianjian.wang1 at gmail.com>
+ */
+/**
+ * @ingroup link
+ * @defgroup geneve Geneve
+ * Generic Network Virtualization Encapsulation
+ *
+ * @details
+ * \b Link Type Name: "geneve"
+ *
+ * @route_doc{link_geneve, Geneve Documentation}
+ *
+ * @{
+ */
+#include <netlink-private/netlink.h>
+#include <netlink/netlink.h>
+#include <netlink/utils.h>
+#include <netlink/object.h>
+#include <netlink/route/rtnl.h>
+#include <netlink-private/route/link/api.h>
+#include <netlink/route/link/geneve.h>
+
+
+/** @cond SKIP */
+#define GENEVE_ATTR_ID          (1<<0)
+#define GENEVE_ATTR_REMOTE      (1<<1)
+#define GENEVE_ATTR_REMOTE6     (1<<2)
+#define GENEVE_ATTR_TTL         (1<<3)
+#define GENEVE_ATTR_TOS         (1<<4)
+#define GENEVE_ATTR_LABEL       (1<<5)
+#define GENEVE_ATTR_PORT        (1<<6)
+#define GENEVE_ATTR_FLAGS       (1<<7)
+#define GENEVE_ATTR_UDP_CSUM    (1<<8)
+#define GENEVE_ATTR_UDP_ZERO_CSUM6_TX   (1<<9)
+#define GENEVE_ATTR_UDP_ZERO_CSUM6_RX   (1<<10)
+
+struct geneve_info
+{
+        uint32_t        id;
+        uint32_t        remote;
+        struct in6_addr remote6;
+        uint8_t         ttl;
+        uint8_t         tos;
+        uint32_t        label;
+        uint16_t        port;
+        uint8_t         flags;
+        uint8_t         udp_csum;
+        uint8_t         udp_zero_csum6_tx;
+        uint8_t         udp_zero_csum6_rx;
+        uint32_t        mask;
+};
+
+/** @endcond */
+
+static struct nla_policy geneve_policy[IFLA_GENEVE_MAX + 1] = {
+        [IFLA_GENEVE_ID] = { .type = NLA_U32 },
+        [IFLA_GENEVE_REMOTE]    = { .minlen = sizeof(uint32_t) },
+        [IFLA_GENEVE_REMOTE6]   = { .minlen = sizeof(struct in6_addr) },
+        [IFLA_GENEVE_TTL]       = { .type = NLA_U8 },
+        [IFLA_GENEVE_TOS]       = { .type = NLA_U8 },
+        [IFLA_GENEVE_LABEL]     = { .type = NLA_U32 },
+        [IFLA_GENEVE_PORT]      = { .type = NLA_U16 },
+        [IFLA_GENEVE_COLLECT_METADATA]  = { .type = NLA_FLAG },
+        [IFLA_GENEVE_UDP_CSUM]  = { .type = NLA_U8 },
+        [IFLA_GENEVE_UDP_ZERO_CSUM6_TX] = { .type = NLA_U8 },
+        [IFLA_GENEVE_UDP_ZERO_CSUM6_RX] = { .type = NLA_U8 },
+};
+
+static int geneve_alloc(struct rtnl_link *link)
+{
+        struct geneve_info *geneve;
+
+        if (link->l_info)
+                memset(link->l_info, 0, sizeof(*geneve));
+        else {
+                if ((geneve = calloc(1, sizeof(*geneve))) == NULL)
+                                return -NLE_NOMEM;
+                link->l_info = geneve;
+        }
+
+        return 0;
+}
+
+static int geneve_parse(struct rtnl_link *link, struct nlattr *data,
+                        struct nlattr *xstats)
+{
+        struct nlattr *tb[IFLA_GENEVE_MAX + 1];
+        struct geneve_info *geneve;
+        int err = 0;
+
+        NL_DBG(3, "Parsing Geneve link info\n");
+
+        err = nla_parse_nested(tb, IFLA_GENEVE_MAX, data, geneve_policy);
+        if (err < 0)
+                return err;
+
+        err = geneve_alloc(link);
+        if (err < 0)
+                return err;
+
+        geneve = link->l_info;
+
+        if (tb[IFLA_GENEVE_ID]) {
+                geneve->id = nla_get_u32(tb[IFLA_GENEVE_ID]);
+                geneve->mask |= GENEVE_ATTR_ID;
+        }
+
+        if (tb[IFLA_GENEVE_REMOTE]) {
+                nla_memcpy(&geneve->remote, tb[IFLA_GENEVE_REMOTE],
+                                sizeof(geneve->remote));
+                geneve->mask |= GENEVE_ATTR_REMOTE;
+                geneve->mask &= ~GENEVE_ATTR_REMOTE6;
+        }
+        if (tb[IFLA_GENEVE_REMOTE6]) {
+                nla_memcpy(&geneve->remote6, tb[IFLA_GENEVE_REMOTE6],
+                                sizeof(geneve->remote6));
+                geneve->mask |= GENEVE_ATTR_REMOTE6;
+                geneve->mask &= ~GENEVE_ATTR_REMOTE;
+        }
+
+        if (tb[IFLA_GENEVE_TTL]) {
+                geneve->ttl = nla_get_u8(tb[IFLA_GENEVE_TTL]);
+                geneve->mask |= GENEVE_ATTR_TTL;
+        }
+
+        if (tb[IFLA_GENEVE_TOS]) {
+                geneve->tos = nla_get_u8(tb[IFLA_GENEVE_TOS]);
+                geneve->mask |= GENEVE_ATTR_TOS;
+        }
+
+        if (tb[IFLA_GENEVE_LABEL]) {
+                geneve->label = nla_get_u32(tb[IFLA_GENEVE_LABEL]);
+                geneve->mask |= GENEVE_ATTR_LABEL;
+        }
+
+        if (tb[IFLA_GENEVE_PORT]) {
+                geneve->port  = nla_get_u16(tb[IFLA_GENEVE_PORT]);
+                geneve->mask |= GENEVE_ATTR_PORT;
+        }
+
+        if (tb[IFLA_GENEVE_COLLECT_METADATA])
+                geneve->flags |= RTNL_LINK_GENEVE_F_COLLECT_METADATA;
+
+        if (tb[IFLA_GENEVE_UDP_CSUM]) {
+                geneve->udp_csum = nla_get_u8(tb[IFLA_GENEVE_UDP_CSUM]);
+                geneve->mask |= GENEVE_ATTR_UDP_CSUM;
+        }
+
+        if (tb[IFLA_GENEVE_UDP_ZERO_CSUM6_TX]) {
+                geneve->udp_zero_csum6_tx = nla_get_u8(tb[IFLA_GENEVE_UDP_ZERO_CSUM6_TX]);
+                geneve->mask |= GENEVE_ATTR_UDP_ZERO_CSUM6_TX;
+        }
+
+        if (tb[IFLA_GENEVE_UDP_ZERO_CSUM6_RX]) {
+                geneve->udp_zero_csum6_rx = nla_get_u8(tb[IFLA_GENEVE_UDP_ZERO_CSUM6_RX]);
+                geneve->mask |= GENEVE_ATTR_UDP_ZERO_CSUM6_RX;
+        }
+
+        return err;
+}
+
+static void geneve_free(struct rtnl_link *link)
+{
+        struct geneve_info *geneve = link->l_info;
+
+        free(geneve);
+        link->l_info = NULL;
+}
+
+static void geneve_dump_line(struct rtnl_link *link, struct nl_dump_params *p)
+{
+        struct geneve_info *geneve = link->l_info;
+
+        nl_dump(p, "geneve-id %u", geneve->id);
+}
+
+static void geneve_dump_details(struct rtnl_link *link, struct nl_dump_params *p)
+{
+        struct geneve_info *geneve = link->l_info;
+        char addr[INET6_ADDRSTRLEN];
+
+        nl_dump_line(p, "    geneve-id %u\n", geneve->id);
+
+        if (geneve->mask & GENEVE_ATTR_REMOTE) {
+                nl_dump(p, "     remote ");
+                if (inet_ntop(AF_INET, &geneve->remote, addr, sizeof(addr)))
+                        nl_dump_line(p, "%s\n", addr);
+                else
+                        nl_dump_line(p, "%#x\n", ntohs(geneve->remote));
+        } else if (geneve->mask & GENEVE_ATTR_REMOTE6) {
+                nl_dump(p, "      remote ");
+                if (inet_ntop(AF_INET6, &geneve->remote6, addr, sizeof(addr)))
+                        nl_dump_line(p, "%s\n", addr);
+                else
+                        nl_dump_line(p, "%#x\n", geneve->remote6);
+        }
+
+        if (geneve->mask & GENEVE_ATTR_TTL) {
+                nl_dump(p, "      ttl ");
+                nl_dump_line(p, "%u\n", geneve->ttl);
+        }
+
+        if (geneve->mask & GENEVE_ATTR_TOS) {
+                nl_dump(p, "      tos ");
+                nl_dump_line(p, "%u\n", geneve->tos);
+        }
+
+        if (geneve->mask & GENEVE_ATTR_PORT) {
+                nl_dump(p, "      port ");
+                nl_dump_line(p, "%u\n", ntohs(geneve->port));
+        }
+
+        if (geneve->mask & GENEVE_ATTR_LABEL) {
+                nl_dump(p, "      label ");
+                nl_dump_line(p, "%u\n", ntohl(geneve->label));
+        }
+
+        if (geneve->mask & GENEVE_ATTR_UDP_CSUM) {
+                nl_dump(p, "      UDP checksum ");
+                if (geneve->udp_csum)
+                        nl_dump_line(p, "enabled (%#x)\n", geneve->udp_csum);
+                else
+                        nl_dump_line(p, "disabled\n");
+        }
+
+        if (geneve->mask & GENEVE_ATTR_UDP_ZERO_CSUM6_TX) {
+                nl_dump(p, "      udp-zero-csum6-tx ");
+                if (geneve->udp_zero_csum6_tx)
+                        nl_dump_line(p, "enabled (%#x)\n", geneve->udp_zero_csum6_tx);
+                else
+                        nl_dump_line(p, "disabled\n");
+        }
+
+        if (geneve->mask & GENEVE_ATTR_UDP_ZERO_CSUM6_RX) {
+                nl_dump(p, "      udp-zero-csum6-rx ");
+                if (geneve->udp_zero_csum6_tx)
+                        nl_dump_line(p, "enabled (%#x)\n", geneve->udp_zero_csum6_rx);
+                else
+                        nl_dump_line(p, "disabled\n");
+        }
+
+        if (geneve->flags & RTNL_LINK_GENEVE_F_COLLECT_METADATA)
+                nl_dump(p, "      collect-metadata\n");
+}
+
+static int geneve_clone(struct rtnl_link *dst, struct rtnl_link *src)
+{
+        struct geneve_info *gdst, *gsrc;
+        int err;
+
+        gsrc = src->l_info;
+        dst->l_info = NULL;
+        err = rtnl_link_set_type(dst, "geneve");
+        if (err < 0)
+                return err;
+
+        gdst = dst->l_info;
+
+        if (!gsrc || !gdst)
+                return -NLE_NOMEM;
+
+        memcpy(gdst, gsrc, sizeof(struct geneve_info));
+
+        return 0;
+}
+
+static int geneve_put_attrs(struct nl_msg *msg, struct rtnl_link *link)
+{
+        struct geneve_info  *geneve = link->l_info;
+        struct nlattr *data;
+
+        if (!(data = nla_nest_start(msg, IFLA_INFO_DATA)))
+                return -NLE_MSGSIZE;
+
+        if (geneve->mask & GENEVE_ATTR_ID)
+                NLA_PUT_U32(msg, IFLA_GENEVE_ID, geneve->id);
+
+        if (geneve->mask & GENEVE_ATTR_REMOTE)
+                NLA_PUT(msg, IFLA_GENEVE_REMOTE,
+                                sizeof(geneve->remote), &geneve->remote);
+
+        if (geneve->mask & GENEVE_ATTR_REMOTE6)
+                NLA_PUT(msg, IFLA_GENEVE_REMOTE6,
+                                sizeof(geneve->remote6), &geneve->remote6);
+
+        if (geneve->mask & GENEVE_ATTR_TTL)
+                NLA_PUT_U8(msg, IFLA_GENEVE_TTL, geneve->ttl);
+
+        if (geneve->mask & GENEVE_ATTR_TOS)
+                NLA_PUT_U8(msg, IFLA_GENEVE_TOS, geneve->tos);
+
+        if (geneve->mask & GENEVE_ATTR_LABEL)
+                NLA_PUT_U32(msg, IFLA_GENEVE_LABEL, geneve->label);
+
+        if (geneve->mask & GENEVE_ATTR_PORT)
+                NLA_PUT_U32(msg, IFLA_GENEVE_PORT, geneve->port);
+
+        if (geneve->mask & GENEVE_ATTR_UDP_CSUM)
+                NLA_PUT_U8(msg, IFLA_GENEVE_UDP_CSUM, geneve->udp_csum);
+
+        if (geneve->mask & GENEVE_ATTR_UDP_ZERO_CSUM6_TX)
+                NLA_PUT_U8(msg, IFLA_GENEVE_UDP_ZERO_CSUM6_TX, geneve->udp_zero_csum6_tx);
+
+        if (geneve->mask & GENEVE_ATTR_UDP_ZERO_CSUM6_RX)
+                NLA_PUT_U8(msg, IFLA_GENEVE_UDP_ZERO_CSUM6_RX, geneve->udp_zero_csum6_rx);
+
+        if (geneve->flags & RTNL_LINK_GENEVE_F_COLLECT_METADATA)
+                NLA_PUT_FLAG(msg, IFLA_GENEVE_COLLECT_METADATA);
+
+        nla_nest_end(msg, data);
+
+nla_put_failure:
+
+        return 0;
+}
+
+static struct rtnl_link_info_ops geneve_info_ops = {
+        .io_name        = "geneve",
+        .io_alloc       = geneve_alloc,
+        .io_parse       = geneve_parse,
+        .io_dump        = {
+                [NL_DUMP_LINE]          = geneve_dump_line,
+                [NL_DUMP_DETAILS]       = geneve_dump_details,
+        },
+        .io_clone       = geneve_clone,
+        .io_put_attrs   = geneve_put_attrs,
+        .io_free        = geneve_free,
+};
+
+
+/** @cond SKIP */
+#define IS_GENEVE_LINK_ASSERT(link) \
+        if ((link)->l_info_ops != &geneve_info_ops) { \
+                APPBUG("Link is not a geneve link. set type \"geneve\" first."); \
+                return -NLE_OPNOTSUPP; \
+        }
+/** @endcond */
+
+/**
+ * @name Geneve Object
+ * @{
+ */
+
+/**
+ * Allocate link object of type Geneve
+ *
+ * @return Allocated link object or NULL.
+ */
+struct rtnl_link *rtnl_link_geneve_alloc(void)
+{
+        struct rtnl_link *link;
+        int err;
+
+        if (!(link = rtnl_link_alloc()))
+                return NULL;
+
+        if ((err = rtnl_link_set_type(link, "geneve")) < 0) {
+                rtnl_link_put(link);
+                return NULL;
+        }
+
+        return link;
+}
+
+/**
+ * Check if link is a Geneve link
+ * @arg link    Link object
+ *
+ * @return True if link is a Geneve link, otherwisee false is returned.
+ */
+int rtnl_link_is_geneve(struct rtnl_link *link)
+{
+        return link->l_info_ops && !strcmp(link->l_info_ops->io_name, "geneve");
+}
+
+/**
+ * Set Geneve Network Indentifier
+ * @arg link    Link object
+ * @arg id      Geneve network identifier
+ *
+ * @return 0 on success or a negative error code
+ */
+int rtnl_link_geneve_set_id(struct rtnl_link *link, uint32_t id)
+{
+        struct geneve_info *geneve = link->l_info;
+
+        IS_GENEVE_LINK_ASSERT(link);
+
+        if (id > GENEVE_ID_MAX)
+                return -NLE_INVAL;
+
+        geneve->id = id;
+        geneve->mask |= GENEVE_ATTR_ID;
+
+        return 0;
+}
+
+/**
+ * Get Geneve Network Identifier
+ * @arg link    Link object
+ * @arg id      Pointer to store network identifier
+ *
+ * @return 0 on success or a negative error code
+ */
+int rtnl_link_geneve_get_id(struct rtnl_link *link, uint32_t *id)
+{
+        struct geneve_info *geneve = link->l_info;
+
+        IS_GENEVE_LINK_ASSERT(link);
+
+        if (!id)
+                return -NLE_INVAL;
+
+        if (geneve->mask & GENEVE_ATTR_ID)
+                *id = geneve->id;
+        else
+                return -NLE_AGAIN;
+
+        return 0;
+}
+
+/**
+ * Set Geneve unicast destination IP address
+ * @arg link    Link object
+ * @arg addr    The unicast destination IP address
+ *
+ * @return 0 on success or a negative error code
+ */
+int rtnl_link_geneve_set_remote(struct rtnl_link *link, struct nl_addr *addr)
+{
+        struct geneve_info *geneve = link->l_info;
+
+        IS_GENEVE_LINK_ASSERT(link);
+
+        if ((nl_addr_get_family(addr) == AF_INET) &&
+                (nl_addr_get_len(addr) == sizeof(geneve->remote))) {
+                memcpy(&geneve->remote, nl_addr_get_binary_addr(addr),
+                                sizeof(geneve->remote));
+                geneve->mask |= GENEVE_ATTR_REMOTE;
+                geneve->mask &= ~GENEVE_ATTR_REMOTE6;
+        } else if ((nl_addr_get_family(addr) == AF_INET6) &&
+                        (nl_addr_get_len(addr) == sizeof(geneve->remote6))) {
+                memcpy(&geneve->remote6, nl_addr_get_binary_addr(addr),
+                                sizeof(geneve->remote6));
+                geneve->mask |= GENEVE_ATTR_REMOTE6;
+                geneve->mask &= ~GENEVE_ATTR_REMOTE;
+        } else
+                return -NLE_INVAL;
+
+        return 0;
+}
+
+/**
+ * Get Geneve unicast destination IP address
+ * @arg link    Link object
+ * @arg addr    Pointer to store unicast destination IP addree
+ *
+ * @return 0 on success or a a negative error code
+ */
+int rtnl_link_geneve_get_remote(struct rtnl_link *link, struct nl_addr **addr)
+{
+        struct geneve_info *geneve = link->l_info;
+
+        IS_GENEVE_LINK_ASSERT(link);
+
+        if (!addr)
+                return -NLE_INVAL;
+
+        if (geneve->mask & GENEVE_ATTR_REMOTE)
+                *addr = nl_addr_build(AF_INET, &geneve->remote, sizeof(geneve->remote));
+        else if (geneve->mask & GENEVE_ATTR_REMOTE6)
+                *addr = nl_addr_build(AF_INET6, &geneve->remote6, sizeof(geneve->remote6));
+        else
+                return -NLE_AGAIN;
+
+        return 0;
+}
+
+/**
+ * Set IP TTL value to use for Geneve
+ * @arg link    Link object
+ * @arg ttl     TTL value
+ *
+ * @return 0 on success or a negative error code
+ */
+int rtnl_link_geneve_set_ttl(struct rtnl_link *link, uint8_t ttl)
+{
+        struct geneve_info *geneve = link->l_info;
+
+        IS_GENEVE_LINK_ASSERT(link);
+
+        geneve->ttl = ttl;
+        geneve->mask |= GENEVE_ATTR_TTL;
+
+        return 0;
+}
+
+/**
+ * Get IP TTL value to use for Geneve
+ * @arg link    Link object
+ *
+ * @return TTL value on success or a negative error code
+ */
+int rtnl_link_geneve_get_ttl(struct rtnl_link *link)
+{
+        struct geneve_info *geneve = link->l_info;
+
+        IS_GENEVE_LINK_ASSERT(link);
+
+        if (!(geneve->mask & GENEVE_ATTR_TTL))
+                return -NLE_AGAIN;
+
+        return geneve->ttl;
+}
+
+/**
+ * Set IP ToS value to use for Geneve
+ * @arg link    Link object
+ * @arg tos     ToS value
+ *
+ * @return 0 on success or a negative error code
+ */
+int rtnl_link_geneve_set_tos(struct rtnl_link *link, uint8_t tos)
+{
+        struct geneve_info *geneve = link->l_info;
+
+        IS_GENEVE_LINK_ASSERT(link);
+
+        geneve->tos = tos;
+        geneve->mask |= GENEVE_ATTR_TOS;
+
+        return 0;
+}
+
+/**
+ * Get IP ToS value to use for Geneve
+ * @arg link    Link object
+ *
+ * @return ToS value on success or a negative error code
+ */
+int rtnl_link_geneve_get_tos(struct rtnl_link *link)
+{
+        struct geneve_info *geneve = link->l_info;
+
+        IS_GENEVE_LINK_ASSERT(link);
+
+        if (!(geneve->mask & GENEVE_ATTR_TOS))
+                return -NLE_AGAIN;
+
+        return geneve->tos;
+}
+
+/**
+ * Set UDP destination port to use for Geneve
+ * @arg link    Link object
+ * @arg port    Destination port
+ *
+ * @return 0 on success or a negative error code
+ */
+
+int rtnl_link_geneve_set_port(struct rtnl_link *link,  uint32_t port)
+{
+        struct geneve_info *geneve = link->l_info;
+
+        IS_GENEVE_LINK_ASSERT(link);
+
+        geneve->port = htons(port);
+        geneve->mask |= GENEVE_ATTR_PORT;
+
+        return 0;
+}
+
+/**
+ * Get UDP destination port to use for Geneve
+ * @arg link    Link object
+ * @arg port    Pointer to store destination port
+ *
+ * @return 0 on success or a negative error code
+ */
+int rtnl_link_geneve_get_port(struct rtnl_link *link, uint32_t *port)
+{
+        struct geneve_info *geneve = link->l_info;
+
+        IS_GENEVE_LINK_ASSERT(link);
+
+        if (!port)
+                return -NLE_INVAL;
+
+        if (!(geneve->mask & GENEVE_ATTR_PORT))
+                return -NLE_NOATTR;
+
+        *port = ntohs(geneve->port);
+
+        return 0;
+}
+
+/**
+ * Set flow label to use for Geneve
+ * @arg link    Link object
+ * @arg label   Destination label
+ *
+ * @return 0 on success or a negative error code
+ */
+int rtnl_link_geneve_set_label(struct rtnl_link *link, uint32_t label)
+{
+        struct geneve_info *geneve = link->l_info;
+
+        IS_GENEVE_LINK_ASSERT(link);
+
+        geneve->label = htonl(label);
+        geneve->mask |= GENEVE_ATTR_LABEL;
+
+        return 0;
+}
+
+/**
+ * Get flow label to use for Geneve
+ * @arg link    Link object
+ * @arg label   Pointer to store destination label
+ *
+ * @return 0 on success or a negative error code
+ */
+int rtnl_link_geneve_get_label(struct rtnl_link *link, uint32_t *label)
+{
+        struct geneve_info *geneve = link->l_info;
+
+        IS_GENEVE_LINK_ASSERT(link);
+
+        if (!label)
+                return -NLE_INVAL;
+        if (!(geneve->mask & GENEVE_ATTR_LABEL))
+                return -NLE_NOATTR;
+
+        *label = ntohl(geneve->label);
+
+        return 0;
+}
+
+/**
+ * Set UDP checksum status to use for Geneve
+ * @arg link    Link object
+ * @arg csum    Status value
+ *
+ * @return 0 on success or a negative error code
+ */
+int rtnl_link_geneve_set_udp_csum(struct rtnl_link *link, uint8_t csum)
+{
+        struct geneve_info *geneve = link->l_info;
+
+        IS_GENEVE_LINK_ASSERT(link);
+
+        geneve->udp_csum = csum;
+        geneve->mask |= GENEVE_ATTR_UDP_CSUM;
+
+        return 0;
+}
+
+/**
+ * Get UDP checksum status to use for Geneve
+ * @arg link    Link object
+ *
+ * @return status value on success or a negative error code
+ */
+int rtnl_link_geneve_get_udp_csum(struct rtnl_link *link)
+{
+        struct geneve_info *geneve = link->l_info;
+
+        IS_GENEVE_LINK_ASSERT(link);
+
+        if (!(geneve->mask & GENEVE_ATTR_UDP_CSUM))
+                return -NLE_NOATTR;
+
+        return geneve->udp_csum;
+}
+
+/**
+ * Set skip UDP checksum transmitted over IPv6 status to use for Geneve
+ * @arg link    Link object
+ * @arg csum    Status value
+ *
+ * @return 0 on success or a negative error code
+ */
+int rtnl_link_geneve_set_udp_zero_csum6_tx(struct rtnl_link *link, uint8_t csum)
+{
+        struct geneve_info *geneve = link->l_info;
+
+        IS_GENEVE_LINK_ASSERT(link);
+
+        geneve->udp_zero_csum6_tx = csum;
+        geneve->mask |= GENEVE_ATTR_UDP_ZERO_CSUM6_TX;
+
+        return 0;
+}
+
+/**
+ * Get skip UDP checksum transmitted over IPv6 status to use for Geneve
+ * @arg link    Link object
+ *
+ * @return Status value on success or a negative error code
+ */
+int rtnl_link_geneve_get_udp_zero_csum6_tx(struct rtnl_link *link)
+{
+        struct geneve_info *geneve = link->l_info;
+
+        IS_GENEVE_LINK_ASSERT(link);
+
+        if (!(geneve->mask & GENEVE_ATTR_UDP_ZERO_CSUM6_TX))
+                return -NLE_NOATTR;
+
+        return geneve->udp_zero_csum6_tx;
+}
+
+/**
+ * Set skip UDP checksum received over IPv6 status to use for Geneve
+ * @arg link    Link object
+ * @arg csum    Status value
+ *
+ * @return 0 on success or a negative error code
+ */
+int rtnl_link_geneve_set_udp_zero_csum6_rx(struct rtnl_link *link, uint8_t csum)
+{
+        struct geneve_info *geneve = link->l_info;
+
+        IS_GENEVE_LINK_ASSERT(link);
+
+        geneve->udp_zero_csum6_rx = csum;
+        geneve->mask |= GENEVE_ATTR_UDP_ZERO_CSUM6_RX;
+
+        return 0;
+}
+
+/**
+ * Get skip UDP checksum received over IPv6  status to use for Geneve
+ * @arg link    Link object
+ *
+ * @return Status value on success or a negative error code
+ */
+int rtnl_link_geneve_get_udp_zero_csum6_rx(struct rtnl_link *link)
+{
+        struct geneve_info *geneve = link->l_info;
+
+        IS_GENEVE_LINK_ASSERT(link);
+
+        if (!(geneve->mask & GENEVE_ATTR_UDP_ZERO_CSUM6_RX))
+                return -NLE_NOATTR;
+
+        return geneve->udp_zero_csum6_rx;
+}
+
+/**
+ * Set Geneve flags
+ * @arg link    Link object
+ * @arg flags   Which flags to set
+ * @arg enable  Boolean enabling or disabling flag
+ *
+ * @return 0 on success or a negative error code
+ */
+int rtnl_link_geneve_set_flags(struct rtnl_link *link, uint8_t flags, int enable)
+{
+        struct geneve_info *geneve = link->l_info;
+
+        IS_GENEVE_LINK_ASSERT(link);
+
+        if (flags & ~RTNL_LINK_GENEVE_F_COLLECT_METADATA)
+                return -NLE_INVAL;
+
+        if (enable)
+                geneve->flags = flags;
+        else
+                geneve->flags &= ~flags;
+
+        return 0;
+}
+
+/**
+ * Get Geneve flags
+ * @arg link    Link object
+ * @arg flags   Pointer to store flags
+ *
+ * @return 0 on success or a negative error code
+ */
+int rtnl_link_geneve_get_flags(struct rtnl_link *link, uint8_t *flags)
+{
+        struct geneve_info *geneve = link->l_info;
+
+        IS_GENEVE_LINK_ASSERT(link);
+
+        *flags = geneve->flags;
+        return 0;
+}
+
+/** @} */
+static void __init geneve_init(void)
+{
+        rtnl_link_register_info(&geneve_info_ops);
+}
+
+static void __exit geneve_exit(void)
+{
+        rtnl_link_unregister_info(&geneve_info_ops);
+}
+
+/** @} */
diff --git a/libnl-route-3.sym b/libnl-route-3.sym
index 917aea7..7c531a0 100644
--- a/libnl-route-3.sym
+++ b/libnl-route-3.sym
@@ -1066,4 +1066,26 @@ libnl_3_5 {
 global:
 	rtnl_cls_cache_set_tc_params;
 	rtnl_netem_set_delay_distribution_data;
+        rtnl_link_is_geneve;
+        rtnl_link_geneve_alloc;
+        rtnl_link_geneve_set_id;
+        rtnl_link_geneve_get_id;
+        rtnl_link_geneve_set_remote;
+        rtnl_link_geneve_get_remote;
+        rtnl_link_geneve_set_ttl;
+        rtnl_link_geneve_get_ttl;
+        rtnl_link_geneve_set_tos;
+        rtnl_link_geneve_get_tos;
+        rtnl_link_geneve_set_port;
+        rtnl_link_geneve_get_port;
+        rtnl_link_geneve_set_label;
+        rtnl_link_geneve_get_label;
+        rtnl_link_geneve_set_udp_csum;
+        rtnl_link_geneve_get_udp_csum;
+        rtnl_link_geneve_set_udp_zero_csum6_tx;
+        rtnl_link_geneve_get_udp_zero_csum6_tx;
+        rtnl_link_geneve_set_udp_zero_csum6_rx;
+        rtnl_link_geneve_get_udp_zero_csum6_rx;
+        rtnl_link_geneve_set_flags;
+        rtnl_link_geneve_get_flags;
 } libnl_3_4;
diff --git a/tests/test-create-geneve.c b/tests/test-create-geneve.c
new file mode 100644
index 0000000..37b220a
--- /dev/null
+++ b/tests/test-create-geneve.c
@@ -0,0 +1,87 @@
+#include <netlink/netlink.h>
+#include <netlink/route/link.h>
+#include <netlink/route/link/geneve.h>
+
+#include <linux/netlink.h>
+
+#define IPv6 1
+
+int main(int argc, char *argv[])
+{
+	struct rtnl_link *link;
+	struct nl_addr *addr;
+	struct nl_sock *sk;
+	int err;
+
+	sk = nl_socket_alloc();
+	if ((err = nl_connect(sk, NETLINK_ROUTE)) < 0) {
+		nl_perror(err, "Unable to connect socket");
+		return err;
+	}
+
+	link = rtnl_link_geneve_alloc();
+
+	rtnl_link_set_name(link, "gnv123");
+
+	if ((err = rtnl_link_geneve_set_id(link, 123)) < 0) {
+		nl_perror(err, "Unable to set GENEVE ID");
+		return err;
+	}
+
+#if IPv6
+	if ((err = nl_addr_parse("2001:0db8:0:f101::1/64", AF_INET6, &addr)) < 0) {
+		nl_perror(err,  "Unable to parse IPv6 address");
+		return err;
+	}
+	if ((err = rtnl_link_geneve_set_label(link, 123)) < 0) {
+		nl_perror(err, "Unable to set label");
+		return err;
+	}
+
+	if ((err = rtnl_link_geneve_set_udp_zero_csum6_tx(link, 1)) < 0) {
+		nl_perror(err, "Unable to set skip transmitted UDP checksum");
+		return err;
+	}
+
+	if ((err = rtnl_link_geneve_set_udp_zero_csum6_rx(link, 1)) < 0) {
+		nl_perror(err, "Unable to set skip received UDP checksum");
+		return err;
+	}
+#else
+	if ((err = nl_addr_parse("10.4.4.4", AF_INET, &addr)) < 0) {
+		nl_perror(err, "Unable to parse IP address");
+		return err;
+	}
+#endif
+
+	if ((err = rtnl_link_geneve_set_remote(link, addr)) < 0) {
+		nl_perror(err, "Unable to set remote address");
+		return err;
+	}
+	nl_addr_put(addr);
+
+	if ((err = rtnl_link_geneve_set_ttl(link, 1)) < 0) {
+		nl_perror(err, "Unable to set TTL");
+		return err;
+	}
+
+	if ((err = rtnl_link_geneve_set_tos(link, 0)) < 0) {
+		nl_perror(err, "Unable to set ToS");
+		return err;
+	}
+
+	if ((err = rtnl_link_geneve_set_port(link, 5060)) < 0) {
+		nl_perror(err, "Unable to set port");
+		return err;
+	}
+
+	if ((err = rtnl_link_add(sk, link, NLM_F_CREATE)) < 0) {
+		nl_perror(err, "Unable to add link");
+		return err;
+	}
+
+	rtnl_link_put(link);
+	nl_close(sk);
+
+	return 0;
+}
-- 
2.7.4




More information about the libnl mailing list