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