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