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