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