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