]> git.proxmox.com Git - mirror_iproute2.git/blobdiff - ip/link_gre.c
libnetlink: add size argument to rtnl_talk
[mirror_iproute2.git] / ip / link_gre.c
index 9109312beb7a2e6f3a8413aeabe9fd050cd5bbc6..58f416ca9720bc7bbc0ae661329f7473189f9f3c 100644 (file)
 
 #include <string.h>
 #include <net/if.h>
-#include <linux/if_tunnel.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 print_usage(FILE *f)
+{
+       fprintf(f, "Usage: ip link { add | set | change | replace | del } NAME\n");
+       fprintf(f, "          type { gre | gretap } [ remote ADDR ] [ local ADDR ]\n");
+       fprintf(f, "          [ [i|o]seq ] [ [i|o]key KEY ] [ [i|o]csum ]\n");
+       fprintf(f, "          [ ttl TTL ] [ tos TOS ] [ [no]pmtudisc ] [ dev PHYS_DEV ]\n");
+       fprintf(f, "          [ noencap ] [ encap { fou | gue | none } ]\n");
+       fprintf(f, "          [ encap-sport PORT ] [ encap-dport PORT ]\n");
+       fprintf(f, "          [ [no]encap-csum ] [ [no]encap-csum6 ] [ [no]encap-remcsum ]\n");
+       fprintf(f, "\n");
+       fprintf(f, "Where: NAME := STRING\n");
+       fprintf(f, "       ADDR := { IP_ADDRESS | any }\n");
+       fprintf(f, "       TOS  := { NUMBER | inherit }\n");
+       fprintf(f, "       TTL  := { 1..255 | inherit }\n");
+       fprintf(f, "       KEY  := { DOTTED_QUAD | NUMBER }\n");
+}
+
 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");
+       print_usage(stderr);
        exit(-1);
 }
 
