]> granicus.if.org Git - libnl/commitdiff
xfrmi: introduce XFRM interfaces support
authorEyal Birger <eyal.birger@gmail.com>
Sun, 7 Apr 2019 14:09:34 +0000 (17:09 +0300)
committerThomas Haller <thaller@redhat.com>
Sun, 1 Sep 2019 12:24:52 +0000 (14:24 +0200)
XFRM interfaces were introduced in kernel 4.19.
This commit adds link support for these interfaces.

Signed-off-by: Eyal Birger <eyal.birger@gmail.com>
Makefile.am
doc/route.txt
include/netlink/route/link/xfrmi.h [new file with mode: 0644]
lib/route/link/xfrmi.c [new file with mode: 0644]
libnl-route-3.sym
tests/.gitignore
tests/test-create-xfrmi.c [new file with mode: 0644]

index 88830be281858103c5ada21c5fc8dca9b6423395..b2e87379ca1f51fa6bc68bfbb47af11fa36584f5 100644 (file)
@@ -166,6 +166,7 @@ libnlinclude_netlink_route_link_HEADERS = \
        include/netlink/route/link/vlan.h \
        include/netlink/route/link/vrf.h \
        include/netlink/route/link/vxlan.h \
+       include/netlink/route/link/xfrmi.h \
        $(NULL)
 libnlinclude_netlink_route_qdiscdir = $(libnlincludedir)/netlink/route/qdisc
 libnlinclude_netlink_route_qdisc_HEADERS = \
@@ -412,6 +413,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/xfrmi.c \
        lib/route/neigh.c \
        lib/route/neightbl.c \
        lib/route/netconf.c \
@@ -852,6 +854,7 @@ check_PROGRAMS += \
        tests/test-create-vlan \
        tests/test-create-vrf \
        tests/test-create-vxlan \
+       tests/test-create-xfrmi \
        tests/test-delete-link \
        tests/test-loopback-up-down \
        tests/test-socket-creation \
@@ -896,6 +899,8 @@ tests_test_create_vrf_CPPFLAGS                    = $(tests_cppflags)
 tests_test_create_vrf_LDADD                       = $(tests_ldadd)
 tests_test_create_vxlan_CPPFLAGS                  = $(tests_cppflags)
 tests_test_create_vxlan_LDADD                     = $(tests_ldadd)
+tests_test_create_xfrmi_CPPFLAGS                  = $(tests_cppflags)
+tests_test_create_xfrmi_LDADD                     = $(tests_ldadd)
 tests_test_delete_link_CPPFLAGS                   = $(tests_cppflags)
 tests_test_delete_link_LDADD                      = $(tests_ldadd)
 tests_test_loopback_up_down_CPPFLAGS              = $(tests_cppflags)
index 6a0dbb9d97b7030d5b734e8dbd17461a2f3cf6c8..9d4c23aacfa449488c4b645494f318888722d103 100644 (file)
@@ -1257,6 +1257,49 @@ rtnl_link_put(link);
 -----
 
 
+[[link_xfrmi]]
+==== XFRMI
+
+[source,c]
+-----
+extern struct rtnl_link *rtnl_link_xfrmi_alloc(void);
+
+extern int rtnl_link_xfrmi_set_link(struct rtnl_link *link,  uint32_t index);
+extern uint32_t rtnl_link_xfrmi_get_link(struct rtnl_link *link);
+
+extern int rtnl_link_xfrmi_set_if_id(struct rtnl_link *link, uint32_t if_id);
+extern uint32_t rtnl_link_xfrmi_get_if_id(struct rtnl_link *link);
+
+-----
+
+.Example: Add a xfrmi device
+[source,c]
+-----
+struct rtnl_link *link
+struct in_addr addr
+
+/* allocate new link object of type xfrmi */
+if(!(link = rtnl_link_xfrmi_alloc()))
+       /* error */
+
+/* set xfrmi name */
+if ((err = rtnl_link_set_name(link, "ipsec0")) < 0)
+       /* error */
+
+/* set link index  */
+if ((err = rtnl_link_xfrmi_set_link(link, if_index)) < 0)
+       /* error */
+
+/* set if_id */
+if ((err = rtnl_link_xfrmi_set_if_id(link, 16)) < 0)
+       /* error */
+
+if((err = rtnl_link_add(sk, link, NLM_F_CREATE)) < 0)
+       /* error */
+
+rtnl_link_put(link);
+-----
+
 == Neighbouring
 
 == Routing
