libnl  3.6.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 
18 struct inet6_data
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 
27 static 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 
38 static 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 
48 static void inet6_free(struct rtnl_link *link, void *data)
49 {
50  free(data);
51 }
52 
53 static 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 
63 static 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 
101 static 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 
142 const uint8_t *const _nltst_map_stat_id_from_IPSTATS_MIB_v2 = map_stat_id_from_IPSTATS_MIB_v2;
143 
144 static 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 
226 static 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 
235 nla_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 
246 static 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 
254 char *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 
260 int rtnl_link_inet6_str2flags(const char *name)
261 {
262  return __str2flags(name, inet6_flags, ARRAY_SIZE(inet6_flags));
263 }
264 
265 static 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 
297 static 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 
303 static 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 
309 const 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 
315 uint8_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 
321 static 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 
401 static 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, "%16" PRIu64 " 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, "%16" PRIu64 " 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 
443  octets = nl_cancel_down_bytes(link->l_stats[RTNL_LINK_IP6_INMCASTOCTETS],
444  &octetsUnit);
445  if (octets)
446  nl_dump(p, "%14.2f %3s ", octets, octetsUnit);
447  else
448  nl_dump(p, "%16" PRIu64 " B ", 0);
449 
450  nl_dump(p, "%18" PRIu64 " ", link->l_stats[RTNL_LINK_IP6_INBCASTPKTS]);
451  octets = nl_cancel_down_bytes(link->l_stats[RTNL_LINK_IP6_INBCASTOCTETS],
452  &octetsUnit);
453  if (octets)
454  nl_dump(p, "%14.2f %3s\n", octets, octetsUnit);
455  else
456  nl_dump(p, "%16" PRIu64 " 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 
463  octets = nl_cancel_down_bytes(link->l_stats[RTNL_LINK_IP6_OUTMCASTOCTETS],
464  &octetsUnit);
465  if (octets)
466  nl_dump(p, "%14.2f %3s ", octets, octetsUnit);
467  else
468  nl_dump(p, "%16" PRIu64 " B ", 0);
469 
470  nl_dump(p, "%18" PRIu64 " ", link->l_stats[RTNL_LINK_IP6_OUTBCASTPKTS]);
471  octets = nl_cancel_down_bytes(link->l_stats[RTNL_LINK_IP6_OUTBCASTOCTETS],
472  &octetsUnit);
473  if (octets)
474  nl_dump(p, "%14.2f %3s\n", octets, octetsUnit);
475  else
476  nl_dump(p, "%16" PRIu64 " 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 
527 static const struct nla_policy protinfo_policy = {
528  .type = NLA_NESTED,
529 };
530 
531 static 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  */
554 int 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  */
575 int 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  */
598 int 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  */
628 int 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  */
657 int 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  */
681 int 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 
692 static void __init inet6_init(void)
693 {
694  rtnl_link_af_register(&inet6_ops);
695 }
696 
697 static void __exit inet6_exit(void)
698 {
699  rtnl_link_af_unregister(&inet6_ops);
700 }
void * nl_addr_get_binary_addr(const struct nl_addr *addr)
Get binary address of abstract address object.
Definition: addr.c:935
int nl_addr_iszero(const struct nl_addr *addr)
Returns true if the address consists of all zeros.
Definition: addr.c:644
char * nl_addr2str(const struct nl_addr *addr, char *buf, size_t size)
Convert abstract address object to character string.
Definition: addr.c:993
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
int nl_addr_get_family(const struct nl_addr *addr)
Return address family.
Definition: addr.c:887
unsigned int nl_addr_get_len(const struct nl_addr *addr)
Get length of binary address of abstract address object.
Definition: addr.c:947
void nl_addr_put(struct nl_addr *addr)
Decrease the reference counter of an abstract address.
Definition: addr.c:533
uint32_t nla_get_u32(const struct nlattr *nla)
Return payload of 32 bit integer attribute.
Definition: attr.c:699
#define NLA_PUT_U8(msg, attrtype, value)
Add 8 bit integer attribute to netlink message.
Definition: attr.h:194
uint8_t nla_get_u8(const struct nlattr *nla)
Return value of 8 bit integer attribute.
Definition: attr.c:599
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:1013
int nla_len(const struct nlattr *nla)
Return length of the payload .
Definition: attr.c:125
void * nla_data(const struct nlattr *nla)
Return pointer to the payload section.
Definition: attr.c:114
@ 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