diff options
Diffstat (limited to 'ip/link_iptnl.c')
-rw-r--r-- | ip/link_iptnl.c | 278 |
1 files changed, 198 insertions, 80 deletions
diff --git a/ip/link_iptnl.c b/ip/link_iptnl.c index 9d6bc986..6a725e91 100644 --- a/ip/link_iptnl.c +++ b/ip/link_iptnl.c @@ -16,6 +16,7 @@ #include <sys/socket.h> #include <arpa/inet.h> +#include <linux/in.h> #include <linux/ip.h> #include <linux/if_tunnel.h> #include "rt_names.h" @@ -25,22 +26,40 @@ static void print_usage(FILE *f, int sit) { - fprintf(f, "Usage: ip link { add | set | change | replace | del } NAME\n"); - fprintf(f, " type { ipip | sit } [ remote ADDR ] [ local ADDR ]\n"); - fprintf(f, " [ ttl TTL ] [ tos TOS ] [ [no]pmtudisc ] [ dev PHYS_DEV ]\n"); - fprintf(f, " [ 6rd-prefix ADDR ] [ 6rd-relay_prefix ADDR ] [ 6rd-reset ]\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"); + const char *type = sit ? "sit " : "ipip"; + + fprintf(f, + "Usage: ... %s [ remote ADDR ]\n" + " [ local ADDR ]\n" + " [ ttl TTL ]\n" + " [ tos TOS ]\n" + " [ [no]pmtudisc ]\n" + " [ dev PHYS_DEV ]\n" + " [ 6rd-prefix ADDR ]\n" + " [ 6rd-relay_prefix ADDR ]\n" + " [ 6rd-reset ]\n" + " [ noencap ]\n" + " [ encap { fou | gue | none } ]\n" + " [ encap-sport PORT ]\n" + " [ encap-dport PORT ]\n" + " [ [no]encap-csum ]\n" + " [ [no]encap-csum6 ]\n" + " [ [no]encap-remcsum ]\n", + type + ); if (sit) { - fprintf(f, " [ mode { ip6ip | ipip | any } ]\n"); + fprintf(f, " [ mode { ip6ip | ipip | mplsip | any } ]\n"); fprintf(f, " [ isatap ]\n"); + } else { + fprintf(f, " [ mode { ipip | mplsip | any } ]\n"); } + fprintf(f, " [ external ]\n"); + fprintf(f, " [ fwmark MARK ]\n"); fprintf(f, "\n"); - fprintf(f, "Where: NAME := STRING\n"); - fprintf(f, " ADDR := { IP_ADDRESS | any }\n"); + fprintf(f, "Where: ADDR := { IP_ADDRESS | any }\n"); fprintf(f, " TOS := { NUMBER | inherit }\n"); fprintf(f, " TTL := { 1..255 | inherit }\n"); + fprintf(f, " MARK := { 0x0..0xffffffff }\n"); } static void usage(int sit) __attribute__((noreturn)); @@ -53,12 +72,18 @@ static void usage(int sit) static int iptunnel_parse_opt(struct link_util *lu, int argc, char **argv, struct nlmsghdr *n) { + struct ifinfomsg *ifi = (struct ifinfomsg *)(n + 1); struct { struct nlmsghdr n; struct ifinfomsg i; char buf[2048]; - } req; - struct ifinfomsg *ifi = (struct ifinfomsg *)(n + 1); + } req = { + .n.nlmsg_len = NLMSG_LENGTH(sizeof(*ifi)), + .n.nlmsg_flags = NLM_F_REQUEST, + .n.nlmsg_type = RTM_GETLINK, + .i.ifi_family = preferred_family, + .i.ifi_index = ifi->ifi_index, + }; struct rtattr *tb[IFLA_MAX + 1]; struct rtattr *linkinfo[IFLA_INFO_MAX+1]; struct rtattr *iptuninfo[IFLA_IPTUN_MAX + 1]; @@ -71,7 +96,7 @@ static int iptunnel_parse_opt(struct link_util *lu, int argc, char **argv, __u8 pmtudisc = 1; __u16 iflags = 0; __u8 proto = 0; - struct in6_addr ip6rdprefix; + struct in6_addr ip6rdprefix = {}; __u16 ip6rdprefixlen = 0; __u32 ip6rdrelayprefix = 0; __u16 ip6rdrelayprefixlen = 0; @@ -79,18 +104,10 @@ static int iptunnel_parse_opt(struct link_util *lu, int argc, char **argv, __u16 encapflags = 0; __u16 encapsport = 0; __u16 encapdport = 0; - - memset(&ip6rdprefix, 0, sizeof(ip6rdprefix)); + __u8 metadata = 0; + __u32 fwmark = 0; 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, &req.n, sizeof(req)) < 0) { get_failed: fprintf(stderr, @@ -165,6 +182,12 @@ get_failed: if (iptuninfo[IFLA_IPTUN_6RD_RELAY_PREFIXLEN]) ip6rdrelayprefixlen = rta_getattr_u16(iptuninfo[IFLA_IPTUN_6RD_RELAY_PREFIXLEN]); + if (iptuninfo[IFLA_IPTUN_COLLECT_METADATA]) + metadata = 1; + + if (iptuninfo[IFLA_IPTUN_FWMARK]) + fwmark = rta_getattr_u32(iptuninfo[IFLA_IPTUN_FWMARK]); + } while (argc > 0) { @@ -197,6 +220,7 @@ get_failed: strcmp(*argv, "tclass") == 0 || matches(*argv, "dsfield") == 0) { __u32 uval; + NEXT_ARG(); if (strcmp(*argv, "inherit") != 0) { if (rtnl_dsfield_a2n(&uval, *argv)) @@ -221,6 +245,24 @@ get_failed: strcmp(*argv, "ipip") == 0 || strcmp(*argv, "ip4ip4") == 0) proto = IPPROTO_IPIP; + else if (strcmp(*argv, "mpls/ipv4") == 0 || + strcmp(*argv, "mplsip") == 0) + proto = IPPROTO_MPLS; + else if (strcmp(*argv, "any/ipv4") == 0 || + strcmp(*argv, "any") == 0) + proto = 0; + else + invarg("Cannot guess tunnel mode.", *argv); + } else if (strcmp(lu->id, "ipip") == 0 && + strcmp(*argv, "mode") == 0) { + NEXT_ARG(); + if (strcmp(*argv, "ipv4/ipv4") == 0 || + strcmp(*argv, "ipip") == 0 || + strcmp(*argv, "ip4ip4") == 0) + proto = IPPROTO_IPIP; + else if (strcmp(*argv, "mpls/ipv4") == 0 || + strcmp(*argv, "mplsip") == 0) + proto = IPPROTO_MPLS; else if (strcmp(*argv, "any/ipv4") == 0 || strcmp(*argv, "any") == 0) proto = 0; @@ -260,8 +302,11 @@ get_failed: encapflags |= TUNNEL_ENCAP_FLAG_REMCSUM; } else if (strcmp(*argv, "noencap-remcsum") == 0) { encapflags &= ~TUNNEL_ENCAP_FLAG_REMCSUM; + } else if (strcmp(*argv, "external") == 0) { + metadata = 1; } 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); @@ -269,6 +314,7 @@ get_failed: 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); @@ -276,11 +322,16 @@ get_failed: 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 if (strcmp(*argv, "fwmark") == 0) { + NEXT_ARG(); + if (get_u32(&fwmark, *argv, 0)) + invarg("invalid fwmark\n", *argv); } else usage(strcmp(lu->id, "sit") == 0); argc--, argv++; @@ -291,21 +342,29 @@ get_failed: exit(-1); } + if (metadata) { + addattr_l(n, 1024, IFLA_IPTUN_COLLECT_METADATA, NULL, 0); + return 0; + } + 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); + addattr32(n, 1024, IFLA_IPTUN_FWMARK, fwmark); addattr16(n, 1024, IFLA_IPTUN_ENCAP_TYPE, encaptype); addattr16(n, 1024, IFLA_IPTUN_ENCAP_FLAGS, encapflags); addattr16(n, 1024, IFLA_IPTUN_ENCAP_SPORT, htons(encapsport)); addattr16(n, 1024, IFLA_IPTUN_ENCAP_DPORT, htons(encapdport)); + if (strcmp(lu->id, "ipip") == 0 || strcmp(lu->id, "sit") == 0) + addattr8(n, 1024, IFLA_IPTUN_PROTO, proto); + if (strcmp(lu->id, "sit") == 0) { addattr16(n, 1024, IFLA_IPTUN_FLAGS, iflags); - addattr8(n, 1024, IFLA_IPTUN_PROTO, proto); if (ip6rdprefixlen) { addattr_l(n, 1024, IFLA_IPTUN_6RD_PREFIX, &ip6rdprefix, sizeof(ip6rdprefix)); @@ -327,126 +386,185 @@ static void iptunnel_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[ char s2[64]; const char *local = "any"; const char *remote = "any"; + __u16 prefixlen, type; if (!tb) return; if (tb[IFLA_IPTUN_REMOTE]) { - unsigned addr = rta_getattr_u32(tb[IFLA_IPTUN_REMOTE]); + unsigned int addr = rta_getattr_u32(tb[IFLA_IPTUN_REMOTE]); if (addr) - remote = format_host(AF_INET, 4, &addr, s1, sizeof(s1)); + remote = format_host(AF_INET, 4, &addr); } - fprintf(f, "remote %s ", remote); + print_string(PRINT_ANY, "remote", "remote %s ", remote); if (tb[IFLA_IPTUN_LOCAL]) { - unsigned addr = rta_getattr_u32(tb[IFLA_IPTUN_LOCAL]); + unsigned int addr = rta_getattr_u32(tb[IFLA_IPTUN_LOCAL]); if (addr) - local = format_host(AF_INET, 4, &addr, s1, sizeof(s1)); + local = format_host(AF_INET, 4, &addr); } - fprintf(f, "local %s ", local); + print_string(PRINT_ANY, "local", "local %s ", local); if (tb[IFLA_IPTUN_LINK] && rta_getattr_u32(tb[IFLA_IPTUN_LINK])) { - unsigned link = rta_getattr_u32(tb[IFLA_IPTUN_LINK]); + unsigned int link = rta_getattr_u32(tb[IFLA_IPTUN_LINK]); const char *n = if_indextoname(link, s2); if (n) - fprintf(f, "dev %s ", n); + print_string(PRINT_ANY, "link", "dev %s ", n); else - fprintf(f, "dev %u ", link); + print_int(PRINT_ANY, "link_index", "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_TTL]) { + __u8 ttl = rta_getattr_u8(tb[IFLA_IPTUN_TTL]); + + if (ttl) + print_int(PRINT_ANY, "ttl", "ttl %d ", ttl); + else + print_int(PRINT_JSON, "ttl", NULL, ttl); + } else { + print_string(PRINT_FP, NULL, "ttl %s ", "inherit"); + } - if (tb[IFLA_IPTUN_TOS] && rta_getattr_u8(tb[IFLA_IPTUN_TOS])) { + if (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 (tos) { + if (is_json_context()) { + print_0xhex(PRINT_JSON, "tos", "%#x", tos); + } else { + 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 "); + print_bool(PRINT_ANY, "pmtudisc", "pmtudisc ", true); else - fprintf(f, "nopmtudisc "); + print_bool(PRINT_ANY, "pmtudisc", "nopmtudisc ", false); if (tb[IFLA_IPTUN_FLAGS]) { __u16 iflags = rta_getattr_u16(tb[IFLA_IPTUN_FLAGS]); if (iflags & SIT_ISATAP) - fprintf(f, "isatap "); + print_bool(PRINT_ANY, "isatap", "isatap ", true); } if (tb[IFLA_IPTUN_6RD_PREFIXLEN] && - *(__u16 *)RTA_DATA(tb[IFLA_IPTUN_6RD_PREFIXLEN])) { - __u16 prefixlen = rta_getattr_u16(tb[IFLA_IPTUN_6RD_PREFIXLEN]); + (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); + const char *prefix = inet_ntop(AF_INET6, + RTA_DATA(tb[IFLA_IPTUN_6RD_PREFIX]), + s1, sizeof(s1)); + + if (is_json_context()) { + print_string(PRINT_JSON, "prefix", NULL, prefix); + print_int(PRINT_JSON, "prefixlen", NULL, prefixlen); + if (relayprefix) { + print_string(PRINT_JSON, + "relay_prefix", + NULL, + format_host(AF_INET, + 4, + &relayprefix)); + print_int(PRINT_JSON, + "relay_prefixlen", + NULL, + relayprefixlen); + } + } else { + printf("6rd-prefix %s/%u ", prefix, prefixlen); + if (relayprefix) { + printf("6rd-relay_prefix %s/%u ", + format_host(AF_INET, 4, &relayprefix), + relayprefixlen); + } } } if (tb[IFLA_IPTUN_ENCAP_TYPE] && - *(__u16 *)RTA_DATA(tb[IFLA_IPTUN_ENCAP_TYPE]) != TUNNEL_ENCAP_NONE) { - __u16 type = rta_getattr_u16(tb[IFLA_IPTUN_ENCAP_TYPE]); + (type = rta_getattr_u16(tb[IFLA_IPTUN_ENCAP_TYPE])) != TUNNEL_ENCAP_NONE) { __u16 flags = rta_getattr_u16(tb[IFLA_IPTUN_ENCAP_FLAGS]); __u16 sport = rta_getattr_u16(tb[IFLA_IPTUN_ENCAP_SPORT]); __u16 dport = rta_getattr_u16(tb[IFLA_IPTUN_ENCAP_DPORT]); - fputs("encap ", f); + print_string(PRINT_FP, NULL, "encap ", NULL); switch (type) { case TUNNEL_ENCAP_FOU: - fputs("fou ", f); + print_string(PRINT_ANY, "type", "%s ", "fou"); break; case TUNNEL_ENCAP_GUE: - fputs("gue ", f); + print_string(PRINT_ANY, "type", "%s ", "gue"); break; default: - fputs("unknown ", f); + print_null(PRINT_ANY, "type", "unknown ", NULL); break; } - if (sport == 0) - fputs("encap-sport auto ", f); - else - fprintf(f, "encap-sport %u", ntohs(sport)); + if (is_json_context()) { + print_uint(PRINT_JSON, + "sport", + NULL, + sport ? ntohs(sport) : 0); + print_uint(PRINT_JSON, "dport", NULL, ntohs(dport)); + print_bool(PRINT_JSON, + "csum", + NULL, + flags & TUNNEL_ENCAP_FLAG_CSUM); + print_bool(PRINT_JSON, + "csum6", + NULL, + flags & TUNNEL_ENCAP_FLAG_CSUM6); + print_bool(PRINT_JSON, + "remcsum", + NULL, + flags & TUNNEL_ENCAP_FLAG_REMCSUM); + close_json_object(); + } else { + if (sport == 0) + fputs("encap-sport auto ", f); + else + fprintf(f, "encap-sport %u", ntohs(sport)); - fprintf(f, "encap-dport %u ", ntohs(dport)); + 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_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_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); + if (flags & TUNNEL_ENCAP_FLAG_REMCSUM) + fputs("encap-remcsum ", f); + else + fputs("noencap-remcsum ", f); + } + } + + if (tb[IFLA_IPTUN_FWMARK]) { + __u32 fwmark = rta_getattr_u32(tb[IFLA_IPTUN_FWMARK]); + + if (fwmark) { + snprintf(s2, sizeof(s2), "0x%x", fwmark); + + print_string(PRINT_ANY, "fwmark", "fwmark %s ", s2); + } } } |