diff --git a/include/netlink/route/link/xfrmi.h b/include/netlink/route/link/xfrmi.h
new file mode 100644 (file)
index 0000000..f361229
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * netlink/route/link/xfrmi.h          XFRMI 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.
+ *
+ * Copyright (c) 2019 Eyal Birger <eyal.birger@gmail.com>
+ *
+ * Based on netlink/route/link/ipvti.h
+ */
+
+#ifndef NETLINK_LINK_XFRMI_H_
+#define NETLINK_LINK_XFRMI_H_
+
+#include <netlink/netlink.h>
+#include <netlink/route/link.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+       extern struct rtnl_link *rtnl_link_xfrmi_alloc(void);
+
+       extern int rtnl_link_is_xfrmi(struct rtnl_link *link);
+
+       extern int rtnl_link_xfrmi_set_link(struct rtnl_link *link,  uint32_t index);
+       extern uint32_t rtnl_link_xfrmi_get_link(struct rtnl_link *link);
+
+       extern int rtnl_link_xfrmi_set_if_id(struct rtnl_link *link, uint32_t if_id);
+       extern uint32_t rtnl_link_xfrmi_get_if_id(struct rtnl_link *link);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/lib/route/link/xfrmi.c b/lib/route/link/xfrmi.c
new file mode 100644 (file)
index 0000000..65533a6
--- /dev/null
@@ -0,0 +1,312 @@
+/*
+ * lib/route/link/xfrmi.c       XFRMI 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) 2019 Eyal Birger <eyal.birger@gmail.com>
+ *
+ * Based on lib/route/link/ipvti.c
+ */
+
+/**
+ * @ingroup link
+ * @defgroup xfrmi XFRMI
+ * xfrmi link module
+ *
+ * @details
+ * \b Link Type Name: "xfrmi"
+ *
+ * @route_doc{link_xfrmi, XFRMI Documentation}
+ *
+ * @{
+ */
+
+#include <netlink-private/netlink.h>
+#include <netlink/netlink.h>
+#include <netlink/attr.h>
+#include <netlink/utils.h>
+#include <netlink/object.h>
+#include <netlink/route/rtnl.h>
+#include <netlink/route/link/xfrmi.h>
+#include <netlink-private/route/link/api.h>
+
+#define XFRMI_ATTR_LINK  (1 << 0)
+#define XFRMI_ATTR_IF_ID (1 << 1)
+
+#define XFRMI_LINK_TYPE_NAME "xfrm"
+
+struct xfrmi_info {
+       uint32_t link;
+       uint32_t if_id;
+       uint32_t xfrmi_mask;
+};
+
+static struct nla_policy xfrmi_policy[IFLA_XFRM_MAX + 1] = {
+       [IFLA_XFRM_LINK]  = { .type = NLA_U32 },
+       [IFLA_XFRM_IF_ID] = { .type = NLA_U32 },
+};
+
+static int xfrmi_alloc(struct rtnl_link *link)
+{
+       struct xfrmi_info *xfrmi;
+
+       if (link->l_info)
+               memset(link->l_info, 0, sizeof(*xfrmi));
+       else {
+               xfrmi = calloc(1, sizeof(*xfrmi));
+               if (!xfrmi)
+                       return -NLE_NOMEM;
+
+               link->l_info = xfrmi;
+       }
+
+       return 0;
+}
+
+static int xfrmi_parse(struct rtnl_link *link, struct nlattr *data,
+                      struct nlattr *xstats)
+{
+       struct nlattr *tb[IFLA_XFRM_MAX + 1];
+       struct xfrmi_info *xfrmi;
+       int err;
+
+       NL_DBG(3, "Parsing XFRMI link info\n");
+
+       err = nla_parse_nested(tb, IFLA_XFRM_MAX, data, xfrmi_policy);
+       if (err < 0)
+               goto errout;
+
+       err = xfrmi_alloc(link);
+       if (err < 0)
+               goto errout;
+
+       xfrmi = link->l_info;
+
+       if (tb[IFLA_XFRM_LINK]) {
+               xfrmi->link = nla_get_u32(tb[IFLA_XFRM_LINK]);
+               xfrmi->xfrmi_mask |= XFRMI_ATTR_LINK;
+       }
+
+       if (tb[IFLA_XFRM_IF_ID]) {
+               xfrmi->if_id = nla_get_u32(tb[IFLA_XFRM_IF_ID]);
+               xfrmi->xfrmi_mask |= XFRMI_ATTR_IF_ID;
+       }
+
+       err = 0;
+
+errout:
+       return err;
+}
+
+static int xfrmi_put_attrs(struct nl_msg *msg, struct rtnl_link *link)
+{
+       struct xfrmi_info *xfrmi = link->l_info;
+       struct nlattr *data;
+
+       data = nla_nest_start(msg, IFLA_INFO_DATA);
+       if (!data)
+               return -NLE_MSGSIZE;
+
+       if (xfrmi->xfrmi_mask & XFRMI_ATTR_LINK)
+               NLA_PUT_U32(msg, IFLA_XFRM_LINK, xfrmi->link);
+
+       if (xfrmi->xfrmi_mask & XFRMI_ATTR_IF_ID)
+               NLA_PUT_U32(msg, IFLA_XFRM_IF_ID, xfrmi->if_id);
+
+       nla_nest_end(msg, data);
+
+nla_put_failure:
+       return 0;
+}
+
+static void xfrmi_free(struct rtnl_link *link)
+{
+       struct xfrmi_info *xfrmi = link->l_info;
+
+       free(xfrmi);
+       link->l_info = NULL;
+}
+
+static void xfrmi_dump_line(struct rtnl_link *link, struct nl_dump_params *p)
+{
+       nl_dump(p, "xfrmi : %s", link->l_name);
+}
+
+static void xfrmi_dump_details(struct rtnl_link *link, struct nl_dump_params *p)
+{
+       struct xfrmi_info *xfrmi = link->l_info;
+
+       if (xfrmi->xfrmi_mask & XFRMI_ATTR_LINK) {
+               struct rtnl_link *parent;
+               char *name;
+
+               nl_dump(p, "      link ");
+
+               name = NULL;
+               parent = link_lookup(link->ce_cache, xfrmi->link);
+               if (parent)
+                       name = rtnl_link_get_name(parent);
+
+               if (name)
+                       nl_dump_line(p, "%s\n", name);
+               else
+                       nl_dump_line(p, "%u\n", xfrmi->link);
+       }
+
+       if (xfrmi->xfrmi_mask & XFRMI_ATTR_IF_ID) {
+               nl_dump(p, "      if_id   ");
+               nl_dump_line(p, "%x\n", xfrmi->if_id);
+       }
+}
+
+static int xfrmi_clone(struct rtnl_link *dst, struct rtnl_link *src)
+{
+       struct xfrmi_info *xfrmi_dst, *xfrmi_src = src->l_info;
+       int err;
+
+       dst->l_info = NULL;
+
+       err = rtnl_link_set_type(dst, XFRMI_LINK_TYPE_NAME);
+       if (err < 0)
+               return err;
+
+       xfrmi_dst = dst->l_info;
+
+       if (!xfrmi_dst || !xfrmi_src)
+               BUG();
+
+       memcpy(xfrmi_dst, xfrmi_src, sizeof(struct xfrmi_info));
+
+       return 0;
+}
+
+static struct rtnl_link_info_ops xfrmi_info_ops = {
+       .io_name                = XFRMI_LINK_TYPE_NAME,
+       .io_alloc               = xfrmi_alloc,
+       .io_parse               = xfrmi_parse,
+       .io_dump = {
+               [NL_DUMP_LINE]  = xfrmi_dump_line,
+               [NL_DUMP_DETAILS] = xfrmi_dump_details,
+       },
+       .io_clone               = xfrmi_clone,
+       .io_put_attrs           = xfrmi_put_attrs,
+       .io_free                = xfrmi_free,
+};
+
+#define IS_XFRMI_LINK_ASSERT(link) do { \
+               if ((link)->l_info_ops != &xfrmi_info_ops) { \
+                       APPBUG("Link is not a xfrmi link. set type \"xfrmi\" first."); \
+                       return -NLE_OPNOTSUPP; \
+               } \
+       } while(0)
+
+struct rtnl_link *rtnl_link_xfrmi_alloc(void)
+{
+       struct rtnl_link *link;
+       int err;
+
+       link = rtnl_link_alloc();
+       if (!link)
+               return NULL;
+
+       err = rtnl_link_set_type(link, XFRMI_LINK_TYPE_NAME);
+       if (err < 0) {
+               rtnl_link_put(link);
+               return NULL;
+       }
+
+       return link;
+}
+
+/**
+ * Check if link is a XFRMI link
+ * @arg link            Link object
+ *
+ * @return True if link is a IXFRMI link, otherwise 0 is returned.
+ */
+int rtnl_link_is_xfrmi(struct rtnl_link *link)
+{
+       return link->l_info_ops && !strcmp(link->l_info_ops->io_name,
+                                          XFRMI_LINK_TYPE_NAME);
+}
+
+/**
+ * Set XFRMI link interface index
+ * @arg link            Link object
+ * @arg index           interface index
+ *
+ * @return 0 on success or a negative error code
+ */
+int rtnl_link_xfrmi_set_link(struct rtnl_link *link, uint32_t index)
+{
+       struct xfrmi_info *xfrmi = link->l_info;
+
+       IS_XFRMI_LINK_ASSERT(link);
+
+       xfrmi->link = index;
+       xfrmi->xfrmi_mask |= XFRMI_ATTR_LINK;
+
+       return 0;
+}
+
+/**
+ * Get XFRMI link interface index
+ * @arg link            Link object
+ *
+ * @return interface index
+ */
+uint32_t rtnl_link_xfrmi_get_link(struct rtnl_link *link)
+{
+       struct xfrmi_info *xfrmi = link->l_info;
+
+       IS_XFRMI_LINK_ASSERT(link);
+
+       return xfrmi->link;
+}
+
+/**
+ * Set XFRMI if_id
+ * @arg link            Link object
+ * @arg if_id            xfrm if_id
+ *
+ * @return 0 on success or a negative error code
+ */
+int rtnl_link_xfrmi_set_if_id(struct rtnl_link *link, uint32_t if_id)
+{
+       struct xfrmi_info *xfrmi = link->l_info;
+
+       IS_XFRMI_LINK_ASSERT(link);
+
+       xfrmi->if_id = if_id;
+       xfrmi->xfrmi_mask |= XFRMI_ATTR_IF_ID;
+
+       return 0;
+}
+
+/**
+ * Get XFRMI if_id
+ * @arg link            Link object
+ *
+ * @return if_id
+ */
+uint32_t rtnl_link_xfrmi_get_if_id(struct rtnl_link *link)
+{
+       struct xfrmi_info *xfrmi = link->l_info;
+
+       IS_XFRMI_LINK_ASSERT(link);
+
+       return xfrmi->if_id;
+}
+
+static void __init xfrmi_init(void)
+{
+       rtnl_link_register_info(&xfrmi_info_ops);
+}
+
+static void __exit xfrmi_exit(void)
+{
+       rtnl_link_unregister_info(&xfrmi_info_ops);
+}
index 5a82d85701f620feca440096e3d40825eafa0e5d..9925a41461b37417cf28ef3afbfcbee418ed0dd2 100644 (file)
@@ -1090,6 +1090,12 @@ global:
        rtnl_link_get_slave_type;
        rtnl_link_is_geneve;
        rtnl_link_set_slave_type;
