xref: /aosp_15_r20/external/libnl/lib/route/link/ip6vti.c (revision 4dc78e53d49367fa8e61b07018507c90983a077d)
1 /* SPDX-License-Identifier: LGPL-2.1-only */
2 
3 /**
4  * @ingroup link
5  * @defgroup ip6vti IP6VTI
6  * ip6vti link module
7  *
8  * @details
9  * \b Link Type Name: "vti6"
10  *
11  * @route_doc{link_ip6vti, IP6VTI Documentation}
12  *
13  * @{
14  */
15 
16 #include "nl-default.h"
17 
18 #include <linux/if_tunnel.h>
19 
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/ip6vti.h>
26 
27 #include "nl-route.h"
28 #include "link-api.h"
29 
30 #define IP6VTI_ATTR_LINK      (1 << 0)
31 #define IP6VTI_ATTR_IKEY      (1 << 1)
32 #define IP6VTI_ATTR_OKEY      (1 << 2)
33 #define IP6VTI_ATTR_LOCAL     (1 << 3)
34 #define IP6VTI_ATTR_REMOTE    (1 << 4)
35 #define IP6VTI_ATTR_FWMARK    (1 << 5)
36 
37 struct ip6vti_info
38 {
39 	uint32_t            link;
40 	uint32_t            ikey;
41 	uint32_t            okey;
42 	struct in6_addr     local;
43 	struct in6_addr     remote;
44 	uint32_t            fwmark;
45 	uint32_t            ip6vti_mask;
46 };
47 
48 static  struct nla_policy ip6vti_policy[IFLA_VTI_MAX + 1] = {
49 	[IFLA_VTI_LINK]     = { .type = NLA_U32 },
50 	[IFLA_VTI_IKEY]     = { .type = NLA_U32 },
51 	[IFLA_VTI_OKEY]     = { .type = NLA_U32 },
52 	[IFLA_VTI_LOCAL]    = { .minlen = sizeof(struct in6_addr) },
53 	[IFLA_VTI_REMOTE]   = { .minlen = sizeof(struct in6_addr) },
54 	[IFLA_VTI_FWMARK]   = { .type = NLA_U32 },
55 };
56 
ip6vti_alloc(struct rtnl_link * link)57 static int ip6vti_alloc(struct rtnl_link *link)
58 {
59 	struct ip6vti_info *ip6vti;
60 
61 	if (link->l_info)
62 		memset(link->l_info, 0, sizeof(*ip6vti));
63 	else {
64 		ip6vti = calloc(1, sizeof(*ip6vti));
65 		if (!ip6vti)
66 			return -NLE_NOMEM;
67 
68 		link->l_info = ip6vti;
69 	}
70 
71 	return 0;
72 }
73 
ip6vti_parse(struct rtnl_link * link,struct nlattr * data,struct nlattr * xstats)74 static int ip6vti_parse(struct rtnl_link *link, struct nlattr *data,
75 		        struct nlattr *xstats)
76 {
77 	struct nlattr *tb[IFLA_VTI_MAX + 1];
78 	struct ip6vti_info *ip6vti;
79 	int err;
80 
81 	NL_DBG(3, "Parsing IP6VTI link info\n");
82 
83 	err = nla_parse_nested(tb, IFLA_VTI_MAX, data, ip6vti_policy);
84 	if (err < 0)
85 		goto errout;
86 
87 	err = ip6vti_alloc(link);
88 	if (err < 0)
89 		goto errout;
90 
91 	ip6vti = link->l_info;
92 
93 	if (tb[IFLA_VTI_LINK]) {
94 		ip6vti->link = nla_get_u32(tb[IFLA_VTI_LINK]);
95 		ip6vti->ip6vti_mask |= IP6VTI_ATTR_LINK;
96 	}
97 
98 	if (tb[IFLA_VTI_IKEY]) {
99 		ip6vti->ikey = nla_get_u32(tb[IFLA_VTI_IKEY]);
100 		ip6vti->ip6vti_mask |= IP6VTI_ATTR_IKEY;
101 	}
102 
103 	if (tb[IFLA_VTI_OKEY]) {
104 		ip6vti->okey = nla_get_u32(tb[IFLA_VTI_OKEY]);
105 		ip6vti->ip6vti_mask |= IP6VTI_ATTR_OKEY;
106 	}
107 
108 	if (tb[IFLA_VTI_LOCAL]) {
109 		nla_memcpy(&ip6vti->local, tb[IFLA_VTI_LOCAL], sizeof(struct in6_addr));
110 		ip6vti->ip6vti_mask |= IP6VTI_ATTR_LOCAL;
111 	}
112 
113 	if (tb[IFLA_VTI_REMOTE]) {
114 		nla_memcpy(&ip6vti->remote, tb[IFLA_VTI_REMOTE], sizeof(struct in6_addr));
115 		ip6vti->ip6vti_mask |= IP6VTI_ATTR_REMOTE;
116 	}
117 
118 	if (tb[IFLA_VTI_FWMARK]) {
119 		ip6vti->fwmark = nla_get_u32(tb[IFLA_VTI_FWMARK]);
120 		ip6vti->ip6vti_mask |= IP6VTI_ATTR_FWMARK;
121 	}
122 
123 	err = 0;
124 
125  errout:
126 	return err;
127 }
128 
ip6vti_put_attrs(struct nl_msg * msg,struct rtnl_link * link)129 static int ip6vti_put_attrs(struct nl_msg *msg, struct rtnl_link *link)
130 {
131 	struct ip6vti_info *ip6vti = link->l_info;
132 	struct nlattr *data;
133 
134 	data = nla_nest_start(msg, IFLA_INFO_DATA);
135 	if (!data)
136 		return -NLE_MSGSIZE;
137 
138 	if (ip6vti->ip6vti_mask & IP6VTI_ATTR_LINK)
139 		NLA_PUT_U32(msg, IFLA_VTI_LINK, ip6vti->link);
140 
141 	if (ip6vti->ip6vti_mask & IP6VTI_ATTR_IKEY)
142 		NLA_PUT_U32(msg, IFLA_VTI_IKEY, ip6vti->ikey);
143 
144 	if (ip6vti->ip6vti_mask & IP6VTI_ATTR_OKEY)
145 		NLA_PUT_U32(msg, IFLA_VTI_OKEY, ip6vti->okey);
146 
147 	if (ip6vti->ip6vti_mask & IP6VTI_ATTR_LOCAL)
148 		NLA_PUT(msg, IFLA_VTI_LOCAL, sizeof(struct in6_addr), &ip6vti->local);
149 
150 	if (ip6vti->ip6vti_mask & IP6VTI_ATTR_REMOTE)
151 		NLA_PUT(msg, IFLA_VTI_REMOTE, sizeof(struct in6_addr), &ip6vti->remote);
152 
153 	if (ip6vti->ip6vti_mask & IP6VTI_ATTR_FWMARK)
154 		NLA_PUT_U32(msg, IFLA_VTI_FWMARK, ip6vti->fwmark);
155 
156 	nla_nest_end(msg, data);
157 
158 nla_put_failure:
159 
160 	return 0;
161 }
162 
ip6vti_free(struct rtnl_link * link)163 static void ip6vti_free(struct rtnl_link *link)
164 {
165 	struct ip6vti_info *ip6vti = link->l_info;
166 
167 	free(ip6vti);
168 	link->l_info = NULL;
169 }
170 
ip6vti_dump_line(struct rtnl_link * link,struct nl_dump_params * p)171 static void ip6vti_dump_line(struct rtnl_link *link, struct nl_dump_params *p)
172 {
173 	nl_dump(p, "ip6vti : %s", link->l_name);
174 }
175 
ip6vti_dump_details(struct rtnl_link * link,struct nl_dump_params * p)176 static void ip6vti_dump_details(struct rtnl_link *link, struct nl_dump_params *p)
177 {
178 	struct ip6vti_info *ip6vti = link->l_info;
179 	char *name;
180 	char addr[INET6_ADDRSTRLEN];
181 
182 	if (ip6vti->ip6vti_mask & IP6VTI_ATTR_LINK) {
183 		nl_dump(p, "      link ");
184 		name = rtnl_link_get_name(link);
185 		if (name)
186 			nl_dump_line(p, "%s\n", name);
187 		else
188 			nl_dump_line(p, "%u\n", ip6vti->link);
189 	}
190 
191 	if (ip6vti->ip6vti_mask & IP6VTI_ATTR_IKEY) {
192 		nl_dump(p, "      ikey   ");
193 		nl_dump_line(p, "%x\n",ip6vti->ikey);
194 	}
195 
196 	if (ip6vti->ip6vti_mask & IP6VTI_ATTR_OKEY) {
197 		nl_dump(p, "      okey ");
198 		nl_dump_line(p, "%x\n", ip6vti->okey);
199 	}
200 
201 	if (ip6vti->ip6vti_mask & IP6VTI_ATTR_LOCAL) {
202 		nl_dump(p, "      local ");
203 		nl_dump_line(p, "%s\n",
204 			     _nl_inet_ntop(AF_INET6, &ip6vti->local, addr));
205 	}
206 
207 	if (ip6vti->ip6vti_mask & IP6VTI_ATTR_REMOTE) {
208 		nl_dump(p, "      remote ");
209 		nl_dump_line(p, "%s\n",
210 			     _nl_inet_ntop(AF_INET6, &ip6vti->remote, addr));
211 	}
212 
213 	if (ip6vti->ip6vti_mask & IP6VTI_ATTR_FWMARK) {
214 		nl_dump(p, "      fwmark ");
215 		nl_dump_line(p, "%x\n", ip6vti->fwmark);
216 	}
217 }
218 
ip6vti_clone(struct rtnl_link * dst,struct rtnl_link * src)219 static int ip6vti_clone(struct rtnl_link *dst, struct rtnl_link *src)
220 {
221 	struct ip6vti_info *ip6vti_dst, *ip6vti_src = src->l_info;
222 	int err;
223 
224 	dst->l_info = NULL;
225 
226 	err = rtnl_link_set_type(dst, "vti6");
227 	if (err < 0)
228 		return err;
229 
230 	ip6vti_dst = dst->l_info;
231 
232 	if (!ip6vti_dst || !ip6vti_src)
233 		BUG();
234 
235 	memcpy(ip6vti_dst, ip6vti_src, sizeof(struct ip6vti_info));
236 
237 	return 0;
238 }
239 
240 static struct rtnl_link_info_ops ip6vti_info_ops = {
241 	.io_name                = "vti6",
242 	.io_alloc               = ip6vti_alloc,
243 	.io_parse               = ip6vti_parse,
244 	.io_dump = {
245 		[NL_DUMP_LINE]  = ip6vti_dump_line,
246 		[NL_DUMP_DETAILS] = ip6vti_dump_details,
247 	},
248 	.io_clone               = ip6vti_clone,
249 	.io_put_attrs           = ip6vti_put_attrs,
250 	.io_free                = ip6vti_free,
251 };
252 
253 #define IS_IP6VTI_LINK_ASSERT(link)                                            \
254         if ((link)->l_info_ops != &ip6vti_info_ops) {                          \
255                 APPBUG("Link is not a ip6vti link. set type \"vti6\" first."); \
256                 return -NLE_OPNOTSUPP;                                         \
257         }
258 
259 #define HAS_IP6VTI_ATTR_ASSERT(ip6vti,attr)                                    \
260         if (!((ip6vti)->ip6vti_mask & (attr)))                                 \
261                 return -NLE_NOATTR;
262 
rtnl_link_ip6vti_alloc(void)263 struct rtnl_link *rtnl_link_ip6vti_alloc(void)
264 {
265 	struct rtnl_link *link;
266 	int err;
267 
268 	link = rtnl_link_alloc();
269 	if (!link)
270 		return NULL;
271 
272 	err = rtnl_link_set_type(link, "vti6");
273 	if (err < 0) {
274 		rtnl_link_put(link);
275 		return NULL;
276 	}
277 
278 	return link;
279 }
280 
281 /**
282  * Check if link is a IP6VTI link
283  * @arg link            Link object
284  *
285  * @return True if link is a IP6VTI link, otherwise 0 is returned.
286  */
rtnl_link_is_ip6vti(struct rtnl_link * link)287 int rtnl_link_is_ip6vti(struct rtnl_link *link)
288 {
289 	return link->l_info_ops && !strcmp(link->l_info_ops->io_name, "vti6");
290 }
291 /**
292  * Create a new vti6 tunnel device
293  * @arg sock            netlink socket
294  * @arg name            name of the tunnel deviceL
295  *
296  * Creates a new vti6 tunnel device in the kernel
297  * @return 0 on success or a negative error code
298  */
rtnl_link_ip6vti_add(struct nl_sock * sk,const char * name)299 int rtnl_link_ip6vti_add(struct nl_sock *sk, const char *name)
300 {
301 	struct rtnl_link *link;
302 	int err;
303 
304 	link = rtnl_link_ip6vti_alloc();
305 	if (!link)
306 		return -NLE_NOMEM;
307 
308 	if(name)
309 		rtnl_link_set_name(link, name);
310 
311 	err = rtnl_link_add(sk, link, NLM_F_CREATE);
312 	rtnl_link_put(link);
313 
314 	return err;
315 }
316 /**
317  * Set IP6VTI tunnel interface index
318  * @arg link            Link object
319  * @arg index           interface index
320  *
321  * @return 0 on success or a negative error code
322  */
rtnl_link_ip6vti_set_link(struct rtnl_link * link,uint32_t index)323 int rtnl_link_ip6vti_set_link(struct rtnl_link *link, uint32_t index)
324 {
325 	struct ip6vti_info *ip6vti = link->l_info;
326 
327 	IS_IP6VTI_LINK_ASSERT(link);
328 
329 	ip6vti->link = index;
330 	ip6vti->ip6vti_mask |= IP6VTI_ATTR_LINK;
331 
332 	return 0;
333 }
334 
335 /**
336  * Get IP6VTI tunnel interface index
337  * @arg link            Link object
338  * @arg index           addr to fill in with the interface index
339  *
340  * @return 0 on success or a negative error code
341  */
rtnl_link_ip6vti_get_link(struct rtnl_link * link,uint32_t * index)342 int rtnl_link_ip6vti_get_link(struct rtnl_link *link, uint32_t *index)
343 {
344 	struct ip6vti_info *ip6vti = link->l_info;
345 
346 	IS_IP6VTI_LINK_ASSERT(link);
347 
348 	HAS_IP6VTI_ATTR_ASSERT(ip6vti, IP6VTI_ATTR_LINK);
349 
350 	*index = ip6vti->link;
351 
352 	return 0;
353 }
354 
355 /**
356  * Set IP6VTI tunnel set ikey
357  * @arg link            Link object
358  * @arg ikey            gre ikey
359  *
360  * @return 0 on success or a negative error code
361  */
rtnl_link_ip6vti_set_ikey(struct rtnl_link * link,uint32_t ikey)362 int rtnl_link_ip6vti_set_ikey(struct rtnl_link *link, uint32_t ikey)
363 {
364 	struct ip6vti_info *ip6vti = link->l_info;
365 
366 	IS_IP6VTI_LINK_ASSERT(link);
367 
368 	ip6vti->ikey = ikey;
369 	ip6vti->ip6vti_mask |= IP6VTI_ATTR_IKEY;
370 
371 	return 0;
372 }
373 
374 /**
375  * Get IP6VTI tunnel ikey
376  * @arg link            Link object
377  * @arg ikey            addr to fill in with the ikey
378  *
379  * @return 0 on success or a negative error code
380  */
rtnl_link_ip6vti_get_ikey(struct rtnl_link * link,uint32_t * ikey)381 int rtnl_link_ip6vti_get_ikey(struct rtnl_link *link, uint32_t *ikey)
382 {
383 	struct ip6vti_info *ip6vti = link->l_info;
384 
385 	IS_IP6VTI_LINK_ASSERT(link);
386 
387 	HAS_IP6VTI_ATTR_ASSERT(ip6vti, IP6VTI_ATTR_IKEY);
388 
389 	*ikey = ip6vti->ikey;
390 
391 	return 0;
392 }
393 
394 /**
395  * Set IP6VTI tunnel set okey
396  * @arg link            Link object
397  * @arg okey            gre okey
398  *
399  * @return 0 on success or a negative error code
400  */
rtnl_link_ip6vti_set_okey(struct rtnl_link * link,uint32_t okey)401 int rtnl_link_ip6vti_set_okey(struct rtnl_link *link, uint32_t okey)
402 {
403 	struct ip6vti_info *ip6vti = link->l_info;
404 
405 	IS_IP6VTI_LINK_ASSERT(link);
406 
407 	ip6vti->okey = okey;
408 	ip6vti->ip6vti_mask |= IP6VTI_ATTR_OKEY;
409 
410 	return 0;
411 }
412 
413 /**
414  * Get IP6VTI tunnel okey
415  * @arg link            Link object
416  * @arg okey            addr to fill in with the okey
417  *
418  * @return 0 on success or a negative error code
419  */
rtnl_link_ip6vti_get_okey(struct rtnl_link * link,uint32_t * okey)420 int rtnl_link_ip6vti_get_okey(struct rtnl_link *link, uint32_t *okey)
421 {
422 	struct ip6vti_info *ip6vti = link->l_info;
423 
424 	IS_IP6VTI_LINK_ASSERT(link);
425 
426 	HAS_IP6VTI_ATTR_ASSERT(ip6vti, IP6VTI_ATTR_OKEY);
427 
428 	*okey = ip6vti->okey;
429 
430 	return 0;
431 }
432 
433 /**
434  * Set IP6VTI tunnel local address
435  * @arg link            Link object
436  * @arg local           local address
437  *
438  * @return 0 on success or a negative error code
439  */
rtnl_link_ip6vti_set_local(struct rtnl_link * link,struct in6_addr * local)440 int rtnl_link_ip6vti_set_local(struct rtnl_link *link, struct in6_addr *local)
441 {
442 	struct ip6vti_info *ip6vti = link->l_info;
443 
444 	IS_IP6VTI_LINK_ASSERT(link);
445 
446 	memcpy(&ip6vti->local, local, sizeof(struct in6_addr));
447 	ip6vti->ip6vti_mask |= IP6VTI_ATTR_LOCAL;
448 
449 	return 0;
450 }
451 
452 /**
453  * Get IP6VTI tunnel local address
454  * @arg link            Link object
455  * @arg local           addr to fill in with remote address
456  *
457  * @return 0 on success or a negative error code
458  */
rtnl_link_ip6vti_get_local(struct rtnl_link * link,struct in6_addr * local)459 int rtnl_link_ip6vti_get_local(struct rtnl_link *link, struct in6_addr *local)
460 {
461 	struct ip6vti_info *ip6vti = link->l_info;
462 
463 	IS_IP6VTI_LINK_ASSERT(link);
464 
465 	HAS_IP6VTI_ATTR_ASSERT(ip6vti, IP6VTI_ATTR_LOCAL);
466 
467 	memcpy(local, &ip6vti->local, sizeof(struct in6_addr));
468 
469 	return 0;
470 }
471 
472 /**
473  * Set IP6VTI tunnel remote address
474  * @arg link            Link object
475  * @arg remote          remote address
476  *
477  * @return 0 on success or a negative error code
478  */
rtnl_link_ip6vti_set_remote(struct rtnl_link * link,struct in6_addr * remote)479 int rtnl_link_ip6vti_set_remote(struct rtnl_link *link, struct in6_addr *remote)
480 {
481 	struct ip6vti_info *ip6vti = link->l_info;
482 
483 	IS_IP6VTI_LINK_ASSERT(link);
484 
485 	memcpy(&ip6vti->remote, remote, sizeof(struct in6_addr));
486 	ip6vti->ip6vti_mask |= IP6VTI_ATTR_REMOTE;
487 
488 	return 0;
489 }
490 
491 /**
492  * Get IP6VTI tunnel remote address
493  * @arg link            Link object
494  * @arg remote          addr to fill in with remote address
495  *
496  * @return 0 on success or a negative error code
497  */
rtnl_link_ip6vti_get_remote(struct rtnl_link * link,struct in6_addr * remote)498 int rtnl_link_ip6vti_get_remote(struct rtnl_link *link, struct in6_addr *remote)
499 {
500 	struct ip6vti_info *ip6vti = link->l_info;
501 
502 	IS_IP6VTI_LINK_ASSERT(link);
503 
504 	HAS_IP6VTI_ATTR_ASSERT(ip6vti, IP6VTI_ATTR_REMOTE);
505 
506 	memcpy(remote, &ip6vti->remote, sizeof(struct in6_addr));
507 
508 	return 0;
509 }
510 
511 /**
512  * Set IP6VTI tunnel fwmark
513  * @arg link            Link object
514  * @arg fwmark          fwmark
515  *
516  * @return 0 on success or a negative error code
517  */
rtnl_link_ip6vti_set_fwmark(struct rtnl_link * link,uint32_t fwmark)518 int rtnl_link_ip6vti_set_fwmark(struct rtnl_link *link, uint32_t fwmark)
519 {
520 	struct ip6vti_info *ip6vti = link->l_info;
521 
522 	IS_IP6VTI_LINK_ASSERT(link);
523 
524 	ip6vti->fwmark = fwmark;
525 	ip6vti->ip6vti_mask |= IP6VTI_ATTR_FWMARK;
526 
527 	return 0;
528 }
529 
530 /**
531  * Get IP6VTI tunnel fwmark
532  * @arg link            Link object
533  * @arg fwmark          addr to fill in with the fwmark
534  *
535  * @return 0 on success or a negative error code
536  */
rtnl_link_ip6vti_get_fwmark(struct rtnl_link * link,uint32_t * fwmark)537 int rtnl_link_ip6vti_get_fwmark(struct rtnl_link *link, uint32_t *fwmark)
538 {
539 	struct ip6vti_info *ip6vti = link->l_info;
540 
541 	IS_IP6VTI_LINK_ASSERT(link);
542 
543 	HAS_IP6VTI_ATTR_ASSERT(ip6vti, IP6VTI_ATTR_FWMARK);
544 
545 	*fwmark = ip6vti->fwmark;
546 
547 	return 0;
548 }
549 
ip6vti_init(void)550 static void _nl_init ip6vti_init(void)
551 {
552 	rtnl_link_register_info(&ip6vti_info_ops);
553 }
554 
ip6vti_exit(void)555 static void _nl_exit ip6vti_exit(void)
556 {
557 	rtnl_link_unregister_info(&ip6vti_info_ops);
558 }
559