iproute2/ip/iplink_vxlan.c
<<
>>
Prefs
   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
  24#define VXLAN_ATTRSET(attrs, type) (((attrs) & (1L << (type))) != 0)
  25
  26static void print_explain(FILE *f)
  27{
  28        fprintf(f,
  29                "Usage: ... vxlan id VNI\n"
  30                "               [ { group | remote } IP_ADDRESS ]\n"
  31                "               [ local ADDR ]\n"
  32                "               [ ttl TTL ]\n"
  33                "               [ tos TOS ]\n"
  34                "               [ df DF ]\n"
  35                "               [ flowlabel LABEL ]\n"
  36                "               [ dev PHYS_DEV ]\n"
  37                "               [ dstport PORT ]\n"
  38                "               [ srcport MIN MAX ]\n"
  39                "               [ [no]learning ]\n"
  40                "               [ [no]proxy ]\n"
  41                "               [ [no]rsc ]\n"
  42                "               [ [no]l2miss ]\n"
  43                "               [ [no]l3miss ]\n"
  44                "               [ ageing SECONDS ]\n"
  45                "               [ maxaddress NUMBER ]\n"
  46                "               [ [no]udpcsum ]\n"
  47                "               [ [no]udp6zerocsumtx ]\n"
  48                "               [ [no]udp6zerocsumrx ]\n"
  49                "               [ [no]remcsumtx ] [ [no]remcsumrx ]\n"
  50                "               [ [no]external ] [ gbp ] [ gpe ]\n"
  51                "\n"
  52                "Where: VNI     := 0-16777215\n"
  53                "       ADDR    := { IP_ADDRESS | any }\n"
  54                "       TOS     := { NUMBER | inherit }\n"
  55                "       TTL     := { 1..255 | auto | inherit }\n"
  56                "       DF      := { unset | set | inherit }\n"
  57                "       LABEL := 0-1048575\n"
  58        );
  59}
  60
  61static void explain(void)
  62{
  63        print_explain(stderr);
  64}
  65
  66static void check_duparg(__u64 *attrs, int type, const char *key,
  67                         const char *argv)
  68{
  69        if (!VXLAN_ATTRSET(*attrs, type)) {
  70                *attrs |= (1L << type);
  71                return;
  72        }
  73        duparg2(key, argv);
  74}
  75
  76static int vxlan_parse_opt(struct link_util *lu, int argc, char **argv,
  77                          struct nlmsghdr *n)
  78{
  79        inet_prefix saddr, daddr;
  80        __u32 vni = 0;
  81        __u8 learning = 1;
  82        __u16 dstport = 0;
  83        __u8 metadata = 0;
  84        __u64 attrs = 0;
  85        bool set_op = (n->nlmsg_type == RTM_NEWLINK &&
  86                       !(n->nlmsg_flags & NLM_F_CREATE));
  87        bool selected_family = false;
  88
  89        saddr.family = daddr.family = AF_UNSPEC;
  90
  91        inet_prefix_reset(&saddr);
  92        inet_prefix_reset(&daddr);
  93
  94        while (argc > 0) {
  95                if (!matches(*argv, "id") ||
  96                    !matches(*argv, "vni")) {
  97                        /* We will add ID attribute outside of the loop since we
  98                         * need to consider metadata information as well.
  99                         */
 100                        NEXT_ARG();
 101                        check_duparg(&attrs, IFLA_VXLAN_ID, "id", *argv);
 102                        if (get_u32(&vni, *argv, 0) ||
 103                            vni >= 1u << 24)
 104                                invarg("invalid id", *argv);
 105                } else if (!matches(*argv, "group")) {
 106                        if (is_addrtype_inet_not_multi(&daddr)) {
 107                                fprintf(stderr, "vxlan: both group and remote");
 108                                fprintf(stderr, " cannot be specified\n");
 109                                return -1;
 110                        }
 111                        NEXT_ARG();
 112                        check_duparg(&attrs, IFLA_VXLAN_GROUP, "group", *argv);
 113                        get_addr(&daddr, *argv, saddr.family);
 114                        if (!is_addrtype_inet_multi(&daddr))
 115                                invarg("invalid group address", *argv);
 116                } else if (!matches(*argv, "remote")) {
 117                        if (is_addrtype_inet_multi(&daddr)) {
 118                                fprintf(stderr, "vxlan: both group and remote");
 119                                fprintf(stderr, " cannot be specified\n");
 120                                return -1;
 121                        }
 122                        NEXT_ARG();
 123                        check_duparg(&attrs, IFLA_VXLAN_GROUP, "remote", *argv);
 124                        get_addr(&daddr, *argv, saddr.family);
 125                        if (!is_addrtype_inet_not_multi(&daddr))
 126                                invarg("invalid remote address", *argv);
 127                } else if (!matches(*argv, "local")) {
 128                        NEXT_ARG();
 129                        check_duparg(&attrs, IFLA_VXLAN_LOCAL, "local", *argv);
 130                        get_addr(&saddr, *argv, daddr.family);
 131                        if (!is_addrtype_inet_not_multi(&saddr))
 132                                invarg("invalid local address", *argv);
 133                } else if (!matches(*argv, "dev")) {
 134                        unsigned int link;
 135
 136                        NEXT_ARG();
 137                        check_duparg(&attrs, IFLA_VXLAN_LINK, "dev", *argv);
 138                        link = ll_name_to_index(*argv);
 139                        if (!link)
 140                                exit(nodev(*argv));
 141                        addattr32(n, 1024, IFLA_VXLAN_LINK, link);
 142                } else if (!matches(*argv, "ttl") ||
 143                           !matches(*argv, "hoplimit")) {
 144                        unsigned int uval;
 145                        __u8 ttl = 0;
 146
 147                        NEXT_ARG();
 148                        check_duparg(&attrs, IFLA_VXLAN_TTL, "ttl", *argv);
 149                        if (strcmp(*argv, "inherit") == 0) {
 150                                addattr(n, 1024, IFLA_VXLAN_TTL_INHERIT);
 151                        } else if (strcmp(*argv, "auto") == 0) {
 152                                addattr8(n, 1024, IFLA_VXLAN_TTL, ttl);
 153                        } else {
 154                                if (get_unsigned(&uval, *argv, 0))
 155                                        invarg("invalid TTL", *argv);
 156                                if (uval > 255)
 157                                        invarg("TTL must be <= 255", *argv);
 158                                ttl = uval;
 159                                addattr8(n, 1024, IFLA_VXLAN_TTL, ttl);
 160                        }
 161                } else if (!matches(*argv, "tos") ||
 162                           !matches(*argv, "dsfield")) {
 163                        __u32 uval;
 164                        __u8 tos;
 165
 166                        NEXT_ARG();
 167                        check_duparg(&attrs, IFLA_VXLAN_TOS, "tos", *argv);
 168                        if (strcmp(*argv, "inherit") != 0) {
 169                                if (rtnl_dsfield_a2n(&uval, *argv))
 170                                        invarg("bad TOS value", *argv);
 171                                tos = uval;
 172                        } else
 173                                tos = 1;
 174                        addattr8(n, 1024, IFLA_VXLAN_TOS, tos);
 175                } else if (!matches(*argv, "df")) {
 176                        enum ifla_vxlan_df df;
 177
 178                        NEXT_ARG();
 179                        check_duparg(&attrs, IFLA_VXLAN_DF, "df", *argv);
 180                        if (strcmp(*argv, "unset") == 0)
 181                                df = VXLAN_DF_UNSET;
 182                        else if (strcmp(*argv, "set") == 0)
 183                                df = VXLAN_DF_SET;
 184                        else if (strcmp(*argv, "inherit") == 0)
 185                                df = VXLAN_DF_INHERIT;
 186                        else
 187                                invarg("DF must be 'unset', 'set' or 'inherit'",
 188                                       *argv);
 189
 190                        addattr8(n, 1024, IFLA_VXLAN_DF, df);
 191                } else if (!matches(*argv, "label") ||
 192                           !matches(*argv, "flowlabel")) {
 193                        __u32 uval;
 194
 195                        NEXT_ARG();
 196                        check_duparg(&attrs, IFLA_VXLAN_LABEL, "flowlabel",
 197                                     *argv);
 198                        if (get_u32(&uval, *argv, 0) ||
 199                            (uval & ~LABEL_MAX_MASK))
 200                                invarg("invalid flowlabel", *argv);
 201                        addattr32(n, 1024, IFLA_VXLAN_LABEL, htonl(uval));
 202                } else if (!matches(*argv, "ageing")) {
 203                        __u32 age;
 204
 205                        NEXT_ARG();
 206                        check_duparg(&attrs, IFLA_VXLAN_AGEING, "ageing",
 207                                     *argv);
 208                        if (strcmp(*argv, "none") == 0)
 209                                age = 0;
 210                        else if (get_u32(&age, *argv, 0))
 211                                invarg("ageing timer", *argv);
 212                        addattr32(n, 1024, IFLA_VXLAN_AGEING, age);
 213                } else if (!matches(*argv, "maxaddress")) {
 214                        __u32 maxaddr;
 215
 216                        NEXT_ARG();
 217                        check_duparg(&attrs, IFLA_VXLAN_LIMIT,
 218                                     "maxaddress", *argv);
 219                        if (strcmp(*argv, "unlimited") == 0)
 220                                maxaddr = 0;
 221                        else if (get_u32(&maxaddr, *argv, 0))
 222                                invarg("max addresses", *argv);
 223                        addattr32(n, 1024, IFLA_VXLAN_LIMIT, maxaddr);
 224                } else if (!matches(*argv, "port") ||
 225                           !matches(*argv, "srcport")) {
 226                        struct ifla_vxlan_port_range range = { 0, 0 };
 227
 228                        NEXT_ARG();
 229                        check_duparg(&attrs, IFLA_VXLAN_PORT_RANGE, "srcport",
 230                                     *argv);
 231                        if (get_be16(&range.low, *argv, 0))
 232                                invarg("min port", *argv);
 233                        NEXT_ARG();
 234                        if (get_be16(&range.high, *argv, 0))
 235                                invarg("max port", *argv);
 236                        if (range.low || range.high) {
 237                                addattr_l(n, 1024, IFLA_VXLAN_PORT_RANGE,
 238                                          &range, sizeof(range));
 239                        }
 240                } else if (!matches(*argv, "dstport")) {
 241                        NEXT_ARG();
 242                        check_duparg(&attrs, IFLA_VXLAN_PORT, "dstport", *argv);
 243                        if (get_u16(&dstport, *argv, 0))
 244                                invarg("dst port", *argv);
 245                } else if (!matches(*argv, "nolearning")) {
 246                        check_duparg(&attrs, IFLA_VXLAN_LEARNING, *argv, *argv);
 247                        learning = 0;
 248                } else if (!matches(*argv, "learning")) {
 249                        check_duparg(&attrs, IFLA_VXLAN_LEARNING, *argv, *argv);
 250                        learning = 1;
 251                } else if (!matches(*argv, "noproxy")) {
 252                        check_duparg(&attrs, IFLA_VXLAN_PROXY, *argv, *argv);
 253                        addattr8(n, 1024, IFLA_VXLAN_PROXY, 0);
 254                } else if (!matches(*argv, "proxy")) {
 255                        check_duparg(&attrs, IFLA_VXLAN_PROXY, *argv, *argv);
 256                        addattr8(n, 1024, IFLA_VXLAN_PROXY, 1);
 257                } else if (!matches(*argv, "norsc")) {
 258                        check_duparg(&attrs, IFLA_VXLAN_RSC, *argv, *argv);
 259                        addattr8(n, 1024, IFLA_VXLAN_RSC, 0);
 260                } else if (!matches(*argv, "rsc")) {
 261                        check_duparg(&attrs, IFLA_VXLAN_RSC, *argv, *argv);
 262                        addattr8(n, 1024, IFLA_VXLAN_RSC, 1);
 263                } else if (!matches(*argv, "nol2miss")) {
 264                        check_duparg(&attrs, IFLA_VXLAN_L2MISS, *argv, *argv);
 265                        addattr8(n, 1024, IFLA_VXLAN_L2MISS, 0);
 266                } else if (!matches(*argv, "l2miss")) {
 267                        check_duparg(&attrs, IFLA_VXLAN_L2MISS, *argv, *argv);
 268                        addattr8(n, 1024, IFLA_VXLAN_L2MISS, 1);
 269                } else if (!matches(*argv, "nol3miss")) {
 270                        check_duparg(&attrs, IFLA_VXLAN_L3MISS, *argv, *argv);
 271                        addattr8(n, 1024, IFLA_VXLAN_L3MISS, 0);
 272                } else if (!matches(*argv, "l3miss")) {
 273                        check_duparg(&attrs, IFLA_VXLAN_L3MISS, *argv, *argv);
 274                        addattr8(n, 1024, IFLA_VXLAN_L3MISS, 1);
 275                } else if (!matches(*argv, "udpcsum")) {
 276                        check_duparg(&attrs, IFLA_VXLAN_UDP_CSUM, *argv, *argv);
 277                        addattr8(n, 1024, IFLA_VXLAN_UDP_CSUM, 1);
 278                } else if (!matches(*argv, "noudpcsum")) {
 279                        check_duparg(&attrs, IFLA_VXLAN_UDP_CSUM, *argv, *argv);
 280                        addattr8(n, 1024, IFLA_VXLAN_UDP_CSUM, 0);
 281                } else if (!matches(*argv, "udp6zerocsumtx")) {
 282                        check_duparg(&attrs, IFLA_VXLAN_UDP_ZERO_CSUM6_TX,
 283                                     *argv, *argv);
 284                        addattr8(n, 1024, IFLA_VXLAN_UDP_ZERO_CSUM6_TX, 1);
 285                } else if (!matches(*argv, "noudp6zerocsumtx")) {
 286                        check_duparg(&attrs, IFLA_VXLAN_UDP_ZERO_CSUM6_TX,
 287                                     *argv, *argv);
 288                        addattr8(n, 1024, IFLA_VXLAN_UDP_ZERO_CSUM6_TX, 0);
 289                } else if (!matches(*argv, "udp6zerocsumrx")) {
 290                        check_duparg(&attrs, IFLA_VXLAN_UDP_ZERO_CSUM6_RX,
 291                                     *argv, *argv);
 292                        addattr8(n, 1024, IFLA_VXLAN_UDP_ZERO_CSUM6_RX, 1);
 293                } else if (!matches(*argv, "noudp6zerocsumrx")) {
 294                        check_duparg(&attrs, IFLA_VXLAN_UDP_ZERO_CSUM6_RX,
 295                                     *argv, *argv);
 296                        addattr8(n, 1024, IFLA_VXLAN_UDP_ZERO_CSUM6_RX, 0);
 297                } else if (!matches(*argv, "remcsumtx")) {
 298                        check_duparg(&attrs, IFLA_VXLAN_REMCSUM_TX,
 299                                     *argv, *argv);
 300                        addattr8(n, 1024, IFLA_VXLAN_REMCSUM_TX, 1);
 301                } else if (!matches(*argv, "noremcsumtx")) {
 302                        check_duparg(&attrs, IFLA_VXLAN_REMCSUM_TX,
 303                                     *argv, *argv);
 304                        addattr8(n, 1024, IFLA_VXLAN_REMCSUM_TX, 0);
 305                } else if (!matches(*argv, "remcsumrx")) {
 306                        check_duparg(&attrs, IFLA_VXLAN_REMCSUM_RX,
 307                                     *argv, *argv);
 308                        addattr8(n, 1024, IFLA_VXLAN_REMCSUM_RX, 1);
 309                } else if (!matches(*argv, "noremcsumrx")) {
 310                        check_duparg(&attrs, IFLA_VXLAN_REMCSUM_RX,
 311                                     *argv, *argv);
 312                        addattr8(n, 1024, IFLA_VXLAN_REMCSUM_RX, 0);
 313                } else if (!matches(*argv, "external")) {
 314                        check_duparg(&attrs, IFLA_VXLAN_COLLECT_METADATA,
 315                                     *argv, *argv);
 316                        metadata = 1;
 317                        learning = 0;
 318                        /* we will add LEARNING attribute outside of the loop */
 319                        addattr8(n, 1024, IFLA_VXLAN_COLLECT_METADATA,
 320                                 metadata);
 321                } else if (!matches(*argv, "noexternal")) {
 322                        check_duparg(&attrs, IFLA_VXLAN_COLLECT_METADATA,
 323                                     *argv, *argv);
 324                        metadata = 0;
 325                        addattr8(n, 1024, IFLA_VXLAN_COLLECT_METADATA,
 326                                 metadata);
 327                } else if (!matches(*argv, "gbp")) {
 328                        check_duparg(&attrs, IFLA_VXLAN_GBP, *argv, *argv);
 329                        addattr_l(n, 1024, IFLA_VXLAN_GBP, NULL, 0);
 330                } else if (!matches(*argv, "gpe")) {
 331                        check_duparg(&attrs, IFLA_VXLAN_GPE, *argv, *argv);
 332                        addattr_l(n, 1024, IFLA_VXLAN_GPE, NULL, 0);
 333                } else if (matches(*argv, "help") == 0) {
 334                        explain();
 335                        return -1;
 336                } else {
 337                        fprintf(stderr, "vxlan: unknown command \"%s\"?\n", *argv);
 338                        explain();
 339                        return -1;
 340                }
 341                argc--, argv++;
 342        }
 343
 344        if (metadata && VXLAN_ATTRSET(attrs, IFLA_VXLAN_ID)) {
 345                fprintf(stderr, "vxlan: both 'external' and vni cannot be specified\n");
 346                return -1;
 347        }
 348
 349        if (!metadata && !VXLAN_ATTRSET(attrs, IFLA_VXLAN_ID) && !set_op) {
 350                fprintf(stderr, "vxlan: missing virtual network identifier\n");
 351                return -1;
 352        }
 353
 354        if (is_addrtype_inet_multi(&daddr) &&
 355            !VXLAN_ATTRSET(attrs, IFLA_VXLAN_LINK)) {
 356                fprintf(stderr, "vxlan: 'group' requires 'dev' to be specified\n");
 357                return -1;
 358        }
 359
 360        if (!VXLAN_ATTRSET(attrs, IFLA_VXLAN_PORT) &&
 361            VXLAN_ATTRSET(attrs, IFLA_VXLAN_GPE)) {
 362                dstport = 4790;
 363        } else if (!VXLAN_ATTRSET(attrs, IFLA_VXLAN_PORT) && !set_op) {
 364                fprintf(stderr, "vxlan: destination port not specified\n"
 365                        "Will use Linux kernel default (non-standard value)\n");
 366                fprintf(stderr,
 367                        "Use 'dstport 4789' to get the IANA assigned value\n"
 368                        "Use 'dstport 0' to get default and quiet this message\n");
 369        }
 370
 371        if (VXLAN_ATTRSET(attrs, IFLA_VXLAN_ID))
 372                addattr32(n, 1024, IFLA_VXLAN_ID, vni);
 373
 374        if (is_addrtype_inet(&saddr)) {
 375                int type = (saddr.family == AF_INET) ? IFLA_VXLAN_LOCAL
 376                                                     : IFLA_VXLAN_LOCAL6;
 377                addattr_l(n, 1024, type, saddr.data, saddr.bytelen);
 378                selected_family = true;
 379        }
 380
 381        if (is_addrtype_inet(&daddr)) {
 382                int type = (daddr.family == AF_INET) ? IFLA_VXLAN_GROUP
 383                                                     : IFLA_VXLAN_GROUP6;
 384                addattr_l(n, 1024, type, daddr.data, daddr.bytelen);
 385                selected_family = true;
 386        }
 387
 388        if (!selected_family) {
 389                if (preferred_family == AF_INET) {
 390                        get_addr(&daddr, "default", AF_INET);
 391                        addattr_l(n, 1024, IFLA_VXLAN_GROUP,
 392                                  daddr.data, daddr.bytelen);
 393                } else if (preferred_family == AF_INET6) {
 394                        get_addr(&daddr, "default", AF_INET6);
 395                        addattr_l(n, 1024, IFLA_VXLAN_GROUP6,
 396                                  daddr.data, daddr.bytelen);
 397                }
 398        }
 399
 400        if (!set_op || VXLAN_ATTRSET(attrs, IFLA_VXLAN_LEARNING))
 401                addattr8(n, 1024, IFLA_VXLAN_LEARNING, learning);
 402
 403        if (dstport)
 404                addattr16(n, 1024, IFLA_VXLAN_PORT, htons(dstport));
 405
 406        return 0;
 407}
 408
 409static void vxlan_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
 410{
 411        __u8 ttl = 0;
 412        __u8 tos = 0;
 413        __u32 maxaddr;
 414
 415        if (!tb)
 416                return;
 417
 418        if (tb[IFLA_VXLAN_COLLECT_METADATA] &&
 419            rta_getattr_u8(tb[IFLA_VXLAN_COLLECT_METADATA])) {
 420                print_bool(PRINT_ANY, "external", "external ", true);
 421        }
 422
 423        if (tb[IFLA_VXLAN_ID] &&
 424            RTA_PAYLOAD(tb[IFLA_VXLAN_ID]) >= sizeof(__u32)) {
 425                print_uint(PRINT_ANY, "id", "id %u ", rta_getattr_u32(tb[IFLA_VXLAN_ID]));
 426        }
 427
 428        if (tb[IFLA_VXLAN_GROUP]) {
 429                __be32 addr = rta_getattr_u32(tb[IFLA_VXLAN_GROUP]);
 430
 431                if (addr) {
 432                        if (IN_MULTICAST(ntohl(addr)))
 433                                print_string(PRINT_ANY,
 434                                             "group",
 435                                             "group %s ",
 436                                             format_host(AF_INET, 4, &addr));
 437                        else
 438                                print_string(PRINT_ANY,
 439                                             "remote",
 440                                             "remote %s ",
 441                                             format_host(AF_INET, 4, &addr));
 442                }
 443        } else if (tb[IFLA_VXLAN_GROUP6]) {
 444                struct in6_addr addr;
 445
 446                memcpy(&addr, RTA_DATA(tb[IFLA_VXLAN_GROUP6]), sizeof(struct in6_addr));
 447                if (!IN6_IS_ADDR_UNSPECIFIED(&addr)) {
 448                        if (IN6_IS_ADDR_MULTICAST(&addr))
 449                                print_string(PRINT_ANY,
 450                                             "group6",
 451                                             "group %s ",
 452                                             format_host(AF_INET6,
 453                                                         sizeof(struct in6_addr),
 454                                                         &addr));
 455                        else
 456                                print_string(PRINT_ANY,
 457                                             "remote6",
 458                                             "remote %s ",
 459                                             format_host(AF_INET6,
 460                                                         sizeof(struct in6_addr),
 461                                                         &addr));
 462                }
 463        }
 464
 465        if (tb[IFLA_VXLAN_LOCAL]) {
 466                __be32 addr = rta_getattr_u32(tb[IFLA_VXLAN_LOCAL]);
 467
 468                if (addr)
 469                        print_string(PRINT_ANY,
 470                                     "local",
 471                                     "local %s ",
 472                                     format_host(AF_INET, 4, &addr));
 473        } else if (tb[IFLA_VXLAN_LOCAL6]) {
 474                struct in6_addr addr;
 475
 476                memcpy(&addr, RTA_DATA(tb[IFLA_VXLAN_LOCAL6]), sizeof(struct in6_addr));
 477                if (!IN6_IS_ADDR_UNSPECIFIED(&addr))
 478                        print_string(PRINT_ANY,
 479                                     "local6",
 480                                     "local %s ",
 481                                     format_host(AF_INET6,
 482                                                 sizeof(struct in6_addr),
 483                                                 &addr));
 484        }
 485
 486        if (tb[IFLA_VXLAN_LINK]) {
 487                unsigned int link = rta_getattr_u32(tb[IFLA_VXLAN_LINK]);
 488
 489                if (link) {
 490                        print_string(PRINT_ANY, "link", "dev %s ",
 491                                     ll_index_to_name(link));
 492                }
 493        }
 494
 495        if (tb[IFLA_VXLAN_PORT_RANGE]) {
 496                const struct ifla_vxlan_port_range *r
 497                        = RTA_DATA(tb[IFLA_VXLAN_PORT_RANGE]);
 498                if (is_json_context()) {
 499                        open_json_object("port_range");
 500                        print_uint(PRINT_JSON, "low", NULL, ntohs(r->low));
 501                        print_uint(PRINT_JSON, "high", NULL, ntohs(r->high));
 502                        close_json_object();
 503                } else {
 504                        fprintf(f, "srcport %u %u ",
 505                                ntohs(r->low), ntohs(r->high));
 506                }
 507        }
 508
 509        if (tb[IFLA_VXLAN_PORT])
 510                print_uint(PRINT_ANY,
 511                           "port",
 512                           "dstport %u ",
 513                           rta_getattr_be16(tb[IFLA_VXLAN_PORT]));
 514
 515        if (tb[IFLA_VXLAN_LEARNING]) {
 516                __u8 learning = rta_getattr_u8(tb[IFLA_VXLAN_LEARNING]);
 517
 518                print_bool(PRINT_JSON, "learning", NULL, learning);
 519                if (!learning)
 520                        print_bool(PRINT_FP, NULL, "nolearning ", true);
 521        }
 522
 523        if (tb[IFLA_VXLAN_PROXY] && rta_getattr_u8(tb[IFLA_VXLAN_PROXY]))
 524                print_bool(PRINT_ANY, "proxy", "proxy ", true);
 525
 526        if (tb[IFLA_VXLAN_RSC] && rta_getattr_u8(tb[IFLA_VXLAN_RSC]))
 527                print_bool(PRINT_ANY, "rsc", "rsc ", true);
 528
 529        if (tb[IFLA_VXLAN_L2MISS] && rta_getattr_u8(tb[IFLA_VXLAN_L2MISS]))
 530                print_bool(PRINT_ANY, "l2miss", "l2miss ", true);
 531
 532        if (tb[IFLA_VXLAN_L3MISS] && rta_getattr_u8(tb[IFLA_VXLAN_L3MISS]))
 533                print_bool(PRINT_ANY, "l3miss", "l3miss ", true);
 534
 535        if (tb[IFLA_VXLAN_TOS])
 536                tos = rta_getattr_u8(tb[IFLA_VXLAN_TOS]);
 537        if (tos) {
 538                if (is_json_context() || tos != 1)
 539                        print_0xhex(PRINT_ANY, "tos", "tos %#llx ", tos);
 540                else
 541                        print_string(PRINT_FP, NULL, "tos %s ", "inherit");
 542        }
 543
 544        if (tb[IFLA_VXLAN_TTL_INHERIT] &&
 545            rta_getattr_u8(tb[IFLA_VXLAN_TTL_INHERIT])) {
 546                print_string(PRINT_FP, NULL, "ttl %s ", "inherit");
 547        } else if (tb[IFLA_VXLAN_TTL]) {
 548                ttl = rta_getattr_u8(tb[IFLA_VXLAN_TTL]);
 549                if (is_json_context() || ttl)
 550                        print_uint(PRINT_ANY, "ttl", "ttl %u ", ttl);
 551                else
 552                        print_string(PRINT_FP, NULL, "ttl %s ", "auto");
 553        }
 554
 555        if (tb[IFLA_VXLAN_DF]) {
 556                enum ifla_vxlan_df df = rta_getattr_u8(tb[IFLA_VXLAN_DF]);
 557
 558                if (df == VXLAN_DF_UNSET)
 559                        print_string(PRINT_JSON, "df", "df %s ", "unset");
 560                else if (df == VXLAN_DF_SET)
 561                        print_string(PRINT_ANY, "df", "df %s ", "set");
 562                else if (df == VXLAN_DF_INHERIT)
 563                        print_string(PRINT_ANY, "df", "df %s ", "inherit");
 564        }
 565
 566        if (tb[IFLA_VXLAN_LABEL]) {
 567                __u32 label = rta_getattr_u32(tb[IFLA_VXLAN_LABEL]);
 568
 569                if (label)
 570                        print_0xhex(PRINT_ANY, "label",
 571                                    "flowlabel %#llx ", ntohl(label));
 572        }
 573
 574        if (tb[IFLA_VXLAN_AGEING]) {
 575                __u32 age = rta_getattr_u32(tb[IFLA_VXLAN_AGEING]);
 576
 577                if (age == 0)
 578                        print_uint(PRINT_ANY, "ageing", "ageing none ", 0);
 579                else
 580                        print_uint(PRINT_ANY, "ageing", "ageing %u ", age);
 581        }
 582
 583        if (tb[IFLA_VXLAN_LIMIT] &&
 584            ((maxaddr = rta_getattr_u32(tb[IFLA_VXLAN_LIMIT])) != 0))
 585                print_uint(PRINT_ANY, "limit", "maxaddr %u ", maxaddr);
 586
 587        if (tb[IFLA_VXLAN_UDP_CSUM]) {
 588                __u8 udp_csum = rta_getattr_u8(tb[IFLA_VXLAN_UDP_CSUM]);
 589
 590                if (is_json_context()) {
 591                        print_bool(PRINT_ANY, "udp_csum", NULL, udp_csum);
 592                } else {
 593                        if (!udp_csum)
 594                                fputs("no", f);
 595                        fputs("udpcsum ", f);
 596                }
 597        }
 598
 599        if (tb[IFLA_VXLAN_UDP_ZERO_CSUM6_TX]) {
 600                __u8 csum6 = rta_getattr_u8(tb[IFLA_VXLAN_UDP_ZERO_CSUM6_TX]);
 601
 602                if (is_json_context()) {
 603                        print_bool(PRINT_ANY,
 604                                   "udp_zero_csum6_tx", NULL, csum6);
 605                } else {
 606                        if (!csum6)
 607                                fputs("no", f);
 608                        fputs("udp6zerocsumtx ", f);
 609                }
 610        }
 611
 612        if (tb[IFLA_VXLAN_UDP_ZERO_CSUM6_RX]) {
 613                __u8 csum6 = rta_getattr_u8(tb[IFLA_VXLAN_UDP_ZERO_CSUM6_RX]);
 614
 615                if (is_json_context()) {
 616                        print_bool(PRINT_ANY,
 617                                   "udp_zero_csum6_rx",
 618                                   NULL,
 619                                   csum6);
 620                } else {
 621                        if (!csum6)
 622                                fputs("no", f);
 623                        fputs("udp6zerocsumrx ", f);
 624                }
 625        }
 626
 627        if (tb[IFLA_VXLAN_REMCSUM_TX] &&
 628            rta_getattr_u8(tb[IFLA_VXLAN_REMCSUM_TX]))
 629                print_bool(PRINT_ANY, "remcsum_tx", "remcsumtx ", true);
 630
 631        if (tb[IFLA_VXLAN_REMCSUM_RX] &&
 632            rta_getattr_u8(tb[IFLA_VXLAN_REMCSUM_RX]))
 633                print_bool(PRINT_ANY, "remcsum_rx", "remcsumrx ", true);
 634
 635        if (tb[IFLA_VXLAN_GBP])
 636                print_bool(PRINT_ANY, "gbp", "gbp ", true);
 637        if (tb[IFLA_VXLAN_GPE])
 638                print_bool(PRINT_ANY, "gpe", "gpe ", true);
 639}
 640
 641static void vxlan_print_help(struct link_util *lu, int argc, char **argv,
 642                             FILE *f)
 643{
 644        print_explain(f);
 645}
 646
 647struct link_util vxlan_link_util = {
 648        .id             = "vxlan",
 649        .maxattr        = IFLA_VXLAN_MAX,
 650        .parse_opt      = vxlan_parse_opt,
 651        .print_opt      = vxlan_print_opt,
 652        .print_help     = vxlan_print_help,
 653};
 654