xref: /aosp_15_r20/external/libnl/lib/route/link/ipip.c (revision 4dc78e53d49367fa8e61b07018507c90983a077d)
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