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