1 /* SPDX-License-Identifier: LGPL-2.1-only */
2 /*
3 * Copyright (c) 2014 Susant Sahani <[email protected]>
4 */
5
6 /**
7 * @ingroup link
8 * @defgroup ipip IPIP
9 * ipip link module
10 *
11 * @details
12 * \b Link Type Name: "ipip"
13 *
14 * @route_doc{link_ipip, IPIP Documentation}
15 *
16 * @{
17 */
18
19 #include "nl-default.h"
20
21 #include <linux/if_tunnel.h>
22
23 #include <netlink/netlink.h>
24 #include <netlink/attr.h>
25 #include <netlink/utils.h>
26 #include <netlink/object.h>
27 #include <netlink/route/rtnl.h>
28 #include <netlink/route/link/ipip.h>
29
30 #include "nl-route.h"
31 #include "link-api.h"
32
33 #define IPIP_ATTR_LINK (1 << 0)
34 #define IPIP_ATTR_LOCAL (1 << 1)
35 #define IPIP_ATTR_REMOTE (1 << 2)
36 #define IPIP_ATTR_TTL (1 << 3)
37 #define IPIP_ATTR_TOS (1 << 4)
38 #define IPIP_ATTR_PMTUDISC (1 << 5)
39 #define IPIP_ATTR_FWMARK (1 << 6)
40
41 struct ipip_info
42 {
43 uint8_t ttl;
44 uint8_t tos;
45 uint8_t pmtudisc;
46 uint32_t link;
47 uint32_t local;
48 uint32_t remote;
49 uint32_t fwmark;
50 uint32_t ipip_mask;
51 };
52
53 static struct nla_policy ipip_policy[IFLA_IPTUN_MAX + 1] = {
54 [IFLA_IPTUN_LINK] = { .type = NLA_U32 },
55 [IFLA_IPTUN_LOCAL] = { .type = NLA_U32 },
56 [IFLA_IPTUN_REMOTE] = { .type = NLA_U32 },
57 [IFLA_IPTUN_TTL] = { .type = NLA_U8 },
58 [IFLA_IPTUN_TOS] = { .type = NLA_U8 },
59 [IFLA_IPTUN_PMTUDISC] = { .type = NLA_U8 },
60 [IFLA_IPTUN_FWMARK] = { .type = NLA_U32 },
61 };
62
ipip_alloc(struct rtnl_link * link)63 static int ipip_alloc(struct rtnl_link *link)
64 {
65 struct ipip_info *ipip;
66
67 if (link->l_info)
68 memset(link->l_info, 0, sizeof(*ipip));
69 else {
70 ipip = calloc(1, sizeof(*ipip));
71 if (!ipip)
72 return -NLE_NOMEM;
73
74 link->l_info = ipip;
75 }
76
77 return 0;
78 }
79
ipip_parse(struct rtnl_link * link,struct nlattr * data,struct nlattr * xstats)80 static int ipip_parse(struct rtnl_link *link, struct nlattr *data,
81 struct nlattr *xstats)
82 {
83 struct nlattr *tb[IFLA_IPTUN_MAX + 1];
84 struct ipip_info *ipip;
85 int err;
86
87 NL_DBG(3, "Parsing IPIP link info\n");
88
89 err = nla_parse_nested(tb, IFLA_IPTUN_MAX, data, ipip_policy);
90 if (err < 0)
91 goto errout;
92
93 err = ipip_alloc(link);
94 if (err < 0)
95 goto errout;
96
97 ipip = link->l_info;
98
99 if (tb[IFLA_IPTUN_LINK]) {
100 ipip->link = nla_get_u32(tb[IFLA_IPTUN_LINK]);
101 ipip->ipip_mask |= IPIP_ATTR_LINK;
102 }
103
104 if (tb[IFLA_IPTUN_LOCAL]) {
105 ipip->local = nla_get_u32(tb[IFLA_IPTUN_LOCAL]);
106 ipip->ipip_mask |= IPIP_ATTR_LOCAL;
107 }
108
109 if (tb[IFLA_IPTUN_REMOTE]) {
110 ipip->remote = nla_get_u32(tb[IFLA_IPTUN_REMOTE]);
111 ipip->ipip_mask |= IPIP_ATTR_REMOTE;
112 }
113
114 if (tb[IFLA_IPTUN_TTL]) {
115 ipip->ttl = nla_get_u8(tb[IFLA_IPTUN_TTL]);
116 ipip->ipip_mask |= IPIP_ATTR_TTL;
117 }
118
119 if (tb[IFLA_IPTUN_TOS]) {
120 ipip->tos = nla_get_u8(tb[IFLA_IPTUN_TOS]);
121 ipip->ipip_mask |= IPIP_ATTR_TOS;
122 }
123
124 if (tb[IFLA_IPTUN_PMTUDISC]) {
125 ipip->pmtudisc = nla_get_u8(tb[IFLA_IPTUN_PMTUDISC]);
126 ipip->ipip_mask |= IPIP_ATTR_PMTUDISC;
127 }
128
129 if (tb[IFLA_IPTUN_FWMARK]) {
130 ipip->fwmark = nla_get_u32(tb[IFLA_IPTUN_FWMARK]);
131 ipip->ipip_mask |= IPIP_ATTR_FWMARK;
132 }
133
134 err = 0;
135
136 errout:
137 return err;
138 }
139
ipip_put_attrs(struct nl_msg * msg,struct rtnl_link * link)140 static int ipip_put_attrs(struct nl_msg *msg, struct rtnl_link *link)
141 {
142 struct ipip_info *ipip = link->l_info;
143 struct nlattr *data;
144
145 data = nla_nest_start(msg, IFLA_INFO_DATA);
146 if (!data)
147 return -NLE_MSGSIZE;
148
149 if (ipip->ipip_mask & IPIP_ATTR_LINK)
150 NLA_PUT_U32(msg, IFLA_IPTUN_LINK, ipip->link);
151
152 if (ipip->ipip_mask & IPIP_ATTR_LOCAL)
153 NLA_PUT_U32(msg, IFLA_IPTUN_LOCAL, ipip->local);
154
155 if (ipip->ipip_mask & IPIP_ATTR_REMOTE)
156 NLA_PUT_U32(msg, IFLA_IPTUN_REMOTE, ipip->remote);
157
158 if (ipip->ipip_mask & IPIP_ATTR_TTL)
159 NLA_PUT_U8(msg, IFLA_IPTUN_TTL, ipip->ttl);
160
161 if (ipip->ipip_mask & IPIP_ATTR_TOS)
162 NLA_PUT_U8(msg, IFLA_IPTUN_TOS, ipip->tos);
163
164 if (ipip->ipip_mask & IPIP_ATTR_PMTUDISC)
165 NLA_PUT_U8(msg, IFLA_IPTUN_PMTUDISC, ipip->pmtudisc);
166
167 if (ipip->ipip_mask & IPIP_ATTR_FWMARK)
168 NLA_PUT_U32(msg, IFLA_IPTUN_FWMARK, ipip->fwmark);
169
170 nla_nest_end(msg, data);
171
172 nla_put_failure:
173 return 0;
174 }
175
ipip_free(struct rtnl_link * link)176 static void ipip_free(struct rtnl_link *link)
177 {
178 struct ipip_info *ipip = link->l_info;
179
180 free(ipip);
181 link->l_info = NULL;
182 }
183
ipip_dump_line(struct rtnl_link * link,struct nl_dump_params * p)184 static void ipip_dump_line(struct rtnl_link *link, struct nl_dump_params *p)
185 {
186 nl_dump(p, "ipip : %s", link->l_name);
187 }
188
ipip_dump_details(struct rtnl_link * link,struct nl_dump_params * p)189 static void ipip_dump_details(struct rtnl_link *link, struct nl_dump_params *p)
190 {
191 struct ipip_info *ipip = link->l_info;
192 char *name, addr[INET_ADDRSTRLEN];
193 struct rtnl_link *parent;
194
195 if (ipip->ipip_mask & IPIP_ATTR_LINK) {
196 nl_dump(p, " link ");
197
198 name = NULL;
199 parent = link_lookup(link->ce_cache, ipip->link);
200 if (parent)
201 name = rtnl_link_get_name(parent);
202
203 if (name)
204 nl_dump_line(p, "%s\n", name);
205 else
206 nl_dump_line(p, "%u\n", ipip->link);
207 }
208
209 if (ipip->ipip_mask & IPIP_ATTR_LOCAL) {
210 nl_dump(p, " local ");
211 if(inet_ntop(AF_INET, &ipip->local, addr, sizeof(addr)))
212 nl_dump_line(p, "%s\n", addr);
213 else
214 nl_dump_line(p, "%#x\n", ntohs(ipip->local));
215 }
216
217 if (ipip->ipip_mask & IPIP_ATTR_REMOTE) {
218 nl_dump(p, " remote ");
219 if(inet_ntop(AF_INET, &ipip->remote, addr, sizeof(addr)))
220 nl_dump_line(p, "%s\n", addr);
221 else
222 nl_dump_line(p, "%#x\n", ntohs(ipip->remote));
223 }
224
225 if (ipip->ipip_mask & IPIP_ATTR_TTL) {
226 nl_dump(p, " ttl ");
227 nl_dump_line(p, "%u\n", ipip->ttl);
228 }
229
230 if (ipip->ipip_mask & IPIP_ATTR_TOS) {
231 nl_dump(p, " tos ");
232 nl_dump_line(p, "%u\n", ipip->tos);
233 }
234
235 if (ipip->ipip_mask & IPIP_ATTR_PMTUDISC) {
236 nl_dump(p, " pmtudisc ");
237 nl_dump_line(p, "enabled (%#x)\n", ipip->pmtudisc);
238 }
239
240 if (ipip->ipip_mask & IPIP_ATTR_FWMARK) {
241 nl_dump(p, " fwmark ");
242 nl_dump_line(p, "%x\n", ipip->fwmark);
243 }
244 }
245
ipip_clone(struct rtnl_link * dst,struct rtnl_link * src)246 static int ipip_clone(struct rtnl_link *dst, struct rtnl_link *src)
247 {
248 struct ipip_info *ipip_dst, *ipip_src = src->l_info;
249 int err;
250
251 dst->l_info = NULL;
252
253 err = rtnl_link_set_type(dst, "ipip");
254 if (err < 0)
255 return err;
256
257 ipip_dst = dst->l_info;
258
259 if (!ipip_dst || !ipip_src)
260 BUG();
261
262 memcpy(ipip_dst, ipip_src, sizeof(struct ipip_info));
263
264 return 0;
265 }
266
267 static struct rtnl_link_info_ops ipip_info_ops = {
268 .io_name = "ipip",
269 .io_alloc = ipip_alloc,
270 .io_parse = ipip_parse,
271 .io_dump = {
272 [NL_DUMP_LINE] = ipip_dump_line,
273 [NL_DUMP_DETAILS] = ipip_dump_details,
274 },
275 .io_clone = ipip_clone,
276 .io_put_attrs = ipip_put_attrs,
277 .io_free = ipip_free,
278 };
279
280 #define IS_IPIP_LINK_ASSERT(link) \
281 if ((link)->l_info_ops != &ipip_info_ops) { \
282 APPBUG("Link is not a ipip link. set type \"ipip\" first."); \
283 return -NLE_OPNOTSUPP; \
284 }
285
rtnl_link_ipip_alloc(void)286 struct rtnl_link *rtnl_link_ipip_alloc(void)
287 {
288 struct rtnl_link *link;
289 int err;
290
291 link = rtnl_link_alloc();
292 if (!link)
293 return NULL;
294
295 err = rtnl_link_set_type(link, "ipip");
296 if (err < 0) {
297 rtnl_link_put(link);
298 return NULL;
299 }
300
301 return link;
302 }
303
304 /**
305 * Check if link is a IPIP link
306 * @arg link Link object
307 *
308 * @return True if link is a IPIP link, otherwise false is returned.
309 */
rtnl_link_is_ipip(struct rtnl_link * link)310 int rtnl_link_is_ipip(struct rtnl_link *link)
311 {
312 return link->l_info_ops && !strcmp(link->l_info_ops->io_name, "ipip");
313 }
314
315 /**
316 * Create a new ipip tunnel device
317 * @arg sock netlink socket
318 * @arg name name of the tunnel deviceL
319 *
320 * Creates a new ipip tunnel device in the kernel
321 * @return 0 on success or a negative error code
322 */
rtnl_link_ipip_add(struct nl_sock * sk,const char * name)323 int rtnl_link_ipip_add(struct nl_sock *sk, const char *name)
324 {
325 struct rtnl_link *link;
326 int err;
327
328 link = rtnl_link_ipip_alloc();
329 if (!link)
330 return -NLE_NOMEM;
331
332 if(name)
333 rtnl_link_set_name(link, name);
334
335 err = rtnl_link_add(sk, link, NLM_F_CREATE);
336 rtnl_link_put(link);
337
338 return err;
339 }
340
341 /**
342 * Set IPIP tunnel interface index
343 * @arg link Link object
344 * @arg index interface index
345 *
346 * @return 0 on success or a negative error code
347 */
rtnl_link_ipip_set_link(struct rtnl_link * link,uint32_t index)348 int rtnl_link_ipip_set_link(struct rtnl_link *link, uint32_t index)
349 {
350 struct ipip_info *ipip = link->l_info;
351
352 IS_IPIP_LINK_ASSERT(link);
353
354 ipip->link = index;
355 ipip->ipip_mask |= IPIP_ATTR_LINK;
356
357 return 0;
358 }
359
360 /**
361 * Get IPIP tunnel interface index
362 * @arg link Link object
363 *
364 * @return interface index value
365 */
rtnl_link_ipip_get_link(struct rtnl_link * link)366 uint32_t rtnl_link_ipip_get_link(struct rtnl_link *link)
367 {
368 struct ipip_info *ipip = link->l_info;
369
370 IS_IPIP_LINK_ASSERT(link);
371
372 return ipip->link;
373 }
374
375 /**
376 * Set IPIP tunnel local address
377 * @arg link Link object
378 * @arg addr local address
379 *
380 * @return 0 on success or a negative error code
381 */
rtnl_link_ipip_set_local(struct rtnl_link * link,uint32_t addr)382 int rtnl_link_ipip_set_local(struct rtnl_link *link, uint32_t addr)
383 {
384 struct ipip_info *ipip = link->l_info;
385
386 IS_IPIP_LINK_ASSERT(link);
387
388 ipip->local = addr;
389 ipip->ipip_mask |= IPIP_ATTR_LOCAL;
390
391 return 0;
392 }
393
394 /**
395 * Get IPIP tunnel local address
396 * @arg link Link object
397 *
398 * @return local address value
399 */
rtnl_link_ipip_get_local(struct rtnl_link * link)400 uint32_t rtnl_link_ipip_get_local(struct rtnl_link *link)
401 {
402 struct ipip_info *ipip = link->l_info;
403
404 IS_IPIP_LINK_ASSERT(link);
405
406 return ipip->local;
407 }
408
409 /**
410 * Set IPIP tunnel remote address
411 * @arg link Link object
412 * @arg remote remote address
413 *
414 * @return 0 on success or a negative error code
415 */
rtnl_link_ipip_set_remote(struct rtnl_link * link,uint32_t addr)416 int rtnl_link_ipip_set_remote(struct rtnl_link *link, uint32_t addr)
417 {
418 struct ipip_info *ipip = link->l_info;
419
420 IS_IPIP_LINK_ASSERT(link);
421
422 ipip->remote = addr;
423 ipip->ipip_mask |= IPIP_ATTR_REMOTE;
424
425 return 0;
426 }
427
428 /**
429 * Get IPIP tunnel remote address
430 * @arg link Link object
431 *
432 * @return remote address
433 */
rtnl_link_ipip_get_remote(struct rtnl_link * link)434 uint32_t rtnl_link_ipip_get_remote(struct rtnl_link *link)
435 {
436 struct ipip_info *ipip = link->l_info;
437
438 IS_IPIP_LINK_ASSERT(link);
439
440 return ipip->remote;
441 }
442
443 /**
444 * Set IPIP tunnel ttl
445 * @arg link Link object
446 * @arg ttl tunnel ttl
447 *
448 * @return 0 on success or a negative error code
449 */
rtnl_link_ipip_set_ttl(struct rtnl_link * link,uint8_t ttl)450 int rtnl_link_ipip_set_ttl(struct rtnl_link *link, uint8_t ttl)
451 {
452 struct ipip_info *ipip = link->l_info;
453
454 IS_IPIP_LINK_ASSERT(link);
455
456 ipip->ttl = ttl;
457 ipip->ipip_mask |= IPIP_ATTR_TTL;
458
459 return 0;
460 }
461
462 /**
463 * Get IPIP tunnel ttl
464 * @arg link Link object
465 *
466 * @return ttl value
467 */
rtnl_link_ipip_get_ttl(struct rtnl_link * link)468 uint8_t rtnl_link_ipip_get_ttl(struct rtnl_link *link)
469 {
470 struct ipip_info *ipip = link->l_info;
471
472 IS_IPIP_LINK_ASSERT(link);
473
474 return ipip->ttl;
475 }
476
477 /**
478 * Set IPIP tunnel tos
479 * @arg link Link object
480 * @arg tos tunnel tos
481 *
482 * @return 0 on success or a negative error code
483 */
rtnl_link_ipip_set_tos(struct rtnl_link * link,uint8_t tos)484 int rtnl_link_ipip_set_tos(struct rtnl_link *link, uint8_t tos)
485 {
486 struct ipip_info *ipip = link->l_info;
487
488 IS_IPIP_LINK_ASSERT(link);
489
490 ipip->tos = tos;
491 ipip->ipip_mask |= IPIP_ATTR_TOS;
492
493 return 0;
494 }
495
496 /**
497 * Get IPIP tunnel tos
498 * @arg link Link object
499 *
500 * @return tos value
501 */
rtnl_link_ipip_get_tos(struct rtnl_link * link)502 uint8_t rtnl_link_ipip_get_tos(struct rtnl_link *link)
503 {
504 struct ipip_info *ipip = link->l_info;
505
506 IS_IPIP_LINK_ASSERT(link);
507
508 return ipip->tos;
509 }
510
511 /**
512 * Set IPIP tunnel path MTU discovery
513 * @arg link Link object
514 * @arg pmtudisc path MTU discovery
515 *
516 * @return 0 on success or a negative error code
517 */
rtnl_link_ipip_set_pmtudisc(struct rtnl_link * link,uint8_t pmtudisc)518 int rtnl_link_ipip_set_pmtudisc(struct rtnl_link *link, uint8_t pmtudisc)
519 {
520 struct ipip_info *ipip = link->l_info;
521
522 IS_IPIP_LINK_ASSERT(link);
523
524 ipip->pmtudisc = pmtudisc;
525 ipip->ipip_mask |= IPIP_ATTR_PMTUDISC;
526
527 return 0;
528 }
529
530 /**
531 * Get IPIP path MTU discovery
532 * @arg link Link object
533 *
534 * @return pmtudisc value
535 */
rtnl_link_ipip_get_pmtudisc(struct rtnl_link * link)536 uint8_t rtnl_link_ipip_get_pmtudisc(struct rtnl_link *link)
537 {
538 struct ipip_info *ipip = link->l_info;
539
540 IS_IPIP_LINK_ASSERT(link);
541
542 return ipip->pmtudisc;
543 }
544
545 /**
546 * Set IPIP tunnel fwmark
547 * @arg link Link object
548 * @arg fwmark fwmark
549 *
550 * @return 0 on success or a negative error code
551 */
rtnl_link_ipip_set_fwmark(struct rtnl_link * link,uint32_t fwmark)552 int rtnl_link_ipip_set_fwmark(struct rtnl_link *link, uint32_t fwmark)
553 {
554 struct ipip_info *ipip = link->l_info;
555
556 IS_IPIP_LINK_ASSERT(link);
557
558 ipip->fwmark = fwmark;
559 ipip->ipip_mask |= IPIP_ATTR_FWMARK;
560
561 return 0;
562 }
563
564 /**
565 * Get IPIP tunnel fwmark
566 * @arg link Link object
567 * @arg fwmark addr to fill in with the fwmark
568 *
569 * @return 0 on success or a negative error code
570 */
rtnl_link_ipip_get_fwmark(struct rtnl_link * link,uint32_t * fwmark)571 int rtnl_link_ipip_get_fwmark(struct rtnl_link *link, uint32_t *fwmark)
572 {
573 struct ipip_info *ipip = link->l_info;
574
575 IS_IPIP_LINK_ASSERT(link);
576
577 if (!(ipip->ipip_mask & IPIP_ATTR_FWMARK))
578 return -NLE_NOATTR;
579
580 *fwmark = ipip->fwmark;
581
582 return 0;
583 }
584
ipip_init(void)585 static void _nl_init ipip_init(void)
586 {
587 rtnl_link_register_info(&ipip_info_ops);
588 }
589
ipip_exit(void)590 static void _nl_exit ipip_exit(void)
591 {
592 rtnl_link_unregister_info(&ipip_info_ops);
593 }
594