]> git.proxmox.com Git - mirror_iproute2.git/commitdiff
Merge branch 'master' into net-next
authorDavid Ahern <dsahern@gmail.com>
Mon, 8 Jan 2018 18:10:45 +0000 (10:10 -0800)
committerDavid Ahern <dsahern@gmail.com>
Mon, 8 Jan 2018 18:10:45 +0000 (10:10 -0800)
 Conflicts:
man/man8/ip-link.8.in

Signed-off-by: David Ahern <dsahern@gmail.com>
17 files changed:
include/uapi/linux/bpf.h
include/uapi/linux/if_ether.h
include/uapi/linux/if_tun.h
include/uapi/linux/if_tunnel.h
include/uapi/linux/sctp.h
ip/Makefile
ip/ipaddress.c
ip/iplink.c
ip/iplink_netdevsim.c [new file with mode: 0644]
ip/link_gre.c
ip/link_gre6.c
man/man8/ip-link.8.in
rdma/dev.c
rdma/link.c
rdma/rdma.c
rdma/rdma.h
rdma/utils.c

index 81f9145fc5a633627e87cc19ddf64ff73efe80b0..ff544fe5911b85f3aacbd70c920d79e1f5a5b843 100644 (file)
@@ -197,8 +197,14 @@ enum bpf_attach_type {
  */
 #define BPF_F_STRICT_ALIGNMENT (1U << 0)
 
+/* when bpf_ldimm64->src_reg == BPF_PSEUDO_MAP_FD, bpf_ldimm64->imm == fd */
 #define BPF_PSEUDO_MAP_FD      1
 
+/* when bpf_call->src_reg == BPF_PSEUDO_CALL, bpf_call->imm == pc-relative
+ * offset to another bpf function
+ */
+#define BPF_PSEUDO_CALL                1
+
 /* flags for BPF_MAP_UPDATE_ELEM command */
 #define BPF_ANY                0 /* create new element or update existing */
 #define BPF_NOEXIST    1 /* create new element if it didn't exist */
@@ -677,6 +683,10 @@ union bpf_attr {
  *     @buf: buf to fill
  *     @buf_size: size of the buf
  *     Return : 0 on success or negative error code
+ *
+ * int bpf_override_return(pt_regs, rc)
+ *     @pt_regs: pointer to struct pt_regs
+ *     @rc: the return value to set
  */
 #define __BPF_FUNC_MAPPER(FN)          \
        FN(unspec),                     \
@@ -736,7 +746,8 @@ union bpf_attr {
        FN(xdp_adjust_meta),            \
        FN(perf_event_read_value),      \
        FN(perf_prog_read_value),       \
-       FN(getsockopt),
+       FN(getsockopt),                 \
+       FN(override_return),
 
 /* integer value in 'imm' field of BPF_CALL instruction selects which helper
  * function eBPF program intends to call
@@ -941,6 +952,12 @@ struct bpf_sock_ops {
        __u32 local_ip6[4];     /* Stored in network byte order */
        __u32 remote_port;      /* Stored in network byte order */
        __u32 local_port;       /* stored in host byte order */
+       __u32 is_fullsock;      /* Some TCP fields are only valid if
+                                * there is a full socket. If not, the
+                                * fields read as zero.
+                                */
+       __u32 snd_cwnd;
+       __u32 srtt_us;          /* Averaged RTT << 3 in usecs */
 };
 
 /* List of known BPF sock_ops operators.
index 2eb529a90250273e641155212b6228535b9adc36..133567bf2e040744835fd2bb13c1d936848e3f38 100644 (file)
@@ -47,6 +47,7 @@
 #define ETH_P_PUP      0x0200          /* Xerox PUP packet             */
 #define ETH_P_PUPAT    0x0201          /* Xerox PUP Addr Trans packet  */
 #define ETH_P_TSN      0x22F0          /* TSN (IEEE 1722) packet       */
+#define ETH_P_ERSPAN2  0x22EB          /* ERSPAN version 2 (type III)  */
 #define ETH_P_IP       0x0800          /* Internet Protocol packet     */
 #define ETH_P_X25      0x0805          /* CCITT X.25                   */
 #define ETH_P_ARP      0x0806          /* Address Resolution packet    */
index a0e25624e421d845ecaaac41aafeda2d663166ad..d176cb432ab12ee404d095a18816171e98d0752a 100644 (file)
@@ -57,6 +57,7 @@
  */
 #define TUNSETVNETBE _IOW('T', 222, int)
 #define TUNGETVNETBE _IOR('T', 223, int)
+#define TUNSETSTEERINGEBPF _IOR('T', 224, int)
 
 /* TUNSETIFF ifr flags */
 #define IFF_TUN                0x0001
index 38cdf90692f86b9869696e2c67063db964a22da9..ecdc76669cfdde02f37158cbec5fbc681b3fc6ba 100644 (file)
@@ -137,6 +137,9 @@ enum {
        IFLA_GRE_IGNORE_DF,
        IFLA_GRE_FWMARK,
        IFLA_GRE_ERSPAN_INDEX,
+       IFLA_GRE_ERSPAN_VER,
+       IFLA_GRE_ERSPAN_DIR,
+       IFLA_GRE_ERSPAN_HWID,
        __IFLA_GRE_MAX,
 };
 
index c5cff287518904ddd9429da6f05798d3773f9ab6..64309a2b73cb326c74200e3ffda62f2ff7f9258e 100644 (file)
@@ -125,6 +125,7 @@ typedef __s32 sctp_assoc_t;
 #define SCTP_SOCKOPT_PEELOFF_FLAGS 122
 #define SCTP_STREAM_SCHEDULER  123
 #define SCTP_STREAM_SCHEDULER_VALUE    124
+#define SCTP_INTERLEAVING_SUPPORTED    125
 
 /* PR-SCTP policies */
 #define SCTP_PR_SCTP_NONE      0x0000
@@ -459,6 +460,8 @@ struct sctp_pdapi_event {
        __u32 pdapi_length;
        __u32 pdapi_indication;
        sctp_assoc_t pdapi_assoc_id;
+       __u32 pdapi_stream;
+       __u32 pdapi_seq;
 };
 
 enum { SCTP_PARTIAL_DELIVERY_ABORTED=0, };
index a653c1bdd9673ee267437dea31850128af4c6665..77fadeed2e62bda3d0cadf345ddb8bca56efc3e5 100644 (file)
@@ -10,7 +10,7 @@ IPOBJ=ip.o ipaddress.o ipaddrlabel.o iproute.o iprule.o ipnetns.o \
     link_iptnl.o link_gre6.o iplink_bond.o iplink_bond_slave.o iplink_hsr.o \
     iplink_bridge.o iplink_bridge_slave.o ipfou.o iplink_ipvlan.o \
     iplink_geneve.o iplink_vrf.o iproute_lwtunnel.o ipmacsec.o ipila.o \
-    ipvrf.o iplink_xstats.o ipseg6.o
+    ipvrf.o iplink_xstats.o ipseg6.o iplink_netdevsim.o
 
 RTMONOBJ=rtmon.o
 
index f150d9190b768241421777760c9bd1698d30f212..c35b6b3f1b10be9e3534376be031d359728a0df6 100644 (file)
@@ -78,7 +78,7 @@ static void usage(void)
        fprintf(stderr, "          bridge | bond | ipoib | ip6tnl | ipip | sit | vxlan | lowpan |\n");
        fprintf(stderr, "          gre | gretap | erspan | ip6gre | ip6gretap | ip6erspan | vti |\n");
        fprintf(stderr, "          nlmon | can | bond_slave | ipvlan | geneve | bridge_slave |\n");
-       fprintf(stderr, "          hsr | macsec\n");
+       fprintf(stderr, "          hsr | macsec | netdevsim\n");
 
        exit(-1);
 }
index 4c967112460aaeeb4100922af5405c61ed8ebc9e..0ea5547f48c58071022fb1bf39f0e2a63c57346d 100644 (file)
 #define LIBDIR "/usr/lib"
 #endif
 
+#ifndef GSO_MAX_SIZE
+#define GSO_MAX_SIZE           65536
+#endif
+#ifndef GSO_MAX_SEGS
+#define GSO_MAX_SEGS           65535
+#endif
+
+
 static void usage(void) __attribute__((noreturn));
 static int iplink_have_newlink(void);
 
@@ -97,7 +105,8 @@ void iplink_usage(void)
                "                         [ master DEVICE ][ vrf NAME ]\n"
                "                         [ nomaster ]\n"
                "                         [ addrgenmode { eui64 | none | stable_secret | random } ]\n"
-               "                         [ protodown { on | off } ]\n"
+               "                         [ protodown { on | off } ]\n"
+               "                         [ gso_max_size BYTES ] | [ gso_max_segs PACKETS ]\n"
                "\n"
                "       ip link show [ DEVICE | group GROUP ] [up] [master DEV] [vrf NAME] [type TYPE]\n");
 
