• 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-private/route/link/api.h>
32 #include <linux/if_tunnel.h>
33 
34 #define SIT_ATTR_LINK          (1 << 0)
35 #define SIT_ATTR_LOCAL         (1 << 1)
36 #define SIT_ATTR_REMOTE        (1 << 2)
37 #define SIT_ATTR_TTL           (1 << 3)
38 #define SIT_ATTR_TOS           (1 << 4)
39 #define SIT_ATTR_PMTUDISC      (1 << 5)
40 #define SIT_ATTR_FLAGS         (1 << 6)
41 #define SIT_ATTR_PROTO         (1 << 7)
42 
43 struct sit_info
44 {
45 	uint8_t    ttl;
46 	uint8_t    tos;
47 	uint8_t    pmtudisc;
48 	uint8_t    proto;
49 	uint16_t   flags;
50 	uint32_t   link;
51 	uint32_t   local;
52 	uint32_t   remote;
53 	uint32_t   sit_mask;
54 };
55 
56 static struct nla_policy sit_policy[IFLA_IPTUN_MAX + 1] = {
57 	[IFLA_IPTUN_LINK]       = { .type = NLA_U32 },
58 	[IFLA_IPTUN_LOCAL]      = { .type = NLA_U32 },
59 	[IFLA_IPTUN_REMOTE]     = { .type = NLA_U32 },
60 	[IFLA_IPTUN_TTL]        = { .type = NLA_U8 },
61 	[IFLA_IPTUN_TOS]        = { .type = NLA_U8 },
62 	[IFLA_IPTUN_PMTUDISC]   = { .type = NLA_U8 },
63 	[IFLA_IPTUN_FLAGS]      = { .type = NLA_U16 },
64 	[IFLA_IPTUN_PROTO]      = { .type = NLA_U8 },
65 };
66 
sit_alloc(struct rtnl_link * link)67 static int sit_alloc(struct rtnl_link *link)
68 {
69 	struct sit_info *sit;
70 
71 	sit = calloc(1, sizeof(*sit));
72 	if (!sit)
73 		return -NLE_NOMEM;
74 
75 	link->l_info = sit;
76 
77 	return 0;
78 }
79 
sit_parse(struct rtnl_link * link,struct nlattr * data,struct nlattr * xstats)80 static int sit_parse(struct rtnl_link *link, struct nlattr *data,
81 		     struct nlattr *xstats)
82 {
83 	struct nlattr *tb[IFLA_IPTUN_MAX + 1];
84 	struct sit_info *sit;
85 	int err;
86 
87 	NL_DBG(3, "Parsing SIT link info");
88 
89 	err = nla_parse_nested(tb, IFLA_IPTUN_MAX, data, sit_policy);
90 	if (err < 0)
91 		goto errout;
92 
93 	err = sit_alloc(link);
94 	if (err < 0)
95 		goto errout;
96 
97 	sit = link->l_info;
98 
99 	if (tb[IFLA_IPTUN_LINK]) {
100 		sit->link = nla_get_u32(tb[IFLA_IPTUN_LINK]);
101 		sit->sit_mask |= SIT_ATTR_LINK;
102 	}
103 
104 	if (tb[IFLA_IPTUN_LOCAL]) {
105 		sit->local = nla_get_u32(tb[IFLA_IPTUN_LOCAL]);
106 		sit->sit_mask |= SIT_ATTR_LOCAL;
107 	}
108 
109 	if (tb[IFLA_IPTUN_REMOTE]) {
110 		sit->remote = nla_get_u32(tb[IFLA_IPTUN_REMOTE]);
111 		sit->sit_mask |= SIT_ATTR_REMOTE;
112 	}
113 
114 	if (tb[IFLA_IPTUN_TTL]) {
115 		sit->ttl = nla_get_u8(tb[IFLA_IPTUN_TTL]);
116 		sit->sit_mask |= SIT_ATTR_TTL;
117 	}
118 
119 	if (tb[IFLA_IPTUN_TOS]) {
120 		sit->tos = nla_get_u8(tb[IFLA_IPTUN_TOS]);
121 		sit->sit_mask |= SIT_ATTR_TOS;
122 	}
123 
124 	if (tb[IFLA_IPTUN_PMTUDISC]) {
125 		sit->pmtudisc = nla_get_u8(tb[IFLA_IPTUN_PMTUDISC]);
126 		sit->sit_mask |= SIT_ATTR_PMTUDISC;
127 	}
128 
129 	if (tb[IFLA_IPTUN_FLAGS]) {
130 		sit->flags = nla_get_u16(tb[IFLA_IPTUN_FLAGS]);
131 		sit->sit_mask |= SIT_ATTR_FLAGS;
132 	}
133 
134 	if (tb[IFLA_IPTUN_PROTO]) {
135 		sit->proto = nla_get_u8(tb[IFLA_IPTUN_PROTO]);
136 		sit->sit_mask |= SIT_ATTR_PROTO;
137 	}
138 
139 	err = 0;
140 
141  errout:
142 	return err;
143 }
144 
sit_put_attrs(struct nl_msg * msg,struct rtnl_link * link)145 static int sit_put_attrs(struct nl_msg *msg, struct rtnl_link *link)
146 {
147 	struct sit_info *sit = link->l_info;
148 	struct nlattr *data;
149 
150 	data = nla_nest_start(msg, IFLA_INFO_DATA);
151 	if (!data)
152 		return -NLE_MSGSIZE;
153 
154 	if (sit->sit_mask & SIT_ATTR_LINK)
155 		NLA_PUT_U32(msg, IFLA_IPTUN_LINK, sit->link);
156 
157 	if (sit->sit_mask & SIT_ATTR_LOCAL)
158 		NLA_PUT_U32(msg, IFLA_IPTUN_LOCAL, sit->local);
159 
160 	if (sit->sit_mask & SIT_ATTR_REMOTE)
161 		NLA_PUT_U32(msg, IFLA_IPTUN_REMOTE, sit->remote);
162 
163 	if (sit->sit_mask & SIT_ATTR_TTL)
164 		NLA_PUT_U8(msg, IFLA_IPTUN_TTL, sit->ttl);
165 
166 	if (sit->sit_mask & SIT_ATTR_TOS)
167 		NLA_PUT_U8(msg, IFLA_IPTUN_TOS, sit->tos);
168 
169 	if (sit->sit_mask & SIT_ATTR_PMTUDISC)
170 		NLA_PUT_U8(msg, IFLA_IPTUN_PMTUDISC, sit->pmtudisc);
171 
172 	if (sit->sit_mask & SIT_ATTR_FLAGS)
173 		NLA_PUT_U16(msg, IFLA_IPTUN_FLAGS, sit->flags);
174 
175 	if (sit->sit_mask & SIT_ATTR_PROTO)
176 		NLA_PUT_U8(msg, IFLA_IPTUN_PROTO, sit->proto);
177 
178 	nla_nest_end(msg, data);
179 
180 nla_put_failure:
181 
182 	return 0;
183 }
184 
sit_free(struct rtnl_link * link)185 static void sit_free(struct rtnl_link *link)
186 {
187 	struct sit_info *sit = link->l_info;
188 
189 	free(sit);
190 	link->l_info = NULL;
191 }
192 
sit_dump_line(struct rtnl_link * link,struct nl_dump_params * p)193 static void sit_dump_line(struct rtnl_link *link, struct nl_dump_params *p)
194 {
195 	nl_dump(p, "sit : %s", link->l_name);
196 }
197 
sit_dump_details(struct rtnl_link * link,struct nl_dump_params * p)198 static void sit_dump_details(struct rtnl_link *link, struct nl_dump_params *p)
199 {
200 	struct sit_info *sit = link->l_info;
201 	char *name, addr[INET_ADDRSTRLEN];
202 
203 	if (sit->sit_mask & SIT_ATTR_LINK) {
204 		nl_dump(p, "      link ");
205 		name = rtnl_link_get_name(link);
206 		if (name)
207 			nl_dump_line(p, "%s\n", name);
208 		else
209 			nl_dump_line(p, "%u\n", sit->link);
210 	}
211 
212 	if (sit->sit_mask & SIT_ATTR_LOCAL) {
213 		nl_dump(p, "      local ");
214 		if(inet_ntop(AF_INET, &sit->local, addr, sizeof(addr)))
215 			nl_dump_line(p, "%s\n", addr);
216 		else
217 			nl_dump_line(p, "%#x\n", ntohs(sit->local));
218 	}
219 
220 	if (sit->sit_mask & SIT_ATTR_REMOTE) {
221 		nl_dump(p, "      remote ");
222 		if(inet_ntop(AF_INET, &sit->remote, addr, sizeof(addr)))
223 			nl_dump_line(p, "%s\n", addr);
224 		else
225 			nl_dump_line(p, "%#x\n", ntohs(sit->remote));
226 	}
227 
228 	if (sit->sit_mask & SIT_ATTR_TTL) {
229 		nl_dump(p, "      ttl ");
230 		nl_dump_line(p, "%u\n", sit->ttl);
231 	}
232 
233 	if (sit->sit_mask & SIT_ATTR_TOS) {
234 		nl_dump(p, "      tos ");
235 		nl_dump_line(p, "%u\n", sit->tos);
236 	}
237 
238 	if (sit->sit_mask & SIT_ATTR_FLAGS) {
239 		nl_dump(p, "      flags ");
240 		nl_dump_line(p, " (%x)\n", sit->flags);
241 	}
242 
243 	if (sit->sit_mask & SIT_ATTR_PROTO) {
244 		nl_dump(p, "    proto   ");
245 		nl_dump_line(p, " (%x)\n", sit->proto);
246 	}
247 }
248 
sit_clone(struct rtnl_link * dst,struct rtnl_link * src)249 static int sit_clone(struct rtnl_link *dst, struct rtnl_link *src)
250 {
251 	struct sit_info *sit_dst, *sit_src = src->l_info;
252 	int err;
253 
254 	dst->l_info = NULL;
255 
256 	err = rtnl_link_set_type(dst, "sit");
257 	if (err < 0)
258 		return err;
259 
260 	sit_dst = dst->l_info;
261 
262 	if (!sit_dst || !sit_src)
263 		return -NLE_NOMEM;
264 
265 	memcpy(sit_dst, sit_src, sizeof(struct sit_info));
266 
267 	return 0;
268 }
269 
270 static struct rtnl_link_info_ops sit_info_ops = {
271 	.io_name                = "sit",
272 	.io_alloc               = sit_alloc,
273 	.io_parse               = sit_parse,
274 	.io_dump = {
275 		[NL_DUMP_LINE]  = sit_dump_line,
276 		[NL_DUMP_DETAILS] = sit_dump_details,
277 	},
278 	.io_clone               = sit_clone,
279 	.io_put_attrs           = sit_put_attrs,
280 	.io_free                = sit_free,
281 };
282 
283 #define IS_SIT_LINK_ASSERT(link)                                           \
284         if ((link)->l_info_ops != &sit_info_ops) {                         \
285                 APPBUG("Link is not a sit link. set type \"sit\" first."); \
286                 return -NLE_OPNOTSUPP;                                     \
287         }
288 
rtnl_link_sit_alloc(void)289 struct rtnl_link *rtnl_link_sit_alloc(void)
290 {
291 	struct rtnl_link *link;
292 	int err;
293 
294 	link = rtnl_link_alloc();
295 	if (!link)
296 		return NULL;
297 
298 	err = rtnl_link_set_type(link, "sit");
299 	if (err < 0) {
300 		rtnl_link_put(link);
301 		return NULL;
302 	}
303 
304 	return link;
305 }
306 
307 /**
308  * Check if link is a SIT link
309  * @arg link            Link object
310  *
311  * @return True if link is a SIT link, otherwise false is returned.
312  */
rtnl_link_is_sit(struct rtnl_link * link)313 int rtnl_link_is_sit(struct rtnl_link *link)
314 {
315 	return link->l_info_ops && !strcmp(link->l_info_ops->io_name, "sit");
316 }
317 
318 /**
319  * Create a new sit tunnel device
320  * @arg sock            netlink socket
321  * @arg name            name of the tunnel device
322  *
323  * Creates a new sit tunnel device in the kernel
324  * @return 0 on success or a negative error code
325  */
rtnl_link_sit_add(struct nl_sock * sk,const char * name)326 int rtnl_link_sit_add(struct nl_sock *sk, const char *name)
327 {
328 	struct rtnl_link *link;
329 	int err;
330 
331 	link = rtnl_link_sit_alloc();
332 	if (!link)
333 		return -NLE_NOMEM;
334 
335 	if(name)
336 		rtnl_link_set_name(link, name);
337 
338 	err = rtnl_link_add(sk, link, NLM_F_CREATE);
339 	rtnl_link_put(link);
340 
341 	return err;
342 }
343 
344 /**
345  * Set SIT tunnel interface index
346  * @arg link            Link object
347  * @arg index           interface index
348  *
349  * @return 0 on success or a negative error code
350  */
rtnl_link_sit_set_link(struct rtnl_link * link,uint32_t index)351 int rtnl_link_sit_set_link(struct rtnl_link *link,  uint32_t index)
352 {
353 	struct sit_info *sit = link->l_info;
354 
355 	IS_SIT_LINK_ASSERT(link);
356 
357 	sit->link = index;
358 	sit->sit_mask |= SIT_ATTR_LINK;
359 
360 	return 0;
361 }
362 
363 /**
364  * Get SIT tunnel interface index
365  * @arg link            Link object
366  *
367  * @return interface index value
368  */
rtnl_link_sit_get_link(struct rtnl_link * link)369 uint32_t rtnl_link_sit_get_link(struct rtnl_link *link)
370 {
371 	struct sit_info *sit = link->l_info;
372 
373 	IS_SIT_LINK_ASSERT(link);
374 
375 	return sit->link;
376 }
377 
378 /**
379  * Set SIT tunnel local address
380  * @arg link            Link object
381  * @arg addr            local address
382  *
383  * @return 0 on success or a negative error code
384  */
rtnl_link_sit_set_local(struct rtnl_link * link,uint32_t addr)385 int rtnl_link_sit_set_local(struct rtnl_link *link, uint32_t addr)
386 {
387 	struct sit_info *sit = link->l_info;
388 
389 	IS_SIT_LINK_ASSERT(link);
390 
391 	sit->local = addr;
392 	sit->sit_mask |= SIT_ATTR_LOCAL;
393 
394 	return 0;
395 }
396 
397 /**
398  * Get SIT tunnel local address
399  * @arg link            Link object
400  *
401  * @return local address value
402  */
rtnl_link_sit_get_local(struct rtnl_link * link)403 uint32_t rtnl_link_sit_get_local(struct rtnl_link *link)
404 {
405 	struct sit_info *sit = link->l_info;
406 
407 	IS_SIT_LINK_ASSERT(link);
408 
409 	return sit->local;
410 }
411 
412 /**
413  * Set SIT tunnel remote address
414  * @arg link            Link object
415  * @arg remote          remote address
416  *
417  * @return 0 on success or a negative error code
418  */
rtnl_link_sit_set_remote(struct rtnl_link * link,uint32_t addr)419 int rtnl_link_sit_set_remote(struct rtnl_link *link, uint32_t addr)
420 {
421 	struct sit_info *sit = link->l_info;
422 
423 	IS_SIT_LINK_ASSERT(link);
424 
425 	sit->remote = addr;
426 	sit->sit_mask |= SIT_ATTR_REMOTE;
427 
428 	return 0;
429 }
430 
431 /**
432  * Get SIT tunnel remote address
433  * @arg link            Link object
434  *
435  * @return remote address
436  */
rtnl_link_sit_get_remote(struct rtnl_link * link)437 uint32_t rtnl_link_sit_get_remote(struct rtnl_link *link)
438 {
439 	struct sit_info *sit = link->l_info;
440 
441 	IS_SIT_LINK_ASSERT(link);
442 
443 	return sit->remote;
444 }
445 
446 /**
447  * Set SIT tunnel ttl
448  * @arg link            Link object
449  * @arg ttl             tunnel ttl
450  *
451  * @return 0 on success or a negative error code
452  */
rtnl_link_sit_set_ttl(struct rtnl_link * link,uint8_t ttl)453 int rtnl_link_sit_set_ttl(struct rtnl_link *link, uint8_t ttl)
454 {
455 	struct sit_info *sit = link->l_info;
456 
457 	IS_SIT_LINK_ASSERT(link);
458 
459 	sit->ttl = ttl;
460 	sit->sit_mask |= SIT_ATTR_TTL;
461 
462 	return 0;
463 }
464 
465 /**
466  * Get SIT tunnel ttl
467  * @arg link            Link object
468  *
469  * @return ttl value
470  */
rtnl_link_sit_get_ttl(struct rtnl_link * link)471 uint8_t rtnl_link_sit_get_ttl(struct rtnl_link *link)
472 {
473 	struct sit_info *sit = link->l_info;
474 
475 	IS_SIT_LINK_ASSERT(link);
476 
477 	return sit->ttl;
478 }
479 
480 /**
481  * Set SIT tunnel tos
482  * @arg link            Link object
483  * @arg tos             tunnel tos
484  *
485  * @return 0 on success or a negative error code
486  */
rtnl_link_sit_set_tos(struct rtnl_link * link,uint8_t tos)487 int rtnl_link_sit_set_tos(struct rtnl_link *link, uint8_t tos)
488 {
489 	struct sit_info *sit = link->l_info;
490 
491 	IS_SIT_LINK_ASSERT(link);
492 
493 	sit->tos = tos;
494 	sit->sit_mask |= SIT_ATTR_TOS;
495 
496 	return 0;
497 }
498 
499 /**
500  * Get SIT tunnel tos
501  * @arg link            Link object
502  *
503  * @return tos value
504  */
rtnl_link_sit_get_tos(struct rtnl_link * link)505 uint8_t rtnl_link_sit_get_tos(struct rtnl_link *link)
506 {
507 	struct sit_info *sit = link->l_info;
508 
509 	IS_SIT_LINK_ASSERT(link);
510 
511 	return sit->tos;
512 }
513 
514 /**
515  * Set SIT tunnel path MTU discovery
516  * @arg link            Link object
517  * @arg pmtudisc        path MTU discovery
518  *
519  * @return 0 on success or a negative error code
520  */
rtnl_link_sit_set_pmtudisc(struct rtnl_link * link,uint8_t pmtudisc)521 int rtnl_link_sit_set_pmtudisc(struct rtnl_link *link, uint8_t pmtudisc)
522 {
523 	struct sit_info *sit = link->l_info;
524 
525 	IS_SIT_LINK_ASSERT(link);
526 
527 	sit->pmtudisc = pmtudisc;
528 	sit->sit_mask |= SIT_ATTR_PMTUDISC;
529 
530 	return 0;
531 }
532 
533 /**
534  * Get SIT path MTU discovery
535  * @arg link            Link object
536  *
537  * @return pmtudisc value
538  */
rtnl_link_sit_get_pmtudisc(struct rtnl_link * link)539 uint8_t rtnl_link_sit_get_pmtudisc(struct rtnl_link *link)
540 {
541 	struct sit_info *sit = link->l_info;
542 
543 	IS_SIT_LINK_ASSERT(link);
544 
545 	return sit->pmtudisc;
546 }
547 
548 /**
549  * Set SIT tunnel flags
550  * @arg link            Link object
551  * @arg flags           tunnel flags
552  *
553  * @return 0 on success or a negative error code
554  */
rtnl_link_sit_set_flags(struct rtnl_link * link,uint16_t flags)555 int rtnl_link_sit_set_flags(struct rtnl_link *link, uint16_t flags)
556 {
557 	struct sit_info *sit = link->l_info;
558 
559 	IS_SIT_LINK_ASSERT(link);
560 
561 	sit->flags = flags;
562 	sit->sit_mask |= SIT_ATTR_FLAGS;
563 
564 	return 0;
565 }
566 
567 /**
568  * Get SIT path flags
569  * @arg link            Link object
570  *
571  * @return flags value
572  */
rtnl_link_sit_get_flags(struct rtnl_link * link)573 uint16_t rtnl_link_sit_get_flags(struct rtnl_link *link)
574 {
575 	struct sit_info *sit = link->l_info;
576 
577 	IS_SIT_LINK_ASSERT(link);
578 
579 	return sit->flags;
580 }
581 
582 /**
583  * Set SIT tunnel proto
584  * @arg link            Link object
585  * @arg proto           tunnel proto
586  *
587  * @return 0 on success or a negative error code
588  */
rtnl_link_sit_set_proto(struct rtnl_link * link,uint8_t proto)589 int rtnl_link_sit_set_proto(struct rtnl_link *link, uint8_t proto)
590 {
591 	struct sit_info *sit = link->l_info;
592 
593 	IS_SIT_LINK_ASSERT(link);
594 
595 	sit->proto = proto;
596 	sit->sit_mask |= SIT_ATTR_PROTO;
597 
598 	return 0;
599 }
600 
601 /**
602  * Get SIT proto
603  * @arg link            Link object
604  *
605  * @return proto value
606  */
rtnl_link_sit_get_proto(struct rtnl_link * link)607 uint8_t rtnl_link_sit_get_proto(struct rtnl_link *link)
608 {
609 	struct sit_info *sit = link->l_info;
610 
611 	IS_SIT_LINK_ASSERT(link);
612 
613 	return sit->proto;
614 }
615 
sit_init(void)616 static void __init sit_init(void)
617 {
618 	rtnl_link_register_info(&sit_info_ops);
619 }
620 
sit_exit(void)621 static void __exit sit_exit(void)
622 {
623 	rtnl_link_unregister_info(&sit_info_ops);
624 }
625