]> git.ipfire.org Git - thirdparty/libnl.git/commitdiff
link/inet6: add link IPv6 address generation mode support
authorDan Williams <dcbw@redhat.com>
Fri, 25 Jul 2014 19:36:29 +0000 (14:36 -0500)
committerThomas Haller <thaller@redhat.com>
Wed, 30 Jul 2014 16:45:51 +0000 (18:45 +0200)
Signed-off-by: Dan Williams <dcbw@redhat.com>
Signed-off-by: Thomas Haller <thaller@redhat.com>
include/Makefile.am
include/netlink/route/link/inet6.h [new file with mode: 0644]
lib/route/link/inet6.c

index 9833defc26d69a06fd409b4f27d3c80c3feb33e8..90f647c4b29513b6bbbf2353008459c9d4e9dc46 100644 (file)
@@ -48,6 +48,7 @@ nobase_libnlinclude_HEADERS = \
        netlink/route/link/bridge.h \
        netlink/route/link/can.h \
        netlink/route/link/inet.h \
+       netlink/route/link/inet6.h \
        netlink/route/link/info-api.h \
        netlink/route/link/macvlan.h \
        netlink/route/link/vlan.h \
diff --git a/include/netlink/route/link/inet6.h b/include/netlink/route/link/inet6.h
new file mode 100644 (file)
index 0000000..8ffeab2
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * netlink/route/link/inet6.h  INET6 Link Module
+ *
+ *     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) 2014 Dan Williams <dcbw@redhat.com>
+ */
+
+#ifndef NETLINK_LINK_INET6_H_
+#define NETLINK_LINK_INET6_H_
+
+#include <netlink/netlink.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+const char *           rtnl_link_inet6_addrgenmode2str  (uint8_t mode,
+                                                         char *buf,
+                                                         size_t len);
+
+uint8_t                        rtnl_link_inet6_str2addrgenmode  (const char *mode);
+
+extern int             rtnl_link_inet6_get_addr_gen_mode(struct rtnl_link *,
+                                                         uint8_t *);
+
+extern int             rtnl_link_inet6_set_addr_gen_mode(struct rtnl_link *,
+                                                         uint8_t);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
index feb02263ac4e0da975b3fa463c66417612217413..0f096fcadff5f7e6ac73b1f4642338c06bdb9d79 100644 (file)
 #include <netlink/route/rtnl.h>
 #include <netlink-private/route/link/api.h>
 
+#define I6_ADDR_GEN_MODE_UNKNOWN       UINT8_MAX
+
 struct inet6_data
 {
        uint32_t                i6_flags;
        struct ifla_cacheinfo   i6_cacheinfo;
        uint32_t                i6_conf[DEVCONF_MAX];
+       uint8_t                 i6_addr_gen_mode;
 };
 
 static void *inet6_alloc(struct rtnl_link *link)
 {
-       return calloc(1, sizeof(struct inet6_data));
+       struct inet6_data *i6;
+
+       i6 = calloc(1, sizeof(struct inet6_data));
+       if (i6)
+               i6->i6_addr_gen_mode = I6_ADDR_GEN_MODE_UNKNOWN;
+
+       return i6;
 }
 
 static void *inet6_clone(struct rtnl_link *link, void *data)
@@ -43,11 +52,12 @@ static void inet6_free(struct rtnl_link *link, void *data)
 }
 
 static struct nla_policy inet6_policy[IFLA_INET6_MAX+1] = {
-       [IFLA_INET6_FLAGS]      = { .type = NLA_U32 },
-       [IFLA_INET6_CACHEINFO]  = { .minlen = sizeof(struct ifla_cacheinfo) },
-       [IFLA_INET6_CONF]       = { .minlen = 4 },
-       [IFLA_INET6_STATS]      = { .minlen = 8 },
-       [IFLA_INET6_ICMP6STATS] = { .minlen = 8 },
+       [IFLA_INET6_FLAGS]              = { .type = NLA_U32 },
+       [IFLA_INET6_CACHEINFO]          = { .minlen = sizeof(struct ifla_cacheinfo) },
+       [IFLA_INET6_CONF]               = { .minlen = 4 },
+       [IFLA_INET6_STATS]              = { .minlen = 8 },
+       [IFLA_INET6_ICMP6STATS]         = { .minlen = 8 },
+       [IFLA_INET6_ADDR_GEN_MODE]      = { .type = NLA_U8 },
 };
 
 static const uint8_t map_stat_id_from_IPSTATS_MIB_v1[__IPSTATS_MIB_MAX] = {
@@ -155,7 +165,10 @@ static int inet6_parse_protinfo(struct rtnl_link *link, struct nlattr *attr,
        if (tb[IFLA_INET6_CONF])
                nla_memcpy(&i6->i6_conf, tb[IFLA_INET6_CONF],
                           sizeof(i6->i6_conf));
+
+       if (tb[IFLA_INET6_ADDR_GEN_MODE])
+               i6->i6_addr_gen_mode = nla_get_u8 (tb[IFLA_INET6_ADDR_GEN_MODE]);
+
        /*
         * Due to 32bit data alignment, these addresses must be copied to an
         * aligned location prior to access.
@@ -200,6 +213,19 @@ static int inet6_parse_protinfo(struct rtnl_link *link, struct nlattr *attr,
        return 0;
 }
 
+static int inet6_fill_af(struct rtnl_link *link, struct nl_msg *msg, void *data)
+{
+       struct inet6_data *id = data;
+
+       if (id->i6_addr_gen_mode != I6_ADDR_GEN_MODE_UNKNOWN)
+               NLA_PUT_U8(msg, IFLA_INET6_ADDR_GEN_MODE, id->i6_addr_gen_mode);
+
+       return 0;
+
+nla_put_failure:
+       return -NLE_MSGSIZE;
+}
+
 /* These live in include/net/if_inet6.h and should be moved to include/linux */
 #define IF_RA_OTHERCONF        0x80
 #define IF_RA_MANAGED  0x40
@@ -259,6 +285,22 @@ static char *inet6_devconf2str(int type, char *buf, size_t len)
                          ARRAY_SIZE(inet6_devconf));
 }
 
