]> git.ipfire.org Git - thirdparty/iproute2.git/commitdiff
ip: add support of 'ip link type [ipip|sit]'
authorNicolas Dichtel <nicolas.dichtel@6wind.com>
Wed, 12 Dec 2012 09:51:47 +0000 (10:51 +0100)
committerStephen Hemminger <shemminger@vyatta.com>
Wed, 12 Dec 2012 17:10:22 +0000 (09:10 -0800)
This patch allows to manage ip tunnels via the interface ip link.
The syntax for parameters is the same that 'ip tunnel'.

It also allows to display tunnels parameters with 'ip -details link' or
'ip -details monitor link'.

Signed-off-by: Nicolas Dichtel <nicolas.dichtel@6wind.com>
ip/Makefile
ip/iplink.c
ip/link_iptnl.c [new file with mode: 0644]

index abf54bf714ed57cbe1d5dfcfa647002114c367ff..2b606d4771c7ed4b57faa5ba8120a68096a13268 100644 (file)
@@ -4,7 +4,8 @@ IPOBJ=ip.o ipaddress.o ipaddrlabel.o iproute.o iprule.o ipnetns.o \
     ipxfrm.o xfrm_state.o xfrm_policy.o xfrm_monitor.o \
     iplink_vlan.o link_veth.o link_gre.o iplink_can.o \
     iplink_macvlan.o iplink_macvtap.o ipl2tp.o link_vti.o \
-    iplink_vxlan.o tcp_metrics.o iplink_ipoib.o ipnetconf.o link_ip6tnl.o
+    iplink_vxlan.o tcp_metrics.o iplink_ipoib.o ipnetconf.o link_ip6tnl.o \
+    link_iptnl.o
 
 RTMONOBJ=rtmon.o
 
index 8aac9fc93d441010209fe075505d11e10394a484..d73c705af55a026bf8d345a60ccb1fb9519e9b37 100644 (file)
@@ -84,7 +84,7 @@ void iplink_usage(void)
        if (iplink_have_newlink()) {
                fprintf(stderr, "\n");
                fprintf(stderr, "TYPE := { vlan | veth | vcan | dummy | ifb | macvlan | can |\n");
-               fprintf(stderr, "          bridge | ipoib | ip6tnl }\n");
+               fprintf(stderr, "          bridge | ipoib | ip6tnl | ipip | sit }\n");
        }
        exit(-1);
 }
