iproute2/tc/m_tunnel_key.c
<<
>>
Prefs
   1/*
   2 * m_tunnel_key.c       ip tunnel manipulation module
   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:     Amir Vadai <amir@vadai.me>
  10 */
  11
  12#include <stdio.h>
  13#include <stdlib.h>
  14#include <unistd.h>
  15#include <string.h>
  16#include <linux/if_ether.h>
  17#include "utils.h"
  18#include "rt_names.h"
  19#include "tc_util.h"
  20#include <linux/tc_act/tc_tunnel_key.h>
  21
  22static void explain(void)
  23{
  24        fprintf(stderr,
  25                "Usage: tunnel_key unset\n"
  26                "       tunnel_key set <TUNNEL_KEY>\n"
  27                "Where TUNNEL_KEY is a combination of:\n"
  28                "id <TUNNELID>\n"
  29                "src_ip <IP> (mandatory)\n"
  30                "dst_ip <IP> (mandatory)\n"
  31                "dst_port <UDP_PORT>\n"
  32                "geneve_opts | vxlan_opts | erspan_opts <OPTIONS>\n"
  33                "csum | nocsum (default is \"csum\")\n");
  34}
  35
  36static void usage(void)
  37{
  38        explain();
  39        exit(-1);
  40}
  41
  42static int tunnel_key_parse_ip_addr(const char *str, int addr4_type,
  43                                    int addr6_type, struct nlmsghdr *n)
  44{
  45        inet_prefix addr;
  46        int ret;
  47
  48        ret = get_addr(&addr, str, AF_UNSPEC);
  49        if (ret)
  50                return ret;
  51
  52        addattr_l(n, MAX_MSG, addr.family == AF_INET ? addr4_type : addr6_type,
  53                  addr.data, addr.bytelen);
  54
  55        return 0;
  56}
  57
  58static int tunnel_key_parse_key_id(const char *str, int type,
  59                                   struct nlmsghdr *n)
  60{
  61        __be32 key_id;
  62        int ret;
  63
  64        ret = get_be32(&key_id, str, 10);
  65        if (!ret)
  66                addattr32(n, MAX_MSG, type, key_id);
  67
  68        return ret;
  69}
  70
  71static int tunnel_key_parse_dst_port(char *str, int type, struct nlmsghdr *n)
  72{
  73        int ret;
  74        __be16 dst_port;
  75
  76        ret = get_be16(&dst_port, str, 10);
  77        if (ret)
  78                return -1;
  79
  80        addattr16(n, MAX_MSG, type, dst_port);
  81
  82        return 0;
  83}
  84
  85static int tunnel_key_parse_be16(char *str, int base, int type,
  86                                 struct nlmsghdr *n)
  87{
  88        int ret;
  89        __be16 value;
  90
  91        ret = get_be16(&value, str, base);
  92        if (ret)
  93                return ret;
  94
  95        addattr16(n, MAX_MSG, type, value);
  96
  97        return 0;
  98}
  99
 100static int tunnel_key_parse_be32(char *str, int base, int type,
 101                                 struct nlmsghdr *n)
 102{
 103        __be32 value;
 104        int ret;
 105
 106        ret = get_be32(&value, str, base);
 107        if (ret)
 108                return ret;
 109
 110        addattr32(n, MAX_MSG, type, value);
 111
 112        return 0;
 113}
 114
 115static int tunnel_key_parse_u8(char *str, int base, int type,
 116                               struct nlmsghdr *n)
 117{
 118        int ret;
 119        __u8 value;
 120
 121        ret = get_u8(&value, str, base);
 122        if (ret)
 123                return ret;
 124
 125        addattr8(n, MAX_MSG, type, value);
 126
 127        return 0;
 128}
 129
 130static int tunnel_key_parse_u32(char *str, int base, int type,
 131                                struct nlmsghdr *n)
 132{
 133        __u32 value;
 134        int ret;
 135
 136        ret = get_u32(&value, str, base);
 137        if (ret)
 138                return ret;
 139
 140        addattr32(n, MAX_MSG, type, value);
 141
 142        return 0;
 143}
 144
 145static int tunnel_key_parse_geneve_opt(char *str, struct nlmsghdr *n)
 146{
 147        char *token, *saveptr = NULL;
 148        struct rtattr *nest;
 149        int i, ret;
 150
 151        nest = addattr_nest(n, MAX_MSG, TCA_TUNNEL_KEY_ENC_OPTS_GENEVE);
 152
 153        token = strtok_r(str, ":", &saveptr);
 154        i = 1;
 155        while (token) {
 156                switch (i) {
 157                case TCA_TUNNEL_KEY_ENC_OPT_GENEVE_CLASS:
 158                {
 159                        ret = tunnel_key_parse_be16(token, 16, i, n);
 160                        if (ret)
 161                                return ret;
 162                        break;
 163                }
 164                case TCA_TUNNEL_KEY_ENC_OPT_GENEVE_TYPE:
 165                {
 166                        ret = tunnel_key_parse_u8(token, 16, i, n);
 167                        if (ret)
 168                                return ret;
 169                        break;
 170                }
 171                case TCA_TUNNEL_KEY_ENC_OPT_GENEVE_DATA:
 172                {
 173                        size_t token_len = strlen(token);
 174                        uint8_t *opts;
 175
 176                        opts = malloc(token_len / 2);
 177                        if (!opts)
 178                                return -1;
 179                        if (hex2mem(token, opts, token_len / 2) < 0) {
 180                                free(opts);
 181                                return -1;
 182                        }
 183                        addattr_l(n, MAX_MSG, i, opts, token_len / 2);
 184                        free(opts);
 185
 186                        break;
 187                }
 188                default:
 189                        return -1;
 190                }
 191
 192                token = strtok_r(NULL, ":", &saveptr);
 193                i++;
 194        }
 195
 196        addattr_nest_end(n, nest);
 197
 198        return 0;
 199}
 200
 201static int tunnel_key_parse_geneve_opts(char *str, struct nlmsghdr *n)
 202{
 203        char *token, *saveptr = NULL;
 204        struct rtattr *nest;
 205        int ret;
 206
 207        nest = addattr_nest(n, MAX_MSG, TCA_TUNNEL_KEY_ENC_OPTS);
 208
 209        token = strtok_r(str, ",", &saveptr);
 210        while (token) {
 211                ret = tunnel_key_parse_geneve_opt(token, n);
 212                if (ret)
 213                        return ret;
 214
 215                token = strtok_r(NULL, ",", &saveptr);
 216        }
 217
 218        addattr_nest_end(n, nest);
 219
 220        return 0;
 221}
 222
 223static int tunnel_key_parse_vxlan_opt(char *str, struct nlmsghdr *n)
 224{
 225        struct rtattr *encap, *nest;
 226        int ret;
 227
 228        encap = addattr_nest(n, MAX_MSG,
 229                             TCA_TUNNEL_KEY_ENC_OPTS | NLA_F_NESTED);
 230        nest = addattr_nest(n, MAX_MSG,
 231                            TCA_TUNNEL_KEY_ENC_OPTS_VXLAN | NLA_F_NESTED);
 232
 233        ret = tunnel_key_parse_u32(str, 0,
 234                                   TCA_TUNNEL_KEY_ENC_OPT_VXLAN_GBP, n);
 235        if (ret)
 236                return ret;
 237
 238        addattr_nest_end(n, nest);
 239        addattr_nest_end(n, encap);
 240
 241        return 0;
 242}
 243
 244static int tunnel_key_parse_erspan_opt(char *str, struct nlmsghdr *n)
 245{
 246        char *token, *saveptr = NULL;
 247        struct rtattr *encap, *nest;
 248        int i, ret;
 249
 250        encap = addattr_nest(n, MAX_MSG,
 251                             TCA_TUNNEL_KEY_ENC_OPTS | NLA_F_NESTED);
 252        nest = addattr_nest(n, MAX_MSG,
 253                            TCA_TUNNEL_KEY_ENC_OPTS_ERSPAN | NLA_F_NESTED);
 254
 255        token = strtok_r(str, ":", &saveptr);
 256        i = 1;
 257        while (token) {
 258                switch (i) {
 259                case TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_VER:
 260                {
 261                        ret = tunnel_key_parse_u8(token, 0, i, n);
 262                        if (ret)
 263                                return ret;
 264                        break;
 265                }
 266                case TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_INDEX:
 267                {
 268                        ret = tunnel_key_parse_be32(token, 0, i, n);
 269                        if (ret)
 270                                return ret;
 271                        break;
 272                }
 273                case TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_DIR:
 274                {
 275                        ret = tunnel_key_parse_u8(token, 0, i, n);
 276                        if (ret)
 277                                return ret;
 278                        break;
 279                }
 280                case TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_HWID:
 281                {
 282                        ret = tunnel_key_parse_u8(token, 0, i, n);
 283                        if (ret)
 284                                return ret;
 285                        break;
 286                }
 287                default:
 288                        return -1;
 289                }
 290
 291                token = strtok_r(NULL, ":", &saveptr);
 292                i++;
 293        }
 294
 295        addattr_nest_end(n, nest);
 296        addattr_nest_end(n, encap);
 297
 298        return 0;
 299}
 300
 301static int tunnel_key_parse_tos_ttl(char *str, int type, struct nlmsghdr *n)
 302{
 303        int ret;
 304        __u8 val;
 305
 306        ret = get_u8(&val, str, 10);
 307        if (ret)
 308                ret = get_u8(&val, str, 16);
 309        if (ret)
 310                return -1;
 311
 312        addattr8(n, MAX_MSG, type, val);
 313
 314        return 0;
 315}
 316
 317static int parse_tunnel_key(struct action_util *a, int *argc_p, char ***argv_p,
 318                            int tca_id, struct nlmsghdr *n)
 319{
 320        struct tc_tunnel_key parm = {};
 321        char **argv = *argv_p;
 322        int argc = *argc_p;
 323        struct rtattr *tail;
 324        int action = 0;
 325        int ret;
 326        int has_src_ip = 0;
 327        int has_dst_ip = 0;
 328        int csum = 1;
 329
 330        if (matches(*argv, "tunnel_key") != 0)
 331                return -1;
 332
 333        tail = addattr_nest(n, MAX_MSG, tca_id);
 334
 335        NEXT_ARG();
 336
 337        while (argc > 0) {
 338                if (matches(*argv, "unset") == 0) {
 339                        if (action) {
 340                                fprintf(stderr, "unexpected \"%s\" - action already specified\n",
 341                                        *argv);
 342                                explain();
 343                                return -1;
 344                        }
 345                        action = TCA_TUNNEL_KEY_ACT_RELEASE;
 346                } else if (matches(*argv, "set") == 0) {
 347                        if (action) {
 348                                fprintf(stderr, "unexpected \"%s\" - action already specified\n",
 349                                        *argv);
 350                                explain();
 351                                return -1;
 352                        }
 353                        action = TCA_TUNNEL_KEY_ACT_SET;
 354                } else if (matches(*argv, "src_ip") == 0) {
 355                        NEXT_ARG();
 356                        ret = tunnel_key_parse_ip_addr(*argv,
 357                                                       TCA_TUNNEL_KEY_ENC_IPV4_SRC,
 358                                                       TCA_TUNNEL_KEY_ENC_IPV6_SRC,
 359                                                       n);
 360                        if (ret < 0) {
 361                                fprintf(stderr, "Illegal \"src_ip\"\n");
 362                                return -1;
 363                        }
 364                        has_src_ip = 1;
 365                } else if (matches(*argv, "dst_ip") == 0) {
 366                        NEXT_ARG();
 367                        ret = tunnel_key_parse_ip_addr(*argv,
 368                                                       TCA_TUNNEL_KEY_ENC_IPV4_DST,
 369                                                       TCA_TUNNEL_KEY_ENC_IPV6_DST,
 370                                                       n);
 371                        if (ret < 0) {
 372                                fprintf(stderr, "Illegal \"dst_ip\"\n");
 373                                return -1;
 374                        }
 375                        has_dst_ip = 1;
 376                } else if (matches(*argv, "id") == 0) {
 377                        NEXT_ARG();
 378                        ret = tunnel_key_parse_key_id(*argv, TCA_TUNNEL_KEY_ENC_KEY_ID, n);
 379                        if (ret < 0) {
 380                                fprintf(stderr, "Illegal \"id\"\n");
 381                                return -1;
 382                        }
 383                } else if (matches(*argv, "dst_port") == 0) {
 384                        NEXT_ARG();
 385                        ret = tunnel_key_parse_dst_port(*argv,
 386                                                        TCA_TUNNEL_KEY_ENC_DST_PORT, n);
 387                        if (ret < 0) {
 388                                fprintf(stderr, "Illegal \"dst port\"\n");
 389                                return -1;
 390                        }
 391                } else if (matches(*argv, "geneve_opts") == 0) {
 392                        NEXT_ARG();
 393
 394                        if (tunnel_key_parse_geneve_opts(*argv, n)) {
 395                                fprintf(stderr, "Illegal \"geneve_opts\"\n");
 396                                return -1;
 397                        }
 398                } else if (matches(*argv, "vxlan_opts") == 0) {
 399                        NEXT_ARG();
 400
 401                        if (tunnel_key_parse_vxlan_opt(*argv, n)) {
 402                                fprintf(stderr, "Illegal \"vxlan_opts\"\n");
 403                                return -1;
 404                        }
 405                } else if (matches(*argv, "erspan_opts") == 0) {
 406                        NEXT_ARG();
 407
 408                        if (tunnel_key_parse_erspan_opt(*argv, n)) {
 409                                fprintf(stderr, "Illegal \"erspan_opts\"\n");
 410                                return -1;
 411                        }
 412                } else if (matches(*argv, "tos") == 0) {
 413                        NEXT_ARG();
 414                        ret = tunnel_key_parse_tos_ttl(*argv,
 415                                                        TCA_TUNNEL_KEY_ENC_TOS, n);
 416                        if (ret < 0) {
 417                                fprintf(stderr, "Illegal \"tos\"\n");
 418                                return -1;
 419                        }
 420                } else if (matches(*argv, "ttl") == 0) {
 421                        NEXT_ARG();
 422                        ret = tunnel_key_parse_tos_ttl(*argv,
 423                                                        TCA_TUNNEL_KEY_ENC_TTL, n);
 424                        if (ret < 0) {
 425                                fprintf(stderr, "Illegal \"ttl\"\n");
 426                                return -1;
 427                        }
 428                } else if (matches(*argv, "csum") == 0) {
 429                        csum = 1;
 430                } else if (matches(*argv, "nocsum") == 0) {
 431                        csum = 0;
 432                } else if (matches(*argv, "help") == 0) {
 433                        usage();
 434                } else {
 435                        break;
 436                }
 437                NEXT_ARG_FWD();
 438        }
 439
 440        addattr8(n, MAX_MSG, TCA_TUNNEL_KEY_NO_CSUM, !csum);
 441
 442        parse_action_control_dflt(&argc, &argv, &parm.action,
 443                                  false, TC_ACT_PIPE);
 444
 445        if (argc) {
 446                if (matches(*argv, "index") == 0) {
 447                        NEXT_ARG();
 448                        if (get_u32(&parm.index, *argv, 10)) {
 449                                fprintf(stderr, "tunnel_key: Illegal \"index\"\n");
 450                                return -1;
 451                        }
 452
 453                        NEXT_ARG_FWD();
 454                }
 455        }
 456
 457        if (action == TCA_TUNNEL_KEY_ACT_SET &&
 458            (!has_src_ip || !has_dst_ip)) {
 459                fprintf(stderr, "set needs tunnel_key parameters\n");
 460                explain();
 461                return -1;
 462        }
 463
 464        parm.t_action = action;
 465        addattr_l(n, MAX_MSG, TCA_TUNNEL_KEY_PARMS, &parm, sizeof(parm));
 466        addattr_nest_end(n, tail);
 467
 468        *argc_p = argc;
 469        *argv_p = argv;
 470
 471        return 0;
 472}
 473
 474static void tunnel_key_print_ip_addr(FILE *f, const char *name,
 475                                     struct rtattr *attr)
 476{
 477        int family;
 478        size_t len;
 479
 480        if (!attr)
 481                return;
 482
 483        len = RTA_PAYLOAD(attr);
 484
 485        if (len == 4)
 486                family = AF_INET;
 487        else if (len == 16)
 488                family = AF_INET6;
 489        else
 490                return;
 491
 492        print_nl();
 493        if (matches(name, "src_ip") == 0)
 494                print_string(PRINT_ANY, "src_ip", "\tsrc_ip %s",
 495                             rt_addr_n2a_rta(family, attr));
 496        else if (matches(name, "dst_ip") == 0)
 497                print_string(PRINT_ANY, "dst_ip", "\tdst_ip %s",
 498                             rt_addr_n2a_rta(family, attr));
 499}
 500
 501static void tunnel_key_print_key_id(FILE *f, const char *name,
 502                                    struct rtattr *attr)
 503{
 504        if (!attr)
 505                return;
 506        print_nl();
 507        print_uint(PRINT_ANY, "key_id", "\tkey_id %u", rta_getattr_be32(attr));
 508}
 509
 510static void tunnel_key_print_dst_port(FILE *f, char *name,
 511                                      struct rtattr *attr)
 512{
 513        if (!attr)
 514                return;
 515        print_nl();
 516        print_uint(PRINT_ANY, "dst_port", "\tdst_port %u",
 517                   rta_getattr_be16(attr));
 518}
 519
 520static void tunnel_key_print_flag(FILE *f, const char *name_on,
 521                                  const char *name_off,
 522                                  struct rtattr *attr)
 523{
 524        if (!attr)
 525                return;
 526        print_nl();
 527        print_string(PRINT_ANY, "flag", "\t%s",
 528                     rta_getattr_u8(attr) ? name_on : name_off);
 529}
 530
 531static void tunnel_key_print_geneve_options(struct rtattr *attr)
 532{
 533        struct rtattr *tb[TCA_TUNNEL_KEY_ENC_OPT_GENEVE_MAX + 1];
 534        struct rtattr *i = RTA_DATA(attr);
 535        int ii, data_len = 0, offset = 0;
 536        int rem = RTA_PAYLOAD(attr);
 537        char *name = "geneve_opts";
 538        char strbuf[rem * 2 + 1];
 539        char data[rem * 2 + 1];
 540        uint8_t data_r[rem];
 541        uint16_t clss;
 542        uint8_t type;
 543
 544        open_json_array(PRINT_JSON, name);
 545        print_nl();
 546        print_string(PRINT_FP, name, "\t%s ", name);
 547
 548        while (rem) {
 549                parse_rtattr(tb, TCA_TUNNEL_KEY_ENC_OPT_GENEVE_MAX, i, rem);
 550                clss = rta_getattr_be16(tb[TCA_TUNNEL_KEY_ENC_OPT_GENEVE_CLASS]);
 551                type = rta_getattr_u8(tb[TCA_TUNNEL_KEY_ENC_OPT_GENEVE_TYPE]);
 552                data_len = RTA_PAYLOAD(tb[TCA_TUNNEL_KEY_ENC_OPT_GENEVE_DATA]);
 553                hexstring_n2a(RTA_DATA(tb[TCA_TUNNEL_KEY_ENC_OPT_GENEVE_DATA]),
 554                              data_len, data, sizeof(data));
 555                hex2mem(data, data_r, data_len);
 556                offset += data_len + 20;
 557                rem -= data_len + 20;
 558                i = RTA_DATA(attr) + offset;
 559
 560                open_json_object(NULL);
 561                print_uint(PRINT_JSON, "class", NULL, clss);
 562                print_uint(PRINT_JSON, "type", NULL, type);
 563                open_json_array(PRINT_JSON, "data");
 564                for (ii = 0; ii < data_len; ii++)
 565                        print_uint(PRINT_JSON, NULL, NULL, data_r[ii]);
 566                close_json_array(PRINT_JSON, "data");
 567                close_json_object();
 568
 569                sprintf(strbuf, "%04x:%02x:%s", clss, type, data);
 570                if (rem)
 571                        print_string(PRINT_FP, NULL, "%s,", strbuf);
 572                else
 573                        print_string(PRINT_FP, NULL, "%s", strbuf);
 574        }
 575
 576        close_json_array(PRINT_JSON, name);
 577}
 578
 579static void tunnel_key_print_vxlan_options(struct rtattr *attr)
 580{
 581        struct rtattr *tb[TCA_TUNNEL_KEY_ENC_OPT_VXLAN_MAX + 1];
 582        struct rtattr *i = RTA_DATA(attr);
 583        int rem = RTA_PAYLOAD(attr);
 584        char *name = "vxlan_opts";
 585        __u32 gbp;
 586
 587        parse_rtattr(tb, TCA_TUNNEL_KEY_ENC_OPT_VXLAN_MAX, i, rem);
 588        gbp = rta_getattr_u32(tb[TCA_TUNNEL_KEY_ENC_OPT_VXLAN_GBP]);
 589
 590        print_nl();
 591        print_string(PRINT_FP, name, "\t%s ", name);
 592        open_json_array(PRINT_JSON, name);
 593        open_json_object(NULL);
 594        print_uint(PRINT_ANY, "gbp", "%u", gbp);
 595        close_json_object();
 596        close_json_array(PRINT_JSON, name);
 597}
 598
 599static void tunnel_key_print_erspan_options(struct rtattr *attr)
 600{
 601        struct rtattr *tb[TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_MAX + 1];
 602        struct rtattr *i = RTA_DATA(attr);
 603        int rem = RTA_PAYLOAD(attr);
 604        char *name = "erspan_opts";
 605        __u8 ver, hwid, dir;
 606        __u32 idx;
 607
 608        parse_rtattr(tb, TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_MAX, i, rem);
 609        ver = rta_getattr_u8(tb[TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_VER]);
 610        if (ver == 1) {
 611                idx = rta_getattr_be32(tb[TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_INDEX]);
 612                dir = 0;
 613                hwid = 0;
 614        } else {
 615                idx = 0;
 616                dir = rta_getattr_u8(tb[TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_DIR]);
 617                hwid = rta_getattr_u8(tb[TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_HWID]);
 618        }
 619
 620        print_nl();
 621        print_string(PRINT_FP, name, "\t%s ", name);
 622        open_json_array(PRINT_JSON, name);
 623        open_json_object(NULL);
 624        print_uint(PRINT_ANY, "ver", "%u", ver);
 625        print_uint(PRINT_ANY, "index", ":%u", idx);
 626        print_uint(PRINT_ANY, "dir", ":%u", dir);
 627        print_uint(PRINT_ANY, "hwid", ":%u", hwid);
 628        close_json_object();
 629        close_json_array(PRINT_JSON, name);
 630}
 631
 632static void tunnel_key_print_key_opt(struct rtattr *attr)
 633{
 634        struct rtattr *tb[TCA_TUNNEL_KEY_ENC_OPTS_MAX + 1];
 635
 636        if (!attr)
 637                return;
 638
 639        parse_rtattr_nested(tb, TCA_TUNNEL_KEY_ENC_OPTS_MAX, attr);
 640        if (tb[TCA_TUNNEL_KEY_ENC_OPTS_GENEVE])
 641                tunnel_key_print_geneve_options(
 642                        tb[TCA_TUNNEL_KEY_ENC_OPTS_GENEVE]);
 643        else if (tb[TCA_TUNNEL_KEY_ENC_OPTS_VXLAN])
 644                tunnel_key_print_vxlan_options(
 645                        tb[TCA_TUNNEL_KEY_ENC_OPTS_VXLAN]);
 646        else if (tb[TCA_TUNNEL_KEY_ENC_OPTS_ERSPAN])
 647                tunnel_key_print_erspan_options(
 648                        tb[TCA_TUNNEL_KEY_ENC_OPTS_ERSPAN]);
 649}
 650
 651static void tunnel_key_print_tos_ttl(FILE *f, char *name,
 652                                     struct rtattr *attr)
 653{
 654        if (!attr)
 655                return;
 656
 657        if (matches(name, "tos") == 0 && rta_getattr_u8(attr) != 0) {
 658                print_nl();
 659                print_uint(PRINT_ANY, "tos", "\ttos 0x%x",
 660                           rta_getattr_u8(attr));
 661        } else if (matches(name, "ttl") == 0 && rta_getattr_u8(attr) != 0) {
 662                print_nl();
 663                print_uint(PRINT_ANY, "ttl", "\tttl %u",
 664                           rta_getattr_u8(attr));
 665        }
 666}
 667
 668static int print_tunnel_key(struct action_util *au, FILE *f, struct rtattr *arg)
 669{
 670        struct rtattr *tb[TCA_TUNNEL_KEY_MAX + 1];
 671        struct tc_tunnel_key *parm;
 672
 673        print_string(PRINT_ANY, "kind", "%s ", "tunnel_key");
 674        if (!arg)
 675                return 0;
 676
 677        parse_rtattr_nested(tb, TCA_TUNNEL_KEY_MAX, arg);
 678
 679        if (!tb[TCA_TUNNEL_KEY_PARMS]) {
 680                fprintf(stderr, "Missing tunnel_key parameters\n");
 681                return -1;
 682        }
 683        parm = RTA_DATA(tb[TCA_TUNNEL_KEY_PARMS]);
 684
 685        switch (parm->t_action) {
 686        case TCA_TUNNEL_KEY_ACT_RELEASE:
 687                print_string(PRINT_ANY, "mode", " %s", "unset");
 688                break;
 689        case TCA_TUNNEL_KEY_ACT_SET:
 690                print_string(PRINT_ANY, "mode", " %s", "set");
 691                tunnel_key_print_ip_addr(f, "src_ip",
 692                                         tb[TCA_TUNNEL_KEY_ENC_IPV4_SRC]);
 693                tunnel_key_print_ip_addr(f, "dst_ip",
 694                                         tb[TCA_TUNNEL_KEY_ENC_IPV4_DST]);
 695                tunnel_key_print_ip_addr(f, "src_ip",
 696                                         tb[TCA_TUNNEL_KEY_ENC_IPV6_SRC]);
 697                tunnel_key_print_ip_addr(f, "dst_ip",
 698                                         tb[TCA_TUNNEL_KEY_ENC_IPV6_DST]);
 699                tunnel_key_print_key_id(f, "key_id",
 700                                        tb[TCA_TUNNEL_KEY_ENC_KEY_ID]);
 701                tunnel_key_print_dst_port(f, "dst_port",
 702                                          tb[TCA_TUNNEL_KEY_ENC_DST_PORT]);
 703                tunnel_key_print_key_opt(tb[TCA_TUNNEL_KEY_ENC_OPTS]);
 704                tunnel_key_print_flag(f, "nocsum", "csum",
 705                                      tb[TCA_TUNNEL_KEY_NO_CSUM]);
 706                tunnel_key_print_tos_ttl(f, "tos",
 707                                          tb[TCA_TUNNEL_KEY_ENC_TOS]);
 708                tunnel_key_print_tos_ttl(f, "ttl",
 709                                          tb[TCA_TUNNEL_KEY_ENC_TTL]);
 710                break;
 711        }
 712        print_action_control(f, " ", parm->action, "");
 713
 714        print_nl();
 715        print_uint(PRINT_ANY, "index", "\t index %u", parm->index);
 716        print_int(PRINT_ANY, "ref", " ref %d", parm->refcnt);
 717        print_int(PRINT_ANY, "bind", " bind %d", parm->bindcnt);
 718
 719        if (show_stats) {
 720                if (tb[TCA_TUNNEL_KEY_TM]) {
 721                        struct tcf_t *tm = RTA_DATA(tb[TCA_TUNNEL_KEY_TM]);
 722
 723                        print_tm(f, tm);
 724                }
 725        }
 726
 727        print_nl();
 728
 729        return 0;
 730}
 731
 732struct action_util tunnel_key_action_util = {
 733        .id = "tunnel_key",
 734        .parse_aopt = parse_tunnel_key,
 735        .print_aopt = print_tunnel_key,
 736};
 737