+static const struct trans_tbl inet6_addr_gen_mode[] = {
+       __ADD(IN6_ADDR_GEN_MODE_EUI64, eui64),
+       __ADD(IN6_ADDR_GEN_MODE_NONE, none),
+};
+
+const char *rtnl_link_inet6_addrgenmode2str(uint8_t mode, char *buf, size_t len)
+{
+       return __type2str(mode, buf, len, inet6_addr_gen_mode,
+                         ARRAY_SIZE(inet6_addr_gen_mode));
+}
+
+uint8_t rtnl_link_inet6_str2addrgenmode(const char *mode)
+{
+       return (uint8_t) __str2type(mode, inet6_addr_gen_mode,
+                                   ARRAY_SIZE(inet6_addr_gen_mode));
+}
 
 static void inet6_dump_details(struct rtnl_link *link,
                                struct nl_dump_params *p, void *data)
@@ -281,6 +323,10 @@ static void inet6_dump_details(struct rtnl_link *link,
        nl_dump(p, " retrans-time %s\n",
                nl_msec2str(i6->i6_cacheinfo.retrans_time, buf, sizeof(buf)));
 
+       nl_dump(p, " link-local address mode %s\n",
+               rtnl_link_inet6_addrgenmode2str(i6->i6_addr_gen_mode,
+                                               buf, sizeof(buf)));
+
        nl_dump_line(p, "      devconf:\n");
        nl_dump_line(p, "      ");
 
@@ -468,11 +514,60 @@ static struct rtnl_link_af_ops inet6_ops = {
        .ao_free                        = &inet6_free,
        .ao_parse_protinfo              = &inet6_parse_protinfo,
        .ao_parse_af                    = &inet6_parse_protinfo,
+       .ao_fill_af                     = &inet6_fill_af,
        .ao_dump[NL_DUMP_DETAILS]       = &inet6_dump_details,
        .ao_dump[NL_DUMP_STATS]         = &inet6_dump_stats,
        .ao_protinfo_policy             = &protinfo_policy,
 };
 
+/**
+ * Get IPv6 link-local address generation mode
+ * @arg link           Link object
+ * @arg mode           Generation mode on success
+ *
+ * Returns the link's IPv6 link-local address generation mode.
+ *
+ * @return 0 on success
+ * @return -NLE_NOATTR configuration setting not available
+ * @return -NLE_INVAL generation mode unknown. If the link was received via
+ *                    netlink, it means that address generation mode is not
+ *                    supported by the kernel.
+ */
+int rtnl_link_inet6_get_addr_gen_mode(struct rtnl_link *link, uint8_t *mode)
+{
+       struct inet6_data *id;
+
+       if (!(id = rtnl_link_af_data(link, &inet6_ops)))
+               return -NLE_NOATTR;
+
+       if (id->i6_addr_gen_mode == I6_ADDR_GEN_MODE_UNKNOWN)
+               return -NLE_INVAL;
+
+       *mode = id->i6_addr_gen_mode;
+       return 0;
+}
+
+/**
+ * Set IPv6 link-local address generation mode
+ * @arg link           Link object
+ * @arg mode           Generation mode
+ *
+ * Sets the link's IPv6 link-local address generation mode.
+ *
+ * @return 0 on success
+ * @return -NLE_NOMEM could not allocate inet6 data
+ */
+int rtnl_link_inet6_set_addr_gen_mode(struct rtnl_link *link, uint8_t mode)
+{
+       struct inet6_data *id;
+
+       if (!(id = rtnl_link_af_alloc(link, &inet6_ops)))
+               return -NLE_NOMEM;
+
+       id->i6_addr_gen_mode = mode;
+       return 0;
+}
+
 static void __init inet6_init(void)
 {
        rtnl_link_af_register(&inet6_ops);