• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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