@@ -113,7 +122,7 @@ void iplink_usage(void)
                        "          bridge | bond | team | ipoib | ip6tnl | ipip | sit | vxlan |\n"
                        "          gre | gretap | erspan | ip6gre | ip6gretap | ip6erspan |\n"
                        "          vti | nlmon | team_slave | bond_slave | ipvlan | geneve |\n"
-                       "          bridge_slave | vrf | macsec }\n");
+                       "          bridge_slave | vrf | macsec | netdevsim }\n");
        }
        exit(-1);
 }
@@ -853,6 +862,26 @@ int iplink_parse(int argc, char **argv, struct iplink_req *req,
                                return on_off("protodown", *argv);
                        addattr8(&req->n, sizeof(*req), IFLA_PROTO_DOWN,
                                 proto_down);
+               } else if (strcmp(*argv, "gso_max_size") == 0) {
+                       unsigned int max_size;
+
+                       NEXT_ARG();
+                       if (get_unsigned(&max_size, *argv, 0) ||
+                           max_size > GSO_MAX_SIZE)
+                               invarg("Invalid \"gso_max_size\" value\n",
+                                      *argv);
+                       addattr32(&req->n, sizeof(*req),
+                                 IFLA_GSO_MAX_SIZE, max_size);
+               } else if (strcmp(*argv, "gso_max_segs") == 0) {
+                       unsigned int max_segs;
+
+                       NEXT_ARG();
+                       if (get_unsigned(&max_segs, *argv, 0) ||
+                           max_segs > GSO_MAX_SEGS)
+                               invarg("Invalid \"gso_max_segs\" value\n",
+                                      *argv);
+                       addattr32(&req->n, sizeof(*req),
+                                 IFLA_GSO_MAX_SEGS, max_segs);
                } else {
                        if (matches(*argv, "help") == 0)
                                usage();
diff --git a/ip/iplink_netdevsim.c b/ip/iplink_netdevsim.c
new file mode 100644 (file)
index 0000000..3448608
--- /dev/null
@@ -0,0 +1,16 @@
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "utils.h"
+#include "ip_common.h"
+
+static void netdevsim_print_help(struct link_util *lu,
+                                int argc, char **argv, FILE *f)
+{
+       fprintf(f, "Usage: ... netdevsim\n");
+}
+
+struct link_util netdevsim_link_util = {
+       .id             = "netdevsim",
+       .print_help     = netdevsim_print_help,
+};
index 3c0b6d678afcfc950839e12f7defe5b45dd10f88..52c581d224ac582ae7231340bd09af5a85d52324 100644 (file)
@@ -45,7 +45,11 @@ static void print_usage(FILE *f)
                "                            [ [no]encap-remcsum ]\n"
                "                            [ external ]\n"
                "                            [ fwmark MARK ]\n"
+               "                            [ erspan_ver version ]\n"
                "                            [ erspan IDX ]\n"
+               "                            [ erspan_dir { ingress | egress } ]\n"
+               "                            [ erspan_hwid hwid ]\n"
+               "                            [ external ]\n"
                "\n"
                "Where: ADDR := { IP_ADDRESS | any }\n"
                "       TOS  := { NUMBER | inherit }\n"
@@ -99,6 +103,9 @@ static int gre_parse_opt(struct link_util *lu, int argc, char **argv,
        __u8 ignore_df = 0;
        __u32 fwmark = 0;
        __u32 erspan_idx = 0;
+       __u8 erspan_ver = 0;
+       __u8 erspan_dir = 0;
+       __u16 erspan_hwid = 0;
 
        if (!(n->nlmsg_flags & NLM_F_CREATE)) {
                if (rtnl_talk(&rth, &req.n, &answer) < 0) {
@@ -179,6 +186,15 @@ get_failed:
                if (greinfo[IFLA_GRE_ERSPAN_INDEX])
                        erspan_idx = rta_getattr_u32(greinfo[IFLA_GRE_ERSPAN_INDEX]);
 
+               if (greinfo[IFLA_GRE_ERSPAN_VER])
+                       erspan_ver = rta_getattr_u8(greinfo[IFLA_GRE_ERSPAN_VER]);
+
+               if (greinfo[IFLA_GRE_ERSPAN_DIR])
+                       erspan_dir = rta_getattr_u8(greinfo[IFLA_GRE_ERSPAN_DIR]);
+
+               if (greinfo[IFLA_GRE_ERSPAN_HWID])
+                       erspan_hwid = rta_getattr_u16(greinfo[IFLA_GRE_ERSPAN_HWID]);
+
                free(answer);
        }
 
@@ -306,6 +322,24 @@ get_failed:
                                invarg("invalid erspan index\n", *argv);
                        if (erspan_idx & ~((1<<20) - 1) || erspan_idx == 0)
                                invarg("erspan index must be > 0 and <= 20-bit\n", *argv);
+               } else if (strcmp(*argv, "erspan_ver") == 0) {
+                       NEXT_ARG();
+                       if (get_u8(&erspan_ver, *argv, 0))
+                               invarg("invalid erspan version\n", *argv);
+                       if (erspan_ver != 1 && erspan_ver != 2)
+                               invarg("erspan version must be 1 or 2\n", *argv);
+               } else if (strcmp(*argv, "erspan_dir") == 0) {
+                       NEXT_ARG();
+                       if (matches(*argv, "ingress") == 0)
+                               erspan_dir = 0;
+                       else if (matches(*argv, "egress") == 0)
+                               erspan_dir = 1;
+                       else
+                               invarg("Invalid erspan direction.", *argv);
+               } else if (strcmp(*argv, "erspan_hwid") == 0) {
+                       NEXT_ARG();
+                       if (get_u16(&erspan_hwid, *argv, 0))
+                               invarg("invalid erspan hwid\n", *argv);
                } else
                        usage();
                argc--; argv++;
@@ -337,8 +371,15 @@ get_failed:
                addattr_l(n, 1024, IFLA_GRE_TTL, &ttl, 1);
                addattr_l(n, 1024, IFLA_GRE_TOS, &tos, 1);
                addattr32(n, 1024, IFLA_GRE_FWMARK, fwmark);
-               if (erspan_idx != 0)
-                       addattr32(n, 1024, IFLA_GRE_ERSPAN_INDEX, erspan_idx);
+               if (erspan_ver) {
+                       addattr8(n, 1024, IFLA_GRE_ERSPAN_VER, erspan_ver);
+                       if (erspan_ver == 1 && erspan_idx != 0) {
+                               addattr32(n, 1024, IFLA_GRE_ERSPAN_INDEX, erspan_idx);
+                       } else if (erspan_ver == 2) {
+                               addattr8(n, 1024, IFLA_GRE_ERSPAN_DIR, erspan_dir);
+                               addattr16(n, 1024, IFLA_GRE_ERSPAN_HWID, erspan_hwid);
+                       }
+               }
        } else {
                addattr_l(n, 1024, IFLA_GRE_COLLECT_METADATA, NULL, 0);
        }
@@ -477,7 +518,30 @@ static void gre_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
        if (tb[IFLA_GRE_ERSPAN_INDEX]) {
                __u32 erspan_idx = rta_getattr_u32(tb[IFLA_GRE_ERSPAN_INDEX]);
 
-               fprintf(f, "erspan_index %u ", erspan_idx);
+               print_uint(PRINT_ANY, "erspan_index", "erspan_index %u ", erspan_idx);
+       }
+
+       if (tb[IFLA_GRE_ERSPAN_VER]) {
+               __u8 erspan_ver = rta_getattr_u8(tb[IFLA_GRE_ERSPAN_VER]);
+
+               print_uint(PRINT_ANY, "erspan_ver", "erspan_ver %u ", erspan_ver);
+       }
+
+       if (tb[IFLA_GRE_ERSPAN_DIR]) {
+               __u8 erspan_dir = rta_getattr_u8(tb[IFLA_GRE_ERSPAN_DIR]);
+
+               if (erspan_dir == 0)
+                       print_string(PRINT_ANY, "erspan_dir",
+                                    "erspan_dir ingress ", NULL);
+               else
+                       print_string(PRINT_ANY, "erspan_dir",
+                                    "erspan_dir egress ", NULL);
+       }
+
+       if (tb[IFLA_GRE_ERSPAN_HWID]) {
+               __u16 erspan_hwid = rta_getattr_u16(tb[IFLA_GRE_ERSPAN_HWID]);
+
+               print_hex(PRINT_ANY, "erspan_hwid", "erspan_hwid 0x%x ", erspan_hwid);
        }
 
        if (tb[IFLA_GRE_ENCAP_TYPE] &&
index 7ae4b4924433fac408dece8e3676039563a726b9..bc33026c31d0d12f75314ab041061ad125b3a65b 100644 (file)
@@ -52,7 +52,11 @@ static void print_usage(FILE *f)
                "                                  [ [no]encap-csum ]\n"
                "                                  [ [no]encap-csum6 ]\n"
                "                                  [ [no]encap-remcsum ]\n"
+               "                                  [ erspan_ver version ]\n"
                "                                  [ erspan IDX ]\n"
+               "                                  [ erspan_dir { ingress | egress } ]\n"
+               "                                  [ erspan_hwid hwid ]\n"
+               "                                  [ external ]\n"
                "\n"
                "Where: ADDR      := IPV6_ADDRESS\n"
                "       TTL       := { 0..255 } (default=%d)\n"
@@ -105,9 +109,13 @@ static int gre_parse_opt(struct link_util *lu, int argc, char **argv,
        __u16 encapflags = TUNNEL_ENCAP_FLAG_CSUM6;
        __u16 encapsport = 0;
        __u16 encapdport = 0;
+       __u8 metadata = 0;
        int len;
        __u32 fwmark = 0;
        __u32 erspan_idx = 0;
+       __u8 erspan_ver = 0;
+       __u8 erspan_dir = 0;
+       __u16 erspan_hwid = 0;
 
        if (!(n->nlmsg_flags & NLM_F_CREATE)) {
                if (rtnl_talk(&rth, &req.n, &answer) < 0) {
@@ -177,6 +185,9 @@ get_failed:
                if (greinfo[IFLA_GRE_ENCAP_SPORT])
                        encapsport = rta_getattr_u16(greinfo[IFLA_GRE_ENCAP_SPORT]);
 
+               if (greinfo[IFLA_GRE_COLLECT_METADATA])
+                       metadata = 1;
+
                if (greinfo[IFLA_GRE_ENCAP_DPORT])
                        encapdport = rta_getattr_u16(greinfo[IFLA_GRE_ENCAP_DPORT]);
 
@@ -186,6 +197,15 @@ get_failed:
                if (greinfo[IFLA_GRE_ERSPAN_INDEX])
                        erspan_idx = rta_getattr_u32(greinfo[IFLA_GRE_ERSPAN_INDEX]);
 
+               if (greinfo[IFLA_GRE_ERSPAN_VER])
+                       erspan_ver = rta_getattr_u8(greinfo[IFLA_GRE_ERSPAN_VER]);
+
+               if (greinfo[IFLA_GRE_ERSPAN_DIR])
+                       erspan_dir = rta_getattr_u8(greinfo[IFLA_GRE_ERSPAN_DIR]);
+
+               if (greinfo[IFLA_GRE_ERSPAN_HWID])
+                       erspan_hwid = rta_getattr_u16(greinfo[IFLA_GRE_ERSPAN_HWID]);
+
                free(answer);
        }
 
@@ -315,6 +335,8 @@ 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, "fwmark") == 0) {
                        NEXT_ARG();
                        if (strcmp(*argv, "inherit") == 0) {
@@ -343,31 +365,59 @@ get_failed:
                                invarg("invalid erspan index\n", *argv);
                        if (erspan_idx & ~((1<<20) - 1) || erspan_idx == 0)
                                invarg("erspan index must be > 0 and <= 20-bit\n", *argv);
+               } else if (strcmp(*argv, "erspan_ver") == 0) {
+                       NEXT_ARG();
+                       if (get_u8(&erspan_ver, *argv, 0))
+                               invarg("invalid erspan version\n", *argv);
+                       if (erspan_ver != 1 && erspan_ver != 2)
+                               invarg("erspan version must be 1 or 2\n", *argv);
+               } else if (strcmp(*argv, "erspan_dir") == 0) {
+                       NEXT_ARG();
+                       if (matches(*argv, "ingress") == 0)
+                               erspan_dir = 0;
+                       else if (matches(*argv, "egress") == 0)
+                               erspan_dir = 1;
+                       else
+                               invarg("Invalid erspan direction.", *argv);
+               } else if (strcmp(*argv, "erspan_hwid") == 0) {
+                       NEXT_ARG();
+                       if (get_u16(&erspan_hwid, *argv, 0))
+                               invarg("invalid erspan hwid\n", *argv);
                } else
                        usage();
                argc--; argv++;
        }
 
-       addattr32(n, 1024, IFLA_GRE_IKEY, ikey);
-       addattr32(n, 1024, IFLA_GRE_OKEY, okey);
-       addattr_l(n, 1024, IFLA_GRE_IFLAGS, &iflags, 2);
-       addattr_l(n, 1024, IFLA_GRE_OFLAGS, &oflags, 2);
-       addattr_l(n, 1024, IFLA_GRE_LOCAL, &laddr, sizeof(laddr));
-       addattr_l(n, 1024, IFLA_GRE_REMOTE, &raddr, sizeof(raddr));
-       if (link)
-               addattr32(n, 1024, IFLA_GRE_LINK, link);
-       addattr_l(n, 1024, IFLA_GRE_TTL, &hop_limit, 1);
-       addattr_l(n, 1024, IFLA_GRE_ENCAP_LIMIT, &encap_limit, 1);
-       addattr_l(n, 1024, IFLA_GRE_FLOWINFO, &flowinfo, 4);
-       addattr32(n, 1024, IFLA_GRE_FLAGS, flags);
-       addattr32(n, 1024, IFLA_GRE_FWMARK, fwmark);
-       if (erspan_idx != 0)
-               addattr32(n, 1024, IFLA_GRE_ERSPAN_INDEX, erspan_idx);
-
-       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));
+       if (!metadata) {
+               addattr32(n, 1024, IFLA_GRE_IKEY, ikey);
+               addattr32(n, 1024, IFLA_GRE_OKEY, okey);
+               addattr_l(n, 1024, IFLA_GRE_IFLAGS, &iflags, 2);
+               addattr_l(n, 1024, IFLA_GRE_OFLAGS, &oflags, 2);
+               addattr_l(n, 1024, IFLA_GRE_LOCAL, &laddr, sizeof(laddr));
+               addattr_l(n, 1024, IFLA_GRE_REMOTE, &raddr, sizeof(raddr));
+               if (link)
+                       addattr32(n, 1024, IFLA_GRE_LINK, link);
+               addattr_l(n, 1024, IFLA_GRE_TTL, &hop_limit, 1);
+               addattr_l(n, 1024, IFLA_GRE_ENCAP_LIMIT, &encap_limit, 1);
+               addattr_l(n, 1024, IFLA_GRE_FLOWINFO, &flowinfo, 4);
+               addattr32(n, 1024, IFLA_GRE_FLAGS, flags);
+               addattr32(n, 1024, IFLA_GRE_FWMARK, fwmark);
+               if (erspan_ver) {
+                       addattr8(n, 1024, IFLA_GRE_ERSPAN_VER, erspan_ver);
+                       if (erspan_ver == 1 && erspan_idx != 0) {
+                               addattr32(n, 1024, IFLA_GRE_ERSPAN_INDEX, erspan_idx);
+                       } else {
+                               addattr8(n, 1024, IFLA_GRE_ERSPAN_DIR, erspan_dir);
+                               addattr16(n, 1024, IFLA_GRE_ERSPAN_HWID, erspan_hwid);
+                       }
+               }
+               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));
+       } else {
+               addattr_l(n, 1024, IFLA_GRE_COLLECT_METADATA, NULL, 0);
+       }
 
        return 0;
 }
