libnl 3.7.0
inet6.c
1/* SPDX-License-Identifier: LGPL-2.1-only */
2/*
3 * Copyright (c) 2010 Thomas Graf <tgraf@suug.ch>
4 */
5
6#include <netlink-private/netlink.h>
7#include <netlink/netlink.h>
8#include <netlink/attr.h>
9#include <netlink/route/rtnl.h>
10#include <netlink/route/link/inet6.h>
11#include <netlink-private/route/link/api.h>
12
13#include "netlink-private/route/utils.h"
14#include "netlink-private/utils.h"
15
16#define I6_ADDR_GEN_MODE_UNKNOWN UINT8_MAX
17
19{
20 uint32_t i6_flags;
21 struct ifla_cacheinfo i6_cacheinfo;
22 uint32_t i6_conf[DEVCONF_MAX];
23 struct in6_addr i6_token;
24 uint8_t i6_addr_gen_mode;
25};
26
27static void *inet6_alloc(struct rtnl_link *link)
28{
29 struct inet6_data *i6;
30
31 i6 = calloc(1, sizeof(struct inet6_data));
32 if (i6)
33 i6->i6_addr_gen_mode = I6_ADDR_GEN_MODE_UNKNOWN;
34
35 return i6;
36}
37
38static void *inet6_clone(struct rtnl_link *link, void *data)
39{
40 struct inet6_data *i6;
41
42 if ((i6 = inet6_alloc(link)))
43 memcpy(i6, data, sizeof(*i6));
44
45 return i6;
46}
47
48static void inet6_free(struct rtnl_link *link, void *data)
49{
50 free(data);
51}
52
53static struct nla_policy inet6_policy[IFLA_INET6_MAX+1] = {
54 [IFLA_INET6_FLAGS] = { .type = NLA_U32 },
55 [IFLA_INET6_CACHEINFO] = { .minlen = sizeof(struct ifla_cacheinfo) },
56 [IFLA_INET6_CONF] = { .minlen = 4 },
57 [IFLA_INET6_STATS] = { .minlen = 8 },
58 [IFLA_INET6_ICMP6STATS] = { .minlen = 8 },
59 [IFLA_INET6_TOKEN] = { .minlen = sizeof(struct in6_addr) },
60 [IFLA_INET6_ADDR_GEN_MODE] = { .type = NLA_U8 },
61};
62
63static const uint8_t map_stat_id_from_IPSTATS_MIB_v1[__IPSTATS_MIB_MAX] = {
64 /* 14a196807482e6fc74f15fc03176d5c08880588f^:include/linux/snmp.h
65 * version before the API change in commit 14a196807482e6fc74f15fc03176d5c08880588f.
66 * This version was valid since commit edf391ff17232f097d72441c9ad467bcb3b5db18, which
67 * predates support for parsing IFLA_PROTINFO in libnl3. Such an even older meaning of
68 * the flags is not supported in libnl3. */
69 [ 1] = RTNL_LINK_IP6_INPKTS, /* IPSTATS_MIB_INPKTS */
70 [ 2] = RTNL_LINK_IP6_INHDRERRORS, /* IPSTATS_MIB_INHDRERRORS */
71 [ 3] = RTNL_LINK_IP6_INTOOBIGERRORS, /* IPSTATS_MIB_INTOOBIGERRORS */
72 [ 4] = RTNL_LINK_IP6_INNOROUTES, /* IPSTATS_MIB_INNOROUTES */
73 [ 5] = RTNL_LINK_IP6_INADDRERRORS, /* IPSTATS_MIB_INADDRERRORS */
74 [ 6] = RTNL_LINK_IP6_INUNKNOWNPROTOS, /* IPSTATS_MIB_INUNKNOWNPROTOS */
75 [ 7] = RTNL_LINK_IP6_INTRUNCATEDPKTS, /* IPSTATS_MIB_INTRUNCATEDPKTS */
76 [ 8] = RTNL_LINK_IP6_INDISCARDS, /* IPSTATS_MIB_INDISCARDS */
77 [ 9] = RTNL_LINK_IP6_INDELIVERS, /* IPSTATS_MIB_INDELIVERS */
78 [10] = RTNL_LINK_IP6_OUTFORWDATAGRAMS, /* IPSTATS_MIB_OUTFORWDATAGRAMS */
79 [11] = RTNL_LINK_IP6_OUTPKTS, /* IPSTATS_MIB_OUTPKTS */
80 [12] = RTNL_LINK_IP6_OUTDISCARDS, /* IPSTATS_MIB_OUTDISCARDS */
81 [13] = RTNL_LINK_IP6_OUTNOROUTES, /* IPSTATS_MIB_OUTNOROUTES */
82 [14] = RTNL_LINK_IP6_REASMTIMEOUT, /* IPSTATS_MIB_REASMTIMEOUT */
83 [15] = RTNL_LINK_IP6_REASMREQDS, /* IPSTATS_MIB_REASMREQDS */
84 [16] = RTNL_LINK_IP6_REASMOKS, /* IPSTATS_MIB_REASMOKS */
85 [17] = RTNL_LINK_IP6_REASMFAILS, /* IPSTATS_MIB_REASMFAILS */
86 [18] = RTNL_LINK_IP6_FRAGOKS, /* IPSTATS_MIB_FRAGOKS */
87 [19] = RTNL_LINK_IP6_FRAGFAILS, /* IPSTATS_MIB_FRAGFAILS */
88 [20] = RTNL_LINK_IP6_FRAGCREATES, /* IPSTATS_MIB_FRAGCREATES */
89 [21] = RTNL_LINK_IP6_INMCASTPKTS, /* IPSTATS_MIB_INMCASTPKTS */
90 [22] = RTNL_LINK_IP6_OUTMCASTPKTS, /* IPSTATS_MIB_OUTMCASTPKTS */
91 [23] = RTNL_LINK_IP6_INBCASTPKTS, /* IPSTATS_MIB_INBCASTPKTS */
92 [24] = RTNL_LINK_IP6_OUTBCASTPKTS, /* IPSTATS_MIB_OUTBCASTPKTS */
93 [25] = RTNL_LINK_IP6_INOCTETS, /* IPSTATS_MIB_INOCTETS */
94 [26] = RTNL_LINK_IP6_OUTOCTETS, /* IPSTATS_MIB_OUTOCTETS */
95 [27] = RTNL_LINK_IP6_INMCASTOCTETS, /* IPSTATS_MIB_INMCASTOCTETS */
96 [28] = RTNL_LINK_IP6_OUTMCASTOCTETS, /* IPSTATS_MIB_OUTMCASTOCTETS */
97 [29] = RTNL_LINK_IP6_INBCASTOCTETS, /* IPSTATS_MIB_INBCASTOCTETS */
98 [30] = RTNL_LINK_IP6_OUTBCASTOCTETS, /* IPSTATS_MIB_OUTBCASTOCTETS */
99};
100
101static const uint8_t map_stat_id_from_IPSTATS_MIB_v2[__IPSTATS_MIB_MAX] = {
102 /* d8ec26d7f8287f5788a494f56e8814210f0e64be:include/uapi/linux/snmp.h
103 * version since the API change in commit 14a196807482e6fc74f15fc03176d5c08880588f */
104 [ 1] = RTNL_LINK_IP6_INPKTS, /* IPSTATS_MIB_INPKTS */
105 [ 2] = RTNL_LINK_IP6_INOCTETS, /* IPSTATS_MIB_INOCTETS */
106 [ 3] = RTNL_LINK_IP6_INDELIVERS, /* IPSTATS_MIB_INDELIVERS */
107 [ 4] = RTNL_LINK_IP6_OUTFORWDATAGRAMS, /* IPSTATS_MIB_OUTFORWDATAGRAMS */
108 [ 5] = RTNL_LINK_IP6_OUTPKTS, /* IPSTATS_MIB_OUTPKTS */
109 [ 6] = RTNL_LINK_IP6_OUTOCTETS, /* IPSTATS_MIB_OUTOCTETS */
110 [ 7] = RTNL_LINK_IP6_INHDRERRORS, /* IPSTATS_MIB_INHDRERRORS */
111 [ 8] = RTNL_LINK_IP6_INTOOBIGERRORS, /* IPSTATS_MIB_INTOOBIGERRORS */
112 [ 9] = RTNL_LINK_IP6_INNOROUTES, /* IPSTATS_MIB_INNOROUTES */
113 [10] = RTNL_LINK_IP6_INADDRERRORS, /* IPSTATS_MIB_INADDRERRORS */
114 [11] = RTNL_LINK_IP6_INUNKNOWNPROTOS, /* IPSTATS_MIB_INUNKNOWNPROTOS */
115 [12] = RTNL_LINK_IP6_INTRUNCATEDPKTS, /* IPSTATS_MIB_INTRUNCATEDPKTS */
116 [13] = RTNL_LINK_IP6_INDISCARDS, /* IPSTATS_MIB_INDISCARDS */
117 [14] = RTNL_LINK_IP6_OUTDISCARDS, /* IPSTATS_MIB_OUTDISCARDS */
118 [15] = RTNL_LINK_IP6_OUTNOROUTES, /* IPSTATS_MIB_OUTNOROUTES */
119 [16] = RTNL_LINK_IP6_REASMTIMEOUT, /* IPSTATS_MIB_REASMTIMEOUT */
120 [17] = RTNL_LINK_IP6_REASMREQDS, /* IPSTATS_MIB_REASMREQDS */
121 [18] = RTNL_LINK_IP6_REASMOKS, /* IPSTATS_MIB_REASMOKS */
122 [19] = RTNL_LINK_IP6_REASMFAILS, /* IPSTATS_MIB_REASMFAILS */
123 [20] = RTNL_LINK_IP6_FRAGOKS, /* IPSTATS_MIB_FRAGOKS */
124 [21] = RTNL_LINK_IP6_FRAGFAILS, /* IPSTATS_MIB_FRAGFAILS */
125 [22] = RTNL_LINK_IP6_FRAGCREATES, /* IPSTATS_MIB_FRAGCREATES */
126 [23] = RTNL_LINK_IP6_INMCASTPKTS, /* IPSTATS_MIB_INMCASTPKTS */
127 [24] = RTNL_LINK_IP6_OUTMCASTPKTS, /* IPSTATS_MIB_OUTMCASTPKTS */
128 [25] = RTNL_LINK_IP6_INBCASTPKTS, /* IPSTATS_MIB_INBCASTPKTS */
129 [26] = RTNL_LINK_IP6_OUTBCASTPKTS, /* IPSTATS_MIB_OUTBCASTPKTS */
130 [27] = RTNL_LINK_IP6_INMCASTOCTETS, /* IPSTATS_MIB_INMCASTOCTETS */
131 [28] = RTNL_LINK_IP6_OUTMCASTOCTETS, /* IPSTATS_MIB_OUTMCASTOCTETS */
132 [29] = RTNL_LINK_IP6_INBCASTOCTETS, /* IPSTATS_MIB_INBCASTOCTETS */
133 [30] = RTNL_LINK_IP6_OUTBCASTOCTETS, /* IPSTATS_MIB_OUTBCASTOCTETS */
134 [31] = RTNL_LINK_IP6_CSUMERRORS, /* IPSTATS_MIB_CSUMERRORS */
135 [32] = RTNL_LINK_IP6_NOECTPKTS, /* IPSTATS_MIB_NOECTPKTS */
136 [33] = RTNL_LINK_IP6_ECT1PKTS, /* IPSTATS_MIB_ECT1PKTS */
137 [34] = RTNL_LINK_IP6_ECT0PKTS, /* IPSTATS_MIB_ECT0PKTS */
138 [35] = RTNL_LINK_IP6_CEPKTS, /* IPSTATS_MIB_CEPKTS */
139 [36] = RTNL_LINK_REASM_OVERLAPS, /* IPSTATS_MIB_REASM_OVERLAPS */
140};
141
142const uint8_t *const _nltst_map_stat_id_from_IPSTATS_MIB_v2 = map_stat_id_from_IPSTATS_MIB_v2;
143
144static int inet6_parse_protinfo(struct rtnl_link *link, struct nlattr *attr,
145 void *data)
146{
147 struct inet6_data *i6 = data;
148 struct nlattr *tb[IFLA_INET6_MAX+1];
149 int err;
150
151 err = nla_parse_nested(tb, IFLA_INET6_MAX, attr, inet6_policy);
152 if (err < 0)
153 return err;
154 if (tb[IFLA_INET6_CONF] && nla_len(tb[IFLA_INET6_CONF]) % 4)
155 return -EINVAL;
156 if (tb[IFLA_INET6_STATS] && nla_len(tb[IFLA_INET6_STATS]) % 8)
157 return -EINVAL;
158 if (tb[IFLA_INET6_ICMP6STATS] && nla_len(tb[IFLA_INET6_ICMP6STATS]) % 8)
159 return -EINVAL;
160
161 if (tb[IFLA_INET6_FLAGS])
162 i6->i6_flags = nla_get_u32(tb[IFLA_INET6_FLAGS]);
163
164 if (tb[IFLA_INET6_CACHEINFO])
165 nla_memcpy(&i6->i6_cacheinfo, tb[IFLA_INET6_CACHEINFO],
166 sizeof(i6->i6_cacheinfo));
167
168 if (tb[IFLA_INET6_CONF])
169 nla_memcpy(&i6->i6_conf, tb[IFLA_INET6_CONF],
170 sizeof(i6->i6_conf));
171
172 if (tb[IFLA_INET6_TOKEN])
173 nla_memcpy(&i6->i6_token, tb[IFLA_INET6_TOKEN],
174 sizeof(struct in6_addr));
175
176 if (tb[IFLA_INET6_ADDR_GEN_MODE])
177 i6->i6_addr_gen_mode = nla_get_u8 (tb[IFLA_INET6_ADDR_GEN_MODE]);
178
179 /*
180 * Due to 32bit data alignment, these addresses must be copied to an
181 * aligned location prior to access.
182 */
183 if (tb[IFLA_INET6_STATS]) {
184 unsigned char *cnt = nla_data(tb[IFLA_INET6_STATS]);
185 uint64_t stat;
186 int i;
187 int len = nla_len(tb[IFLA_INET6_STATS]) / 8;
188 const uint8_t *map_stat_id = map_stat_id_from_IPSTATS_MIB_v2;
189
190 if (len < 32 ||
191 (tb[IFLA_INET6_ICMP6STATS] && nla_len(tb[IFLA_INET6_ICMP6STATS]) < 6)) {
192 /* kernel commit 14a196807482e6fc74f15fc03176d5c08880588f reordered the values.
193 * The later commit 6a5dc9e598fe90160fee7de098fa319665f5253e added values
194 * IPSTATS_MIB_CSUMERRORS/ICMP6_MIB_CSUMERRORS. If the netlink is shorter
195 * then this, assume that the kernel uses the previous meaning of the
196 * enumeration. */
197 map_stat_id = map_stat_id_from_IPSTATS_MIB_v1;
198 }
199
200 len = min_t(int, __IPSTATS_MIB_MAX, len);
201 for (i = 1; i < len; i++) {
202 memcpy(&stat, &cnt[i * sizeof(stat)], sizeof(stat));
203 rtnl_link_set_stat(link, map_stat_id[i], stat);
204 }
205 }
206
207 if (tb[IFLA_INET6_ICMP6STATS]) {
208 unsigned char *cnt = nla_data(tb[IFLA_INET6_ICMP6STATS]);
209 uint64_t stat;
210 int i;
211 int len = min_t(int, __ICMP6_MIB_MAX, nla_len(tb[IFLA_INET6_ICMP6STATS]) / 8);
212
213 _NL_STATIC_ASSERT (__ICMP6_MIB_MAX == 6);
214 _NL_STATIC_ASSERT (RTNL_LINK_ICMP6_CSUMERRORS - RTNL_LINK_ICMP6_INMSGS + 1 == 5);
215
216 for (i = 1; i < len; i++) {
217 memcpy(&stat, &cnt[i * sizeof(stat)], sizeof(stat));
219 stat);
220 }
221 }
222
223 return 0;
224}
225
226static int inet6_fill_af(struct rtnl_link *link, struct nl_msg *msg, void *data)
227{
228 struct inet6_data *id = data;
229
230 if (id->i6_addr_gen_mode != I6_ADDR_GEN_MODE_UNKNOWN)
231 NLA_PUT_U8(msg, IFLA_INET6_ADDR_GEN_MODE, id->i6_addr_gen_mode);
232
233 return 0;
234
235nla_put_failure:
236 return -NLE_MSGSIZE;
237}
238
239/* These live in include/net/if_inet6.h and should be moved to include/linux */
240#define IF_RA_OTHERCONF 0x80
241#define IF_RA_MANAGED 0x40
242#define IF_RA_RCVD 0x20
243#define IF_RS_SENT 0x10
244#define IF_READY 0x80000000
245
246static const struct trans_tbl inet6_flags[] = {
247 __ADD(IF_RA_OTHERCONF, ra_otherconf),
248 __ADD(IF_RA_MANAGED, ra_managed),
249 __ADD(IF_RA_RCVD, ra_rcvd),
250 __ADD(IF_RS_SENT, rs_sent),
251 __ADD(IF_READY, ready),
252};
253
254char *rtnl_link_inet6_flags2str(int flags, char *buf, size_t len)
255{
256 return __flags2str(flags, buf, len, inet6_flags,
257 ARRAY_SIZE(inet6_flags));
258}
259
260int rtnl_link_inet6_str2flags(const char *name)
261{
262 return __str2flags(name, inet6_flags, ARRAY_SIZE(inet6_flags));
263}
264
265static const struct trans_tbl inet6_devconf[] = {
266 __ADD(DEVCONF_FORWARDING, forwarding),
267 __ADD(DEVCONF_HOPLIMIT, hoplimit),
268 __ADD(DEVCONF_MTU6, mtu6),
269 __ADD(DEVCONF_ACCEPT_RA, accept_ra),
270 __ADD(DEVCONF_ACCEPT_REDIRECTS, accept_redirects),
271 __ADD(DEVCONF_AUTOCONF, autoconf),
272 __ADD(DEVCONF_DAD_TRANSMITS, dad_transmits),
273 __ADD(DEVCONF_RTR_SOLICITS, rtr_solicits),
274 __ADD(DEVCONF_RTR_SOLICIT_INTERVAL, rtr_solicit_interval),
275 __ADD(DEVCONF_RTR_SOLICIT_DELAY, rtr_solicit_delay),
276 __ADD(DEVCONF_USE_TEMPADDR, use_tempaddr),
277 __ADD(DEVCONF_TEMP_VALID_LFT, temp_valid_lft),
278 __ADD(DEVCONF_TEMP_PREFERED_LFT, temp_prefered_lft),
279 __ADD(DEVCONF_REGEN_MAX_RETRY, regen_max_retry),
280 __ADD(DEVCONF_MAX_DESYNC_FACTOR, max_desync_factor),
281 __ADD(DEVCONF_MAX_ADDRESSES, max_addresses),
282 __ADD(DEVCONF_FORCE_MLD_VERSION, force_mld_version),
283 __ADD(DEVCONF_ACCEPT_RA_DEFRTR, accept_ra_defrtr),
284 __ADD(DEVCONF_ACCEPT_RA_PINFO, accept_ra_pinfo),
285 __ADD(DEVCONF_ACCEPT_RA_RTR_PREF, accept_ra_rtr_pref),
286 __ADD(DEVCONF_RTR_PROBE_INTERVAL, rtr_probe_interval),
287 __ADD(DEVCONF_ACCEPT_RA_RT_INFO_MAX_PLEN, accept_ra_rt_info),
288 __ADD(DEVCONF_PROXY_NDP, proxy_ndp),
289 __ADD(DEVCONF_OPTIMISTIC_DAD, optimistic_dad),
290 __ADD(DEVCONF_ACCEPT_SOURCE_ROUTE, accept_source_route),
291 __ADD(DEVCONF_MC_FORWARDING, mc_forwarding),
292 __ADD(DEVCONF_DISABLE_IPV6, disable_ipv6),
293 __ADD(DEVCONF_ACCEPT_DAD, accept_dad),
294 __ADD(DEVCONF_FORCE_TLLAO, force_tllao),
295};
296
297static char *inet6_devconf2str(int type, char *buf, size_t len)
298{
299 return __type2str(type, buf, len, inet6_devconf,
300 ARRAY_SIZE(inet6_devconf));
301}
302
303static const struct trans_tbl inet6_addr_gen_mode[] = {
304 __ADD(IN6_ADDR_GEN_MODE_EUI64, eui64),
305 __ADD(IN6_ADDR_GEN_MODE_NONE, none),
306 __ADD(IN6_ADDR_GEN_MODE_STABLE_PRIVACY, stable_privacy),
307};
308
309const char *rtnl_link_inet6_addrgenmode2str(uint8_t mode, char *buf, size_t len)
310{
311 return __type2str(mode, buf, len, inet6_addr_gen_mode,
312 ARRAY_SIZE(inet6_addr_gen_mode));
313}
314
315uint8_t rtnl_link_inet6_str2addrgenmode(const char *mode)
316{
317 return (uint8_t) __str2type(mode, inet6_addr_gen_mode,
318 ARRAY_SIZE(inet6_addr_gen_mode));
319}
320
321static void inet6_dump_details(struct rtnl_link *link,
322 struct nl_dump_params *p, void *data)
323{
324 struct inet6_data *i6 = data;
325 struct nl_addr *addr;
326 int i, n = 0;
327 char buf[64];
328
329 nl_dump_line(p, " ipv6 max-reasm-len %s",
330 nl_size2str(i6->i6_cacheinfo.max_reasm_len, buf, sizeof(buf)));
331
332 nl_dump(p, " <%s>\n",
333 rtnl_link_inet6_flags2str(i6->i6_flags, buf, sizeof(buf)));
334
335 nl_dump_line(p, " create-stamp %.2fs reachable-time %s",
336 (double) i6->i6_cacheinfo.tstamp / 100.,
337 nl_msec2str(i6->i6_cacheinfo.reachable_time, buf, sizeof(buf)));
338
339 nl_dump(p, " retrans-time %s\n",
340 nl_msec2str(i6->i6_cacheinfo.retrans_time, buf, sizeof(buf)));
341
342 addr = nl_addr_build(AF_INET6, &i6->i6_token, sizeof(i6->i6_token));
343 nl_dump(p, " token %s\n",
344 nl_addr2str(addr, buf, sizeof(buf)));
345 nl_addr_put(addr);
346
347 nl_dump(p, " link-local address mode %s\n",
348 rtnl_link_inet6_addrgenmode2str(i6->i6_addr_gen_mode,
349 buf, sizeof(buf)));
350
351 nl_dump_line(p, " devconf:\n");
352 nl_dump_line(p, " ");
353
354 for (i = 0; i < DEVCONF_MAX; i++) {
355 char buf2[64];
356 uint32_t value = i6->i6_conf[i];
357 int x, offset;
358
359 switch (i) {
360 case DEVCONF_TEMP_VALID_LFT:
361 case DEVCONF_TEMP_PREFERED_LFT:
362 nl_msec2str((uint64_t) value * 1000., buf2, sizeof(buf2));
363 break;
364
365 case DEVCONF_RTR_PROBE_INTERVAL:
366 case DEVCONF_RTR_SOLICIT_INTERVAL:
367 case DEVCONF_RTR_SOLICIT_DELAY:
368 nl_msec2str(value, buf2, sizeof(buf2));
369 break;
370
371 default:
372 snprintf(buf2, sizeof(buf2), "%u", value);
373 break;
374 }
375
376 inet6_devconf2str(i, buf, sizeof(buf));
377
378 offset = 23 - strlen(buf2);
379 if (offset < 0)
380 offset = 0;
381
382 for (x = strlen(buf); x < offset; x++)
383 buf[x] = ' ';
384
385 _nl_strncpy_trunc(&buf[offset], buf2, sizeof(buf) - offset);
386
387 nl_dump_line(p, "%s", buf);
388
389 if (++n == 3) {
390 nl_dump(p, "\n");
391 nl_dump_line(p, " ");
392 n = 0;
393 } else
394 nl_dump(p, " ");
395 }
396
397 if (n != 0)
398 nl_dump(p, "\n");
399}
400
401static void inet6_dump_stats(struct rtnl_link *link,
402 struct nl_dump_params *p, void *data)
403{
404 double octets;
405 char *octetsUnit;
406
407 nl_dump(p, " IPv6: InPkts InOctets "
408 " InDiscards InDelivers\n");
409 nl_dump(p, " %18" PRIu64 " ", link->l_stats[RTNL_LINK_IP6_INPKTS]);
410
411 octets = nl_cancel_down_bytes(link->l_stats[RTNL_LINK_IP6_INOCTETS],
412 &octetsUnit);
413 if (octets)
414 nl_dump(p, "%14.2f %3s ", octets, octetsUnit);
415 else
416 nl_dump(p, "%16u B ", 0);
417
418 nl_dump(p, "%18" PRIu64 " %18" PRIu64 "\n",
419 link->l_stats[RTNL_LINK_IP6_INDISCARDS],
420 link->l_stats[RTNL_LINK_IP6_INDELIVERS]);
421
422 nl_dump(p, " OutPkts OutOctets "
423 " OutDiscards OutForwards\n");
424
425 nl_dump(p, " %18" PRIu64 " ", link->l_stats[RTNL_LINK_IP6_OUTPKTS]);
426
427 octets = nl_cancel_down_bytes(link->l_stats[RTNL_LINK_IP6_OUTOCTETS],
428 &octetsUnit);
429 if (octets)
430 nl_dump(p, "%14.2f %3s ", octets, octetsUnit);
431 else
432 nl_dump(p, "%16u B ", 0);
433
434 nl_dump(p, "%18" PRIu64 " %18" PRIu64 "\n",
435 link->l_stats[RTNL_LINK_IP6_OUTDISCARDS],
436 link->l_stats[RTNL_LINK_IP6_OUTFORWDATAGRAMS]);
437
438 nl_dump(p, " InMcastPkts InMcastOctets "
439 " InBcastPkts InBcastOctests\n");
440
441 nl_dump(p, " %18" PRIu64 " ", link->l_stats[RTNL_LINK_IP6_INMCASTPKTS]);
442
444 &octetsUnit);
445 if (octets)
446 nl_dump(p, "%14.2f %3s ", octets, octetsUnit);
447 else
448 nl_dump(p, "%16u B ", 0);
449
450 nl_dump(p, "%18" PRIu64 " ", link->l_stats[RTNL_LINK_IP6_INBCASTPKTS]);
452 &octetsUnit);
453 if (octets)
454 nl_dump(p, "%14.2f %3s\n", octets, octetsUnit);
455 else
456 nl_dump(p, "%16u B\n", 0);
457
458 nl_dump(p, " OutMcastPkts OutMcastOctets "
459 " OutBcastPkts OutBcastOctests\n");
460
461 nl_dump(p, " %18" PRIu64 " ", link->l_stats[RTNL_LINK_IP6_OUTMCASTPKTS]);
462
464 &octetsUnit);
465 if (octets)
466 nl_dump(p, "%14.2f %3s ", octets, octetsUnit);
467 else
468 nl_dump(p, "%16u B ", 0);
469
470 nl_dump(p, "%18" PRIu64 " ", link->l_stats[RTNL_LINK_IP6_OUTBCASTPKTS]);
472 &octetsUnit);
473 if (octets)
474 nl_dump(p, "%14.2f %3s\n", octets, octetsUnit);
475 else
476 nl_dump(p, "%16u B\n", 0);
477
478 nl_dump(p, " ReasmOKs ReasmFails "
479 " ReasmReqds ReasmTimeout\n");
480 nl_dump(p, " %18" PRIu64 " %18" PRIu64 " %18" PRIu64 " %18" PRIu64 "\n",
481 link->l_stats[RTNL_LINK_IP6_REASMOKS],
482 link->l_stats[RTNL_LINK_IP6_REASMFAILS],
483 link->l_stats[RTNL_LINK_IP6_REASMREQDS],
484 link->l_stats[RTNL_LINK_IP6_REASMTIMEOUT]);
485
486 nl_dump(p, " FragOKs FragFails "
487 " FragCreates\n");
488 nl_dump(p, " %18" PRIu64 " %18" PRIu64 " %18" PRIu64 "\n",
489 link->l_stats[RTNL_LINK_IP6_FRAGOKS],
490 link->l_stats[RTNL_LINK_IP6_FRAGFAILS],
491 link->l_stats[RTNL_LINK_IP6_FRAGCREATES]);
492
493 nl_dump(p, " InHdrErrors InTooBigErrors "
494 " InNoRoutes InAddrErrors\n");
495 nl_dump(p, " %18" PRIu64 " %18" PRIu64 " %18" PRIu64 " %18" PRIu64 "\n",
496 link->l_stats[RTNL_LINK_IP6_INHDRERRORS],
497 link->l_stats[RTNL_LINK_IP6_INTOOBIGERRORS],
498 link->l_stats[RTNL_LINK_IP6_INNOROUTES],
499 link->l_stats[RTNL_LINK_IP6_INADDRERRORS]);
500
501 nl_dump(p, " InUnknownProtos InTruncatedPkts "
502 " OutNoRoutes InCsumErrors\n");
503 nl_dump(p, " %18" PRIu64 " %18" PRIu64 " %18" PRIu64 " %18" PRIu64 "\n",
504 link->l_stats[RTNL_LINK_IP6_INUNKNOWNPROTOS],
505 link->l_stats[RTNL_LINK_IP6_INTRUNCATEDPKTS],
506 link->l_stats[RTNL_LINK_IP6_OUTNOROUTES],
507 link->l_stats[RTNL_LINK_IP6_CSUMERRORS]);
508
509 nl_dump(p, " InNoECTPkts InECT1Pkts "
510 " InECT0Pkts InCEPkts\n");
511 nl_dump(p, " %18" PRIu64 " %18" PRIu64 " %18" PRIu64 " %18" PRIu64 "\n",
512 link->l_stats[RTNL_LINK_IP6_NOECTPKTS],
513 link->l_stats[RTNL_LINK_IP6_ECT1PKTS],
514 link->l_stats[RTNL_LINK_IP6_ECT0PKTS],
515 link->l_stats[RTNL_LINK_IP6_CEPKTS]);
516
517 nl_dump(p, " ICMPv6: InMsgs InErrors "
518 " OutMsgs OutErrors InCsumErrors\n");
519 nl_dump(p, " %18" PRIu64 " %18" PRIu64 " %18" PRIu64 " %18" PRIu64 " %18" PRIu64 "\n",
520 link->l_stats[RTNL_LINK_ICMP6_INMSGS],
521 link->l_stats[RTNL_LINK_ICMP6_INERRORS],
522 link->l_stats[RTNL_LINK_ICMP6_OUTMSGS],
523 link->l_stats[RTNL_LINK_ICMP6_OUTERRORS],
524 link->l_stats[RTNL_LINK_ICMP6_CSUMERRORS]);
525}
526
527static const struct nla_policy protinfo_policy = {
528 .type = NLA_NESTED,
529};
530
531static struct rtnl_link_af_ops inet6_ops = {
532 .ao_family = AF_INET6,
533 .ao_alloc = &inet6_alloc,
534 .ao_clone = &inet6_clone,
535 .ao_free = &inet6_free,
536 .ao_parse_protinfo = &inet6_parse_protinfo,
537 .ao_parse_af = &inet6_parse_protinfo,
538 .ao_fill_af = &inet6_fill_af,
539 .ao_dump[NL_DUMP_DETAILS] = &inet6_dump_details,
540 .ao_dump[NL_DUMP_STATS] = &inet6_dump_stats,
541 .ao_protinfo_policy = &protinfo_policy,
542};
543
544/**
545 * Return IPv6 specific flags
546 * @arg link Link object
547 * @arg out_flags Flags on success
548 *
549 * Returns the link's IPv6 flags.
550 *
551 * @return 0 on success
552 * @return -NLE_NOATTR configuration setting not available
553 */
554int rtnl_link_inet6_get_flags(struct rtnl_link *link, uint32_t* out_flags)
555{
556 struct inet6_data *id = NULL;
557
558 if (!(id = rtnl_link_af_data(link, &inet6_ops)))
559 return -NLE_NOATTR;
560
561 *out_flags = id->i6_flags;
562 return 0;
563}
564
565/**
566 * Set IPv6 specific flags
567 * @arg link Link object
568 * @arg flags Flags to set
569 *
570 * Sets the link's IPv6 specific flags. Overwrites currently set flags.
571 *
572 * @return 0 on success
573 * @return -NLE_NOMEM could not allocate inet6 data
574 */
575int rtnl_link_inet6_set_flags(struct rtnl_link *link, uint32_t flags)
576{
577 struct inet6_data *id;
578
579 if (!(id = rtnl_link_af_alloc(link, &inet6_ops)))
580 return -NLE_NOMEM;
581
582 id->i6_flags = flags;
583 return 0;
584}
585
586/**
587 * Get IPv6 tokenized interface identifier
588 * @arg link Link object
589 * @arg token Tokenized interface identifier on success
590 *
591 * Returns the link's IPv6 tokenized interface identifier.
592 *
593 * @return 0 on success
594 * @return -NLE_NOMEM failure to allocate struct nl_addr result
595 * @return -NLE_NOATTR configuration setting not available
596 * @return -NLE_NOADDR tokenized interface identifier is not set
597 */
598int rtnl_link_inet6_get_token(struct rtnl_link *link, struct nl_addr **addr)
599{
600 struct inet6_data *id;
601
602 if (!(id = rtnl_link_af_data(link, &inet6_ops)))
603 return -NLE_NOATTR;
604
605 *addr = nl_addr_build(AF_INET6, &id->i6_token, sizeof(id->i6_token));
606 if (!*addr)
607 return -NLE_NOMEM;
608 if (nl_addr_iszero(*addr)) {
609 nl_addr_put(*addr);
610 *addr = NULL;
611 return -NLE_NOADDR;
612 }
613
614 return 0;
615}
616
617/**
618 * Set IPv6 tokenized interface identifier
619 * @arg link Link object
620 * @arg token Tokenized interface identifier
621 *
622 * Sets the link's IPv6 tokenized interface identifier.
623 *
624 * @return 0 on success
625 * @return -NLE_NOMEM could not allocate inet6 data
626 * @return -NLE_INVAL addr is not a valid inet6 address
627 */
628int rtnl_link_inet6_set_token(struct rtnl_link *link, struct nl_addr *addr)
629{
630 struct inet6_data *id;
631
632 if ((nl_addr_get_family(addr) != AF_INET6) ||
633 (nl_addr_get_len(addr) != sizeof(id->i6_token)))
634 return -NLE_INVAL;
635
636 if (!(id = rtnl_link_af_alloc(link, &inet6_ops)))
637 return -NLE_NOMEM;
638
639 memcpy(&id->i6_token, nl_addr_get_binary_addr(addr),
640 sizeof(id->i6_token));
641 return 0;
642}
643
644/**
645 * Get IPv6 link-local address generation mode
646 * @arg link Link object
647 * @arg mode Generation mode on success
648 *
649 * Returns the link's IPv6 link-local address generation mode.
650 *
651 * @return 0 on success
652 * @return -NLE_NOATTR configuration setting not available
653 * @return -NLE_INVAL generation mode unknown. If the link was received via
654 * netlink, it means that address generation mode is not
655 * supported by the kernel.
656 */
657int rtnl_link_inet6_get_addr_gen_mode(struct rtnl_link *link, uint8_t *mode)
658{
659 struct inet6_data *id;
660
661 if (!(id = rtnl_link_af_data(link, &inet6_ops)))
662 return -NLE_NOATTR;
663
664 if (id->i6_addr_gen_mode == I6_ADDR_GEN_MODE_UNKNOWN)
665 return -NLE_INVAL;
666
667 *mode = id->i6_addr_gen_mode;
668 return 0;
669}
670
671/**
672 * Set IPv6 link-local address generation mode
673 * @arg link Link object
674 * @arg mode Generation mode
675 *
676 * Sets the link's IPv6 link-local address generation mode.
677 *
678 * @return 0 on success
679 * @return -NLE_NOMEM could not allocate inet6 data
680 */
681int rtnl_link_inet6_set_addr_gen_mode(struct rtnl_link *link, uint8_t mode)
682{
683 struct inet6_data *id;
684
685 if (!(id = rtnl_link_af_alloc(link, &inet6_ops)))
686 return -NLE_NOMEM;
687
688 id->i6_addr_gen_mode = mode;
689 return 0;
690}
691
692static void __init inet6_init(void)
693{
694 rtnl_link_af_register(&inet6_ops);
695}
696
697static void __exit inet6_exit(void)
698{
699 rtnl_link_af_unregister(&inet6_ops);
700}
int nl_addr_iszero(const struct nl_addr *addr)
Returns true if the address consists of all zeros.
Definition: addr.c:649
struct nl_addr * nl_addr_build(int family, const void *buf, size_t size)
Allocate abstract address based on a binary address.
Definition: addr.c:211
void * nl_addr_get_binary_addr(const struct nl_addr *addr)
Get binary address of abstract address object.
Definition: addr.c:940
int nl_addr_get_family(const struct nl_addr *addr)
Return address family.
Definition: addr.c:892
char * nl_addr2str(const struct nl_addr *addr, char *buf, size_t size)
Convert abstract address object to character string.
Definition: addr.c:998
unsigned int nl_addr_get_len(const struct nl_addr *addr)
Get length of binary address of abstract address object.
Definition: addr.c:952
void nl_addr_put(struct nl_addr *addr)
Decrease the reference counter of an abstract address.
Definition: addr.c:538
uint32_t nla_get_u32(const struct nlattr *nla)
Return payload of 32 bit integer attribute.
Definition: attr.c:702
#define NLA_PUT_U8(msg, attrtype, value)
Add 8 bit integer attribute to netlink message.
Definition: attr.h:194
void * nla_data(const struct nlattr *nla)
Return pointer to the payload section.
Definition: attr.c:114
uint8_t nla_get_u8(const struct nlattr *nla)
Return value of 8 bit integer attribute.
Definition: attr.c:602
int nla_memcpy(void *dest, const struct nlattr *src, int count)
Copy attribute payload to another memory area.
Definition: attr.c:346
int nla_parse_nested(struct nlattr *tb[], int maxtype, struct nlattr *nla, const struct nla_policy *policy)
Create attribute index based on nested attribute.
Definition: attr.c:1016
int nla_len(const struct nlattr *nla)
Return length of the payload .
Definition: attr.c:125
@ NLA_U8
8 bit integer
Definition: attr.h:35
@ NLA_NESTED
Nested attributes.
Definition: attr.h:42
@ NLA_U32
32 bit integer
Definition: attr.h:37
char * nl_size2str(const size_t size, char *buf, const size_t len)
Convert a size toa character string.
Definition: utils.c:351
void nl_dump(struct nl_dump_params *params, const char *fmt,...)
Dump a formatted character string.
Definition: utils.c:955
double nl_cancel_down_bytes(unsigned long long l, char **unit)
Cancel down a byte counter.
Definition: utils.c:163
char * nl_msec2str(uint64_t msec, char *buf, size_t len)
Convert milliseconds to a character string.
Definition: utils.c:588
@ NL_DUMP_STATS
Dump all attributes including statistics.
Definition: types.h:18
@ NL_DUMP_DETAILS
Dump all attributes but no statistics.
Definition: types.h:17
Dumping parameters.
Definition: types.h:28
Attribute validation policy.
Definition: attr.h:63
uint16_t type
Type of attribute or NLA_UNSPEC.
Definition: attr.h:65