1 /*
2 * lib/route/link/ip6tnl.c IP6TNL Link Info
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) 2014 Susant Sahani <susant@redhat.com>
10 */
11
12 /**
13 * @ingroup link
14 * @defgroup ip6tnl IP6TNL
15 * ip6tnl link module
16 *
17 * @details
18 * \b Link Type Name: "ip6tnl"
19 *
20 * @route_doc{link_ip6tnl, IP6TNL Documentation}
21 *
22 * @{
23 */
24
25 #include <netlink-private/netlink.h>
26 #include <netlink/netlink.h>
27 #include <netlink/attr.h>
28 #include <netlink/utils.h>
29 #include <netlink/object.h>
30 #include <netlink/route/rtnl.h>
31 #include <netlink-private/route/link/api.h>
32 #include <linux/if_tunnel.h>
33 #include <netinet/in.h>
34
35 #define IP6_TNL_ATTR_LINK (1 << 0)
36 #define IP6_TNL_ATTR_LOCAL (1 << 1)
37 #define IP6_TNL_ATTR_REMOTE (1 << 2)
38 #define IP6_TNL_ATTR_TTL (1 << 3)
39 #define IP6_TNL_ATTR_TOS (1 << 4)
40 #define IP6_TNL_ATTR_ENCAPLIMIT (1 << 5)
41 #define IP6_TNL_ATTR_FLAGS (1 << 6)
42 #define IP6_TNL_ATTR_PROTO (1 << 7)
43 #define IP6_TNL_ATTR_FLOWINFO (1 << 8)
44
45 struct ip6_tnl_info
46 {
47 uint8_t ttl;
48 uint8_t tos;
49 uint8_t encap_limit;
50 uint8_t proto;
51 uint32_t flags;
52 uint32_t link;
53 uint32_t flowinfo;
54 struct in6_addr local;
55 struct in6_addr remote;
56 uint32_t ip6_tnl_mask;
57 };
58
59 static struct nla_policy ip6_tnl_policy[IFLA_IPTUN_MAX + 1] = {
60 [IFLA_IPTUN_LINK] = { .type = NLA_U32 },
61 [IFLA_IPTUN_LOCAL] = { .minlen = sizeof(struct in6_addr) },
62 [IFLA_IPTUN_REMOTE] = { .minlen = sizeof(struct in6_addr) },
63 [IFLA_IPTUN_TTL] = { .type = NLA_U8 },
64 [IFLA_IPTUN_TOS] = { .type = NLA_U8 },
65 [IFLA_IPTUN_ENCAP_LIMIT] = { .type = NLA_U8 },
66 [IFLA_IPTUN_FLOWINFO] = { .type = NLA_U32 },
67 [IFLA_IPTUN_FLAGS] = { .type = NLA_U32 },
68 [IFLA_IPTUN_PROTO] = { .type = NLA_U8 },
69 };
70
ip6_tnl_alloc(struct rtnl_link * link)71 static int ip6_tnl_alloc(struct rtnl_link *link)
72 {
73 struct ip6_tnl_info *ip6_tnl;
74
75 ip6_tnl = calloc(1, sizeof(*ip6_tnl));
76 if (!ip6_tnl)
77 return -NLE_NOMEM;
78
79 link->l_info = ip6_tnl;
80
81 return 0;
82 }
83
ip6_tnl_parse(struct rtnl_link * link,struct nlattr * data,struct nlattr * xstats)84 static int ip6_tnl_parse(struct rtnl_link *link, struct nlattr *data,
85 struct nlattr *xstats)
86 {
87 struct nlattr *tb[IFLA_IPTUN_MAX + 1];
88 struct ip6_tnl_info *ip6_tnl;
89 int err;
90
91 NL_DBG(3, "Parsing IP6_TNL link info");
92
93 err = nla_parse_nested(tb, IFLA_IPTUN_MAX, data, ip6_tnl_policy);
94 if (err < 0)
95 goto errout;
96
97 err = ip6_tnl_alloc(link);
98 if (err < 0)
99 goto errout;
100
101 ip6_tnl = link->l_info;
102
103 if (tb[IFLA_IPTUN_LINK]) {
104 ip6_tnl->link = nla_get_u32(tb[IFLA_IPTUN_LINK]);
105 ip6_tnl->ip6_tnl_mask |= IP6_TNL_ATTR_LINK;
106 }
107
108 if (tb[IFLA_IPTUN_LOCAL]) {
109 nla_memcpy(&ip6_tnl->local, tb[IFLA_IPTUN_LOCAL], sizeof(struct in6_addr));
110 ip6_tnl->ip6_tnl_mask |= IP6_TNL_ATTR_LOCAL;
111 }
112
113 if (tb[IFLA_IPTUN_REMOTE]) {
114 nla_memcpy(&ip6_tnl->remote, tb[IFLA_IPTUN_REMOTE], sizeof(struct in6_addr));
115 ip6_tnl->ip6_tnl_mask |= IP6_TNL_ATTR_REMOTE;
116 }
117
118 if (tb[IFLA_IPTUN_TTL]) {
119 ip6_tnl->ttl = nla_get_u8(tb[IFLA_IPTUN_TTL]);
120 ip6_tnl->ip6_tnl_mask |= IP6_TNL_ATTR_TTL;
121 }
122
123 if (tb[IFLA_IPTUN_TOS]) {
124 ip6_tnl->tos = nla_get_u8(tb[IFLA_IPTUN_TOS]);
125 ip6_tnl->ip6_tnl_mask |= IP6_TNL_ATTR_TOS;
126 }
127
128 if (tb[IFLA_IPTUN_ENCAP_LIMIT]) {
129 ip6_tnl->encap_limit = nla_get_u8(tb[IFLA_IPTUN_ENCAP_LIMIT]);
130 ip6_tnl->ip6_tnl_mask |= IP6_TNL_ATTR_ENCAPLIMIT;
131 }
132
133 if (tb[IFLA_IPTUN_FLAGS]) {
134 ip6_tnl->flags = nla_get_u32(tb[IFLA_IPTUN_FLAGS]);
135 ip6_tnl->ip6_tnl_mask |= IP6_TNL_ATTR_FLAGS;
136 }
137
138 if (tb[IFLA_IPTUN_FLOWINFO]) {
139 ip6_tnl->flowinfo = nla_get_u32(tb[IFLA_IPTUN_FLOWINFO]);
140 ip6_tnl->ip6_tnl_mask |= IP6_TNL_ATTR_FLOWINFO;
141 }
142
143 if (tb[IFLA_IPTUN_PROTO]) {
144 ip6_tnl->proto = nla_get_u8(tb[IFLA_IPTUN_PROTO]);
145 ip6_tnl->ip6_tnl_mask |= IP6_TNL_ATTR_PROTO;
146 }
147
148 err = 0;
149
150 errout:
151 return err;
152 }
153
ip6_tnl_put_attrs(struct nl_msg * msg,struct rtnl_link * link)154 static int ip6_tnl_put_attrs(struct nl_msg *msg, struct rtnl_link *link)
155 {
156 struct ip6_tnl_info *ip6_tnl = link->l_info;
157 struct nlattr *data;
158
159 data = nla_nest_start(msg, IFLA_INFO_DATA);
160 if (!data)
161 return -NLE_MSGSIZE;
162
163 if (ip6_tnl->ip6_tnl_mask & IP6_TNL_ATTR_LINK)
164 NLA_PUT_U32(msg, IFLA_IPTUN_LINK, ip6_tnl->link);
165
166 if (ip6_tnl->ip6_tnl_mask & IP6_TNL_ATTR_LOCAL)
167 NLA_PUT(msg, IFLA_IPTUN_LOCAL, sizeof(struct in6_addr), &ip6_tnl->local);
168
169 if (ip6_tnl->ip6_tnl_mask & IP6_TNL_ATTR_REMOTE)
170 NLA_PUT(msg, IFLA_IPTUN_REMOTE, sizeof(struct in6_addr), &ip6_tnl->remote);
171
172 if (ip6_tnl->ip6_tnl_mask & IP6_TNL_ATTR_TTL)
173 NLA_PUT_U8(msg, IFLA_IPTUN_TTL, ip6_tnl->ttl);
174
175 if (ip6_tnl->ip6_tnl_mask & IP6_TNL_ATTR_TOS)
176 NLA_PUT_U8(msg, IFLA_IPTUN_TOS, ip6_tnl->tos);
177
178 if (ip6_tnl->ip6_tnl_mask & IP6_TNL_ATTR_ENCAPLIMIT)
179 NLA_PUT_U8(msg, IFLA_IPTUN_ENCAP_LIMIT, ip6_tnl->encap_limit);
180
181 if (ip6_tnl->ip6_tnl_mask & IP6_TNL_ATTR_FLAGS)
182 NLA_PUT_U32(msg, IFLA_IPTUN_FLAGS, ip6_tnl->flags);
183
184 if (ip6_tnl->ip6_tnl_mask & IP6_TNL_ATTR_FLOWINFO)
185 NLA_PUT_U32(msg, IFLA_IPTUN_FLOWINFO, ip6_tnl->flowinfo);
186
187 /* kernel crashes if this attribure is missing temporary fix */
188 if (ip6_tnl->ip6_tnl_mask & IP6_TNL_ATTR_PROTO)
189 NLA_PUT_U8(msg, IFLA_IPTUN_PROTO, ip6_tnl->proto);
190 else
191 NLA_PUT_U8(msg, IFLA_IPTUN_PROTO, 0);
192
193 nla_nest_end(msg, data);
194
195 nla_put_failure:
196 return 0;
197 }
198
ip6_tnl_free(struct rtnl_link * link)199 static void ip6_tnl_free(struct rtnl_link *link)
200 {
201 struct ip6_tnl_info *ip6_tnl = link->l_info;
202
203 free(ip6_tnl);
204 link->l_info = NULL;
205 }
206
ip6_tnl_dump_line(struct rtnl_link * link,struct nl_dump_params * p)207 static void ip6_tnl_dump_line(struct rtnl_link *link, struct nl_dump_params *p)
208 {
209 nl_dump(p, "ip6_tnl : %s", link->l_name);
210 }
211
ip6_tnl_dump_details(struct rtnl_link * link,struct nl_dump_params * p)212 static void ip6_tnl_dump_details(struct rtnl_link *link, struct nl_dump_params *p)
213 {
214 struct ip6_tnl_info *ip6_tnl = link->l_info;
215 char *name, addr[INET6_ADDRSTRLEN];
216
217 if (ip6_tnl->ip6_tnl_mask & IP6_TNL_ATTR_LINK) {
218 nl_dump(p, " link ");
219 name = rtnl_link_get_name(link);
220 if (name)
221 nl_dump_line(p, "%s\n", name);
222 else
223 nl_dump_line(p, "%u\n", ip6_tnl->link);
224 }
225
226 if (ip6_tnl->ip6_tnl_mask & IP6_TNL_ATTR_LOCAL) {
227 nl_dump(p, " local ");
228
229 if(inet_ntop(AF_INET6, &ip6_tnl->local, addr, INET6_ADDRSTRLEN))
230 nl_dump_line(p, "%s\n", addr);
231 else
232 nl_dump_line(p, "%#x\n", ip6_tnl->local);
233 }
234
235 if (ip6_tnl->ip6_tnl_mask & IP6_TNL_ATTR_REMOTE) {
236 nl_dump(p, " remote ");
237
238 if(inet_ntop(AF_INET6, &ip6_tnl->remote, addr, INET6_ADDRSTRLEN))
239 nl_dump_line(p, "%s\n", addr);
240 else
241 nl_dump_line(p, "%#x\n", ip6_tnl->remote);
242 }
243
244 if (ip6_tnl->ip6_tnl_mask & IP6_TNL_ATTR_TTL) {
245 nl_dump(p, " ttl ");
246 nl_dump_line(p, "%d\n", ip6_tnl->ttl);
247 }
248
249 if (ip6_tnl->ip6_tnl_mask & IP6_TNL_ATTR_TOS) {
250 nl_dump(p, " tos ");
251 nl_dump_line(p, "%d\n", ip6_tnl->tos);
252 }
253
254 if (ip6_tnl->ip6_tnl_mask & IP6_TNL_ATTR_ENCAPLIMIT) {
255 nl_dump(p, " encaplimit ");
256 nl_dump_line(p, "%d\n", ip6_tnl->encap_limit);
257 }
258
259 if (ip6_tnl->ip6_tnl_mask & IP6_TNL_ATTR_FLAGS) {
260 nl_dump(p, " flags ");
261 nl_dump_line(p, " (%x)\n", ip6_tnl->flags);
262 }
263
264 if (ip6_tnl->ip6_tnl_mask & IP6_TNL_ATTR_FLOWINFO) {
265 nl_dump(p, " flowinfo ");
266 nl_dump_line(p, " (%x)\n", ip6_tnl->flowinfo);
267 }
268
269 if (ip6_tnl->ip6_tnl_mask & IP6_TNL_ATTR_PROTO) {
270 nl_dump(p, " proto ");
271 nl_dump_line(p, " (%x)\n", ip6_tnl->proto);
272 }
273 }
274
ip6_tnl_clone(struct rtnl_link * dst,struct rtnl_link * src)275 static int ip6_tnl_clone(struct rtnl_link *dst, struct rtnl_link *src)
276 {
277 struct ip6_tnl_info *ip6_tnl_dst, *ip6_tnl_src = src->l_info;
278 int err;
279
280 dst->l_info = NULL;
281
282 err = rtnl_link_set_type(dst, "ip6tnl");
283 if (err < 0)
284 return err;
285
286 ip6_tnl_dst = dst->l_info;
287
288 if (!ip6_tnl_dst || !ip6_tnl_src)
289 BUG();
290
291 memcpy(ip6_tnl_dst, ip6_tnl_src, sizeof(struct ip6_tnl_info));
292
293 return 0;
294 }
295
296 static struct rtnl_link_info_ops ip6_tnl_info_ops = {
297 .io_name = "ip6tnl",
298 .io_alloc = ip6_tnl_alloc,
299 .io_parse = ip6_tnl_parse,
300 .io_dump = {
301 [NL_DUMP_LINE] = ip6_tnl_dump_line,
302 [NL_DUMP_DETAILS] = ip6_tnl_dump_details,
303 },
304 .io_clone = ip6_tnl_clone,
305 .io_put_attrs = ip6_tnl_put_attrs,
306 .io_free = ip6_tnl_free,
307 };
308
309 #define IS_IP6_TNL_LINK_ASSERT(link)\
310 if ((link)->l_info_ops != &ip6_tnl_info_ops) {\
311 APPBUG("Link is not a ip6_tnl link. set type \"ip6tnl\" first.");\
312 return -NLE_OPNOTSUPP;\
313 }
314
rtnl_link_ip6_tnl_alloc(void)315 struct rtnl_link *rtnl_link_ip6_tnl_alloc(void)
316 {
317 struct rtnl_link *link;
318 int err;
319
320 link = rtnl_link_alloc();
321 if (!link)
322 return NULL;
323
324 err = rtnl_link_set_type(link, "ip6tnl");
325 if (err < 0) {
326 rtnl_link_put(link);
327 return NULL;
328 }
329
330 return link;
331 }
332
333 /**
334 * Check if link is a IP6_TNL link
335 * @arg link Link object
336 *
337 * @return True if link is a IP6_TNL link, otherwise false is returned.
338 */
rtnl_link_is_ip6_tnl(struct rtnl_link * link)339 int rtnl_link_is_ip6_tnl(struct rtnl_link *link)
340 {
341 return link->l_info_ops && !strcmp(link->l_info_ops->io_name, "ip6tnl");
342 }
343
344 /**
345 * Create a new ip6_tnl tunnel device
346 * @arg sock netlink socket
347 * @arg name name of the tunnel device
348 *
349 * Creates a new ip6_tnl tunnel device in the kernel
350 * @return 0 on success or a negative error code
351 */
rtnl_link_ip6_tnl_add(struct nl_sock * sk,const char * name)352 int rtnl_link_ip6_tnl_add(struct nl_sock *sk, const char *name)
353 {
354 struct rtnl_link *link;
355 int err;
356
357 link = rtnl_link_ip6_tnl_alloc();
358 if (!link)
359 return -NLE_NOMEM;
360
361 if(name)
362 rtnl_link_set_name(link, name);
363
364 err = rtnl_link_add(sk, link, NLM_F_CREATE);
365 rtnl_link_put(link);
366
367 return err;
368 }
369
370 /**
371 * Set IP6_TNL tunnel interface index
372 * @arg link Link object
373 * @arg index interface index
374 *
375 * @return 0 on success or a negative error code
376 */
rtnl_link_ip6_tnl_set_link(struct rtnl_link * link,uint32_t index)377 int rtnl_link_ip6_tnl_set_link(struct rtnl_link *link, uint32_t index)
378 {
379 struct ip6_tnl_info *ip6_tnl = link->l_info;
380
381 IS_IP6_TNL_LINK_ASSERT(link);
382
383 ip6_tnl->link = index;
384 ip6_tnl->ip6_tnl_mask |= IP6_TNL_ATTR_LINK;
385
386 return 0;
387 }
388
389 /**
390 * Get IP6_TNL tunnel interface index
391 * @arg link Link object
392 *
393 * @return interface index value
394 */
rtnl_link_ip6_tnl_get_link(struct rtnl_link * link)395 uint32_t rtnl_link_ip6_tnl_get_link(struct rtnl_link *link)
396 {
397 struct ip6_tnl_info *ip6_tnl = link->l_info;
398
399 IS_IP6_TNL_LINK_ASSERT(link);
400
401 return ip6_tnl->link;
402 }
403
404 /**
405 * Set IP6_TNL tunnel local address
406 * @arg link Link object
407 * @arg addr local address
408 *
409 * @return 0 on success or a negative error code
410 */
rtnl_link_ip6_tnl_set_local(struct rtnl_link * link,struct in6_addr * addr)411 int rtnl_link_ip6_tnl_set_local(struct rtnl_link *link, struct in6_addr *addr)
412 {
413 struct ip6_tnl_info *ip6_tnl = link->l_info;
414
415 IS_IP6_TNL_LINK_ASSERT(link);
416
417 memcpy(&ip6_tnl->local, addr, sizeof(struct in6_addr));
418 ip6_tnl->ip6_tnl_mask |= IP6_TNL_ATTR_LOCAL;
419
420 return 0;
421 }
422
423 /**
424 * Get IP6_TNL tunnel local address
425 * @arg link Link object
426 *
427 * @return 0 on success or a negative error code
428 */
rtnl_link_ip6_tnl_get_local(struct rtnl_link * link,struct in6_addr * addr)429 int rtnl_link_ip6_tnl_get_local(struct rtnl_link *link, struct in6_addr *addr)
430 {
431 struct ip6_tnl_info *ip6_tnl = link->l_info;
432
433 IS_IP6_TNL_LINK_ASSERT(link);
434
435 memcpy(addr, &ip6_tnl->local, sizeof(struct in6_addr));
436
437 return 0;
438 }
439
440 /**
441 * Set IP6_TNL tunnel remote address
442 * @arg link Link object
443 * @arg remote remote address
444 *
445 * @return 0 on success or a negative error code
446 */
rtnl_link_ip6_tnl_set_remote(struct rtnl_link * link,struct in6_addr * addr)447 int rtnl_link_ip6_tnl_set_remote(struct rtnl_link *link, struct in6_addr *addr)
448 {
449 struct ip6_tnl_info *ip6_tnl = link->l_info;
450
451 IS_IP6_TNL_LINK_ASSERT(link);
452
453 memcpy(&ip6_tnl->remote, addr, sizeof(struct in6_addr));
454 ip6_tnl->ip6_tnl_mask |= IP6_TNL_ATTR_REMOTE;
455
456 return 0;
457 }
458
459 /**
460 * Get IP6_TNL tunnel remote address
461 * @arg link Link object
462 *
463 * @return 0 on success or a negative error code
464 */
rtnl_link_ip6_tnl_get_remote(struct rtnl_link * link,struct in6_addr * addr)465 int rtnl_link_ip6_tnl_get_remote(struct rtnl_link *link, struct in6_addr *addr)
466 {
467 struct ip6_tnl_info *ip6_tnl = link->l_info;
468
469 IS_IP6_TNL_LINK_ASSERT(link);
470
471 memcpy(addr, &ip6_tnl->remote, sizeof(struct in6_addr));
472
473 return 0;
474 }
475
476 /**
477 * Set IP6_TNL tunnel ttl
478 * @arg link Link object
479 * @arg ttl tunnel ttl
480 *
481 * @return 0 on success or a negative error code
482 */
rtnl_link_ip6_tnl_set_ttl(struct rtnl_link * link,uint8_t ttl)483 int rtnl_link_ip6_tnl_set_ttl(struct rtnl_link *link, uint8_t ttl)
484 {
485 struct ip6_tnl_info *ip6_tnl = link->l_info;
486
487 IS_IP6_TNL_LINK_ASSERT(link);
488
489 ip6_tnl->ttl = ttl;
490 ip6_tnl->ip6_tnl_mask |= IP6_TNL_ATTR_TTL;
491
492 return 0;
493 }
494
495 /**
496 * Get IP6_TNL tunnel ttl
497 * @arg link Link object
498 *
499 * @return ttl value
500 */
rtnl_link_ip6_tnl_get_ttl(struct rtnl_link * link)501 uint8_t rtnl_link_ip6_tnl_get_ttl(struct rtnl_link *link)
502 {
503 struct ip6_tnl_info *ip6_tnl = link->l_info;
504
505 IS_IP6_TNL_LINK_ASSERT(link);
506
507 return ip6_tnl->ttl;
508 }
509
510 /**
511 * Set IP6_TNL tunnel tos
512 * @arg link Link object
513 * @arg tos tunnel tos
514 *
515 * @return 0 on success or a negative error code
516 */
rtnl_link_ip6_tnl_set_tos(struct rtnl_link * link,uint8_t tos)517 int rtnl_link_ip6_tnl_set_tos(struct rtnl_link *link, uint8_t tos)
518 {
519 struct ip6_tnl_info *ip6_tnl = link->l_info;
520
521 IS_IP6_TNL_LINK_ASSERT(link);
522
523 ip6_tnl->tos = tos;
524 ip6_tnl->ip6_tnl_mask |= IP6_TNL_ATTR_TOS;
525
526 return 0;
527 }
528
529 /**
530 * Get IP6_TNL tunnel tos
531 * @arg link Link object
532 *
533 * @return tos value
534 */
rtnl_link_ip6_tnl_get_tos(struct rtnl_link * link)535 uint8_t rtnl_link_ip6_tnl_get_tos(struct rtnl_link *link)
536 {
537 struct ip6_tnl_info *ip6_tnl = link->l_info;
538
539 IS_IP6_TNL_LINK_ASSERT(link);
540
541 return ip6_tnl->tos;
542 }
543
544 /**
545 * Set IP6_TNL tunnel encap limit
546 * @arg link Link object
547 * @arg encap_limit encaplimit value
548 *
549 * @return 0 on success or a negative error code
550 */
rtnl_link_ip6_tnl_set_encaplimit(struct rtnl_link * link,uint8_t encap_limit)551 int rtnl_link_ip6_tnl_set_encaplimit(struct rtnl_link *link, uint8_t encap_limit)
552 {
553 struct ip6_tnl_info *ip6_tnl = link->l_info;
554
555 IS_IP6_TNL_LINK_ASSERT(link);
556
557 ip6_tnl->encap_limit = encap_limit;
558 ip6_tnl->ip6_tnl_mask |= IP6_TNL_ATTR_ENCAPLIMIT;
559
560 return 0;
561 }
562
563 /**
564 * Get IP6_TNL encaplimit
565 * @arg link Link object
566 *
567 * @return encaplimit value
568 */
rtnl_link_ip6_tnl_get_encaplimit(struct rtnl_link * link)569 uint8_t rtnl_link_ip6_tnl_get_encaplimit(struct rtnl_link *link)
570 {
571 struct ip6_tnl_info *ip6_tnl = link->l_info;
572
573 IS_IP6_TNL_LINK_ASSERT(link);
574
575 return ip6_tnl->encap_limit;
576 }
577
578 /**
579 * Set IP6_TNL tunnel flowinfo
580 * @arg link Link object
581 * @arg flowinfo flowinfo value
582 *
583 * @return 0 on success or a negative error code
584 */
rtnl_link_ip6_tnl_set_flowinfo(struct rtnl_link * link,uint32_t flowinfo)585 int rtnl_link_ip6_tnl_set_flowinfo(struct rtnl_link *link, uint32_t flowinfo)
586 {
587 struct ip6_tnl_info *ip6_tnl = link->l_info;
588
589 IS_IP6_TNL_LINK_ASSERT(link);
590
591 ip6_tnl->flowinfo = flowinfo;
592 ip6_tnl->ip6_tnl_mask |= IP6_TNL_ATTR_FLOWINFO;
593
594 return 0;
595 }
596
597 /**
598 * Get IP6_TNL flowinfo
599 * @arg link Link object
600 *
601 * @return flowinfo value
602 */
rtnl_link_ip6_tnl_get_flowinfo(struct rtnl_link * link)603 uint32_t rtnl_link_ip6_tnl_get_flowinfo(struct rtnl_link *link)
604 {
605 struct ip6_tnl_info *ip6_tnl = link->l_info;
606
607 IS_IP6_TNL_LINK_ASSERT(link);
608
609 return ip6_tnl->flowinfo;
610 }
611
612 /**
613 * Set IP6_TNL tunnel flags
614 * @arg link Link object
615 * @arg flags tunnel flags
616 *
617 * @return 0 on success or a negative error code
618 */
rtnl_link_ip6_tnl_set_flags(struct rtnl_link * link,uint32_t flags)619 int rtnl_link_ip6_tnl_set_flags(struct rtnl_link *link, uint32_t flags)
620 {
621 struct ip6_tnl_info *ip6_tnl = link->l_info;
622
623 IS_IP6_TNL_LINK_ASSERT(link);
624
625 ip6_tnl->flags = flags;
626 ip6_tnl->ip6_tnl_mask |= IP6_TNL_ATTR_FLAGS;
627
628 return 0;
629 }
630
631 /**
632 * Get IP6_TNL path flags
633 * @arg link Link object
634 *
635 * @return flags value
636 */
rtnl_link_ip6_tnl_get_flags(struct rtnl_link * link)637 uint32_t rtnl_link_ip6_tnl_get_flags(struct rtnl_link *link)
638 {
639 struct ip6_tnl_info *ip6_tnl = link->l_info;
640
641 IS_IP6_TNL_LINK_ASSERT(link);
642
643 return ip6_tnl->flags;
644 }
645
646 /**
647 * Set IP6_TNL tunnel proto
648 * @arg link Link object
649 * @arg proto tunnel proto
650 *
651 * @return 0 on success or a negative error code
652 */
rtnl_link_ip6_tnl_set_proto(struct rtnl_link * link,uint8_t proto)653 int rtnl_link_ip6_tnl_set_proto(struct rtnl_link *link, uint8_t proto)
654 {
655 struct ip6_tnl_info *ip6_tnl = link->l_info;
656
657 IS_IP6_TNL_LINK_ASSERT(link);
658
659 ip6_tnl->proto = proto;
660 ip6_tnl->ip6_tnl_mask |= IP6_TNL_ATTR_PROTO;
661
662 return 0;
663 }
664
665 /**
666 * Get IP6_TNL proto
667 * @arg link Link object
668 *
669 * @return proto value
670 */
rtnl_link_ip6_tnl_get_proto(struct rtnl_link * link)671 uint8_t rtnl_link_ip6_tnl_get_proto(struct rtnl_link *link)
672 {
673 struct ip6_tnl_info *ip6_tnl = link->l_info;
674
675 IS_IP6_TNL_LINK_ASSERT(link);
676
677 return ip6_tnl->proto;
678 }
679
ip6_tnl_init(void)680 static void __init ip6_tnl_init(void)
681 {
682 rtnl_link_register_info(&ip6_tnl_info_ops);
683 }
684
ip6_tnl_exit(void)685 static void __exit ip6_tnl_exit(void)
686 {
687 rtnl_link_unregister_info(&ip6_tnl_info_ops);
688 }
689