iplink_vxlan.c revision e79c327edddba0f1f70528ab4cf8ce37227054a6
1/* 2 * iplink_vxlan.c VXLAN device support 3 * 4 * This program is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU General Public License 6 * as published by the Free Software Foundation; either version 7 * 2 of the License, or (at your option) any later version. 8 * 9 * Authors: Stephen Hemminger <shemminger@vyatta.com 10 */ 11 12#include <stdio.h> 13#include <stdlib.h> 14#include <string.h> 15#include <net/if.h> 16#include <linux/ip.h> 17#include <linux/if_link.h> 18#include <arpa/inet.h> 19 20#include "rt_names.h" 21#include "utils.h" 22#include "ip_common.h" 23 24static void print_explain(FILE *f) 25{ 26 fprintf(f, "Usage: ... vxlan id VNI [ { group | remote } ADDR ] [ local ADDR ]\n"); 27 fprintf(f, " [ ttl TTL ] [ tos TOS ] [ dev PHYS_DEV ]\n"); 28 fprintf(f, " [ dstport PORT ] [ srcport MIN MAX ]\n"); 29 fprintf(f, " [ [no]learning ] [ [no]proxy ] [ [no]rsc ]\n"); 30 fprintf(f, " [ [no]l2miss ] [ [no]l3miss ]\n"); 31 fprintf(f, " [ ageing SECONDS ] [ maxaddress NUMBER ]\n"); 32 fprintf(f, " [ [no]udpcsum ] [ [no]udp6zerocsumtx ] [ [no]udp6zerocsumrx ]\n"); 33 fprintf(f, " [ [no]remcsumtx ] [ [no]remcsumrx ]\n"); 34 fprintf(f, " [ [no]external ] [ gbp ]\n"); 35 fprintf(f, "\n"); 36 fprintf(f, "Where: VNI := 0-16777215\n"); 37 fprintf(f, " ADDR := { IP_ADDRESS | any }\n"); 38 fprintf(f, " TOS := { NUMBER | inherit }\n"); 39 fprintf(f, " TTL := { 1..255 | inherit }\n"); 40} 41 42static void explain(void) 43{ 44 print_explain(stderr); 45} 46 47static int vxlan_parse_opt(struct link_util *lu, int argc, char **argv, 48 struct nlmsghdr *n) 49{ 50 __u32 vni = 0; 51 int vni_set = 0; 52 __u32 saddr = 0; 53 __u32 gaddr = 0; 54 __u32 daddr = 0; 55 struct in6_addr saddr6 = IN6ADDR_ANY_INIT; 56 struct in6_addr gaddr6 = IN6ADDR_ANY_INIT; 57 struct in6_addr daddr6 = IN6ADDR_ANY_INIT; 58 unsigned link = 0; 59 __u8 tos = 0; 60 __u8 ttl = 0; 61 __u8 learning = 1; 62 __u8 proxy = 0; 63 __u8 rsc = 0; 64 __u8 l2miss = 0; 65 __u8 l3miss = 0; 66 __u8 noage = 0; 67 __u32 age = 0; 68 __u32 maxaddr = 0; 69 __u16 dstport = 0; 70 __u8 udpcsum = 0; 71 __u8 udp6zerocsumtx = 0; 72 __u8 udp6zerocsumrx = 0; 73 __u8 remcsumtx = 0; 74 __u8 remcsumrx = 0; 75 __u8 metadata = 0; 76 __u8 gbp = 0; 77 int dst_port_set = 0; 78 struct ifla_vxlan_port_range range = { 0, 0 }; 79 80 while (argc > 0) { 81 if (!matches(*argv, "id") || 82 !matches(*argv, "vni")) { 83 NEXT_ARG(); 84 if (get_u32(&vni, *argv, 0) || 85 vni >= 1u << 24) 86 invarg("invalid id", *argv); 87 vni_set = 1; 88 } else if (!matches(*argv, "group")) { 89 NEXT_ARG(); 90 if (!inet_get_addr(*argv, &gaddr, &gaddr6)) { 91 fprintf(stderr, "Invalid address \"%s\"\n", *argv); 92 return -1; 93 } 94 if (!IN6_IS_ADDR_MULTICAST(&gaddr6) && !IN_MULTICAST(ntohl(gaddr))) 95 invarg("invalid group address", *argv); 96 } else if (!matches(*argv, "remote")) { 97 NEXT_ARG(); 98 if (!inet_get_addr(*argv, &daddr, &daddr6)) { 99 fprintf(stderr, "Invalid address \"%s\"\n", *argv); 100 return -1; 101 } 102 if (IN6_IS_ADDR_MULTICAST(&daddr6) || IN_MULTICAST(ntohl(daddr))) 103 invarg("invalid remote address", *argv); 104 } else if (!matches(*argv, "local")) { 105 NEXT_ARG(); 106 if (strcmp(*argv, "any")) { 107 if (!inet_get_addr(*argv, &saddr, &saddr6)) { 108 fprintf(stderr, "Invalid address \"%s\"\n", *argv); 109 return -1; 110 } 111 } 112 113 if (IN_MULTICAST(ntohl(saddr)) || IN6_IS_ADDR_MULTICAST(&saddr6)) 114 invarg("invalid local address", *argv); 115 } else if (!matches(*argv, "dev")) { 116 NEXT_ARG(); 117 link = if_nametoindex(*argv); 118 if (link == 0) { 119 fprintf(stderr, "Cannot find device \"%s\"\n", 120 *argv); 121 exit(-1); 122 } 123 } else if (!matches(*argv, "ttl") || 124 !matches(*argv, "hoplimit")) { 125 unsigned uval; 126 127 NEXT_ARG(); 128 if (strcmp(*argv, "inherit") != 0) { 129 if (get_unsigned(&uval, *argv, 0)) 130 invarg("invalid TTL", *argv); 131 if (uval > 255) 132 invarg("TTL must be <= 255", *argv); 133 ttl = uval; 134 } 135 } else if (!matches(*argv, "tos") || 136 !matches(*argv, "dsfield")) { 137 __u32 uval; 138 139 NEXT_ARG(); 140 if (strcmp(*argv, "inherit") != 0) { 141 if (rtnl_dsfield_a2n(&uval, *argv)) 142 invarg("bad TOS value", *argv); 143 tos = uval; 144 } else 145 tos = 1; 146 } else if (!matches(*argv, "ageing")) { 147 NEXT_ARG(); 148 if (strcmp(*argv, "none") == 0) 149 noage = 1; 150 else if (get_u32(&age, *argv, 0)) 151 invarg("ageing timer", *argv); 152 } else if (!matches(*argv, "maxaddress")) { 153 NEXT_ARG(); 154 if (strcmp(*argv, "unlimited") == 0) 155 maxaddr = 0; 156 else if (get_u32(&maxaddr, *argv, 0)) 157 invarg("max addresses", *argv); 158 } else if (!matches(*argv, "port") || 159 !matches(*argv, "srcport")) { 160 __u16 minport, maxport; 161 NEXT_ARG(); 162 if (get_u16(&minport, *argv, 0)) 163 invarg("min port", *argv); 164 NEXT_ARG(); 165 if (get_u16(&maxport, *argv, 0)) 166 invarg("max port", *argv); 167 range.low = htons(minport); 168 range.high = htons(maxport); 169 } else if (!matches(*argv, "dstport")){ 170 NEXT_ARG(); 171 if (get_u16(&dstport, *argv, 0)) 172 invarg("dst port", *argv); 173 dst_port_set = 1; 174 } else if (!matches(*argv, "nolearning")) { 175 learning = 0; 176 } else if (!matches(*argv, "learning")) { 177 learning = 1; 178 } else if (!matches(*argv, "noproxy")) { 179 proxy = 0; 180 } else if (!matches(*argv, "proxy")) { 181 proxy = 1; 182 } else if (!matches(*argv, "norsc")) { 183 rsc = 0; 184 } else if (!matches(*argv, "rsc")) { 185 rsc = 1; 186 } else if (!matches(*argv, "nol2miss")) { 187 l2miss = 0; 188 } else if (!matches(*argv, "l2miss")) { 189 l2miss = 1; 190 } else if (!matches(*argv, "nol3miss")) { 191 l3miss = 0; 192 } else if (!matches(*argv, "l3miss")) { 193 l3miss = 1; 194 } else if (!matches(*argv, "udpcsum")) { 195 udpcsum = 1; 196 } else if (!matches(*argv, "noudpcsum")) { 197 udpcsum = 0; 198 } else if (!matches(*argv, "udp6zerocsumtx")) { 199 udp6zerocsumtx = 1; 200 } else if (!matches(*argv, "noudp6zerocsumtx")) { 201 udp6zerocsumtx = 0; 202 } else if (!matches(*argv, "udp6zerocsumrx")) { 203 udp6zerocsumrx = 1; 204 } else if (!matches(*argv, "noudp6zerocsumrx")) { 205 udp6zerocsumrx = 0; 206 } else if (!matches(*argv, "remcsumtx")) { 207 remcsumtx = 1; 208 } else if (!matches(*argv, "noremcsumtx")) { 209 remcsumtx = 0; 210 } else if (!matches(*argv, "remcsumrx")) { 211 remcsumrx = 1; 212 } else if (!matches(*argv, "noremcsumrx")) { 213 remcsumrx = 0; 214 } else if (!matches(*argv, "external")) { 215 metadata = 1; 216 } else if (!matches(*argv, "noexternal")) { 217 metadata = 0; 218 } else if (!matches(*argv, "gbp")) { 219 gbp = 1; 220 } else if (matches(*argv, "help") == 0) { 221 explain(); 222 return -1; 223 } else { 224 fprintf(stderr, "vxlan: unknown command \"%s\"?\n", *argv); 225 explain(); 226 return -1; 227 } 228 argc--, argv++; 229 } 230 231 if (metadata && vni_set) { 232 fprintf(stderr, "vxlan: both 'external' and vni cannot be specified\n"); 233 return -1; 234 } 235 236 if (!metadata && !vni_set) { 237 fprintf(stderr, "vxlan: missing virtual network identifier\n"); 238 return -1; 239 } 240 241 if ((gaddr && daddr) || 242 (memcmp(&gaddr6, &in6addr_any, sizeof(gaddr6)) && 243 memcmp(&daddr6, &in6addr_any, sizeof(daddr6)))) { 244 fprintf(stderr, "vxlan: both group and remote cannot be specified\n"); 245 return -1; 246 } 247 248 if (!dst_port_set) { 249 fprintf(stderr, "vxlan: destination port not specified\n" 250 "Will use Linux kernel default (non-standard value)\n"); 251 fprintf(stderr, 252 "Use 'dstport 4789' to get the IANA assigned value\n" 253 "Use 'dstport 0' to get default and quiet this message\n"); 254 } 255 256 addattr32(n, 1024, IFLA_VXLAN_ID, vni); 257 if (gaddr) 258 addattr_l(n, 1024, IFLA_VXLAN_GROUP, &gaddr, 4); 259 else if (daddr) 260 addattr_l(n, 1024, IFLA_VXLAN_GROUP, &daddr, 4); 261 if (memcmp(&gaddr6, &in6addr_any, sizeof(gaddr6)) != 0) 262 addattr_l(n, 1024, IFLA_VXLAN_GROUP6, &gaddr6, sizeof(struct in6_addr)); 263 else if (memcmp(&daddr6, &in6addr_any, sizeof(daddr6)) != 0) 264 addattr_l(n, 1024, IFLA_VXLAN_GROUP6, &daddr6, sizeof(struct in6_addr)); 265 266 if (saddr) 267 addattr_l(n, 1024, IFLA_VXLAN_LOCAL, &saddr, 4); 268 else if (memcmp(&saddr6, &in6addr_any, sizeof(saddr6)) != 0) 269 addattr_l(n, 1024, IFLA_VXLAN_LOCAL6, &saddr6, sizeof(struct in6_addr)); 270 271 if (link) 272 addattr32(n, 1024, IFLA_VXLAN_LINK, link); 273 addattr8(n, 1024, IFLA_VXLAN_TTL, ttl); 274 addattr8(n, 1024, IFLA_VXLAN_TOS, tos); 275 addattr8(n, 1024, IFLA_VXLAN_LEARNING, learning); 276 addattr8(n, 1024, IFLA_VXLAN_PROXY, proxy); 277 addattr8(n, 1024, IFLA_VXLAN_RSC, rsc); 278 addattr8(n, 1024, IFLA_VXLAN_L2MISS, l2miss); 279 addattr8(n, 1024, IFLA_VXLAN_L3MISS, l3miss); 280 addattr8(n, 1024, IFLA_VXLAN_UDP_CSUM, udpcsum); 281 addattr8(n, 1024, IFLA_VXLAN_UDP_ZERO_CSUM6_TX, udp6zerocsumtx); 282 addattr8(n, 1024, IFLA_VXLAN_UDP_ZERO_CSUM6_RX, udp6zerocsumrx); 283 addattr8(n, 1024, IFLA_VXLAN_REMCSUM_TX, remcsumtx); 284 addattr8(n, 1024, IFLA_VXLAN_REMCSUM_RX, remcsumrx); 285 addattr8(n, 1024, IFLA_VXLAN_COLLECT_METADATA, metadata); 286 287 if (noage) 288 addattr32(n, 1024, IFLA_VXLAN_AGEING, 0); 289 else if (age) 290 addattr32(n, 1024, IFLA_VXLAN_AGEING, age); 291 if (maxaddr) 292 addattr32(n, 1024, IFLA_VXLAN_LIMIT, maxaddr); 293 if (range.low || range.high) 294 addattr_l(n, 1024, IFLA_VXLAN_PORT_RANGE, 295 &range, sizeof(range)); 296 if (dstport) 297 addattr16(n, 1024, IFLA_VXLAN_PORT, htons(dstport)); 298 299 if (gbp) 300 addattr_l(n, 1024, IFLA_VXLAN_GBP, NULL, 0); 301 302 303 return 0; 304} 305 306static void vxlan_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) 307{ 308 __u32 vni; 309 unsigned link; 310 __u8 tos; 311 __u32 maxaddr; 312 char s1[1024]; 313 char s2[64]; 314 315 if (!tb) 316 return; 317 318 if (!tb[IFLA_VXLAN_ID] || 319 RTA_PAYLOAD(tb[IFLA_VXLAN_ID]) < sizeof(__u32)) 320 return; 321 322 vni = rta_getattr_u32(tb[IFLA_VXLAN_ID]); 323 fprintf(f, "id %u ", vni); 324 325 if (tb[IFLA_VXLAN_GROUP]) { 326 __be32 addr = rta_getattr_u32(tb[IFLA_VXLAN_GROUP]); 327 if (addr) { 328 if (IN_MULTICAST(ntohl(addr))) 329 fprintf(f, "group %s ", 330 format_host(AF_INET, 4, &addr, s1, sizeof(s1))); 331 else 332 fprintf(f, "remote %s ", 333 format_host(AF_INET, 4, &addr, s1, sizeof(s1))); 334 } 335 } else if (tb[IFLA_VXLAN_GROUP6]) { 336 struct in6_addr addr; 337 memcpy(&addr, RTA_DATA(tb[IFLA_VXLAN_GROUP6]), sizeof(struct in6_addr)); 338 if (memcmp(&addr, &in6addr_any, sizeof(addr)) != 0) { 339 if (IN6_IS_ADDR_MULTICAST(&addr)) 340 fprintf(f, "group %s ", 341 format_host(AF_INET6, sizeof(struct in6_addr), &addr, s1, sizeof(s1))); 342 else 343 fprintf(f, "remote %s ", 344 format_host(AF_INET6, sizeof(struct in6_addr), &addr, s1, sizeof(s1))); 345 } 346 } 347 348 if (tb[IFLA_VXLAN_LOCAL]) { 349 __be32 addr = rta_getattr_u32(tb[IFLA_VXLAN_LOCAL]); 350 if (addr) 351 fprintf(f, "local %s ", 352 format_host(AF_INET, 4, &addr, s1, sizeof(s1))); 353 } else if (tb[IFLA_VXLAN_LOCAL6]) { 354 struct in6_addr addr; 355 memcpy(&addr, RTA_DATA(tb[IFLA_VXLAN_LOCAL6]), sizeof(struct in6_addr)); 356 if (memcmp(&addr, &in6addr_any, sizeof(addr)) != 0) 357 fprintf(f, "local %s ", 358 format_host(AF_INET6, sizeof(struct in6_addr), &addr, s1, sizeof(s1))); 359 } 360 361 if (tb[IFLA_VXLAN_LINK] && 362 (link = rta_getattr_u32(tb[IFLA_VXLAN_LINK]))) { 363 const char *n = if_indextoname(link, s2); 364 365 if (n) 366 fprintf(f, "dev %s ", n); 367 else 368 fprintf(f, "dev %u ", link); 369 } 370 371 if (tb[IFLA_VXLAN_PORT_RANGE]) { 372 const struct ifla_vxlan_port_range *r 373 = RTA_DATA(tb[IFLA_VXLAN_PORT_RANGE]); 374 fprintf(f, "srcport %u %u ", ntohs(r->low), ntohs(r->high)); 375 } 376 377 if (tb[IFLA_VXLAN_PORT]) 378 fprintf(f, "dstport %u ", 379 ntohs(rta_getattr_u16(tb[IFLA_VXLAN_PORT]))); 380 381 if (tb[IFLA_VXLAN_LEARNING] && 382 !rta_getattr_u8(tb[IFLA_VXLAN_LEARNING])) 383 fputs("nolearning ", f); 384 385 if (tb[IFLA_VXLAN_PROXY] && rta_getattr_u8(tb[IFLA_VXLAN_PROXY])) 386 fputs("proxy ", f); 387 388 if (tb[IFLA_VXLAN_RSC] && rta_getattr_u8(tb[IFLA_VXLAN_RSC])) 389 fputs("rsc ", f); 390 391 if (tb[IFLA_VXLAN_L2MISS] && rta_getattr_u8(tb[IFLA_VXLAN_L2MISS])) 392 fputs("l2miss ", f); 393 394 if (tb[IFLA_VXLAN_L3MISS] && rta_getattr_u8(tb[IFLA_VXLAN_L3MISS])) 395 fputs("l3miss ", f); 396 397 if (tb[IFLA_VXLAN_TOS] && 398 (tos = rta_getattr_u8(tb[IFLA_VXLAN_TOS]))) { 399 if (tos == 1) 400 fprintf(f, "tos inherit "); 401 else 402 fprintf(f, "tos %#x ", tos); 403 } 404 405 if (tb[IFLA_VXLAN_TTL]) { 406 __u8 ttl = rta_getattr_u8(tb[IFLA_VXLAN_TTL]); 407 if (ttl) 408 fprintf(f, "ttl %d ", ttl); 409 } 410 411 if (tb[IFLA_VXLAN_AGEING]) { 412 __u32 age = rta_getattr_u32(tb[IFLA_VXLAN_AGEING]); 413 if (age == 0) 414 fprintf(f, "ageing none "); 415 else 416 fprintf(f, "ageing %u ", age); 417 } 418 419 if (tb[IFLA_VXLAN_LIMIT] && 420 ((maxaddr = rta_getattr_u32(tb[IFLA_VXLAN_LIMIT])) != 0)) 421 fprintf(f, "maxaddr %u ", maxaddr); 422 423 if (tb[IFLA_VXLAN_UDP_CSUM] && rta_getattr_u8(tb[IFLA_VXLAN_UDP_CSUM])) 424 fputs("udpcsum ", f); 425 426 if (tb[IFLA_VXLAN_UDP_ZERO_CSUM6_TX] && 427 rta_getattr_u8(tb[IFLA_VXLAN_UDP_ZERO_CSUM6_TX])) 428 fputs("udp6zerocsumtx ", f); 429 430 if (tb[IFLA_VXLAN_UDP_ZERO_CSUM6_RX] && 431 rta_getattr_u8(tb[IFLA_VXLAN_UDP_ZERO_CSUM6_RX])) 432 fputs("udp6zerocsumrx ", f); 433 434 if (tb[IFLA_VXLAN_REMCSUM_TX] && 435 rta_getattr_u8(tb[IFLA_VXLAN_REMCSUM_TX])) 436 fputs("remcsumtx ", f); 437 438 if (tb[IFLA_VXLAN_REMCSUM_RX] && 439 rta_getattr_u8(tb[IFLA_VXLAN_REMCSUM_RX])) 440 fputs("remcsumrx ", f); 441 442 if (tb[IFLA_VXLAN_COLLECT_METADATA] && 443 rta_getattr_u8(tb[IFLA_VXLAN_COLLECT_METADATA])) 444 fputs("external ", f); 445 446 if (tb[IFLA_VXLAN_GBP]) 447 fputs("gbp ", f); 448} 449 450static void vxlan_print_help(struct link_util *lu, int argc, char **argv, 451 FILE *f) 452{ 453 print_explain(f); 454} 455 456struct link_util vxlan_link_util = { 457 .id = "vxlan", 458 .maxattr = IFLA_VXLAN_MAX, 459 .parse_opt = vxlan_parse_opt, 460 .print_opt = vxlan_print_opt, 461 .print_help = vxlan_print_help, 462}; 463