Update version of IP gre

This patch adds support for configuring GRE tunnels using the
new rtnl_link interface.  This only works on kernels that have
the new GRE configuration interface.

This is accessed through the "ip link" command.  The previous
tunnel configuration interface "ip tunnel" remains as it is
and should be retained for compatibility with old kernels.

Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
This commit is contained in:
Herbert Xu 2009-01-06 18:27:52 -08:00 committed by Stephen Hemminger
parent 237d9e82c5
commit 72c771b20e
1 changed files with 87 additions and 14 deletions

View File

@ -41,12 +41,92 @@ static void usage(void)
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, NULL, NULL) < 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")) {
@ -112,13 +192,9 @@ static int gre_parse_opt(struct link_util *lu, int argc, char **argv,
} else if (!matches(*argv, "ocsum")) {
oflags |= GRE_CSUM;
} else if (!matches(*argv, "nopmtudisc")) {
__u8 val = 0;
addattr_l(n, 1024, IFLA_GRE_PMTUDISC, &val, 1);
pmtudisc = 0;
} else if (!matches(*argv, "pmtudisc")) {
__u8 val = 1;
addattr_l(n, 1024, IFLA_GRE_PMTUDISC, &val, 1);
pmtudisc = 1;
} else if (!matches(*argv, "remote")) {
NEXT_ARG();
if (strcmp(*argv, "any"))
@ -128,18 +204,13 @@ static int gre_parse_opt(struct link_util *lu, int argc, char **argv,
if (strcmp(*argv, "any"))
saddr = get_addr32(*argv);
} else if (!matches(*argv, "dev")) {
unsigned link;
NEXT_ARG();
link = tnl_ioctl_get_ifindex(*argv);
if (link == 0)
exit(-1);
addattr32(n, 1024, IFLA_GRE_LINK, link);
} else if (!matches(*argv, "ttl") ||
!matches(*argv, "hoplimit")) {
unsigned uval;
__u8 ttl;
NEXT_ARG();
if (strcmp(*argv, "inherit") != 0) {
@ -148,13 +219,11 @@ static int gre_parse_opt(struct link_util *lu, int argc, char **argv,
if (uval > 255)
invarg("TTL must be <= 255\n", *argv);
ttl = uval;
addattr_l(n, 1024, IFLA_GRE_TTL, &ttl, 1);
}
} else if (!matches(*argv, "tos") ||
!matches(*argv, "tclass") ||
!matches(*argv, "dsfield")) {
__u32 uval;
__u8 tos;
NEXT_ARG();
if (strcmp(*argv, "inherit") != 0) {
@ -163,7 +232,6 @@ static int gre_parse_opt(struct link_util *lu, int argc, char **argv,
tos = uval;
} else
tos = 1;
addattr_l(n, 1024, IFLA_GRE_TOS, &tos, 1);
} else
usage();
argc--; argv++;
@ -188,6 +256,11 @@ static int gre_parse_opt(struct link_util *lu, int argc, char **argv,
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;
}