Home | History | Annotate | Download | only in link
      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 (at) 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 
     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 
     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 
    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 
    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 
    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 
    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 
    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 
    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  */
    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  */
    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  */
    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  */
    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  */
    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  */
    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  */
    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  */
    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  */
    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  */
    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  */
    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  */
    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  */
    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  */
    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 
    520 static void __init ipip_init(void)
    521 {
    522 	rtnl_link_register_info(&ipip_info_ops);
    523 }
    524 
    525 static void __exit ipip_exit(void)
    526 {
    527 	rtnl_link_unregister_info(&ipip_info_ops);
    528 }
    529