mirror of
https://git.kernel.org/pub/scm/network/iproute2/iproute2.git
synced 2024-11-17 06:53:26 +08:00
cd70f3f522
Both rtnl_talk and rtnl_dump had a callback for handling portions of netlink message that do not match the correct pid or seq. But this callback was never used by any part of iproute2 so remove it.
369 lines
9.1 KiB
C
369 lines
9.1 KiB
C
/*
|
|
* link_gre.c gre driver module
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version
|
|
* 2 of the License, or (at your option) any later version.
|
|
*
|
|
* Authors: Herbert Xu <herbert@gondor.apana.org.au>
|
|
*
|
|
*/
|
|
|
|
#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 usage(void) __attribute__((noreturn));
|
|
static void usage(void)
|
|
{
|
|
fprintf(stderr, "Usage: ip link { add | set | change | replace | del } NAME\n");
|
|
fprintf(stderr, " type { gre | gretap } [ remote ADDR ] [ local ADDR ]\n");
|
|
fprintf(stderr, " [ [i|o]seq ] [ [i|o]key KEY ] [ [i|o]csum ]\n");
|
|
fprintf(stderr, " [ ttl TTL ] [ tos TOS ] [ [no]pmtudisc ] [ dev PHYS_DEV ]\n");
|
|
fprintf(stderr, "\n");
|
|
fprintf(stderr, "Where: NAME := STRING\n");
|
|
fprintf(stderr, " ADDR := { IP_ADDRESS | any }\n");
|
|
fprintf(stderr, " TOS := { NUMBER | inherit }\n");
|
|
fprintf(stderr, " TTL := { 1..255 | inherit }\n");
|
|
fprintf(stderr, " KEY := { DOTTED_QUAD | NUMBER }\n");
|
|
exit(-1);
|
|
}
|
|
|
|
static int gre_parse_opt(struct link_util *lu, int argc, char **argv,
|
|
struct nlmsghdr *n)
|
|
{
|
|
struct {
|
|
struct nlmsghdr n;
|
|
struct ifinfomsg i;
|
|
char buf[1024];
|
|
} req;
|
|
struct ifinfomsg *ifi = (struct ifinfomsg *)(n + 1);
|
|
struct rtattr *tb[IFLA_MAX + 1];
|
|
struct rtattr *linkinfo[IFLA_INFO_MAX+1];
|
|
struct rtattr *greinfo[IFLA_GRE_MAX + 1];
|
|
__u16 iflags = 0;
|
|
__u16 oflags = 0;
|
|
unsigned ikey = 0;
|
|
unsigned okey = 0;
|
|
unsigned saddr = 0;
|
|
unsigned daddr = 0;
|
|
unsigned link = 0;
|
|
__u8 pmtudisc = 1;
|
|
__u8 ttl = 0;
|
|
__u8 tos = 0;
|
|
int len;
|
|
|
|
if (!(n->nlmsg_flags & NLM_F_CREATE)) {
|
|
memset(&req, 0, sizeof(req));
|
|
|
|
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 (rtnl_talk(&rth, &req.n, 0, 0, &req.n) < 0) {
|
|
get_failed:
|
|
fprintf(stderr,
|
|
"Failed to get existing tunnel info.\n");
|
|
return -1;
|
|
}
|
|
|
|
len = req.n.nlmsg_len;
|
|
len -= NLMSG_LENGTH(sizeof(*ifi));
|
|
if (len < 0)
|
|
goto get_failed;
|
|
|
|
parse_rtattr(tb, IFLA_MAX, IFLA_RTA(&req.i), 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(greinfo, IFLA_GRE_MAX,
|
|
linkinfo[IFLA_INFO_DATA]);
|
|
|
|
if (greinfo[IFLA_GRE_IKEY])
|
|
ikey = *(__u32 *)RTA_DATA(greinfo[IFLA_GRE_IKEY]);
|
|
|
|
if (greinfo[IFLA_GRE_OKEY])
|
|
okey = *(__u32 *)RTA_DATA(greinfo[IFLA_GRE_OKEY]);
|
|
|
|
if (greinfo[IFLA_GRE_IFLAGS])
|
|
iflags = *(__u16 *)RTA_DATA(greinfo[IFLA_GRE_IFLAGS]);
|
|
|
|
if (greinfo[IFLA_GRE_OFLAGS])
|
|
oflags = *(__u16 *)RTA_DATA(greinfo[IFLA_GRE_OFLAGS]);
|
|
|
|
if (greinfo[IFLA_GRE_LOCAL])
|
|
saddr = *(__u32 *)RTA_DATA(greinfo[IFLA_GRE_LOCAL]);
|
|
|
|
if (greinfo[IFLA_GRE_REMOTE])
|
|
daddr = *(__u32 *)RTA_DATA(greinfo[IFLA_GRE_REMOTE]);
|
|
|
|
if (greinfo[IFLA_GRE_PMTUDISC])
|
|
pmtudisc = *(__u8 *)RTA_DATA(
|
|
greinfo[IFLA_GRE_PMTUDISC]);
|
|
|
|
if (greinfo[IFLA_GRE_TTL])
|
|
ttl = *(__u8 *)RTA_DATA(greinfo[IFLA_GRE_TTL]);
|
|
|
|
if (greinfo[IFLA_GRE_TOS])
|
|
tos = *(__u8 *)RTA_DATA(greinfo[IFLA_GRE_TOS]);
|
|
|
|
if (greinfo[IFLA_GRE_LINK])
|
|
link = *(__u8 *)RTA_DATA(greinfo[IFLA_GRE_LINK]);
|
|
}
|
|
|
|
while (argc > 0) {
|
|
if (!matches(*argv, "key")) {
|
|
unsigned uval;
|
|
|
|
NEXT_ARG();
|
|
iflags |= GRE_KEY;
|
|
oflags |= GRE_KEY;
|
|
if (strchr(*argv, '.'))
|
|
uval = get_addr32(*argv);
|
|
else {
|
|
if (get_unsigned(&uval, *argv, 0) < 0) {
|
|
fprintf(stderr,
|
|
"Invalid value for \"key\"\n");
|
|
exit(-1);
|
|
}
|
|
uval = htonl(uval);
|
|
}
|
|
|
|
ikey = okey = uval;
|
|
} else if (!matches(*argv, "ikey")) {
|
|
unsigned uval;
|
|
|
|
NEXT_ARG();
|
|
iflags |= GRE_KEY;
|
|
if (strchr(*argv, '.'))
|
|
uval = get_addr32(*argv);
|
|
else {
|
|
if (get_unsigned(&uval, *argv, 0)<0) {
|
|
fprintf(stderr, "invalid value of \"ikey\"\n");
|
|
exit(-1);
|
|
}
|
|
uval = htonl(uval);
|
|
}
|
|
ikey = uval;
|
|
} else if (!matches(*argv, "okey")) {
|
|
unsigned uval;
|
|
|
|
NEXT_ARG();
|
|
oflags |= GRE_KEY;
|
|
if (strchr(*argv, '.'))
|
|
uval = get_addr32(*argv);
|
|
else {
|
|
if (get_unsigned(&uval, *argv, 0)<0) {
|
|
fprintf(stderr, "invalid value of \"okey\"\n");
|
|
exit(-1);
|
|
}
|
|
uval = htonl(uval);
|
|
}
|
|
okey = uval;
|
|
} else if (!matches(*argv, "seq")) {
|
|
iflags |= GRE_SEQ;
|
|
oflags |= GRE_SEQ;
|
|
} else if (!matches(*argv, "iseq")) {
|
|
iflags |= GRE_SEQ;
|
|
} else if (!matches(*argv, "oseq")) {
|
|
oflags |= GRE_SEQ;
|
|
} else if (!matches(*argv, "csum")) {
|
|
iflags |= GRE_CSUM;
|
|
oflags |= GRE_CSUM;
|
|
} else if (!matches(*argv, "icsum")) {
|
|
iflags |= GRE_CSUM;
|
|
} else if (!matches(*argv, "ocsum")) {
|
|
oflags |= GRE_CSUM;
|
|
} else if (!matches(*argv, "nopmtudisc")) {
|
|
pmtudisc = 0;
|
|
} else if (!matches(*argv, "pmtudisc")) {
|
|
pmtudisc = 1;
|
|
} else if (!matches(*argv, "remote")) {
|
|
NEXT_ARG();
|
|
if (strcmp(*argv, "any"))
|
|
daddr = get_addr32(*argv);
|
|
} else if (!matches(*argv, "local")) {
|
|
NEXT_ARG();
|
|
if (strcmp(*argv, "any"))
|
|
saddr = get_addr32(*argv);
|
|
} else if (!matches(*argv, "dev")) {
|
|
NEXT_ARG();
|
|
link = if_nametoindex(*argv);
|
|
if (link == 0)
|
|
exit(-1);
|
|
} else if (!matches(*argv, "ttl") ||
|
|
!matches(*argv, "hoplimit")) {
|
|
unsigned uval;
|
|
|
|
NEXT_ARG();
|
|
if (strcmp(*argv, "inherit") != 0) {
|
|
if (get_unsigned(&uval, *argv, 0))
|
|
invarg("invalid TTL\n", *argv);
|
|
if (uval > 255)
|
|
invarg("TTL must be <= 255\n", *argv);
|
|
ttl = uval;
|
|
}
|
|
} else if (!matches(*argv, "tos") ||
|
|
!matches(*argv, "tclass") ||
|
|
!matches(*argv, "dsfield")) {
|
|
__u32 uval;
|
|
|
|
NEXT_ARG();
|
|
if (strcmp(*argv, "inherit") != 0) {
|
|
if (rtnl_dsfield_a2n(&uval, *argv))
|
|
invarg("bad TOS value", *argv);
|
|
tos = uval;
|
|
} else
|
|
tos = 1;
|
|
} else
|
|
usage();
|
|
argc--; argv++;
|
|
}
|
|
|
|
if (!ikey && IN_MULTICAST(ntohl(daddr))) {
|
|
ikey = daddr;
|
|
iflags |= GRE_KEY;
|
|
}
|
|
if (!okey && IN_MULTICAST(ntohl(daddr))) {
|
|
okey = daddr;
|
|
oflags |= GRE_KEY;
|
|
}
|
|
if (IN_MULTICAST(ntohl(daddr)) && !saddr) {
|
|
fprintf(stderr, "Broadcast tunnel requires a source address.\n");
|
|
return -1;
|
|
}
|
|
|
|
addattr32(n, 1024, IFLA_GRE_IKEY, ikey);
|
|
addattr32(n, 1024, IFLA_GRE_OKEY, okey);
|
|
addattr_l(n, 1024, IFLA_GRE_IFLAGS, &iflags, 2);
|
|
addattr_l(n, 1024, IFLA_GRE_OFLAGS, &oflags, 2);
|
|
addattr_l(n, 1024, IFLA_GRE_LOCAL, &saddr, 4);
|
|
addattr_l(n, 1024, IFLA_GRE_REMOTE, &daddr, 4);
|
|
addattr_l(n, 1024, IFLA_GRE_PMTUDISC, &pmtudisc, 1);
|
|
if (link)
|
|
addattr32(n, 1024, IFLA_GRE_LINK, link);
|
|
addattr_l(n, 1024, IFLA_GRE_TTL, &ttl, 1);
|
|
addattr_l(n, 1024, IFLA_GRE_TOS, &tos, 1);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void gre_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";
|
|
unsigned iflags = 0;
|
|
unsigned oflags = 0;
|
|
|
|
if (!tb)
|
|
return;
|
|
|
|
if (tb[IFLA_GRE_REMOTE]) {
|
|
unsigned addr = *(__u32 *)RTA_DATA(tb[IFLA_GRE_REMOTE]);
|
|
|
|
if (addr)
|
|
remote = format_host(AF_INET, 4, &addr, s1, sizeof(s1));
|
|
}
|
|
|
|
fprintf(f, "remote %s ", remote);
|
|
|
|
if (tb[IFLA_GRE_LOCAL]) {
|
|
unsigned addr = *(__u32 *)RTA_DATA(tb[IFLA_GRE_LOCAL]);
|
|
|
|
if (addr)
|
|
local = format_host(AF_INET, 4, &addr, s1, sizeof(s1));
|
|
}
|
|
|
|
fprintf(f, "local %s ", local);
|
|
|
|
if (tb[IFLA_GRE_LINK] && *(__u32 *)RTA_DATA(tb[IFLA_GRE_LINK])) {
|
|
unsigned link = *(__u32 *)RTA_DATA(tb[IFLA_GRE_LINK]);
|
|
const char *n = if_indextoname(link, s2);
|
|
|
|
if (n)
|
|
fprintf(f, "dev %s ", n);
|
|
else
|
|
fprintf(f, "dev %u ", link);
|
|
}
|
|
|
|
if (tb[IFLA_GRE_TTL] && *(__u8 *)RTA_DATA(tb[IFLA_GRE_TTL]))
|
|
fprintf(f, "ttl %d ", *(__u8 *)RTA_DATA(tb[IFLA_GRE_TTL]));
|
|
else
|
|
fprintf(f, "ttl inherit ");
|
|
|
|
if (tb[IFLA_GRE_TOS] && *(__u8 *)RTA_DATA(tb[IFLA_GRE_TOS])) {
|
|
int tos = *(__u8 *)RTA_DATA(tb[IFLA_GRE_TOS]);
|
|
|
|
fputs("tos ", f);
|
|
if (tos == 1)
|
|
fputs("inherit ", f);
|
|
else
|
|
fprintf(f, "0x%x ", tos);
|
|
}
|
|
|
|
if (tb[IFLA_GRE_PMTUDISC] &&
|
|
!*(__u8 *)RTA_DATA(tb[IFLA_GRE_PMTUDISC]))
|
|
fputs("nopmtudisc ", f);
|
|
|
|
if (tb[IFLA_GRE_IFLAGS])
|
|
iflags = *(__u16 *)RTA_DATA(tb[IFLA_GRE_IFLAGS]);
|
|
|
|
if (tb[IFLA_GRE_OFLAGS])
|
|
oflags = *(__u16 *)RTA_DATA(tb[IFLA_GRE_OFLAGS]);
|
|
|
|
if (iflags & GRE_KEY && tb[IFLA_GRE_IKEY] &&
|
|
*(__u32 *)RTA_DATA(tb[IFLA_GRE_IKEY])) {
|
|
inet_ntop(AF_INET, RTA_DATA(tb[IFLA_GRE_IKEY]), s2, sizeof(s2));
|
|
fprintf(f, "ikey %s ", s2);
|
|
}
|
|
|
|
if (oflags & GRE_KEY && tb[IFLA_GRE_OKEY] &&
|
|
*(__u32 *)RTA_DATA(tb[IFLA_GRE_OKEY])) {
|
|
inet_ntop(AF_INET, RTA_DATA(tb[IFLA_GRE_OKEY]), s2, sizeof(s2));
|
|
fprintf(f, "ikey %s ", s2);
|
|
}
|
|
|
|
if (iflags & GRE_SEQ)
|
|
fputs("iseq ", f);
|
|
if (oflags & GRE_SEQ)
|
|
fputs("oseq ", f);
|
|
if (iflags & GRE_CSUM)
|
|
fputs("icsum ", f);
|
|
if (oflags & GRE_CSUM)
|
|
fputs("ocsum ", f);
|
|
}
|
|
|
|
struct link_util gre_link_util = {
|
|
.id = "gre",
|
|
.maxattr = IFLA_GRE_MAX,
|
|
.parse_opt = gre_parse_opt,
|
|
.print_opt = gre_print_opt,
|
|
};
|
|
|
|
struct link_util gretap_link_util = {
|
|
.id = "gretap",
|
|
.maxattr = IFLA_GRE_MAX,
|
|
.parse_opt = gre_parse_opt,
|
|
.print_opt = gre_print_opt,
|
|
};
|