1/*
2 * lib/route/link/ipgre.c        IPGRE 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 ipgre IPGRE
15 * ipgre link module
16 *
17 * @details
18 * \b Link Type Name: "ipgre"
19 *
20 * @route_doc{link_ipgre, IPGRE 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 IPGRE_ATTR_LINK          (1 << 0)
35#define IPGRE_ATTR_IFLAGS        (1 << 1)
36#define IPGRE_ATTR_OFLAGS        (1 << 2)
37#define IPGRE_ATTR_IKEY          (1 << 3)
38#define IPGRE_ATTR_OKEY          (1 << 4)
39#define IPGRE_ATTR_LOCAL         (1 << 5)
40#define IPGRE_ATTR_REMOTE        (1 << 6)
41#define IPGRE_ATTR_TTL           (1 << 7)
42#define IPGRE_ATTR_TOS           (1 << 8)
43#define IPGRE_ATTR_PMTUDISC      (1 << 9)
44
45struct ipgre_info
46{
47	uint8_t    ttl;
48	uint8_t    tos;
49	uint8_t    pmtudisc;
50	uint16_t   iflags;
51	uint16_t   oflags;
52	uint32_t   ikey;
53	uint32_t   okey;
54	uint32_t   link;
55	uint32_t   local;
56	uint32_t   remote;
57	uint32_t   ipgre_mask;
58};
59
60static  struct nla_policy ipgre_policy[IFLA_GRE_MAX + 1] = {
61	[IFLA_GRE_LINK]     = { .type = NLA_U32 },
62	[IFLA_GRE_IFLAGS]   = { .type = NLA_U16 },
63	[IFLA_GRE_OFLAGS]   = { .type = NLA_U16 },
64	[IFLA_GRE_IKEY]     = { .type = NLA_U32 },
65	[IFLA_GRE_OKEY]     = { .type = NLA_U32 },
66	[IFLA_GRE_LOCAL]    = { .type = NLA_U32 },
67	[IFLA_GRE_REMOTE]   = { .type = NLA_U32 },
68	[IFLA_GRE_TTL]      = { .type = NLA_U8 },
69	[IFLA_GRE_TOS]      = { .type = NLA_U8 },
70	[IFLA_GRE_PMTUDISC] = { .type = NLA_U8 },
71};
72
73static int ipgre_alloc(struct rtnl_link *link)
74{
75	struct ipgre_info *ipgre;
76
77	ipgre = calloc(1, sizeof(*ipgre));
78	if (!ipgre)
79		return -NLE_NOMEM;
80
81	link->l_info = ipgre;
82
83	return 0;
84}
85
86static int ipgre_parse(struct rtnl_link *link, struct nlattr *data,
87		       struct nlattr *xstats)
88{
89	struct nlattr *tb[IFLA_IPTUN_MAX + 1];
90	struct ipgre_info *ipgre;
91	int err;
92
93	NL_DBG(3, "Parsing IPGRE link info");
94
95	err = nla_parse_nested(tb, IFLA_GRE_MAX, data, ipgre_policy);
96	if (err < 0)
97		goto errout;
98
99	err = ipgre_alloc(link);
100	if (err < 0)
101		goto errout;
102
103	ipgre = link->l_info;
104
105	if (tb[IFLA_GRE_LINK]) {
106		ipgre->link = nla_get_u32(tb[IFLA_GRE_LINK]);
107		ipgre->ipgre_mask |= IPGRE_ATTR_LINK;
108	}
109
110	if (tb[IFLA_GRE_IFLAGS]) {
111		ipgre->iflags = nla_get_u16(tb[IFLA_GRE_IFLAGS]);
112		ipgre->ipgre_mask |= IPGRE_ATTR_IFLAGS;
113	}
114
115	if (tb[IFLA_GRE_OFLAGS]) {
116		ipgre->oflags = nla_get_u16(tb[IFLA_GRE_OFLAGS]);
117		ipgre->ipgre_mask |= IPGRE_ATTR_OFLAGS;
118	}
119
120	if (tb[IFLA_GRE_IKEY]) {
121		ipgre->ikey = nla_get_u32(tb[IFLA_GRE_IKEY]);
122		ipgre->ipgre_mask |= IPGRE_ATTR_IKEY;
123	}
124
125	if (tb[IFLA_GRE_OKEY]) {
126		ipgre->okey = nla_get_u32(tb[IFLA_GRE_OKEY]);
127		ipgre->ipgre_mask |= IPGRE_ATTR_OKEY;
128	}
129
130	if (tb[IFLA_GRE_LOCAL]) {
131		ipgre->local = nla_get_u32(tb[IFLA_GRE_LOCAL]);
132		ipgre->ipgre_mask |= IPGRE_ATTR_LOCAL;
133	}
134
135	if (tb[IFLA_GRE_LOCAL]) {
136		ipgre->remote = nla_get_u32(tb[IFLA_GRE_LOCAL]);
137		ipgre->ipgre_mask |= IPGRE_ATTR_REMOTE;
138	}
139
140	if (tb[IFLA_GRE_TTL]) {
141		ipgre->ttl = nla_get_u8(tb[IFLA_GRE_TTL]);
142		ipgre->ipgre_mask |= IPGRE_ATTR_TTL;
143	}
144
145	if (tb[IFLA_GRE_TOS]) {
146		ipgre->tos = nla_get_u8(tb[IFLA_GRE_TOS]);
147		ipgre->ipgre_mask |= IPGRE_ATTR_TOS;
148	}
149
150	if (tb[IFLA_GRE_PMTUDISC]) {
151		ipgre->pmtudisc = nla_get_u8(tb[IFLA_GRE_PMTUDISC]);
152		ipgre->ipgre_mask |= IPGRE_ATTR_PMTUDISC;
153	}
154
155	err = 0;
156
157 errout:
158	return err;
159}
160
161static int ipgre_put_attrs(struct nl_msg *msg, struct rtnl_link *link)
162{
163	struct ipgre_info *ipgre = link->l_info;
164	struct nlattr *data;
165
166	data = nla_nest_start(msg, IFLA_INFO_DATA);
167	if (!data)
168		return -NLE_MSGSIZE;
169
170	if (ipgre->ipgre_mask & IPGRE_ATTR_LINK)
171		NLA_PUT_U32(msg, IFLA_GRE_LINK, ipgre->link);
172
173	if (ipgre->ipgre_mask & IFLA_GRE_IFLAGS)
174		NLA_PUT_U16(msg, IFLA_GRE_IFLAGS, ipgre->iflags);
175
176	if (ipgre->ipgre_mask & IFLA_GRE_OFLAGS)
177		NLA_PUT_U16(msg, IFLA_GRE_OFLAGS, ipgre->oflags);
178
179	if (ipgre->ipgre_mask & IPGRE_ATTR_IKEY)
180		NLA_PUT_U32(msg, IFLA_GRE_IKEY, ipgre->ikey);
181
182	if (ipgre->ipgre_mask & IPGRE_ATTR_OKEY)
183		NLA_PUT_U32(msg, IFLA_GRE_OKEY, ipgre->okey);
184
185	if (ipgre->ipgre_mask & IPGRE_ATTR_LOCAL)
186		NLA_PUT_U32(msg, IFLA_GRE_LOCAL, ipgre->local);
187
188	if (ipgre->ipgre_mask & IPGRE_ATTR_REMOTE)
189		NLA_PUT_U32(msg, IFLA_GRE_REMOTE, ipgre->remote);
190
191	if (ipgre->ipgre_mask & IPGRE_ATTR_TTL)
192		NLA_PUT_U8(msg, IFLA_GRE_TTL, ipgre->ttl);
193
194	if (ipgre->ipgre_mask & IPGRE_ATTR_TOS)
195		NLA_PUT_U8(msg, IFLA_GRE_TOS, ipgre->tos);
196
197	if (ipgre->ipgre_mask & IPGRE_ATTR_PMTUDISC)
198		NLA_PUT_U8(msg, IFLA_GRE_PMTUDISC, ipgre->pmtudisc);
199
200	nla_nest_end(msg, data);
201
202 nla_put_failure:
203
204	return 0;
205}
206
207static void ipgre_free(struct rtnl_link *link)
208{
209	struct ipgre_info *ipgre = link->l_info;
210
211	free(ipgre);
212	link->l_info = NULL;
213}
214
215static void ipgre_dump_line(struct rtnl_link *link, struct nl_dump_params *p)
216{
217	nl_dump(p, "ipgre : %s", link->l_name);
218}
219
220static void ipgre_dump_details(struct rtnl_link *link, struct nl_dump_params *p)
221{
222	struct ipgre_info *ipgre = link->l_info;
223	char *name, addr[INET_ADDRSTRLEN];
224
225	if (ipgre->ipgre_mask & IPGRE_ATTR_LINK) {
226		nl_dump(p, "      link ");
227		name = rtnl_link_get_name(link);
228		if (name)
229			nl_dump_line(p, "%s\n", name);
230		else
231			nl_dump_line(p, "%u\n", ipgre->link);
232	}
233
234	if (ipgre->ipgre_mask & IPGRE_ATTR_IFLAGS) {
235		nl_dump(p, "      iflags ");
236		nl_dump_line(p, "%x\n", ipgre->iflags);
237	}
238
239	if (ipgre->ipgre_mask & IPGRE_ATTR_OFLAGS) {
240		nl_dump(p, "      oflags ");
241		nl_dump_line(p, "%x\n", ipgre->oflags);
242	}
243
244	if (ipgre->ipgre_mask & IPGRE_ATTR_IKEY) {
245		nl_dump(p, "    ikey   ");
246		nl_dump_line(p, "%x\n",ipgre->ikey);
247	}
248
249	if (ipgre->ipgre_mask & IPGRE_ATTR_OKEY) {
250		nl_dump(p, "      okey ");
251		nl_dump_line(p, "%x\n", ipgre->okey);
252	}
253
254	if (ipgre->ipgre_mask & IPGRE_ATTR_LOCAL) {
255		nl_dump(p, "      local ");
256		if(inet_ntop(AF_INET, &ipgre->local, addr, sizeof(addr)))
257			nl_dump_line(p, "%s\n", addr);
258		else
259			nl_dump_line(p, "%#x\n", ntohs(ipgre->local));
260	}
261
262	if (ipgre->ipgre_mask & IPGRE_ATTR_REMOTE) {
263		nl_dump(p, "      remote ");
264		if(inet_ntop(AF_INET, &ipgre->remote, addr, sizeof(addr)))
265			nl_dump_line(p, "%s\n", addr);
266		else
267			nl_dump_line(p, "%#x\n", ntohs(ipgre->remote));
268	}
269
270	if (ipgre->ipgre_mask & IPGRE_ATTR_TTL) {
271		nl_dump(p, "      ttl ");
272		nl_dump_line(p, "%u\n", ipgre->ttl);
273	}
274
275	if (ipgre->ipgre_mask & IPGRE_ATTR_TOS) {
276		nl_dump(p, "      tos ");
277		nl_dump_line(p, "%u\n", ipgre->tos);
278	}
279
280	if (ipgre->ipgre_mask & IPGRE_ATTR_PMTUDISC) {
281		nl_dump(p, "      pmtudisc ");
282		nl_dump_line(p, "enabled (%#x)\n", ipgre->pmtudisc);
283	}
284}
285
286static int ipgre_clone(struct rtnl_link *dst, struct rtnl_link *src)
287{
288	struct ipgre_info *ipgre_dst, *ipgre_src = src->l_info;
289	int err;
290
291	dst->l_info = NULL;
292
293	err = rtnl_link_set_type(dst, "gre");
294	if (err < 0)
295		return err;
296
297	ipgre_dst = dst->l_info;
298
299	if (!ipgre_dst || !ipgre_src)
300		BUG();
301
302	memcpy(ipgre_dst, ipgre_src, sizeof(struct ipgre_info));
303
304	return 0;
305}
306
307static struct rtnl_link_info_ops ipgre_info_ops = {
308	.io_name                = "gre",
309	.io_alloc               = ipgre_alloc,
310	.io_parse               = ipgre_parse,
311	.io_dump = {
312		[NL_DUMP_LINE]  = ipgre_dump_line,
313		[NL_DUMP_DETAILS] = ipgre_dump_details,
314	},
315	.io_clone               = ipgre_clone,
316	.io_put_attrs           = ipgre_put_attrs,
317	.io_free                = ipgre_free,
318};
319
320#define IS_IPGRE_LINK_ASSERT(link)                                          \
321        if ((link)->l_info_ops != &ipgre_info_ops) {                        \
322                APPBUG("Link is not a ipgre link. set type \"gre\" first.");\
323                return -NLE_OPNOTSUPP;                                      \
324        }
325
326struct rtnl_link *rtnl_link_ipgre_alloc(void)
327{
328	struct rtnl_link *link;
329	int err;
330
331	link = rtnl_link_alloc();
332	if (!link)
333		return NULL;
334
335	err = rtnl_link_set_type(link, "gre");
336	if (err < 0) {
337		rtnl_link_put(link);
338		return NULL;
339	}
340
341	return link;
342}
343
344/**
345 * Check if link is a IPGRE link
346 * @arg link            Link object
347 *
348 * @return True if link is a IPGRE link, otherwise 0 is returned.
349 */
350int rtnl_link_is_ipgre(struct rtnl_link *link)
351{
352	return link->l_info_ops && !strcmp(link->l_info_ops->io_name, "gre");
353}
354/**
355 * Create a new ipip tunnel device
356 * @arg sock            netlink socket
357 * @arg name            name of the tunnel deviceL
358 *
359 * Creates a new ipip tunnel device in the kernel
360 * @return 0 on success or a negative error code
361 */
362int rtnl_link_ipgre_add(struct nl_sock *sk, const char *name)
363{
364	struct rtnl_link *link;
365	int err;
366
367	link = rtnl_link_ipgre_alloc();
368	if (!link)
369		return -NLE_NOMEM;
370
371	if(name)
372		rtnl_link_set_name(link, name);
373
374	err = rtnl_link_add(sk, link, NLM_F_CREATE);
375	rtnl_link_put(link);
376
377	return err;
378}
379/**
380 * Set IPGRE tunnel interface index
381 * @arg link            Link object
382 * @arg index           interface index
383 *
384 * @return 0 on success or a negative error code
385 */
386int rtnl_link_ipgre_set_link(struct rtnl_link *link,  uint32_t index)
387{
388	struct ipgre_info *ipgre = link->l_info;
389
390	IS_IPGRE_LINK_ASSERT(link);
391
392	ipgre->link = index;
393	ipgre->ipgre_mask |= IPGRE_ATTR_LINK;
394
395	return 0;
396}
397
398/**
399 * Get IPGRE tunnel interface index
400 * @arg link            Link object
401 *
402 * @return interface index
403 */
404uint32_t rtnl_link_ipgre_get_link(struct rtnl_link *link)
405{
406	struct ipgre_info *ipgre = link->l_info;
407
408	IS_IPGRE_LINK_ASSERT(link);
409
410	return ipgre->link;
411}
412
413/**
414 * Set IPGRE tunnel set iflags
415 * @arg link            Link object
416 * @arg iflags          gre iflags
417 *
418 * @return 0 on success or a negative error code
419 */
420int rtnl_link_ipgre_set_iflags(struct rtnl_link *link, uint16_t iflags)
421{
422	struct ipgre_info *ipgre = link->l_info;
423
424	IS_IPGRE_LINK_ASSERT(link);
425
426	ipgre->iflags = iflags;
427	ipgre->ipgre_mask |= IPGRE_ATTR_IFLAGS;
428
429	return 0;
430}
431
432/**
433 * Get IPGRE tunnel iflags
434 * @arg link            Link object
435 *
436 * @return iflags
437 */
438uint16_t rtnl_link_ipgre_get_iflags(struct rtnl_link *link)
439{
440	struct ipgre_info *ipgre = link->l_info;
441
442	IS_IPGRE_LINK_ASSERT(link);
443
444	return ipgre->iflags;
445}
446
447/**
448 * Set IPGRE tunnel set oflags
449 * @arg link            Link object
450 * @arg iflags          gre oflags
451 *
452 * @return 0 on success or a negative error code
453 */
454int rtnl_link_ipgre_set_oflags(struct rtnl_link *link, uint16_t oflags)
455{
456	struct ipgre_info *ipgre = link->l_info;
457
458	IS_IPGRE_LINK_ASSERT(link);
459
460	ipgre->oflags = oflags;
461	ipgre->ipgre_mask |= IPGRE_ATTR_OFLAGS;
462
463	return 0;
464}
465
466/**
467 * Get IPGRE tunnel oflags
468 * @arg link            Link object
469 *
470 * @return oflags
471 */
472uint16_t rtnl_link_ipgre_get_oflags(struct rtnl_link *link)
473{
474	struct ipgre_info *ipgre = link->l_info;
475
476	IS_IPGRE_LINK_ASSERT(link);
477
478	return ipgre->oflags;
479}
480
481/**
482 * Set IPGRE tunnel set ikey
483 * @arg link            Link object
484 * @arg ikey            gre ikey
485 *
486 * @return 0 on success or a negative error code
487 */
488int rtnl_link_ipgre_set_ikey(struct rtnl_link *link, uint32_t ikey)
489{
490	struct ipgre_info *ipgre = link->l_info;
491
492	IS_IPGRE_LINK_ASSERT(link);
493
494	ipgre->ikey = ikey;
495	ipgre->ipgre_mask |= IPGRE_ATTR_IKEY;
496
497	return 0;
498}
499
500/**
501 * Get IPGRE tunnel ikey
502 * @arg link            Link object
503 *
504 * @return ikey
505 */
506uint32_t rtnl_link_ipgre_get_ikey(struct rtnl_link *link)
507{
508	struct ipgre_info *ipgre = link->l_info;
509
510	IS_IPGRE_LINK_ASSERT(link);
511
512	return ipgre->ikey;
513}
514
515/**
516 * Set IPGRE tunnel set okey
517 * @arg link            Link object
518 * @arg okey            gre okey
519 *
520 * @return 0 on success or a negative error code
521 */
522int rtnl_link_ipgre_set_okey(struct rtnl_link *link, uint32_t okey)
523{
524	struct ipgre_info *ipgre = link->l_info;
525
526	IS_IPGRE_LINK_ASSERT(link);
527
528	ipgre->okey = okey;
529	ipgre->ipgre_mask |= IPGRE_ATTR_OKEY;
530
531	return 0;
532}
533
534/**
535 * Get IPGRE tunnel okey
536 * @arg link            Link object
537 *
538 * @return okey value
539 */
540uint32_t rtnl_link_ipgre_get_okey(struct rtnl_link *link)
541{
542	struct ipgre_info *ipgre = link->l_info;
543
544	IS_IPGRE_LINK_ASSERT(link);
545
546	return ipgre->okey;
547}
548
549/**
550 * Set IPGRE tunnel local address
551 * @arg link            Link object
552 * @arg addr            local address
553 *
554 * @return 0 on success or a negative error code
555 */
556int rtnl_link_ipgre_set_local(struct rtnl_link *link, uint32_t addr)
557{
558	struct ipgre_info *ipgre = link->l_info;
559
560	IS_IPGRE_LINK_ASSERT(link);
561
562	ipgre->local = addr;
563	ipgre->ipgre_mask |= IPGRE_ATTR_LOCAL;
564
565	return 0;
566}
567
568/**
569 * Get IPGRE tunnel local address
570 * @arg link            Link object
571 *
572 * @return local address
573 */
574uint32_t rtnl_link_ipgre_get_local(struct rtnl_link *link)
575{
576	struct ipgre_info *ipgre = link->l_info;
577
578	IS_IPGRE_LINK_ASSERT(link);
579
580	return ipgre->local;
581}
582
583/**
584 * Set IPGRE tunnel remote address
585 * @arg link            Link object
586 * @arg remote          remote address
587 *
588 * @return 0 on success or a negative error code
589 */
590int rtnl_link_ipgre_set_remote(struct rtnl_link *link, uint32_t remote)
591{
592	struct ipgre_info *ipgre = link->l_info;
593
594	IS_IPGRE_LINK_ASSERT(link);
595
596	ipgre->remote = remote;
597	ipgre->ipgre_mask |= IPGRE_ATTR_REMOTE;
598
599	return 0;
600}
601
602/**
603 * Get IPGRE tunnel remote address
604 * @arg link            Link object
605 *
606 * @return remote address  on success or a negative error code
607 */
608uint32_t rtnl_link_ipgre_get_remote(struct rtnl_link *link)
609{
610	struct ipgre_info *ipgre = link->l_info;
611
612	IS_IPGRE_LINK_ASSERT(link);
613
614	return ipgre->remote;
615}
616
617/**
618 * Set IPGRE tunnel ttl
619 * @arg link            Link object
620 * @arg ttl             tunnel ttl
621 *
622 * @return 0 on success or a negative error code
623 */
624int rtnl_link_ipgre_set_ttl(struct rtnl_link *link, uint8_t ttl)
625{
626	struct ipgre_info *ipgre = link->l_info;
627
628	IS_IPGRE_LINK_ASSERT(link);
629
630	ipgre->ttl = ttl;
631	ipgre->ipgre_mask |= IPGRE_ATTR_TTL;
632
633	return 0;
634}
635
636/**
637 * Set IPGRE tunnel ttl
638 * @arg link            Link object
639 *
640 * @return ttl value
641 */
642uint8_t rtnl_link_ipgre_get_ttl(struct rtnl_link *link)
643{
644	struct ipgre_info *ipgre = link->l_info;
645
646	IS_IPGRE_LINK_ASSERT(link);
647
648	return ipgre->ttl;
649}
650
651/**
652 * Set IPGRE tunnel tos
653 * @arg link            Link object
654 * @arg tos             tunnel tos
655 *
656 * @return 0 on success or a negative error code
657 */
658int rtnl_link_ipgre_set_tos(struct rtnl_link *link, uint8_t tos)
659{
660	struct ipgre_info *ipgre = link->l_info;
661
662	IS_IPGRE_LINK_ASSERT(link);
663
664	ipgre->tos = tos;
665	ipgre->ipgre_mask |= IPGRE_ATTR_TOS;
666
667	return 0;
668}
669
670/**
671 * Get IPGRE tunnel tos
672 * @arg link            Link object
673 *
674 * @return tos value
675 */
676uint8_t rtnl_link_ipgre_get_tos(struct rtnl_link *link)
677{
678	struct ipgre_info *ipgre = link->l_info;
679
680	IS_IPGRE_LINK_ASSERT(link);
681
682	return ipgre->tos;
683}
684
685/**
686 * Set IPGRE tunnel path MTU discovery
687 * @arg link            Link object
688 * @arg pmtudisc        path MTU discovery
689 *
690 * @return 0 on success or a negative error code
691 */
692int rtnl_link_ipgre_set_pmtudisc(struct rtnl_link *link, uint8_t pmtudisc)
693{
694	struct ipgre_info *ipgre = link->l_info;
695
696	IS_IPGRE_LINK_ASSERT(link);
697
698	ipgre->pmtudisc = pmtudisc;
699	ipgre->ipgre_mask |= IPGRE_ATTR_PMTUDISC;
700
701	return 0;
702}
703
704/**
705 * Get IPGRE path MTU discovery
706 * @arg link            Link object
707 *
708 * @return pmtudisc value
709 */
710uint8_t rtnl_link_get_pmtudisc(struct rtnl_link *link)
711{
712	struct ipgre_info *ipgre = link->l_info;
713
714	IS_IPGRE_LINK_ASSERT(link);
715
716	return ipgre->pmtudisc;
717}
718
719static void __init ipgre_init(void)
720{
721	rtnl_link_register_info(&ipgre_info_ops);
722}
723
724static void __exit ipgre_exit(void)
725{
726	rtnl_link_unregister_info(&ipgre_info_ops);
727}
728