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