diff --git a/ip/link_iptnl.c b/ip/link_iptnl.c
new file mode 100644 (file)
index 0000000..238722d
--- /dev/null
@@ -0,0 +1,340 @@
+/*
+ * link_iptnl.c        ipip and sit 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:    Nicolas Dichtel <nicolas.dichtel@6wind.com>
+ *
+ */
+
+#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(int sit) __attribute__((noreturn));
+static void usage(int sit)
+{
+       fprintf(stderr, "Usage: ip link { add | set | change | replace | del } NAME\n");
+       fprintf(stderr, "          type { ipip | sit } [ remote ADDR ] [ local ADDR ]\n");
+       fprintf(stderr, "          [ ttl TTL ] [ tos TOS ] [ [no]pmtudisc ] [ dev PHYS_DEV ]\n");
+       fprintf(stderr, "          [ 6rd-prefix ADDR ] [ 6rd-relay_prefix ADDR ] [ 6rd-reset ]\n");
+       if (sit)
+               fprintf(stderr, "          [ isatap ]\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");
+       exit(-1);
+}
+
+static int iptunnel_parse_opt(struct link_util *lu, int argc, char **argv,
+                             struct nlmsghdr *n)
+{
+       struct {
+               struct nlmsghdr n;
+               struct ifinfomsg i;
+               char buf[2048];
+       } req;
+       struct ifinfomsg *ifi = (struct ifinfomsg *)(n + 1);
+       struct rtattr *tb[IFLA_MAX + 1];
+       struct rtattr *linkinfo[IFLA_INFO_MAX+1];
+       struct rtattr *iptuninfo[IFLA_IPTUN_MAX + 1];
+       int len;
+       __u32 link = 0;
+       __u32 laddr = 0;
+       __u32 raddr = 0;
+       __u8 ttl = 0;
+       __u8 tos = 0;
+       __u8 pmtudisc = 1;
+       __u16 iflags = 0;
+       struct in6_addr ip6rdprefix;
+       __u16 ip6rdprefixlen = 0;
+       __u32 ip6rdrelayprefix = 0;
+       __u16 ip6rdrelayprefixlen = 0;
+
+       memset(&ip6rdprefix, 0, sizeof(ip6rdprefix));
+
+       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(iptuninfo, IFLA_IPTUN_MAX,
+                                   linkinfo[IFLA_INFO_DATA]);
+
+               if (iptuninfo[IFLA_IPTUN_LOCAL])
+                       laddr = rta_getattr_u32(iptuninfo[IFLA_IPTUN_LOCAL]);
+
+               if (iptuninfo[IFLA_IPTUN_REMOTE])
+                       raddr = rta_getattr_u32(iptuninfo[IFLA_IPTUN_REMOTE]);
+
+               if (iptuninfo[IFLA_IPTUN_TTL])
+                       ttl = rta_getattr_u8(iptuninfo[IFLA_IPTUN_TTL]);
+
+               if (iptuninfo[IFLA_IPTUN_TOS])
+                       tos = rta_getattr_u8(iptuninfo[IFLA_IPTUN_TOS]);
+
+               if (iptuninfo[IFLA_IPTUN_PMTUDISC])
+                       pmtudisc =
+                               rta_getattr_u8(iptuninfo[IFLA_IPTUN_PMTUDISC]);
+
+               if (iptuninfo[IFLA_IPTUN_FLAGS])
+                       iflags = rta_getattr_u16(iptuninfo[IFLA_IPTUN_FLAGS]);
+
+               if (iptuninfo[IFLA_IPTUN_LINK])
+                       link = rta_getattr_u32(iptuninfo[IFLA_IPTUN_LINK]);
+
+               if (iptuninfo[IFLA_IPTUN_6RD_PREFIX])
+                       memcpy(&ip6rdprefix,
+                              RTA_DATA(iptuninfo[IFLA_IPTUN_6RD_PREFIX]),
+                              sizeof(laddr));
+
+               if (iptuninfo[IFLA_IPTUN_6RD_PREFIXLEN])
+                       ip6rdprefixlen =
+                               rta_getattr_u16(iptuninfo[IFLA_IPTUN_6RD_PREFIXLEN]);
+
+               if (iptuninfo[IFLA_IPTUN_6RD_RELAY_PREFIX])
+                       ip6rdrelayprefix =
+                               rta_getattr_u32(iptuninfo[IFLA_IPTUN_6RD_RELAY_PREFIX]);
+
+               if (iptuninfo[IFLA_IPTUN_6RD_RELAY_PREFIXLEN])
+                       ip6rdrelayprefixlen =
+                               rta_getattr_u16(iptuninfo[IFLA_IPTUN_6RD_RELAY_PREFIXLEN]);
+       }
+
+       while (argc > 0) {
+               if (strcmp(*argv, "remote") == 0) {
+                       NEXT_ARG();
+                       if (strcmp(*argv, "any"))
+                               raddr = get_addr32(*argv);
+                       else
+                               raddr = 0;
+               } else if (strcmp(*argv, "local") == 0) {
+                       NEXT_ARG();
+                       if (strcmp(*argv, "any"))
+                               laddr = get_addr32(*argv);
+                       else
+                               laddr = 0;
+               } else if (matches(*argv, "dev") == 0) {
+                       NEXT_ARG();
+                       link = if_nametoindex(*argv);
+                       if (link == 0)
+                               invarg("\"dev\" is invalid", *argv);
+               } else if (strcmp(*argv, "ttl") == 0 ||
+                          strcmp(*argv, "hoplimit") == 0) {
+                       NEXT_ARG();
+                       if (strcmp(*argv, "inherit") != 0) {
+                               if (get_u8(&ttl, *argv, 0))
+                                       invarg("invalid TTL\n", *argv);
+                       } else
+                               ttl = 0;
+               } else if (strcmp(*argv, "tos") == 0 ||
+                          strcmp(*argv, "tclass") == 0 ||
+                          matches(*argv, "dsfield") == 0) {
+                       __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 if (strcmp(*argv, "nopmtudisc") == 0) {
+                       pmtudisc = 0;
+               } else if (strcmp(*argv, "pmtudisc") == 0) {
+                       pmtudisc = 1;
+               } else if (strcmp(lu->id, "sit") == 0 &&
+                          strcmp(*argv, "isatap") == 0) {
+                       iflags |= SIT_ISATAP;
+               } else if (strcmp(*argv, "6rd-prefix") == 0) {
+                       inet_prefix prefix;
+                       NEXT_ARG();
+                       if (get_prefix(&prefix, *argv, AF_INET6))
+                               invarg("invalid 6rd_prefix\n", *argv);
+                       memcpy(&ip6rdprefix, prefix.data, 16);
+                       ip6rdprefixlen = prefix.bitlen;
+               } else if (strcmp(*argv, "6rd-relay_prefix") == 0) {
+                       inet_prefix prefix;
+                       NEXT_ARG();
+                       if (get_prefix(&prefix, *argv, AF_INET))
+                               invarg("invalid 6rd-relay_prefix\n", *argv);
+                       memcpy(&ip6rdrelayprefix, prefix.data, 4);
+                       ip6rdrelayprefixlen = prefix.bitlen;
+               } else if (strcmp(*argv, "6rd-reset") == 0) {
+                       inet_prefix prefix;
+                       get_prefix(&prefix, "2002::", AF_INET6);
+                       memcpy(&ip6rdprefix, prefix.data, 16);
+                       ip6rdprefixlen = 16;
+                       ip6rdrelayprefix = 0;
+                       ip6rdrelayprefixlen = 0;
+               } else
+                       usage(strcmp(lu->id, "sit") == 0);
+               argc--, argv++;
+       }
+
+       if (ttl && pmtudisc == 0) {
+               fprintf(stderr, "ttl != 0 and noptmudisc are incompatible\n");
+               exit(-1);
+       }
+
+       addattr32(n, 1024, IFLA_IPTUN_LINK, link);
+       addattr32(n, 1024, IFLA_IPTUN_LOCAL, laddr);
+       addattr32(n, 1024, IFLA_IPTUN_REMOTE, raddr);
+       addattr8(n, 1024, IFLA_IPTUN_TTL, ttl);
+       addattr8(n, 1024, IFLA_IPTUN_TOS, tos);
+       addattr8(n, 1024, IFLA_IPTUN_PMTUDISC, pmtudisc);
+       if (strcmp(lu->id, "sit") == 0) {
+               addattr16(n, 1024, IFLA_IPTUN_FLAGS, iflags);
+               if (ip6rdprefixlen) {
+                       addattr_l(n, 1024, IFLA_IPTUN_6RD_PREFIX,
+                                 &ip6rdprefix, sizeof(ip6rdprefix));
+                       addattr16(n, 1024, IFLA_IPTUN_6RD_PREFIXLEN,
+                                 ip6rdprefixlen);
+                       addattr32(n, 1024, IFLA_IPTUN_6RD_RELAY_PREFIX,
+                                 ip6rdrelayprefix);
+                       addattr16(n, 1024, IFLA_IPTUN_6RD_RELAY_PREFIXLEN,
+                                 ip6rdrelayprefixlen);
+               }
+       }
+
+       return 0;
+}
+
+static void iptunnel_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";
+
+       if (!tb)
+               return;
+
+       if (tb[IFLA_IPTUN_REMOTE]) {
+               unsigned addr = rta_getattr_u32(tb[IFLA_IPTUN_REMOTE]);
+
+               if (addr)
+                       remote = format_host(AF_INET, 4, &addr, s1, sizeof(s1));
+       }
+
+       fprintf(f, "remote %s ", remote);
+
+       if (tb[IFLA_IPTUN_LOCAL]) {
+               unsigned addr = rta_getattr_u32(tb[IFLA_IPTUN_LOCAL]);
+
+               if (addr)
+                       local = format_host(AF_INET, 4, &addr, s1, sizeof(s1));
+       }
+
+       fprintf(f, "local %s ", local);
+
+       if (tb[IFLA_IPTUN_LINK] && rta_getattr_u32(tb[IFLA_IPTUN_LINK])) {
+               unsigned link = rta_getattr_u32(tb[IFLA_IPTUN_LINK]);
+               const char *n = if_indextoname(link, s2);
+
+               if (n)
+                       fprintf(f, "dev %s ", n);
+               else
+                       fprintf(f, "dev %u ", link);
+       }
+
+       if (tb[IFLA_IPTUN_TTL] && rta_getattr_u8(tb[IFLA_IPTUN_TTL]))
+               fprintf(f, "ttl %d ", rta_getattr_u8(tb[IFLA_IPTUN_TTL]));
+       else
+               fprintf(f, "ttl inherit ");
+
+       if (tb[IFLA_IPTUN_TOS] && rta_getattr_u8(tb[IFLA_IPTUN_TOS])) {
+               int tos = rta_getattr_u8(tb[IFLA_IPTUN_TOS]);
+
+               fputs("tos ", f);
+               if (tos == 1)
+                       fputs("inherit ", f);
+               else
+                       fprintf(f, "0x%x ", tos);
+       }
+
+       if (tb[IFLA_IPTUN_PMTUDISC] && rta_getattr_u8(tb[IFLA_IPTUN_PMTUDISC]))
+               fprintf(f, "pmtudisc ");
+       else
+               fprintf(f, "nopmtudisc ");
+
+       if (tb[IFLA_IPTUN_FLAGS]) {
+              __u16 iflags = rta_getattr_u16(tb[IFLA_IPTUN_FLAGS]);
+
+             if (iflags & SIT_ISATAP)
+                     fprintf(f, "isatap ");
+       }
+
+       if (tb[IFLA_IPTUN_6RD_PREFIXLEN] &&
+           *(__u16 *)RTA_DATA(tb[IFLA_IPTUN_6RD_PREFIXLEN])) {
+               __u16 prefixlen = rta_getattr_u16(tb[IFLA_IPTUN_6RD_PREFIXLEN]);
+               __u16 relayprefixlen =
+                       rta_getattr_u16(tb[IFLA_IPTUN_6RD_RELAY_PREFIXLEN]);
+               __u32 relayprefix =
+                       rta_getattr_u32(tb[IFLA_IPTUN_6RD_RELAY_PREFIX]);
+
+               printf("6rd-prefix %s/%u ",
+                      inet_ntop(AF_INET6, RTA_DATA(tb[IFLA_IPTUN_6RD_PREFIX]),
+                                s1, sizeof(s1)),
+                      prefixlen);
+               if (relayprefix) {
+                       printf("6rd-relay_prefix %s/%u ",
+                              format_host(AF_INET, 4, &relayprefix, s1,
+                                          sizeof(s1)),
+                              relayprefixlen);
+               }
+       }
+}
+
+struct link_util ipip_link_util = {
+       .id = "ipip",
+       .maxattr = IFLA_IPTUN_MAX,
+       .parse_opt = iptunnel_parse_opt,
+       .print_opt = iptunnel_print_opt,
+};
+
+struct link_util sit_link_util = {
+       .id = "sit",
+       .maxattr = IFLA_IPTUN_MAX,
+       .parse_opt = iptunnel_parse_opt,
+       .print_opt = iptunnel_print_opt,
+};