summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Graf <tgraf@suug.ch>2010-11-11 23:15:28 +0100
committerThomas Graf <tgraf@suug.ch>2010-11-11 23:15:28 +0100
commita4efc65c3a0fcf2a56336290e94ba58c212873db (patch)
tree10e913eac2c1a41214efbbeebc4397dee9bace35
parente69efadc46c1395a281a540d9721c8f8af0c8a22 (diff)
downloadlibnl-a4efc65c3a0fcf2a56336290e94ba58c212873db.tar.gz
link: Add support for IPv6 specific link data
- parses IFLA_PROTINFO - dumps flags, cacheinfo, devconf and all statistics
-rw-r--r--lib/Makefile.am2
-rw-r--r--lib/route/link/inet6.c327
2 files changed, 328 insertions, 1 deletions
diff --git a/lib/Makefile.am b/lib/Makefile.am
index c1277be..4aafb3b 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -59,7 +59,7 @@ libnl_route_la_SOURCES = \
route/cls/ematch/meta.c \
\
route/link/api.c route/link/vlan.c \
- route/link/bridge.c \
+ route/link/bridge.c route/link/inet6.c \
\
route/sch/blackhole.c route/sch/cbq.c route/sch/dsmark.c \
route/sch/fifo.c route/sch/htb.c route/sch/netem.c route/sch/prio.c \
diff --git a/lib/route/link/inet6.c b/lib/route/link/inet6.c
new file mode 100644
index 0000000..e368404
--- /dev/null
+++ b/lib/route/link/inet6.c
@@ -0,0 +1,327 @@
+/*
+ * lib/route/link/inet6.c AF_INET6 link operations
+ *
+ * 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) 2010 Thomas Graf <tgraf@suug.ch>
+ */
+
+#include <netlink-local.h>
+#include <netlink/netlink.h>
+#include <netlink/attr.h>
+#include <netlink/route/rtnl.h>
+#include <netlink/route/link/api.h>
+
+struct inet6_data
+{
+ uint32_t i6_flags;
+ struct ifla_cacheinfo i6_cacheinfo;
+ uint32_t i6_conf[DEVCONF_MAX];
+};
+
+static void *inet6_alloc(struct rtnl_link *link)
+{
+ return calloc(1, sizeof(struct inet6_data));
+}
+
+static void *inet6_clone(struct rtnl_link *link, void *data)
+{
+ struct inet6_data *i6;
+
+ if ((i6 = inet6_alloc(link)))
+ memcpy(i6, data, sizeof(*i6));
+
+ return i6;
+}
+
+static void inet6_free(struct rtnl_link *link, void *data)
+{
+ free(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 = DEVCONF_MAX * 4 },
+ [IFLA_INET6_STATS] = { .minlen = __IPSTATS_MIB_MAX * 8 },
+ [IFLA_INET6_ICMP6STATS] = { .minlen = __ICMP6_MIB_MAX * 8 },
+};
+
+static int inet6_parse_protinfo(struct rtnl_link *link, struct nlattr *attr,
+ void *data)
+{
+ struct inet6_data *i6 = data;
+ struct nlattr *tb[IFLA_INET6_MAX+1];
+ int err;
+
+ err = nla_parse_nested(tb, IFLA_INET6_MAX, attr, inet6_policy);
+ if (err < 0)
+ return err;
+
+ if (tb[IFLA_INET6_FLAGS])
+ i6->i6_flags = nla_get_u32(tb[IFLA_INET6_FLAGS]);
+
+ if (tb[IFLA_INET6_CACHEINFO])
+ nla_memcpy(&i6->i6_cacheinfo, tb[IFLA_INET6_CACHEINFO],
+ sizeof(i6->i6_cacheinfo));
+
+ if (tb[IFLA_INET6_CONF])
+ nla_memcpy(&i6->i6_conf, tb[IFLA_INET6_CONF],
+ sizeof(i6->i6_conf));
+
+ if (tb[IFLA_INET6_STATS]) {
+ uint64_t *cnt = nla_data(tb[IFLA_INET6_STATS]);
+ int i;
+
+ for (i = 1; i < __IPSTATS_MIB_MAX; i++)
+ rtnl_link_set_stat(link, RTNL_LINK_INPKTS, cnt[i-1]);
+ }
+
+ if (tb[IFLA_INET6_ICMP6STATS]) {
+ uint64_t *cnt = nla_data(tb[IFLA_INET6_STATS]);
+ int i;
+
+ for (i = 1; i < __ICMP6_MIB_MAX; i++)
+ rtnl_link_set_stat(link, RTNL_LINK_ICMP6_INMSGS, cnt[i-1]);
+ }
+
+ return 0;
+}
+
+/* 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
+#define IF_RA_RCVD 0x20
+#define IF_RS_SENT 0x10
+#define IF_READY 0x80000000
+
+static struct trans_tbl inet6_flags[] = {
+ __ADD(IF_RA_OTHERCONF, ra_otherconf)
+ __ADD(IF_RA_MANAGED, ra_managed)
+ __ADD(IF_RA_RCVD, ra_rcvd)
+ __ADD(IF_RS_SENT, rs_sent)
+ __ADD(IF_READY, ready)
+};
+
+static char *inet6_flags2str(int flags, char *buf, size_t len)
+{
+ return __flags2str(flags, buf, len, inet6_flags,
+ ARRAY_SIZE(inet6_flags));
+}
+
+static struct trans_tbl inet6_devconf[] = {
+ __ADD(DEVCONF_FORWARDING, forwarding)
+ __ADD(DEVCONF_HOPLIMIT, hoplimit)
+ __ADD(DEVCONF_MTU6, mtu6)
+ __ADD(DEVCONF_ACCEPT_RA, accept_ra)
+ __ADD(DEVCONF_ACCEPT_REDIRECTS, accept_redirects)
+ __ADD(DEVCONF_AUTOCONF, autoconf)
+ __ADD(DEVCONF_DAD_TRANSMITS, dad_transmits)
+ __ADD(DEVCONF_RTR_SOLICITS, rtr_solicits)
+ __ADD(DEVCONF_RTR_SOLICIT_INTERVAL, rtr_solicit_interval)
+ __ADD(DEVCONF_RTR_SOLICIT_DELAY, rtr_solicit_delay)
+ __ADD(DEVCONF_USE_TEMPADDR, use_tempaddr)
+ __ADD(DEVCONF_TEMP_VALID_LFT, temp_valid_lft)
+ __ADD(DEVCONF_TEMP_PREFERED_LFT, temp_prefered_lft)
+ __ADD(DEVCONF_REGEN_MAX_RETRY, regen_max_retry)
+ __ADD(DEVCONF_MAX_DESYNC_FACTOR, max_desync_factor)
+ __ADD(DEVCONF_MAX_ADDRESSES, max_addresses)
+ __ADD(DEVCONF_FORCE_MLD_VERSION, force_mld_version)
+ __ADD(DEVCONF_ACCEPT_RA_DEFRTR, accept_ra_defrtr)
+ __ADD(DEVCONF_ACCEPT_RA_PINFO, accept_ra_pinfo)
+ __ADD(DEVCONF_ACCEPT_RA_RTR_PREF, accept_ra_rtr_pref)
+ __ADD(DEVCONF_RTR_PROBE_INTERVAL, rtr_probe_interval)
+ __ADD(DEVCONF_ACCEPT_RA_RT_INFO_MAX_PLEN, accept_ra_rt_info)
+ __ADD(DEVCONF_PROXY_NDP, proxy_ndp)
+ __ADD(DEVCONF_OPTIMISTIC_DAD, optimistic_dad)
+ __ADD(DEVCONF_ACCEPT_SOURCE_ROUTE, accept_source_route)
+ __ADD(DEVCONF_MC_FORWARDING, mc_forwarding)
+ __ADD(DEVCONF_DISABLE_IPV6, disable_ipv6)
+ __ADD(DEVCONF_ACCEPT_DAD, accept_dad)
+ __ADD(DEVCONF_FORCE_TLLAO, force_tllao)
+};
+
+static char *inet6_devconf2str(int type, char *buf, size_t len)
+{
+ return __type2str(type, buf, len, inet6_devconf,
+ ARRAY_SIZE(inet6_devconf));
+}
+
+
+static void inet6_dump_details(struct rtnl_link *link,
+ struct nl_dump_params *p, void *data)
+{
+ struct inet6_data *i6 = data;
+ char buf[64];
+ int i, n = 0;
+
+ nl_dump_line(p, " flags %s max-reasm-len %u timestamp %u "
+ "reachable-time %u retrans-time %u\n",
+ inet6_flags2str(i6->i6_flags, buf, sizeof(buf)),
+ i6->i6_cacheinfo.max_reasm_len,
+ i6->i6_cacheinfo.tstamp,
+ i6->i6_cacheinfo.reachable_time,
+ i6->i6_cacheinfo.retrans_time);
+
+ nl_dump_line(p, " ipv6 devconf:\n");
+ nl_dump_line(p, " ");
+
+ for (i = 0; i < DEVCONF_MAX; i++) {
+ nl_dump_line(p, "%s %u",
+ inet6_devconf2str(i, buf, sizeof(buf)), i6->i6_conf[i]);
+
+ if (++n == 3) {
+ nl_dump(p, "\n");
+ nl_dump_line(p, " ");
+ n = 0;
+ } else
+ nl_dump(p, " ");
+ }
+
+ if (n != 0)
+ nl_dump(p, "\n");
+}
+
+static void inet6_dump_stats(struct rtnl_link *link,
+ struct nl_dump_params *p, void *data)
+{
+ double octets;
+ char *octetsUnit;
+
+ nl_dump(p, " IPv6: InPkts InOctets "
+ " InDiscards InDelivers\n");
+ nl_dump(p, " %18llu ", link->l_stats[RTNL_LINK_INPKTS]);
+
+ octets = nl_cancel_down_bytes(link->l_stats[RTNL_LINK_INOCTETS],
+ &octetsUnit);
+ if (octets)
+ nl_dump(p, "%14.2f %3s ", octets, octetsUnit);
+ else
+ nl_dump(p, "%16llu B ", 0);
+
+ nl_dump(p, "%18llu %18llu\n",
+ link->l_stats[RTNL_LINK_INDISCARDS],
+ link->l_stats[RTNL_LINK_INDELIVERS]);
+
+ nl_dump(p, " OutPkts OutOctets "
+ " OutDiscards OutForwards\n");
+
+ nl_dump(p, " %18llu ", link->l_stats[RTNL_LINK_OUTPKTS]);
+
+ octets = nl_cancel_down_bytes(link->l_stats[RTNL_LINK_OUTOCTETS],
+ &octetsUnit);
+ if (octets)
+ nl_dump(p, "%14.2f %3s ", octets, octetsUnit);
+ else
+ nl_dump(p, "%16llu B ", 0);
+
+ nl_dump(p, "%18llu %18llu\n",
+ link->l_stats[RTNL_LINK_OUTDISCARDS],
+ link->l_stats[RTNL_LINK_OUTFORWDATAGRAMS]);
+
+ nl_dump(p, " InMcastPkts InMcastOctets "
+ " InBcastPkts InBcastOctests\n");
+
+ nl_dump(p, " %18llu ", link->l_stats[RTNL_LINK_INMCASTPKTS]);
+
+ octets = nl_cancel_down_bytes(link->l_stats[RTNL_LINK_INMCASTOCTETS],
+ &octetsUnit);
+ if (octets)
+ nl_dump(p, "%14.2f %3s ", octets, octetsUnit);
+ else
+ nl_dump(p, "%16llu B ", 0);
+
+ nl_dump(p, "%18llu ", link->l_stats[RTNL_LINK_INBCASTPKTS]);
+ octets = nl_cancel_down_bytes(link->l_stats[RTNL_LINK_INBCASTOCTETS],
+ &octetsUnit);
+ if (octets)
+ nl_dump(p, "%14.2f %3s\n", octets, octetsUnit);
+ else
+ nl_dump(p, "%16llu B\n", 0);
+
+ nl_dump(p, " OutMcastPkts OutMcastOctets "
+ " OutBcastPkts OutBcastOctests\n");
+
+ nl_dump(p, " %18llu ", link->l_stats[RTNL_LINK_OUTMCASTPKTS]);
+
+ octets = nl_cancel_down_bytes(link->l_stats[RTNL_LINK_OUTMCASTOCTETS],
+ &octetsUnit);
+ if (octets)
+ nl_dump(p, "%14.2f %3s ", octets, octetsUnit);
+ else
+ nl_dump(p, "%16llu B ", 0);
+
+ nl_dump(p, "%18llu ", link->l_stats[RTNL_LINK_OUTBCASTPKTS]);
+ octets = nl_cancel_down_bytes(link->l_stats[RTNL_LINK_OUTBCASTOCTETS],
+ &octetsUnit);
+ if (octets)
+ nl_dump(p, "%14.2f %3s\n", octets, octetsUnit);
+ else
+ nl_dump(p, "%16llu B\n", 0);
+
+ nl_dump(p, " ReasmOKs ReasmFails "
+ " ReasmReqds ReasmTimeout\n");
+ nl_dump(p, " %18llu %18llu %18llu %18llu\n",
+ link->l_stats[RTNL_LINK_REASMOKS],
+ link->l_stats[RTNL_LINK_REASMFAILS],
+ link->l_stats[RTNL_LINK_REASMREQDS],
+ link->l_stats[RTNL_LINK_REASMTIMEOUT]);
+
+ nl_dump(p, " FragOKs FragFails "
+ " FragCreates\n");
+ nl_dump(p, " %18llu %18llu %18llu\n",
+ link->l_stats[RTNL_LINK_FRAGOKS],
+ link->l_stats[RTNL_LINK_FRAGFAILS],
+ link->l_stats[RTNL_LINK_FRAGCREATES]);
+
+ nl_dump(p, " InHdrErrors InTooBigErrors "
+ " InNoRoutes InAddrErrors\n");
+ nl_dump(p, " %18llu %18llu %18llu %18llu\n",
+ link->l_stats[RTNL_LINK_INHDRERRORS],
+ link->l_stats[RTNL_LINK_INTOOBIGERRORS],
+ link->l_stats[RTNL_LINK_INNOROUTES],
+ link->l_stats[RTNL_LINK_INADDRERRORS]);
+
+ nl_dump(p, " InUnknownProtos InTruncatedPkts "
+ " OutNoRoutes\n");
+ nl_dump(p, " %18llu %18llu %18llu\n",
+ link->l_stats[RTNL_LINK_INUNKNOWNPROTOS],
+ link->l_stats[RTNL_LINK_INTRUNCATEDPKTS],
+ link->l_stats[RTNL_LINK_OUTNOROUTES]);
+
+ nl_dump(p, " ICMPv6: InMsgs InErrors "
+ " OutMsgs OutErrors\n");
+ nl_dump(p, " %18llu %18llu %18llu %18llu\n",
+ link->l_stats[RTNL_LINK_ICMP6_INMSGS],
+ link->l_stats[RTNL_LINK_ICMP6_INERRORS],
+ link->l_stats[RTNL_LINK_ICMP6_OUTMSGS],
+ link->l_stats[RTNL_LINK_ICMP6_OUTERRORS]);
+}
+
+static const struct nla_policy protinfo_policy = {
+ .type = NLA_NESTED,
+};
+
+static struct rtnl_link_af_ops inet6_ops = {
+ .ao_family = AF_INET6,
+ .ao_alloc = &inet6_alloc,
+ .ao_clone = &inet6_clone,
+ .ao_free = &inet6_free,
+ .ao_parse_protinfo = &inet6_parse_protinfo,
+ .ao_dump[NL_DUMP_DETAILS] = &inet6_dump_details,
+ .ao_dump[NL_DUMP_STATS] = &inet6_dump_stats,
+ .ao_protinfo_policy = &protinfo_policy,
+};
+
+static void __init inet6_init(void)
+{
+ rtnl_link_af_register(&inet6_ops);
+}
+
+static void __exit inet6_exit(void)
+{
+ rtnl_link_af_unregister(&inet6_ops);
+}