[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