Home | History | Annotate | Download | only in link
      1  /*
      2  * lib/route/link/ipvti.c	 IPVTI 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 ipvti IPVTI
     15  * ipvti link module
     16  *
     17  * @details
     18  * \b Link Type Name: "ipvti"
     19  *
     20  * @route_doc{link_ipvti, IPVTI 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 IPVTI_ATTR_LINK		 (1 << 0)
     35 #define IPVTI_ATTR_IKEY		 (1 << 1)
     36 #define IPVTI_ATTR_OKEY		 (1 << 2)
     37 #define IPVTI_ATTR_LOCAL	 (1 << 3)
     38 #define IPVTI_ATTR_REMOTE	 (1 << 4)
     39 
     40 struct ipvti_info
     41 {
     42 	uint32_t   link;
     43 	uint32_t   ikey;
     44 	uint32_t   okey;
     45 	uint32_t   local;
     46 	uint32_t   remote;
     47 	uint32_t   ipvti_mask;
     48 };
     49 
     50 static	struct nla_policy ipvti_policy[IFLA_GRE_MAX + 1] = {
     51 	[IFLA_VTI_LINK]     = { .type = NLA_U32 },
     52 	[IFLA_VTI_IKEY]     = { .type = NLA_U32 },
     53 	[IFLA_VTI_OKEY]     = { .type = NLA_U32 },
     54 	[IFLA_VTI_LOCAL]    = { .type = NLA_U32 },
     55 	[IFLA_VTI_REMOTE]   = { .type = NLA_U32 },
     56 };
     57 
     58 static int ipvti_alloc(struct rtnl_link *link)
     59 {
     60 	struct ipvti_info *ipvti;
     61 
     62 	ipvti = calloc(1, sizeof(*ipvti));
     63 	if (!ipvti)
     64 		return -NLE_NOMEM;
     65 
     66 	link->l_info = ipvti;
     67 
     68 	return 0;
     69 }
     70 
     71 static int ipvti_parse(struct rtnl_link *link, struct nlattr *data,
     72 		       struct nlattr *xstats)
     73 {
     74 	struct nlattr *tb[IFLA_IPTUN_MAX + 1];
     75 	struct ipvti_info *ipvti;
     76 	int err;
     77 
     78 	NL_DBG(3, "Parsing IPVTI link info");
     79 
     80 	err = nla_parse_nested(tb, IFLA_GRE_MAX, data, ipvti_policy);
     81 	if (err < 0)
     82 		goto errout;
     83 
     84 	err = ipvti_alloc(link);
     85 	if (err < 0)
     86 		goto errout;
     87 
     88 	ipvti = link->l_info;
     89 
     90 	if (tb[IFLA_VTI_LINK]) {
     91 		ipvti->link = nla_get_u32(tb[IFLA_VTI_LINK]);
     92 		ipvti->ipvti_mask |= IPVTI_ATTR_LINK;
     93 	}
     94 
     95 	if (tb[IFLA_VTI_IKEY]) {
     96 		ipvti->ikey = nla_get_u32(tb[IFLA_VTI_IKEY]);
     97 		ipvti->ipvti_mask |= IPVTI_ATTR_IKEY;
     98 	}
     99 
    100 	if (tb[IFLA_VTI_OKEY]) {
    101 		ipvti->okey = nla_get_u32(tb[IFLA_VTI_OKEY]);
    102 		ipvti->ipvti_mask |= IPVTI_ATTR_OKEY;
    103 	}
    104 
    105 	if (tb[IFLA_VTI_LOCAL]) {
    106 		ipvti->local = nla_get_u32(tb[IFLA_VTI_LOCAL]);
    107 		ipvti->ipvti_mask |= IPVTI_ATTR_LOCAL;
    108 	}
    109 
    110 	if (tb[IFLA_VTI_REMOTE]) {
    111 		ipvti->remote = nla_get_u32(tb[IFLA_VTI_REMOTE]);
    112 		ipvti->ipvti_mask |= IPVTI_ATTR_REMOTE;
    113 	}
    114 
    115 	err = 0;
    116 
    117  errout:
    118 	return err;
    119 }
    120 
    121 static int ipvti_put_attrs(struct nl_msg *msg, struct rtnl_link *link)
    122 {
    123 	struct ipvti_info *ipvti = link->l_info;
    124 	struct nlattr *data;
    125 
    126 	data = nla_nest_start(msg, IFLA_INFO_DATA);
    127 	if (!data)
    128 		return -NLE_MSGSIZE;
    129 
    130 	if (ipvti->ipvti_mask & IPVTI_ATTR_LINK)
    131 		NLA_PUT_U32(msg, IFLA_VTI_LINK, ipvti->link);
    132 
    133 	if (ipvti->ipvti_mask & IPVTI_ATTR_IKEY)
    134 		NLA_PUT_U32(msg, IFLA_VTI_IKEY, ipvti->ikey);
    135 
    136 	if (ipvti->ipvti_mask & IFLA_VTI_IKEY)
    137 		NLA_PUT_U32(msg, IFLA_VTI_OKEY, ipvti->okey);
    138 
    139 	if (ipvti->ipvti_mask & IPVTI_ATTR_LOCAL)
    140 		NLA_PUT_U32(msg, IFLA_VTI_LOCAL, ipvti->local);
    141 
    142 	if (ipvti->ipvti_mask & IPVTI_ATTR_REMOTE)
    143 		NLA_PUT_U32(msg, IFLA_VTI_REMOTE, ipvti->remote);
    144 
    145 	nla_nest_end(msg, data);
    146 
    147 nla_put_failure:
    148 
    149 	return 0;
    150 }
    151 
    152 static void ipvti_free(struct rtnl_link *link)
    153 {
    154 	struct ipvti_info *ipvti = link->l_info;
    155 
    156 	free(ipvti);
    157 	link->l_info = NULL;
    158 }
    159 
    160 static void ipvti_dump_line(struct rtnl_link *link, struct nl_dump_params *p)
    161 {
    162 	nl_dump(p, "ipvti : %s", link->l_name);
    163 }
    164 
    165 static void ipvti_dump_details(struct rtnl_link *link, struct nl_dump_params *p)
    166 {
    167 	struct ipvti_info *ipvti = link->l_info;
    168 	char *name, addr[INET_ADDRSTRLEN];
    169 
    170 	if (ipvti->ipvti_mask & IPVTI_ATTR_LINK) {
    171 		nl_dump(p, "      link ");
    172 		name = rtnl_link_get_name(link);
    173 		if (name)
    174 			nl_dump_line(p, "%s\n", name);
    175 		else
    176 			nl_dump_line(p, "%u\n", ipvti->link);
    177 	}
    178 
    179 	if (ipvti->ipvti_mask & IPVTI_ATTR_IKEY) {
    180 		nl_dump(p, "      ikey   ");
    181 		nl_dump_line(p, "%x\n",ipvti->ikey);
    182 	}
    183 
    184 	if (ipvti->ipvti_mask & IPVTI_ATTR_OKEY) {
    185 		nl_dump(p, "      okey ");
    186 		nl_dump_line(p, "%x\n", ipvti->okey);
    187 	}
    188 
    189 	if (ipvti->ipvti_mask & IPVTI_ATTR_LOCAL) {
    190 		nl_dump(p, "      local ");
    191 		if(inet_ntop(AF_INET, &ipvti->local, addr, sizeof(addr)))
    192 			nl_dump_line(p, "%s\n", addr);
    193 		else
    194 			nl_dump_line(p, "%#x\n", ntohs(ipvti->local));
    195 	}
    196 
    197 	if (ipvti->ipvti_mask & IPVTI_ATTR_REMOTE) {
    198 		nl_dump(p, "      remote ");
    199 		if(inet_ntop(AF_INET, &ipvti->remote, addr, sizeof(addr)))
    200 			nl_dump_line(p, "%s\n", addr);
    201 		else
    202 			nl_dump_line(p, "%#x\n", ntohs(ipvti->remote));
    203 	}
    204 }
    205 
    206 static int ipvti_clone(struct rtnl_link *dst, struct rtnl_link *src)
    207 {
    208 	struct ipvti_info *ipvti_dst, *ipvti_src = src->l_info;
    209 	int err;
    210 
    211 	dst->l_info = NULL;
    212 
    213 	err = rtnl_link_set_type(dst, "vti");
    214 	if (err < 0)
    215 		return err;
    216 
    217 	ipvti_dst = dst->l_info;
    218 
    219 	if (!ipvti_dst || !ipvti_src)
    220 		BUG();
    221 
    222 	memcpy(ipvti_dst, ipvti_src, sizeof(struct ipvti_info));
    223 
    224 	return 0;
    225 }
    226 
    227 static struct rtnl_link_info_ops ipvti_info_ops = {
    228 	.io_name                = "vti",
    229 	.io_alloc               = ipvti_alloc,
    230 	.io_parse               = ipvti_parse,
    231 	.io_dump = {
    232 		[NL_DUMP_LINE]  = ipvti_dump_line,
    233 		[NL_DUMP_DETAILS] = ipvti_dump_details,
    234 	},
    235 	.io_clone               = ipvti_clone,
    236 	.io_put_attrs           = ipvti_put_attrs,
    237 	.io_free                = ipvti_free,
    238 };
    239 
    240 #define IS_IPVTI_LINK_ASSERT(link)                                          \
    241         if ((link)->l_info_ops != &ipvti_info_ops) {                        \
    242                 APPBUG("Link is not a ipvti link. set type \vti\" first."); \
    243                 return -NLE_OPNOTSUPP;                                      \
    244         }
    245 
    246 struct rtnl_link *rtnl_link_ipvti_alloc(void)
    247 {
    248 	struct rtnl_link *link;
    249 	int err;
    250 
    251 	link = rtnl_link_alloc();
    252 	if (!link)
    253 		return NULL;
    254 
    255 	err = rtnl_link_set_type(link, "vti");
    256 	if (err < 0) {
    257 		rtnl_link_put(link);
    258 		return NULL;
    259 	}
    260 
    261 	return link;
    262 }
    263 
    264 /**
    265  * Check if link is a IPVTI link
    266  * @arg link            Link object
    267  *
    268  * @return True if link is a IPVTI link, otherwise 0 is returned.
    269  */
    270 int rtnl_link_is_ipvti(struct rtnl_link *link)
    271 {
    272 	return link->l_info_ops && !strcmp(link->l_info_ops->io_name, "vti");
    273 }
    274 /**
    275  * Create a new ipvti tunnel device
    276  * @arg sock            netlink socket
    277  * @arg name            name of the tunnel deviceL
    278  *
    279  * Creates a new ipvti tunnel device in the kernel
    280  * @return 0 on success or a negative error code
    281  */
    282 int rtnl_link_ipvti_add(struct nl_sock *sk, const char *name)
    283 {
    284 	struct rtnl_link *link;
    285 	int err;
    286 
    287 	link = rtnl_link_ipvti_alloc();
    288 	if (!link)
    289 		return -NLE_NOMEM;
    290 
    291 	if(name)
    292 		rtnl_link_set_name(link, name);
    293 
    294 	err = rtnl_link_add(sk, link, NLM_F_CREATE);
    295 	rtnl_link_put(link);
    296 
    297 	return err;
    298 }
    299 /**
    300  * Set IPVTI tunnel interface index
    301  * @arg link            Link object
    302  * @arg index           interface index
    303  *
    304  * @return 0 on success or a negative error code
    305  */
    306 int rtnl_link_ipvti_set_link(struct rtnl_link *link, uint32_t index)
    307 {
    308 	struct ipvti_info *ipvti = link->l_info;
    309 
    310 	IS_IPVTI_LINK_ASSERT(link);
    311 
    312 	ipvti->link = index;
    313 	ipvti->ipvti_mask |= IPVTI_ATTR_LINK;
    314 
    315 	return 0;
    316 }
    317 
    318 /**
    319  * Get IPVTI tunnel interface index
    320  * @arg link            Link object
    321  *
    322  * @return interface index
    323  */
    324 uint32_t rtnl_link_ipvti_get_link(struct rtnl_link *link)
    325 {
    326 	struct ipvti_info *ipvti = link->l_info;
    327 
    328 	IS_IPVTI_LINK_ASSERT(link);
    329 
    330 	return ipvti->link;
    331 }
    332 
    333 /**
    334  * Set IPVTI tunnel set ikey
    335  * @arg link            Link object
    336  * @arg ikey            gre ikey
    337  *
    338  * @return 0 on success or a negative error code
    339  */
    340 int rtnl_link_ipvti_set_ikey(struct rtnl_link *link, uint32_t ikey)
    341 {
    342 	struct ipvti_info *ipvti = link->l_info;
    343 
    344 	IS_IPVTI_LINK_ASSERT(link);
    345 
    346 	ipvti->ikey = ikey;
    347 	ipvti->ipvti_mask |= IPVTI_ATTR_IKEY;
    348 
    349 	return 0;
    350 }
    351 
    352 /**
    353  * Get IPVTI tunnel ikey
    354  * @arg link            Link object
    355  *
    356  * @return ikey
    357  */
    358 uint32_t rtnl_link_ipvti_get_ikey(struct rtnl_link *link)
    359 {
    360 	struct ipvti_info *ipvti = link->l_info;
    361 
    362 	IS_IPVTI_LINK_ASSERT(link);
    363 
    364 	return ipvti->ikey;
    365 }
    366 
    367 /**
    368  * Set IPVTI tunnel set okey
    369  * @arg link            Link object
    370  * @arg okey            gre okey
    371  *
    372  * @return 0 on success or a negative error code
    373  */
    374 int rtnl_link_ipvti_set_okey(struct rtnl_link *link, uint32_t okey)
    375 {
    376 	struct ipvti_info *ipvti = link->l_info;
    377 
    378 	IS_IPVTI_LINK_ASSERT(link);
    379 
    380 	ipvti->okey = okey;
    381 	ipvti->ipvti_mask |= IPVTI_ATTR_OKEY;
    382 
    383 	return 0;
    384 }
    385 
    386 /**
    387  * Get IPVTI tunnel okey
    388  * @arg link            Link object
    389  *
    390  * @return okey value
    391  */
    392 uint32_t rtnl_link_ipvti_get_okey(struct rtnl_link *link)
    393 {
    394 	struct ipvti_info *ipvti = link->l_info;
    395 
    396 	IS_IPVTI_LINK_ASSERT(link);
    397 
    398 	return ipvti->okey;
    399 }
    400 
    401 /**
    402  * Set IPVTI tunnel local address
    403  * @arg link            Link object
    404  * @arg addr            local address
    405  *
    406  * @return 0 on success or a negative error code
    407  */
    408 int rtnl_link_ipvti_set_local(struct rtnl_link *link, uint32_t addr)
    409 {
    410 	struct ipvti_info *ipvti = link->l_info;
    411 
    412 	IS_IPVTI_LINK_ASSERT(link);
    413 
    414 	ipvti->local = addr;
    415 	ipvti->ipvti_mask |= IPVTI_ATTR_LOCAL;
    416 
    417 	return 0;
    418 }
    419 
    420 /**
    421  * Get IPVTI tunnel local address
    422  * @arg link            Link object
    423  *
    424  * @return local address
    425  */
    426 uint32_t rtnl_link_ipvti_get_local(struct rtnl_link *link)
    427 {
    428 	struct ipvti_info *ipvti = link->l_info;
    429 
    430 	IS_IPVTI_LINK_ASSERT(link);
    431 
    432 	return ipvti->local;
    433 }
    434 
    435 /**
    436  * Set IPVTI tunnel remote address
    437  * @arg link            Link object
    438  * @arg remote          remote address
    439  *
    440  * @return 0 on success or a negative error code
    441  */
    442 int rtnl_link_ipvti_set_remote(struct rtnl_link *link, uint32_t remote)
    443 {
    444 	struct ipvti_info *ipvti = link->l_info;
    445 
    446 	IS_IPVTI_LINK_ASSERT(link);
    447 
    448 	ipvti->remote = remote;
    449 	ipvti->ipvti_mask |= IPVTI_ATTR_REMOTE;
    450 
    451 	return 0;
    452 }
    453 
    454 /**
    455  * Get IPVTI tunnel remote address
    456  * @arg link            Link object
    457  *
    458  * @return remote address  on success or a negative error code
    459  */
    460 uint32_t rtnl_link_ipvti_get_remote(struct rtnl_link *link)
    461 {
    462 	struct ipvti_info *ipvti = link->l_info;
    463 
    464 	IS_IPVTI_LINK_ASSERT(link);
    465 
    466 	return ipvti->remote;
    467 }
    468 
    469 static void __init ipvti_init(void)
    470 {
    471 	rtnl_link_register_info(&ipvti_info_ops);
    472 }
    473 
    474 static void __exit ipvti_exit(void)
    475 {
    476 	rtnl_link_unregister_info(&ipvti_info_ops);
    477 }
    478