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 (at) 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 41 struct 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 52 static 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 61 static 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 74 static 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 125 errout: 126 return err; 127 } 128 129 static 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 158 nla_put_failure: 159 return 0; 160 } 161 162 static 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 170 static 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 175 static 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 221 static 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 242 static 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 261 struct 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 */ 285 int 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 */ 298 int 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 */ 323 int 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 */ 341 uint32_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 */ 357 int 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 */ 375 uint32_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 */ 391 int 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 */ 409 uint32_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 */ 425 int 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 */ 443 uint8_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 */ 459 int 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 */ 477 uint8_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 */ 493 int 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 */ 511 uint8_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 520 static void __init ipip_init(void) 521 { 522 rtnl_link_register_info(&ipip_info_ops); 523 } 524 525 static void __exit ipip_exit(void) 526 { 527 rtnl_link_unregister_info(&ipip_info_ops); 528 } 529