From 72c771b20e38eaabb7699625fcdc144a51771f9c Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Tue, 6 Jan 2009 18:27:52 -0800 Subject: [PATCH] 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 --- ip/link_gre.c | 101 +++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 87 insertions(+), 14 deletions(-) diff --git a/ip/link_gre.c b/ip/link_gre.c index e92b0d376..9109312be 100644 --- a/ip/link_gre.c +++ b/ip/link_gre.c @@ -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; } -- 2.47.2