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