libnl  3.2.24-rc1
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 struct inet6_data
19 {
20  uint32_t i6_flags;
21  struct ifla_cacheinfo i6_cacheinfo;
22  uint32_t i6_conf[DEVCONF_MAX];
23 };
24 
25 static void *inet6_alloc(struct rtnl_link *link)
26 {
27  return calloc(1, sizeof(struct inet6_data));
28 }
29 
30 static void *inet6_clone(struct rtnl_link *link, void *data)
31 {
32  struct inet6_data *i6;
33 
34  if ((i6 = inet6_alloc(link)))
35  memcpy(i6, data, sizeof(*i6));
36 
37  return i6;
38 }
39 
40 static void inet6_free(struct rtnl_link *link, void *data)
41 {
42  free(data);
43 }
44 
45 static struct nla_policy inet6_policy[IFLA_INET6_MAX+1] = {
46  [IFLA_INET6_FLAGS] = { .type = NLA_U32 },
47  [IFLA_INET6_CACHEINFO] = { .minlen = sizeof(struct ifla_cacheinfo) },
48  [IFLA_INET6_CONF] = { .minlen = DEVCONF_MAX * 4 },
49  [IFLA_INET6_STATS] = { .minlen = __IPSTATS_MIB_MAX * 8 },
50  [IFLA_INET6_ICMP6STATS] = { .minlen = __ICMP6_MIB_MAX * 8 },
51 };
52 
53 static int inet6_parse_protinfo(struct rtnl_link *link, struct nlattr *attr,
54  void *data)
55 {
56  struct inet6_data *i6 = data;
57  struct nlattr *tb[IFLA_INET6_MAX+1];
58  int err;
59 
60  err = nla_parse_nested(tb, IFLA_INET6_MAX, attr, inet6_policy);
61  if (err < 0)
62  return err;
63 
64  if (tb[IFLA_INET6_FLAGS])
65  i6->i6_flags = nla_get_u32(tb[IFLA_INET6_FLAGS]);
66 
67  if (tb[IFLA_INET6_CACHEINFO])
68  nla_memcpy(&i6->i6_cacheinfo, tb[IFLA_INET6_CACHEINFO],
69  sizeof(i6->i6_cacheinfo));
70 
71  if (tb[IFLA_INET6_CONF])
72  nla_memcpy(&i6->i6_conf, tb[IFLA_INET6_CONF],
73  sizeof(i6->i6_conf));
74 
75  /*
76  * Due to 32bit data alignment, these addresses must be copied to an
77  * aligned location prior to access.
78  */
79  if (tb[IFLA_INET6_STATS]) {
80  unsigned char *cnt = nla_data(tb[IFLA_INET6_STATS]);
81  uint64_t stat;
82  int i;
83 
84  for (i = 1; i < __IPSTATS_MIB_MAX; i++) {
85  memcpy(&stat, &cnt[i * sizeof(stat)], sizeof(stat));
87  stat);
88  }
89  }
90 
91  if (tb[IFLA_INET6_ICMP6STATS]) {
92  unsigned char *cnt = nla_data(tb[IFLA_INET6_ICMP6STATS]);
93  uint64_t stat;
94  int i;
95 
96  for (i = 1; i < __ICMP6_MIB_MAX; i++) {
97  memcpy(&stat, &cnt[i * sizeof(stat)], sizeof(stat));
99  stat);
100  }
101  }
102 
103  return 0;
104 }
105 
106 /* These live in include/net/if_inet6.h and should be moved to include/linux */
107 #define IF_RA_OTHERCONF 0x80
108 #define IF_RA_MANAGED 0x40
109 #define IF_RA_RCVD 0x20
110 #define IF_RS_SENT 0x10
111 #define IF_READY 0x80000000
112 
113 static const struct trans_tbl inet6_flags[] = {
114  __ADD(IF_RA_OTHERCONF, ra_otherconf)
115  __ADD(IF_RA_MANAGED, ra_managed)
116  __ADD(IF_RA_RCVD, ra_rcvd)
117  __ADD(IF_RS_SENT, rs_sent)
118  __ADD(IF_READY, ready)
119 };
120 
121 static char *inet6_flags2str(int flags, char *buf, size_t len)
122 {
123  return __flags2str(flags, buf, len, inet6_flags,
124  ARRAY_SIZE(inet6_flags));
125 }
126 
127 static const struct trans_tbl inet6_devconf[] = {
128  __ADD(DEVCONF_FORWARDING, forwarding)
129  __ADD(DEVCONF_HOPLIMIT, hoplimit)
130  __ADD(DEVCONF_MTU6, mtu6)
131  __ADD(DEVCONF_ACCEPT_RA, accept_ra)
132  __ADD(DEVCONF_ACCEPT_REDIRECTS, accept_redirects)
133  __ADD(DEVCONF_AUTOCONF, autoconf)
134  __ADD(DEVCONF_DAD_TRANSMITS, dad_transmits)
135  __ADD(DEVCONF_RTR_SOLICITS, rtr_solicits)
136  __ADD(DEVCONF_RTR_SOLICIT_INTERVAL, rtr_solicit_interval)
137  __ADD(DEVCONF_RTR_SOLICIT_DELAY, rtr_solicit_delay)
138  __ADD(DEVCONF_USE_TEMPADDR, use_tempaddr)
139  __ADD(DEVCONF_TEMP_VALID_LFT, temp_valid_lft)
140  __ADD(DEVCONF_TEMP_PREFERED_LFT, temp_prefered_lft)
141  __ADD(DEVCONF_REGEN_MAX_RETRY, regen_max_retry)
142  __ADD(DEVCONF_MAX_DESYNC_FACTOR, max_desync_factor)
143  __ADD(DEVCONF_MAX_ADDRESSES, max_addresses)
144  __ADD(DEVCONF_FORCE_MLD_VERSION, force_mld_version)
145  __ADD(DEVCONF_ACCEPT_RA_DEFRTR, accept_ra_defrtr)
146  __ADD(DEVCONF_ACCEPT_RA_PINFO, accept_ra_pinfo)
147  __ADD(DEVCONF_ACCEPT_RA_RTR_PREF, accept_ra_rtr_pref)
148  __ADD(DEVCONF_RTR_PROBE_INTERVAL, rtr_probe_interval)
149  __ADD(DEVCONF_ACCEPT_RA_RT_INFO_MAX_PLEN, accept_ra_rt_info)
150  __ADD(DEVCONF_PROXY_NDP, proxy_ndp)
151  __ADD(DEVCONF_OPTIMISTIC_DAD, optimistic_dad)
152  __ADD(DEVCONF_ACCEPT_SOURCE_ROUTE, accept_source_route)
153  __ADD(DEVCONF_MC_FORWARDING, mc_forwarding)
154  __ADD(DEVCONF_DISABLE_IPV6, disable_ipv6)
155  __ADD(DEVCONF_ACCEPT_DAD, accept_dad)
156  __ADD(DEVCONF_FORCE_TLLAO, force_tllao)
157 };
158 
159 static char *inet6_devconf2str(int type, char *buf, size_t len)
160 {
161  return __type2str(type, buf, len, inet6_devconf,
162  ARRAY_SIZE(inet6_devconf));
163 }
164 
165 
166 static void inet6_dump_details(struct rtnl_link *link,
167  struct nl_dump_params *p, void *data)
168 {
169  struct inet6_data *i6 = data;
170  char buf[64], buf2[64];
171  int i, n = 0;
172 
173  nl_dump_line(p, " ipv6 max-reasm-len %s",
174  nl_size2str(i6->i6_cacheinfo.max_reasm_len, buf, sizeof(buf)));
175 
176  nl_dump(p, " <%s>\n",
177  inet6_flags2str(i6->i6_flags, buf, sizeof(buf)));
178 
179 
180  nl_dump_line(p, " create-stamp %.2fs reachable-time %s",
181  (double) i6->i6_cacheinfo.tstamp / 100.,
182  nl_msec2str(i6->i6_cacheinfo.reachable_time, buf, sizeof(buf)));
183 
184  nl_dump(p, " retrans-time %s\n",
185  nl_msec2str(i6->i6_cacheinfo.retrans_time, buf, sizeof(buf)));
186 
187  nl_dump_line(p, " devconf:\n");
188  nl_dump_line(p, " ");
189 
190  for (i = 0; i < DEVCONF_MAX; i++) {
191  uint32_t value = i6->i6_conf[i];
192  int x, offset;
193 
194  switch (i) {
195  case DEVCONF_TEMP_VALID_LFT:
196  case DEVCONF_TEMP_PREFERED_LFT:
197  nl_msec2str((uint64_t) value * 1000., buf2, sizeof(buf2));
198  break;
199 
200  case DEVCONF_RTR_PROBE_INTERVAL:
201  case DEVCONF_RTR_SOLICIT_INTERVAL:
202  case DEVCONF_RTR_SOLICIT_DELAY:
203  nl_msec2str(value, buf2, sizeof(buf2));
204  break;
205 
206  default:
207  snprintf(buf2, sizeof(buf2), "%u", value);
208  break;
209 
210  }
211 
212  inet6_devconf2str(i, buf, sizeof(buf));
213 
214  offset = 23 - strlen(buf2);
215  if (offset < 0)
216  offset = 0;
217 
218  for (x = strlen(buf); x < offset; x++)
219  buf[x] = ' ';
220 
221  strncpy(&buf[offset], buf2, strlen(buf2));
222 
223  nl_dump_line(p, "%s", buf);
224 
225  if (++n == 3) {
226  nl_dump(p, "\n");
227  nl_dump_line(p, " ");
228  n = 0;
229  } else
230  nl_dump(p, " ");
231  }
232 
233  if (n != 0)
234  nl_dump(p, "\n");
235 }
236 
237 static void inet6_dump_stats(struct rtnl_link *link,
238  struct nl_dump_params *p, void *data)
239 {
240  double octets;
241  char *octetsUnit;
242 
243  nl_dump(p, " IPv6: InPkts InOctets "
244  " InDiscards InDelivers\n");
245  nl_dump(p, " %18" PRIu64 " ", link->l_stats[RTNL_LINK_IP6_INPKTS]);
246 
247  octets = nl_cancel_down_bytes(link->l_stats[RTNL_LINK_IP6_INOCTETS],
248  &octetsUnit);
249  if (octets)
250  nl_dump(p, "%14.2f %3s ", octets, octetsUnit);
251  else
252  nl_dump(p, "%16" PRIu64 " B ", 0);
253 
254  nl_dump(p, "%18" PRIu64 " %18" PRIu64 "\n",
255  link->l_stats[RTNL_LINK_IP6_INDISCARDS],
256  link->l_stats[RTNL_LINK_IP6_INDELIVERS]);
257 
258  nl_dump(p, " OutPkts OutOctets "
259  " OutDiscards OutForwards\n");
260 
261  nl_dump(p, " %18" PRIu64 " ", link->l_stats[RTNL_LINK_IP6_OUTPKTS]);
262 
263  octets = nl_cancel_down_bytes(link->l_stats[RTNL_LINK_IP6_OUTOCTETS],
264  &octetsUnit);
265  if (octets)
266  nl_dump(p, "%14.2f %3s ", octets, octetsUnit);
267  else
268  nl_dump(p, "%16" PRIu64 " B ", 0);
269 
270  nl_dump(p, "%18" PRIu64 " %18" PRIu64 "\n",
271  link->l_stats[RTNL_LINK_IP6_OUTDISCARDS],
272  link->l_stats[RTNL_LINK_IP6_OUTFORWDATAGRAMS]);
273 
274  nl_dump(p, " InMcastPkts InMcastOctets "
275  " InBcastPkts InBcastOctests\n");
276 
277  nl_dump(p, " %18" PRIu64 " ", link->l_stats[RTNL_LINK_IP6_INMCASTPKTS]);
278 
279  octets = nl_cancel_down_bytes(link->l_stats[RTNL_LINK_IP6_INMCASTOCTETS],
280  &octetsUnit);
281  if (octets)
282  nl_dump(p, "%14.2f %3s ", octets, octetsUnit);
283  else
284  nl_dump(p, "%16" PRIu64 " B ", 0);
285 
286  nl_dump(p, "%18" PRIu64 " ", link->l_stats[RTNL_LINK_IP6_INBCASTPKTS]);
287  octets = nl_cancel_down_bytes(link->l_stats[RTNL_LINK_IP6_INBCASTOCTETS],
288  &octetsUnit);
289  if (octets)
290  nl_dump(p, "%14.2f %3s\n", octets, octetsUnit);
291  else
292  nl_dump(p, "%16" PRIu64 " B\n", 0);
293 
294  nl_dump(p, " OutMcastPkts OutMcastOctets "
295  " OutBcastPkts OutBcastOctests\n");
296 
297  nl_dump(p, " %18" PRIu64 " ", link->l_stats[RTNL_LINK_IP6_OUTMCASTPKTS]);
298 
299  octets = nl_cancel_down_bytes(link->l_stats[RTNL_LINK_IP6_OUTMCASTOCTETS],
300  &octetsUnit);
301  if (octets)
302  nl_dump(p, "%14.2f %3s ", octets, octetsUnit);
303  else
304  nl_dump(p, "%16" PRIu64 " B ", 0);
305 
306  nl_dump(p, "%18" PRIu64 " ", link->l_stats[RTNL_LINK_IP6_OUTBCASTPKTS]);
307  octets = nl_cancel_down_bytes(link->l_stats[RTNL_LINK_IP6_OUTBCASTOCTETS],
308  &octetsUnit);
309  if (octets)
310  nl_dump(p, "%14.2f %3s\n", octets, octetsUnit);
311  else
312  nl_dump(p, "%16" PRIu64 " B\n", 0);
313 
314  nl_dump(p, " ReasmOKs ReasmFails "
315  " ReasmReqds ReasmTimeout\n");
316  nl_dump(p, " %18" PRIu64 " %18" PRIu64 " %18" PRIu64 " %18" PRIu64 "\n",
317  link->l_stats[RTNL_LINK_IP6_REASMOKS],
318  link->l_stats[RTNL_LINK_IP6_REASMFAILS],
319  link->l_stats[RTNL_LINK_IP6_REASMREQDS],
320  link->l_stats[RTNL_LINK_IP6_REASMTIMEOUT]);
321 
322  nl_dump(p, " FragOKs FragFails "
323  " FragCreates\n");
324  nl_dump(p, " %18" PRIu64 " %18" PRIu64 " %18" PRIu64 "\n",
325  link->l_stats[RTNL_LINK_IP6_FRAGOKS],
326  link->l_stats[RTNL_LINK_IP6_FRAGFAILS],
327  link->l_stats[RTNL_LINK_IP6_FRAGCREATES]);
328 
329  nl_dump(p, " InHdrErrors InTooBigErrors "
330  " InNoRoutes InAddrErrors\n");
331  nl_dump(p, " %18" PRIu64 " %18" PRIu64 " %18" PRIu64 " %18" PRIu64 "\n",
332  link->l_stats[RTNL_LINK_IP6_INHDRERRORS],
333  link->l_stats[RTNL_LINK_IP6_INTOOBIGERRORS],
334  link->l_stats[RTNL_LINK_IP6_INNOROUTES],
335  link->l_stats[RTNL_LINK_IP6_INADDRERRORS]);
336 
337  nl_dump(p, " InUnknownProtos InTruncatedPkts "
338  " OutNoRoutes\n");
339  nl_dump(p, " %18" PRIu64 " %18" PRIu64 " %18" PRIu64 "\n",
340  link->l_stats[RTNL_LINK_IP6_INUNKNOWNPROTOS],
341  link->l_stats[RTNL_LINK_IP6_INTRUNCATEDPKTS],
342  link->l_stats[RTNL_LINK_IP6_OUTNOROUTES]);
343 
344  nl_dump(p, " ICMPv6: InMsgs InErrors "
345  " OutMsgs OutErrors\n");
346  nl_dump(p, " %18" PRIu64 " %18" PRIu64 " %18" PRIu64 " %18" PRIu64 "\n",
347  link->l_stats[RTNL_LINK_ICMP6_INMSGS],
348  link->l_stats[RTNL_LINK_ICMP6_INERRORS],
349  link->l_stats[RTNL_LINK_ICMP6_OUTMSGS],
350  link->l_stats[RTNL_LINK_ICMP6_OUTERRORS]);
351 }
352 
353 static const struct nla_policy protinfo_policy = {
354  .type = NLA_NESTED,
355 };
356 
357 static struct rtnl_link_af_ops inet6_ops = {
358  .ao_family = AF_INET6,
359  .ao_alloc = &inet6_alloc,
360  .ao_clone = &inet6_clone,
361  .ao_free = &inet6_free,
362  .ao_parse_protinfo = &inet6_parse_protinfo,
363  .ao_parse_af = &inet6_parse_protinfo,
364  .ao_dump[NL_DUMP_DETAILS] = &inet6_dump_details,
365  .ao_dump[NL_DUMP_STATS] = &inet6_dump_stats,
366  .ao_protinfo_policy = &protinfo_policy,
367 };
368 
369 static void __init inet6_init(void)
370 {
371  rtnl_link_af_register(&inet6_ops);
372 }
373 
374 static void __exit inet6_exit(void)
375 {
376  rtnl_link_af_unregister(&inet6_ops);
377 }