@@ -386,6 +436,11 @@ static void gre_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
        if (!tb)
                return;
 
+       if (tb[IFLA_GRE_COLLECT_METADATA]) {
+               print_bool(PRINT_ANY, "collect_metadata", "external", true);
+               return;
+       }
+
        if (tb[IFLA_GRE_FLAGS])
                flags = rta_getattr_u32(tb[IFLA_GRE_FLAGS]);
 
@@ -532,7 +587,30 @@ static void gre_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
 
        if (tb[IFLA_GRE_ERSPAN_INDEX]) {
                __u32 erspan_idx = rta_getattr_u32(tb[IFLA_GRE_ERSPAN_INDEX]);
-               fprintf(f, "erspan_index %u ", erspan_idx);
+               print_uint(PRINT_ANY, "erspan_index", "erspan_index %u ", erspan_idx);
+       }
+
+       if (tb[IFLA_GRE_ERSPAN_VER]) {
+               __u8 erspan_ver = rta_getattr_u8(tb[IFLA_GRE_ERSPAN_VER]);
+
+               print_uint(PRINT_ANY, "erspan_ver", "erspan_ver %u ", erspan_ver);
+       }
+
+       if (tb[IFLA_GRE_ERSPAN_DIR]) {
+               __u8 erspan_dir = rta_getattr_u8(tb[IFLA_GRE_ERSPAN_DIR]);
+
+               if (erspan_dir == 0)
+                       print_string(PRINT_ANY, "erspan_dir",
+                                    "erspan_dir ingress ", NULL);
+               else
+                       print_string(PRINT_ANY, "erspan_dir",
+                                    "erspan_dir egress ", NULL);
+       }
+
+       if (tb[IFLA_GRE_ERSPAN_HWID]) {
+               __u16 erspan_hwid = rta_getattr_u16(tb[IFLA_GRE_ERSPAN_HWID]);
+
+               print_hex(PRINT_ANY, "erspan_hwid", "erspan_hwid 0x%x ", erspan_hwid);
        }
 
        if (tb[IFLA_GRE_ENCAP_TYPE] &&
index ff6bb9a2013c772dd0480cbc94a901195a1bf478..1d1f0363f4908cd23ff38bdc3e1140717d9cc7b8 100644 (file)
@@ -36,6 +36,11 @@ ip-link \- network device configuration
 .RB "[ " numrxqueues
 .IR QUEUE_COUNT " ]"
 .br
+.BR "[ " gso_max_size
+.IR BYTES " ]"
+.RB "[ " gso_max_segs
+.IR SEGMENTS " ]"
+.br
 .BI type " TYPE"
 .RI "[ " ARGS " ]"
 
@@ -213,7 +218,8 @@ ip-link \- network device configuration
 .BR lowpan " |"
 .BR geneve " |"
 .BR vrf " |"
-.BR macsec " ]"
+.BR macsec " |"
+.BR netdevsim " ]"
 
 .ti -8
 .IR ETYPE " := [ " TYPE " |"
@@ -333,6 +339,9 @@ Link types:
 .sp
 .BR vrf
 - Interface for L3 VRF domains
+.sp
+.BR netdevsim
+- Interface for netdev API tests
 .in -8
 
 .TP
@@ -343,6 +352,14 @@ specifies the number of transmit queues for new device.
 .BI numrxqueues " QUEUE_COUNT "
 specifies the number of receive queues for new device.
 
+.TP
+.BI gso_max_size " BYTES "
+specifies the recommended maximum size of a Generic Segment Offload packet the new device should accept.
+
+.TP
+.BI gso_max_segs " SEGMENTS "
+specifies the recommended maximum number of a Generic Segment Offload segments the new device should accept.
+
 .TP
 .BI index " IDX "
 specifies the desired index of the new virtual device. The link creation fails, if the index is busy.
@@ -676,13 +693,13 @@ tunnel.
 .in -8
 
 .TP
-GRE, IPIP, SIT, ERSPAN Type Support
+GRE, IPIP, SIT Type Support
 For a link of types
-.I GRE/IPIP/SIT/ERSPAN
+.I GRE/IPIP/SIT
 the following additional arguments are supported:
 
 .BI "ip link add " DEVICE
-.BR type " { " gre " | " ipip " | " sit " | " erspan " }"
+.BR type " { " gre " | " ipip " | " sit " }"
 .BI " remote " ADDR " local " ADDR
 [
 .BR encap " { " fou " | " gue " | " none " }"
@@ -697,8 +714,6 @@ the following additional arguments are supported:
 ] [
 .I " mode " { ip6ip | ipip | mplsip | any } "
 ] [
-.BR erspan " \fIIDX "
-] [
 .BR external
 ]
 
@@ -744,13 +759,6 @@ MPLS-Over-IPv4, "any" indicates IPv6, IPv4 or MPLS Over IPv4. Supported for
 SIT where the default is "ip6ip" and IPIP where the default is "ipip".
 IPv6-Over-IPv4 is not supported for IPIP.
 
-.sp
-.BR erspan " \fIIDX "
-- specifies the ERSPAN index field.
-.IR IDX
-indicates a 20 bit index/port number associated with the ERSPAN
-traffic's source port and direction.
-
 .sp
 .BR external
 - make this tunnel externally controlled
@@ -786,6 +794,8 @@ the following additional arguments are supported:
 .BI "dscp inherit"
 ] [
 .BI dev " PHYS_DEV "
+] [
+.RB external
 ]
 
 .in +8