@@ -44,7 +53,7 @@ static int gre_parse_opt(struct link_util *lu, int argc, char **argv,
        struct {
                struct nlmsghdr n;
                struct ifinfomsg i;
-               char buf[1024];
+               char buf[16384];
        } req;
        struct ifinfomsg *ifi = (struct ifinfomsg *)(n + 1);
        struct rtattr *tb[IFLA_MAX + 1];
@@ -61,6 +70,10 @@ static int gre_parse_opt(struct link_util *lu, int argc, char **argv,
        __u8 ttl = 0;
        __u8 tos = 0;
        int len;
+       __u16 encaptype = 0;
+       __u16 encapflags = 0;
+       __u16 encapsport = 0;
+       __u16 encapdport = 0;
 
        if (!(n->nlmsg_flags & NLM_F_CREATE)) {
                memset(&req, 0, sizeof(req));
@@ -71,7 +84,7 @@ static int gre_parse_opt(struct link_util *lu, int argc, char **argv,
                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) {
+               if (rtnl_talk(&rth, &req.n, &req.n, sizeof(req)) < 0) {
 get_failed:
                        fprintf(stderr,
                                "Failed to get existing tunnel info.\n");
@@ -97,35 +110,44 @@ get_failed:
                                    linkinfo[IFLA_INFO_DATA]);
 
                if (greinfo[IFLA_GRE_IKEY])
-                       ikey = *(__u32 *)RTA_DATA(greinfo[IFLA_GRE_IKEY]);
+                       ikey = rta_getattr_u32(greinfo[IFLA_GRE_IKEY]);
 
                if (greinfo[IFLA_GRE_OKEY])
-                       okey = *(__u32 *)RTA_DATA(greinfo[IFLA_GRE_OKEY]);
+                       okey = rta_getattr_u32(greinfo[IFLA_GRE_OKEY]);
 
                if (greinfo[IFLA_GRE_IFLAGS])
-                       iflags = *(__u16 *)RTA_DATA(greinfo[IFLA_GRE_IFLAGS]);
+                       iflags = rta_getattr_u16(greinfo[IFLA_GRE_IFLAGS]);
 
                if (greinfo[IFLA_GRE_OFLAGS])
-                       oflags = *(__u16 *)RTA_DATA(greinfo[IFLA_GRE_OFLAGS]);
+                       oflags = rta_getattr_u16(greinfo[IFLA_GRE_OFLAGS]);
 
                if (greinfo[IFLA_GRE_LOCAL])
-                       saddr = *(__u32 *)RTA_DATA(greinfo[IFLA_GRE_LOCAL]);
+                       saddr = rta_getattr_u32(greinfo[IFLA_GRE_LOCAL]);
 
                if (greinfo[IFLA_GRE_REMOTE])
-                       daddr = *(__u32 *)RTA_DATA(greinfo[IFLA_GRE_REMOTE]);
+                       daddr = rta_getattr_u32(greinfo[IFLA_GRE_REMOTE]);
 
                if (greinfo[IFLA_GRE_PMTUDISC])
-                       pmtudisc = *(__u8 *)RTA_DATA(
+                       pmtudisc = rta_getattr_u8(
                                greinfo[IFLA_GRE_PMTUDISC]);
 
                if (greinfo[IFLA_GRE_TTL])
-                       ttl = *(__u8 *)RTA_DATA(greinfo[IFLA_GRE_TTL]);
+                       ttl = rta_getattr_u8(greinfo[IFLA_GRE_TTL]);
 
                if (greinfo[IFLA_GRE_TOS])
-                       tos = *(__u8 *)RTA_DATA(greinfo[IFLA_GRE_TOS]);
+                       tos = rta_getattr_u8(greinfo[IFLA_GRE_TOS]);
 
                if (greinfo[IFLA_GRE_LINK])
-                       link = *(__u8 *)RTA_DATA(greinfo[IFLA_GRE_LINK]);
+                       link = rta_getattr_u8(greinfo[IFLA_GRE_LINK]);
+
+               if (greinfo[IFLA_GRE_ENCAP_TYPE])
+                       encaptype = rta_getattr_u16(greinfo[IFLA_GRE_ENCAP_TYPE]);
+               if (greinfo[IFLA_GRE_ENCAP_FLAGS])
+                       encapflags = rta_getattr_u16(greinfo[IFLA_GRE_ENCAP_FLAGS]);
+               if (greinfo[IFLA_GRE_ENCAP_SPORT])
+                       encapsport = rta_getattr_u16(greinfo[IFLA_GRE_ENCAP_SPORT]);
+               if (greinfo[IFLA_GRE_ENCAP_DPORT])
+                       encapdport = rta_getattr_u16(greinfo[IFLA_GRE_ENCAP_DPORT]);
        }
 
        while (argc > 0) {
@@ -140,7 +162,7 @@ get_failed:
                        else {
                                if (get_unsigned(&uval, *argv, 0) < 0) {
                                        fprintf(stderr,
-                                               "Invalid value for \"key\"\n");
+                                               "Invalid value for \"key\": \"%s\"; it should be an unsigned integer\n", *argv);
                                        exit(-1);
                                }
                                uval = htonl(uval);
@@ -156,7 +178,7 @@ get_failed:
                                uval = get_addr32(*argv);
                        else {
                                if (get_unsigned(&uval, *argv, 0)<0) {
-                                       fprintf(stderr, "invalid value of \"ikey\"\n");
+                                       fprintf(stderr, "invalid value for \"ikey\": \"%s\"; it should be an unsigned integer\n", *argv);
                                        exit(-1);
                                }
                                uval = htonl(uval);
@@ -171,7 +193,7 @@ get_failed:
                                uval = get_addr32(*argv);
                        else {
                                if (get_unsigned(&uval, *argv, 0)<0) {
-                                       fprintf(stderr, "invalid value of \"okey\"\n");
+                                       fprintf(stderr, "invalid value for \"okey\": \"%s\"; it should be an unsigned integer\n", *argv);
                                        exit(-1);
                                }
                                uval = htonl(uval);
@@ -205,9 +227,12 @@ get_failed:
                                saddr = get_addr32(*argv);
                } else if (!matches(*argv, "dev")) {
                        NEXT_ARG();
-                       link = tnl_ioctl_get_ifindex(*argv);
-                       if (link == 0)
+                       link = if_nametoindex(*argv);
+                       if (link == 0) {
+                               fprintf(stderr, "Cannot find device \"%s\"\n",
+                                       *argv);
                                exit(-1);
+                       }
                } else if (!matches(*argv, "ttl") ||
                           !matches(*argv, "hoplimit")) {
                        unsigned uval;
@@ -232,7 +257,41 @@ get_failed:
                                tos = uval;
                        } else
                                tos = 1;
-               } else 
+               } else if (strcmp(*argv, "noencap") == 0) {
+                       encaptype = TUNNEL_ENCAP_NONE;
+               } else if (strcmp(*argv, "encap") == 0) {
+                       NEXT_ARG();
+                       if (strcmp(*argv, "fou") == 0)
+                               encaptype = TUNNEL_ENCAP_FOU;
+                       else if (strcmp(*argv, "gue") == 0)
+                               encaptype = TUNNEL_ENCAP_GUE;
+                       else if (strcmp(*argv, "none") == 0)
+                               encaptype = TUNNEL_ENCAP_NONE;
+                       else
+                               invarg("Invalid encap type.", *argv);
+               } else if (strcmp(*argv, "encap-sport") == 0) {
+                       NEXT_ARG();
+                       if (strcmp(*argv, "auto") == 0)
+                               encapsport = 0;
+                       else if (get_u16(&encapsport, *argv, 0))
+                               invarg("Invalid source port.", *argv);
+               } else if (strcmp(*argv, "encap-dport") == 0) {
+                       NEXT_ARG();
+                       if (get_u16(&encapdport, *argv, 0))
+                               invarg("Invalid destination port.", *argv);
+               } else if (strcmp(*argv, "encap-csum") == 0) {
+                       encapflags |= TUNNEL_ENCAP_FLAG_CSUM;
+               } else if (strcmp(*argv, "noencap-csum") == 0) {
+                       encapflags &= ~TUNNEL_ENCAP_FLAG_CSUM;
+               } else if (strcmp(*argv, "encap-udp6-csum") == 0) {
+                       encapflags |= TUNNEL_ENCAP_FLAG_CSUM6;
+               } else if (strcmp(*argv, "noencap-udp6-csum") == 0) {
+                       encapflags |= ~TUNNEL_ENCAP_FLAG_CSUM6;
+               } else if (strcmp(*argv, "encap-remcsum") == 0) {
+                       encapflags |= TUNNEL_ENCAP_FLAG_REMCSUM;
+               } else if (strcmp(*argv, "noencap-remcsum") == 0) {
+                       encapflags |= ~TUNNEL_ENCAP_FLAG_REMCSUM;
+               } else
                        usage();
                argc--; argv++;
        }
@@ -246,7 +305,7 @@ get_failed:
                oflags |= GRE_KEY;
        }
        if (IN_MULTICAST(ntohl(daddr)) && !saddr) {
-               fprintf(stderr, "Broadcast tunnel requires a source address.\n");
+               fprintf(stderr, "A broadcast tunnel requires a source address.\n");
                return -1;
        }
 
@@ -262,6 +321,11 @@ get_failed:
        addattr_l(n, 1024, IFLA_GRE_TTL, &ttl, 1);
        addattr_l(n, 1024, IFLA_GRE_TOS, &tos, 1);
 
+       addattr16(n, 1024, IFLA_GRE_ENCAP_TYPE, encaptype);
+       addattr16(n, 1024, IFLA_GRE_ENCAP_FLAGS, encapflags);
+       addattr16(n, 1024, IFLA_GRE_ENCAP_SPORT, htons(encapsport));
+       addattr16(n, 1024, IFLA_GRE_ENCAP_DPORT, htons(encapdport));
+
        return 0;
 }
 
@@ -278,7 +342,7 @@ static void gre_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
                return;
 
        if (tb[IFLA_GRE_REMOTE]) {
-               unsigned addr = *(__u32 *)RTA_DATA(tb[IFLA_GRE_REMOTE]);
+               unsigned addr = rta_getattr_u32(tb[IFLA_GRE_REMOTE]);
 
                if (addr)
                        remote = format_host(AF_INET, 4, &addr, s1, sizeof(s1));
@@ -287,7 +351,7 @@ static void gre_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
        fprintf(f, "remote %s ", remote);
 
        if (tb[IFLA_GRE_LOCAL]) {
-               unsigned addr = *(__u32 *)RTA_DATA(tb[IFLA_GRE_LOCAL]);
+               unsigned addr = rta_getattr_u32(tb[IFLA_GRE_LOCAL]);
 
                if (addr)
                        local = format_host(AF_INET, 4, &addr, s1, sizeof(s1));
@@ -295,9 +359,9 @@ static void gre_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
 
        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]);
-               char *n = tnl_ioctl_get_ifname(link);
+       if (tb[IFLA_GRE_LINK] && rta_getattr_u32(tb[IFLA_GRE_LINK])) {
+               unsigned link = rta_getattr_u32(tb[IFLA_GRE_LINK]);
+               const char *n = if_indextoname(link, s2);
 
                if (n)
                        fprintf(f, "dev %s ", n);
@@ -305,13 +369,13 @@ static void gre_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
                        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]));
