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