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