• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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@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 
inet6_alloc(struct rtnl_link * link)25 static void *inet6_alloc(struct rtnl_link *link)
26 {
27 	return calloc(1, sizeof(struct inet6_data));
28 }
29 
inet6_clone(struct rtnl_link * link,void * data)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 
inet6_free(struct rtnl_link * link,void * data)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 
inet6_parse_protinfo(struct rtnl_link * link,struct nlattr * attr,void * data)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 
inet6_flags2str(int flags,char * buf,size_t len)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 
inet6_devconf2str(int type,char * buf,size_t len)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 
inet6_dump_details(struct rtnl_link * link,struct nl_dump_params * p,void * data)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 
inet6_dump_stats(struct rtnl_link * link,struct nl_dump_params * p,void * data)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 
inet6_init(void)476 static void __init inet6_init(void)
477 {
478 	rtnl_link_af_register(&inet6_ops);
479 }
480 
inet6_exit(void)481 static void __exit inet6_exit(void)
482 {
483 	rtnl_link_af_unregister(&inet6_ops);
484 }
485