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