@@ -864,6 +874,21 @@ or
 .IR 00 ".." ff
 when tunneling non-IP packets. The default value is 00.
 
+.sp
+.RB external
+- make this tunnel externally controlled (or not, which is the default).
+In the kernel, this is referred to as collect metadata mode.  This flag is
+mutually exclusive with the
+.BR remote ,
+.BR local ,
+.BR seq ,
+.BR key,
+.BR csum,
+.BR hoplimit,
+.BR encaplimit,
+.BR flowlabel " and " tclass
+options.
+
 .in -8
 
 .TP
@@ -883,6 +908,76 @@ the following additional arguments are supported:
 .BI  mode " MODE "
 - specifies the mode (datagram or connected) to use.
 
+.TP
+ERSPAN Type Support
+For a link of type
+.I ERSPAN/IP6ERSPAN
+the following additional arguments are supported:
+
+.BI "ip link add " DEVICE
+.BR type " { " erspan " | " ip6erspan " }"
+.BI remote " ADDR " local " ADDR " seq
+.RB key
+.I KEY
+.BR erspan_ver " \fIversion "
+[
+.BR erspan " \fIIDX "
+] [
+.BR erspan_dir " { " \fIingress " | " \fIegress " }"
+] [
+.BR erspan_hwid " \fIhwid "
+] [
+.RB external
+]
+
+.in +8
+.sp
+.BI  remote " ADDR "
+- specifies the remote address of the tunnel.
+
+.sp
+.BI  local " ADDR "
+- specifies the fixed local address for tunneled packets.
+It must be an address on another interface on this host.
+
+.sp
+.BR erspan_ver " \fIversion "
+- specifies the ERSPAN version number.
+.IR version
+indicates the ERSPAN version to be created: 1 for version 1 (type II)
+or 2 for version 2 (type III).
+
+.sp
+.BR erspan " \fIIDX "
+- specifies the ERSPAN v1 index field.
+.IR IDX
+indicates a 20 bit index/port number associated with the ERSPAN
+traffic's source port and direction.
+
+.sp
+.BR erspan_dir " { " \fIingress " | " \fIegress " }"
+- specifies the ERSPAN v2 mirrored traffic's direction.
+
+.sp
+.BR erspan_hwid " \fIhwid "
+- an unique identifier of an ERSPAN v2 engine within a system.
+.IR hwid
+is a 6-bit value for users to configure.
+
+.sp
+.BR external
+- make this tunnel externally controlled (or not, which is the default).
+In the kernel, this is referred to as collect metadata mode.  This flag is
+mutually exclusive with the
+.BR remote ,
+.BR local ,
+.BR erspan_ver ,
+.BR erspan ,
+.BR erspan_dir " and " erspan_hwid
+options.
+
+.in -8
+
 .TP
 GENEVE Type Support
 For a link of type
