Home | History | Annotate | Download | only in link
      1 /*
      2  * lib/route/link/inet6.c	AF_INET6 link operations
      3  *
      4  *	This library is free software; you can redistribute it and/or
      5  *	modify it under the terms of the GNU Lesser General Public
      6  *	License as published by the Free Software Foundation version 2.1
      7  *	of the License.
      8  *
      9  * Copyright (c) 2010 Thomas Graf <tgraf (at) suug.ch>
     10  */
     11 
     12 #include <netlink-private/netlink.h>
     13 #include <netlink/netlink.h>
     14 #include <netlink/attr.h>
     15 #include <netlink/route/rtnl.h>
     16 #include <netlink-private/route/link/api.h>
     17 
     18 struct inet6_data
     19 {
     20 	uint32_t		i6_flags;
     21 	struct ifla_cacheinfo	i6_cacheinfo;
     22 	uint32_t		i6_conf[DEVCONF_MAX];
     23 };
     24 
     25 static void *inet6_alloc(struct rtnl_link *link)
     26 {
     27 	return calloc(1, sizeof(struct inet6_data));
     28 }
     29 
     30 static void *inet6_clone(struct rtnl_link *link, void *data)
     31 {
     32 	struct inet6_data *i6;
     33 
     34 	if ((i6 = inet6_alloc(link)))
     35 		memcpy(i6, data, sizeof(*i6));
     36 
     37 	return i6;
     38 }
     39 
     40 static void inet6_free(struct rtnl_link *link, void *data)
     41 {
     42 	free(data);
     43 }
     44 
     45 static struct nla_policy inet6_policy[IFLA_INET6_MAX+1] = {
     46 	[IFLA_INET6_FLAGS]	= { .type = NLA_U32 },
     47 	[IFLA_INET6_CACHEINFO]	= { .minlen = sizeof(struct ifla_cacheinfo) },
     48 	[IFLA_INET6_CONF]	= { .minlen = 4 },
     49 	[IFLA_INET6_STATS]	= { .minlen = 8 },
     50 	[IFLA_INET6_ICMP6STATS]	= { .minlen = 8 },
     51 };
     52 
     53 static const uint8_t map_stat_id_from_IPSTATS_MIB_v1[__IPSTATS_MIB_MAX] = {
     54 	/* 14a196807482e6fc74f15fc03176d5c08880588f^:include/linux/snmp.h
     55 	 * version before the API change in commit 14a196807482e6fc74f15fc03176d5c08880588f.
     56 	 * This version was valid since commit edf391ff17232f097d72441c9ad467bcb3b5db18, which
     57 	 * predates support for parsing IFLA_PROTINFO in libnl3. Such an even older meaning of
     58 	 * the flags is not supported in libnl3. */
     59 	[ 1] = RTNL_LINK_IP6_INPKTS,                    /* IPSTATS_MIB_INPKTS                   */
     60 	[ 2] = RTNL_LINK_IP6_INHDRERRORS,               /* IPSTATS_MIB_INHDRERRORS              */
     61 	[ 3] = RTNL_LINK_IP6_INTOOBIGERRORS,            /* IPSTATS_MIB_INTOOBIGERRORS           */
     62 	[ 4] = RTNL_LINK_IP6_INNOROUTES,                /* IPSTATS_MIB_INNOROUTES               */
     63 	[ 5] = RTNL_LINK_IP6_INADDRERRORS,              /* IPSTATS_MIB_INADDRERRORS             */
     64 	[ 6] = RTNL_LINK_IP6_INUNKNOWNPROTOS,           /* IPSTATS_MIB_INUNKNOWNPROTOS          */
     65 	[ 7] = RTNL_LINK_IP6_INTRUNCATEDPKTS,           /* IPSTATS_MIB_INTRUNCATEDPKTS          */
     66 	[ 8] = RTNL_LINK_IP6_INDISCARDS,                /* IPSTATS_MIB_INDISCARDS               */
     67 	[ 9] = RTNL_LINK_IP6_INDELIVERS,                /* IPSTATS_MIB_INDELIVERS               */
     68 	[10] = RTNL_LINK_IP6_OUTFORWDATAGRAMS,          /* IPSTATS_MIB_OUTFORWDATAGRAMS         */
     69 	[11] = RTNL_LINK_IP6_OUTPKTS,                   /* IPSTATS_MIB_OUTPKTS                  */
     70 	[12] = RTNL_LINK_IP6_OUTDISCARDS,               /* IPSTATS_MIB_OUTDISCARDS              */
     71 	[13] = RTNL_LINK_IP6_OUTNOROUTES,               /* IPSTATS_MIB_OUTNOROUTES              */
     72 	[14] = RTNL_LINK_IP6_REASMTIMEOUT,              /* IPSTATS_MIB_REASMTIMEOUT             */
     73 	[15] = RTNL_LINK_IP6_REASMREQDS,                /* IPSTATS_MIB_REASMREQDS               */
     74 	[16] = RTNL_LINK_IP6_REASMOKS,                  /* IPSTATS_MIB_REASMOKS                 */
     75 	[17] = RTNL_LINK_IP6_REASMFAILS,                /* IPSTATS_MIB_REASMFAILS               */
     76 	[18] = RTNL_LINK_IP6_FRAGOKS,                   /* IPSTATS_MIB_FRAGOKS                  */
     77 	[19] = RTNL_LINK_IP6_FRAGFAILS,                 /* IPSTATS_MIB_FRAGFAILS                */
     78 	[20] = RTNL_LINK_IP6_FRAGCREATES,               /* IPSTATS_MIB_FRAGCREATES              */
     79 	[21] = RTNL_LINK_IP6_INMCASTPKTS,               /* IPSTATS_MIB_INMCASTPKTS              */
     80 	[22] = RTNL_LINK_IP6_OUTMCASTPKTS,              /* IPSTATS_MIB_OUTMCASTPKTS             */
     81 	[23] = RTNL_LINK_IP6_INBCASTPKTS,               /* IPSTATS_MIB_INBCASTPKTS              */
     82 	[24] = RTNL_LINK_IP6_OUTBCASTPKTS,              /* IPSTATS_MIB_OUTBCASTPKTS             */
     83 	[25] = RTNL_LINK_IP6_INOCTETS,                  /* IPSTATS_MIB_INOCTETS                 */
     84 	[26] = RTNL_LINK_IP6_OUTOCTETS,                 /* IPSTATS_MIB_OUTOCTETS                */
     85 	[27] = RTNL_LINK_IP6_INMCASTOCTETS,             /* IPSTATS_MIB_INMCASTOCTETS            */
     86 	[28] = RTNL_LINK_IP6_OUTMCASTOCTETS,            /* IPSTATS_MIB_OUTMCASTOCTETS           */
     87 	[29] = RTNL_LINK_IP6_INBCASTOCTETS,             /* IPSTATS_MIB_INBCASTOCTETS            */
     88 	[30] = RTNL_LINK_IP6_OUTBCASTOCTETS,            /* IPSTATS_MIB_OUTBCASTOCTETS           */
     89 };
     90 
     91 static const uint8_t map_stat_id_from_IPSTATS_MIB_v2[__IPSTATS_MIB_MAX] = {
     92 	/* d8ec26d7f8287f5788a494f56e8814210f0e64be:include/uapi/linux/snmp.h
     93 	 * version since the API change in commit 14a196807482e6fc74f15fc03176d5c08880588f */
     94 	[ 1] = RTNL_LINK_IP6_INPKTS,                    /* IPSTATS_MIB_INPKTS                   */
     95 	[ 2] = RTNL_LINK_IP6_INOCTETS,                  /* IPSTATS_MIB_INOCTETS                 */
     96 	[ 3] = RTNL_LINK_IP6_INDELIVERS,                /* IPSTATS_MIB_INDELIVERS               */
     97 	[ 4] = RTNL_LINK_IP6_OUTFORWDATAGRAMS,          /* IPSTATS_MIB_OUTFORWDATAGRAMS         */
     98 	[ 5] = RTNL_LINK_IP6_OUTPKTS,                   /* IPSTATS_MIB_OUTPKTS                  */
     99 	[ 6] = RTNL_LINK_IP6_OUTOCTETS,                 /* IPSTATS_MIB_OUTOCTETS                */
    100 	[ 7] = RTNL_LINK_IP6_INHDRERRORS,               /* IPSTATS_MIB_INHDRERRORS              */
    101 	[ 8] = RTNL_LINK_IP6_INTOOBIGERRORS,            /* IPSTATS_MIB_INTOOBIGERRORS           */
    102 	[ 9] = RTNL_LINK_IP6_INNOROUTES,                /* IPSTATS_MIB_INNOROUTES               */
    103 	[10] = RTNL_LINK_IP6_INADDRERRORS,              /* IPSTATS_MIB_INADDRERRORS             */
    104 	[11] = RTNL_LINK_IP6_INUNKNOWNPROTOS,           /* IPSTATS_MIB_INUNKNOWNPROTOS          */
    105 	[12] = RTNL_LINK_IP6_INTRUNCATEDPKTS,           /* IPSTATS_MIB_INTRUNCATEDPKTS          */
    106 	[13] = RTNL_LINK_IP6_INDISCARDS,                /* IPSTATS_MIB_INDISCARDS               */
    107 	[14] = RTNL_LINK_IP6_OUTDISCARDS,               /* IPSTATS_MIB_OUTDISCARDS              */
    108 	[15] = RTNL_LINK_IP6_OUTNOROUTES,               /* IPSTATS_MIB_OUTNOROUTES              */
    109 	[16] = RTNL_LINK_IP6_REASMTIMEOUT,              /* IPSTATS_MIB_REASMTIMEOUT             */
    110 	[17] = RTNL_LINK_IP6_REASMREQDS,                /* IPSTATS_MIB_REASMREQDS               */
    111 	[18] = RTNL_LINK_IP6_REASMOKS,                  /* IPSTATS_MIB_REASMOKS                 */
    112 	[19] = RTNL_LINK_IP6_REASMFAILS,                /* IPSTATS_MIB_REASMFAILS               */
    113 	[20] = RTNL_LINK_IP6_FRAGOKS,                   /* IPSTATS_MIB_FRAGOKS                  */
    114 	[21] = RTNL_LINK_IP6_FRAGFAILS,                 /* IPSTATS_MIB_FRAGFAILS                */
    115 	[22] = RTNL_LINK_IP6_FRAGCREATES,               /* IPSTATS_MIB_FRAGCREATES              */
    116 	[23] = RTNL_LINK_IP6_INMCASTPKTS,               /* IPSTATS_MIB_INMCASTPKTS              */
    117 	[24] = RTNL_LINK_IP6_OUTMCASTPKTS,              /* IPSTATS_MIB_OUTMCASTPKTS             */
    118 	[25] = RTNL_LINK_IP6_INBCASTPKTS,               /* IPSTATS_MIB_INBCASTPKTS              */
    119 	[26] = RTNL_LINK_IP6_OUTBCASTPKTS,              /* IPSTATS_MIB_OUTBCASTPKTS             */
    120 	[27] = RTNL_LINK_IP6_INMCASTOCTETS,             /* IPSTATS_MIB_INMCASTOCTETS            */
    121 	[28] = RTNL_LINK_IP6_OUTMCASTOCTETS,            /* IPSTATS_MIB_OUTMCASTOCTETS           */
    122 	[29] = RTNL_LINK_IP6_INBCASTOCTETS,             /* IPSTATS_MIB_INBCASTOCTETS            */
    123 	[30] = RTNL_LINK_IP6_OUTBCASTOCTETS,            /* IPSTATS_MIB_OUTBCASTOCTETS           */
    124 	[31] = RTNL_LINK_IP6_CSUMERRORS,                /* IPSTATS_MIB_CSUMERRORS               */
    125 	[32] = RTNL_LINK_IP6_NOECTPKTS,                 /* IPSTATS_MIB_NOECTPKTS                */
    126 	[33] = RTNL_LINK_IP6_ECT1PKTS,                  /* IPSTATS_MIB_ECT1PKTS                 */
    127 	[34] = RTNL_LINK_IP6_ECT0PKTS,                  /* IPSTATS_MIB_ECT0PKTS                 */
    128 	[35] = RTNL_LINK_IP6_CEPKTS,                    /* IPSTATS_MIB_CEPKTS                   */
    129 };
    130 
    131 static int inet6_parse_protinfo(struct rtnl_link *link, struct nlattr *attr,
    132 				void *data)
    133 {
    134 	struct inet6_data *i6 = data;
    135 	struct nlattr *tb[IFLA_INET6_MAX+1];
    136 	int err;
    137 
    138 	err = nla_parse_nested(tb, IFLA_INET6_MAX, attr, inet6_policy);
    139 	if (err < 0)
    140 		return err;
    141 	if (tb[IFLA_INET6_CONF] && nla_len(tb[IFLA_INET6_CONF]) % 4)
    142 		return -EINVAL;
    143 	if (tb[IFLA_INET6_STATS] && nla_len(tb[IFLA_INET6_STATS]) % 8)
    144 		return -EINVAL;
    145 	if (tb[IFLA_INET6_ICMP6STATS] && nla_len(tb[IFLA_INET6_ICMP6STATS]) % 8)
    146 		return -EINVAL;
    147 
    148 	if (tb[IFLA_INET6_FLAGS])
    149 		i6->i6_flags = nla_get_u32(tb[IFLA_INET6_FLAGS]);
    150 
    151 	if (tb[IFLA_INET6_CACHEINFO])
    152 		nla_memcpy(&i6->i6_cacheinfo, tb[IFLA_INET6_CACHEINFO],
    153 			   sizeof(i6->i6_cacheinfo));
    154 
    155 	if (tb[IFLA_INET6_CONF])
    156 		nla_memcpy(&i6->i6_conf, tb[IFLA_INET6_CONF],
    157 			   sizeof(i6->i6_conf));
    158 
    159 	/*
    160 	 * Due to 32bit data alignment, these addresses must be copied to an
    161 	 * aligned location prior to access.
    162 	 */
    163 	if (tb[IFLA_INET6_STATS]) {
    164 		unsigned char *cnt = nla_data(tb[IFLA_INET6_STATS]);
    165 		uint64_t stat;
    166 		int i;
    167 		int len = nla_len(tb[IFLA_INET6_STATS]) / 8;
    168 		const uint8_t *map_stat_id = map_stat_id_from_IPSTATS_MIB_v2;
    169 
    170 		if (len < 32 ||
    171 		    (tb[IFLA_INET6_ICMP6STATS] && nla_len(tb[IFLA_INET6_ICMP6STATS]) < 6)) {
    172 			/* kernel commit 14a196807482e6fc74f15fc03176d5c08880588f reordered the values.
    173 			 * The later commit 6a5dc9e598fe90160fee7de098fa319665f5253e added values
    174 			 * IPSTATS_MIB_CSUMERRORS/ICMP6_MIB_CSUMERRORS. If the netlink is shorter
    175 			 * then this, assume that the kernel uses the previous meaning of the
    176 			 * enumeration. */
    177 			map_stat_id = map_stat_id_from_IPSTATS_MIB_v1;
    178 		}
    179 
    180 		len = min_t(int, __IPSTATS_MIB_MAX, len);
    181 		for (i = 1; i < len; i++) {
    182 			memcpy(&stat, &cnt[i * sizeof(stat)], sizeof(stat));
    183 			rtnl_link_set_stat(link, map_stat_id[i], stat);
    184 		}
    185 	}
    186 
    187 	if (tb[IFLA_INET6_ICMP6STATS]) {
    188 		unsigned char *cnt = nla_data(tb[IFLA_INET6_ICMP6STATS]);
    189 		uint64_t stat;
    190 		int i;
    191 		int len = min_t(int, __ICMP6_MIB_MAX, nla_len(tb[IFLA_INET6_ICMP6STATS]) / 8);
    192 
    193 		for (i = 1; i < len; i++) {
    194 			memcpy(&stat, &cnt[i * sizeof(stat)], sizeof(stat));
    195 			rtnl_link_set_stat(link, RTNL_LINK_ICMP6_INMSGS + i - 1,
    196 					   stat);
    197 		}
    198 	}
    199 
    200 	return 0;
    201 }
    202 
    203 /* These live in include/net/if_inet6.h and should be moved to include/linux */
    204 #define IF_RA_OTHERCONF	0x80
    205 #define IF_RA_MANAGED	0x40
    206 #define IF_RA_RCVD	0x20
    207 #define IF_RS_SENT	0x10
    208 #define IF_READY	0x80000000
    209 
    210 static const struct trans_tbl inet6_flags[] = {
    211 	__ADD(IF_RA_OTHERCONF, ra_otherconf)
    212 	__ADD(IF_RA_MANAGED, ra_managed)
    213 	__ADD(IF_RA_RCVD, ra_rcvd)
    214 	__ADD(IF_RS_SENT, rs_sent)
    215 	__ADD(IF_READY, ready)
    216 };
    217 
    218 static char *inet6_flags2str(int flags, char *buf, size_t len)
    219 {
    220 	return __flags2str(flags, buf, len, inet6_flags,
    221 			   ARRAY_SIZE(inet6_flags));
    222 }
    223 
    224 static const struct trans_tbl inet6_devconf[] = {
    225 	__ADD(DEVCONF_FORWARDING, forwarding)
    226 	__ADD(DEVCONF_HOPLIMIT, hoplimit)
    227 	__ADD(DEVCONF_MTU6, mtu6)
    228 	__ADD(DEVCONF_ACCEPT_RA, accept_ra)
    229 	__ADD(DEVCONF_ACCEPT_REDIRECTS, accept_redirects)
    230 	__ADD(DEVCONF_AUTOCONF, autoconf)
    231 	__ADD(DEVCONF_DAD_TRANSMITS, dad_transmits)
    232 	__ADD(DEVCONF_RTR_SOLICITS, rtr_solicits)
    233 	__ADD(DEVCONF_RTR_SOLICIT_INTERVAL, rtr_solicit_interval)
    234 	__ADD(DEVCONF_RTR_SOLICIT_DELAY, rtr_solicit_delay)
    235 	__ADD(DEVCONF_USE_TEMPADDR, use_tempaddr)
    236 	__ADD(DEVCONF_TEMP_VALID_LFT, temp_valid_lft)
    237 	__ADD(DEVCONF_TEMP_PREFERED_LFT, temp_prefered_lft)
    238 	__ADD(DEVCONF_REGEN_MAX_RETRY, regen_max_retry)
    239 	__ADD(DEVCONF_MAX_DESYNC_FACTOR, max_desync_factor)
    240 	__ADD(DEVCONF_MAX_ADDRESSES, max_addresses)
    241 	__ADD(DEVCONF_FORCE_MLD_VERSION, force_mld_version)
    242 	__ADD(DEVCONF_ACCEPT_RA_DEFRTR, accept_ra_defrtr)
    243 	__ADD(DEVCONF_ACCEPT_RA_PINFO, accept_ra_pinfo)
    244 	__ADD(DEVCONF_ACCEPT_RA_RTR_PREF, accept_ra_rtr_pref)
    245 	__ADD(DEVCONF_RTR_PROBE_INTERVAL, rtr_probe_interval)
    246 	__ADD(DEVCONF_ACCEPT_RA_RT_INFO_MAX_PLEN, accept_ra_rt_info)
    247 	__ADD(DEVCONF_PROXY_NDP, proxy_ndp)
    248 	__ADD(DEVCONF_OPTIMISTIC_DAD, optimistic_dad)
    249 	__ADD(DEVCONF_ACCEPT_SOURCE_ROUTE, accept_source_route)
    250 	__ADD(DEVCONF_MC_FORWARDING, mc_forwarding)
    251 	__ADD(DEVCONF_DISABLE_IPV6, disable_ipv6)
    252 	__ADD(DEVCONF_ACCEPT_DAD, accept_dad)
    253 	__ADD(DEVCONF_FORCE_TLLAO, force_tllao)
    254 };
    255 
    256 static char *inet6_devconf2str(int type, char *buf, size_t len)
    257 {
    258 	return __type2str(type, buf, len, inet6_devconf,
    259 			  ARRAY_SIZE(inet6_devconf));
    260 }
    261 
    262 
    263 static void inet6_dump_details(struct rtnl_link *link,
    264 				struct nl_dump_params *p, void *data)
    265 {
    266 	struct inet6_data *i6 = data;
    267 	char buf[64], buf2[64];
    268 	int i, n = 0;
    269 
    270 	nl_dump_line(p, "    ipv6 max-reasm-len %s",
    271 		nl_size2str(i6->i6_cacheinfo.max_reasm_len, buf, sizeof(buf)));
    272 
    273 	nl_dump(p, " <%s>\n",
    274 		inet6_flags2str(i6->i6_flags, buf, sizeof(buf)));
    275 
    276 
    277 	nl_dump_line(p, "      create-stamp %.2fs reachable-time %s",
    278 		(double) i6->i6_cacheinfo.tstamp / 100.,
    279 		nl_msec2str(i6->i6_cacheinfo.reachable_time, buf, sizeof(buf)));
    280 
    281 	nl_dump(p, " retrans-time %s\n",
    282 		nl_msec2str(i6->i6_cacheinfo.retrans_time, buf, sizeof(buf)));
    283 
    284 	nl_dump_line(p, "      devconf:\n");
    285 	nl_dump_line(p, "      ");
    286 
    287 	for (i = 0; i < DEVCONF_MAX; i++) {
    288 		uint32_t value = i6->i6_conf[i];
    289 		int x, offset;
    290 
    291 		switch (i) {
    292 		case DEVCONF_TEMP_VALID_LFT:
    293 		case DEVCONF_TEMP_PREFERED_LFT:
    294 			nl_msec2str((uint64_t) value * 1000., buf2, sizeof(buf2));
    295 			break;
    296 
    297 		case DEVCONF_RTR_PROBE_INTERVAL:
    298 		case DEVCONF_RTR_SOLICIT_INTERVAL:
    299 		case DEVCONF_RTR_SOLICIT_DELAY:
    300 			nl_msec2str(value, buf2, sizeof(buf2));
    301 			break;
    302 
    303 		default:
    304 			snprintf(buf2, sizeof(buf2), "%u", value);
    305 			break;
    306 
    307 		}
    308 
    309 		inet6_devconf2str(i, buf, sizeof(buf));
    310 
    311 		offset = 23 - strlen(buf2);
    312 		if (offset < 0)
    313 			offset = 0;
    314 
    315 		for (x = strlen(buf); x < offset; x++)
    316 			buf[x] = ' ';
    317 
    318 		strncpy(&buf[offset], buf2, strlen(buf2));
    319 
    320 		nl_dump_line(p, "%s", buf);
    321 
    322 		if (++n == 3) {
    323 			nl_dump(p, "\n");
    324 			nl_dump_line(p, "      ");
    325 			n = 0;
    326 		} else
    327 			nl_dump(p, "  ");
    328 	}
    329 
    330 	if (n != 0)
    331 		nl_dump(p, "\n");
    332 }
    333 
    334 static void inet6_dump_stats(struct rtnl_link *link,
    335 			     struct nl_dump_params *p, void *data)
    336 {
    337 	double octets;
    338 	char *octetsUnit;
    339 
    340 	nl_dump(p, "    IPv6:       InPkts           InOctets     "
    341 		   "    InDiscards         InDelivers\n");
    342 	nl_dump(p, "    %18" PRIu64 " ", link->l_stats[RTNL_LINK_IP6_INPKTS]);
    343 
    344 	octets = nl_cancel_down_bytes(link->l_stats[RTNL_LINK_IP6_INOCTETS],
    345 				      &octetsUnit);
    346 	if (octets)
    347 		nl_dump(p, "%14.2f %3s ", octets, octetsUnit);
    348 	else
    349 		nl_dump(p, "%16" PRIu64 " B ", 0);
    350 
    351 	nl_dump(p, "%18" PRIu64 " %18" PRIu64 "\n",
    352 		link->l_stats[RTNL_LINK_IP6_INDISCARDS],
    353 		link->l_stats[RTNL_LINK_IP6_INDELIVERS]);
    354 
    355 	nl_dump(p, "               OutPkts          OutOctets     "
    356 		   "   OutDiscards        OutForwards\n");
    357 
    358 	nl_dump(p, "    %18" PRIu64 " ", link->l_stats[RTNL_LINK_IP6_OUTPKTS]);
    359 
    360 	octets = nl_cancel_down_bytes(link->l_stats[RTNL_LINK_IP6_OUTOCTETS],
    361 				      &octetsUnit);
    362 	if (octets)
    363 		nl_dump(p, "%14.2f %3s ", octets, octetsUnit);
    364 	else
    365 		nl_dump(p, "%16" PRIu64 " B ", 0);
    366 
    367 	nl_dump(p, "%18" PRIu64 " %18" PRIu64 "\n",
    368 		link->l_stats[RTNL_LINK_IP6_OUTDISCARDS],
    369 		link->l_stats[RTNL_LINK_IP6_OUTFORWDATAGRAMS]);
    370 
    371 	nl_dump(p, "           InMcastPkts      InMcastOctets     "
    372 		   "   InBcastPkts     InBcastOctests\n");
    373 
    374 	nl_dump(p, "    %18" PRIu64 " ", link->l_stats[RTNL_LINK_IP6_INMCASTPKTS]);
    375 
    376 	octets = nl_cancel_down_bytes(link->l_stats[RTNL_LINK_IP6_INMCASTOCTETS],
    377 				      &octetsUnit);
    378 	if (octets)
    379 		nl_dump(p, "%14.2f %3s ", octets, octetsUnit);
    380 	else
    381 		nl_dump(p, "%16" PRIu64 " B ", 0);
    382 
    383 	nl_dump(p, "%18" PRIu64 " ", link->l_stats[RTNL_LINK_IP6_INBCASTPKTS]);
    384 	octets = nl_cancel_down_bytes(link->l_stats[RTNL_LINK_IP6_INBCASTOCTETS],
    385 				      &octetsUnit);
    386 	if (octets)
    387 		nl_dump(p, "%14.2f %3s\n", octets, octetsUnit);
    388 	else
    389 		nl_dump(p, "%16" PRIu64 " B\n", 0);
    390 
    391 	nl_dump(p, "          OutMcastPkts     OutMcastOctets     "
    392 		   "  OutBcastPkts    OutBcastOctests\n");
    393 
    394 	nl_dump(p, "    %18" PRIu64 " ", link->l_stats[RTNL_LINK_IP6_OUTMCASTPKTS]);
    395 
    396 	octets = nl_cancel_down_bytes(link->l_stats[RTNL_LINK_IP6_OUTMCASTOCTETS],
    397 				      &octetsUnit);
    398 	if (octets)
    399 		nl_dump(p, "%14.2f %3s ", octets, octetsUnit);
    400 	else
    401 		nl_dump(p, "%16" PRIu64 " B ", 0);
    402 
    403 	nl_dump(p, "%18" PRIu64 " ", link->l_stats[RTNL_LINK_IP6_OUTBCASTPKTS]);
    404 	octets = nl_cancel_down_bytes(link->l_stats[RTNL_LINK_IP6_OUTBCASTOCTETS],
    405 				      &octetsUnit);
    406 	if (octets)
    407 		nl_dump(p, "%14.2f %3s\n", octets, octetsUnit);
    408 	else
    409 		nl_dump(p, "%16" PRIu64 " B\n", 0);
    410 
    411 	nl_dump(p, "              ReasmOKs         ReasmFails     "
    412 		   "    ReasmReqds       ReasmTimeout\n");
    413 	nl_dump(p, "    %18" PRIu64 " %18" PRIu64 " %18" PRIu64 " %18" PRIu64 "\n",
    414 		link->l_stats[RTNL_LINK_IP6_REASMOKS],
    415 		link->l_stats[RTNL_LINK_IP6_REASMFAILS],
    416 		link->l_stats[RTNL_LINK_IP6_REASMREQDS],
    417 		link->l_stats[RTNL_LINK_IP6_REASMTIMEOUT]);
    418 
    419 	nl_dump(p, "               FragOKs          FragFails    "
    420 		   "    FragCreates\n");
    421 	nl_dump(p, "    %18" PRIu64 " %18" PRIu64 " %18" PRIu64 "\n",
    422 		link->l_stats[RTNL_LINK_IP6_FRAGOKS],
    423 		link->l_stats[RTNL_LINK_IP6_FRAGFAILS],
    424 		link->l_stats[RTNL_LINK_IP6_FRAGCREATES]);
    425 
    426 	nl_dump(p, "           InHdrErrors      InTooBigErrors   "
    427 		   "     InNoRoutes       InAddrErrors\n");
    428 	nl_dump(p, "    %18" PRIu64 " %18" PRIu64 " %18" PRIu64 " %18" PRIu64 "\n",
    429 		link->l_stats[RTNL_LINK_IP6_INHDRERRORS],
    430 		link->l_stats[RTNL_LINK_IP6_INTOOBIGERRORS],
    431 		link->l_stats[RTNL_LINK_IP6_INNOROUTES],
    432 		link->l_stats[RTNL_LINK_IP6_INADDRERRORS]);
    433 
    434 	nl_dump(p, "       InUnknownProtos     InTruncatedPkts   "
    435 		   "    OutNoRoutes       InCsumErrors\n");
    436 	nl_dump(p, "    %18" PRIu64 " %18" PRIu64 " %18" PRIu64 " %18" PRIu64 "\n",
    437 		link->l_stats[RTNL_LINK_IP6_INUNKNOWNPROTOS],
    438 		link->l_stats[RTNL_LINK_IP6_INTRUNCATEDPKTS],
    439 		link->l_stats[RTNL_LINK_IP6_OUTNOROUTES],
    440 		link->l_stats[RTNL_LINK_IP6_CSUMERRORS]);
    441 
    442 	nl_dump(p, "           InNoECTPkts          InECT1Pkts   "
    443 		   "     InECT0Pkts           InCEPkts\n");
    444 	nl_dump(p, "    %18" PRIu64 " %18" PRIu64 " %18" PRIu64 " %18" PRIu64 "\n",
    445 		link->l_stats[RTNL_LINK_IP6_NOECTPKTS],
    446 		link->l_stats[RTNL_LINK_IP6_ECT1PKTS],
    447 		link->l_stats[RTNL_LINK_IP6_ECT0PKTS],
    448 		link->l_stats[RTNL_LINK_IP6_CEPKTS]);
    449 
    450 	nl_dump(p, "    ICMPv6:     InMsgs           InErrors        "
    451 		   "    OutMsgs          OutErrors       InCsumErrors\n");
    452 	nl_dump(p, "    %18" PRIu64 " %18" PRIu64 " %18" PRIu64 " %18" PRIu64 " %18" PRIu64 "\n",
    453 		link->l_stats[RTNL_LINK_ICMP6_INMSGS],
    454 		link->l_stats[RTNL_LINK_ICMP6_INERRORS],
    455 		link->l_stats[RTNL_LINK_ICMP6_OUTMSGS],
    456 		link->l_stats[RTNL_LINK_ICMP6_OUTERRORS],
    457 		link->l_stats[RTNL_LINK_ICMP6_CSUMERRORS]);
    458 }
    459 
    460 static const struct nla_policy protinfo_policy = {
    461 	.type			= NLA_NESTED,
    462 };
    463 
    464 static struct rtnl_link_af_ops inet6_ops = {
    465 	.ao_family			= AF_INET6,
    466 	.ao_alloc			= &inet6_alloc,
    467 	.ao_clone			= &inet6_clone,
    468 	.ao_free			= &inet6_free,
    469 	.ao_parse_protinfo		= &inet6_parse_protinfo,
    470 	.ao_parse_af			= &inet6_parse_protinfo,
    471 	.ao_dump[NL_DUMP_DETAILS]	= &inet6_dump_details,
    472 	.ao_dump[NL_DUMP_STATS]		= &inet6_dump_stats,
    473 	.ao_protinfo_policy		= &protinfo_policy,
    474 };
    475 
    476 static void __init inet6_init(void)
    477 {
    478 	rtnl_link_af_register(&inet6_ops);
    479 }
    480 
    481 static void __exit inet6_exit(void)
    482 {
    483 	rtnl_link_af_unregister(&inet6_ops);
    484 }
    485