diff --git a/ip/Makefile b/ip/Makefile
index 1928489e7f90..4276a34b529e 100644
--- a/ip/Makefile
+++ b/ip/Makefile
@@ -8,7 +8,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
+    ipvrf.o iplink_xstats.o
 
 RTMONOBJ=rtmon.o
 
diff --git a/ip/ip_common.h b/ip/ip_common.h
index ab6a83431fd6..071c3db280f2 100644
--- a/ip/ip_common.h
+++ b/ip/ip_common.h
@@ -61,6 +61,7 @@ int do_ipvrf(int argc, char **argv);
 void vrf_reset(void);
 
 int iplink_get(unsigned int flags, char *name, __u32 filt_mask);
+int iplink_ifla_xstats(int argc, char **argv);
 
 static inline int rtm_get_table(struct rtmsg *r, struct rtattr **tb)
 {
@@ -84,9 +85,13 @@ struct link_util {
 	void			(*print_opt)(struct link_util *, FILE *,
 					     struct rtattr *[]);
 	void			(*print_xstats)(struct link_util *, FILE *,
-					     struct rtattr *);
+						struct rtattr *);
 	void			(*print_help)(struct link_util *, int, char **,
-					     FILE *);
+					      FILE *);
+	int			(*parse_ifla_xstats)(struct link_util *,
+						     int, char **);
+	int			(*print_ifla_xstats)(const struct sockaddr_nl *,
+						     struct nlmsghdr *, void *);
 };
 
 struct link_util *get_link_kind(const char *kind);
diff --git a/ip/iplink.c b/ip/iplink.c
index 2638408c23b8..00fed9006ea6 100644
--- a/ip/iplink.c
+++ b/ip/iplink.c
@@ -98,6 +98,8 @@ void iplink_usage(void)
 		"\n"
 		"       ip link show [ DEVICE | group GROUP ] [up] [master DEV] [vrf NAME] [type TYPE]\n");
 
+	fprintf(stderr, "\n       ip link xstats type TYPE [ ARGS ]\n");
+
 	if (iplink_have_newlink()) {
 		fprintf(stderr,
 			"\n"
@@ -1411,6 +1413,9 @@ int do_iplink(int argc, char **argv)
 	    matches(*argv, "list") == 0)
 		return ipaddr_list_link(argc-1, argv+1);
 
+	if (matches(*argv, "xstats") == 0)
+		return iplink_ifla_xstats(argc-1, argv+1);
+
 	if (matches(*argv, "help") == 0) {
 		do_help(argc-1, argv+1);
 		return 0;
diff --git a/ip/iplink_xstats.c b/ip/iplink_xstats.c
new file mode 100644
index 000000000000..10f953bc4584
--- /dev/null
+++ b/ip/iplink_xstats.c
@@ -0,0 +1,81 @@
+/*
+ * iplink_stats.c       Extended statistics commands
+ *
+ *              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:     Nikolay Aleksandrov <nikolay@cumulusnetworks.com>
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <linux/if_link.h>
+#include <netinet/ether.h>
+
+#include "utils.h"
+#include "ip_common.h"
+
+static void print_explain(FILE *f)
+{
+	fprintf(f, "Usage: ... xstats type TYPE [ ARGS ]\n");
+}
+
+int iplink_ifla_xstats(int argc, char **argv)
+{
+	struct link_util *lu = NULL;
+	__u32 filt_mask;
+
+	if (!argc) {
+		fprintf(stderr, "xstats: missing argument\n");
+		return -1;
+	}
+
+	if (matches(*argv, "type") == 0) {
+		NEXT_ARG();
+		lu = get_link_kind(*argv);
+		if (!lu)
+			invarg("invalid type", *argv);
+	} else if (matches(*argv, "help") == 0) {
+		print_explain(stdout);
+		return 0;
+	} else {
+		invarg("unknown argument", *argv);
+	}
+
+	if (!lu) {
+		print_explain(stderr);
+		return -1;
+	}
+
+	if (!lu->print_ifla_xstats) {
+		fprintf(stderr, "xstats: link type %s doesn't support xstats\n",
+			lu->id);
+		return -1;
+	}
+
+	if (lu->parse_ifla_xstats &&
+	    lu->parse_ifla_xstats(lu, argc-1, argv+1))
+		return -1;
+
+	if (strstr(lu->id, "_slave"))
+		filt_mask = IFLA_STATS_FILTER_BIT(IFLA_STATS_LINK_XSTATS_SLAVE);
+	else
+		filt_mask = IFLA_STATS_FILTER_BIT(IFLA_STATS_LINK_XSTATS);
+
+	if (rtnl_wilddump_stats_req_filter(&rth, AF_UNSPEC,
+					   RTM_GETSTATS,
+					   filt_mask) < 0) {
+		perror("Cannont send dump request");
+		return -1;
+	}
+
+	if (rtnl_dump_filter(&rth, lu->print_ifla_xstats, stdout) < 0) {
+		fprintf(stderr, "Dump terminated\n");
+		return -1;
+	}
+
+	return 0;
+}
diff --git a/man/man8/ip-link.8.in b/man/man8/ip-link.8.in
index 116034dc620a..2cbdefeb749a 100644
--- a/man/man8/ip-link.8.in
+++ b/man/man8/ip-link.8.in
@@ -169,6 +169,11 @@ ip-link \- network device configuration
 .IR NAME " ]"
 
 .ti -8
+.B ip link xstats
+.BI type " TYPE"
+.RI "[ " ARGS " ]"
+
+.ti -8
 .B ip link help
 .RI "[ " TYPE " ]"
 
@@ -1616,6 +1621,13 @@ interface list by comparing it with the relevant attribute in case the kernel
 didn't filter already. Therefore any string is accepted, but may lead to empty
 output.
 
+.SS  ip link xstats - display extended statistics
+
+.TP
+.BI type " TYPE "
+.I TYPE
+specifies the type of devices to display extended statistics for.
+
 .SS  ip link help - display help
 
 .PP
