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
inet6_alloc(struct rtnl_link * link)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
inet6_clone(struct rtnl_link * link,void * data)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
inet6_free(struct rtnl_link * link,void * data)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
inet6_parse_protinfo(struct rtnl_link * link,struct nlattr * attr,void * data)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));
217 rtnl_link_set_stat(link, RTNL_LINK_ICMP6_INMSGS + i - 1,
218 stat);
219 }
220 }
221
222 return 0;
223 }
224
inet6_fill_af(struct rtnl_link * link,struct nl_msg * msg,void * data)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
rtnl_link_inet6_flags2str(int flags,char * buf,size_t len)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
rtnl_link_inet6_str2flags(const char * name)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
inet6_devconf2str(int type,char * buf,size_t len)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
rtnl_link_inet6_addrgenmode2str(uint8_t mode,char * buf,size_t len)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
rtnl_link_inet6_str2addrgenmode(const char * mode)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
inet6_dump_details(struct rtnl_link * link,struct nl_dump_params * p,void * data)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
inet6_dump_stats(struct rtnl_link * link,struct nl_dump_params * p,void * data)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 */
rtnl_link_inet6_get_flags(struct rtnl_link * link,uint32_t * out_flags)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 */
rtnl_link_inet6_set_flags(struct rtnl_link * link,uint32_t flags)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 */
rtnl_link_inet6_get_token(struct rtnl_link * link,struct nl_addr ** addr)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 */
rtnl_link_inet6_set_token(struct rtnl_link * link,struct nl_addr * addr)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 */
rtnl_link_inet6_get_addr_gen_mode(struct rtnl_link * link,uint8_t * mode)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 */
rtnl_link_inet6_set_addr_gen_mode(struct rtnl_link * link,uint8_t mode)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
inet6_init(void)691 static void __init inet6_init(void)
692 {
693 rtnl_link_af_register(&inet6_ops);
694 }
695
inet6_exit(void)696 static void __exit inet6_exit(void)
697 {
698 rtnl_link_af_unregister(&inet6_ops);
699 }
700