1/* 2 * lib/route/link/ipip.c IPIP 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 ipip IPIP 15 * ipip link module 16 * 17 * @details 18 * \b Link Type Name: "ipip" 19 * 20 * @route_doc{link_ipip, IPIP 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 IPIP_ATTR_LINK (1 << 0) 35#define IPIP_ATTR_LOCAL (1 << 1) 36#define IPIP_ATTR_REMOTE (1 << 2) 37#define IPIP_ATTR_TTL (1 << 3) 38#define IPIP_ATTR_TOS (1 << 4) 39#define IPIP_ATTR_PMTUDISC (1 << 5) 40 41struct ipip_info 42{ 43 uint8_t ttl; 44 uint8_t tos; 45 uint8_t pmtudisc; 46 uint32_t link; 47 uint32_t local; 48 uint32_t remote; 49 uint32_t ipip_mask; 50}; 51 52static struct nla_policy ipip_policy[IFLA_IPTUN_MAX + 1] = { 53 [IFLA_IPTUN_LINK] = { .type = NLA_U32 }, 54 [IFLA_IPTUN_LOCAL] = { .type = NLA_U32 }, 55 [IFLA_IPTUN_REMOTE] = { .type = NLA_U32 }, 56 [IFLA_IPTUN_TTL] = { .type = NLA_U8 }, 57 [IFLA_IPTUN_TOS] = { .type = NLA_U8 }, 58 [IFLA_IPTUN_PMTUDISC] = { .type = NLA_U8 }, 59}; 60 61static int ipip_alloc(struct rtnl_link *link) 62{ 63 struct ipip_info *ipip; 64 65 ipip = calloc(1, sizeof(*ipip)); 66 if (!ipip) 67 return -NLE_NOMEM; 68 69 link->l_info = ipip; 70 71 return 0; 72} 73 74static int ipip_parse(struct rtnl_link *link, struct nlattr *data, 75 struct nlattr *xstats) 76{ 77 struct nlattr *tb[IFLA_IPTUN_MAX + 1]; 78 struct ipip_info *ipip; 79 int err; 80 81 NL_DBG(3, "Parsing IPIP link info"); 82 83 err = nla_parse_nested(tb, IFLA_IPTUN_MAX, data, ipip_policy); 84 if (err < 0) 85 goto errout; 86 87 err = ipip_alloc(link); 88 if (err < 0) 89 goto errout; 90 91 ipip = link->l_info; 92 93 if (tb[IFLA_IPTUN_LINK]) { 94 ipip->link = nla_get_u32(tb[IFLA_IPTUN_LINK]); 95 ipip->ipip_mask |= IPIP_ATTR_LINK; 96 } 97 98 if (tb[IFLA_IPTUN_LOCAL]) { 99 ipip->local = nla_get_u32(tb[IFLA_IPTUN_LOCAL]); 100 ipip->ipip_mask |= IPIP_ATTR_LOCAL; 101 } 102 103 if (tb[IFLA_IPTUN_REMOTE]) { 104 ipip->remote = nla_get_u32(tb[IFLA_IPTUN_REMOTE]); 105 ipip->ipip_mask |= IPIP_ATTR_REMOTE; 106 } 107 108 if (tb[IFLA_IPTUN_TTL]) { 109 ipip->ttl = nla_get_u8(tb[IFLA_IPTUN_TTL]); 110 ipip->ipip_mask |= IPIP_ATTR_TTL; 111 } 112 113 if (tb[IFLA_IPTUN_TOS]) { 114 ipip->tos = nla_get_u8(tb[IFLA_IPTUN_TOS]); 115 ipip->ipip_mask |= IPIP_ATTR_TOS; 116 } 117 118 if (tb[IFLA_IPTUN_PMTUDISC]) { 119 ipip->pmtudisc = nla_get_u8(tb[IFLA_IPTUN_PMTUDISC]); 120 ipip->ipip_mask |= IPIP_ATTR_PMTUDISC; 121 } 122 123 err = 0; 124 125errout: 126 return err; 127} 128 129static int ipip_put_attrs(struct nl_msg *msg, struct rtnl_link *link) 130{ 131 struct ipip_info *ipip = link->l_info; 132 struct nlattr *data; 133 134 data = nla_nest_start(msg, IFLA_INFO_DATA); 135 if (!data) 136 return -NLE_MSGSIZE; 137 138 if (ipip->ipip_mask & IPIP_ATTR_LINK) 139 NLA_PUT_U32(msg, IFLA_IPTUN_LINK, ipip->link); 140 141 if (ipip->ipip_mask & IPIP_ATTR_LOCAL) 142 NLA_PUT_U32(msg, IFLA_IPTUN_LOCAL, ipip->local); 143 144 if (ipip->ipip_mask & IPIP_ATTR_REMOTE) 145 NLA_PUT_U32(msg, IFLA_IPTUN_REMOTE, ipip->remote); 146 147 if (ipip->ipip_mask & IPIP_ATTR_TTL) 148 NLA_PUT_U8(msg, IFLA_IPTUN_TTL, ipip->ttl); 149 150 if (ipip->ipip_mask & IPIP_ATTR_TOS) 151 NLA_PUT_U8(msg, IFLA_IPTUN_TOS, ipip->tos); 152 153 if (ipip->ipip_mask & IPIP_ATTR_PMTUDISC) 154 NLA_PUT_U8(msg, IFLA_IPTUN_PMTUDISC, ipip->pmtudisc); 155 156 nla_nest_end(msg, data); 157 158nla_put_failure: 159 return 0; 160} 161 162static void ipip_free(struct rtnl_link *link) 163{ 164 struct ipip_info *ipip = link->l_info; 165 166 free(ipip); 167 link->l_info = NULL; 168} 169 170static void ipip_dump_line(struct rtnl_link *link, struct nl_dump_params *p) 171{ 172 nl_dump(p, "ipip : %s", link->l_name); 173} 174 175static void ipip_dump_details(struct rtnl_link *link, struct nl_dump_params *p) 176{ 177 struct ipip_info *ipip = link->l_info; 178 char *name, addr[INET_ADDRSTRLEN]; 179 180 if (ipip->ipip_mask & IPIP_ATTR_LINK) { 181 nl_dump(p, " link "); 182 name = rtnl_link_get_name(link); 183 if (name) 184 nl_dump_line(p, "%s\n", name); 185 else 186 nl_dump_line(p, "%u\n", ipip->link); 187 } 188 189 if (ipip->ipip_mask & IPIP_ATTR_LOCAL) { 190 nl_dump(p, " local "); 191 if(inet_ntop(AF_INET, &ipip->local, addr, sizeof(addr))) 192 nl_dump_line(p, "%s\n", addr); 193 else 194 nl_dump_line(p, "%#x\n", ntohs(ipip->local)); 195 } 196 197 if (ipip->ipip_mask & IPIP_ATTR_REMOTE) { 198 nl_dump(p, " remote "); 199 if(inet_ntop(AF_INET, &ipip->remote, addr, sizeof(addr))) 200 nl_dump_line(p, "%s\n", addr); 201 else 202 nl_dump_line(p, "%#x\n", ntohs(ipip->remote)); 203 } 204 205 if (ipip->ipip_mask & IPIP_ATTR_TTL) { 206 nl_dump(p, " ttl "); 207 nl_dump_line(p, "%u\n", ipip->ttl); 208 } 209 210 if (ipip->ipip_mask & IPIP_ATTR_TOS) { 211 nl_dump(p, " tos "); 212 nl_dump_line(p, "%u\n", ipip->tos); 213 } 214 215 if (ipip->ipip_mask & IPIP_ATTR_PMTUDISC) { 216 nl_dump(p, " pmtudisc "); 217 nl_dump_line(p, "enabled (%#x)\n", ipip->pmtudisc); 218 } 219} 220 221static int ipip_clone(struct rtnl_link *dst, struct rtnl_link *src) 222{ 223 struct ipip_info *ipip_dst, *ipip_src = src->l_info; 224 int err; 225 226 dst->l_info = NULL; 227 228 err = rtnl_link_set_type(dst, "ipip"); 229 if (err < 0) 230 return err; 231 232 ipip_dst = dst->l_info; 233 234 if (!ipip_dst || !ipip_src) 235 BUG(); 236 237 memcpy(ipip_dst, ipip_src, sizeof(struct ipip_info)); 238 239 return 0; 240} 241 242static struct rtnl_link_info_ops ipip_info_ops = { 243 .io_name = "ipip", 244 .io_alloc = ipip_alloc, 245 .io_parse = ipip_parse, 246 .io_dump = { 247 [NL_DUMP_LINE] = ipip_dump_line, 248 [NL_DUMP_DETAILS] = ipip_dump_details, 249 }, 250 .io_clone = ipip_clone, 251 .io_put_attrs = ipip_put_attrs, 252 .io_free = ipip_free, 253}; 254 255#define IS_IPIP_LINK_ASSERT(link) \ 256 if ((link)->l_info_ops != &ipip_info_ops) { \ 257 APPBUG("Link is not a ipip link. set type \"ipip\" first."); \ 258 return -NLE_OPNOTSUPP; \ 259 } 260 261struct rtnl_link *rtnl_link_ipip_alloc(void) 262{ 263 struct rtnl_link *link; 264 int err; 265 266 link = rtnl_link_alloc(); 267 if (!link) 268 return NULL; 269 270 err = rtnl_link_set_type(link, "ipip"); 271 if (err < 0) { 272 rtnl_link_put(link); 273 return NULL; 274 } 275 276 return link; 277} 278 279/** 280 * Check if link is a IPIP link 281 * @arg link Link object 282 * 283 * @return True if link is a IPIP link, otherwise false is returned. 284 */ 285int rtnl_link_is_ipip(struct rtnl_link *link) 286{ 287 return link->l_info_ops && !strcmp(link->l_info_ops->io_name, "ipip"); 288} 289 290/** 291 * Create a new ipip tunnel device 292 * @arg sock netlink socket 293 * @arg name name of the tunnel deviceL 294 * 295 * Creates a new ipip tunnel device in the kernel 296 * @return 0 on success or a negative error code 297 */ 298int rtnl_link_ipip_add(struct nl_sock *sk, const char *name) 299{ 300 struct rtnl_link *link; 301 int err; 302 303 link = rtnl_link_ipip_alloc(); 304 if (!link) 305 return -NLE_NOMEM; 306 307 if(name) 308 rtnl_link_set_name(link, name); 309 310 err = rtnl_link_add(sk, link, NLM_F_CREATE); 311 rtnl_link_put(link); 312 313 return err; 314} 315 316/** 317 * Set IPIP tunnel interface index 318 * @arg link Link object 319 * @arg index interface index 320 * 321 * @return 0 on success or a negative error code 322 */ 323int rtnl_link_ipip_set_link(struct rtnl_link *link, uint32_t index) 324{ 325 struct ipip_info *ipip = link->l_info; 326 327 IS_IPIP_LINK_ASSERT(link); 328 329 ipip->link = index; 330 ipip->ipip_mask |= IPIP_ATTR_LINK; 331 332 return 0; 333} 334 335/** 336 * Get IPIP tunnel interface index 337 * @arg link Link object 338 * 339 * @return interface index value 340 */ 341uint32_t rtnl_link_ipip_get_link(struct rtnl_link *link) 342{ 343 struct ipip_info *ipip = link->l_info; 344 345 IS_IPIP_LINK_ASSERT(link); 346 347 return ipip->link; 348} 349 350/** 351 * Set IPIP tunnel local address 352 * @arg link Link object 353 * @arg addr local address 354 * 355 * @return 0 on success or a negative error code 356 */ 357int rtnl_link_ipip_set_local(struct rtnl_link *link, uint32_t addr) 358{ 359 struct ipip_info *ipip = link->l_info; 360 361 IS_IPIP_LINK_ASSERT(link); 362 363 ipip->local = addr; 364 ipip->ipip_mask |= IPIP_ATTR_LOCAL; 365 366 return 0; 367} 368 369/** 370 * Get IPIP tunnel local address 371 * @arg link Link object 372 * 373 * @return local address value 374 */ 375uint32_t rtnl_link_ipip_get_local(struct rtnl_link *link) 376{ 377 struct ipip_info *ipip = link->l_info; 378 379 IS_IPIP_LINK_ASSERT(link); 380 381 return ipip->local; 382} 383 384/** 385 * Set IPIP tunnel remote address 386 * @arg link Link object 387 * @arg remote remote address 388 * 389 * @return 0 on success or a negative error code 390 */ 391int rtnl_link_ipip_set_remote(struct rtnl_link *link, uint32_t addr) 392{ 393 struct ipip_info *ipip = link->l_info; 394 395 IS_IPIP_LINK_ASSERT(link); 396 397 ipip->remote = addr; 398 ipip->ipip_mask |= IPIP_ATTR_REMOTE; 399 400 return 0; 401} 402 403/** 404 * Get IPIP tunnel remote address 405 * @arg link Link object 406 * 407 * @return remote address 408 */ 409uint32_t rtnl_link_ipip_get_remote(struct rtnl_link *link) 410{ 411 struct ipip_info *ipip = link->l_info; 412 413 IS_IPIP_LINK_ASSERT(link); 414 415 return ipip->remote; 416} 417 418/** 419 * Set IPIP tunnel ttl 420 * @arg link Link object 421 * @arg ttl tunnel ttl 422 * 423 * @return 0 on success or a negative error code 424 */ 425int rtnl_link_ipip_set_ttl(struct rtnl_link *link, uint8_t ttl) 426{ 427 struct ipip_info *ipip = link->l_info; 428 429 IS_IPIP_LINK_ASSERT(link); 430 431 ipip->ttl = ttl; 432 ipip->ipip_mask |= IPIP_ATTR_TTL; 433 434 return 0; 435} 436 437/** 438 * Get IPIP tunnel ttl 439 * @arg link Link object 440 * 441 * @return ttl value 442 */ 443uint8_t rtnl_link_ipip_get_ttl(struct rtnl_link *link) 444{ 445 struct ipip_info *ipip = link->l_info; 446 447 IS_IPIP_LINK_ASSERT(link); 448 449 return ipip->ttl; 450} 451 452/** 453 * Set IPIP tunnel tos 454 * @arg link Link object 455 * @arg tos tunnel tos 456 * 457 * @return 0 on success or a negative error code 458 */ 459int rtnl_link_ipip_set_tos(struct rtnl_link *link, uint8_t tos) 460{ 461 struct ipip_info *ipip = link->l_info; 462 463 IS_IPIP_LINK_ASSERT(link); 464 465 ipip->tos = tos; 466 ipip->ipip_mask |= IPIP_ATTR_TOS; 467 468 return 0; 469} 470 471/** 472 * Get IPIP tunnel tos 473 * @arg link Link object 474 * 475 * @return tos value 476 */ 477uint8_t rtnl_link_ipip_get_tos(struct rtnl_link *link) 478{ 479 struct ipip_info *ipip = link->l_info; 480 481 IS_IPIP_LINK_ASSERT(link); 482 483 return ipip->tos; 484} 485 486/** 487 * Set IPIP tunnel path MTU discovery 488 * @arg link Link object 489 * @arg pmtudisc path MTU discovery 490 * 491 * @return 0 on success or a negative error code 492 */ 493int rtnl_link_ipip_set_pmtudisc(struct rtnl_link *link, uint8_t pmtudisc) 494{ 495 struct ipip_info *ipip = link->l_info; 496 497 IS_IPIP_LINK_ASSERT(link); 498 499 ipip->pmtudisc = pmtudisc; 500 ipip->ipip_mask |= IPIP_ATTR_PMTUDISC; 501 502 return 0; 503} 504 505/** 506 * Get IPIP path MTU discovery 507 * @arg link Link object 508 * 509 * @return pmtudisc value 510 */ 511uint8_t rtnl_link_ipip_get_pmtudisc(struct rtnl_link *link) 512{ 513 struct ipip_info *ipip = link->l_info; 514 515 IS_IPIP_LINK_ASSERT(link); 516 517 return ipip->pmtudisc; 518} 519 520static void __init ipip_init(void) 521{ 522 rtnl_link_register_info(&ipip_info_ops); 523} 524 525static void __exit ipip_exit(void) 526{ 527 rtnl_link_unregister_info(&ipip_info_ops); 528} 529