@@ -2063,6 +2158,13 @@ ip link add link wpan0 lowpan0 type lowpan
 Creates a 6LoWPAN interface named lowpan0 on the underlying
 IEEE 802.15.4 device wpan0.
 .RE
+.PP
+ip link add dev ip6erspan11 type ip6erspan seq key 102
+local fc00:100::2 remote fc00:100::1
+erspan_ver 2 erspan_dir ingress erspan_hwid 17
+.RS 4
+Creates a IP6ERSPAN version 2 interface named ip6erspan00.
+.RE
 
 .SH SEE ALSO
 .br
index 9fadf3ac3b9cd45388d962b35dc99694c551c642..03ab8683332d661c9cc69faa75e7722782fd892a 100644 (file)
@@ -241,33 +241,7 @@ static int dev_one_show(struct rd *rd)
 
 static int dev_show(struct rd *rd)
 {
-       struct dev_map *dev_map;
-       int ret = 0;
-
-       if (rd->json_output)
-               jsonw_start_array(rd->jw);
-       if (rd_no_arg(rd)) {
-               list_for_each_entry(dev_map, &rd->dev_map_list, list) {
-                       rd->dev_idx = dev_map->idx;
-                       ret = dev_one_show(rd);
-                       if (ret)
-                               goto out;
-               }
-       } else {
-               dev_map = dev_map_lookup(rd, false);
-               if (!dev_map) {
-                       pr_err("Wrong device name\n");
-                       ret = -ENOENT;
-                       goto out;
-               }
-               rd_arg_inc(rd);
-               rd->dev_idx = dev_map->idx;
-               ret = dev_one_show(rd);
-       }
-out:
-       if (rd->json_output)
-               jsonw_end_array(rd->jw);
-       return ret;
+       return rd_exec_dev(rd, dev_one_show);
 }
 
 int cmd_dev(struct rd *rd)
