Home | History | Annotate | Download | only in link
      1 /*
      2  * lib/route/link/vxlan.c	VXLAN 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) 2013 Yasunobu Chiba <yasu (at) dsl.gr.jp>
     10  */
     11 
     12 /**
     13  * @ingroup link
     14  * @defgroup vxlan VXLAN
     15  * Virtual eXtensible Local Area Network link module
     16  *
     17  * @details
     18  * \b Link Type Name: "vxlan"
     19  *
     20  * @route_doc{link_vxlan, VXLAN 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 <netlink/route/link/vxlan.h>
     33 
     34 #include <linux/if_link.h>
     35 
     36 /** @cond SKIP */
     37 #define VXLAN_HAS_ID	(1<<0)
     38 #define VXLAN_HAS_GROUP	(1<<1)
     39 #define VXLAN_HAS_LINK	(1<<2)
     40 #define VXLAN_HAS_LOCAL	(1<<3)
     41 #define VXLAN_HAS_TTL	(1<<4)
     42 #define VXLAN_HAS_TOS	(1<<5)
     43 #define VXLAN_HAS_LEARNING	(1<<6)
     44 #define VXLAN_HAS_AGEING	(1<<7)
     45 #define VXLAN_HAS_LIMIT		(1<<8)
     46 #define VXLAN_HAS_PORT_RANGE	(1<<9)
     47 #define VXLAN_HAS_PROXY	(1<<10)
     48 #define VXLAN_HAS_RSC	(1<<11)
     49 #define VXLAN_HAS_L2MISS	(1<<12)
     50 #define VXLAN_HAS_L3MISS	(1<<13)
     51 
     52 struct vxlan_info
     53 {
     54 	uint32_t		vxi_id;
     55 	uint32_t		vxi_group;
     56 	uint32_t		vxi_link;
     57 	uint32_t		vxi_local;
     58 	uint8_t			vxi_ttl;
     59 	uint8_t			vxi_tos;
     60 	uint8_t			vxi_learning;
     61 	uint32_t		vxi_ageing;
     62 	uint32_t		vxi_limit;
     63 	struct ifla_vxlan_port_range	vxi_port_range;
     64 	uint8_t			vxi_proxy;
     65 	uint8_t			vxi_rsc;
     66 	uint8_t			vxi_l2miss;
     67 	uint8_t			vxi_l3miss;
     68 	uint32_t		vxi_mask;
     69 };
     70 
     71 /** @endcond */
     72 
     73 static struct nla_policy vxlan_policy[IFLA_VXLAN_MAX+1] = {
     74 	[IFLA_VXLAN_ID]	= { .type = NLA_U32 },
     75 	[IFLA_VXLAN_GROUP] = { .minlen = sizeof(uint32_t) },
     76 	[IFLA_VXLAN_LINK] = { .type = NLA_U32 },
     77 	[IFLA_VXLAN_LOCAL] = { .minlen = sizeof(uint32_t) },
     78 	[IFLA_VXLAN_TTL] = { .type = NLA_U8 },
     79 	[IFLA_VXLAN_TOS] = { .type = NLA_U8 },
     80 	[IFLA_VXLAN_LEARNING] = { .type = NLA_U8 },
     81 	[IFLA_VXLAN_AGEING] = { .type = NLA_U32 },
     82 	[IFLA_VXLAN_LIMIT] = { .type = NLA_U32 },
     83 	[IFLA_VXLAN_PORT_RANGE] = { .minlen = sizeof(struct ifla_vxlan_port_range) },
     84 	[IFLA_VXLAN_PROXY] = { .type = NLA_U8 },
     85 	[IFLA_VXLAN_RSC] = { .type = NLA_U8 },
     86 	[IFLA_VXLAN_L2MISS] = { .type = NLA_U8 },
     87 	[IFLA_VXLAN_L3MISS] = { .type = NLA_U8 },
     88 };
     89 
     90 static int vxlan_alloc(struct rtnl_link *link)
     91 {
     92 	struct vxlan_info *vxi;
     93 
     94 	if ((vxi = calloc(1, sizeof(*vxi))) == NULL)
     95 		return -NLE_NOMEM;
     96 
     97 	link->l_info = vxi;
     98 
     99 	return 0;
    100 }
    101 
    102 static int vxlan_parse(struct rtnl_link *link, struct nlattr *data,
    103 		      struct nlattr *xstats)
    104 {
    105 	struct nlattr *tb[IFLA_VXLAN_MAX+1];
    106 	struct vxlan_info *vxi;
    107 	int err;
    108 
    109 	NL_DBG(3, "Parsing VXLAN link info");
    110 
    111 	if ((err = nla_parse_nested(tb, IFLA_VXLAN_MAX, data, vxlan_policy)) < 0)
    112 		goto errout;
    113 
    114 	if ((err = vxlan_alloc(link)) < 0)
    115 		goto errout;
    116 
    117 	vxi = link->l_info;
    118 
    119 	if (tb[IFLA_VXLAN_ID]) {
    120 		vxi->vxi_id = nla_get_u32(tb[IFLA_VXLAN_ID]);
    121 		vxi->vxi_mask |= VXLAN_HAS_ID;
    122 	}
    123 
    124 	if (tb[IFLA_VXLAN_GROUP]) {
    125 		nla_memcpy(&vxi->vxi_group, tb[IFLA_VXLAN_GROUP],
    126 				   sizeof(vxi->vxi_group));
    127 		vxi->vxi_mask |= VXLAN_HAS_GROUP;
    128 	}
    129 
    130 	if (tb[IFLA_VXLAN_LINK]) {
    131 		vxi->vxi_link = nla_get_u32(tb[IFLA_VXLAN_LINK]);
    132 		vxi->vxi_mask |= VXLAN_HAS_LINK;
    133 	}
    134 
    135 	if (tb[IFLA_VXLAN_LOCAL]) {
    136 		nla_memcpy(&vxi->vxi_local, tb[IFLA_VXLAN_LOCAL],
    137 				   sizeof(vxi->vxi_local));
    138 		vxi->vxi_mask |= VXLAN_HAS_LOCAL;
    139 	}
    140 
    141 	if (tb[IFLA_VXLAN_TTL]) {
    142 		vxi->vxi_ttl = nla_get_u8(tb[IFLA_VXLAN_TTL]);
    143 		vxi->vxi_mask |= VXLAN_HAS_TTL;
    144 	}
    145 
    146 	if (tb[IFLA_VXLAN_TOS]) {
    147 		vxi->vxi_tos = nla_get_u8(tb[IFLA_VXLAN_TOS]);
    148 		vxi->vxi_mask |= VXLAN_HAS_TOS;
    149 	}
    150 
    151 	if (tb[IFLA_VXLAN_LEARNING]) {
    152 		vxi->vxi_learning = nla_get_u8(tb[IFLA_VXLAN_LEARNING]);
    153 		vxi->vxi_mask |= VXLAN_HAS_LEARNING;
    154 	}
    155 
    156 	if (tb[IFLA_VXLAN_AGEING]) {
    157 		vxi->vxi_ageing = nla_get_u32(tb[IFLA_VXLAN_AGEING]);
    158 		vxi->vxi_mask |= VXLAN_HAS_AGEING;
    159 	}
    160 
    161 	if (tb[IFLA_VXLAN_LIMIT]) {
    162 		vxi->vxi_limit = nla_get_u32(tb[IFLA_VXLAN_LIMIT]);
    163 		vxi->vxi_mask |= VXLAN_HAS_LIMIT;
    164 	}
    165 
    166 	if (tb[IFLA_VXLAN_PORT_RANGE]) {
    167 		nla_memcpy(&vxi->vxi_port_range, tb[IFLA_VXLAN_PORT_RANGE],
    168 				   sizeof(vxi->vxi_port_range));
    169 		vxi->vxi_mask |= VXLAN_HAS_PORT_RANGE;
    170 	}
    171 
    172 	if (tb[IFLA_VXLAN_PROXY]) {
    173 		vxi->vxi_proxy = nla_get_u8(tb[IFLA_VXLAN_PROXY]);
    174 		vxi->vxi_mask |= VXLAN_HAS_PROXY;
    175 	}
    176 
    177 	if (tb[IFLA_VXLAN_RSC]) {
    178 		vxi->vxi_rsc = nla_get_u8(tb[IFLA_VXLAN_RSC]);
    179 		vxi->vxi_mask |= VXLAN_HAS_RSC;
    180 	}
    181 
    182 	if (tb[IFLA_VXLAN_L2MISS]) {
    183 		vxi->vxi_l2miss = nla_get_u8(tb[IFLA_VXLAN_L2MISS]);
    184 		vxi->vxi_mask |= VXLAN_HAS_L2MISS;
    185 	}
    186 
    187 	if (tb[IFLA_VXLAN_L3MISS]) {
    188 		vxi->vxi_l3miss = nla_get_u8(tb[IFLA_VXLAN_L3MISS]);
    189 		vxi->vxi_mask |= VXLAN_HAS_L3MISS;
    190 	}
    191 
    192 	err = 0;
    193 
    194 errout:
    195 	return err;
    196 }
    197 
    198 static void vxlan_free(struct rtnl_link *link)
    199 {
    200 	struct vxlan_info *vxi = link->l_info;
    201 
    202 	free(vxi);
    203 	link->l_info = NULL;
    204 }
    205 
    206 static void vxlan_dump_line(struct rtnl_link *link, struct nl_dump_params *p)
    207 {
    208 	struct vxlan_info *vxi = link->l_info;
    209 
    210 	nl_dump(p, "vxlan-id %u", vxi->vxi_id);
    211 }
    212 
    213 static void vxlan_dump_details(struct rtnl_link *link, struct nl_dump_params *p)
    214 {
    215 	struct vxlan_info *vxi = link->l_info;
    216 	char *name, addr[INET_ADDRSTRLEN];
    217 
    218 	nl_dump_line(p, "    vxlan-id %u\n", vxi->vxi_id);
    219 
    220 	if (vxi->vxi_mask & VXLAN_HAS_GROUP) {
    221 		nl_dump(p, "      group ");
    222 		if(inet_ntop(AF_INET, &vxi->vxi_group, addr, sizeof(addr)))
    223 			nl_dump_line(p, "%s\n", addr);
    224 		else
    225 			nl_dump_line(p, "%#x\n", ntohs(vxi->vxi_group));
    226 	}
    227 
    228 	if (vxi->vxi_mask & VXLAN_HAS_LINK) {
    229 		nl_dump(p, "      link ");
    230 		name = rtnl_link_get_name(link);
    231 		if (name)
    232 			nl_dump_line(p, "%s\n", name);
    233 		else
    234 			nl_dump_line(p, "%u\n", vxi->vxi_link);
    235 	}
    236 
    237 	if (vxi->vxi_mask & VXLAN_HAS_LOCAL) {
    238 		nl_dump(p, "      local ");
    239 		if(inet_ntop(AF_INET, &vxi->vxi_local, addr, sizeof(addr)))
    240 			nl_dump_line(p, "%s\n", addr);
    241 		else
    242 			nl_dump_line(p, "%#x\n", ntohs(vxi->vxi_local));
    243 	}
    244 
    245 	if (vxi->vxi_mask & VXLAN_HAS_TTL) {
    246 		nl_dump(p, "      ttl ");
    247 		if(vxi->vxi_ttl)
    248 			nl_dump_line(p, "%u\n", vxi->vxi_ttl);
    249 		else
    250 			nl_dump_line(p, "inherit\n");
    251 	}
    252 
    253 	if (vxi->vxi_mask & VXLAN_HAS_TOS) {
    254 		nl_dump(p, "      tos ");
    255 		if (vxi->vxi_tos == 1)
    256 			nl_dump_line(p, "inherit\n", vxi->vxi_tos);
    257 		else
    258 			nl_dump_line(p, "%#x\n", vxi->vxi_tos);
    259 	}
    260 
    261 	if (vxi->vxi_mask & VXLAN_HAS_LEARNING) {
    262 		nl_dump(p, "      learning ");
    263 		if (vxi->vxi_learning)
    264 			nl_dump_line(p, "enabled (%#x)\n", vxi->vxi_learning);
    265 		else
    266 			nl_dump_line(p, "disabled\n");
    267 	}
    268 
    269 	if (vxi->vxi_mask & VXLAN_HAS_AGEING) {
    270 		nl_dump(p, "      ageing ");
    271 		if (vxi->vxi_ageing)
    272 			nl_dump_line(p, "%u seconds\n", vxi->vxi_ageing);
    273 		else
    274 			nl_dump_line(p, "disabled\n");
    275 	}
    276 
    277 	if (vxi->vxi_mask & VXLAN_HAS_LIMIT) {
    278 		nl_dump(p, "      limit ");
    279 		if (vxi->vxi_limit)
    280 			nl_dump_line(p, "%u\n", vxi->vxi_limit);
    281 		else
    282 			nl_dump_line(p, "unlimited\n");
    283 	}
    284 
    285 	if (vxi->vxi_mask & VXLAN_HAS_PORT_RANGE)
    286 		nl_dump_line(p, "      port range %u - %u\n",
    287 					 ntohs(vxi->vxi_port_range.low),
    288 					 ntohs(vxi->vxi_port_range.high));
    289 
    290 	if (vxi->vxi_mask & VXLAN_HAS_PROXY) {
    291 		nl_dump(p, "      proxy ");
    292 		if (vxi->vxi_proxy)
    293 			nl_dump_line(p, "enabled (%#x)\n", vxi->vxi_proxy);
    294 		else
    295 			nl_dump_line(p, "disabled\n");
    296 	}
    297 
    298 	if (vxi->vxi_mask & VXLAN_HAS_RSC) {
    299 		nl_dump(p, "      rsc ");
    300 		if (vxi->vxi_rsc)
    301 			nl_dump_line(p, "enabled (%#x)\n", vxi->vxi_rsc);
    302 		else
    303 			nl_dump_line(p, "disabled\n");
    304 	}
    305 
    306 	if (vxi->vxi_mask & VXLAN_HAS_L2MISS) {
    307 		nl_dump(p, "      l2miss ");
    308 		if (vxi->vxi_l2miss)
    309 			nl_dump_line(p, "enabled (%#x)\n", vxi->vxi_l2miss);
    310 		else
    311 			nl_dump_line(p, "disabled\n");
    312 	}
    313 
    314 	if (vxi->vxi_mask & VXLAN_HAS_L3MISS) {
    315 		nl_dump(p, "      l3miss ");
    316 		if (vxi->vxi_l3miss)
    317 			nl_dump_line(p, "enabled (%#x)\n", vxi->vxi_l3miss);
    318 		else
    319 			nl_dump_line(p, "disabled\n");
    320 	}
    321 }
    322 
    323 static int vxlan_clone(struct rtnl_link *dst, struct rtnl_link *src)
    324 {
    325 	struct vxlan_info *vdst, *vsrc = src->l_info;
    326 	int err;
    327 
    328 	dst->l_info = NULL;
    329 	if ((err = rtnl_link_set_type(dst, "vxlan")) < 0)
    330 		return err;
    331 	vdst = dst->l_info;
    332 
    333 	if (!vdst || !vsrc)
    334 		return -NLE_NOMEM;
    335 
    336 	memcpy(vdst, vsrc, sizeof(struct vxlan_info));
    337 
    338 	return 0;
    339 }
    340 
    341 static int vxlan_put_attrs(struct nl_msg *msg, struct rtnl_link *link)
    342 {
    343 	struct vxlan_info *vxi = link->l_info;
    344 	struct nlattr *data;
    345 
    346 	if (!(data = nla_nest_start(msg, IFLA_INFO_DATA)))
    347 		return -NLE_MSGSIZE;
    348 
    349 	if (vxi->vxi_mask & VXLAN_HAS_ID)
    350 		NLA_PUT_U32(msg, IFLA_VXLAN_ID, vxi->vxi_id);
    351 
    352 	if (vxi->vxi_mask & VXLAN_HAS_GROUP)
    353 		NLA_PUT(msg, IFLA_VXLAN_GROUP, sizeof(vxi->vxi_group), &vxi->vxi_group);
    354 
    355 	if (vxi->vxi_mask & VXLAN_HAS_LINK)
    356 		NLA_PUT_U32(msg, IFLA_VXLAN_LINK, vxi->vxi_link);
    357 
    358 	if (vxi->vxi_mask & VXLAN_HAS_LOCAL)
    359 		NLA_PUT(msg, IFLA_VXLAN_LOCAL, sizeof(vxi->vxi_local), &vxi->vxi_local);
    360 
    361 	if (vxi->vxi_mask & VXLAN_HAS_TTL)
    362 		NLA_PUT_U8(msg, IFLA_VXLAN_TTL, vxi->vxi_ttl);
    363 
    364 	if (vxi->vxi_mask & VXLAN_HAS_TOS)
    365 		NLA_PUT_U8(msg, IFLA_VXLAN_TOS, vxi->vxi_tos);
    366 
    367 	if (vxi->vxi_mask & VXLAN_HAS_LEARNING)
    368 		NLA_PUT_U8(msg, IFLA_VXLAN_LEARNING, vxi->vxi_learning);
    369 
    370 	if (vxi->vxi_mask & VXLAN_HAS_AGEING)
    371 		NLA_PUT_U32(msg, IFLA_VXLAN_AGEING, vxi->vxi_ageing);
    372 
    373 	if (vxi->vxi_mask & VXLAN_HAS_LIMIT)
    374 		NLA_PUT_U32(msg, IFLA_VXLAN_LIMIT, vxi->vxi_limit);
    375 
    376 	if (vxi->vxi_mask & VXLAN_HAS_PORT_RANGE)
    377 		NLA_PUT(msg, IFLA_VXLAN_PORT_RANGE, sizeof(vxi->vxi_port_range),
    378 				&vxi->vxi_port_range);
    379 
    380 	if (vxi->vxi_mask & VXLAN_HAS_PROXY)
    381 		NLA_PUT_U8(msg, IFLA_VXLAN_PROXY, vxi->vxi_proxy);
    382 
    383 	if (vxi->vxi_mask & VXLAN_HAS_RSC)
    384 		NLA_PUT_U8(msg, IFLA_VXLAN_RSC, vxi->vxi_rsc);
    385 
    386 	if (vxi->vxi_mask & VXLAN_HAS_L2MISS)
    387 		NLA_PUT_U8(msg, IFLA_VXLAN_L2MISS, vxi->vxi_l2miss);
    388 
    389 	if (vxi->vxi_mask & VXLAN_HAS_L3MISS)
    390 		NLA_PUT_U8(msg, IFLA_VXLAN_L3MISS, vxi->vxi_l3miss);
    391 
    392 	nla_nest_end(msg, data);
    393 
    394 nla_put_failure:
    395 
    396 	return 0;
    397 }
    398 
    399 static struct rtnl_link_info_ops vxlan_info_ops = {
    400 	.io_name		= "vxlan",
    401 	.io_alloc		= vxlan_alloc,
    402 	.io_parse		= vxlan_parse,
    403 	.io_dump = {
    404 	    [NL_DUMP_LINE]	= vxlan_dump_line,
    405 	    [NL_DUMP_DETAILS]	= vxlan_dump_details,
    406 	},
    407 	.io_clone		= vxlan_clone,
    408 	.io_put_attrs		= vxlan_put_attrs,
    409 	.io_free		= vxlan_free,
    410 };
    411 
    412 /** @cond SKIP */
    413 #define IS_VXLAN_LINK_ASSERT(link) \
    414 	if ((link)->l_info_ops != &vxlan_info_ops) { \
    415 		APPBUG("Link is not a vxlan link. set type \"vxlan\" first."); \
    416 		return -NLE_OPNOTSUPP; \
    417 	}
    418 /** @endcond */
    419 
    420 /**
    421  * @name VXLAN Object
    422  * @{
    423  */
    424 
    425 /**
    426  * Allocate link object of type VXLAN
    427  *
    428  * @return Allocated link object or NULL.
    429  */
    430 struct rtnl_link *rtnl_link_vxlan_alloc(void)
    431 {
    432 	struct rtnl_link *link;
    433 	int err;
    434 
    435 	if (!(link = rtnl_link_alloc()))
    436 		return NULL;
    437 
    438 	if ((err = rtnl_link_set_type(link, "vxlan")) < 0) {
    439 		rtnl_link_put(link);
    440 		return NULL;
    441 	}
    442 
    443 	return link;
    444 }
    445 
    446 /**
    447  * Check if link is a VXLAN link
    448  * @arg link		Link object
    449  *
    450  * @return True if link is a VXLAN link, otherwise false is returned.
    451  */
    452 int rtnl_link_is_vxlan(struct rtnl_link *link)
    453 {
    454 	return link->l_info_ops && !strcmp(link->l_info_ops->io_name, "vxlan");
    455 }
    456 
    457 /**
    458  * Set VXLAN Network Identifier
    459  * @arg link		Link object
    460  * @arg id		VXLAN network identifier (or VXLAN segment identifier)
    461  *
    462  * @return 0 on success or a negative error code
    463  */
    464 int rtnl_link_vxlan_set_id(struct rtnl_link *link, uint32_t id)
    465 {
    466 	struct vxlan_info *vxi = link->l_info;
    467 
    468 	IS_VXLAN_LINK_ASSERT(link);
    469 
    470 	if (id > VXLAN_ID_MAX)
    471 		return -NLE_INVAL;
    472 
    473 	vxi->vxi_id = id;
    474 	vxi->vxi_mask |= VXLAN_HAS_ID;
    475 
    476 	return 0;
    477 }
    478 
    479 /**
    480  * Get VXLAN Network Identifier
    481  * @arg link		Link object
    482  * @arg id			Pointer to store network identifier
    483  *
    484  * @return 0 on success or a negative error code
    485  */
    486 int rtnl_link_vxlan_get_id(struct rtnl_link *link, uint32_t *id)
    487 {
    488 	struct vxlan_info *vxi = link->l_info;
    489 
    490 	IS_VXLAN_LINK_ASSERT(link);
    491 
    492 	if(!id)
    493 		return -NLE_INVAL;
    494 
    495 	if (vxi->vxi_mask & VXLAN_HAS_ID)
    496 		*id = vxi->vxi_id;
    497 	else
    498 		return -NLE_AGAIN;
    499 
    500 	return 0;
    501 }
    502 
    503 /**
    504  * Set VXLAN multicast IP address
    505  * @arg link		Link object
    506  * @arg addr		Multicast IP address to join
    507  *
    508  * @return 0 on success or a negative error code
    509  */
    510 int rtnl_link_vxlan_set_group(struct rtnl_link *link, struct nl_addr *addr)
    511 {
    512 	struct vxlan_info *vxi = link->l_info;
    513 
    514 	IS_VXLAN_LINK_ASSERT(link);
    515 
    516 	if ((nl_addr_get_family(addr) != AF_INET) ||
    517 		(nl_addr_get_len(addr) != sizeof(vxi->vxi_group)))
    518 		return -NLE_INVAL;
    519 
    520 	memcpy(&vxi->vxi_group, nl_addr_get_binary_addr(addr),
    521 		   sizeof(vxi->vxi_group));
    522 	vxi->vxi_mask |= VXLAN_HAS_GROUP;
    523 
    524 	return 0;
    525 }
    526 
    527 /**
    528  * Get VXLAN multicast IP address
    529  * @arg link		Link object
    530  * @arg addr		Pointer to store multicast IP address
    531  *
    532  * @return 0 on success or a negative error code
    533  */
    534 int rtnl_link_vxlan_get_group(struct rtnl_link *link, struct nl_addr **addr)
    535 {
    536 	struct vxlan_info *vxi = link->l_info;
    537 
    538 	IS_VXLAN_LINK_ASSERT(link);
    539 
    540 	if (!addr)
    541 		return -NLE_INVAL;
    542 
    543 	if (!(vxi->vxi_mask & VXLAN_HAS_GROUP))
    544 		return -NLE_AGAIN;
    545 
    546 	*addr = nl_addr_build(AF_INET, &vxi->vxi_group, sizeof(vxi->vxi_group));
    547 
    548 	return 0;
    549 }
    550 
    551 /**
    552  * Set physical device to use for VXLAN
    553  * @arg link		Link object
    554  * @arg index		Interface index
    555  *
    556  * @return 0 on success or a negative error code
    557  */
    558 int rtnl_link_vxlan_set_link(struct rtnl_link *link, uint32_t index)
    559 {
    560 	struct vxlan_info *vxi = link->l_info;
    561 
    562 	IS_VXLAN_LINK_ASSERT(link);
    563 
    564 	vxi->vxi_link = index;
    565 	vxi->vxi_mask |= VXLAN_HAS_LINK;
    566 
    567 	return 0;
    568 }
    569 
    570 /**
    571  * Get physical device to use for VXLAN
    572  * @arg link		Link object
    573  * @arg index		Pointer to store interface index
    574  *
    575  * @return 0 on success or a negative error code
    576  */
    577 int rtnl_link_vxlan_get_link(struct rtnl_link *link, uint32_t *index)
    578 {
    579 	struct vxlan_info *vxi = link->l_info;
    580 
    581 	IS_VXLAN_LINK_ASSERT(link);
    582 
    583 	if (!index)
    584 		return -NLE_INVAL;
    585 
    586 	if (!(vxi->vxi_mask & VXLAN_HAS_LINK))
    587 		return -NLE_AGAIN;
    588 
    589 	*index = vxi->vxi_link;
    590 
    591 	return 0;
    592 }
    593 
    594 /**
    595  * Set source address to use for VXLAN
    596  * @arg link		Link object
    597  * @arg addr		Local address
    598  *
    599  * @return 0 on success or a negative error code
    600  */
    601 int rtnl_link_vxlan_set_local(struct rtnl_link *link, struct nl_addr *addr)
    602 {
    603 	struct vxlan_info *vxi = link->l_info;
    604 
    605 	IS_VXLAN_LINK_ASSERT(link);
    606 
    607 	if ((nl_addr_get_family(addr) != AF_INET) ||
    608 		(nl_addr_get_len(addr) != sizeof(vxi->vxi_local)))
    609 		return -NLE_INVAL;
    610 
    611 	memcpy(&vxi->vxi_local, nl_addr_get_binary_addr(addr),
    612 		   sizeof(vxi->vxi_local));
    613 	vxi->vxi_mask |= VXLAN_HAS_LOCAL;
    614 
    615 	return 0;
    616 }
    617 
    618 /**
    619  * Get source address to use for VXLAN
    620  * @arg link		Link object
    621  * @arg addr		Pointer to store local address
    622  *
    623  * @return 0 on success or a negative error code
    624  */
    625 int rtnl_link_vxlan_get_local(struct rtnl_link *link, struct nl_addr **addr)
    626 {
    627 	struct vxlan_info *vxi = link->l_info;
    628 
    629 	IS_VXLAN_LINK_ASSERT(link);
    630 
    631 	if (!addr)
    632 		return -NLE_INVAL;
    633 
    634 	if (!(vxi->vxi_mask & VXLAN_HAS_LOCAL))
    635 		return -NLE_AGAIN;
    636 
    637 	*addr = nl_addr_build(AF_INET, &vxi->vxi_local, sizeof(vxi->vxi_local));
    638 
    639 	return 0;
    640 }
    641 
    642 /**
    643  * Set IP TTL value to use for VXLAN
    644  * @arg link		Link object
    645  * @arg ttl			TTL value
    646  *
    647  * @return 0 on success or a negative error code
    648  */
    649 int rtnl_link_vxlan_set_ttl(struct rtnl_link *link, uint8_t ttl)
    650 {
    651 	struct vxlan_info *vxi = link->l_info;
    652 
    653 	IS_VXLAN_LINK_ASSERT(link);
    654 
    655 	vxi->vxi_ttl = ttl;
    656 	vxi->vxi_mask |= VXLAN_HAS_TTL;
    657 
    658 	return 0;
    659 }
    660 
    661 /**
    662  * Get IP TTL value to use for VXLAN
    663  * @arg link		Link object
    664  *
    665  * @return TTL value on success or a negative error code
    666  */
    667 int rtnl_link_vxlan_get_ttl(struct rtnl_link *link)
    668 {
    669 	struct vxlan_info *vxi = link->l_info;
    670 
    671 	IS_VXLAN_LINK_ASSERT(link);
    672 
    673 	if (!(vxi->vxi_mask & VXLAN_HAS_TTL))
    674 		return -NLE_AGAIN;
    675 
    676 	return vxi->vxi_ttl;
    677 }
    678 
    679 /**
    680  * Set IP ToS value to use for VXLAN
    681  * @arg link		Link object
    682  * @arg tos		ToS value
    683  *
    684  * @return 0 on success or a negative error code
    685  */
    686 int rtnl_link_vxlan_set_tos(struct rtnl_link *link, uint8_t tos)
    687 {
    688 	struct vxlan_info *vxi = link->l_info;
    689 
    690 	IS_VXLAN_LINK_ASSERT(link);
    691 
    692 	vxi->vxi_tos = tos;
    693 	vxi->vxi_mask |= VXLAN_HAS_TOS;
    694 
    695 	return 0;
    696 }
    697 
    698 /**
    699  * Get IP ToS value to use for VXLAN
    700  * @arg link		Link object
    701  *
    702  * @return ToS value on success or a negative error code
    703  */
    704 int rtnl_link_vxlan_get_tos(struct rtnl_link *link)
    705 {
    706 	struct vxlan_info *vxi = link->l_info;
    707 
    708 	IS_VXLAN_LINK_ASSERT(link);
    709 
    710 	if (!(vxi->vxi_mask & VXLAN_HAS_TOS))
    711 		return -NLE_AGAIN;
    712 
    713 	return vxi->vxi_tos;
    714 }
    715 
    716 /**
    717  * Set VXLAN learning status
    718  * @arg link		Link object
    719  * @arg learning	Learning status value
    720  *
    721  * @return 0 on success or a negative error code
    722  */
    723 int rtnl_link_vxlan_set_learning(struct rtnl_link *link, uint8_t learning)
    724 {
    725 	struct vxlan_info *vxi = link->l_info;
    726 
    727 	IS_VXLAN_LINK_ASSERT(link);
    728 
    729 	vxi->vxi_learning = learning;
    730 	vxi->vxi_mask |= VXLAN_HAS_LEARNING;
    731 
    732 	return 0;
    733 }
    734 
    735 /**
    736  * Get VXLAN learning status
    737  * @arg link		Link object
    738  *
    739  * @return Learning status value on success or a negative error code
    740  */
    741 int rtnl_link_vxlan_get_learning(struct rtnl_link *link)
    742 {
    743 	struct vxlan_info *vxi = link->l_info;
    744 
    745 	IS_VXLAN_LINK_ASSERT(link);
    746 
    747 	if (!(vxi->vxi_mask & VXLAN_HAS_LEARNING))
    748 		return -NLE_AGAIN;
    749 
    750 	return vxi->vxi_learning;
    751 }
    752 
    753 /**
    754  * Enable VXLAN address learning
    755  * @arg link		Link object
    756  *
    757  * @return 0 on success or a negative error code
    758  */
    759 int rtnl_link_vxlan_enable_learning(struct rtnl_link *link)
    760 {
    761 	return rtnl_link_vxlan_set_learning(link, 1);
    762 }
    763 
    764 /**
    765  * Disable VXLAN address learning
    766  * @arg link		Link object
    767  *
    768  * @return 0 on success or a negative error code
    769  */
    770 int rtnl_link_vxlan_disable_learning(struct rtnl_link *link)
    771 {
    772 	return rtnl_link_vxlan_set_learning(link, 0);
    773 }
    774 
    775 /**
    776  * Set expiration timer value to use for VXLAN
    777  * @arg link		Link object
    778  * @arg expiry		Expiration timer value
    779  *
    780  * @return 0 on success or a negative error code
    781  */
    782 int rtnl_link_vxlan_set_ageing(struct rtnl_link *link, uint32_t expiry)
    783 {
    784 	struct vxlan_info *vxi = link->l_info;
    785 
    786 	IS_VXLAN_LINK_ASSERT(link);
    787 
    788 	vxi->vxi_ageing = expiry;
    789 	vxi->vxi_mask |= VXLAN_HAS_AGEING;
    790 
    791 	return 0;
    792 }
    793 
    794 /**
    795  * Get expiration timer value to use for VXLAN
    796  * @arg link		Link object
    797  * @arg expiry		Pointer to store expiration timer value
    798  *
    799  * @return 0 on success or a negative error code
    800  */
    801 int rtnl_link_vxlan_get_ageing(struct rtnl_link *link, uint32_t *expiry)
    802 {
    803 	struct vxlan_info *vxi = link->l_info;
    804 
    805 	IS_VXLAN_LINK_ASSERT(link);
    806 
    807 	if (!expiry)
    808 		return -NLE_INVAL;
    809 
    810 	if (vxi->vxi_mask & VXLAN_HAS_AGEING)
    811 		*expiry = vxi->vxi_ageing;
    812 	else
    813 		return -NLE_AGAIN;
    814 
    815 	return 0;
    816 }
    817 
    818 /**
    819  * Set maximum number of forwarding database entries to use for VXLAN
    820  * @arg link		Link object
    821  * @arg limit		Maximum number
    822  *
    823  * @return 0 on success or a negative error code
    824  */
    825 int rtnl_link_vxlan_set_limit(struct rtnl_link *link, uint32_t limit)
    826 {
    827 	struct vxlan_info *vxi = link->l_info;
    828 
    829 	IS_VXLAN_LINK_ASSERT(link);
    830 
    831 	vxi->vxi_limit = limit;
    832 	vxi->vxi_mask |= VXLAN_HAS_LIMIT;
    833 
    834 	return 0;
    835 }
    836 
    837 /**
    838  * Get maximum number of forwarding database entries to use for VXLAN
    839  * @arg link		Link object
    840  * @arg limit		Pointer to store maximum number
    841  *
    842  * @return 0 on success or a negative error code
    843  */
    844 int rtnl_link_vxlan_get_limit(struct rtnl_link *link, uint32_t *limit)
    845 {
    846 	struct vxlan_info *vxi = link->l_info;
    847 
    848 	IS_VXLAN_LINK_ASSERT(link);
    849 
    850 	if (!limit)
    851 		return -NLE_INVAL;
    852 
    853 	if (vxi->vxi_mask & VXLAN_HAS_LIMIT)
    854 		*limit = vxi->vxi_limit;
    855 	else
    856 		return -NLE_AGAIN;
    857 
    858 	return 0;
    859 }
    860 
    861 /**
    862  * Set range of UDP port numbers to use for VXLAN
    863  * @arg link		Link object
    864  * @arg range		Port number range
    865  *
    866  * @return 0 on success or a negative error code
    867  */
    868 int rtnl_link_vxlan_set_port_range(struct rtnl_link *link,
    869 								   struct ifla_vxlan_port_range *range)
    870 {
    871 	struct vxlan_info *vxi = link->l_info;
    872 
    873 	IS_VXLAN_LINK_ASSERT(link);
    874 
    875 	if (!range)
    876 		return -NLE_INVAL;
    877 
    878 	memcpy(&vxi->vxi_port_range, range, sizeof(vxi->vxi_port_range));
    879 	vxi->vxi_mask |= VXLAN_HAS_PORT_RANGE;
    880 
    881 	return 0;
    882 }
    883 
    884 /**
    885  * Get range of UDP port numbers to use for VXLAN
    886  * @arg link		Link object
    887  * @arg range		Pointer to store port range
    888  *
    889  * @return 0 on success or a negative error code
    890  */
    891 int rtnl_link_vxlan_get_port_range(struct rtnl_link *link,
    892 								   struct ifla_vxlan_port_range *range)
    893 {
    894 	struct vxlan_info *vxi = link->l_info;
    895 
    896 	IS_VXLAN_LINK_ASSERT(link);
    897 
    898 	if (!range)
    899 		return -NLE_INVAL;
    900 
    901 	if (vxi->vxi_mask & VXLAN_HAS_PORT_RANGE)
    902 		memcpy(range, &vxi->vxi_port_range, sizeof(*range));
    903 	else
    904 		return -NLE_AGAIN;
    905 
    906 	return 0;
    907 }
    908 
    909 /**
    910  * Set ARP proxy status to use for VXLAN
    911  * @arg link		Link object
    912  * @arg proxy		Status value
    913  *
    914  * @return 0 on success or a negative error code
    915  */
    916 int rtnl_link_vxlan_set_proxy(struct rtnl_link *link, uint8_t proxy)
    917 {
    918 	struct vxlan_info *vxi = link->l_info;
    919 
    920 	IS_VXLAN_LINK_ASSERT(link);
    921 
    922 	vxi->vxi_proxy = proxy;
    923 	vxi->vxi_mask |= VXLAN_HAS_PROXY;
    924 
    925 	return 0;
    926 }
    927 
    928 /**
    929  * Get ARP proxy status to use for VXLAN
    930  * @arg link		Link object
    931  *
    932  * @return Status value on success or a negative error code
    933  */
    934 int rtnl_link_vxlan_get_proxy(struct rtnl_link *link)
    935 {
    936 	struct vxlan_info *vxi = link->l_info;
    937 
    938 	IS_VXLAN_LINK_ASSERT(link);
    939 
    940 	if (!(vxi->vxi_mask & VXLAN_HAS_PROXY))
    941 		return -NLE_AGAIN;
    942 
    943 	return vxi->vxi_proxy;
    944 }
    945 
    946 /**
    947  * Enable ARP proxy
    948  * @arg link		Link object
    949  *
    950  * @return 0 on success or a negative error code
    951  */
    952 int rtnl_link_vxlan_enable_proxy(struct rtnl_link *link)
    953 {
    954 	return rtnl_link_vxlan_set_proxy(link, 1);
    955 }
    956 
    957 /**
    958  * Disable ARP proxy
    959  * @arg link		Link object
    960  *
    961  * @return 0 on success or a negative error code
    962  */
    963 int rtnl_link_vxlan_disable_proxy(struct rtnl_link *link)
    964 {
    965 	return rtnl_link_vxlan_set_proxy(link, 0);
    966 }
    967 
    968 /**
    969  * Set Route Short Circuit status to use for VXLAN
    970  * @arg link		Link object
    971  * @arg rsc			Status value
    972  *
    973  * @return 0 on success or a negative error code
    974  */
    975 int rtnl_link_vxlan_set_rsc(struct rtnl_link *link, uint8_t rsc)
    976 {
    977 	struct vxlan_info *vxi = link->l_info;
    978 
    979 	IS_VXLAN_LINK_ASSERT(link);
    980 
    981 	vxi->vxi_rsc = rsc;
    982 	vxi->vxi_mask |= VXLAN_HAS_RSC;
    983 
    984 	return 0;
    985 }
    986 
    987 /**
    988  * Get Route Short Circuit status to use for VXLAN
    989  * @arg link		Link object
    990  *
    991  * @return Status value on success or a negative error code
    992  */
    993 int rtnl_link_vxlan_get_rsc(struct rtnl_link *link)
    994 {
    995 	struct vxlan_info *vxi = link->l_info;
    996 
    997 	IS_VXLAN_LINK_ASSERT(link);
    998 
    999 	if (!(vxi->vxi_mask & VXLAN_HAS_RSC))
   1000 		return -NLE_AGAIN;
   1001 
   1002 	return vxi->vxi_rsc;
   1003 }
   1004 
   1005 /**
   1006  * Enable Route Short Circuit
   1007  * @arg link		Link object
   1008  *
   1009  * @return 0 on success or a negative error code
   1010  */
   1011 int rtnl_link_vxlan_enable_rsc(struct rtnl_link *link)
   1012 {
   1013 	return rtnl_link_vxlan_set_rsc(link, 1);
   1014 }
   1015 
   1016 /**
   1017  * Disable Route Short Circuit
   1018  * @arg link		Link object
   1019  *
   1020  * @return 0 on success or a negative error code
   1021  */
   1022 int rtnl_link_vxlan_disable_rsc(struct rtnl_link *link)
   1023 {
   1024 	return rtnl_link_vxlan_set_rsc(link, 0);
   1025 }
   1026 
   1027 /**
   1028  * Set netlink LLADDR miss notification status to use for VXLAN
   1029  * @arg link		Link object
   1030  * @arg miss		Status value
   1031  *
   1032  * @return 0 on success or a negative error code
   1033  */
   1034 int rtnl_link_vxlan_set_l2miss(struct rtnl_link *link, uint8_t miss)
   1035 {
   1036 	struct vxlan_info *vxi = link->l_info;
   1037 
   1038 	IS_VXLAN_LINK_ASSERT(link);
   1039 
   1040 	vxi->vxi_l2miss = miss;
   1041 	vxi->vxi_mask |= VXLAN_HAS_L2MISS;
   1042 
   1043 	return 0;
   1044 }
   1045 
   1046 /**
   1047  * Get netlink LLADDR miss notification status to use for VXLAN
   1048  * @arg link		Link object
   1049  *
   1050  * @return Status value on success or a negative error code
   1051  */
   1052 int rtnl_link_vxlan_get_l2miss(struct rtnl_link *link)
   1053 {
   1054 	struct vxlan_info *vxi = link->l_info;
   1055 
   1056 	IS_VXLAN_LINK_ASSERT(link);
   1057 
   1058 	if (!(vxi->vxi_mask & VXLAN_HAS_L2MISS))
   1059 		return -NLE_AGAIN;
   1060 
   1061 	return vxi->vxi_l2miss;
   1062 }
   1063 
   1064 /**
   1065  * Enable netlink LLADDR miss notifications
   1066  * @arg link		Link object
   1067  *
   1068  * @return 0 on success or a negative error code
   1069  */
   1070 int rtnl_link_vxlan_enable_l2miss(struct rtnl_link *link)
   1071 {
   1072 	return rtnl_link_vxlan_set_l2miss(link, 1);
   1073 }
   1074 
   1075 /**
   1076  * Disable netlink LLADDR miss notifications
   1077  * @arg link		Link object
   1078  *
   1079  * @return 0 on success or a negative error code
   1080  */
   1081 int rtnl_link_vxlan_disable_l2miss(struct rtnl_link *link)
   1082 {
   1083 	return rtnl_link_vxlan_set_l2miss(link, 0);
   1084 }
   1085 
   1086 /**
   1087  * Set netlink IP ADDR miss notification status to use for VXLAN
   1088  * @arg link		Link object
   1089  * @arg miss		Status value
   1090  *
   1091  * @return 0 on success or a negative error code
   1092  */
   1093 int rtnl_link_vxlan_set_l3miss(struct rtnl_link *link, uint8_t miss)
   1094 {
   1095 	struct vxlan_info *vxi = link->l_info;
   1096 
   1097 	IS_VXLAN_LINK_ASSERT(link);
   1098 
   1099 	vxi->vxi_l3miss = miss;
   1100 	vxi->vxi_mask |= VXLAN_HAS_L3MISS;
   1101 
   1102 	return 0;
   1103 }
   1104 
   1105 /**
   1106  * Get netlink IP ADDR miss notification status to use for VXLAN
   1107  * @arg link		Link object
   1108  *
   1109  * @return Status value on success or a negative error code
   1110  */
   1111 int rtnl_link_vxlan_get_l3miss(struct rtnl_link *link)
   1112 {
   1113 	struct vxlan_info *vxi = link->l_info;
   1114 
   1115 	IS_VXLAN_LINK_ASSERT(link);
   1116 
   1117 	if (!(vxi->vxi_mask & VXLAN_HAS_L3MISS))
   1118 		return -NLE_AGAIN;
   1119 
   1120 	return vxi->vxi_l3miss;
   1121 }
   1122 
   1123 /**
   1124  * Enable netlink IP DDR miss notifications
   1125  * @arg link		Link object
   1126  *
   1127  * @return 0 on success or a negative error code
   1128  */
   1129 int rtnl_link_vxlan_enable_l3miss(struct rtnl_link *link)
   1130 {
   1131 	return rtnl_link_vxlan_set_l3miss(link, 1);
   1132 }
   1133 
   1134 /**
   1135  * Disable netlink IP ADDR miss notifications
   1136  * @arg link		Link object
   1137  *
   1138  * @return 0 on success or a negative error code
   1139  */
   1140 int rtnl_link_vxlan_disable_l3miss(struct rtnl_link *link)
   1141 {
   1142 	return rtnl_link_vxlan_set_l3miss(link, 0);
   1143 }
   1144 
   1145 /** @} */
   1146 
   1147 static void __init vxlan_init(void)
   1148 {
   1149 	rtnl_link_register_info(&vxlan_info_ops);
   1150 }
   1151 
   1152 static void __exit vxlan_exit(void)
   1153 {
   1154 	rtnl_link_unregister_info(&vxlan_info_ops);
   1155 }
   1156 
   1157 /** @} */
   1158