1 /* 2 * lib/route/link/sit.c SIT 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 sit SIT 15 * sit link module 16 * 17 * @details 18 * \b Link Type Name: "sit" 19 * 20 * @route_doc{link_sit, SIT 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 SIT_ATTR_LINK (1 << 0) 35 #define SIT_ATTR_LOCAL (1 << 1) 36 #define SIT_ATTR_REMOTE (1 << 2) 37 #define SIT_ATTR_TTL (1 << 3) 38 #define SIT_ATTR_TOS (1 << 4) 39 #define SIT_ATTR_PMTUDISC (1 << 5) 40 #define SIT_ATTR_FLAGS (1 << 6) 41 #define SIT_ATTR_PROTO (1 << 7) 42 43 struct sit_info 44 { 45 uint8_t ttl; 46 uint8_t tos; 47 uint8_t pmtudisc; 48 uint8_t proto; 49 uint16_t flags; 50 uint32_t link; 51 uint32_t local; 52 uint32_t remote; 53 uint32_t sit_mask; 54 }; 55 56 static struct nla_policy sit_policy[IFLA_IPTUN_MAX + 1] = { 57 [IFLA_IPTUN_LINK] = { .type = NLA_U32 }, 58 [IFLA_IPTUN_LOCAL] = { .type = NLA_U32 }, 59 [IFLA_IPTUN_REMOTE] = { .type = NLA_U32 }, 60 [IFLA_IPTUN_TTL] = { .type = NLA_U8 }, 61 [IFLA_IPTUN_TOS] = { .type = NLA_U8 }, 62 [IFLA_IPTUN_PMTUDISC] = { .type = NLA_U8 }, 63 [IFLA_IPTUN_FLAGS] = { .type = NLA_U16 }, 64 [IFLA_IPTUN_PROTO] = { .type = NLA_U8 }, 65 }; 66 67 static int sit_alloc(struct rtnl_link *link) 68 { 69 struct sit_info *sit; 70 71 sit = calloc(1, sizeof(*sit)); 72 if (!sit) 73 return -NLE_NOMEM; 74 75 link->l_info = sit; 76 77 return 0; 78 } 79 80 static int sit_parse(struct rtnl_link *link, struct nlattr *data, 81 struct nlattr *xstats) 82 { 83 struct nlattr *tb[IFLA_IPTUN_MAX + 1]; 84 struct sit_info *sit; 85 int err; 86 87 NL_DBG(3, "Parsing SIT link info"); 88 89 err = nla_parse_nested(tb, IFLA_IPTUN_MAX, data, sit_policy); 90 if (err < 0) 91 goto errout; 92 93 err = sit_alloc(link); 94 if (err < 0) 95 goto errout; 96 97 sit = link->l_info; 98 99 if (tb[IFLA_IPTUN_LINK]) { 100 sit->link = nla_get_u32(tb[IFLA_IPTUN_LINK]); 101 sit->sit_mask |= SIT_ATTR_LINK; 102 } 103 104 if (tb[IFLA_IPTUN_LOCAL]) { 105 sit->local = nla_get_u32(tb[IFLA_IPTUN_LOCAL]); 106 sit->sit_mask |= SIT_ATTR_LOCAL; 107 } 108 109 if (tb[IFLA_IPTUN_REMOTE]) { 110 sit->remote = nla_get_u32(tb[IFLA_IPTUN_REMOTE]); 111 sit->sit_mask |= SIT_ATTR_REMOTE; 112 } 113 114 if (tb[IFLA_IPTUN_TTL]) { 115 sit->ttl = nla_get_u8(tb[IFLA_IPTUN_TTL]); 116 sit->sit_mask |= SIT_ATTR_TTL; 117 } 118 119 if (tb[IFLA_IPTUN_TOS]) { 120 sit->tos = nla_get_u8(tb[IFLA_IPTUN_TOS]); 121 sit->sit_mask |= SIT_ATTR_TOS; 122 } 123 124 if (tb[IFLA_IPTUN_PMTUDISC]) { 125 sit->pmtudisc = nla_get_u8(tb[IFLA_IPTUN_PMTUDISC]); 126 sit->sit_mask |= SIT_ATTR_PMTUDISC; 127 } 128 129 if (tb[IFLA_IPTUN_FLAGS]) { 130 sit->flags = nla_get_u16(tb[IFLA_IPTUN_FLAGS]); 131 sit->sit_mask |= SIT_ATTR_FLAGS; 132 } 133 134 if (tb[IFLA_IPTUN_PROTO]) { 135 sit->proto = nla_get_u8(tb[IFLA_IPTUN_PROTO]); 136 sit->sit_mask |= SIT_ATTR_PROTO; 137 } 138 139 err = 0; 140 141 errout: 142 return err; 143 } 144 145 static int sit_put_attrs(struct nl_msg *msg, struct rtnl_link *link) 146 { 147 struct sit_info *sit = link->l_info; 148 struct nlattr *data; 149 150 data = nla_nest_start(msg, IFLA_INFO_DATA); 151 if (!data) 152 return -NLE_MSGSIZE; 153 154 if (sit->sit_mask & SIT_ATTR_LINK) 155 NLA_PUT_U32(msg, IFLA_IPTUN_LINK, sit->link); 156 157 if (sit->sit_mask & SIT_ATTR_LOCAL) 158 NLA_PUT_U32(msg, IFLA_IPTUN_LOCAL, sit->local); 159 160 if (sit->sit_mask & SIT_ATTR_REMOTE) 161 NLA_PUT_U32(msg, IFLA_IPTUN_REMOTE, sit->remote); 162 163 if (sit->sit_mask & SIT_ATTR_TTL) 164 NLA_PUT_U8(msg, IFLA_IPTUN_TTL, sit->ttl); 165 166 if (sit->sit_mask & SIT_ATTR_TOS) 167 NLA_PUT_U8(msg, IFLA_IPTUN_TOS, sit->tos); 168 169 if (sit->sit_mask & SIT_ATTR_PMTUDISC) 170 NLA_PUT_U8(msg, IFLA_IPTUN_PMTUDISC, sit->pmtudisc); 171 172 if (sit->sit_mask & SIT_ATTR_FLAGS) 173 NLA_PUT_U16(msg, IFLA_IPTUN_FLAGS, sit->flags); 174 175 if (sit->sit_mask & SIT_ATTR_PROTO) 176 NLA_PUT_U8(msg, IFLA_IPTUN_PROTO, sit->proto); 177 178 nla_nest_end(msg, data); 179 180 nla_put_failure: 181 182 return 0; 183 } 184 185 static void sit_free(struct rtnl_link *link) 186 { 187 struct sit_info *sit = link->l_info; 188 189 free(sit); 190 link->l_info = NULL; 191 } 192 193 static void sit_dump_line(struct rtnl_link *link, struct nl_dump_params *p) 194 { 195 nl_dump(p, "sit : %s", link->l_name); 196 } 197 198 static void sit_dump_details(struct rtnl_link *link, struct nl_dump_params *p) 199 { 200 struct sit_info *sit = link->l_info; 201 char *name, addr[INET_ADDRSTRLEN]; 202 203 if (sit->sit_mask & SIT_ATTR_LINK) { 204 nl_dump(p, " link "); 205 name = rtnl_link_get_name(link); 206 if (name) 207 nl_dump_line(p, "%s\n", name); 208 else 209 nl_dump_line(p, "%u\n", sit->link); 210 } 211 212 if (sit->sit_mask & SIT_ATTR_LOCAL) { 213 nl_dump(p, " local "); 214 if(inet_ntop(AF_INET, &sit->local, addr, sizeof(addr))) 215 nl_dump_line(p, "%s\n", addr); 216 else 217 nl_dump_line(p, "%#x\n", ntohs(sit->local)); 218 } 219 220 if (sit->sit_mask & SIT_ATTR_REMOTE) { 221 nl_dump(p, " remote "); 222 if(inet_ntop(AF_INET, &sit->remote, addr, sizeof(addr))) 223 nl_dump_line(p, "%s\n", addr); 224 else 225 nl_dump_line(p, "%#x\n", ntohs(sit->remote)); 226 } 227 228 if (sit->sit_mask & SIT_ATTR_TTL) { 229 nl_dump(p, " ttl "); 230 nl_dump_line(p, "%u\n", sit->ttl); 231 } 232 233 if (sit->sit_mask & SIT_ATTR_TOS) { 234 nl_dump(p, " tos "); 235 nl_dump_line(p, "%u\n", sit->tos); 236 } 237 238 if (sit->sit_mask & SIT_ATTR_FLAGS) { 239 nl_dump(p, " flags "); 240 nl_dump_line(p, " (%x)\n", sit->flags); 241 } 242 243 if (sit->sit_mask & SIT_ATTR_PROTO) { 244 nl_dump(p, " proto "); 245 nl_dump_line(p, " (%x)\n", sit->proto); 246 } 247 } 248 249 static int sit_clone(struct rtnl_link *dst, struct rtnl_link *src) 250 { 251 struct sit_info *sit_dst, *sit_src = src->l_info; 252 int err; 253 254 dst->l_info = NULL; 255 256 err = rtnl_link_set_type(dst, "sit"); 257 if (err < 0) 258 return err; 259 260 sit_dst = dst->l_info; 261 262 if (!sit_dst || !sit_src) 263 return -NLE_NOMEM; 264 265 memcpy(sit_dst, sit_src, sizeof(struct sit_info)); 266 267 return 0; 268 } 269 270 static struct rtnl_link_info_ops sit_info_ops = { 271 .io_name = "sit", 272 .io_alloc = sit_alloc, 273 .io_parse = sit_parse, 274 .io_dump = { 275 [NL_DUMP_LINE] = sit_dump_line, 276 [NL_DUMP_DETAILS] = sit_dump_details, 277 }, 278 .io_clone = sit_clone, 279 .io_put_attrs = sit_put_attrs, 280 .io_free = sit_free, 281 }; 282 283 #define IS_SIT_LINK_ASSERT(link) \ 284 if ((link)->l_info_ops != &sit_info_ops) { \ 285 APPBUG("Link is not a sit link. set type \"sit\" first."); \ 286 return -NLE_OPNOTSUPP; \ 287 } 288 289 struct rtnl_link *rtnl_link_sit_alloc(void) 290 { 291 struct rtnl_link *link; 292 int err; 293 294 link = rtnl_link_alloc(); 295 if (!link) 296 return NULL; 297 298 err = rtnl_link_set_type(link, "sit"); 299 if (err < 0) { 300 rtnl_link_put(link); 301 return NULL; 302 } 303 304 return link; 305 } 306 307 /** 308 * Check if link is a SIT link 309 * @arg link Link object 310 * 311 * @return True if link is a SIT link, otherwise false is returned. 312 */ 313 int rtnl_link_is_sit(struct rtnl_link *link) 314 { 315 return link->l_info_ops && !strcmp(link->l_info_ops->io_name, "sit"); 316 } 317 318 /** 319 * Create a new sit tunnel device 320 * @arg sock netlink socket 321 * @arg name name of the tunnel device 322 * 323 * Creates a new sit tunnel device in the kernel 324 * @return 0 on success or a negative error code 325 */ 326 int rtnl_link_sit_add(struct nl_sock *sk, const char *name) 327 { 328 struct rtnl_link *link; 329 int err; 330 331 link = rtnl_link_sit_alloc(); 332 if (!link) 333 return -NLE_NOMEM; 334 335 if(name) 336 rtnl_link_set_name(link, name); 337 338 err = rtnl_link_add(sk, link, NLM_F_CREATE); 339 rtnl_link_put(link); 340 341 return err; 342 } 343 344 /** 345 * Set SIT tunnel interface index 346 * @arg link Link object 347 * @arg index interface index 348 * 349 * @return 0 on success or a negative error code 350 */ 351 int rtnl_link_sit_set_link(struct rtnl_link *link, uint32_t index) 352 { 353 struct sit_info *sit = link->l_info; 354 355 IS_SIT_LINK_ASSERT(link); 356 357 sit->link = index; 358 sit->sit_mask |= SIT_ATTR_LINK; 359 360 return 0; 361 } 362 363 /** 364 * Get SIT tunnel interface index 365 * @arg link Link object 366 * 367 * @return interface index value 368 */ 369 uint32_t rtnl_link_sit_get_link(struct rtnl_link *link) 370 { 371 struct sit_info *sit = link->l_info; 372 373 IS_SIT_LINK_ASSERT(link); 374 375 return sit->link; 376 } 377 378 /** 379 * Set SIT tunnel local address 380 * @arg link Link object 381 * @arg addr local address 382 * 383 * @return 0 on success or a negative error code 384 */ 385 int rtnl_link_sit_set_local(struct rtnl_link *link, uint32_t addr) 386 { 387 struct sit_info *sit = link->l_info; 388 389 IS_SIT_LINK_ASSERT(link); 390 391 sit->local = addr; 392 sit->sit_mask |= SIT_ATTR_LOCAL; 393 394 return 0; 395 } 396 397 /** 398 * Get SIT tunnel local address 399 * @arg link Link object 400 * 401 * @return local address value 402 */ 403 uint32_t rtnl_link_sit_get_local(struct rtnl_link *link) 404 { 405 struct sit_info *sit = link->l_info; 406 407 IS_SIT_LINK_ASSERT(link); 408 409 return sit->local; 410 } 411 412 /** 413 * Set SIT tunnel remote address 414 * @arg link Link object 415 * @arg remote remote address 416 * 417 * @return 0 on success or a negative error code 418 */ 419 int rtnl_link_sit_set_remote(struct rtnl_link *link, uint32_t addr) 420 { 421 struct sit_info *sit = link->l_info; 422 423 IS_SIT_LINK_ASSERT(link); 424 425 sit->remote = addr; 426 sit->sit_mask |= SIT_ATTR_REMOTE; 427 428 return 0; 429 } 430 431 /** 432 * Get SIT tunnel remote address 433 * @arg link Link object 434 * 435 * @return remote address 436 */ 437 uint32_t rtnl_link_sit_get_remote(struct rtnl_link *link) 438 { 439 struct sit_info *sit = link->l_info; 440 441 IS_SIT_LINK_ASSERT(link); 442 443 return sit->remote; 444 } 445 446 /** 447 * Set SIT tunnel ttl 448 * @arg link Link object 449 * @arg ttl tunnel ttl 450 * 451 * @return 0 on success or a negative error code 452 */ 453 int rtnl_link_sit_set_ttl(struct rtnl_link *link, uint8_t ttl) 454 { 455 struct sit_info *sit = link->l_info; 456 457 IS_SIT_LINK_ASSERT(link); 458 459 sit->ttl = ttl; 460 sit->sit_mask |= SIT_ATTR_TTL; 461 462 return 0; 463 } 464 465 /** 466 * Get SIT tunnel ttl 467 * @arg link Link object 468 * 469 * @return ttl value 470 */ 471 uint8_t rtnl_link_sit_get_ttl(struct rtnl_link *link) 472 { 473 struct sit_info *sit = link->l_info; 474 475 IS_SIT_LINK_ASSERT(link); 476 477 return sit->ttl; 478 } 479 480 /** 481 * Set SIT tunnel tos 482 * @arg link Link object 483 * @arg tos tunnel tos 484 * 485 * @return 0 on success or a negative error code 486 */ 487 int rtnl_link_sit_set_tos(struct rtnl_link *link, uint8_t tos) 488 { 489 struct sit_info *sit = link->l_info; 490 491 IS_SIT_LINK_ASSERT(link); 492 493 sit->tos = tos; 494 sit->sit_mask |= SIT_ATTR_TOS; 495 496 return 0; 497 } 498 499 /** 500 * Get SIT tunnel tos 501 * @arg link Link object 502 * 503 * @return tos value 504 */ 505 uint8_t rtnl_link_sit_get_tos(struct rtnl_link *link) 506 { 507 struct sit_info *sit = link->l_info; 508 509 IS_SIT_LINK_ASSERT(link); 510 511 return sit->tos; 512 } 513 514 /** 515 * Set SIT tunnel path MTU discovery 516 * @arg link Link object 517 * @arg pmtudisc path MTU discovery 518 * 519 * @return 0 on success or a negative error code 520 */ 521 int rtnl_link_sit_set_pmtudisc(struct rtnl_link *link, uint8_t pmtudisc) 522 { 523 struct sit_info *sit = link->l_info; 524 525 IS_SIT_LINK_ASSERT(link); 526 527 sit->pmtudisc = pmtudisc; 528 sit->sit_mask |= SIT_ATTR_PMTUDISC; 529 530 return 0; 531 } 532 533 /** 534 * Get SIT path MTU discovery 535 * @arg link Link object 536 * 537 * @return pmtudisc value 538 */ 539 uint8_t rtnl_link_sit_get_pmtudisc(struct rtnl_link *link) 540 { 541 struct sit_info *sit = link->l_info; 542 543 IS_SIT_LINK_ASSERT(link); 544 545 return sit->pmtudisc; 546 } 547 548 /** 549 * Set SIT tunnel flags 550 * @arg link Link object 551 * @arg flags tunnel flags 552 * 553 * @return 0 on success or a negative error code 554 */ 555 int rtnl_link_sit_set_flags(struct rtnl_link *link, uint16_t flags) 556 { 557 struct sit_info *sit = link->l_info; 558 559 IS_SIT_LINK_ASSERT(link); 560 561 sit->flags = flags; 562 sit->sit_mask |= SIT_ATTR_FLAGS; 563 564 return 0; 565 } 566 567 /** 568 * Get SIT path flags 569 * @arg link Link object 570 * 571 * @return flags value 572 */ 573 uint16_t rtnl_link_sit_get_flags(struct rtnl_link *link) 574 { 575 struct sit_info *sit = link->l_info; 576 577 IS_SIT_LINK_ASSERT(link); 578 579 return sit->flags; 580 } 581 582 /** 583 * Set SIT tunnel proto 584 * @arg link Link object 585 * @arg proto tunnel proto 586 * 587 * @return 0 on success or a negative error code 588 */ 589 int rtnl_link_sit_set_proto(struct rtnl_link *link, uint8_t proto) 590 { 591 struct sit_info *sit = link->l_info; 592 593 IS_SIT_LINK_ASSERT(link); 594 595 sit->proto = proto; 596 sit->sit_mask |= SIT_ATTR_PROTO; 597 598 return 0; 599 } 600 601 /** 602 * Get SIT proto 603 * @arg link Link object 604 * 605 * @return proto value 606 */ 607 uint8_t rtnl_link_sit_get_proto(struct rtnl_link *link) 608 { 609 struct sit_info *sit = link->l_info; 610 611 IS_SIT_LINK_ASSERT(link); 612 613 return sit->proto; 614 } 615 616 static void __init sit_init(void) 617 { 618 rtnl_link_register_info(&sit_info_ops); 619 } 620 621 static void __exit sit_exit(void) 622 { 623 rtnl_link_unregister_info(&sit_info_ops); 624 } 625