• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* SPDX-License-Identifier: LGPL-2.1-only */
2 
3 /**
4  * @ingroup link
5  * @defgroup ip6gre IP6GRE
6  * ip6gre link module
7  *
8  * @details
9  * \b Link Type Name: "ip6gre"
10  *
11  * @route_doc{link_ip6gre, IP6GRE Documentation}
12  *
13  * @{
14  */
15 
16 #include <netlink-private/netlink.h>
17 #include <netlink/netlink.h>
18 #include <netlink/attr.h>
19 #include <netlink/utils.h>
20 #include <netlink/object.h>
21 #include <netlink/route/rtnl.h>
22 #include <netlink/route/link/ip6gre.h>
23 #include <netlink-private/route/link/api.h>
24 #include <linux/if_tunnel.h>
25 
26 #define IP6GRE_ATTR_LINK          (1 << 0)
27 #define IP6GRE_ATTR_IFLAGS        (1 << 1)
28 #define IP6GRE_ATTR_OFLAGS        (1 << 2)
29 #define IP6GRE_ATTR_IKEY          (1 << 3)
30 #define IP6GRE_ATTR_OKEY          (1 << 4)
31 #define IP6GRE_ATTR_LOCAL         (1 << 5)
32 #define IP6GRE_ATTR_REMOTE        (1 << 6)
33 #define IP6GRE_ATTR_TTL           (1 << 7)
34 #define IP6GRE_ATTR_ENCAPLIMIT    (1 << 8)
35 #define IP6GRE_ATTR_FLOWINFO      (1 << 9)
36 #define IP6GRE_ATTR_FLAGS         (1 << 10)
37 #define IP6GRE_ATTR_FWMARK        (1 << 11)
38 
39 struct ip6gre_info
40 {
41 	uint8_t             ttl;
42 	uint8_t             encaplimit;
43 	uint16_t            iflags;
44 	uint16_t            oflags;
45 	uint32_t            ikey;
46 	uint32_t            okey;
47 	uint32_t            link;
48 	uint32_t            flowinfo;
49 	uint32_t            flags;
50 	struct in6_addr     local;
51 	struct in6_addr     remote;
52 	uint32_t            fwmark;
53 	uint32_t            ip6gre_mask;
54 };
55 
56 static  struct nla_policy ip6gre_policy[IFLA_GRE_MAX + 1] = {
57 	[IFLA_GRE_LINK]         = { .type = NLA_U32 },
58 	[IFLA_GRE_IFLAGS]       = { .type = NLA_U16 },
59 	[IFLA_GRE_OFLAGS]       = { .type = NLA_U16 },
60 	[IFLA_GRE_IKEY]         = { .type = NLA_U32 },
61 	[IFLA_GRE_OKEY]         = { .type = NLA_U32 },
62 	[IFLA_GRE_LOCAL]        = { .minlen = sizeof(struct in6_addr) },
63 	[IFLA_GRE_REMOTE]       = { .minlen = sizeof(struct in6_addr) },
64 	[IFLA_GRE_TTL]          = { .type = NLA_U8 },
65 	[IFLA_GRE_ENCAP_LIMIT]  = { .type = NLA_U8 },
66 	[IFLA_GRE_FLOWINFO]     = { .type = NLA_U32 },
67 	[IFLA_GRE_FLAGS]        = { .type = NLA_U32 },
68 	[IFLA_GRE_FWMARK]       = { .type = NLA_U32 },
69 };
70 
ip6gre_alloc(struct rtnl_link * link)71 static int ip6gre_alloc(struct rtnl_link *link)
72 {
73 	struct ip6gre_info *ip6gre;
74 
75 	if (link->l_info)
76 		memset(link->l_info, 0, sizeof(*ip6gre));
77 	else {
78 		ip6gre = calloc(1, sizeof(*ip6gre));
79 		if (!ip6gre)
80 			return -NLE_NOMEM;
81 
82 		link->l_info = ip6gre;
83 	}
84 
85 	return 0;
86 }
87 
ip6gre_parse(struct rtnl_link * link,struct nlattr * data,struct nlattr * xstats)88 static int ip6gre_parse(struct rtnl_link *link, struct nlattr *data,
89 		        struct nlattr *xstats)
90 {
91 	struct nlattr *tb[IFLA_GRE_MAX + 1];
92 	struct ip6gre_info *ip6gre;
93 	int err;
94 
95 	NL_DBG(3, "Parsing IP6GRE link info\n");
96 
97 	err = nla_parse_nested(tb, IFLA_GRE_MAX, data, ip6gre_policy);
98 	if (err < 0)
99 		goto errout;
100 
101 	err = ip6gre_alloc(link);
102 	if (err < 0)
103 		goto errout;
104 
105 	ip6gre = link->l_info;
106 
107 	if (tb[IFLA_GRE_LINK]) {
108 		ip6gre->link = nla_get_u32(tb[IFLA_GRE_LINK]);
109 		ip6gre->ip6gre_mask |= IP6GRE_ATTR_LINK;
110 	}
111 
112 	if (tb[IFLA_GRE_IFLAGS]) {
113 		ip6gre->iflags = nla_get_u16(tb[IFLA_GRE_IFLAGS]);
114 		ip6gre->ip6gre_mask |= IP6GRE_ATTR_IFLAGS;
115 	}
116 
117 	if (tb[IFLA_GRE_OFLAGS]) {
118 		ip6gre->oflags = nla_get_u16(tb[IFLA_GRE_OFLAGS]);
119 		ip6gre->ip6gre_mask |= IP6GRE_ATTR_OFLAGS;
120 	}
121 
122 	if (tb[IFLA_GRE_IKEY]) {
123 		ip6gre->ikey = nla_get_u32(tb[IFLA_GRE_IKEY]);
124 		ip6gre->ip6gre_mask |= IP6GRE_ATTR_IKEY;
125 	}
126 
127 	if (tb[IFLA_GRE_OKEY]) {
128 		ip6gre->okey = nla_get_u32(tb[IFLA_GRE_OKEY]);
129 		ip6gre->ip6gre_mask |= IP6GRE_ATTR_OKEY;
130 	}
131 
132 	if (tb[IFLA_GRE_LOCAL]) {
133 		nla_memcpy(&ip6gre->local, tb[IFLA_GRE_LOCAL], sizeof(struct in6_addr));
134 		ip6gre->ip6gre_mask |= IP6GRE_ATTR_LOCAL;
135 	}
136 
137 	if (tb[IFLA_GRE_REMOTE]) {
138 		nla_memcpy(&ip6gre->remote, tb[IFLA_GRE_REMOTE], sizeof(struct in6_addr));
139 		ip6gre->ip6gre_mask |= IP6GRE_ATTR_REMOTE;
140 	}
141 
142 	if (tb[IFLA_GRE_TTL]) {
143 		ip6gre->ttl = nla_get_u8(tb[IFLA_GRE_TTL]);
144 		ip6gre->ip6gre_mask |= IP6GRE_ATTR_TTL;
145 	}
146 
147 	if (tb[IFLA_GRE_ENCAP_LIMIT]) {
148 		ip6gre->encaplimit = nla_get_u8(tb[IFLA_GRE_ENCAP_LIMIT]);
149 		ip6gre->ip6gre_mask |= IP6GRE_ATTR_ENCAPLIMIT;
150 	}
151 
152 	if (tb[IFLA_GRE_FLOWINFO]) {
153 		ip6gre->flowinfo = nla_get_u32(tb[IFLA_GRE_FLOWINFO]);
154 		ip6gre->ip6gre_mask |= IP6GRE_ATTR_FLOWINFO;
155 	}
156 
157 	if (tb[IFLA_GRE_FLAGS]) {
158 		ip6gre->flags = nla_get_u32(tb[IFLA_GRE_FLAGS]);
159 		ip6gre->ip6gre_mask |= IP6GRE_ATTR_FLAGS;
160 	}
161 
162 	if (tb[IFLA_GRE_FWMARK]) {
163 		ip6gre->fwmark = nla_get_u32(tb[IFLA_GRE_FWMARK]);
164 		ip6gre->ip6gre_mask |= IP6GRE_ATTR_FWMARK;
165 	}
166 
167 	err = 0;
168 
169  errout:
170 	return err;
171 }
172 
ip6gre_put_attrs(struct nl_msg * msg,struct rtnl_link * link)173 static int ip6gre_put_attrs(struct nl_msg *msg, struct rtnl_link *link)
174 {
175 	struct ip6gre_info *ip6gre = link->l_info;
176 	struct nlattr *data;
177 
178 	data = nla_nest_start(msg, IFLA_INFO_DATA);
179 	if (!data)
180 		return -NLE_MSGSIZE;
181 
182 	if (ip6gre->ip6gre_mask & IP6GRE_ATTR_LINK)
183 		NLA_PUT_U32(msg, IFLA_GRE_LINK, ip6gre->link);
184 
185 	if (ip6gre->ip6gre_mask & IP6GRE_ATTR_IFLAGS)
186 		NLA_PUT_U16(msg, IFLA_GRE_IFLAGS, ip6gre->iflags);
187 
188 	if (ip6gre->ip6gre_mask & IP6GRE_ATTR_OFLAGS)
189 		NLA_PUT_U16(msg, IFLA_GRE_OFLAGS, ip6gre->oflags);
190 
191 	if (ip6gre->ip6gre_mask & IP6GRE_ATTR_IKEY)
192 		NLA_PUT_U32(msg, IFLA_GRE_IKEY, ip6gre->ikey);
193 
194 	if (ip6gre->ip6gre_mask & IP6GRE_ATTR_OKEY)
195 		NLA_PUT_U32(msg, IFLA_GRE_OKEY, ip6gre->okey);
196 
197 	if (ip6gre->ip6gre_mask & IP6GRE_ATTR_LOCAL)
198 		NLA_PUT(msg, IFLA_GRE_LOCAL, sizeof(struct in6_addr), &ip6gre->local);
199 
200 	if (ip6gre->ip6gre_mask & IP6GRE_ATTR_REMOTE)
201 		NLA_PUT(msg, IFLA_GRE_REMOTE, sizeof(struct in6_addr), &ip6gre->remote);
202 
203 	if (ip6gre->ip6gre_mask & IP6GRE_ATTR_TTL)
204 		NLA_PUT_U8(msg, IFLA_GRE_TTL, ip6gre->ttl);
205 
206 	if (ip6gre->ip6gre_mask & IP6GRE_ATTR_ENCAPLIMIT)
207 		NLA_PUT_U8(msg, IFLA_GRE_ENCAP_LIMIT, ip6gre->encaplimit);
208 
209 	if (ip6gre->ip6gre_mask & IP6GRE_ATTR_FLOWINFO)
210 		NLA_PUT_U32(msg, IFLA_GRE_FLOWINFO, ip6gre->flowinfo);
211 
212 	if (ip6gre->ip6gre_mask & IP6GRE_ATTR_FLAGS)
213 		NLA_PUT_U32(msg, IFLA_GRE_FLAGS, ip6gre->flags);
214 
215 	if (ip6gre->ip6gre_mask & IP6GRE_ATTR_FWMARK)
216 		NLA_PUT_U32(msg, IFLA_GRE_FWMARK, ip6gre->fwmark);
217 
218 	nla_nest_end(msg, data);
219 
220  nla_put_failure:
221 
222 	return 0;
223 }
224 
ip6gre_free(struct rtnl_link * link)225 static void ip6gre_free(struct rtnl_link *link)
226 {
227 	struct ip6gre_info *ip6gre = link->l_info;
228 
229 	free(ip6gre);
230 	link->l_info = NULL;
231 }
232 
ip6gre_dump_line(struct rtnl_link * link,struct nl_dump_params * p)233 static void ip6gre_dump_line(struct rtnl_link *link, struct nl_dump_params *p)
234 {
235 	nl_dump(p, "ip6gre : %s", link->l_name);
236 }
237 
ip6gre_dump_details(struct rtnl_link * link,struct nl_dump_params * p)238 static void ip6gre_dump_details(struct rtnl_link *link, struct nl_dump_params *p)
239 {
240 	struct ip6gre_info *ip6gre = link->l_info;
241 	char *name;
242 	char addr[INET6_ADDRSTRLEN];
243 
244 	if (ip6gre->ip6gre_mask & IP6GRE_ATTR_LINK) {
245 		nl_dump(p, "      link ");
246 		name = rtnl_link_get_name(link);
247 		if (name)
248 			nl_dump_line(p, "%s\n", name);
249 		else
250 			nl_dump_line(p, "%u\n", ip6gre->link);
251 	}
252 
253 	if (ip6gre->ip6gre_mask & IP6GRE_ATTR_IFLAGS) {
254 		nl_dump(p, "      iflags ");
255 		nl_dump_line(p, "%x\n", ip6gre->iflags);
256 	}
257 
258 	if (ip6gre->ip6gre_mask & IP6GRE_ATTR_OFLAGS) {
259 		nl_dump(p, "      oflags ");
260 		nl_dump_line(p, "%x\n", ip6gre->oflags);
261 	}
262 
263 	if (ip6gre->ip6gre_mask & IP6GRE_ATTR_IKEY) {
264 		nl_dump(p, "    ikey   ");
265 		nl_dump_line(p, "%x\n",ip6gre->ikey);
266 	}
267 
268 	if (ip6gre->ip6gre_mask & IP6GRE_ATTR_OKEY) {
269 		nl_dump(p, "      okey ");
270 		nl_dump_line(p, "%x\n", ip6gre->okey);
271 	}
272 
273 	if (ip6gre->ip6gre_mask & IP6GRE_ATTR_LOCAL) {
274 		nl_dump(p, "      local ");
275 		nl_dump_line(p, "%s\n",
276 			     _nl_inet_ntop(AF_INET6, &ip6gre->local, addr));
277 	}
278 
279 	if (ip6gre->ip6gre_mask & IP6GRE_ATTR_REMOTE) {
280 		nl_dump(p, "      remote ");
281 		nl_dump_line(p, "%s\n",
282 			     _nl_inet_ntop(AF_INET6, &ip6gre->remote, addr));
283 	}
284 
285 	if (ip6gre->ip6gre_mask & IP6GRE_ATTR_TTL) {
286 		nl_dump(p, "      ttl ");
287 		nl_dump_line(p, "%u\n", ip6gre->ttl);
288 	}
289 
290 	if (ip6gre->ip6gre_mask & IP6GRE_ATTR_ENCAPLIMIT) {
291 		nl_dump(p, "      encaplimit ");
292 		nl_dump_line(p, "%u\n", ip6gre->encaplimit);
293 	}
294 
295 	if (ip6gre->ip6gre_mask & IP6GRE_ATTR_FLOWINFO) {
296 		nl_dump(p, "      flowinfo ");
297 		nl_dump_line(p, "%x\n", ip6gre->flowinfo);
298 	}
299 
300 	if (ip6gre->ip6gre_mask & IP6GRE_ATTR_FLAGS) {
301 		nl_dump(p, "      flags ");
302 		nl_dump_line(p, "%x\n", ip6gre->flags);
303 	}
304 
305 	if (ip6gre->ip6gre_mask & IP6GRE_ATTR_FWMARK) {
306 		nl_dump(p, "    fwmark   ");
307 		nl_dump_line(p, "%x\n", ip6gre->fwmark);
308 	}
309 }
310 
ip6gre_clone(struct rtnl_link * dst,struct rtnl_link * src)311 static int ip6gre_clone(struct rtnl_link *dst, struct rtnl_link *src)
312 {
313 	struct ip6gre_info *ip6gre_dst, *ip6gre_src = src->l_info;
314 	int err;
315 
316 	dst->l_info = NULL;
317 
318 	err = rtnl_link_set_type(dst, "ip6gre");
319 	if (err < 0)
320 		return err;
321 
322 	ip6gre_dst = dst->l_info;
323 
324 	if (!ip6gre_dst || !ip6gre_src)
325 		BUG();
326 
327 	memcpy(ip6gre_dst, ip6gre_src, sizeof(struct ip6gre_info));
328 
329 	return 0;
330 }
331 
332 static struct rtnl_link_info_ops ip6gre_info_ops = {
333 	.io_name                = "ip6gre",
334 	.io_alloc               = ip6gre_alloc,
335 	.io_parse               = ip6gre_parse,
336 	.io_dump = {
337 		[NL_DUMP_LINE]  = ip6gre_dump_line,
338 		[NL_DUMP_DETAILS] = ip6gre_dump_details,
339 	},
340 	.io_clone               = ip6gre_clone,
341 	.io_put_attrs           = ip6gre_put_attrs,
342 	.io_free                = ip6gre_free,
343 };
344 
345 #define IS_IP6GRE_LINK_ASSERT(link)                                             \
346         if ((link)->l_info_ops != &ip6gre_info_ops) {                           \
347                 APPBUG("Link is not a ip6gre link. set type \"ip6gre\" first.");\
348                 return -NLE_OPNOTSUPP;                                          \
349         }
350 
351 #define HAS_IP6GRE_ATTR_ASSERT(link,attr)                                       \
352         if (!((link)->ip6gre_mask & (attr)))                                    \
353                 return -NLE_NOATTR;
354 
rtnl_link_ip6gre_alloc(void)355 struct rtnl_link *rtnl_link_ip6gre_alloc(void)
356 {
357 	struct rtnl_link *link;
358 	int err;
359 
360 	link = rtnl_link_alloc();
361 	if (!link)
362 		return NULL;
363 
364 	err = rtnl_link_set_type(link, "ip6gre");
365 	if (err < 0) {
366 		rtnl_link_put(link);
367 		return NULL;
368 	}
369 
370 	return link;
371 }
372 
373 /**
374  * Check if link is a IP6GRE link
375  * @arg link            Link object
376  *
377  * @return True if link is a IP6GRE link, otherwise 0 is returned.
378  */
rtnl_link_is_ip6gre(struct rtnl_link * link)379 int rtnl_link_is_ip6gre(struct rtnl_link *link)
380 {
381 	return link->l_info_ops && !strcmp(link->l_info_ops->io_name, "ip6gre");
382 }
383 
384 /**
385  * Create a new IP6GRE tunnel device
386  * @arg sock            netlink socket
387  * @arg name            name of the tunnel deviceL
388  *
389  * Creates a new ip6gre tunnel device in the kernel
390  * @return 0 on success or a negative error code
391  */
rtnl_link_ip6gre_add(struct nl_sock * sk,const char * name)392 int rtnl_link_ip6gre_add(struct nl_sock *sk, const char *name)
393 {
394 	struct rtnl_link *link;
395 	int err;
396 
397 	link = rtnl_link_ip6gre_alloc();
398 	if (!link)
399 		return -NLE_NOMEM;
400 
401 	if(name)
402 		rtnl_link_set_name(link, name);
403 
404 	err = rtnl_link_add(sk, link, NLM_F_CREATE);
405 	rtnl_link_put(link);
406 
407 	return err;
408 }
409 
410 /**
411  * Set IP6GRE tunnel interface index
412  * @arg link            Link object
413  * @arg index           interface index
414  *
415  * @return 0 on success or a negative error code
416  */
rtnl_link_ip6gre_set_link(struct rtnl_link * link,uint32_t index)417 int rtnl_link_ip6gre_set_link(struct rtnl_link *link, uint32_t index)
418 {
419 	struct ip6gre_info *ip6gre = link->l_info;
420 
421 	IS_IP6GRE_LINK_ASSERT(link);
422 
423 	ip6gre->link = index;
424 	ip6gre->ip6gre_mask |= IP6GRE_ATTR_LINK;
425 
426 	return 0;
427 }
428 
429 /**
430  * Get IP6GRE tunnel interface index
431  * @arg link            Link object
432  * @arg index           addr to fill in with the interface index
433  *
434  * @return 0 on success or a negative error code
435  */
rtnl_link_ip6gre_get_link(struct rtnl_link * link,uint32_t * index)436 int rtnl_link_ip6gre_get_link(struct rtnl_link *link, uint32_t *index)
437 {
438 	struct ip6gre_info *ip6gre = link->l_info;
439 
440 	IS_IP6GRE_LINK_ASSERT(link);
441 
442 	HAS_IP6GRE_ATTR_ASSERT(ip6gre, IP6GRE_ATTR_LINK);
443 
444 	*index = ip6gre->link;
445 
446 	return 0;
447 }
448 
449 /**
450  * Set IP6GRE tunnel set iflags
451  * @arg link            Link object
452  * @arg iflags          ip6gre iflags
453  *
454  * @return 0 on success or a negative error code
455  */
rtnl_link_ip6gre_set_iflags(struct rtnl_link * link,uint16_t iflags)456 int rtnl_link_ip6gre_set_iflags(struct rtnl_link *link, uint16_t iflags)
457 {
458 	struct ip6gre_info *ip6gre = link->l_info;
459 
460 	IS_IP6GRE_LINK_ASSERT(link);
461 
462 	ip6gre->iflags = iflags;
463 	ip6gre->ip6gre_mask |= IP6GRE_ATTR_IFLAGS;
464 
465 	return 0;
466 }
467 
468 /**
469  * Get IP6GRE tunnel iflags
470  * @arg link            Link object
471  * @arg iflags          addr to fill in with the iflags
472  *
473  * @return 0 on success or a negative error code
474  */
rtnl_link_ip6gre_get_iflags(struct rtnl_link * link,uint16_t * iflags)475 int rtnl_link_ip6gre_get_iflags(struct rtnl_link *link, uint16_t *iflags)
476 {
477 	struct ip6gre_info *ip6gre = link->l_info;
478 
479 	IS_IP6GRE_LINK_ASSERT(link);
480 
481 	HAS_IP6GRE_ATTR_ASSERT(ip6gre, IP6GRE_ATTR_IFLAGS);
482 
483 	*iflags = ip6gre->iflags;
484 
485 	return 0;
486 }
487 
488 /**
489  * Set IP6GRE tunnel set oflags
490  * @arg link            Link object
491  * @arg oflags          ip6gre oflags
492  *
493  * @return 0 on success or a negative error code
494  */
rtnl_link_ip6gre_set_oflags(struct rtnl_link * link,uint16_t oflags)495 int rtnl_link_ip6gre_set_oflags(struct rtnl_link *link, uint16_t oflags)
496 {
497 	struct ip6gre_info *ip6gre = link->l_info;
498 
499 	IS_IP6GRE_LINK_ASSERT(link);
500 
501 	ip6gre->oflags = oflags;
502 	ip6gre->ip6gre_mask |= IP6GRE_ATTR_OFLAGS;
503 
504 	return 0;
505 }
506 
507 /**
508  * Get IP6GRE tunnel oflags
509  * @arg link            Link object
510  * @arg oflags          addr to fill in with the oflags
511  *
512  * @return 0 on success or a negative error code
513  */
rtnl_link_ip6gre_get_oflags(struct rtnl_link * link,uint16_t * oflags)514 int rtnl_link_ip6gre_get_oflags(struct rtnl_link *link, uint16_t *oflags)
515 {
516 	struct ip6gre_info *ip6gre = link->l_info;
517 
518 	IS_IP6GRE_LINK_ASSERT(link);
519 
520 	HAS_IP6GRE_ATTR_ASSERT(ip6gre, IP6GRE_ATTR_OFLAGS);
521 
522 	*oflags = ip6gre->oflags;
523 
524 	return 0;
525 }
526 
527 /**
528  * Set IP6GRE tunnel set ikey
529  * @arg link            Link object
530  * @arg ikey            ip6gre ikey
531  *
532  * @return 0 on success or a negative error code
533  */
rtnl_link_ip6gre_set_ikey(struct rtnl_link * link,uint32_t ikey)534 int rtnl_link_ip6gre_set_ikey(struct rtnl_link *link, uint32_t ikey)
535 {
536 	struct ip6gre_info *ip6gre = link->l_info;
537 
538 	IS_IP6GRE_LINK_ASSERT(link);
539 
540 	ip6gre->ikey = ikey;
541 	ip6gre->ip6gre_mask |= IP6GRE_ATTR_IKEY;
542 
543 	return 0;
544 }
545 
546 /**
547  * Get IP6GRE tunnel ikey
548  * @arg link            Link object
549  * @arg ikey            addr to fill in with the ikey
550  *
551  * @return 0 on success or a negative error code
552  */
rtnl_link_ip6gre_get_ikey(struct rtnl_link * link,uint32_t * ikey)553 int rtnl_link_ip6gre_get_ikey(struct rtnl_link *link, uint32_t *ikey)
554 {
555 	struct ip6gre_info *ip6gre = link->l_info;
556 
557 	IS_IP6GRE_LINK_ASSERT(link);
558 
559 	HAS_IP6GRE_ATTR_ASSERT(ip6gre, IP6GRE_ATTR_IKEY);
560 
561 	*ikey = ip6gre->ikey;
562 
563 	return 0;
564 }
565 
566 /**
567  * Set IP6GRE tunnel set okey
568  * @arg link            Link object
569  * @arg okey            ip6gre okey
570  *
571  * @return 0 on success or a negative error code
572  */
rtnl_link_ip6gre_set_okey(struct rtnl_link * link,uint32_t okey)573 int rtnl_link_ip6gre_set_okey(struct rtnl_link *link, uint32_t okey)
574 {
575 	struct ip6gre_info *ip6gre = link->l_info;
576 
577 	IS_IP6GRE_LINK_ASSERT(link);
578 
579 	ip6gre->okey = okey;
580 	ip6gre->ip6gre_mask |= IP6GRE_ATTR_OKEY;
581 
582 	return 0;
583 }
584 
585 /**
586  * Get IP6GRE tunnel okey
587  * @arg link            Link object
588  * @arg okey            addr to fill in with the okey
589  *
590  * @return okey value
591  */
rtnl_link_ip6gre_get_okey(struct rtnl_link * link,uint32_t * okey)592 int rtnl_link_ip6gre_get_okey(struct rtnl_link *link, uint32_t *okey)
593 {
594 	struct ip6gre_info *ip6gre = link->l_info;
595 
596 	IS_IP6GRE_LINK_ASSERT(link);
597 
598 	HAS_IP6GRE_ATTR_ASSERT(ip6gre, IP6GRE_ATTR_OKEY);
599 
600 	*okey = ip6gre->okey;
601 
602 	return 0;
603 }
604 
605 /**
606  * Set IP6GRE tunnel local address
607  * @arg link            Link object
608  * @arg local           local address
609  *
610  * @return 0 on success or a negative error code
611  */
rtnl_link_ip6gre_set_local(struct rtnl_link * link,struct in6_addr * local)612 int rtnl_link_ip6gre_set_local(struct rtnl_link *link, struct in6_addr *local)
613 {
614 	struct ip6gre_info *ip6gre = link->l_info;
615 
616 	IS_IP6GRE_LINK_ASSERT(link);
617 
618 	memcpy(&ip6gre->local, local, sizeof(struct in6_addr));
619 	ip6gre->ip6gre_mask |= IP6GRE_ATTR_LOCAL;
620 
621 	return 0;
622 }
623 
624 /**
625  * Get IP6GRE tunnel local address
626  * @arg link            Link object
627  * @arg local           addr to fill in with local address
628  *
629  * @return 0 on success or a negative error code
630  */
rtnl_link_ip6gre_get_local(struct rtnl_link * link,struct in6_addr * local)631 int rtnl_link_ip6gre_get_local(struct rtnl_link *link, struct in6_addr *local)
632 {
633 	struct ip6gre_info *ip6gre = link->l_info;
634 
635 	IS_IP6GRE_LINK_ASSERT(link);
636 
637 	HAS_IP6GRE_ATTR_ASSERT(ip6gre, IP6GRE_ATTR_LOCAL);
638 
639 	memcpy(local, &ip6gre->local, sizeof(struct in6_addr));
640 
641 	return 0;
642 }
643 
644 /**
645  * Set IP6GRE tunnel remote address
646  * @arg link            Link object
647  * @arg remote          remote address
648  *
649  * @return 0 on success or a negative error code
650  */
rtnl_link_ip6gre_set_remote(struct rtnl_link * link,struct in6_addr * remote)651 int rtnl_link_ip6gre_set_remote(struct rtnl_link *link, struct in6_addr *remote)
652 {
653 	struct ip6gre_info *ip6gre = link->l_info;
654 
655 	IS_IP6GRE_LINK_ASSERT(link);
656 
657 	memcpy(&ip6gre->remote, remote, sizeof(struct in6_addr));
658 	ip6gre->ip6gre_mask |= IP6GRE_ATTR_REMOTE;
659 
660 	return 0;
661 }
662 
663 /**
664  * Get IP6GRE tunnel remote address
665  * @arg link            Link object
666  * @arg remote          addr to fill in with remote address
667  *
668  * @return 0 on success or a negative error code
669  */
rtnl_link_ip6gre_get_remote(struct rtnl_link * link,struct in6_addr * remote)670 int rtnl_link_ip6gre_get_remote(struct rtnl_link *link, struct in6_addr *remote)
671 {
672 	struct ip6gre_info *ip6gre = link->l_info;
673 
674 	IS_IP6GRE_LINK_ASSERT(link);
675 
676 	HAS_IP6GRE_ATTR_ASSERT(ip6gre, IP6GRE_ATTR_REMOTE);
677 
678 	memcpy(remote, &ip6gre->remote, sizeof(struct in6_addr));
679 
680 	return 0;
681 }
682 
683 /**
684  * Set IP6GRE tunnel ttl
685  * @arg link            Link object
686  * @arg ttl             tunnel ttl
687  *
688  * @return 0 on success or a negative error code
689  */
rtnl_link_ip6gre_set_ttl(struct rtnl_link * link,uint8_t ttl)690 int rtnl_link_ip6gre_set_ttl(struct rtnl_link *link, uint8_t ttl)
691 {
692 	struct ip6gre_info *ip6gre = link->l_info;
693 
694 	IS_IP6GRE_LINK_ASSERT(link);
695 
696 	ip6gre->ttl = ttl;
697 	ip6gre->ip6gre_mask |= IP6GRE_ATTR_TTL;
698 
699 	return 0;
700 }
701 
702 /**
703  * Set IP6GRE tunnel ttl
704  * @arg link            Link object
705  * @arg ttl             addr to fill in with the ttl
706  *
707  * @return 0 on success or a negative error code
708  */
rtnl_link_ip6gre_get_ttl(struct rtnl_link * link,uint8_t * ttl)709 int rtnl_link_ip6gre_get_ttl(struct rtnl_link *link, uint8_t *ttl)
710 {
711 	struct ip6gre_info *ip6gre = link->l_info;
712 
713 	IS_IP6GRE_LINK_ASSERT(link);
714 
715 	HAS_IP6GRE_ATTR_ASSERT(ip6gre, IP6GRE_ATTR_TTL);
716 
717 	*ttl = ip6gre->ttl;
718 
719 	return 0;
720 }
721 
722 /**
723  * Set IP6GRE tunnel encap limit
724  * @arg link            Link object
725  * @arg encaplimit      tunnel encap limit value
726  *
727  * @return 0 on success or a negative error code
728  */
rtnl_link_ip6gre_set_encaplimit(struct rtnl_link * link,uint8_t encaplimit)729 int rtnl_link_ip6gre_set_encaplimit(struct rtnl_link *link, uint8_t encaplimit)
730 {
731 	struct ip6gre_info *ip6gre = link->l_info;
732 
733 	IS_IP6GRE_LINK_ASSERT(link);
734 
735 	ip6gre->encaplimit = encaplimit;
736 	ip6gre->ip6gre_mask |= IP6GRE_ATTR_ENCAPLIMIT;
737 
738 	return 0;
739 }
740 
741 /**
742  * Get IP6GRE tunnel encap limit
743  * @arg link            Link object
744  * @arg encaplimit      addr to fill in with the encaplimit
745  *
746  * @return 0 on success or a negative error code
747  */
rtnl_link_ip6gre_get_encaplimit(struct rtnl_link * link,uint8_t * encaplimit)748 int rtnl_link_ip6gre_get_encaplimit(struct rtnl_link *link, uint8_t *encaplimit)
749 {
750 	struct ip6gre_info *ip6gre = link->l_info;
751 
752 	IS_IP6GRE_LINK_ASSERT(link);
753 
754 	HAS_IP6GRE_ATTR_ASSERT(ip6gre, IP6GRE_ATTR_ENCAPLIMIT);
755 
756 	*encaplimit = ip6gre->encaplimit;
757 
758 	return 0;
759 }
760 
761 /**
762  * Set IP6GRE tunnel flowinfo
763  * @arg link            Link object
764  * @arg flowinfo        flowinfo value
765  *
766  * @return 0 on success or a negative error code
767  */
rtnl_link_ip6gre_set_flowinfo(struct rtnl_link * link,uint32_t flowinfo)768 int rtnl_link_ip6gre_set_flowinfo(struct rtnl_link *link, uint32_t flowinfo)
769 {
770 	struct ip6gre_info *ip6gre = link->l_info;
771 
772 	IS_IP6GRE_LINK_ASSERT(link);
773 
774 	ip6gre->flowinfo = flowinfo;
775 	ip6gre->ip6gre_mask |= IP6GRE_ATTR_FLOWINFO;
776 
777 	return 0;
778 }
779 
780 /**
781  * Get IP6GRE flowinfo
782  * @arg link            Link object
783  * @arg flowinfo        addr to fill in with the flowinfo
784  *
785  * @return 0 on success or a negative error code
786  */
rtnl_link_ip6gre_get_flowinfo(struct rtnl_link * link,uint32_t * flowinfo)787 int rtnl_link_ip6gre_get_flowinfo(struct rtnl_link *link, uint32_t *flowinfo)
788 {
789 	struct ip6gre_info *ip6gre = link->l_info;
790 
791 	IS_IP6GRE_LINK_ASSERT(link);
792 
793 	HAS_IP6GRE_ATTR_ASSERT(ip6gre, IP6GRE_ATTR_FLOWINFO);
794 
795 	*flowinfo = ip6gre->flowinfo;
796 
797 	return 0;
798 }
799 
800 /**
801  * Set IP6GRE tunnel flags
802  * @arg link            Link object
803  * @arg flags           tunnel flags
804  *
805  * @return 0 on success or a negative error code
806  */
rtnl_link_ip6gre_set_flags(struct rtnl_link * link,uint32_t flags)807 int rtnl_link_ip6gre_set_flags(struct rtnl_link *link, uint32_t flags)
808 {
809 	struct ip6gre_info *ip6gre = link->l_info;
810 
811 	IS_IP6GRE_LINK_ASSERT(link);
812 
813 	ip6gre->flags = flags;
814 	ip6gre->ip6gre_mask |= IP6GRE_ATTR_FLAGS;
815 
816 	return 0;
817 }
818 
819 /**
820  * Get IP6GRE flags
821  * @arg link            Link object
822  * @arg flags           addr to fill in with the tunnel flags
823  *
824  * @return 0 on success or a negative error code
825  */
rtnl_link_ip6gre_get_flags(struct rtnl_link * link,uint32_t * flags)826 int rtnl_link_ip6gre_get_flags(struct rtnl_link *link, uint32_t *flags)
827 {
828 	struct ip6gre_info *ip6gre = link->l_info;
829 
830 	IS_IP6GRE_LINK_ASSERT(link);
831 
832 	HAS_IP6GRE_ATTR_ASSERT(ip6gre, IP6GRE_ATTR_FLAGS);
833 
834 	*flags = ip6gre->flags;
835 
836 	return 0;
837 }
838 
839 /**
840  * Set IP6GRE tunnel fwmark
841  * @arg link            Link object
842  * @arg fwmark          fwmark
843  *
844  * @return 0 on success or a negative error code
845  */
rtnl_link_ip6gre_set_fwmark(struct rtnl_link * link,uint32_t fwmark)846 int rtnl_link_ip6gre_set_fwmark(struct rtnl_link *link, uint32_t fwmark)
847 {
848 	struct ip6gre_info *ip6gre = link->l_info;
849 
850 	IS_IP6GRE_LINK_ASSERT(link);
851 
852 	ip6gre->fwmark = fwmark;
853 	ip6gre->ip6gre_mask |= IP6GRE_ATTR_FWMARK;
854 
855 	return 0;
856 }
857 
858 /**
859  * Get IP6GRE tunnel fwmark
860  * @arg link            Link object
861  * @arg fwmark          addr to fill in with the fwmark
862  *
863  * @return 0 on success or a negative error code
864  */
rtnl_link_ip6gre_get_fwmark(struct rtnl_link * link,uint32_t * fwmark)865 int rtnl_link_ip6gre_get_fwmark(struct rtnl_link *link, uint32_t *fwmark)
866 {
867 	struct ip6gre_info *ip6gre = link->l_info;
868 
869 	IS_IP6GRE_LINK_ASSERT(link);
870 
871 	HAS_IP6GRE_ATTR_ASSERT(ip6gre, IP6GRE_ATTR_FWMARK);
872 
873 	*fwmark = ip6gre->fwmark;
874 
875 	return 0;
876 }
877 
ip6gre_init(void)878 static void __init ip6gre_init(void)
879 {
880 	rtnl_link_register_info(&ip6gre_info_ops);
881 }
882 
ip6gre_exit(void)883 static void __exit ip6gre_exit(void)
884 {
885 	rtnl_link_unregister_info(&ip6gre_info_ops);
886 }
887