#include "ip_common.h"
#include "tunnel.h"
-
-static void usage(void) __attribute__((noreturn));
-static void usage(void)
+static void vti6_print_help(struct link_util *lu, int argc, char **argv,
+ FILE *f)
{
- fprintf(stderr, "Usage: ip link { add | set | change | replace | del } NAME\n");
- fprintf(stderr, " type { vti6 } [ remote ADDR ] [ local ADDR ]\n");
- fprintf(stderr, " [ [i|o]key KEY ]\n");
- fprintf(stderr, " [ dev PHYS_DEV ]\n");
- fprintf(stderr, "\n");
- fprintf(stderr, "Where: NAME := STRING\n");
- fprintf(stderr, " ADDR := { IPV6_ADDRESS }\n");
- fprintf(stderr, " KEY := { DOTTED_QUAD | NUMBER }\n");
- exit(-1);
+ fprintf(f,
+ "Usage: ... %-4s [ remote ADDR ]\n",
+ lu->id
+ );
+ fprintf(f,
+ " [ local ADDR ]\n"
+ " [ [i|o]key KEY ]\n"
+ " [ dev PHYS_DEV ]\n"
+ " [ fwmark MARK ]\n"
+ "\n"
+ );
+ fprintf(f,
+ "Where: ADDR := { IP%s_ADDRESS }\n"
+ " KEY := { DOTTED_QUAD | NUMBER }\n"
+ " MARK := { 0x0..0xffffffff }\n",
+ "V6"
+ );
}
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;
- char buf[1024];
- } req;
- struct ifinfomsg *ifi = (struct ifinfomsg *)(n + 1);
+ } 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;
struct rtattr *tb[IFLA_MAX + 1];
struct rtattr *linkinfo[IFLA_INFO_MAX+1];
struct rtattr *vtiinfo[IFLA_VTI_MAX + 1];
- struct in6_addr saddr;
- struct in6_addr daddr;
- unsigned ikey = 0;
- unsigned okey = 0;
- unsigned link = 0;
+ __be32 ikey = 0;
+ __be32 okey = 0;
+ inet_prefix saddr, daddr;
+ unsigned int link = 0;
+ __u32 fwmark = 0;
int len;
- if (!(n->nlmsg_flags & NLM_F_CREATE)) {
- memset(&req, 0, sizeof(req));
+ inet_prefix_reset(&saddr);
+ inet_prefix_reset(&daddr);
- req.n.nlmsg_len = NLMSG_LENGTH(sizeof(*ifi));
- req.n.nlmsg_flags = NLM_F_REQUEST;
- req.n.nlmsg_type = RTM_GETLINK;
- req.i.ifi_family = preferred_family;
- req.i.ifi_index = ifi->ifi_index;
+ if (!(n->nlmsg_flags & NLM_F_CREATE)) {
+ const struct rtattr *rta;
- if (rtnl_talk(&rth, &req.n, &req.n, sizeof(req)) < 0) {
+ if (rtnl_talk(&rth, &req.n, &answer) < 0) {
get_failed:
fprintf(stderr,
"Failed to get existing tunnel info.\n");
return -1;
}
- len = req.n.nlmsg_len;
+ len = answer->nlmsg_len;
len -= NLMSG_LENGTH(sizeof(*ifi));
if (len < 0)
goto get_failed;
- parse_rtattr(tb, IFLA_MAX, IFLA_RTA(&req.i), len);
+ parse_rtattr(tb, IFLA_MAX, IFLA_RTA(NLMSG_DATA(answer)), len);
if (!tb[IFLA_LINKINFO])
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_LOCAL])
- memcpy(&saddr, RTA_DATA(vtiinfo[IFLA_VTI_LOCAL]), sizeof(saddr));
-
- if (vtiinfo[IFLA_VTI_REMOTE])
- memcpy(&daddr, RTA_DATA(vtiinfo[IFLA_VTI_REMOTE]), sizeof(daddr));
-
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")) {
- unsigned uval;
-
NEXT_ARG();
- if (strchr(*argv, '.'))
- uval = get_addr32(*argv);
- else {
- if (get_unsigned(&uval, *argv, 0) < 0) {
- fprintf(stderr,
- "Invalid value for \"key\": \"%s\"; it should be an unsigned integer\n", *argv);
- exit(-1);
- }
- uval = htonl(uval);
- }
-
- ikey = okey = uval;
+ ikey = okey = tnl_parse_key("key", *argv);
} else if (!matches(*argv, "ikey")) {
- unsigned uval;
-
NEXT_ARG();
- if (strchr(*argv, '.'))
- uval = get_addr32(*argv);
- else {
- if (get_unsigned(&uval, *argv, 0) < 0) {
- fprintf(stderr, "invalid value for \"ikey\": \"%s\"; it should be an unsigned integer\n", *argv);
- exit(-1);
- }
- uval = htonl(uval);
- }
- ikey = uval;
+ ikey = tnl_parse_key("ikey", *argv);
} else if (!matches(*argv, "okey")) {
- unsigned uval;
-
NEXT_ARG();
- if (strchr(*argv, '.'))
- uval = get_addr32(*argv);
- else {
- if (get_unsigned(&uval, *argv, 0) < 0) {
- fprintf(stderr, "invalid value for \"okey\": \"%s\"; it should be an unsigned integer\n", *argv);
- exit(-1);
- }
- uval = htonl(uval);
- }
- okey = uval;
+ okey = tnl_parse_key("okey", *argv);
} else if (!matches(*argv, "remote")) {
NEXT_ARG();
- if (!strcmp(*argv, "any")) {
- fprintf(stderr, "invalid value for \"remote\": \"%s\"\n", *argv);
- exit(-1);
- } else {
- inet_prefix addr;
- get_prefix(&addr, *argv, AF_INET6);
- memcpy(&daddr, addr.data, addr.bytelen);
- }
+ get_addr(&daddr, *argv, AF_INET6);
} else if (!matches(*argv, "local")) {
NEXT_ARG();
- if (!strcmp(*argv, "any")) {
- fprintf(stderr, "invalid value for \"local\": \"%s\"\n", *argv);
- exit(-1);
- } else {
- inet_prefix addr;
- get_prefix(&addr, *argv, AF_INET6);
- memcpy(&saddr, addr.data, addr.bytelen);
- }
+ get_addr(&saddr, *argv, AF_INET6);
} else if (!matches(*argv, "dev")) {
NEXT_ARG();
- link = if_nametoindex(*argv);
- if (link == 0)
- exit(-1);
- } else
- usage();
+ 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);
- addattr_l(n, 1024, IFLA_VTI_LOCAL, &saddr, sizeof(saddr));
- addattr_l(n, 1024, IFLA_VTI_REMOTE, &daddr, sizeof(daddr));
+ 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);
static void vti6_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
{
- char s1[1024];
char s2[64];
- const char *local = "any";
- const char *remote = "any";
- struct in6_addr saddr;
- struct in6_addr daddr;
if (!tb)
return;
- if (tb[IFLA_VTI_REMOTE]) {
- memcpy(&daddr, RTA_DATA(tb[IFLA_VTI_REMOTE]), sizeof(daddr));
+ tnl_print_endpoint("remote", tb[IFLA_VTI_REMOTE], AF_INET6);
+ tnl_print_endpoint("local", tb[IFLA_VTI_LOCAL], AF_INET6);
- remote = format_host(AF_INET6, 16, &daddr, s1, sizeof(s1));
- }
+ if (tb[IFLA_VTI_LINK]) {
+ __u32 link = rta_getattr_u32(tb[IFLA_VTI_LINK]);
- fprintf(f, "remote %s ", remote);
+ if (link) {
+ print_string(PRINT_ANY, "link", "dev %s ",
+ ll_index_to_name(link));
+ }
+ }
- if (tb[IFLA_VTI_LOCAL]) {
- memcpy(&saddr, RTA_DATA(tb[IFLA_VTI_LOCAL]), sizeof(saddr));
+ if (tb[IFLA_VTI_IKEY]) {
+ struct rtattr *rta = tb[IFLA_VTI_IKEY];
+ __u32 key = rta_getattr_u32(rta);
- local = format_host(AF_INET6, 16, &saddr, s1, sizeof(s1));
+ if (key && inet_ntop(AF_INET, RTA_DATA(rta), s2, sizeof(s2)))
+ print_string(PRINT_ANY, "ikey", "ikey %s ", s2);
}
- fprintf(f, "local %s ", local);
-
- if (tb[IFLA_VTI_LINK] && *(__u32 *)RTA_DATA(tb[IFLA_VTI_LINK])) {
- unsigned link = *(__u32 *)RTA_DATA(tb[IFLA_VTI_LINK]);
- const char *n = if_indextoname(link, s2);
+ if (tb[IFLA_VTI_OKEY]) {
+ struct rtattr *rta = tb[IFLA_VTI_OKEY];
+ __u32 key = rta_getattr_u32(rta);
- if (n)
- fprintf(f, "dev %s ", n);
- else
- fprintf(f, "dev %u ", link);
+ if (key && inet_ntop(AF_INET, RTA_DATA(rta), s2, sizeof(s2)))
+ print_string(PRINT_ANY, "okey", "okey %s ", s2);
}
- if (tb[IFLA_VTI_IKEY]) {
- inet_ntop(AF_INET, RTA_DATA(tb[IFLA_VTI_IKEY]), s2, sizeof(s2));
- fprintf(f, "ikey %s ", s2);
- }
+ if (tb[IFLA_VTI_FWMARK]) {
+ __u32 fwmark = rta_getattr_u32(tb[IFLA_VTI_FWMARK]);
- if (tb[IFLA_VTI_OKEY]) {
- inet_ntop(AF_INET, RTA_DATA(tb[IFLA_VTI_OKEY]), s2, sizeof(s2));
- fprintf(f, "okey %s ", s2);
+ if (fwmark) {
+ print_0xhex(PRINT_ANY,
+ "fwmark", "fwmark %#llx ", fwmark);
+ }
}
}
.maxattr = IFLA_VTI_MAX,
.parse_opt = vti6_parse_opt,
.print_opt = vti6_print_opt,
+ .print_help = vti6_print_help,
};