iproute2/ip/link_iptnl.c
<<
>>
Prefs
   1/*
   2 * link_iptnl.c ipip and sit driver 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:     Nicolas Dichtel <nicolas.dichtel@6wind.com>
  10 *
  11 */
  12
  13#include <string.h>
  14#include <net/if.h>
  15#include <sys/types.h>
  16#include <sys/socket.h>
  17#include <arpa/inet.h>
  18
  19#include <linux/in.h>
  20#include <linux/ip.h>
  21#include <linux/if_tunnel.h>
  22#include "rt_names.h"
  23#include "utils.h"
  24#include "ip_common.h"
  25#include "tunnel.h"
  26
  27static void iptunnel_print_help(struct link_util *lu, int argc, char **argv,
  28                                FILE *f)
  29{
  30        const char *mode;
  31
  32        if (strcmp(lu->id, "sit") == 0) {
  33                mode =  "{ ip6ip | ipip | mplsip | any } ]\n"
  34                        "                       [ isatap";
  35        } else {
  36                mode = "{ ipip | mplsip | any }";
  37        }
  38
  39        fprintf(f,
  40                "Usage: ... %-6s        [ remote ADDR ]\n"
  41                "                       [ local ADDR ]\n"
  42                "                       [ ttl TTL ]\n"
  43                "                       [ tos TOS ]\n"
  44                "                       [ [no]pmtudisc ]\n"
  45                "                       [ 6rd-prefix ADDR ]\n"
  46                "                       [ 6rd-relay_prefix ADDR ]\n"
  47                "                       [ 6rd-reset ]\n"
  48                "                       [ dev PHYS_DEV ]\n"
  49                "                       [ fwmark MARK ]\n"
  50                "                       [ external ]\n"
  51                "                       [ noencap ]\n"
  52                "                       [ encap { fou | gue | none } ]\n"
  53                "                       [ encap-sport PORT ]\n"
  54                "                       [ encap-dport PORT ]\n"
  55                "                       [ [no]encap-csum ]\n"
  56                "                       [ [no]encap-csum6 ]\n"
  57                "                       [ [no]encap-remcsum ]\n"
  58                "                       [ mode %s ]\n"
  59                "\n"
  60                "Where: ADDR := { IP_ADDRESS | any }\n"
  61                "       TOS  := { NUMBER | inherit }\n"
  62                "       TTL  := { 1..255 | inherit }\n"
  63                "       MARK := { 0x0..0xffffffff }\n",
  64                lu->id, mode);
  65}
  66
  67static int iptunnel_parse_opt(struct link_util *lu, int argc, char **argv,
  68                              struct nlmsghdr *n)
  69{
  70        struct ifinfomsg *ifi = NLMSG_DATA(n);
  71        struct {
  72                struct nlmsghdr n;
  73                struct ifinfomsg i;
  74        } req = {
  75                .n.nlmsg_len = NLMSG_LENGTH(sizeof(*ifi)),
  76                .n.nlmsg_flags = NLM_F_REQUEST,
  77                .n.nlmsg_type = RTM_GETLINK,
  78                .i.ifi_family = preferred_family,
  79                .i.ifi_index = ifi->ifi_index,
  80        };
  81        struct nlmsghdr *answer;
  82        struct rtattr *tb[IFLA_MAX + 1];
  83        struct rtattr *linkinfo[IFLA_INFO_MAX+1];
  84        struct rtattr *iptuninfo[IFLA_IPTUN_MAX + 1];
  85        int len;
  86        inet_prefix saddr, daddr, ip6rdprefix, ip6rdrelayprefix;
  87        __u8 pmtudisc = 1;
  88        __u8 tos = 0;
  89        __u16 iflags = 0;
  90        __u8 ttl = 0;
  91        __u8 proto = 0;
  92        __u32 link = 0;
  93        __u16 encaptype = 0;
  94        __u16 encapflags = 0;
  95        __u16 encapsport = 0;
  96        __u16 encapdport = 0;
  97        __u8 metadata = 0;
  98        __u32 fwmark = 0;
  99
 100        inet_prefix_reset(&saddr);
 101        inet_prefix_reset(&daddr);
 102
 103        inet_prefix_reset(&ip6rdprefix);
 104        inet_prefix_reset(&ip6rdrelayprefix);
 105
 106        if (!(n->nlmsg_flags & NLM_F_CREATE)) {
 107                const struct rtattr *rta;
 108
 109                if (rtnl_talk(&rth, &req.n, &answer) < 0) {
 110get_failed:
 111                        fprintf(stderr,
 112                                "Failed to get existing tunnel info.\n");
 113                        return -1;
 114                }
 115
 116                len = answer->nlmsg_len;
 117                len -= NLMSG_LENGTH(sizeof(*ifi));
 118                if (len < 0)
 119                        goto get_failed;
 120
 121                parse_rtattr(tb, IFLA_MAX, IFLA_RTA(NLMSG_DATA(answer)), len);
 122
 123                if (!tb[IFLA_LINKINFO])
 124                        goto get_failed;
 125
 126                parse_rtattr_nested(linkinfo, IFLA_INFO_MAX, tb[IFLA_LINKINFO]);
 127
 128                if (!linkinfo[IFLA_INFO_DATA])
 129                        goto get_failed;
 130
 131                parse_rtattr_nested(iptuninfo, IFLA_IPTUN_MAX,
 132                                    linkinfo[IFLA_INFO_DATA]);
 133
 134                rta = iptuninfo[IFLA_IPTUN_LOCAL];
 135                if (rta && get_addr_rta(&saddr, rta, AF_INET))
 136                        goto get_failed;
 137
 138                rta = iptuninfo[IFLA_IPTUN_REMOTE];
 139                if (rta && get_addr_rta(&daddr, rta, AF_INET))
 140                        goto get_failed;
 141
 142                rta = iptuninfo[IFLA_IPTUN_6RD_PREFIX];
 143                if (rta && get_addr_rta(&ip6rdprefix, rta, AF_INET6))
 144                        goto get_failed;
 145
 146                rta = iptuninfo[IFLA_IPTUN_6RD_RELAY_PREFIX];
 147                if (rta && get_addr_rta(&ip6rdrelayprefix, rta, AF_INET))
 148                        goto get_failed;
 149
 150                rta = iptuninfo[IFLA_IPTUN_6RD_PREFIXLEN];
 151                ip6rdprefix.bitlen = rta ? rta_getattr_u16(rta) : 0;
 152
 153                rta = iptuninfo[IFLA_IPTUN_6RD_RELAY_PREFIXLEN];
 154                ip6rdrelayprefix.bitlen = rta ? rta_getattr_u16(rta) : 0;
 155
 156                if (iptuninfo[IFLA_IPTUN_TTL])
 157                        ttl = rta_getattr_u8(iptuninfo[IFLA_IPTUN_TTL]);
 158
 159                if (iptuninfo[IFLA_IPTUN_PMTUDISC])
 160                        pmtudisc =
 161                                rta_getattr_u8(iptuninfo[IFLA_IPTUN_PMTUDISC]);
 162
 163                if (iptuninfo[IFLA_IPTUN_TOS])
 164                        tos = rta_getattr_u8(iptuninfo[IFLA_IPTUN_TOS]);
 165
 166                if (iptuninfo[IFLA_IPTUN_FLAGS])
 167                        iflags = rta_getattr_u16(iptuninfo[IFLA_IPTUN_FLAGS]);
 168
 169                if (iptuninfo[IFLA_IPTUN_LINK])
 170                        link = rta_getattr_u32(iptuninfo[IFLA_IPTUN_LINK]);
 171
 172                if (iptuninfo[IFLA_IPTUN_PROTO])
 173                        proto = rta_getattr_u8(iptuninfo[IFLA_IPTUN_PROTO]);
 174
 175                if (iptuninfo[IFLA_IPTUN_ENCAP_TYPE])
 176                        encaptype = rta_getattr_u16(iptuninfo[IFLA_IPTUN_ENCAP_TYPE]);
 177                if (iptuninfo[IFLA_IPTUN_ENCAP_FLAGS])
 178                        encapflags = rta_getattr_u16(iptuninfo[IFLA_IPTUN_ENCAP_FLAGS]);
 179                if (iptuninfo[IFLA_IPTUN_ENCAP_SPORT])
 180                        encapsport = rta_getattr_u16(iptuninfo[IFLA_IPTUN_ENCAP_SPORT]);
 181                if (iptuninfo[IFLA_IPTUN_ENCAP_DPORT])
 182                        encapdport = rta_getattr_u16(iptuninfo[IFLA_IPTUN_ENCAP_DPORT]);
 183
 184                if (iptuninfo[IFLA_IPTUN_COLLECT_METADATA])
 185                        metadata = 1;
 186
 187                if (iptuninfo[IFLA_IPTUN_FWMARK])
 188                        fwmark = rta_getattr_u32(iptuninfo[IFLA_IPTUN_FWMARK]);
 189
 190                free(answer);
 191        }
 192
 193        while (argc > 0) {
 194                if (strcmp(*argv, "mode") == 0) {
 195                        NEXT_ARG();
 196                        if (strcmp(lu->id, "sit") == 0 &&
 197                            (strcmp(*argv, "ipv6/ipv4") == 0 ||
 198                             strcmp(*argv, "ip6ip") == 0))
 199                                proto = IPPROTO_IPV6;
 200                        else if (strcmp(*argv, "ipv4/ipv4") == 0 ||
 201                                 strcmp(*argv, "ipip") == 0 ||
 202                                 strcmp(*argv, "ip4ip4") == 0)
 203                                proto = IPPROTO_IPIP;
 204                        else if (strcmp(*argv, "mpls/ipv4") == 0 ||
 205                                   strcmp(*argv, "mplsip") == 0)
 206                                proto = IPPROTO_MPLS;
 207                        else if (strcmp(*argv, "any/ipv4") == 0 ||
 208                                 strcmp(*argv, "any") == 0)
 209                                proto = 0;
 210                        else
 211                                invarg("Cannot guess tunnel mode.", *argv);
 212                } else if (strcmp(*argv, "remote") == 0) {
 213                        NEXT_ARG();
 214                        get_addr(&daddr, *argv, AF_INET);
 215                } else if (strcmp(*argv, "local") == 0) {
 216                        NEXT_ARG();
 217                        get_addr(&saddr, *argv, AF_INET);
 218                } else if (matches(*argv, "dev") == 0) {
 219                        NEXT_ARG();
 220                        link = ll_name_to_index(*argv);
 221                        if (!link)
 222                                exit(nodev(*argv));
 223                } else if (strcmp(*argv, "ttl") == 0 ||
 224                           strcmp(*argv, "hoplimit") == 0 ||
 225                           strcmp(*argv, "hlim") == 0) {
 226                        NEXT_ARG();
 227                        if (strcmp(*argv, "inherit") != 0) {
 228                                if (get_u8(&ttl, *argv, 0))
 229                                        invarg("invalid TTL\n", *argv);
 230                        } else
 231                                ttl = 0;
 232                } else if (strcmp(*argv, "tos") == 0 ||
 233                           strcmp(*argv, "tclass") == 0 ||
 234                           strcmp(*argv, "tc") == 0 ||
 235                           matches(*argv, "dsfield") == 0) {
 236                        __u32 uval;
 237
 238                        NEXT_ARG();
 239                        if (strcmp(*argv, "inherit") != 0) {
 240                                if (rtnl_dsfield_a2n(&uval, *argv))
 241                                        invarg("bad TOS value", *argv);
 242                                tos = uval;
 243                        } else
 244                                tos = 1;
 245                } else if (strcmp(*argv, "nopmtudisc") == 0) {
 246                        pmtudisc = 0;
 247                } else if (strcmp(*argv, "pmtudisc") == 0) {
 248                        pmtudisc = 1;
 249                } else if (strcmp(lu->id, "sit") == 0 &&
 250                           strcmp(*argv, "isatap") == 0) {
 251                        iflags |= SIT_ISATAP;
 252                } else if (strcmp(*argv, "noencap") == 0) {
 253                        encaptype = TUNNEL_ENCAP_NONE;
 254                } else if (strcmp(*argv, "encap") == 0) {
 255                        NEXT_ARG();
 256                        if (strcmp(*argv, "fou") == 0)
 257                                encaptype = TUNNEL_ENCAP_FOU;
 258                        else if (strcmp(*argv, "gue") == 0)
 259                                encaptype = TUNNEL_ENCAP_GUE;
 260                        else if (strcmp(*argv, "none") == 0)
 261                                encaptype = TUNNEL_ENCAP_NONE;
 262                        else
 263                                invarg("Invalid encap type.", *argv);
 264                } else if (strcmp(*argv, "encap-sport") == 0) {
 265                        NEXT_ARG();
 266                        if (strcmp(*argv, "auto") == 0)
 267                                encapsport = 0;
 268                        else if (get_u16(&encapsport, *argv, 0))
 269                                invarg("Invalid source port.", *argv);
 270                } else if (strcmp(*argv, "encap-dport") == 0) {
 271                        NEXT_ARG();
 272                        if (get_u16(&encapdport, *argv, 0))
 273                                invarg("Invalid destination port.", *argv);
 274                } else if (strcmp(*argv, "encap-csum") == 0) {
 275                        encapflags |= TUNNEL_ENCAP_FLAG_CSUM;
 276                } else if (strcmp(*argv, "noencap-csum") == 0) {
 277                        encapflags &= ~TUNNEL_ENCAP_FLAG_CSUM;
 278                } else if (strcmp(*argv, "encap-udp6-csum") == 0) {
 279                        encapflags |= TUNNEL_ENCAP_FLAG_CSUM6;
 280                } else if (strcmp(*argv, "noencap-udp6-csum") == 0) {
 281                        encapflags &= ~TUNNEL_ENCAP_FLAG_CSUM6;
 282                } else if (strcmp(*argv, "encap-remcsum") == 0) {
 283                        encapflags |= TUNNEL_ENCAP_FLAG_REMCSUM;
 284                } else if (strcmp(*argv, "noencap-remcsum") == 0) {
 285                        encapflags &= ~TUNNEL_ENCAP_FLAG_REMCSUM;
 286                } else if (strcmp(*argv, "external") == 0) {
 287                        metadata = 1;
 288                } else if (strcmp(*argv, "6rd-prefix") == 0) {
 289                        NEXT_ARG();
 290                        if (get_prefix(&ip6rdprefix, *argv, AF_INET6))
 291                                invarg("invalid 6rd_prefix\n", *argv);
 292                } else if (strcmp(*argv, "6rd-relay_prefix") == 0) {
 293                        NEXT_ARG();
 294                        if (get_prefix(&ip6rdrelayprefix, *argv, AF_INET))
 295                                invarg("invalid 6rd-relay_prefix\n", *argv);
 296                } else if (strcmp(*argv, "6rd-reset") == 0) {
 297                        get_prefix(&ip6rdprefix, "2002::/16", AF_INET6);
 298                        inet_prefix_reset(&ip6rdrelayprefix);
 299                } else if (strcmp(*argv, "fwmark") == 0) {
 300                        NEXT_ARG();
 301                        if (get_u32(&fwmark, *argv, 0))
 302                                invarg("invalid fwmark\n", *argv);
 303                } else {
 304                        iptunnel_print_help(lu, argc, argv, stderr);
 305                        return -1;
 306                }
 307                argc--, argv++;
 308        }
 309
 310        if (ttl && pmtudisc == 0) {
 311                fprintf(stderr, "ttl != 0 and nopmtudisc are incompatible\n");
 312                exit(-1);
 313        }
 314
 315        addattr8(n, 1024, IFLA_IPTUN_PROTO, proto);
 316        if (metadata) {
 317                addattr_l(n, 1024, IFLA_IPTUN_COLLECT_METADATA, NULL, 0);
 318                return 0;
 319        }
 320
 321        if (is_addrtype_inet_not_unspec(&saddr)) {
 322                addattr_l(n, 1024, IFLA_IPTUN_LOCAL,
 323                          saddr.data, saddr.bytelen);
 324        }
 325        if (is_addrtype_inet_not_unspec(&daddr)) {
 326                addattr_l(n, 1024, IFLA_IPTUN_REMOTE,
 327                          daddr.data, daddr.bytelen);
 328        }
 329        addattr8(n, 1024, IFLA_IPTUN_PMTUDISC, pmtudisc);
 330        addattr8(n, 1024, IFLA_IPTUN_TOS, tos);
 331        addattr8(n, 1024, IFLA_IPTUN_TTL, ttl);
 332        addattr32(n, 1024, IFLA_IPTUN_LINK, link);
 333        addattr32(n, 1024, IFLA_IPTUN_FWMARK, fwmark);
 334
 335        addattr16(n, 1024, IFLA_IPTUN_ENCAP_TYPE, encaptype);
 336        addattr16(n, 1024, IFLA_IPTUN_ENCAP_FLAGS, encapflags);
 337        addattr16(n, 1024, IFLA_IPTUN_ENCAP_SPORT, htons(encapsport));
 338        addattr16(n, 1024, IFLA_IPTUN_ENCAP_DPORT, htons(encapdport));
 339
 340        if (strcmp(lu->id, "sit") == 0) {
 341                addattr16(n, 1024, IFLA_IPTUN_FLAGS, iflags);
 342                if (is_addrtype_inet(&ip6rdprefix)) {
 343                        addattr_l(n, 1024, IFLA_IPTUN_6RD_PREFIX,
 344                                  ip6rdprefix.data, ip6rdprefix.bytelen);
 345                        addattr16(n, 1024, IFLA_IPTUN_6RD_PREFIXLEN,
 346                                  ip6rdprefix.bitlen);
 347                }
 348                if (is_addrtype_inet(&ip6rdrelayprefix)) {
 349                        addattr32(n, 1024, IFLA_IPTUN_6RD_RELAY_PREFIX,
 350                                  ip6rdrelayprefix.data[0]);
 351                        addattr16(n, 1024, IFLA_IPTUN_6RD_RELAY_PREFIXLEN,
 352                                  ip6rdrelayprefix.bitlen);
 353                }
 354        }
 355
 356        return 0;
 357}
 358
 359static void iptunnel_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
 360{
 361        char s2[64];
 362        __u16 prefixlen;
 363        __u8 ttl = 0;
 364        __u8 tos = 0;
 365
 366        if (!tb)
 367                return;
 368
 369        if (tb[IFLA_IPTUN_COLLECT_METADATA]) {
 370                print_bool(PRINT_ANY, "external", "external ", true);
 371        }
 372
 373        if (tb[IFLA_IPTUN_PROTO]) {
 374                switch (rta_getattr_u8(tb[IFLA_IPTUN_PROTO])) {
 375                case IPPROTO_IPIP:
 376                        print_string(PRINT_ANY, "proto", "%s ", "ipip");
 377                        break;
 378                case IPPROTO_IPV6:
 379                        print_string(PRINT_ANY, "proto", "%s ", "ip6ip");
 380                        break;
 381                case IPPROTO_MPLS:
 382                        print_string(PRINT_ANY, "proto", "%s ", "mplsip");
 383                        break;
 384                case 0:
 385                        print_string(PRINT_ANY, "proto", "%s ", "any");
 386                        break;
 387                }
 388        }
 389
 390        tnl_print_endpoint("remote", tb[IFLA_IPTUN_REMOTE], AF_INET);
 391        tnl_print_endpoint("local", tb[IFLA_IPTUN_LOCAL], AF_INET);
 392
 393        if (tb[IFLA_IPTUN_LINK]) {
 394                __u32 link = rta_getattr_u32(tb[IFLA_IPTUN_LINK]);
 395
 396                if (link) {
 397                        print_string(PRINT_ANY, "link", "dev %s ",
 398                                     ll_index_to_name(link));
 399                }
 400        }
 401
 402        if (tb[IFLA_IPTUN_TTL])
 403                ttl = rta_getattr_u8(tb[IFLA_IPTUN_TTL]);
 404        if (is_json_context() || ttl)
 405                print_uint(PRINT_ANY, "ttl", "ttl %u ", ttl);
 406        else
 407                print_string(PRINT_FP, NULL, "ttl %s ", "inherit");
 408
 409        if (tb[IFLA_IPTUN_TOS])
 410                tos = rta_getattr_u8(tb[IFLA_IPTUN_TOS]);
 411        if (tos) {
 412                if (is_json_context() || tos != 1)
 413                        print_0xhex(PRINT_ANY, "tos", "tos %#llx ", tos);
 414                else
 415                        print_string(PRINT_FP, NULL, "tos %s ", "inherit");
 416        }
 417
 418        if (tb[IFLA_IPTUN_PMTUDISC] && rta_getattr_u8(tb[IFLA_IPTUN_PMTUDISC]))
 419                print_bool(PRINT_ANY, "pmtudisc", "pmtudisc ", true);
 420        else
 421                print_bool(PRINT_ANY, "pmtudisc", "nopmtudisc ", false);
 422
 423        if (tb[IFLA_IPTUN_FLAGS]) {
 424                __u16 iflags = rta_getattr_u16(tb[IFLA_IPTUN_FLAGS]);
 425
 426                if (iflags & SIT_ISATAP)
 427                        print_bool(PRINT_ANY, "isatap", "isatap ", true);
 428        }
 429
 430        if (tb[IFLA_IPTUN_6RD_PREFIXLEN] &&
 431            (prefixlen = rta_getattr_u16(tb[IFLA_IPTUN_6RD_PREFIXLEN]))) {
 432                __u16 relayprefixlen =
 433                        rta_getattr_u16(tb[IFLA_IPTUN_6RD_RELAY_PREFIXLEN]);
 434                __u32 relayprefix =
 435                        rta_getattr_u32(tb[IFLA_IPTUN_6RD_RELAY_PREFIX]);
 436
 437                const char *prefix = inet_ntop(AF_INET6,
 438                                               RTA_DATA(tb[IFLA_IPTUN_6RD_PREFIX]),
 439                                               s2, sizeof(s2));
 440
 441                if (is_json_context()) {
 442                        print_string(PRINT_JSON, "prefix", NULL, prefix);
 443                        print_int(PRINT_JSON, "prefixlen", NULL, prefixlen);
 444                        if (relayprefix) {
 445                                print_string(PRINT_JSON,
 446                                             "relay_prefix",
 447                                             NULL,
 448                                             format_host(AF_INET,
 449                                                         4,
 450                                                         &relayprefix));
 451                                print_int(PRINT_JSON,
 452                                          "relay_prefixlen",
 453                                          NULL,
 454                                          relayprefixlen);
 455                        }
 456                } else {
 457                        printf("6rd-prefix %s/%u ", prefix, prefixlen);
 458                        if (relayprefix) {
 459                                printf("6rd-relay_prefix %s/%u ",
 460                                       format_host(AF_INET, 4, &relayprefix),
 461                                       relayprefixlen);
 462                        }
 463                }
 464        }
 465
 466        if (tb[IFLA_IPTUN_FWMARK]) {
 467                __u32 fwmark = rta_getattr_u32(tb[IFLA_IPTUN_FWMARK]);
 468
 469                if (fwmark) {
 470                        print_0xhex(PRINT_ANY,
 471                                    "fwmark", "fwmark %#llx ", fwmark);
 472                }
 473        }
 474
 475        tnl_print_encap(tb,
 476                        IFLA_IPTUN_ENCAP_TYPE,
 477                        IFLA_IPTUN_ENCAP_FLAGS,
 478                        IFLA_IPTUN_ENCAP_SPORT,
 479                        IFLA_IPTUN_ENCAP_DPORT);
 480}
 481
 482struct link_util ipip_link_util = {
 483        .id = "ipip",
 484        .maxattr = IFLA_IPTUN_MAX,
 485        .parse_opt = iptunnel_parse_opt,
 486        .print_opt = iptunnel_print_opt,
 487        .print_help = iptunnel_print_help,
 488};
 489
 490struct link_util sit_link_util = {
 491        .id = "sit",
 492        .maxattr = IFLA_IPTUN_MAX,
 493        .parse_opt = iptunnel_parse_opt,
 494        .print_opt = iptunnel_print_opt,
 495        .print_help = iptunnel_print_help,
 496};
 497