1 /* 2 * lib/route/link/ipvti.c IPVTI 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 ipvti IPVTI 15 * ipvti link module 16 * 17 * @details 18 * \b Link Type Name: "ipvti" 19 * 20 * @route_doc{link_ipvti, IPVTI 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 IPVTI_ATTR_LINK (1 << 0) 35 #define IPVTI_ATTR_IKEY (1 << 1) 36 #define IPVTI_ATTR_OKEY (1 << 2) 37 #define IPVTI_ATTR_LOCAL (1 << 3) 38 #define IPVTI_ATTR_REMOTE (1 << 4) 39 40 struct ipvti_info 41 { 42 uint32_t link; 43 uint32_t ikey; 44 uint32_t okey; 45 uint32_t local; 46 uint32_t remote; 47 uint32_t ipvti_mask; 48 }; 49 50 static struct nla_policy ipvti_policy[IFLA_GRE_MAX + 1] = { 51 [IFLA_VTI_LINK] = { .type = NLA_U32 }, 52 [IFLA_VTI_IKEY] = { .type = NLA_U32 }, 53 [IFLA_VTI_OKEY] = { .type = NLA_U32 }, 54 [IFLA_VTI_LOCAL] = { .type = NLA_U32 }, 55 [IFLA_VTI_REMOTE] = { .type = NLA_U32 }, 56 }; 57 58 static int ipvti_alloc(struct rtnl_link *link) 59 { 60 struct ipvti_info *ipvti; 61 62 ipvti = calloc(1, sizeof(*ipvti)); 63 if (!ipvti) 64 return -NLE_NOMEM; 65 66 link->l_info = ipvti; 67 68 return 0; 69 } 70 71 static int ipvti_parse(struct rtnl_link *link, struct nlattr *data, 72 struct nlattr *xstats) 73 { 74 struct nlattr *tb[IFLA_IPTUN_MAX + 1]; 75 struct ipvti_info *ipvti; 76 int err; 77 78 NL_DBG(3, "Parsing IPVTI link info"); 79 80 err = nla_parse_nested(tb, IFLA_GRE_MAX, data, ipvti_policy); 81 if (err < 0) 82 goto errout; 83 84 err = ipvti_alloc(link); 85 if (err < 0) 86 goto errout; 87 88 ipvti = link->l_info; 89 90 if (tb[IFLA_VTI_LINK]) { 91 ipvti->link = nla_get_u32(tb[IFLA_VTI_LINK]); 92 ipvti->ipvti_mask |= IPVTI_ATTR_LINK; 93 } 94 95 if (tb[IFLA_VTI_IKEY]) { 96 ipvti->ikey = nla_get_u32(tb[IFLA_VTI_IKEY]); 97 ipvti->ipvti_mask |= IPVTI_ATTR_IKEY; 98 } 99 100 if (tb[IFLA_VTI_OKEY]) { 101 ipvti->okey = nla_get_u32(tb[IFLA_VTI_OKEY]); 102 ipvti->ipvti_mask |= IPVTI_ATTR_OKEY; 103 } 104 105 if (tb[IFLA_VTI_LOCAL]) { 106 ipvti->local = nla_get_u32(tb[IFLA_VTI_LOCAL]); 107 ipvti->ipvti_mask |= IPVTI_ATTR_LOCAL; 108 } 109 110 if (tb[IFLA_VTI_REMOTE]) { 111 ipvti->remote = nla_get_u32(tb[IFLA_VTI_REMOTE]); 112 ipvti->ipvti_mask |= IPVTI_ATTR_REMOTE; 113 } 114 115 err = 0; 116 117 errout: 118 return err; 119 } 120 121 static int ipvti_put_attrs(struct nl_msg *msg, struct rtnl_link *link) 122 { 123 struct ipvti_info *ipvti = link->l_info; 124 struct nlattr *data; 125 126 data = nla_nest_start(msg, IFLA_INFO_DATA); 127 if (!data) 128 return -NLE_MSGSIZE; 129 130 if (ipvti->ipvti_mask & IPVTI_ATTR_LINK) 131 NLA_PUT_U32(msg, IFLA_VTI_LINK, ipvti->link); 132 133 if (ipvti->ipvti_mask & IPVTI_ATTR_IKEY) 134 NLA_PUT_U32(msg, IFLA_VTI_IKEY, ipvti->ikey); 135 136 if (ipvti->ipvti_mask & IFLA_VTI_IKEY) 137 NLA_PUT_U32(msg, IFLA_VTI_OKEY, ipvti->okey); 138 139 if (ipvti->ipvti_mask & IPVTI_ATTR_LOCAL) 140 NLA_PUT_U32(msg, IFLA_VTI_LOCAL, ipvti->local); 141 142 if (ipvti->ipvti_mask & IPVTI_ATTR_REMOTE) 143 NLA_PUT_U32(msg, IFLA_VTI_REMOTE, ipvti->remote); 144 145 nla_nest_end(msg, data); 146 147 nla_put_failure: 148 149 return 0; 150 } 151 152 static void ipvti_free(struct rtnl_link *link) 153 { 154 struct ipvti_info *ipvti = link->l_info; 155 156 free(ipvti); 157 link->l_info = NULL; 158 } 159 160 static void ipvti_dump_line(struct rtnl_link *link, struct nl_dump_params *p) 161 { 162 nl_dump(p, "ipvti : %s", link->l_name); 163 } 164 165 static void ipvti_dump_details(struct rtnl_link *link, struct nl_dump_params *p) 166 { 167 struct ipvti_info *ipvti = link->l_info; 168 char *name, addr[INET_ADDRSTRLEN]; 169 170 if (ipvti->ipvti_mask & IPVTI_ATTR_LINK) { 171 nl_dump(p, " link "); 172 name = rtnl_link_get_name(link); 173 if (name) 174 nl_dump_line(p, "%s\n", name); 175 else 176 nl_dump_line(p, "%u\n", ipvti->link); 177 } 178 179 if (ipvti->ipvti_mask & IPVTI_ATTR_IKEY) { 180 nl_dump(p, " ikey "); 181 nl_dump_line(p, "%x\n",ipvti->ikey); 182 } 183 184 if (ipvti->ipvti_mask & IPVTI_ATTR_OKEY) { 185 nl_dump(p, " okey "); 186 nl_dump_line(p, "%x\n", ipvti->okey); 187 } 188 189 if (ipvti->ipvti_mask & IPVTI_ATTR_LOCAL) { 190 nl_dump(p, " local "); 191 if(inet_ntop(AF_INET, &ipvti->local, addr, sizeof(addr))) 192 nl_dump_line(p, "%s\n", addr); 193 else 194 nl_dump_line(p, "%#x\n", ntohs(ipvti->local)); 195 } 196 197 if (ipvti->ipvti_mask & IPVTI_ATTR_REMOTE) { 198 nl_dump(p, " remote "); 199 if(inet_ntop(AF_INET, &ipvti->remote, addr, sizeof(addr))) 200 nl_dump_line(p, "%s\n", addr); 201 else 202 nl_dump_line(p, "%#x\n", ntohs(ipvti->remote)); 203 } 204 } 205 206 static int ipvti_clone(struct rtnl_link *dst, struct rtnl_link *src) 207 { 208 struct ipvti_info *ipvti_dst, *ipvti_src = src->l_info; 209 int err; 210 211 dst->l_info = NULL; 212 213 err = rtnl_link_set_type(dst, "vti"); 214 if (err < 0) 215 return err; 216 217 ipvti_dst = dst->l_info; 218 219 if (!ipvti_dst || !ipvti_src) 220 BUG(); 221 222 memcpy(ipvti_dst, ipvti_src, sizeof(struct ipvti_info)); 223 224 return 0; 225 } 226 227 static struct rtnl_link_info_ops ipvti_info_ops = { 228 .io_name = "vti", 229 .io_alloc = ipvti_alloc, 230 .io_parse = ipvti_parse, 231 .io_dump = { 232 [NL_DUMP_LINE] = ipvti_dump_line, 233 [NL_DUMP_DETAILS] = ipvti_dump_details, 234 }, 235 .io_clone = ipvti_clone, 236 .io_put_attrs = ipvti_put_attrs, 237 .io_free = ipvti_free, 238 }; 239 240 #define IS_IPVTI_LINK_ASSERT(link) \ 241 if ((link)->l_info_ops != &ipvti_info_ops) { \ 242 APPBUG("Link is not a ipvti link. set type \vti\" first."); \ 243 return -NLE_OPNOTSUPP; \ 244 } 245 246 struct rtnl_link *rtnl_link_ipvti_alloc(void) 247 { 248 struct rtnl_link *link; 249 int err; 250 251 link = rtnl_link_alloc(); 252 if (!link) 253 return NULL; 254 255 err = rtnl_link_set_type(link, "vti"); 256 if (err < 0) { 257 rtnl_link_put(link); 258 return NULL; 259 } 260 261 return link; 262 } 263 264 /** 265 * Check if link is a IPVTI link 266 * @arg link Link object 267 * 268 * @return True if link is a IPVTI link, otherwise 0 is returned. 269 */ 270 int rtnl_link_is_ipvti(struct rtnl_link *link) 271 { 272 return link->l_info_ops && !strcmp(link->l_info_ops->io_name, "vti"); 273 } 274 /** 275 * Create a new ipvti tunnel device 276 * @arg sock netlink socket 277 * @arg name name of the tunnel deviceL 278 * 279 * Creates a new ipvti tunnel device in the kernel 280 * @return 0 on success or a negative error code 281 */ 282 int rtnl_link_ipvti_add(struct nl_sock *sk, const char *name) 283 { 284 struct rtnl_link *link; 285 int err; 286 287 link = rtnl_link_ipvti_alloc(); 288 if (!link) 289 return -NLE_NOMEM; 290 291 if(name) 292 rtnl_link_set_name(link, name); 293 294 err = rtnl_link_add(sk, link, NLM_F_CREATE); 295 rtnl_link_put(link); 296 297 return err; 298 } 299 /** 300 * Set IPVTI tunnel interface index 301 * @arg link Link object 302 * @arg index interface index 303 * 304 * @return 0 on success or a negative error code 305 */ 306 int rtnl_link_ipvti_set_link(struct rtnl_link *link, uint32_t index) 307 { 308 struct ipvti_info *ipvti = link->l_info; 309 310 IS_IPVTI_LINK_ASSERT(link); 311 312 ipvti->link = index; 313 ipvti->ipvti_mask |= IPVTI_ATTR_LINK; 314 315 return 0; 316 } 317 318 /** 319 * Get IPVTI tunnel interface index 320 * @arg link Link object 321 * 322 * @return interface index 323 */ 324 uint32_t rtnl_link_ipvti_get_link(struct rtnl_link *link) 325 { 326 struct ipvti_info *ipvti = link->l_info; 327 328 IS_IPVTI_LINK_ASSERT(link); 329 330 return ipvti->link; 331 } 332 333 /** 334 * Set IPVTI tunnel set ikey 335 * @arg link Link object 336 * @arg ikey gre ikey 337 * 338 * @return 0 on success or a negative error code 339 */ 340 int rtnl_link_ipvti_set_ikey(struct rtnl_link *link, uint32_t ikey) 341 { 342 struct ipvti_info *ipvti = link->l_info; 343 344 IS_IPVTI_LINK_ASSERT(link); 345 346 ipvti->ikey = ikey; 347 ipvti->ipvti_mask |= IPVTI_ATTR_IKEY; 348 349 return 0; 350 } 351 352 /** 353 * Get IPVTI tunnel ikey 354 * @arg link Link object 355 * 356 * @return ikey 357 */ 358 uint32_t rtnl_link_ipvti_get_ikey(struct rtnl_link *link) 359 { 360 struct ipvti_info *ipvti = link->l_info; 361 362 IS_IPVTI_LINK_ASSERT(link); 363 364 return ipvti->ikey; 365 } 366 367 /** 368 * Set IPVTI tunnel set okey 369 * @arg link Link object 370 * @arg okey gre okey 371 * 372 * @return 0 on success or a negative error code 373 */ 374 int rtnl_link_ipvti_set_okey(struct rtnl_link *link, uint32_t okey) 375 { 376 struct ipvti_info *ipvti = link->l_info; 377 378 IS_IPVTI_LINK_ASSERT(link); 379 380 ipvti->okey = okey; 381 ipvti->ipvti_mask |= IPVTI_ATTR_OKEY; 382 383 return 0; 384 } 385 386 /** 387 * Get IPVTI tunnel okey 388 * @arg link Link object 389 * 390 * @return okey value 391 */ 392 uint32_t rtnl_link_ipvti_get_okey(struct rtnl_link *link) 393 { 394 struct ipvti_info *ipvti = link->l_info; 395 396 IS_IPVTI_LINK_ASSERT(link); 397 398 return ipvti->okey; 399 } 400 401 /** 402 * Set IPVTI tunnel local address 403 * @arg link Link object 404 * @arg addr local address 405 * 406 * @return 0 on success or a negative error code 407 */ 408 int rtnl_link_ipvti_set_local(struct rtnl_link *link, uint32_t addr) 409 { 410 struct ipvti_info *ipvti = link->l_info; 411 412 IS_IPVTI_LINK_ASSERT(link); 413 414 ipvti->local = addr; 415 ipvti->ipvti_mask |= IPVTI_ATTR_LOCAL; 416 417 return 0; 418 } 419 420 /** 421 * Get IPVTI tunnel local address 422 * @arg link Link object 423 * 424 * @return local address 425 */ 426 uint32_t rtnl_link_ipvti_get_local(struct rtnl_link *link) 427 { 428 struct ipvti_info *ipvti = link->l_info; 429 430 IS_IPVTI_LINK_ASSERT(link); 431 432 return ipvti->local; 433 } 434 435 /** 436 * Set IPVTI tunnel remote address 437 * @arg link Link object 438 * @arg remote remote address 439 * 440 * @return 0 on success or a negative error code 441 */ 442 int rtnl_link_ipvti_set_remote(struct rtnl_link *link, uint32_t remote) 443 { 444 struct ipvti_info *ipvti = link->l_info; 445 446 IS_IPVTI_LINK_ASSERT(link); 447 448 ipvti->remote = remote; 449 ipvti->ipvti_mask |= IPVTI_ATTR_REMOTE; 450 451 return 0; 452 } 453 454 /** 455 * Get IPVTI tunnel remote address 456 * @arg link Link object 457 * 458 * @return remote address on success or a negative error code 459 */ 460 uint32_t rtnl_link_ipvti_get_remote(struct rtnl_link *link) 461 { 462 struct ipvti_info *ipvti = link->l_info; 463 464 IS_IPVTI_LINK_ASSERT(link); 465 466 return ipvti->remote; 467 } 468 469 static void __init ipvti_init(void) 470 { 471 rtnl_link_register_info(&ipvti_info_ops); 472 } 473 474 static void __exit ipvti_exit(void) 475 { 476 rtnl_link_unregister_info(&ipvti_info_ops); 477 } 478