index 3a4b00bd533b18267fdfe203e0fea8494236539c..676cb21d216716f61b861c91764d89114589aac7 100644 (file)
@@ -30,7 +30,7 @@ static const char *caps_to_str(uint32_t idx)
        x(PKEY_NVRAM, 8) \
        x(LED_INFO, 9) \
        x(SM_DISABLED, 10) \
-       x(SYS_IMAGE_GUIG, 11) \
+       x(SYS_IMAGE_GUID, 11) \
        x(PKEY_SW_EXT_PORT_TRAP, 12) \
        x(EXTENDED_SPEEDS, 14) \
        x(CM, 16) \
@@ -277,56 +277,15 @@ static int link_one_show(struct rd *rd)
                { 0 }
        };
 
+       if (!rd->port_idx)
+               return 0;
+
        return rd_exec_cmd(rd, cmds, "parameter");
 }
 
 static int link_show(struct rd *rd)
 {
-       struct dev_map *dev_map;
-       uint32_t port;
-       int ret = 0;
-
-       if (rd->json_output)
-               jsonw_start_array(rd->jw);
-       if (rd_no_arg(rd)) {
-               list_for_each_entry(dev_map, &rd->dev_map_list, list) {
-                       rd->dev_idx = dev_map->idx;
-                       for (port = 1; port < dev_map->num_ports + 1; port++) {
-                               rd->port_idx = port;
-                               ret = link_one_show(rd);
-                               if (ret)
-                                       goto out;
-                       }
-               }
-
-       } else {
-               dev_map = dev_map_lookup(rd, true);
-               port = get_port_from_argv(rd);
-               if (!dev_map || port > dev_map->num_ports) {
-                       pr_err("Wrong device name\n");
-                       ret = -ENOENT;
-                       goto out;
-               }
-               rd_arg_inc(rd);
-               rd->dev_idx = dev_map->idx;
-               rd->port_idx = port ? : 1;
-               for (; rd->port_idx < dev_map->num_ports + 1; rd->port_idx++) {
-                       ret = link_one_show(rd);
-                       if (ret)
-                               goto out;
-                       if (port)
-                               /*
-                                * We got request to show link for devname
-                                * with port index.
-                                */
-                               break;
-               }
-       }
-
-out:
-       if (rd->json_output)
-               jsonw_end_array(rd->jw);
-       return ret;
+       return rd_exec_link(rd, link_one_show);
 }
 
 int cmd_link(struct rd *rd)