+       if (tb[IFLA_GRE_TTL] && rta_getattr_u8(tb[IFLA_GRE_TTL]))
+               fprintf(f, "ttl %d ", rta_getattr_u8(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]);
+       if (tb[IFLA_GRE_TOS] && rta_getattr_u8(tb[IFLA_GRE_TOS])) {
+               int tos = rta_getattr_u8(tb[IFLA_GRE_TOS]);
 
                fputs("tos ", f);
                if (tos == 1)
@@ -321,25 +385,23 @@ static void gre_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
        }
 
        if (tb[IFLA_GRE_PMTUDISC] &&
-           !*(__u8 *)RTA_DATA(tb[IFLA_GRE_PMTUDISC]))
+           !rta_getattr_u8(tb[IFLA_GRE_PMTUDISC]))
                fputs("nopmtudisc ", f);
 
        if (tb[IFLA_GRE_IFLAGS])
-               iflags = *(__u16 *)RTA_DATA(tb[IFLA_GRE_IFLAGS]);
+               iflags = rta_getattr_u16(tb[IFLA_GRE_IFLAGS]);
 
        if (tb[IFLA_GRE_OFLAGS])
-               oflags = *(__u16 *)RTA_DATA(tb[IFLA_GRE_OFLAGS]);
+               oflags = rta_getattr_u16(tb[IFLA_GRE_OFLAGS]);
 