+       rtnl_link_is_xfrmi;
+       rtnl_link_xfrmi_alloc;
+       rtnl_link_xfrmi_get_link;
+       rtnl_link_xfrmi_get_if_id;
+       rtnl_link_xfrmi_set_link;
+       rtnl_link_xfrmi_set_if_id;
        rtnl_mall_append_action;
        rtnl_mall_del_action;
        rtnl_mall_get_classid;
index 425a7c47e9828dc40e9630677f11af7a4470fc8a..90af67ad2460cd0022c68a4e51a32e997d363bc3 100644 (file)
@@ -23,6 +23,7 @@
 /test-create-vlan
 /test-create-vrf
 /test-create-vxlan
+/test-create-xfrmi
 /test-delete-link
 /test-genl
 /test-loopback-up-down
diff --git a/tests/test-create-xfrmi.c b/tests/test-create-xfrmi.c
new file mode 100644 (file)
index 0000000..3a01a4f
--- /dev/null
@@ -0,0 +1,49 @@
+#include <netlink/route/link/xfrmi.h>
+#include <netlink-private/netlink.h>
+
+int main(int argc, char *argv[])
+{
+       struct nl_cache *link_cache;
+       struct rtnl_link *link;
+       struct nl_sock *sk;
+       int err, if_index;
+
+       sk = nl_socket_alloc();
+       if ((err = nl_connect(sk, NETLINK_ROUTE)) < 0) {
+               nl_perror(err, "Unable to connect socket");
+               return err;
+       }
+
+       err = rtnl_link_alloc_cache(sk, AF_UNSPEC, &link_cache);
+       if (err < 0) {
+               nl_perror(err, "Unable to allocate cache");
+               return err;
+       }
+
+       if_index = rtnl_link_name2i(link_cache, "eth0");
+       if (!if_index) {
+               fprintf(stderr, "Unable to lookup eth0");
+               return -1;
+       }
+
+       link = rtnl_link_xfrmi_alloc();
+       if (!link) {
+               nl_perror(err, "Unable to allocate link");
+               return -1;
+
+       }
+
+       rtnl_link_set_name(link, "ipsec0");
+       rtnl_link_xfrmi_set_link(link, if_index);
+       rtnl_link_xfrmi_set_if_id(link, 16);
+
+       err = rtnl_link_add(sk, link, NLM_F_CREATE);
+       if (err < 0) {
+               nl_perror(err, "Unable to add link");
+               return err;
+       }
+
+       rtnl_link_put(link);
+       nl_close(sk);
+       return 0;
+}