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