-       if (iflags & GRE_KEY && tb[IFLA_GRE_IKEY] &&
-           *(__u32 *)RTA_DATA(tb[IFLA_GRE_IKEY])) {
+       if ((iflags & GRE_KEY) && 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])) {
+       if ((oflags & GRE_KEY) && tb[IFLA_GRE_OKEY]) {
                inet_ntop(AF_INET, RTA_DATA(tb[IFLA_GRE_OKEY]), s2, sizeof(s2));
-               fprintf(f, "ikey %s ", s2);
+               fprintf(f, "okey %s ", s2);
        }
 
        if (iflags & GRE_SEQ)
@@ -350,6 +412,55 @@ static void gre_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
                fputs("icsum ", f);
        if (oflags & GRE_CSUM)
                fputs("ocsum ", f);
+
+       if (tb[IFLA_GRE_ENCAP_TYPE] &&
+           *(__u16 *)RTA_DATA(tb[IFLA_GRE_ENCAP_TYPE]) != TUNNEL_ENCAP_NONE) {
+               __u16 type = rta_getattr_u16(tb[IFLA_GRE_ENCAP_TYPE]);
+               __u16 flags = rta_getattr_u16(tb[IFLA_GRE_ENCAP_FLAGS]);
+               __u16 sport = rta_getattr_u16(tb[IFLA_GRE_ENCAP_SPORT]);
+               __u16 dport = rta_getattr_u16(tb[IFLA_GRE_ENCAP_DPORT]);
+
+               fputs("encap ", f);
+               switch (type) {
+               case TUNNEL_ENCAP_FOU:
+                       fputs("fou ", f);
+                       break;
+               case TUNNEL_ENCAP_GUE:
+                       fputs("gue ", f);
+                       break;
+               default:
+                       fputs("unknown ", f);
+                       break;
+               }
+
+               if (sport == 0)
+                       fputs("encap-sport auto ", f);
+               else
+                       fprintf(f, "encap-sport %u", ntohs(sport));
+
+               fprintf(f, "encap-dport %u ", ntohs(dport));
+
+               if (flags & TUNNEL_ENCAP_FLAG_CSUM)
+                       fputs("encap-csum ", f);
+               else
+                       fputs("noencap-csum ", f);
+
+               if (flags & TUNNEL_ENCAP_FLAG_CSUM6)
+                       fputs("encap-csum6 ", f);
+               else
+                       fputs("noencap-csum6 ", f);
+
+               if (flags & TUNNEL_ENCAP_FLAG_REMCSUM)
+                       fputs("encap-remcsum ", f);
+               else
+                       fputs("noencap-remcsum ", f);
+       }
+}
+
+static void gre_print_help(struct link_util *lu, int argc, char **argv,
+       FILE *f)
+{
+       print_usage(f);
 }
 
 struct link_util gre_link_util = {
@@ -357,6 +468,7 @@ struct link_util gre_link_util = {
        .maxattr = IFLA_GRE_MAX,
        .parse_opt = gre_parse_opt,
        .print_opt = gre_print_opt,
+       .print_help = gre_print_help,
 };
 
 struct link_util gretap_link_util = {
@@ -364,4 +476,5 @@ struct link_util gretap_link_util = {
        .maxattr = IFLA_GRE_MAX,
        .parse_opt = gre_parse_opt,
        .print_opt = gre_print_opt,
+       .print_help = gre_print_help,
 };