index f9f4f2a2ad76ddb46113f5788b55bcaa9ae26ad0..0e8fd688674ce8e3622af6546d8b1286ec878346 100644 (file)
@@ -70,12 +70,11 @@ static int rd_init(struct rd *rd, int argc, char **argv, char *filename)
        return rd_recv_msg(rd, rd_dev_init_cb, rd, seq);
 }
 
-static void rd_free(struct rd *rd)
+static void rd_cleanup(struct rd *rd)
 {
        if (rd->json_output)
                jsonw_destroy(&rd->jw);
-       free(rd->buff);
-       rd_free_devmap(rd);
+       rd_free(rd);
 }
 
 int main(int argc, char **argv)
@@ -138,6 +137,6 @@ int main(int argc, char **argv)
        err = rd_cmd(&rd);
 out:
        /* Always cleanup */
-       rd_free(&rd);
+       rd_cleanup(&rd);
        return err ? EXIT_FAILURE : EXIT_SUCCESS;
 }
index d551eb2966e11d9810edaf0c2e7f9dab7af487e0..8d53d3a03b91fac87e2e9f7d0b382d83c557d25c 100644 (file)
@@ -72,13 +72,14 @@ uint32_t get_port_from_argv(struct rd *rd);
 int cmd_dev(struct rd *rd);
 int cmd_link(struct rd *rd);
 int rd_exec_cmd(struct rd *rd, const struct rd_cmd *c, const char *str);
