iproute2/ip/link_vti6.c
<<
>>
Prefs
   1/*
   2 * link_vti6.c  VTI 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:     Herbert Xu <herbert@gondor.apana.org.au>
  10 *              Saurabh Mohan <saurabh.mohan@vyatta.com> Modified link_gre.c for VTI
  11 *              Steffen Klassert <steffen.klassert@secunet.com> Modified link_vti.c for IPv6
  12 */
  13
  14#include <string.h>
  15#include <net/if.h>
  16#include <sys/types.h>
  17#include <sys/socket.h>
  18#include <arpa/inet.h>
  19
  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 vti6_print_help(struct link_util *lu, int argc, char **argv,
  28                            FILE *f)
  29{
  30        fprintf(f,
  31                "Usage: ... %-4s        [ remote ADDR ]\n"
  32                "               [ local ADDR ]\n"
  33                "               [ [i|o]key KEY ]\n"
  34                "               [ dev PHYS_DEV ]\n"
  35                "               [ fwmark MARK ]\n"
  36                "\n"
  37                "Where: ADDR := { IPV6_ADDRESS }\n"
  38                "       KEY  := { DOTTED_QUAD | NUMBER }\n"
  39                "       MARK := { 0x0..0xffffffff }\n",
  40                lu->id);
  41}
  42
  43static int vti6_parse_opt(struct link_util *lu, int argc, char **argv,
  44                          struct nlmsghdr *n)
  45{
  46        struct ifinfomsg *ifi = NLMSG_DATA(n);
  47        struct {
  48                struct nlmsghdr n;
  49                struct ifinfomsg i;
  50        } req = {
  51                .n.nlmsg_len = NLMSG_LENGTH(sizeof(*ifi)),
  52                .n.nlmsg_flags = NLM_F_REQUEST,
  53                .n.nlmsg_type = RTM_GETLINK,
  54                .i.ifi_family = preferred_family,
  55                .i.ifi_index = ifi->ifi_index,
  56        };
  57        struct nlmsghdr *answer;
  58        struct rtattr *tb[IFLA_MAX + 1];
  59        struct rtattr *linkinfo[IFLA_INFO_MAX+1];
  60        struct rtattr *vtiinfo[IFLA_VTI_MAX + 1];
  61        __be32 ikey = 0;
  62        __be32 okey = 0;
  63        inet_prefix saddr, daddr;
  64        unsigned int link = 0;
  65        __u32 fwmark = 0;
  66        int len;
  67
  68        inet_prefix_reset(&saddr);
  69        inet_prefix_reset(&daddr);
  70
  71        if (!(n->nlmsg_flags & NLM_F_CREATE)) {
  72                const struct rtattr *rta;
  73
  74                if (rtnl_talk(&rth, &req.n, &answer) < 0) {
  75get_failed:
  76                        fprintf(stderr,
  77                                "Failed to get existing tunnel info.\n");
  78                        return -1;
  79                }
  80
  81                len = answer->nlmsg_len;
  82                len -= NLMSG_LENGTH(sizeof(*ifi));
  83                if (len < 0)
  84                        goto get_failed;
  85
  86                parse_rtattr(tb, IFLA_MAX, IFLA_RTA(NLMSG_DATA(answer)), len);
  87
  88                if (!tb[IFLA_LINKINFO])
  89                        goto get_failed;
  90
  91                parse_rtattr_nested(linkinfo, IFLA_INFO_MAX, tb[IFLA_LINKINFO]);
  92
  93                if (!linkinfo[IFLA_INFO_DATA])
  94                        goto get_failed;
  95
  96                parse_rtattr_nested(vtiinfo, IFLA_VTI_MAX,
  97                                    linkinfo[IFLA_INFO_DATA]);
  98
  99                rta = vtiinfo[IFLA_VTI_LOCAL];
 100                if (rta && get_addr_rta(&saddr, rta, AF_INET6))
 101                        goto get_failed;
 102
 103                rta = vtiinfo[IFLA_VTI_REMOTE];
 104                if (rta && get_addr_rta(&daddr, rta, AF_INET6))
 105                        goto get_failed;
 106
 107                if (vtiinfo[IFLA_VTI_IKEY])
 108                        ikey = rta_getattr_u32(vtiinfo[IFLA_VTI_IKEY]);
 109
 110                if (vtiinfo[IFLA_VTI_OKEY])
 111                        okey = rta_getattr_u32(vtiinfo[IFLA_VTI_OKEY]);
 112
 113                if (vtiinfo[IFLA_VTI_LINK])
 114                        link = rta_getattr_u8(vtiinfo[IFLA_VTI_LINK]);
 115
 116                if (vtiinfo[IFLA_VTI_FWMARK])
 117                        fwmark = rta_getattr_u32(vtiinfo[IFLA_VTI_FWMARK]);
 118
 119                free(answer);
 120        }
 121
 122        while (argc > 0) {
 123                if (!matches(*argv, "key")) {
 124                        NEXT_ARG();
 125                        ikey = okey = tnl_parse_key("key", *argv);
 126                } else if (!matches(*argv, "ikey")) {
 127                        NEXT_ARG();
 128                        ikey = tnl_parse_key("ikey", *argv);
 129                } else if (!matches(*argv, "okey")) {
 130                        NEXT_ARG();
 131                        okey = tnl_parse_key("okey", *argv);
 132                } else if (!matches(*argv, "remote")) {
 133                        NEXT_ARG();
 134                        get_addr(&daddr, *argv, AF_INET6);
 135                } else if (!matches(*argv, "local")) {
 136                        NEXT_ARG();
 137                        get_addr(&saddr, *argv, AF_INET6);
 138                } else if (!matches(*argv, "dev")) {
 139                        NEXT_ARG();
 140                        link = ll_name_to_index(*argv);
 141                        if (!link)
 142                                exit(nodev(*argv));
 143                } else if (strcmp(*argv, "fwmark") == 0) {
 144                        NEXT_ARG();
 145                        if (get_u32(&fwmark, *argv, 0))
 146                                invarg("invalid fwmark\n", *argv);
 147                } else {
 148                        vti6_print_help(lu, argc, argv, stderr);
 149                        return -1;
 150                }
 151                argc--; argv++;
 152        }
 153
 154        addattr32(n, 1024, IFLA_VTI_IKEY, ikey);
 155        addattr32(n, 1024, IFLA_VTI_OKEY, okey);
 156        if (is_addrtype_inet_not_unspec(&saddr))
 157                addattr_l(n, 1024, IFLA_VTI_LOCAL, saddr.data, saddr.bytelen);
 158        if (is_addrtype_inet_not_unspec(&daddr))
 159                addattr_l(n, 1024, IFLA_VTI_REMOTE, daddr.data, daddr.bytelen);
 160        addattr32(n, 1024, IFLA_VTI_FWMARK, fwmark);
 161        if (link)
 162                addattr32(n, 1024, IFLA_VTI_LINK, link);
 163
 164        return 0;
 165}
 166
 167static void vti6_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
 168{
 169        char s2[64];
 170
 171        if (!tb)
 172                return;
 173
 174        tnl_print_endpoint("remote", tb[IFLA_VTI_REMOTE], AF_INET6);
 175        tnl_print_endpoint("local", tb[IFLA_VTI_LOCAL], AF_INET6);
 176
 177        if (tb[IFLA_VTI_LINK]) {
 178                __u32 link = rta_getattr_u32(tb[IFLA_VTI_LINK]);
 179
 180                if (link) {
 181                        print_string(PRINT_ANY, "link", "dev %s ",
 182                                     ll_index_to_name(link));
 183                }
 184        }
 185
 186        if (tb[IFLA_VTI_IKEY]) {
 187                struct rtattr *rta = tb[IFLA_VTI_IKEY];
 188                __u32 key = rta_getattr_u32(rta);
 189
 190                if (key && inet_ntop(AF_INET, RTA_DATA(rta), s2, sizeof(s2)))
 191                        print_string(PRINT_ANY, "ikey", "ikey %s ", s2);
 192        }
 193
 194        if (tb[IFLA_VTI_OKEY]) {
 195                struct rtattr *rta = tb[IFLA_VTI_OKEY];
 196                __u32 key = rta_getattr_u32(rta);
 197
 198                if (key && inet_ntop(AF_INET, RTA_DATA(rta), s2, sizeof(s2)))
 199                        print_string(PRINT_ANY, "okey", "okey %s ", s2);
 200        }
 201
 202        if (tb[IFLA_VTI_FWMARK]) {
 203                __u32 fwmark = rta_getattr_u32(tb[IFLA_VTI_FWMARK]);
 204
 205                if (fwmark) {
 206                        print_0xhex(PRINT_ANY,
 207                                    "fwmark", "fwmark %#llx ", fwmark);
 208                }
 209        }
 210}
 211
 212struct link_util vti6_link_util = {
 213        .id = "vti6",
 214        .maxattr = IFLA_VTI_MAX,
 215        .parse_opt = vti6_parse_opt,
 216        .print_opt = vti6_print_opt,
 217        .print_help = vti6_print_help,
 218};
 219