• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * lib/route/link/sit.c        SIT 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 sit SIT
15  * sit link module
16  *
17  * @details
18  * \b Link Type Name: "sit"
19  *
20  * @route_doc{link_sit, SIT 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/sit.h>
32 #include <netlink-private/route/link/api.h>
33 #include <linux/if_tunnel.h>
34 
35 #define SIT_ATTR_LINK          (1 << 0)
36 #define SIT_ATTR_LOCAL         (1 << 1)
37 #define SIT_ATTR_REMOTE        (1 << 2)
38 #define SIT_ATTR_TTL           (1 << 3)
39 #define SIT_ATTR_TOS           (1 << 4)
40 #define SIT_ATTR_PMTUDISC      (1 << 5)
41 #define SIT_ATTR_FLAGS         (1 << 6)
42 #define SIT_ATTR_PROTO         (1 << 7)
43 #define SIT_ATTR_6RD_PREFIX          (1 << 8)
44 #define SIT_ATTR_6RD_RELAY_PREFIX    (1 << 9)
45 #define SIT_ATTR_6RD_PREFIXLEN       (1 << 10)
46 #define SIT_ATTR_6RD_RELAY_PREFIXLEN (1 << 11)
47 
48 struct sit_info
49 {
50 	uint8_t    ttl;
51 	uint8_t    tos;
52 	uint8_t    pmtudisc;
53 	uint8_t    proto;
54 	uint16_t   flags;
55 	uint32_t   link;
56 	uint32_t   local;
57 	uint32_t   remote;
58 	struct in6_addr ip6rd_prefix;
59 	uint32_t   ip6rd_relay_prefix;
60 	uint16_t   ip6rd_prefixlen;
61 	uint16_t   ip6rd_relay_prefixlen;
62 	uint32_t   sit_mask;
63 };
64 
65 static struct nla_policy sit_policy[IFLA_IPTUN_MAX + 1] = {
66 	[IFLA_IPTUN_LINK]       = { .type = NLA_U32 },
67 	[IFLA_IPTUN_LOCAL]      = { .type = NLA_U32 },
68 	[IFLA_IPTUN_REMOTE]     = { .type = NLA_U32 },
69 	[IFLA_IPTUN_TTL]        = { .type = NLA_U8 },
70 	[IFLA_IPTUN_TOS]        = { .type = NLA_U8 },
71 	[IFLA_IPTUN_PMTUDISC]   = { .type = NLA_U8 },
72 	[IFLA_IPTUN_FLAGS]      = { .type = NLA_U16 },
73 	[IFLA_IPTUN_PROTO]      = { .type = NLA_U8 },
74 	[IFLA_IPTUN_6RD_PREFIX]          = { .minlen = sizeof(struct in6_addr) },
75 	[IFLA_IPTUN_6RD_RELAY_PREFIX]    = { .type = NLA_U32 },
76 	[IFLA_IPTUN_6RD_PREFIXLEN]       = { .type = NLA_U16 },
77 	[IFLA_IPTUN_6RD_RELAY_PREFIXLEN] = { .type = NLA_U16 },
78 };
79 
sit_alloc(struct rtnl_link * link)80 static int sit_alloc(struct rtnl_link *link)
81 {
82 	struct sit_info *sit;
83 
84 	if (link->l_info)
85 		memset(link->l_info, 0, sizeof(*sit));
86 	else {
87 		sit = calloc(1, sizeof(*sit));
88 		if (!sit)
89 			return -NLE_NOMEM;
90 
91 		link->l_info = sit;
92 	}
93 
94 	return 0;
95 }
96 
sit_parse(struct rtnl_link * link,struct nlattr * data,struct nlattr * xstats)97 static int sit_parse(struct rtnl_link *link, struct nlattr *data,
98 		     struct nlattr *xstats)
99 {
100 	struct nlattr *tb[IFLA_IPTUN_MAX + 1];
101 	struct sit_info *sit;
102 	int err;
103 
104 	NL_DBG(3, "Parsing SIT link info\n");
105 
106 	err = nla_parse_nested(tb, IFLA_IPTUN_MAX, data, sit_policy);
107 	if (err < 0)
108 		goto errout;
109 
110 	err = sit_alloc(link);
111 	if (err < 0)
112 		goto errout;
113 
114 	sit = link->l_info;
115 
116 	if (tb[IFLA_IPTUN_LINK]) {
117 		sit->link = nla_get_u32(tb[IFLA_IPTUN_LINK]);
118 		sit->sit_mask |= SIT_ATTR_LINK;
119 	}
120 
121 	if (tb[IFLA_IPTUN_LOCAL]) {
122 		sit->local = nla_get_u32(tb[IFLA_IPTUN_LOCAL]);
123 		sit->sit_mask |= SIT_ATTR_LOCAL;
124 	}
125 
126 	if (tb[IFLA_IPTUN_REMOTE]) {
127 		sit->remote = nla_get_u32(tb[IFLA_IPTUN_REMOTE]);
128 		sit->sit_mask |= SIT_ATTR_REMOTE;
129 	}
130 
131 	if (tb[IFLA_IPTUN_TTL]) {
132 		sit->ttl = nla_get_u8(tb[IFLA_IPTUN_TTL]);
133 		sit->sit_mask |= SIT_ATTR_TTL;
134 	}
135 
136 	if (tb[IFLA_IPTUN_TOS]) {
137 		sit->tos = nla_get_u8(tb[IFLA_IPTUN_TOS]);
138 		sit->sit_mask |= SIT_ATTR_TOS;
139 	}
140 
141 	if (tb[IFLA_IPTUN_PMTUDISC]) {
142 		sit->pmtudisc = nla_get_u8(tb[IFLA_IPTUN_PMTUDISC]);
143 		sit->sit_mask |= SIT_ATTR_PMTUDISC;
144 	}
145 
146 	if (tb[IFLA_IPTUN_FLAGS]) {
147 		sit->flags = nla_get_u16(tb[IFLA_IPTUN_FLAGS]);
148 		sit->sit_mask |= SIT_ATTR_FLAGS;
149 	}
150 
151 	if (tb[IFLA_IPTUN_PROTO]) {
152 		sit->proto = nla_get_u8(tb[IFLA_IPTUN_PROTO]);
153 		sit->sit_mask |= SIT_ATTR_PROTO;
154 	}
155 
156 	if (tb[IFLA_IPTUN_6RD_PREFIX]) {
157 		nla_memcpy(&sit->ip6rd_prefix, tb[IFLA_IPTUN_6RD_PREFIX],
158 			   sizeof(struct in6_addr));
159 		sit->sit_mask |= SIT_ATTR_6RD_PREFIX;
160 	}
161 
162 	if (tb[IFLA_IPTUN_6RD_RELAY_PREFIX]) {
163 		sit->ip6rd_relay_prefix = nla_get_u32(tb[IFLA_IPTUN_6RD_RELAY_PREFIX]);
164 		sit->sit_mask |= SIT_ATTR_6RD_RELAY_PREFIX;
165 	}
166 
167 	if (tb[IFLA_IPTUN_6RD_PREFIXLEN]) {
168 		sit->ip6rd_prefixlen = nla_get_u16(tb[IFLA_IPTUN_6RD_PREFIXLEN]);
169 		sit->sit_mask |= SIT_ATTR_6RD_PREFIXLEN;
170 	}
171 
172 	if (tb[IFLA_IPTUN_6RD_RELAY_PREFIXLEN]) {
173 		sit->ip6rd_relay_prefixlen = nla_get_u16(tb[IFLA_IPTUN_6RD_RELAY_PREFIXLEN]);
174 		sit->sit_mask |= SIT_ATTR_6RD_RELAY_PREFIXLEN;
175 	}
176 
177 	err = 0;
178 
179 errout:
180 	return err;
181 }
182 
sit_put_attrs(struct nl_msg * msg,struct rtnl_link * link)183 static int sit_put_attrs(struct nl_msg *msg, struct rtnl_link *link)
184 {
185 	struct sit_info *sit = link->l_info;
186 	struct nlattr *data;
187 
188 	data = nla_nest_start(msg, IFLA_INFO_DATA);
189 	if (!data)
190 		return -NLE_MSGSIZE;
191 
192 	if (sit->sit_mask & SIT_ATTR_LINK)
193 		NLA_PUT_U32(msg, IFLA_IPTUN_LINK, sit->link);
194 
195 	if (sit->sit_mask & SIT_ATTR_LOCAL)
196 		NLA_PUT_U32(msg, IFLA_IPTUN_LOCAL, sit->local);
197 
198 	if (sit->sit_mask & SIT_ATTR_REMOTE)
199 		NLA_PUT_U32(msg, IFLA_IPTUN_REMOTE, sit->remote);
200 
201 	if (sit->sit_mask & SIT_ATTR_TTL)
202 		NLA_PUT_U8(msg, IFLA_IPTUN_TTL, sit->ttl);
203 
204 	if (sit->sit_mask & SIT_ATTR_TOS)
205 		NLA_PUT_U8(msg, IFLA_IPTUN_TOS, sit->tos);
206 
207 	if (sit->sit_mask & SIT_ATTR_PMTUDISC)
208 		NLA_PUT_U8(msg, IFLA_IPTUN_PMTUDISC, sit->pmtudisc);
209 
210 	if (sit->sit_mask & SIT_ATTR_FLAGS)
211 		NLA_PUT_U16(msg, IFLA_IPTUN_FLAGS, sit->flags);
212 
213 	if (sit->sit_mask & SIT_ATTR_PROTO)
214 		NLA_PUT_U8(msg, IFLA_IPTUN_PROTO, sit->proto);
215 
216 	if (sit->sit_mask & SIT_ATTR_6RD_PREFIX)
217 		NLA_PUT(msg, IFLA_IPTUN_6RD_PREFIX, sizeof(struct in6_addr), &sit->ip6rd_prefix);
218 
219 	if (sit->sit_mask & SIT_ATTR_6RD_RELAY_PREFIX)
220 		NLA_PUT_U32(msg, IFLA_IPTUN_6RD_RELAY_PREFIX, sit->ip6rd_relay_prefix);
221 
222 	if (sit->sit_mask & SIT_ATTR_6RD_PREFIXLEN)
223 		NLA_PUT_U16(msg, IFLA_IPTUN_6RD_PREFIXLEN, sit->ip6rd_prefixlen);
224 
225 	if (sit->sit_mask & SIT_ATTR_6RD_RELAY_PREFIXLEN)
226 		NLA_PUT_U16(msg, IFLA_IPTUN_6RD_RELAY_PREFIXLEN, sit->ip6rd_relay_prefixlen);
227 
228 	nla_nest_end(msg, data);
229 
230 nla_put_failure:
231 
232 	return 0;
233 }
234 
sit_free(struct rtnl_link * link)235 static void sit_free(struct rtnl_link *link)
236 {
237 	struct sit_info *sit = link->l_info;
238 
239 	free(sit);
240 	link->l_info = NULL;
241 }
242 
sit_dump_line(struct rtnl_link * link,struct nl_dump_params * p)243 static void sit_dump_line(struct rtnl_link *link, struct nl_dump_params *p)
244 {
245 	nl_dump(p, "sit : %s", link->l_name);
246 }
247 
sit_dump_details(struct rtnl_link * link,struct nl_dump_params * p)248 static void sit_dump_details(struct rtnl_link *link, struct nl_dump_params *p)
249 {
250 	struct sit_info *sit = link->l_info;
251 	char *name, addr[INET_ADDRSTRLEN], addr6[INET6_ADDRSTRLEN];
252 	struct rtnl_link *parent;
253 
254 	if (sit->sit_mask & SIT_ATTR_LINK) {
255 		nl_dump(p, "      link ");
256 
257 		name = NULL;
258 		parent = link_lookup(link->ce_cache, sit->link);
259 		if (parent)
260 			name = rtnl_link_get_name(parent);
261 
262 		if (name)
263 			nl_dump_line(p, "%s\n", name);
264 		else
265 			nl_dump_line(p, "%u\n", sit->link);
266 	}
267 
268 	if (sit->sit_mask & SIT_ATTR_LOCAL) {
269 		nl_dump(p, "      local ");
270 		if(inet_ntop(AF_INET, &sit->local, addr, sizeof(addr)))
271 			nl_dump_line(p, "%s\n", addr);
272 		else
273 			nl_dump_line(p, "%#x\n", ntohs(sit->local));
274 	}
275 
276 	if (sit->sit_mask & SIT_ATTR_REMOTE) {
277 		nl_dump(p, "      remote ");
278 		if(inet_ntop(AF_INET, &sit->remote, addr, sizeof(addr)))
279 			nl_dump_line(p, "%s\n", addr);
280 		else
281 			nl_dump_line(p, "%#x\n", ntohs(sit->remote));
282 	}
283 
284 	if (sit->sit_mask & SIT_ATTR_TTL) {
285 		nl_dump(p, "      ttl ");
286 		nl_dump_line(p, "%u\n", sit->ttl);
287 	}
288 
289 	if (sit->sit_mask & SIT_ATTR_TOS) {
290 		nl_dump(p, "      tos ");
291 		nl_dump_line(p, "%u\n", sit->tos);
292 	}
293 
294 	if (sit->sit_mask & SIT_ATTR_FLAGS) {
295 		nl_dump(p, "      flags ");
296 		nl_dump_line(p, " (%x)\n", sit->flags);
297 	}
298 
299 	if (sit->sit_mask & SIT_ATTR_PROTO) {
300 		nl_dump(p, "      proto   ");
301 		nl_dump_line(p, " (%x)\n", sit->proto);
302 	}
303 
304 	if (sit->sit_mask & SIT_ATTR_6RD_PREFIX) {
305 		nl_dump(p, "      6rd_prefix   ");
306 		if(inet_ntop(AF_INET6, &sit->ip6rd_prefix, addr6, INET6_ADDRSTRLEN))
307 			nl_dump_line(p, "%s\n", addr6);
308 		else
309 			nl_dump_line(p, "[unknown]\n");
310 	}
311 
312 	if (sit->sit_mask & SIT_ATTR_6RD_RELAY_PREFIX) {
313 		nl_dump(p, "      6rd_relay_prefix   ");
314 		if(inet_ntop(AF_INET, &sit->ip6rd_relay_prefix, addr, sizeof(addr)))
315 			nl_dump_line(p, "%s\n", addr);
316 		else
317 			nl_dump_line(p, "[unknown]\n");
318 	}
319 
320 	if (sit->sit_mask & SIT_ATTR_6RD_PREFIXLEN) {
321 		nl_dump(p, "      6rd_prefixlen   ");
322 		nl_dump_line(p, "%d\n", sit->ip6rd_prefixlen);
323 	}
324 
325 	if (sit->sit_mask & SIT_ATTR_6RD_RELAY_PREFIXLEN) {
326 		nl_dump(p, "      6rd_relay_prefixlen   ");
327 		nl_dump_line(p, "%d\n", sit->ip6rd_relay_prefixlen);
328 	}
329 }
330 
sit_clone(struct rtnl_link * dst,struct rtnl_link * src)331 static int sit_clone(struct rtnl_link *dst, struct rtnl_link *src)
332 {
333 	struct sit_info *sit_dst, *sit_src = src->l_info;
334 	int err;
335 
336 	dst->l_info = NULL;
337 
338 	err = rtnl_link_set_type(dst, "sit");
339 	if (err < 0)
340 		return err;
341 
342 	sit_dst = dst->l_info;
343 
344 	if (!sit_dst || !sit_src)
345 		return -NLE_NOMEM;
346 
347 	memcpy(sit_dst, sit_src, sizeof(struct sit_info));
348 
349 	return 0;
350 }
351 
352 static struct rtnl_link_info_ops sit_info_ops = {
353 	.io_name                = "sit",
354 	.io_alloc               = sit_alloc,
355 	.io_parse               = sit_parse,
356 	.io_dump = {
357 		[NL_DUMP_LINE]  = sit_dump_line,
358 		[NL_DUMP_DETAILS] = sit_dump_details,
359 	},
360 	.io_clone               = sit_clone,
361 	.io_put_attrs           = sit_put_attrs,
362 	.io_free                = sit_free,
363 };
364 
365 #define IS_SIT_LINK_ASSERT(link, sit)                                              \
366         struct sit_info *sit;                                                      \
367         do {                                                                       \
368                 const struct rtnl_link *_link = (link);                            \
369                 if (!_link || _link->l_info_ops != &sit_info_ops) {                \
370                         APPBUG("Link is not a sit link. set type \"sit\" first."); \
371                         return -NLE_OPNOTSUPP;                                     \
372                 }                                                                  \
373                 (sit) = _link->l_info;                                             \
374         } while (0)
375 
rtnl_link_sit_alloc(void)376 struct rtnl_link *rtnl_link_sit_alloc(void)
377 {
378 	struct rtnl_link *link;
379 	int err;
380 
381 	link = rtnl_link_alloc();
382 	if (!link)
383 		return NULL;
384 
385 	err = rtnl_link_set_type(link, "sit");
386 	if (err < 0) {
387 		rtnl_link_put(link);
388 		return NULL;
389 	}
390 
391 	return link;
392 }
393 
394 /**
395  * Check if link is a SIT link
396  * @arg link            Link object
397  *
398  * @return True if link is a SIT link, otherwise false is returned.
399  */
rtnl_link_is_sit(struct rtnl_link * link)400 int rtnl_link_is_sit(struct rtnl_link *link)
401 {
402 	return link->l_info_ops && !strcmp(link->l_info_ops->io_name, "sit");
403 }
404 
405 /**
406  * Create a new sit tunnel device
407  * @arg sock            netlink socket
408  * @arg name            name of the tunnel device
409  *
410  * Creates a new sit tunnel device in the kernel
411  * @return 0 on success or a negative error code
412  */
rtnl_link_sit_add(struct nl_sock * sk,const char * name)413 int rtnl_link_sit_add(struct nl_sock *sk, const char *name)
414 {
415 	struct rtnl_link *link;
416 	int err;
417 
418 	link = rtnl_link_sit_alloc();
419 	if (!link)
420 		return -NLE_NOMEM;
421 
422 	if(name)
423 		rtnl_link_set_name(link, name);
424 
425 	err = rtnl_link_add(sk, link, NLM_F_CREATE);
426 	rtnl_link_put(link);
427 
428 	return err;
429 }
430 
431 /**
432  * Set SIT tunnel interface index
433  * @arg link            Link object
434  * @arg index           interface index
435  *
436  * @return 0 on success or a negative error code
437  */
rtnl_link_sit_set_link(struct rtnl_link * link,uint32_t index)438 int rtnl_link_sit_set_link(struct rtnl_link *link,  uint32_t index)
439 {
440 	IS_SIT_LINK_ASSERT(link, sit);
441 
442 	sit->link = index;
443 	sit->sit_mask |= SIT_ATTR_LINK;
444 
445 	return 0;
446 }
447 
448 /**
449  * Get SIT tunnel interface index
450  * @arg link            Link object
451  *
452  * @return interface index value
453  */
rtnl_link_sit_get_link(struct rtnl_link * link)454 uint32_t rtnl_link_sit_get_link(struct rtnl_link *link)
455 {
456 	IS_SIT_LINK_ASSERT(link, sit);
457 
458 	return sit->link;
459 }
460 
461 /**
462  * Set SIT tunnel local address
463  * @arg link            Link object
464  * @arg addr            local address
465  *
466  * @return 0 on success or a negative error code
467  */
rtnl_link_sit_set_local(struct rtnl_link * link,uint32_t addr)468 int rtnl_link_sit_set_local(struct rtnl_link *link, uint32_t addr)
469 {
470 	IS_SIT_LINK_ASSERT(link, sit);
471 
472 	sit->local = addr;
473 	sit->sit_mask |= SIT_ATTR_LOCAL;
474 
475 	return 0;
476 }
477 
478 /**
479  * Get SIT tunnel local address
480  * @arg link            Link object
481  *
482  * @return local address value
483  */
rtnl_link_sit_get_local(struct rtnl_link * link)484 uint32_t rtnl_link_sit_get_local(struct rtnl_link *link)
485 {
486 	IS_SIT_LINK_ASSERT(link, sit);
487 
488 	return sit->local;
489 }
490 
491 /**
492  * Set SIT tunnel remote address
493  * @arg link            Link object
494  * @arg remote          remote address
495  *
496  * @return 0 on success or a negative error code
497  */
rtnl_link_sit_set_remote(struct rtnl_link * link,uint32_t addr)498 int rtnl_link_sit_set_remote(struct rtnl_link *link, uint32_t addr)
499 {
500 	IS_SIT_LINK_ASSERT(link, sit);
501 
502 	sit->remote = addr;
503 	sit->sit_mask |= SIT_ATTR_REMOTE;
504 
505 	return 0;
506 }
507 
508 /**
509  * Get SIT tunnel remote address
510  * @arg link            Link object
511  *
512  * @return remote address
513  */
rtnl_link_sit_get_remote(struct rtnl_link * link)514 uint32_t rtnl_link_sit_get_remote(struct rtnl_link *link)
515 {
516 	IS_SIT_LINK_ASSERT(link, sit);
517 
518 	return sit->remote;
519 }
520 
521 /**
522  * Set SIT tunnel ttl
523  * @arg link            Link object
524  * @arg ttl             tunnel ttl
525  *
526  * @return 0 on success or a negative error code
527  */
rtnl_link_sit_set_ttl(struct rtnl_link * link,uint8_t ttl)528 int rtnl_link_sit_set_ttl(struct rtnl_link *link, uint8_t ttl)
529 {
530 	IS_SIT_LINK_ASSERT(link, sit);
531 
532 	sit->ttl = ttl;
533 	sit->sit_mask |= SIT_ATTR_TTL;
534 
535 	return 0;
536 }
537 
538 /**
539  * Get SIT tunnel ttl
540  * @arg link            Link object
541  *
542  * @return ttl value
543  */
rtnl_link_sit_get_ttl(struct rtnl_link * link)544 uint8_t rtnl_link_sit_get_ttl(struct rtnl_link *link)
545 {
546 	IS_SIT_LINK_ASSERT(link, sit);
547 
548 	return sit->ttl;
549 }
550 
551 /**
552  * Set SIT tunnel tos
553  * @arg link            Link object
554  * @arg tos             tunnel tos
555  *
556  * @return 0 on success or a negative error code
557  */
rtnl_link_sit_set_tos(struct rtnl_link * link,uint8_t tos)558 int rtnl_link_sit_set_tos(struct rtnl_link *link, uint8_t tos)
559 {
560 	IS_SIT_LINK_ASSERT(link, sit);
561 
562 	sit->tos = tos;
563 	sit->sit_mask |= SIT_ATTR_TOS;
564 
565 	return 0;
566 }
567 
568 /**
569  * Get SIT tunnel tos
570  * @arg link            Link object
571  *
572  * @return tos value
573  */
rtnl_link_sit_get_tos(struct rtnl_link * link)574 uint8_t rtnl_link_sit_get_tos(struct rtnl_link *link)
575 {
576 	IS_SIT_LINK_ASSERT(link, sit);
577 
578 	return sit->tos;
579 }
580 
581 /**
582  * Set SIT tunnel path MTU discovery
583  * @arg link            Link object
584  * @arg pmtudisc        path MTU discovery
585  *
586  * @return 0 on success or a negative error code
587  */
rtnl_link_sit_set_pmtudisc(struct rtnl_link * link,uint8_t pmtudisc)588 int rtnl_link_sit_set_pmtudisc(struct rtnl_link *link, uint8_t pmtudisc)
589 {
590 	IS_SIT_LINK_ASSERT(link, sit);
591 
592 	sit->pmtudisc = pmtudisc;
593 	sit->sit_mask |= SIT_ATTR_PMTUDISC;
594 
595 	return 0;
596 }
597 
598 /**
599  * Get SIT path MTU discovery
600  * @arg link            Link object
601  *
602  * @return pmtudisc value
603  */
rtnl_link_sit_get_pmtudisc(struct rtnl_link * link)604 uint8_t rtnl_link_sit_get_pmtudisc(struct rtnl_link *link)
605 {
606 	IS_SIT_LINK_ASSERT(link, sit);
607 
608 	return sit->pmtudisc;
609 }
610 
611 /**
612  * Set SIT tunnel flags
613  * @arg link            Link object
614  * @arg flags           tunnel flags
615  *
616  * @return 0 on success or a negative error code
617  */
rtnl_link_sit_set_flags(struct rtnl_link * link,uint16_t flags)618 int rtnl_link_sit_set_flags(struct rtnl_link *link, uint16_t flags)
619 {
620 	IS_SIT_LINK_ASSERT(link, sit);
621 
622 	sit->flags = flags;
623 	sit->sit_mask |= SIT_ATTR_FLAGS;
624 
625 	return 0;
626 }
627 
628 /**
629  * Get SIT path flags
630  * @arg link            Link object
631  *
632  * @return flags value
633  */
rtnl_link_sit_get_flags(struct rtnl_link * link)634 uint16_t rtnl_link_sit_get_flags(struct rtnl_link *link)
635 {
636 	IS_SIT_LINK_ASSERT(link, sit);
637 
638 	return sit->flags;
639 }
640 
641 /**
642  * Set SIT tunnel proto
643  * @arg link            Link object
644  * @arg proto           tunnel proto
645  *
646  * @return 0 on success or a negative error code
647  */
rtnl_link_sit_set_proto(struct rtnl_link * link,uint8_t proto)648 int rtnl_link_sit_set_proto(struct rtnl_link *link, uint8_t proto)
649 {
650 	IS_SIT_LINK_ASSERT(link, sit);
651 
652 	sit->proto = proto;
653 	sit->sit_mask |= SIT_ATTR_PROTO;
654 
655 	return 0;
656 }
657 
658 /**
659  * Get SIT proto
660  * @arg link            Link object
661  *
662  * @return proto value
663  */
rtnl_link_sit_get_proto(struct rtnl_link * link)664 uint8_t rtnl_link_sit_get_proto(struct rtnl_link *link)
665 {
666 	IS_SIT_LINK_ASSERT(link, sit);
667 
668 	return sit->proto;
669 }
670 
671 /**
672  * Set ip6rd prefix
673  * @arg link            Link object
674  * @arg prefix          The IPv6 prefix
675  *
676  * @return 0 on success or an error code.
677  */
rtnl_link_sit_set_ip6rd_prefix(struct rtnl_link * link,const struct in6_addr * prefix)678 int rtnl_link_sit_set_ip6rd_prefix(struct rtnl_link *link, const struct in6_addr *prefix)
679 {
680 	IS_SIT_LINK_ASSERT(link, sit);
681 
682 	sit->ip6rd_prefix = *prefix;
683 	sit->sit_mask |= SIT_ATTR_6RD_PREFIX;
684 	return 0;
685 }
686 
687 /**
688  * Get ip6rd prefix
689  * @arg link            Link object
690  * @arg prefix          The output IPv6 prefix
691  *
692  * @return 0 on success or an error code. If the property is unset,
693  *   this call fails too.
694  */
rtnl_link_sit_get_ip6rd_prefix(const struct rtnl_link * link,struct in6_addr * prefix)695 int rtnl_link_sit_get_ip6rd_prefix(const struct rtnl_link *link, struct in6_addr *prefix)
696 {
697 	IS_SIT_LINK_ASSERT(link, sit);
698 
699 	if (!(sit->sit_mask & SIT_ATTR_6RD_PREFIX))
700 		return -NLE_NOATTR;
701 
702 	if (prefix)
703 		*prefix = sit->ip6rd_prefix;
704 	return 0;
705 }
706 
707 /**
708  * Set ip6rd prefix length
709  * @arg link            Link object
710  * @arg prefixlen       The IPv6 prefix length
711  *
712  * @return 0 on success or an error code.
713  */
rtnl_link_sit_set_ip6rd_prefixlen(struct rtnl_link * link,uint16_t prefixlen)714 int rtnl_link_sit_set_ip6rd_prefixlen(struct rtnl_link *link, uint16_t prefixlen)
715 {
716 	IS_SIT_LINK_ASSERT(link, sit);
717 
718 	sit->sit_mask |= SIT_ATTR_6RD_PREFIXLEN;
719 	sit->ip6rd_prefixlen = prefixlen;
720 	return 0;
721 }
722 
723 /**
724  * Get ip6rd prefix length
725  * @arg link            Link object
726  * @arg prefixlen       Output pointer for the prefix length
727  *
728  * @return 0 on success or an error code. If the property is unset,
729  *   this call fails.
730  */
rtnl_link_sit_get_ip6rd_prefixlen(struct rtnl_link * link,uint16_t * prefixlen)731 int rtnl_link_sit_get_ip6rd_prefixlen(struct rtnl_link *link, uint16_t *prefixlen)
732 {
733 	IS_SIT_LINK_ASSERT(link, sit);
734 
735 	if (!(sit->sit_mask & SIT_ATTR_6RD_PREFIXLEN))
736 		return -NLE_NOATTR;
737 
738 	if (prefixlen)
739 		*prefixlen = sit->ip6rd_prefixlen;
740 	return 0;
741 }
742 
743 /**
744  * Set ip6rd relay prefix
745  * @arg link            Link object
746  * @arg prefix          The IPv6 prefix length
747  *
748  * @return 0 on success or an error code.
749  */
rtnl_link_sit_set_ip6rd_relay_prefix(struct rtnl_link * link,uint32_t prefix)750 int rtnl_link_sit_set_ip6rd_relay_prefix(struct rtnl_link *link, uint32_t prefix)
751 {
752 	IS_SIT_LINK_ASSERT(link, sit);
753 
754 	sit->sit_mask |= SIT_ATTR_6RD_RELAY_PREFIX;
755 	sit->ip6rd_relay_prefix = prefix;
756 	return 0;
757 }
758 
759 /**
760  * Get ip6rd prefix length
761  * @arg link            Link object
762  * @arg prefixlen       Output pointer for the prefix length
763  *
764  * @return 0 on success or an error code. If the property is unset,
765  *   this call fails.
766  */
rtnl_link_sit_get_ip6rd_relay_prefix(const struct rtnl_link * link,uint32_t * prefix)767 int rtnl_link_sit_get_ip6rd_relay_prefix(const struct rtnl_link *link, uint32_t *prefix)
768 {
769 	IS_SIT_LINK_ASSERT(link, sit);
770 
771 	if (!(sit->sit_mask & SIT_ATTR_6RD_RELAY_PREFIX))
772 		return -NLE_NOATTR;
773 
774 	if (prefix)
775 		*prefix = sit->ip6rd_relay_prefix;
776 	return 0;
777 }
778 
779 /**
780  * Set ip6rd relay prefix length
781  * @arg link            Link object
782  * @arg prefixlen       The IPv6 prefix length
783  *
784  * @return 0 on success or an error code.
785  */
rtnl_link_sit_set_ip6rd_relay_prefixlen(struct rtnl_link * link,uint16_t prefixlen)786 int rtnl_link_sit_set_ip6rd_relay_prefixlen(struct rtnl_link *link, uint16_t prefixlen)
787 {
788 	IS_SIT_LINK_ASSERT(link, sit);
789 
790 	sit->sit_mask |= SIT_ATTR_6RD_RELAY_PREFIXLEN;
791 	sit->ip6rd_relay_prefixlen = prefixlen;
792 	return 0;
793 }
794 
795 /**
796  * Get ip6rd relay prefix length
797  * @arg link            Link object
798  * @arg prefixlen       Output pointer for the prefix length
799  *
800  * @return 0 on success or an error code. If the property is unset,
801  *   this call fails.
802  */
rtnl_link_sit_get_ip6rd_relay_prefixlen(struct rtnl_link * link,uint16_t * prefixlen)803 int rtnl_link_sit_get_ip6rd_relay_prefixlen(struct rtnl_link *link, uint16_t *prefixlen)
804 {
805 	IS_SIT_LINK_ASSERT(link, sit);
806 
807 	if (!(sit->sit_mask & SIT_ATTR_6RD_RELAY_PREFIX))
808 		return -NLE_NOATTR;
809 
810 	if (prefixlen)
811 		*prefixlen = sit->ip6rd_relay_prefixlen;
812 	return 0;
813 }
814 
sit_init(void)815 static void __init sit_init(void)
816 {
817 	rtnl_link_register_info(&sit_info_ops);
818 }
819 
sit_exit(void)820 static void __exit sit_exit(void)
821 {
822 	rtnl_link_unregister_info(&sit_info_ops);
823 }
824