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