+int rd_exec_dev(struct rd *rd, int (*cb)(struct rd *rd));
+int rd_exec_link(struct rd *rd, int (*cb)(struct rd *rd));
+void rd_free(struct rd *rd);
 
 /*
  * Device manipulation
  */
-void rd_free_devmap(struct rd *rd);
 struct dev_map *dev_map_lookup(struct rd *rd, bool allow_port_index);
-struct dev_map *_dev_map_lookup(struct rd *rd, const char *dev_name);
 
 /*
  * Netlink
index eb4377cf2e185d19a6f88d7487c71043ccd18ffa..7b2001e2091d3b5eb5c075b978d927ada4c7a6b3 100644 (file)
@@ -71,15 +71,6 @@ static struct dev_map *dev_map_alloc(const char *dev_name)
        return dev_map;
 }
 
-static void dev_map_free(struct dev_map *dev_map)
-{
-       if (!dev_map)
-               return;
-
-       free(dev_map->dev_name);
-       free(dev_map);
-}
-
 static void dev_map_cleanup(struct rd *rd)
 {
        struct dev_map *dev_map, *tmp;
@@ -87,7 +78,8 @@ static void dev_map_cleanup(struct rd *rd)
        list_for_each_entry_safe(dev_map, tmp,
                                 &rd->dev_map_list, list) {
                list_del(&dev_map->list);
-               dev_map_free(dev_map);
+               free(dev_map->dev_name);
+               free(dev_map);
        }
 }
 
@@ -152,13 +144,94 @@ int rd_dev_init_cb(const struct nlmsghdr *nlh, void *data)
        return MNL_CB_OK;
 }
 
-void rd_free_devmap(struct rd *rd)
+void rd_free(struct rd *rd)
 {
        if (!rd)
                return;
+       free(rd->buff);
        dev_map_cleanup(rd);
 }
 
+int rd_exec_link(struct rd *rd, int (*cb)(struct rd *rd))
+{
+       struct dev_map *dev_map;
+       uint32_t port;
+       int ret = 0;
+
+       if (rd->json_output)
+               jsonw_start_array(rd->jw);
+       if (rd_no_arg(rd)) {
+               list_for_each_entry(dev_map, &rd->dev_map_list, list) {
+                       rd->dev_idx = dev_map->idx;
+                       for (port = 1; port < dev_map->num_ports + 1; port++) {
+                               rd->port_idx = port;
+                               ret = cb(rd);
+                               if (ret)
+                                       goto out;
+                       }
+               }
+
+       } else {
+               dev_map = dev_map_lookup(rd, true);
+               port = get_port_from_argv(rd);
+               if (!dev_map || port > dev_map->num_ports) {
+                       pr_err("Wrong device name\n");
+                       ret = -ENOENT;
+                       goto out;
+               }
+               rd_arg_inc(rd);
+               rd->dev_idx = dev_map->idx;
+               rd->port_idx = port ? : 1;
+               for (; rd->port_idx < dev_map->num_ports + 1; rd->port_idx++) {
+                       ret = cb(rd);
+                       if (ret)
+                               goto out;
+                       if (port)
+                               /*
+                                * We got request to show link for devname
+                                * with port index.
+                                */
+                               break;
+               }
+       }
+
+out:
+       if (rd->json_output)
+               jsonw_end_array(rd->jw);
+       return ret;
+}
+
+int rd_exec_dev(struct rd *rd, int (*cb)(struct rd *rd))
+{
+       struct dev_map *dev_map;
+       int ret = 0;
+
+       if (rd->json_output)
+               jsonw_start_array(rd->jw);
+       if (rd_no_arg(rd)) {
+               list_for_each_entry(dev_map, &rd->dev_map_list, list) {
+                       rd->dev_idx = dev_map->idx;
+                       ret = cb(rd);
+                       if (ret)
+                               goto out;
+               }
+       } else {
+               dev_map = dev_map_lookup(rd, false);
+               if (!dev_map) {
+                       pr_err("Wrong device name - %s\n", rd_argv(rd));
+                       ret = -ENOENT;
+                       goto out;
+               }
+               rd_arg_inc(rd);
+               rd->dev_idx = dev_map->idx;
+               ret = cb(rd);
+       }
+out:
+       if (rd->json_output)
+               jsonw_end_array(rd->jw);
+       return ret;
+}
+
 int rd_exec_cmd(struct rd *rd, const struct rd_cmd *cmds, const char *str)
 {
        const struct rd_cmd *c;
@@ -236,7 +309,7 @@ int rd_recv_msg(struct rd *rd, mnl_cb_t callback, void *data, unsigned int seq)
        return ret;
 }
 
-struct dev_map *_dev_map_lookup(struct rd *rd, const char *dev_name)
+static struct dev_map *_dev_map_lookup(struct rd *rd, const char *dev_name)
 {
        struct dev_map *dev_map;
 
@@ -253,6 +326,9 @@ struct dev_map *dev_map_lookup(struct rd *rd, bool allow_port_index)
        char *dev_name;
        char *slash;
 
+       if (rd_no_arg(rd))
+               return NULL;
+
        dev_name = strdup(rd_argv(rd));
        if (allow_port_index) {
                slash = strrchr(dev_name, '/');