diff --git a/SOURCES/0025-Consolidated-tunnel-support-fixes-for-ip6-gre-and-ip.patch b/SOURCES/0025-Consolidated-tunnel-support-fixes-for-ip6-gre-and-ip.patch
new file mode 100644
index 0000000..cac6882
--- /dev/null
+++ b/SOURCES/0025-Consolidated-tunnel-support-fixes-for-ip6-gre-and-ip.patch
@@ -0,0 +1,1067 @@
+From 0148deddeee0682884fe95b2ee4f58790498bf0a Mon Sep 17 00:00:00 2001
+From: Phil Sutter <psutter@redhat.com>
+Date: Mon, 3 Aug 2015 09:38:43 -0400
+Subject: [PATCH] Consolidated tunnel support/fixes for ip6/gre and ip6_vti
+
+The original patches are:
+- iproute2: GRE over IPv6 tunnel support.
+- Whitespace and indentation cleanup
+- iproute2: Add support for IPv6 VTI tunnels to ip6tunnel
+- ip tunnel: fix 'ip -oneline tunnel show' for some GRE tunnels
+- iproute2: ip6_tunnel mode bugfixes: any,vti6
+- iproute2: VTI6 support for ip -6 link command.
+
+Conflicts:
+	ip/ipaddress.c
+- due to previous backport of 07fa9c1529 ("Add VF link state control")
+- and missing 30b55792 ("iproute2: show counter of carrier on<->off transitions")
+---
+ ip/Makefile    |   5 +-
+ ip/ip6tunnel.c | 138 ++++++++++++++++----
+ ip/iplink.c    |  19 ++-
+ ip/iptunnel.c  |   2 +-
+ ip/link_gre6.c | 398 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ ip/link_vti6.c | 250 ++++++++++++++++++++++++++++++++++++
+ 6 files changed, 776 insertions(+), 36 deletions(-)
+ create mode 100644 ip/link_gre6.c
+ create mode 100644 ip/link_vti6.c
+
+diff --git a/ip/Makefile b/ip/Makefile
+index 48bd4a1..f377c37 100644
+--- a/ip/Makefile
++++ b/ip/Makefile
+@@ -3,9 +3,9 @@ IPOBJ=ip.o ipaddress.o ipaddrlabel.o iproute.o iprule.o ipnetns.o \
+     ipmaddr.o ipmonitor.o ipmroute.o ipprefix.o iptuntap.o iptoken.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_macvlan.o iplink_macvtap.o ipl2tp.o link_vti.o link_vti6.o \
+     iplink_vxlan.o tcp_metrics.o iplink_ipoib.o ipnetconf.o link_ip6tnl.o \
+-    link_iptnl.o
++    link_iptnl.o link_gre6.o
+ 
+ RTMONOBJ=rtmon.o
+ 
+@@ -23,7 +23,6 @@ all: $(TARGETS) $(SCRIPTS)
+ 
+ ip: $(IPOBJ) $(LIBNETLINK)
+ 
+-
+ rtmon: $(RTMONOBJ)
+ 
+ install: all
+diff --git a/ip/ip6tunnel.c b/ip/ip6tunnel.c
+index 216e982..f37042e 100644
+--- a/ip/ip6tunnel.c
++++ b/ip/ip6tunnel.c
+@@ -48,11 +48,12 @@ static void usage(void) __attribute__((noreturn));
+ static void usage(void)
+ {
+ 	fprintf(stderr, "Usage: ip -f inet6 tunnel { add | change | del | show } [ NAME ]\n");
+-	fprintf(stderr, "          [ mode { ip6ip6 | ipip6 | any } ]\n");
++	fprintf(stderr, "          [ mode { ip6ip6 | ipip6 | ip6gre | vti6 | any } ]\n");
+ 	fprintf(stderr, "          [ remote ADDR local ADDR ] [ dev PHYS_DEV ]\n");
+ 	fprintf(stderr, "          [ encaplimit ELIM ]\n");
+ 	fprintf(stderr ,"          [ hoplimit TTL ] [ tclass TCLASS ] [ flowlabel FLOWLABEL ]\n");
+ 	fprintf(stderr, "          [ dscp inherit ]\n");
++	fprintf(stderr, "          [ [i|o]seq ] [ [i|o]key KEY ] [ [i|o]csum ]\n");
+ 	fprintf(stderr, "\n");
+ 	fprintf(stderr, "Where: NAME      := STRING\n");
+ 	fprintf(stderr, "       ADDR      := IPV6_ADDRESS\n");
+@@ -62,10 +63,11 @@ static void usage(void)
+ 		DEFAULT_TNL_HOP_LIMIT);
+ 	fprintf(stderr, "       TCLASS    := { 0x0..0xff | inherit }\n");
+ 	fprintf(stderr, "       FLOWLABEL := { 0x0..0xfffff | inherit }\n");
++	fprintf(stderr, "       KEY       := { DOTTED_QUAD | NUMBER }\n");
+ 	exit(-1);
+ }
+ 
+-static void print_tunnel(struct ip6_tnl_parm *p)
++static void print_tunnel(struct ip6_tnl_parm2 *p)
+ {
+ 	char remote[64];
+ 	char local[64];
+@@ -104,9 +106,29 @@ static void print_tunnel(struct ip6_tnl_parm *p)
+ 
+ 	if (p->flags & IP6_TNL_F_RCV_DSCP_COPY)
+ 		printf(" dscp inherit");
++
++	if (p->proto == IPPROTO_GRE) {
++		if ((p->i_flags&GRE_KEY) && (p->o_flags&GRE_KEY) && p->o_key == p->i_key)
++			printf(" key %u", ntohl(p->i_key));
++		else if ((p->i_flags|p->o_flags)&GRE_KEY) {
++			if (p->i_flags&GRE_KEY)
++				printf(" ikey %u ", ntohl(p->i_key));
++			if (p->o_flags&GRE_KEY)
++				printf(" okey %u ", ntohl(p->o_key));
++		}
++
++		if (p->i_flags&GRE_SEQ)
++			printf("%s  Drop packets out of sequence.", _SL_);
++		if (p->i_flags&GRE_CSUM)
++			printf("%s  Checksum in received packet is required.", _SL_);
++		if (p->o_flags&GRE_SEQ)
++			printf("%s  Sequence packets on output.", _SL_);
++		if (p->o_flags&GRE_CSUM)
++			printf("%s  Checksum output packets.", _SL_);
++	}
+ }
+ 
+-static int parse_args(int argc, char **argv, int cmd, struct ip6_tnl_parm *p)
++static int parse_args(int argc, char **argv, int cmd, struct ip6_tnl_parm2 *p)
+ {
+ 	int count = 0;
+ 	char medium[IFNAMSIZ];
+@@ -119,19 +141,25 @@ static int parse_args(int argc, char **argv, int cmd, struct ip6_tnl_parm *p)
+ 			if (strcmp(*argv, "ipv6/ipv6") == 0 ||
+ 			    strcmp(*argv, "ip6ip6") == 0)
+ 				p->proto = IPPROTO_IPV6;
+-			else if (strcmp(*argv, "ip/ipv6") == 0 ||
++			else if (strcmp(*argv, "vti6") == 0) {
++				p->proto = IPPROTO_IPV6;
++				p->i_flags |= VTI_ISVTI;
++			} else if (strcmp(*argv, "ip/ipv6") == 0 ||
+ 				 strcmp(*argv, "ipv4/ipv6") == 0 ||
+ 				 strcmp(*argv, "ipip6") == 0 ||
+ 				 strcmp(*argv, "ip4ip6") == 0)
+ 				p->proto = IPPROTO_IPIP;
++			else if (strcmp(*argv, "ip6gre") == 0 ||
++				 strcmp(*argv, "gre/ipv6") == 0)
++				p->proto = IPPROTO_GRE;
+ 			else if (strcmp(*argv, "any/ipv6") == 0 ||
+ 				 strcmp(*argv, "any") == 0)
+ 				p->proto = 0;
+ 			else {
+-                                fprintf(stderr,"Unknown tunnel mode \"%s\"\n", *argv);
+-                                exit(-1);
+-                        }
+-                } else if (strcmp(*argv, "remote") == 0) {
++				fprintf(stderr,"Unknown tunnel mode \"%s\"\n", *argv);
++				exit(-1);
++			}
++		} else if (strcmp(*argv, "remote") == 0) {
+ 			inet_prefix raddr;
+ 			NEXT_ARG();
+ 			get_prefix(&raddr, *argv, preferred_family);
+@@ -202,6 +230,60 @@ static int parse_args(int argc, char **argv, int cmd, struct ip6_tnl_parm *p)
+ 			if (strcmp(*argv, "inherit") != 0)
+ 				invarg("not inherit", *argv);
+ 			p->flags |= IP6_TNL_F_RCV_DSCP_COPY;
++		} else if (strcmp(*argv, "key") == 0) {
++			unsigned uval;
++			NEXT_ARG();
++			p->i_flags |= GRE_KEY;
++			p->o_flags |= GRE_KEY;
++			if (strchr(*argv, '.'))
++				p->i_key = p->o_key = get_addr32(*argv);
++			else {
++				if (get_unsigned(&uval, *argv, 0) < 0) {
++					fprintf(stderr, "invalid value of \"key\"\n");
++					exit(-1);
++				}
++				p->i_key = p->o_key = htonl(uval);
++			}
++		} else if (strcmp(*argv, "ikey") == 0) {
++			unsigned uval;
++			NEXT_ARG();
++			p->i_flags |= GRE_KEY;
++			if (strchr(*argv, '.'))
++				p->i_key = get_addr32(*argv);
++			else {
++				if (get_unsigned(&uval, *argv, 0)<0) {
++					fprintf(stderr, "invalid value of \"ikey\"\n");
++					exit(-1);
++				}
++				p->i_key = htonl(uval);
++			}
++		} else if (strcmp(*argv, "okey") == 0) {
++			unsigned uval;
++			NEXT_ARG();
++			p->o_flags |= GRE_KEY;
++			if (strchr(*argv, '.'))
++				p->o_key = get_addr32(*argv);
++			else {
++				if (get_unsigned(&uval, *argv, 0)<0) {
++					fprintf(stderr, "invalid value of \"okey\"\n");
++					exit(-1);
++				}
++				p->o_key = htonl(uval);
++			}
++		} else if (strcmp(*argv, "seq") == 0) {
++			p->i_flags |= GRE_SEQ;
++			p->o_flags |= GRE_SEQ;
++		} else if (strcmp(*argv, "iseq") == 0) {
++			p->i_flags |= GRE_SEQ;
++		} else if (strcmp(*argv, "oseq") == 0) {
++			p->o_flags |= GRE_SEQ;
++		} else if (strcmp(*argv, "csum") == 0) {
++			p->i_flags |= GRE_CSUM;
++			p->o_flags |= GRE_CSUM;
++		} else if (strcmp(*argv, "icsum") == 0) {
++			p->i_flags |= GRE_CSUM;
++		} else if (strcmp(*argv, "ocsum") == 0) {
++			p->o_flags |= GRE_CSUM;
+ 		} else {
+ 			if (strcmp(*argv, "name") == 0) {
+ 				NEXT_ARG();
+@@ -212,7 +294,7 @@ static int parse_args(int argc, char **argv, int cmd, struct ip6_tnl_parm *p)
+ 				duparg2("name", *argv);
+ 			strncpy(p->name, *argv, IFNAMSIZ - 1);
+ 			if (cmd == SIOCCHGTUNNEL && count == 0) {
+-				struct ip6_tnl_parm old_p;
++				struct ip6_tnl_parm2 old_p;
+ 				memset(&old_p, 0, sizeof(old_p));
+ 				if (tnl_get_ioctl(*argv, &old_p))
+ 					return -1;
+@@ -230,7 +312,7 @@ static int parse_args(int argc, char **argv, int cmd, struct ip6_tnl_parm *p)
+ 	return 0;
+ }
+ 
+-static void ip6_tnl_parm_init(struct ip6_tnl_parm *p, int apply_default)
++static void ip6_tnl_parm_init(struct ip6_tnl_parm2 *p, int apply_default)
+ {
+ 	memset(p, 0, sizeof(*p));
+ 	p->proto = IPPROTO_IPV6;
+@@ -244,8 +326,8 @@ static void ip6_tnl_parm_init(struct ip6_tnl_parm *p, int apply_default)
+  * @p1: user specified parameter
+  * @p2: database entry
+  */
+-static int ip6_tnl_parm_match(const struct ip6_tnl_parm *p1,
+-			      const struct ip6_tnl_parm *p2)
++static int ip6_tnl_parm_match(const struct ip6_tnl_parm2 *p1,
++			      const struct ip6_tnl_parm2 *p2)
+ {
+ 	return ((!p1->link || p1->link == p2->link) &&
+ 		(!p1->name[0] || strcmp(p1->name, p2->name) == 0) &&
+@@ -263,7 +345,7 @@ static int ip6_tnl_parm_match(const struct ip6_tnl_parm *p1,
+ 		(!p1->flags || (p1->flags & p2->flags)));
+ }
+ 
+-static int do_tunnels_list(struct ip6_tnl_parm *p)
++static int do_tunnels_list(struct ip6_tnl_parm2 *p)
+ {
+ 	char buf[512];
+ 	int err = -1;
+@@ -287,7 +369,7 @@ static int do_tunnels_list(struct ip6_tnl_parm *p)
+ 			rx_fifo, rx_frame,
+ 			tx_bytes, tx_packets, tx_errs, tx_drops,
+ 			tx_fifo, tx_colls, tx_carrier, rx_multi;
+-		struct ip6_tnl_parm p1;
++		struct ip6_tnl_parm2 p1;
+ 		char *ptr;
+ 
+ 		buf[sizeof(buf) - 1] = '\0';
+@@ -312,10 +394,12 @@ static int do_tunnels_list(struct ip6_tnl_parm *p)
+ 			fprintf(stderr, "Failed to get type of \"%s\"\n", name);
+ 			continue;
+ 		}
+-		if (type != ARPHRD_TUNNEL6)
++		if (type != ARPHRD_TUNNEL6 && type != ARPHRD_IP6GRE)
+ 			continue;
+ 		memset(&p1, 0, sizeof(p1));
+ 		ip6_tnl_parm_init(&p1, 0);
++		if (type == ARPHRD_IP6GRE)
++			p1.proto = IPPROTO_GRE;
+ 		strcpy(p1.name, name);
+ 		p1.link = ll_name_to_index(p1.name);
+ 		if (p1.link == 0)
+@@ -346,7 +430,7 @@ static int do_tunnels_list(struct ip6_tnl_parm *p)
+ 
+ static int do_show(int argc, char **argv)
+ {
+-        struct ip6_tnl_parm p;
++        struct ip6_tnl_parm2 p;
+ 
+ 	ll_init_map(&rth);
+ 	ip6_tnl_parm_init(&p, 0);
+@@ -369,28 +453,38 @@ static int do_show(int argc, char **argv)
+ 
+ static int do_add(int cmd, int argc, char **argv)
+ {
+-	struct ip6_tnl_parm p;
++	struct ip6_tnl_parm2 p;
++	const char *basedev = "ip6tnl0";
+ 
+ 	ip6_tnl_parm_init(&p, 1);
+ 
+ 	if (parse_args(argc, argv, cmd, &p) < 0)
+ 		return -1;
+ 
+-	return tnl_add_ioctl(cmd,
+-			     cmd == SIOCCHGTUNNEL && p.name[0] ?
+-			     p.name : "ip6tnl0", p.name, &p);
++	if (p.proto == IPPROTO_GRE)
++		basedev = "ip6gre0";
++	else if (p.i_flags & VTI_ISVTI)
++		basedev = "ip6_vti0";
++
++	return tnl_add_ioctl(cmd, basedev, p.name, &p);
+ }
+ 
+ static int do_del(int argc, char **argv)
+ {
+-	struct ip6_tnl_parm p;
++	struct ip6_tnl_parm2 p;
++	const char *basedev = "ip6tnl0";
+ 
+ 	ip6_tnl_parm_init(&p, 1);
+ 
+ 	if (parse_args(argc, argv, SIOCDELTUNNEL, &p) < 0)
+ 		return -1;
+ 
+-	return tnl_del_ioctl(p.name[0] ? p.name : "ip6tnl0", p.name, &p);
++	if (p.proto == IPPROTO_GRE)
++		basedev = "ip6gre0";
++	else if (p.i_flags & VTI_ISVTI)
++		basedev = "ip6_vti0";
++
++	return tnl_del_ioctl(basedev, p.name, &p);
+ }
+ 
+ int do_ip6tunnel(int argc, char **argv)
+diff --git a/ip/iplink.c b/ip/iplink.c
+index dc98019..deef14b 100644
+--- a/ip/iplink.c
++++ b/ip/iplink.c
+@@ -84,7 +84,8 @@ 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 | ipip | sit | vxlan }\n");
++		fprintf(stderr, "          bridge | ipoib | ip6tnl | ipip | sit | vxlan |\n");
++		fprintf(stderr, "          gre | gretap | ip6gre | ip6gretap }\n");
+ 	}
+ 	exit(-1);
+ }
+@@ -242,7 +243,7 @@ static int iplink_parse_vf(int vf, int *argcp, char ***argvp,
+ 			}
+ 			ivt.vf = vf;
+ 			addattr_l(&req->n, sizeof(*req), IFLA_VF_TX_RATE, &ivt, sizeof(ivt));
+-		
++
+ 		} else if (matches(*argv, "spoofchk") == 0) {
+ 			struct ifla_vf_spoofchk ivs;
+ 			NEXT_ARG();
+@@ -272,7 +273,6 @@ static int iplink_parse_vf(int vf, int *argcp, char ***argvp,
+ 	return 0;
+ }
+ 
+-
+ int iplink_parse(int argc, char **argv, struct iplink_req *req,
+ 		char **name, char **type, char **link, char **dev, int *group)
+ {
+@@ -330,16 +330,16 @@ int iplink_parse(int argc, char **argv, struct iplink_req *req,
+ 			if (get_integer(&mtu, *argv, 0))
+ 				invarg("Invalid \"mtu\" value\n", *argv);
+ 			addattr_l(&req->n, sizeof(*req), IFLA_MTU, &mtu, 4);
+-                } else if (strcmp(*argv, "netns") == 0) {
+-                        NEXT_ARG();
+-                        if (netns != -1)
+-                                duparg("netns", *argv);
++		} else if (strcmp(*argv, "netns") == 0) {
++			NEXT_ARG();
++			if (netns != -1)
++				duparg("netns", *argv);
+ 			if ((netns = get_netns_fd(*argv)) >= 0)
+ 				addattr_l(&req->n, sizeof(*req), IFLA_NET_NS_FD, &netns, 4);
+ 			else if (get_integer(&netns, *argv, 0) == 0)
+ 				addattr_l(&req->n, sizeof(*req), IFLA_NET_NS_PID, &netns, 4);
+ 			else
+-                                invarg("Invalid \"netns\" value\n", *argv);
++				invarg("Invalid \"netns\" value\n", *argv);
+ 		} else if (strcmp(*argv, "multicast") == 0) {
+ 			NEXT_ARG();
+ 			req->i.ifi_change |= IFF_MULTICAST;
+@@ -797,7 +797,6 @@ static int set_address(struct ifreq *ifr, int brd)
+ 	return 0;
+ }
+ 
+-
+ static int do_set(int argc, char **argv)
+ {
+ 	char *dev = NULL;
+@@ -897,7 +896,7 @@ static int do_set(int argc, char **argv)
+ 			} else
+ 				return on_off("dynamic", *argv);
+ 		} else {
+-                        if (strcmp(*argv, "dev") == 0) {
++			if (strcmp(*argv, "dev") == 0) {
+ 				NEXT_ARG();
+ 			}
+ 			if (matches(*argv, "help") == 0)
+diff --git a/ip/iptunnel.c b/ip/iptunnel.c
+index 43f8585..9099503 100644
+--- a/ip/iptunnel.c
++++ b/ip/iptunnel.c
+@@ -405,7 +405,7 @@ static void print_tunnel(struct ip_tunnel_parm *p)
+ 	}
+ 
+ 	if (p->i_flags&GRE_SEQ)
+-		printf("%s  Drop packets out of sequence.\n", _SL_);
++		printf("%s  Drop packets out of sequence.", _SL_);
+ 	if (p->i_flags&GRE_CSUM)
+ 		printf("%s  Checksum in received packet is required.", _SL_);
+ 	if (p->o_flags&GRE_SEQ)
+diff --git a/ip/link_gre6.c b/ip/link_gre6.c
+new file mode 100644
+index 0000000..4c9c536
+--- /dev/null
++++ b/ip/link_gre6.c
+@@ -0,0 +1,398 @@
++/*
++ * link_gre6.c	gre 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:	Dmitry Kozlov <xeb@mail.ru>
++ *
++ */
++
++#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 <linux/ip6_tunnel.h>
++
++#include "rt_names.h"
++#include "utils.h"
++#include "ip_common.h"
++#include "tunnel.h"
++
++#define IP6_FLOWINFO_TCLASS	htonl(0x0FF00000)
++#define IP6_FLOWINFO_FLOWLABEL	htonl(0x000FFFFF)
++
++#define DEFAULT_TNL_HOP_LIMIT	(64)
++
++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 { ip6gre | ip6gretap } [ remote ADDR ] [ local ADDR ]\n");
++	fprintf(stderr, "          [ [i|o]seq ] [ [i|o]key KEY ] [ [i|o]csum ]\n");
++	fprintf(stderr, "          [ hoplimit TTL ] [ encaplimit ELIM ]\n");
++	fprintf(stderr, "          [ tclass TCLASS ] [ flowlabel FLOWLABEL ]\n");
++	fprintf(stderr, "          [ dscp inherit ] [ dev PHYS_DEV ]\n");
++	fprintf(stderr, "\n");
++	fprintf(stderr, "Where: NAME      := STRING\n");
++	fprintf(stderr, "       ADDR      := IPV6_ADDRESS\n");
++	fprintf(stderr, "       TTL       := { 0..255 } (default=%d)\n",
++		DEFAULT_TNL_HOP_LIMIT);
++	fprintf(stderr, "       KEY       := { DOTTED_QUAD | NUMBER }\n");
++	fprintf(stderr, "       ELIM      := { none | 0..255 }(default=%d)\n",
++		IPV6_DEFAULT_TNL_ENCAP_LIMIT);
++	fprintf(stderr, "       TCLASS    := { 0x0..0xff | inherit }\n");
++	fprintf(stderr, "       FLOWLABEL := { 0x0..0xfffff | inherit }\n");
++	exit(-1);
++}
++
++static int gre_parse_opt(struct link_util *lu, int argc, char **argv,
++			 struct nlmsghdr *n)
++{
++	struct {
++		struct nlmsghdr n;
++		struct ifinfomsg i;
++		char buf[1024];
++	} req;
++	struct ifinfomsg *ifi = (struct ifinfomsg *)(n + 1);
++	struct rtattr *tb[IFLA_MAX + 1];
++	struct rtattr *linkinfo[IFLA_INFO_MAX+1];
++	struct rtattr *greinfo[IFLA_GRE_MAX + 1];
++	__u16 iflags = 0;
++	__u16 oflags = 0;
++	unsigned ikey = 0;
++	unsigned okey = 0;
++	struct in6_addr raddr = IN6ADDR_ANY_INIT;
++	struct in6_addr laddr = IN6ADDR_ANY_INIT;
++	unsigned link = 0;
++	unsigned flowinfo = 0;
++	unsigned flags = 0;
++	__u8 hop_limit = DEFAULT_TNL_HOP_LIMIT;
++	__u8 encap_limit = IPV6_DEFAULT_TNL_ENCAP_LIMIT;
++	int len;
++
++	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(greinfo, IFLA_GRE_MAX,
++				    linkinfo[IFLA_INFO_DATA]);
++
++		if (greinfo[IFLA_GRE_IKEY])
++			ikey = rta_getattr_u32(greinfo[IFLA_GRE_IKEY]);
++
++		if (greinfo[IFLA_GRE_OKEY])
++			okey = rta_getattr_u32(greinfo[IFLA_GRE_OKEY]);
++
++		if (greinfo[IFLA_GRE_IFLAGS])
++			iflags = rta_getattr_u16(greinfo[IFLA_GRE_IFLAGS]);
++
++		if (greinfo[IFLA_GRE_OFLAGS])
++			oflags = rta_getattr_u16(greinfo[IFLA_GRE_OFLAGS]);
++
++		if (greinfo[IFLA_GRE_LOCAL])
++			memcpy(&laddr, RTA_DATA(greinfo[IFLA_GRE_LOCAL]), sizeof(laddr));
++
++		if (greinfo[IFLA_GRE_REMOTE])
++			memcpy(&raddr, RTA_DATA(greinfo[IFLA_GRE_REMOTE]), sizeof(raddr));
++
++		if (greinfo[IFLA_GRE_TTL])
++			hop_limit = rta_getattr_u8(greinfo[IFLA_GRE_TTL]);
++
++		if (greinfo[IFLA_GRE_LINK])
++			link = rta_getattr_u32(greinfo[IFLA_GRE_LINK]);
++
++		if (greinfo[IFLA_GRE_ENCAP_LIMIT])
++			encap_limit = rta_getattr_u8(greinfo[IFLA_GRE_ENCAP_LIMIT]);
++
++		if (greinfo[IFLA_GRE_FLOWINFO])
++			flowinfo = rta_getattr_u32(greinfo[IFLA_GRE_FLOWINFO]);
++
++		if (greinfo[IFLA_GRE_FLAGS])
++			flags = rta_getattr_u32(greinfo[IFLA_GRE_FLAGS]);
++	}
++
++	while (argc > 0) {
++		if (!matches(*argv, "key")) {
++			unsigned uval;
++
++			NEXT_ARG();
++			iflags |= GRE_KEY;
++			oflags |= GRE_KEY;
++			if (strchr(*argv, '.'))
++				uval = get_addr32(*argv);
++			else {
++				if (get_unsigned(&uval, *argv, 0) < 0) {
++					fprintf(stderr,
++						"Invalid value for \"key\"\n");
++					exit(-1);
++				}
++				uval = htonl(uval);
++			}
++
++			ikey = okey = uval;
++		} else if (!matches(*argv, "ikey")) {
++			unsigned uval;
++
++			NEXT_ARG();
++			iflags |= GRE_KEY;
++			if (strchr(*argv, '.'))
++				uval = get_addr32(*argv);
++			else {
++				if (get_unsigned(&uval, *argv, 0)<0) {
++					fprintf(stderr, "invalid value of \"ikey\"\n");
++					exit(-1);
++				}
++				uval = htonl(uval);
++			}
++			ikey = uval;
++		} else if (!matches(*argv, "okey")) {
++			unsigned uval;
++
++			NEXT_ARG();
++			oflags |= GRE_KEY;
++			if (strchr(*argv, '.'))
++				uval = get_addr32(*argv);
++			else {
++				if (get_unsigned(&uval, *argv, 0)<0) {
++					fprintf(stderr, "invalid value of \"okey\"\n");
++					exit(-1);
++				}
++				uval = htonl(uval);
++			}
++			okey = uval;
++		} else if (!matches(*argv, "seq")) {
++			iflags |= GRE_SEQ;
++			oflags |= GRE_SEQ;
++		} else if (!matches(*argv, "iseq")) {
++			iflags |= GRE_SEQ;
++		} else if (!matches(*argv, "oseq")) {
++			oflags |= GRE_SEQ;
++		} else if (!matches(*argv, "csum")) {
++			iflags |= GRE_CSUM;
++			oflags |= GRE_CSUM;
++		} else if (!matches(*argv, "icsum")) {
++			iflags |= GRE_CSUM;
++		} else if (!matches(*argv, "ocsum")) {
++			oflags |= GRE_CSUM;
++		} else if (!matches(*argv, "remote")) {
++			inet_prefix addr;
++			NEXT_ARG();
++			get_prefix(&addr, *argv, preferred_family);
++			if (addr.family == AF_UNSPEC)
++				invarg("\"remote\" address family is AF_UNSPEC", *argv);
++			memcpy(&raddr, &addr.data, sizeof(raddr));
++		} else if (!matches(*argv, "local")) {
++			inet_prefix addr;
++			NEXT_ARG();
++			get_prefix(&addr, *argv, preferred_family);
++			if (addr.family == AF_UNSPEC)
++				invarg("\"local\" address family is AF_UNSPEC", *argv);
++			memcpy(&laddr, &addr.data, sizeof(laddr));
++		} else if (!matches(*argv, "dev")) {
++			NEXT_ARG();
++			link = if_nametoindex(*argv);
++			if (link == 0)
++				exit(-1);
++		} else if (!matches(*argv, "ttl") ||
++			   !matches(*argv, "hoplimit")) {
++			__u8 uval;
++			NEXT_ARG();
++			if (get_u8(&uval, *argv, 0))
++				invarg("invalid TTL", *argv);
++			hop_limit = uval;
++		} else if (!matches(*argv, "tos") ||
++			   !matches(*argv, "tclass") ||
++			   !matches(*argv, "dsfield")) {
++			__u8 uval;
++			NEXT_ARG();
++			if (strcmp(*argv, "inherit") == 0)
++				flags |= IP6_TNL_F_USE_ORIG_TCLASS;
++			else {
++				if (get_u8(&uval, *argv, 16))
++					invarg("invalid TClass", *argv);
++				flowinfo |= htonl((__u32)uval << 20) & IP6_FLOWINFO_TCLASS;
++				flags &= ~IP6_TNL_F_USE_ORIG_TCLASS;
++			}
++		} else if (strcmp(*argv, "flowlabel") == 0 ||
++			   strcmp(*argv, "fl") == 0) {
++			__u32 uval;
++			NEXT_ARG();
++			if (strcmp(*argv, "inherit") == 0)
++				flags |= IP6_TNL_F_USE_ORIG_FLOWLABEL;
++			else {
++				if (get_u32(&uval, *argv, 16))
++					invarg("invalid Flowlabel", *argv);
++				if (uval > 0xFFFFF)
++					invarg("invalid Flowlabel", *argv);
++				flowinfo |= htonl(uval) & IP6_FLOWINFO_FLOWLABEL;
++				flags &= ~IP6_TNL_F_USE_ORIG_FLOWLABEL;
++			}
++		} else if (strcmp(*argv, "dscp") == 0) {
++			NEXT_ARG();
++			if (strcmp(*argv, "inherit") != 0)
++				invarg("not inherit", *argv);
++			flags |= IP6_TNL_F_RCV_DSCP_COPY;
++		} 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);
++	addattr_l(n, 1024, IFLA_GRE_FLAGS, &flowinfo, 4);
++
++	return 0;
++}
++
++static void gre_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";
++	unsigned iflags = 0;
++	unsigned oflags = 0;
++	unsigned flags = 0;
++	unsigned flowinfo = 0;
++	struct in6_addr in6_addr_any = IN6ADDR_ANY_INIT;
++
++	if (!tb)
++		return;
++
++	if (tb[IFLA_GRE_FLAGS])
++		flags = rta_getattr_u32(tb[IFLA_GRE_FLAGS]);
++
++	if (tb[IFLA_GRE_FLOWINFO])
++		flags = rta_getattr_u32(tb[IFLA_GRE_FLOWINFO]);
++
++	if (tb[IFLA_GRE_REMOTE]) {
++		struct in6_addr addr;
++		memcpy(&addr, RTA_DATA(tb[IFLA_GRE_REMOTE]), sizeof(addr));
++
++		if (memcmp(&addr, &in6_addr_any, sizeof(addr)))
++			remote = format_host(AF_INET6, sizeof(addr), &addr, s1, sizeof(s1));
++	}
++
++	fprintf(f, "remote %s ", remote);
++
++	if (tb[IFLA_GRE_LOCAL]) {
++		struct in6_addr addr;
++		memcpy(&addr, RTA_DATA(tb[IFLA_GRE_LOCAL]), sizeof(addr));
++
++		if (memcmp(&addr, &in6_addr_any, sizeof(addr)))
++			local = format_host(AF_INET6, sizeof(addr), &addr, s1, sizeof(s1));
++	}
++
++	fprintf(f, "local %s ", local);
++
++	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);
++		else
++			fprintf(f, "dev %u ", link);
++	}
++
++	if (tb[IFLA_GRE_TTL] && rta_getattr_u8(tb[IFLA_GRE_TTL]))
++		fprintf(f, "hoplimit %d ", rta_getattr_u8(tb[IFLA_GRE_TTL]));
++
++	if (flags & IP6_TNL_F_IGN_ENCAP_LIMIT)
++		fprintf(f, "encaplimit none ");
++	else if (tb[IFLA_GRE_ENCAP_LIMIT]) {
++		int encap_limit = rta_getattr_u8(tb[IFLA_GRE_ENCAP_LIMIT]);
++
++		fprintf(f, "encaplimit %d ", encap_limit);
++	}
++
++	if (flags & IP6_TNL_F_USE_ORIG_FLOWLABEL)
++		fprintf(f, "flowlabel inherit ");
++	else
++		fprintf(f, "flowlabel 0x%05x ", ntohl(flowinfo & IP6_FLOWINFO_FLOWLABEL));
++
++	if (flags & IP6_TNL_F_RCV_DSCP_COPY)
++		fprintf(f, "dscp inherit ");
++
++	if (tb[IFLA_GRE_IFLAGS])
++		iflags = rta_getattr_u16(tb[IFLA_GRE_IFLAGS]);
++
++	if (tb[IFLA_GRE_OFLAGS])
++		oflags = rta_getattr_u16(tb[IFLA_GRE_OFLAGS]);
++
++	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]) {
++		inet_ntop(AF_INET, RTA_DATA(tb[IFLA_GRE_OKEY]), s2, sizeof(s2));
++		fprintf(f, "okey %s ", s2);
++	}
++
++	if (iflags & GRE_SEQ)
++		fputs("iseq ", f);
++	if (oflags & GRE_SEQ)
++		fputs("oseq ", f);
++	if (iflags & GRE_CSUM)
++		fputs("icsum ", f);
++	if (oflags & GRE_CSUM)
++		fputs("ocsum ", f);
++}
++
++struct link_util ip6gre_link_util = {
++	.id = "ip6gre",
++	.maxattr = IFLA_GRE_MAX,
++	.parse_opt = gre_parse_opt,
++	.print_opt = gre_print_opt,
++};
++
++struct link_util ip6gretap_link_util = {
++	.id = "ip6gretap",
++	.maxattr = IFLA_GRE_MAX,
++	.parse_opt = gre_parse_opt,
++	.print_opt = gre_print_opt,
++};
+diff --git a/ip/link_vti6.c b/ip/link_vti6.c
+new file mode 100644
+index 0000000..282896d
+--- /dev/null
++++ b/ip/link_vti6.c
+@@ -0,0 +1,250 @@
++/*
++ * link_vti6.c	VTI 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:	Herbert Xu <herbert@gondor.apana.org.au>
++ *		Saurabh Mohan <saurabh.mohan@vyatta.com> Modified link_gre.c for VTI
++ *		Steffen Klassert <steffen.klassert@secunet.com> Modified link_vti.c for IPv6
++ */
++
++#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(void) __attribute__((noreturn));
++static void usage(void)
++{
++	fprintf(stderr, "Usage: ip link { add | set | change | replace | del } NAME\n");
++	fprintf(stderr, "          type { vti6 } [ remote ADDR ] [ local ADDR ]\n");
++	fprintf(stderr, "          [ [i|o]key KEY ]\n");
++	fprintf(stderr, "          [ dev PHYS_DEV ]\n");
++	fprintf(stderr, "\n");
++	fprintf(stderr, "Where: NAME := STRING\n");
++	fprintf(stderr, "       ADDR := { IPV6_ADDRESS }\n");
++	fprintf(stderr, "       KEY  := { DOTTED_QUAD | NUMBER }\n");
++	exit(-1);
++}
++
++static int vti6_parse_opt(struct link_util *lu, int argc, char **argv,
++			  struct nlmsghdr *n)
++{
++	struct {
++		struct nlmsghdr n;
++		struct ifinfomsg i;
++		char buf[1024];
++	} req;
++	struct ifinfomsg *ifi = (struct ifinfomsg *)(n + 1);
++	struct rtattr *tb[IFLA_MAX + 1];
++	struct rtattr *linkinfo[IFLA_INFO_MAX+1];
++	struct rtattr *vtiinfo[IFLA_VTI_MAX + 1];
++	struct in6_addr saddr;
++	struct in6_addr daddr;
++	unsigned ikey = 0;
++	unsigned okey = 0;
++	unsigned link = 0;
++	int len;
++
++	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(vtiinfo, IFLA_VTI_MAX,
++				    linkinfo[IFLA_INFO_DATA]);
++
++		if (vtiinfo[IFLA_VTI_IKEY])
++			ikey = rta_getattr_u32(vtiinfo[IFLA_VTI_IKEY]);
++
++		if (vtiinfo[IFLA_VTI_OKEY])
++			okey = rta_getattr_u32(vtiinfo[IFLA_VTI_OKEY]);
++
++		if (vtiinfo[IFLA_VTI_LOCAL])
++			memcpy(&saddr, RTA_DATA(vtiinfo[IFLA_VTI_LOCAL]), sizeof(saddr));
++
++		if (vtiinfo[IFLA_VTI_REMOTE])
++			memcpy(&daddr, RTA_DATA(vtiinfo[IFLA_VTI_REMOTE]), sizeof(daddr));
++
++		if (vtiinfo[IFLA_VTI_LINK])
++			link = rta_getattr_u8(vtiinfo[IFLA_VTI_LINK]);
++	}
++
++	while (argc > 0) {
++		if (!matches(*argv, "key")) {
++			unsigned uval;
++
++			NEXT_ARG();
++			if (strchr(*argv, '.'))
++				uval = get_addr32(*argv);
++			else {
++				if (get_unsigned(&uval, *argv, 0) < 0) {
++					fprintf(stderr,
++						"Invalid value for \"key\": \"%s\"; it should be an unsigned integer\n", *argv);
++					exit(-1);
++				}
++				uval = htonl(uval);
++			}
++
++			ikey = okey = uval;
++		} else if (!matches(*argv, "ikey")) {
++			unsigned uval;
++
++			NEXT_ARG();
++			if (strchr(*argv, '.'))
++				uval = get_addr32(*argv);
++			else {
++				if (get_unsigned(&uval, *argv, 0) < 0) {
++					fprintf(stderr, "invalid value for \"ikey\": \"%s\"; it should be an unsigned integer\n", *argv);
++					exit(-1);
++				}
++				uval = htonl(uval);
++			}
++			ikey = uval;
++		} else if (!matches(*argv, "okey")) {
++			unsigned uval;
++
++			NEXT_ARG();
++			if (strchr(*argv, '.'))
++				uval = get_addr32(*argv);
++			else {
++				if (get_unsigned(&uval, *argv, 0) < 0) {
++					fprintf(stderr, "invalid value for \"okey\": \"%s\"; it should be an unsigned integer\n", *argv);
++					exit(-1);
++				}
++				uval = htonl(uval);
++			}
++			okey = uval;
++		} else if (!matches(*argv, "remote")) {
++			NEXT_ARG();
++			if (!strcmp(*argv, "any")) {
++				fprintf(stderr, "invalid value for \"remote\": \"%s\"\n", *argv);
++				exit(-1);
++			} else {
++				inet_prefix addr;
++				get_prefix(&addr, *argv, AF_INET6);
++				memcpy(&daddr, addr.data, addr.bytelen);
++			}
++		} else if (!matches(*argv, "local")) {
++			NEXT_ARG();
++			if (!strcmp(*argv, "any")) {
++				fprintf(stderr, "invalid value for \"local\": \"%s\"\n", *argv);
++				exit(-1);
++			} else {
++				inet_prefix addr;
++				get_prefix(&addr, *argv, AF_INET6);
++				memcpy(&saddr, addr.data, addr.bytelen);
++			}
++		} else if (!matches(*argv, "dev")) {
++			NEXT_ARG();
++			link = if_nametoindex(*argv);
++			if (link == 0)
++				exit(-1);
++		} else
++			usage();
++		argc--; argv++;
++	}
++
++	addattr32(n, 1024, IFLA_VTI_IKEY, ikey);
++	addattr32(n, 1024, IFLA_VTI_OKEY, okey);
++	addattr_l(n, 1024, IFLA_VTI_LOCAL, &saddr, sizeof(saddr));
++	addattr_l(n, 1024, IFLA_VTI_REMOTE, &daddr, sizeof(daddr));
++	if (link)
++		addattr32(n, 1024, IFLA_VTI_LINK, link);
++
++	return 0;
++}
++
++static void vti6_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";
++	struct in6_addr saddr;
++	struct in6_addr daddr;
++
++	if (!tb)
++		return;
++
++	if (tb[IFLA_VTI_REMOTE]) {
++		memcpy(&daddr, RTA_DATA(tb[IFLA_VTI_REMOTE]), sizeof(daddr));
++
++		remote = format_host(AF_INET6, 16, &daddr, s1, sizeof(s1));
++	}
++
++	fprintf(f, "remote %s ", remote);
++
++	if (tb[IFLA_VTI_LOCAL]) {
++		memcpy(&saddr, RTA_DATA(tb[IFLA_VTI_LOCAL]), sizeof(saddr));
++
++		local = format_host(AF_INET6, 16, &saddr, s1, sizeof(s1));
++	}
++
++	fprintf(f, "local %s ", local);
++
++	if (tb[IFLA_VTI_LINK] && *(__u32 *)RTA_DATA(tb[IFLA_VTI_LINK])) {
++		unsigned link = *(__u32 *)RTA_DATA(tb[IFLA_VTI_LINK]);
++		const char *n = if_indextoname(link, s2);
++
++		if (n)
++			fprintf(f, "dev %s ", n);
++		else
++			fprintf(f, "dev %u ", link);
++	}
++
++	if (tb[IFLA_VTI_IKEY]) {
++		inet_ntop(AF_INET, RTA_DATA(tb[IFLA_VTI_IKEY]), s2, sizeof(s2));
++		fprintf(f, "ikey %s ", s2);
++	}
++
++	if (tb[IFLA_VTI_OKEY]) {
++		inet_ntop(AF_INET, RTA_DATA(tb[IFLA_VTI_OKEY]), s2, sizeof(s2));
++		fprintf(f, "okey %s ", s2);
++	}
++}
++
++struct link_util vti6_link_util = {
++	.id = "vti6",
++	.maxattr = IFLA_VTI_MAX,
++	.parse_opt = vti6_parse_opt,
++	.print_opt = vti6_print_opt,
++};
+-- 
+1.8.3.1
+
diff --git a/SOURCES/iproute-3.10.0-man-tc.8-mention-Fair-Queue-scheduler.patch b/SOURCES/iproute-3.10.0-man-tc.8-mention-Fair-Queue-scheduler.patch
new file mode 100644
index 0000000..b405656
--- /dev/null
+++ b/SOURCES/iproute-3.10.0-man-tc.8-mention-Fair-Queue-scheduler.patch
@@ -0,0 +1,31 @@
+From e4341c2d317de1d30deb1672af1e43fc04ac4f0d Mon Sep 17 00:00:00 2001
+From: Phil Sutter <psutter@redhat.com>
+Date: Wed, 9 Sep 2015 15:33:36 +0200
+Subject: [PATCH] man: tc.8: mention Fair Queue scheduler
+
+This is rather a placeholder to let users know fq exists at all.
+---
+This patch has not been accepted upstream yet, but since it's the last blocker
+for RHEL7.2 I'll condone the consequences.
+---
+ man/man8/tc.8 | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+diff --git a/man/man8/tc.8 b/man/man8/tc.8
+index cc839d9..b8ef52a 100644
+--- a/man/man8/tc.8
++++ b/man/man8/tc.8
+@@ -148,6 +148,10 @@ The classless qdiscs are:
+ Simplest usable qdisc, pure First In, First Out behaviour. Limited in
+ packets or in bytes.
+ .TP
++fq
++Fair Queue Scheduler realises TCP pacing and scales to millions of concurrent
++flows per qdisc.
++.TP
+ pfifo_fast
+ Standard qdisc for 'Advanced Router' enabled kernels. Consists of a three-band
+ queue which honors Type of Service flags, as well as the priority that may be
+-- 
+1.8.3.1
+
diff --git a/SOURCES/iproute2-3.10.0-1139173.patch b/SOURCES/iproute2-3.10.0-1139173.patch
new file mode 100644
index 0000000..b5f9d7d
--- /dev/null
+++ b/SOURCES/iproute2-3.10.0-1139173.patch
@@ -0,0 +1,27 @@
+commit 1ed509bb522225050edfa1ed7ddc7255e9a18bd5
+Author: Thomas Egerer <thomas.egerer@secunet.com>
+Date:   Thu Aug 29 14:00:36 2013 +0200
+
+    ip/xfrm: Fix potential SIGSEGV when printing extra flags
+    
+    The git-commit dc8867d0, that added support for displaying the
+    extra-flags of a state, introduced a potential segfault.
+    Trying to show a state without the extra-flag attribute and show_stats
+    enabled, would cause the NULL pointer in tb[XFRMA_SA_EXTRA_FLAGS] to be
+    dereferenced.
+    
+    Signed-off-by: Thomas Egerer <thomas.egerer@secunet.com>
+
+diff --git a/ip/ipxfrm.c b/ip/ipxfrm.c
+index 0a3a9fb..411d9d5 100644
+--- a/ip/ipxfrm.c
++++ b/ip/ipxfrm.c
+@@ -856,7 +856,7 @@ void xfrm_state_info_print(struct xfrm_usersa_info *xsinfo,
+ 		if (flags)
+ 			fprintf(fp, "%x", flags);
+ 	}
+-	if (show_stats > 0 || tb[XFRMA_SA_EXTRA_FLAGS]) {
++	if (show_stats > 0 && tb[XFRMA_SA_EXTRA_FLAGS]) {
+ 		__u32 extra_flags = *(__u32 *)RTA_DATA(tb[XFRMA_SA_EXTRA_FLAGS]);
+ 
+ 		fprintf(fp, "extra_flag ");
diff --git a/SOURCES/iproute2-3.10.0-Add-IPv6-support-to-VXLAN.patch b/SOURCES/iproute2-3.10.0-Add-IPv6-support-to-VXLAN.patch
deleted file mode 100644
index 732f6c8..0000000
--- a/SOURCES/iproute2-3.10.0-Add-IPv6-support-to-VXLAN.patch
+++ /dev/null
@@ -1,172 +0,0 @@
-From 885f6dfe74abec4f29fe48433b5ad9f899f2defd Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Petr=20=C5=A0abata?= <contyk@redhat.com>
-Date: Tue, 25 Feb 2014 16:36:10 +0100
-Subject: [PATCH 2/2] Add IPv6 support to VXLAN
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Signed-off-by: Petr Šabata <contyk@redhat.com>
----
- include/utils.h   |  1 +
- ip/iplink_vxlan.c | 59 +++++++++++++++++++++++++++++++++++++++++++++----------
- lib/utils.c       |  8 ++++++++
- 3 files changed, 58 insertions(+), 10 deletions(-)
-
-diff --git a/include/utils.h b/include/utils.h
-index 24ff19f..a3e310e 100644
---- a/include/utils.h
-+++ b/include/utils.h
-@@ -151,6 +151,7 @@ int print_timestamp(FILE *fp);
- extern int cmdlineno;
- extern ssize_t getcmdline(char **line, size_t *len, FILE *in);
- extern int makeargs(char *line, char *argv[], int maxargs);
-+extern int inet_get_addr(const char *src, __u32 *dst, struct in6_addr *dst6);
- 
- struct iplink_req;
- int iplink_parse(int argc, char **argv, struct iplink_req *req,
-diff --git a/ip/iplink_vxlan.c b/ip/iplink_vxlan.c
-index fdae6b1..81b8706 100644
---- a/ip/iplink_vxlan.c
-+++ b/ip/iplink_vxlan.c
-@@ -43,6 +43,9 @@ static int vxlan_parse_opt(struct link_util *lu, int argc, char **argv,
- 	__u32 saddr = 0;
- 	__u32 gaddr = 0;
- 	__u32 daddr = 0;
-+	struct in6_addr saddr6 = IN6ADDR_ANY_INIT;
-+	struct in6_addr gaddr6 = IN6ADDR_ANY_INIT;
-+	struct in6_addr daddr6 = IN6ADDR_ANY_INIT;
- 	unsigned link = 0;
- 	__u8 tos = 0;
- 	__u8 ttl = 0;
-@@ -68,21 +71,30 @@ static int vxlan_parse_opt(struct link_util *lu, int argc, char **argv,
- 			vni_set = 1;
- 		} else if (!matches(*argv, "group")) {
- 			NEXT_ARG();
--			gaddr = get_addr32(*argv);
--
--			if (!IN_MULTICAST(ntohl(gaddr)))
-+			if (!inet_get_addr(*argv, &gaddr, &gaddr6)) {
-+				fprintf(stderr, "Invalid address \"%s\"\n", *argv);
-+				return -1;
-+			}
-+			if (!IN6_IS_ADDR_MULTICAST(&gaddr6) && !IN_MULTICAST(ntohl(gaddr)))
- 				invarg("invalid group address", *argv);
- 		} else if (!matches(*argv, "remote")) {
- 			NEXT_ARG();
--			daddr = get_addr32(*argv);
--
--			if (IN_MULTICAST(ntohl(daddr)))
-+			if (!inet_get_addr(*argv, &daddr, &daddr6)) {
-+				fprintf(stderr, "Invalid address \"%s\"\n", *argv);
-+				return -1;
-+			}
-+			if (IN6_IS_ADDR_MULTICAST(&daddr6) || IN_MULTICAST(ntohl(daddr)))
- 				invarg("invalid remote address", *argv);
- 		} else if (!matches(*argv, "local")) {
- 			NEXT_ARG();
--			if (strcmp(*argv, "any"))
--				saddr = get_addr32(*argv);
--			if (IN_MULTICAST(ntohl(saddr)))
-+			if (strcmp(*argv, "any")) {
-+				if (!inet_get_addr(*argv, &saddr, &saddr6)) {
-+					fprintf(stderr, "Invalid address \"%s\"\n", *argv);
-+					return -1;
-+				}
-+			}
-+
-+			if (IN_MULTICAST(ntohl(saddr)) || IN6_IS_ADDR_MULTICAST(&saddr6))
- 				invarg("invalid local address", *argv);
- 		} else if (!matches(*argv, "dev")) {
- 			NEXT_ARG();
-@@ -183,7 +195,9 @@ static int vxlan_parse_opt(struct link_util *lu, int argc, char **argv,
- 			"Use 'dstport 4789' to get the IANA assigned value\n"
- 			"Use 'dstport 0' to get default and quiet this message\n");
- 	}
--	if (gaddr && daddr) {
-+	if ((gaddr && daddr) ||
-+		(memcmp(&gaddr6, &in6addr_any, sizeof(gaddr6)) &&
-+		 memcmp(&daddr6, &in6addr_any, sizeof(daddr6)))) {
- 		fprintf(stderr, "vxlan: both group and remote cannot be specified\n");
- 		return -1;
- 	}
-@@ -192,8 +206,16 @@ static int vxlan_parse_opt(struct link_util *lu, int argc, char **argv,
- 		addattr_l(n, 1024, IFLA_VXLAN_GROUP, &gaddr, 4);
- 	else if (daddr)
- 		addattr_l(n, 1024, IFLA_VXLAN_GROUP, &daddr, 4);
-+	if (memcmp(&gaddr6, &in6addr_any, sizeof(gaddr6)) != 0)
-+		addattr_l(n, 1024, IFLA_VXLAN_GROUP6, &gaddr6, sizeof(struct in6_addr));
-+	else if (memcmp(&daddr6, &in6addr_any, sizeof(daddr6)) != 0)
-+		addattr_l(n, 1024, IFLA_VXLAN_GROUP6, &daddr6, sizeof(struct in6_addr));
-+
- 	if (saddr)
- 		addattr_l(n, 1024, IFLA_VXLAN_LOCAL, &saddr, 4);
-+	else if (memcmp(&saddr6, &in6addr_any, sizeof(saddr6)) != 0)
-+		addattr_l(n, 1024, IFLA_VXLAN_LOCAL6, &saddr6, sizeof(struct in6_addr));
-+
- 	if (link)
- 		addattr32(n, 1024, IFLA_VXLAN_LINK, link);
- 	addattr8(n, 1024, IFLA_VXLAN_TTL, ttl);
-@@ -248,6 +270,17 @@ static void vxlan_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
- 				fprintf(f, "remote %s ",
- 					format_host(AF_INET, 4, &addr, s1, sizeof(s1)));
- 		}
-+	} else if (tb[IFLA_VXLAN_GROUP6]) {
-+		struct in6_addr addr;
-+		memcpy(&addr, RTA_DATA(tb[IFLA_VXLAN_GROUP6]), sizeof(struct in6_addr));
-+		if (memcmp(&addr, &in6addr_any, sizeof(addr)) != 0) {
-+			if (IN6_IS_ADDR_MULTICAST(&addr))
-+				fprintf(f, "group %s ",
-+					format_host(AF_INET6, sizeof(struct in6_addr), &addr, s1, sizeof(s1)));
-+			else
-+				fprintf(f, "remote %s ",
-+					format_host(AF_INET6, sizeof(struct in6_addr), &addr, s1, sizeof(s1)));
-+		}
- 	}
- 
- 	if (tb[IFLA_VXLAN_LOCAL]) {
-@@ -255,6 +288,12 @@ static void vxlan_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
- 		if (addr)
- 			fprintf(f, "local %s ",
- 				format_host(AF_INET, 4, &addr, s1, sizeof(s1)));
-+	} else if (tb[IFLA_VXLAN_LOCAL6]) {
-+		struct in6_addr addr;
-+		memcpy(&addr, RTA_DATA(tb[IFLA_VXLAN_LOCAL6]), sizeof(struct in6_addr));
-+		if (memcmp(&addr, &in6addr_any, sizeof(addr)) != 0)
-+			fprintf(f, "local %s ",
-+				format_host(AF_INET6, sizeof(struct in6_addr), &addr, s1, sizeof(s1)));
- 	}
- 
- 	if (tb[IFLA_VXLAN_LINK] &&
-diff --git a/lib/utils.c b/lib/utils.c
-index 55fea18..1e12f85 100644
---- a/lib/utils.c
-+++ b/lib/utils.c
-@@ -864,3 +864,11 @@ int makeargs(char *line, char *argv[], int maxargs)
- 
- 	return argc;
- }
-+
-+int inet_get_addr(const char *src, __u32 *dst, struct in6_addr *dst6)
-+{
-+	if (strchr(src, ':'))
-+		return inet_pton(AF_INET6, src, dst6);
-+	else
-+		return inet_pton(AF_INET, src, dst);
-+}
--- 
-1.8.5.3
-
-diff --git a/include/linux/if_link.h b/include/linux/if_link.h
-index 965dc9f..b352b73 100644
---- a/include/linux/if_link.h
-+++ b/include/linux/if_link.h
-@@ -309,6 +309,8 @@ enum {
- 	IFLA_VXLAN_L2MISS,
- 	IFLA_VXLAN_L3MISS,
- 	IFLA_VXLAN_PORT,	/* destination port */
-+	IFLA_VXLAN_GROUP6,
-+	IFLA_VXLAN_LOCAL6,
- 	__IFLA_VXLAN_MAX
- };
- #define IFLA_VXLAN_MAX	(__IFLA_VXLAN_MAX - 1)
diff --git a/SOURCES/iproute2-3.10.0-Add-VF-link-state-control.patch b/SOURCES/iproute2-3.10.0-Add-VF-link-state-control.patch
deleted file mode 100644
index 3ee81b4..0000000
--- a/SOURCES/iproute2-3.10.0-Add-VF-link-state-control.patch
+++ /dev/null
@@ -1,115 +0,0 @@
-diff --git a/ip/ipaddress.c b/ip/ipaddress.c
-index 2b3707a..013b4cb 100644
---- a/ip/ipaddress.c
-+++ b/ip/ipaddress.c
-@@ -229,6 +229,7 @@ static void print_vfinfo(FILE *fp, struct rtattr *vfinfo)
- 	struct ifla_vf_vlan *vf_vlan;
- 	struct ifla_vf_tx_rate *vf_tx_rate;
- 	struct ifla_vf_spoofchk *vf_spoofchk;
-+	struct ifla_vf_link_state *vf_linkstate;
- 	struct rtattr *vf[IFLA_VF_MAX+1];
- 	struct rtattr *tmp;
- 	SPRINT_BUF(b1);
-@@ -255,6 +256,20 @@ static void print_vfinfo(FILE *fp, struct rtattr *vfinfo)
- 	else
- 		vf_spoofchk = RTA_DATA(vf[IFLA_VF_SPOOFCHK]);
- 
-+	if (vf_spoofchk) {
-+		/* Check if the link state vf info type is supported by
-+		 * this kernel.
-+		 */
-+		tmp = (struct rtattr *)((char *)vf[IFLA_VF_SPOOFCHK] +
-+				vf[IFLA_VF_SPOOFCHK]->rta_len);
-+
-+		if (tmp->rta_type != IFLA_VF_LINK_STATE)
-+			vf_linkstate = NULL;
-+		else
-+			vf_linkstate = RTA_DATA(vf[IFLA_VF_LINK_STATE]);
-+	} else
-+		vf_linkstate = NULL;
-+
- 	fprintf(fp, "\n    vf %d MAC %s", vf_mac->vf,
- 		ll_addr_n2a((unsigned char *)&vf_mac->mac,
- 		ETH_ALEN, 0, b1, sizeof(b1)));
-@@ -270,6 +285,14 @@ static void print_vfinfo(FILE *fp, struct rtattr *vfinfo)
- 		else
- 			fprintf(fp, ", spoof checking off");
- 	}
-+	if (vf_linkstate) {
-+		if (vf_linkstate->link_state == IFLA_VF_LINK_STATE_AUTO)
-+			fprintf(fp, ", link-state auto");
-+		else if (vf_linkstate->link_state == IFLA_VF_LINK_STATE_ENABLE)
-+			fprintf(fp, ", link-state enable");
-+		else
-+			fprintf(fp, ", link-state disable");
-+	}
- }
- 
- static void print_link_stats64(FILE *fp, const struct rtnl_link_stats64 *s) {
-diff --git a/ip/iplink.c b/ip/iplink.c
-index 15dd84f..f8bcd8c 100644
---- a/ip/iplink.c
-+++ b/ip/iplink.c
-@@ -77,6 +77,7 @@ void iplink_usage(void)
- 	fprintf(stderr, "				   [ rate TXRATE ] ] \n");
- 
- 	fprintf(stderr, "				   [ spoofchk { on | off} ] ] \n");
-+	fprintf(stderr, "				   [ state { auto | enable | disable} ] ]\n");
- 	fprintf(stderr, "			  [ master DEVICE ]\n");
- 	fprintf(stderr, "			  [ nomaster ]\n");
- 	fprintf(stderr, "       ip link show [ DEVICE | group GROUP ] [up]\n");
-@@ -260,6 +261,19 @@ static int iplink_parse_vf(int vf, int *argcp, char ***argvp,
- 			ivs.vf = vf;
- 			addattr_l(&req->n, sizeof(*req), IFLA_VF_SPOOFCHK, &ivs, sizeof(ivs));
- 
-+		} else if (matches(*argv, "state") == 0) {
-+			struct ifla_vf_link_state ivl;
-+			NEXT_ARG();
-+			if (matches(*argv, "auto") == 0)
-+				ivl.link_state = IFLA_VF_LINK_STATE_AUTO;
-+			else if (matches(*argv, "enable") == 0)
-+				ivl.link_state = IFLA_VF_LINK_STATE_ENABLE;
-+			else if (matches(*argv, "disable") == 0)
-+				ivl.link_state = IFLA_VF_LINK_STATE_DISABLE;
-+			else
-+				invarg("Invalid \"state\" value\n", *argv);
-+			ivl.vf = vf;
-+			addattr_l(&req->n, sizeof(*req), IFLA_VF_LINK_STATE, &ivl, sizeof(ivl));
- 		} else {
- 			/* rewind arg */
- 			PREV_ARG();
-diff --git a/include/linux/if_link.h b/include/linux/if_link.h
-index 9a31d6b..20092a7 100644
---- a/include/linux/if_link.h
-+++ b/include/linux/if_link.h
-@@ -362,6 +362,18 @@ struct ifla_vf_spoofchk {
- 	__u32 setting;
- };
- 
-+enum {
-+	IFLA_VF_LINK_STATE_AUTO,        /* link state of the uplink */
-+	IFLA_VF_LINK_STATE_ENABLE,      /* link always up */
-+	IFLA_VF_LINK_STATE_DISABLE,     /* link always down */
-+	__IFLA_VF_LINK_STATE_MAX,
-+};
-+
-+struct ifla_vf_link_state {
-+	__u32 vf;
-+	__u32 link_state;
-+};
-+
- /* VF ports management section
-  *
-  *	Nested layout of set/get msg is:
-diff --git a/include/linux/if_link.h b/include/linux/if_link.h
-index 20092a7..4877906 100644
---- a/include/linux/if_link.h
-+++ b/include/linux/if_link.h
-@@ -336,6 +336,7 @@ enum {
- 	IFLA_VF_VLAN,
- 	IFLA_VF_TX_RATE,	/* TX Bandwidth Allocation */
- 	IFLA_VF_SPOOFCHK,	/* Spoof Checking on/off switch */
-+	IFLA_VF_LINK_STATE,     /* link state enable/disable/auto switch */
- 	__IFLA_VF_MAX,
- };
- 
diff --git a/SOURCES/iproute2-3.10.0-Add-destination-port-support-for-VXLAN.patch b/SOURCES/iproute2-3.10.0-Add-destination-port-support-for-VXLAN.patch
deleted file mode 100644
index 9e471a0..0000000
--- a/SOURCES/iproute2-3.10.0-Add-destination-port-support-for-VXLAN.patch
+++ /dev/null
@@ -1,121 +0,0 @@
-From 31996f4f78d5532447ef5144fc19e4c046f174b5 Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Petr=20=C5=A0abata?= <contyk@redhat.com>
-Date: Tue, 25 Feb 2014 16:30:45 +0100
-Subject: [PATCH 1/2] Add destination port support for VXLAN
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Signed-off-by: Petr Šabata <contyk@redhat.com>
----
- ip/iplink_vxlan.c     | 29 +++++++++++++++++++++++------
- man/man8/ip-link.8.in | 15 +++++++++++++--
- 2 files changed, 36 insertions(+), 8 deletions(-)
-
-diff --git a/ip/iplink_vxlan.c b/ip/iplink_vxlan.c
-index 3450135..fdae6b1 100644
---- a/ip/iplink_vxlan.c
-+++ b/ip/iplink_vxlan.c
-@@ -23,7 +23,7 @@
- 
- static void explain(void)
- {
--	fprintf(stderr, "Usage: ... vxlan id VNI [ group ADDR ] [ local ADDR ]\n");
-+	fprintf(stderr, "Usage: ... vxlan id VNI [ { group | remote } ADDR ] [ local ADDR ]\n");
- 	fprintf(stderr, "                 [ ttl TTL ] [ tos TOS ] [ dev PHYS_DEV ]\n");
- 	fprintf(stderr, "                 [ dstport PORT ] [ srcport MIN MAX ]\n");
- 	fprintf(stderr, "                 [ [no]learning ] [ [no]proxy ] [ [no]rsc ]\n");
-@@ -42,6 +42,7 @@ static int vxlan_parse_opt(struct link_util *lu, int argc, char **argv,
- 	int vni_set = 0;
- 	__u32 saddr = 0;
- 	__u32 gaddr = 0;
-+	__u32 daddr = 0;
- 	unsigned link = 0;
- 	__u8 tos = 0;
- 	__u8 ttl = 0;
-@@ -70,7 +71,13 @@ static int vxlan_parse_opt(struct link_util *lu, int argc, char **argv,
- 			gaddr = get_addr32(*argv);
- 
- 			if (!IN_MULTICAST(ntohl(gaddr)))
--				invarg("invald group address", *argv);
-+				invarg("invalid group address", *argv);
-+		} else if (!matches(*argv, "remote")) {
-+			NEXT_ARG();
-+			daddr = get_addr32(*argv);
-+
-+			if (IN_MULTICAST(ntohl(daddr)))
-+				invarg("invalid remote address", *argv);
- 		} else if (!matches(*argv, "local")) {
- 			NEXT_ARG();
- 			if (strcmp(*argv, "any"))
-@@ -176,10 +183,15 @@ static int vxlan_parse_opt(struct link_util *lu, int argc, char **argv,
- 			"Use 'dstport 4789' to get the IANA assigned value\n"
- 			"Use 'dstport 0' to get default and quiet this message\n");
- 	}
--
-+	if (gaddr && daddr) {
-+		fprintf(stderr, "vxlan: both group and remote cannot be specified\n");
-+		return -1;
-+	}
- 	addattr32(n, 1024, IFLA_VXLAN_ID, vni);
- 	if (gaddr)
- 		addattr_l(n, 1024, IFLA_VXLAN_GROUP, &gaddr, 4);
-+	else if (daddr)
-+		addattr_l(n, 1024, IFLA_VXLAN_GROUP, &daddr, 4);
- 	if (saddr)
- 		addattr_l(n, 1024, IFLA_VXLAN_LOCAL, &saddr, 4);
- 	if (link)
-@@ -228,9 +240,14 @@ static void vxlan_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
- 
- 	if (tb[IFLA_VXLAN_GROUP]) {
- 		__be32 addr = rta_getattr_u32(tb[IFLA_VXLAN_GROUP]);
--		if (addr)
--			fprintf(f, "group %s ",
--				format_host(AF_INET, 4, &addr, s1, sizeof(s1)));
-+		if (addr) {
-+			if (IN_MULTICAST(ntohl(addr)))
-+				fprintf(f, "group %s ",
-+					format_host(AF_INET, 4, &addr, s1, sizeof(s1)));
-+			else
-+				fprintf(f, "remote %s ",
-+					format_host(AF_INET, 4, &addr, s1, sizeof(s1)));
-+		}
- 	}
- 
- 	if (tb[IFLA_VXLAN_LOCAL]) {
-diff --git a/man/man8/ip-link.8.in b/man/man8/ip-link.8.in
-index 9daac71..6a32990 100644
---- a/man/man8/ip-link.8.in
-+++ b/man/man8/ip-link.8.in
-@@ -265,8 +265,8 @@ the following additional arguments are supported:
- .BI type " vxlan " id " ID
- .R " [ "
- .BI dev " PHYS_DEV "
--.R " ] [ "
--.BI group " IPADDR "
-+.RB " ] [ { " group " | " remote " } "
-+.I IPADDR
- .R " ] [ "
- .BI local " IPADDR "
- .R " ] [ "
-@@ -299,6 +299,17 @@ Identifier) to use.
- .sp
- .BI group " IPADDR"
- - specifies the multicast IP address to join.
-+This parameter cannot be specified with the
-+.B remote
-+parameter.
-+
-+.sp
-+.BI remote " IPADDR"
-+- specifies the unicast destination IP address to use in outgoing packets
-+when the destination link layer address is not known in the VXLAN device
-+forwarding database.  This parameter cannot be specified with the
-+.B group
-+parameter.
- 
- .sp
- .BI local " IPADDR"
--- 
-1.8.5.3
-
diff --git a/SOURCES/iproute2-3.10.0-Fix-changing-tunnel-remote-and-local-address-to-any.patch b/SOURCES/iproute2-3.10.0-Fix-changing-tunnel-remote-and-local-address-to-any.patch
new file mode 100644
index 0000000..755a924
--- /dev/null
+++ b/SOURCES/iproute2-3.10.0-Fix-changing-tunnel-remote-and-local-address-to-any.patch
@@ -0,0 +1,51 @@
+From b45db2060837990b05d2f8da28c1ba0217011439 Mon Sep 17 00:00:00 2001
+From: Thadeu Lima de Souza Cascardo <cascardo@redhat.com>
+Date: Thu, 4 Jun 2015 09:01:18 -0300
+Subject: [PATCH] Fix changing tunnel remote and local address to any
+
+If a tunnel is created with a local address, you can't change it to any.
+
+ # ip tunnel add tunl1 mode ipip remote 10.16.42.37 local 10.16.42.214 ttl 64
+ # ip tunnel show tunl1
+ tunl1: ip/ip  remote 10.16.42.37  local 10.16.42.214  ttl 64
+ # ip tunnel change tunl1 local any
+ # echo $?
+ 0
+ # ip tunnel show tunl1
+ tunl1: ip/ip  remote 10.16.42.37  local 10.16.42.214  ttl 64
+
+It happens that parse_args zeroes ip_tunnel_parm, and when creating the
+tunnel, it is OK to leave it as is if the address is any. However, when
+changing the tunnel, the current parameters will be read from
+ip_tunnel_parm, and local and remote address won't be zeroes anymore, so
+it needs to be explicitly set to any.
+
+Signed-off-by: Thadeu Lima de Souza Cascardo <cascardo@redhat.com>
+Acked-by: Nicolas Dichtel <nicolas.dichtel@6wind.com>
+(cherry picked from commit 4e4b78324f1dbcee590c01a7ac3e5ebaf20daa27)
+---
+ ip/iptunnel.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+diff --git a/ip/iptunnel.c b/ip/iptunnel.c
+index 43f8585..4c9c429 100644
+--- a/ip/iptunnel.c
++++ b/ip/iptunnel.c
+@@ -167,10 +167,14 @@ static int parse_args(int argc, char **argv, int cmd, struct ip_tunnel_parm *p)
+ 			NEXT_ARG();
+ 			if (strcmp(*argv, "any"))
+ 				p->iph.daddr = get_addr32(*argv);
++			else
++				p->iph.daddr = htonl(INADDR_ANY);
+ 		} else if (strcmp(*argv, "local") == 0) {
+ 			NEXT_ARG();
+ 			if (strcmp(*argv, "any"))
+ 				p->iph.saddr = get_addr32(*argv);
++			else
++				p->iph.saddr = htonl(INADDR_ANY);
+ 		} else if (strcmp(*argv, "dev") == 0) {
+ 			NEXT_ARG();
+ 			strncpy(medium, *argv, IFNAMSIZ-1);
+-- 
+1.8.3.1
+
diff --git a/SOURCES/iproute2-3.10.0-Fix-multiple-programming-errors.patch b/SOURCES/iproute2-3.10.0-Fix-multiple-programming-errors.patch
new file mode 100644
index 0000000..fb24eee
--- /dev/null
+++ b/SOURCES/iproute2-3.10.0-Fix-multiple-programming-errors.patch
@@ -0,0 +1,229 @@
+From 453eee90927d1c28951af40c3fd2c40365b07055 Mon Sep 17 00:00:00 2001
+From: Stephen Hemminger <shemming@brocade.com>
+Date: Wed, 12 Aug 2015 08:35:54 -0700
+Subject: [PATCH] Fix multiple programming errors
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+This is a combination of 8 commits:
+
+commit 2f29d6bb5089271988a820d1f9596f9973ee2e4d
+Author: Stephen Hemminger <shemming@brocade.com>
+Date:   Wed Aug 12 08:35:54 2015 -0700
+
+    ipnetns: make net namespace cache variable size
+
+    Save some space by using variable size for nsid cache elements.
+
+    Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
+
+commit e0dce0e5dc363b7e307984706c130f6ee769259b
+Author: Phil Sutter <phil@nwl.cc>
+Date:   Thu Aug 6 14:24:32 2015 +0200
+
+    misc/ss: avoid NULL pointer dereference
+
+    This was working before, but only if realloc a) succeeded and b) did not
+    move the buffer to a different location. ''**buf = **new_buf' then
+    writes the value of *new_buf's first field into that of *buf.
+
+    Signed-off-by: Phil Sutter <phil@nwl.cc>
+
+commit 532ca40a52d4103816f2e50690a02e9dd6c1abe5
+Author: Phil Sutter <phil@nwl.cc>
+Date:   Thu Aug 6 14:24:33 2015 +0200
+
+    misc/ss: simplify buffer realloc, fix checking realloc failure
+
+    Signed-off-by: Phil Sutter <phil@nwl.cc>
+
+commit b95d28c380c945ac760b128403dc82279cb9cc39
+Author: Phil Sutter <phil@nwl.cc>
+Date:   Thu Aug 6 14:24:34 2015 +0200
+
+    misc/ss: add missing fclose() calls
+
+    Signed-off-by: Phil Sutter <phil@nwl.cc>
+
+commit 5950ba914e12b9c942e45e2dda6b1732a3efa058
+Author: Phil Sutter <phil@nwl.cc>
+Date:   Thu Aug 6 14:24:35 2015 +0200
+
+    lib/namespace: don't leak fd in error case
+
+    Signed-off-by: Phil Sutter <phil@nwl.cc>
+
+commit a02371fb3831c8d3d9d53209f2389b250a1fb804
+Author: Phil Sutter <phil@nwl.cc>
+Date:   Thu Aug 6 14:24:36 2015 +0200
+
+    misc/ss: fix memory leak in user_ent_hash_build()
+
+    Signed-off-by: Phil Sutter <phil@nwl.cc>
+
+commit 9e5ba07f491037f51472915477575d3e3fe0adcb
+Author: Phil Sutter <phil@nwl.cc>
+Date:   Tue Aug 18 18:11:08 2015 +0200
+
+    lib/namespace: fix fd leakage in non-error case
+
+    My previous patch 5950ba9 ("lib/namespace: don't leak fd in error case")
+    was a step in the wrong direction. Instead of closing the opened file
+    descriptor in error case only, follow a better approach here and close
+    the fd as soon as it is not used anymore. This way the inelegant goto
+    statements can be dropped, and the fd leak in non-error case is fixed as
+    well.
+
+    Fixes: 5950ba9 ("lib/namespace: don't leak fd in error case")
+    Signed-off-by: Phil Sutter <phil@nwl.cc>
+
+commit b765eda924363caec99b760d8cff815ecf4a8de6
+Author: Nicolas Dichtel <nicolas.dichtel@6wind.com>
+Date:   Wed Apr 22 10:27:06 2015 +0200
+
+    libnamespaces: fix warning about syscall()
+
+    The warning was:
+    In file included from namespace.c:14:0:
+    ../include/namespace.h: In function ‘setns’:
+    ../include/namespace.h:37:2: warning: implicit declaration of function ‘syscall’ [-Wimplicit-function-declaration]
+
+    Signed-off-by: Nicolas Dichtel <nicolas.dichtel@6wind.com>
+---
+ include/namespace.h |  1 +
+ ip/ipnetns.c        |  6 +++---
+ lib/namespace.c     |  2 ++
+ misc/ss.c           | 17 +++++++++++------
+ 4 files changed, 17 insertions(+), 9 deletions(-)
+
+diff --git a/include/namespace.h b/include/namespace.h
+index a2ac7dc..5add9d2 100644
+--- a/include/namespace.h
++++ b/include/namespace.h
+@@ -3,6 +3,7 @@
+ 
+ #include <sched.h>
+ #include <sys/mount.h>
++#include <unistd.h>
+ #include <sys/syscall.h>
+ #include <errno.h>
+ 
+diff --git a/ip/ipnetns.c b/ip/ipnetns.c
+index 019f954..00b6cc4 100644
+--- a/ip/ipnetns.c
++++ b/ip/ipnetns.c
+@@ -140,7 +140,7 @@ struct nsid_cache {
+ 	struct hlist_node	nsid_hash;
+ 	struct hlist_node	name_hash;
+ 	int			nsid;
+-	char			name[NAME_MAX];
++	char			name[0];
+ };
+ 
+ #define NSIDMAP_SIZE		128
+@@ -165,7 +165,7 @@ static struct nsid_cache *netns_map_get_by_nsid(int nsid)
+ 	return NULL;
+ }
+ 
+-static int netns_map_add(int nsid, char *name)
++static int netns_map_add(int nsid, const char *name)
+ {
+ 	struct nsid_cache *c;
+ 	uint32_t h;
+@@ -173,7 +173,7 @@ static int netns_map_add(int nsid, char *name)
+ 	if (netns_map_get_by_nsid(nsid) != NULL)
+ 		return -EEXIST;
+ 
+-	c = malloc(sizeof(*c));
++	c = malloc(sizeof(*c) + strlen(name));
+ 	if (c == NULL) {
+ 		perror("malloc");
+ 		return -ENOMEM;
+diff --git a/lib/namespace.c b/lib/namespace.c
+index c03a103..0549916 100644
+--- a/lib/namespace.c
++++ b/lib/namespace.c
+@@ -57,8 +57,10 @@ int netns_switch(char *name)
+ 	if (setns(netns, CLONE_NEWNET) < 0) {
+ 		fprintf(stderr, "setting the network namespace \"%s\" failed: %s\n",
+ 			name, strerror(errno));
++		close(netns);
+ 		return -1;
+ 	}
++	close(netns);
+ 
+ 	if (unshare(CLONE_NEWNS) < 0) {
+ 		fprintf(stderr, "unshare failed: %s\n", strerror(errno));
+diff --git a/misc/ss.c b/misc/ss.c
+index 951e1eb..5d0cc36 100644
+--- a/misc/ss.c
++++ b/misc/ss.c
+@@ -474,8 +474,10 @@ static void user_ent_hash_build(void)
+ 
+ 		sprintf(name + nameoff, "%d/fd/", pid);
+ 		pos = strlen(name);
+-		if ((dir1 = opendir(name)) == NULL)
++		if ((dir1 = opendir(name)) == NULL) {
++			free(pid_context);
+ 			continue;
++		}
+ 
+ 		process[0] = '\0';
+ 		p = process;
+@@ -541,7 +543,7 @@ static int find_entry(unsigned ino, char **buf, int type)
+ 	struct user_ent *p;
+ 	int cnt = 0;
+ 	char *ptr;
+-	char **new_buf = buf;
++	char *new_buf;
+ 	int len, new_buf_len;
+ 	int buf_used = 0;
+ 	int buf_len = 0;
+@@ -583,12 +585,12 @@ static int find_entry(unsigned ino, char **buf, int type)
+ 
+ 			if (len < 0 || len >= buf_len - buf_used) {
+ 				new_buf_len = buf_len + ENTRY_BUF_SIZE;
+-				*new_buf = realloc(*buf, new_buf_len);
++				new_buf = realloc(*buf, new_buf_len);
+ 				if (!new_buf) {
+ 					fprintf(stderr, "ss: failed to malloc buffer\n");
+ 					abort();
+ 				}
+-				**buf = **new_buf;
++				*buf = new_buf;
+ 				buf_len = new_buf_len;
+ 				continue;
+ 			} else {
+@@ -2928,6 +2930,7 @@ static int packet_show_line(char *buf, const struct filter *f, int fam)
+ static int packet_show(struct filter *f)
+ {
+ 	FILE *fp;
++	int rc = 0;
+ 
+ 	if (!filter_af_get(f, AF_PACKET) || !(f->states & (1 << SS_CLOSE)))
+ 		return 0;
+@@ -2939,9 +2942,10 @@ static int packet_show(struct filter *f)
+ 	if ((fp = net_packet_open()) == NULL)
+ 		return -1;
+ 	if (generic_record_read(fp, packet_show_line, f, AF_PACKET))
+-		return -1;
++		rc = -1;
+ 
+-	return 0;
++	fclose(fp);
++	return rc;
+ }
+ 
+ static int netlink_show_one(struct filter *f,
+@@ -3118,6 +3122,7 @@ static int netlink_show(struct filter *f)
+ 		netlink_show_one(f, prot, pid, groups, 0, 0, 0, rq, wq, sk, cb);
+ 	}
+ 
++	fclose(fp);
+ 	return 0;
+ }
+ 
+-- 
+1.8.3.1
+
diff --git a/SOURCES/iproute2-3.10.0-Revert-Changes-for-BZ-1212026.patch b/SOURCES/iproute2-3.10.0-Revert-Changes-for-BZ-1212026.patch
new file mode 100644
index 0000000..4825a88
--- /dev/null
+++ b/SOURCES/iproute2-3.10.0-Revert-Changes-for-BZ-1212026.patch
@@ -0,0 +1,275 @@
+From ae646501d67a3c6e5078529f92339ffc87277cea Mon Sep 17 00:00:00 2001
+From: Phil Sutter <psutter@redhat.com>
+Date: Thu, 3 Sep 2015 13:02:02 +0200
+Subject: [PATCH] Revert Changes for BZ#1212026
+
+Kernel lacks support for it in RHEL7.2, delivering this would be inconsistent.
+
+This is a combination of 2 reverts:
+
+Revert "xfrm: add command for configuring SPD hash table"
+Revert "xfrm: revise man page and document ip xfrm policy set"
+---
+ ip/xfrm_policy.c   | 105 ++---------------------------------------------------
+ man/man8/ip-xfrm.8 |  61 +------------------------------
+ 2 files changed, 5 insertions(+), 161 deletions(-)
+
+diff --git a/ip/xfrm_policy.c b/ip/xfrm_policy.c
+index 9ac4a89..36e33c9 100644
+--- a/ip/xfrm_policy.c
++++ b/ip/xfrm_policy.c
+@@ -64,8 +64,7 @@ static void usage(void)
+ 	fprintf(stderr, "        [ index INDEX ] [ ptype PTYPE ] [ action ACTION ] [ priority PRIORITY ]\n");
+ 	fprintf(stderr, "        [ flag FLAG-LIST ]\n");
+ 	fprintf(stderr, "Usage: ip xfrm policy flush [ ptype PTYPE ]\n");
+-	fprintf(stderr, "Usage: ip xfrm policy count\n");
+-	fprintf(stderr, "Usage: ip xfrm policy set [ hthresh4 LBITS RBITS ] [ hthresh6 LBITS RBITS ]\n");
++	fprintf(stderr, "Usage: ip xfrm count\n");
+ 	fprintf(stderr, "SELECTOR := [ src ADDR[/PLEN] ] [ dst ADDR[/PLEN] ] [ dev DEV ] [ UPSPEC ]\n");
+ 	fprintf(stderr, "UPSPEC := proto { { ");
+ 	fprintf(stderr, "%s | ", strxf_proto(IPPROTO_TCP));
+@@ -936,7 +935,7 @@ static int print_spdinfo( struct nlmsghdr *n, void *arg)
+ 			fprintf(fp,")");
+ 		}
+ 
+-		fprintf(fp, "%s", _SL_);
++		fprintf(fp,"\n");
+ 	}
+ 	if (show_stats > 1) {
+ 		struct xfrmu_spdhinfo *sh;
+@@ -950,109 +949,13 @@ static int print_spdinfo( struct nlmsghdr *n, void *arg)
+ 			fprintf(fp,"\t SPD buckets:");
+ 			fprintf(fp," count %d", sh->spdhcnt);
+ 			fprintf(fp," Max %d", sh->spdhmcnt);
+-			fprintf(fp, "%s", _SL_);
+-		}
+-		if (tb[XFRMA_SPD_IPV4_HTHRESH]) {
+-			struct xfrmu_spdhthresh *th;
+-			if (RTA_PAYLOAD(tb[XFRMA_SPD_IPV4_HTHRESH]) < sizeof(*th)) {
+-				fprintf(stderr, "SPDinfo: Wrong len %d\n", len);
+-				return -1;
+-			}
+-			th = RTA_DATA(tb[XFRMA_SPD_IPV4_HTHRESH]);
+-			fprintf(fp,"\t SPD IPv4 thresholds:");
+-			fprintf(fp," local %d", th->lbits);
+-			fprintf(fp," remote %d", th->rbits);
+-			fprintf(fp, "%s", _SL_);
+-
+-		}
+-		if (tb[XFRMA_SPD_IPV6_HTHRESH]) {
+-			struct xfrmu_spdhthresh *th;
+-			if (RTA_PAYLOAD(tb[XFRMA_SPD_IPV6_HTHRESH]) < sizeof(*th)) {
+-				fprintf(stderr, "SPDinfo: Wrong len %d\n", len);
+-				return -1;
+-			}
+-			th = RTA_DATA(tb[XFRMA_SPD_IPV6_HTHRESH]);
+-			fprintf(fp,"\t SPD IPv6 thresholds:");
+-			fprintf(fp," local %d", th->lbits);
+-			fprintf(fp," remote %d", th->rbits);
+-			fprintf(fp, "%s", _SL_);
+ 		}
+ 	}
+-
+-	if (oneline)
+-		fprintf(fp, "\n");
++	fprintf(fp,"\n");
+ 
+         return 0;
+ }
+ 
+-static int xfrm_spd_setinfo(int argc, char **argv)
+-{
+-	struct rtnl_handle rth;
+-	struct {
+-		struct nlmsghdr			n;
+-		__u32				flags;
+-		char				buf[RTA_BUF_SIZE];
+-	} req;
+-
+-	char *thr4 = NULL;
+-	char *thr6 = NULL;
+-
+-	memset(&req, 0, sizeof(req));
+-
+-	req.n.nlmsg_len = NLMSG_LENGTH(sizeof(__u32));
+-	req.n.nlmsg_flags = NLM_F_REQUEST;
+-	req.n.nlmsg_type = XFRM_MSG_NEWSPDINFO;
+-	req.flags = 0XFFFFFFFF;
+-
+-	while (argc > 0) {
+-		if (strcmp(*argv, "hthresh4") == 0) {
+-			struct xfrmu_spdhthresh thr;
+-
+-			if (thr4)
+-				duparg("hthresh4", *argv);
+-			thr4 = *argv;
+-			NEXT_ARG();
+-			if (get_u8(&thr.lbits, *argv, 0) || thr.lbits > 32)
+-				invarg("hthresh4 LBITS value is invalid", *argv);
+-			NEXT_ARG();
+-			if (get_u8(&thr.rbits, *argv, 0) || thr.rbits > 32)
+-				invarg("hthresh4 RBITS value is invalid", *argv);
+-
+-			addattr_l(&req.n, sizeof(req), XFRMA_SPD_IPV4_HTHRESH,
+-				  (void *)&thr, sizeof(thr));
+-		} else if (strcmp(*argv, "hthresh6") == 0) {
+-			struct xfrmu_spdhthresh thr;
+-
+-			if (thr6)
+-				duparg("hthresh6", *argv);
+-			thr6 = *argv;
+-			NEXT_ARG();
+-			if (get_u8(&thr.lbits, *argv, 0) || thr.lbits > 128)
+-				invarg("hthresh6 LBITS value is invalid", *argv);
+-			NEXT_ARG();
+-			if (get_u8(&thr.rbits, *argv, 0) || thr.rbits > 128)
+-				invarg("hthresh6 RBITS value is invalid", *argv);
+-
+-			addattr_l(&req.n, sizeof(req), XFRMA_SPD_IPV6_HTHRESH,
+-				  (void *)&thr, sizeof(thr));
+-		} else {
+-			invarg("unknown", *argv);
+-		}
+-
+-		argc--; argv++;
+-	}
+-
+-	if (rtnl_open_byproto(&rth, 0, NETLINK_XFRM) < 0)
+-		exit(1);
+-
+-	if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0)
+-		exit(2);
+-
+-	rtnl_close(&rth);
+-
+-	return 0;
+-}
+-
+ static int xfrm_spd_getinfo(int argc, char **argv)
+ {
+ 	struct rtnl_handle rth;
+@@ -1156,8 +1059,6 @@ int do_xfrm_policy(int argc, char **argv)
+ 		return xfrm_policy_flush(argc-1, argv+1);
+ 	if (matches(*argv, "count") == 0)
+ 		return xfrm_spd_getinfo(argc, argv);
+-	if (matches(*argv, "set") == 0)
+-		return xfrm_spd_setinfo(argc-1, argv+1);
+ 	if (matches(*argv, "help") == 0)
+ 		usage();
+ 	fprintf(stderr, "Command \"%s\" is unknown, try \"ip xfrm policy help\".\n", *argv);
+diff --git a/man/man8/ip-xfrm.8 b/man/man8/ip-xfrm.8
+index aea4fda..3752c7e 100644
+--- a/man/man8/ip-xfrm.8
++++ b/man/man8/ip-xfrm.8
+@@ -252,13 +252,6 @@ ip-xfrm \- transform configuration
+ .B "ip xfrm policy count"
+ 
+ .ti -8
+-.B "ip xfrm policy set"
+-.RB "[ " hthresh4
+-.IR LBITS " " RBITS " ]"
+-.RB "[ " hthresh6
+-.IR LBITS " " RBITS " ]"
+-
+-.ti -8
+ .IR SELECTOR " :="
+ .RB "[ " src
+ .IR ADDR "[/" PLEN "] ]"
+@@ -366,13 +359,6 @@ ip-xfrm \- transform configuration
+  |
+ .IR LISTofXFRM-OBJECTS " ]"
+ 
+-.ti -8
+-.IR LISTofXFRM-OBJECTS " := [ " LISTofXFRM-OBJECTS " ] " XFRM-OBJECT
+-
+-.ti -8
+-.IR XFRM-OBJECT " := "
+-.BR acquire " | " expire " | " SA " | " policy " | " aevent " | " report
+-
+ .in -8
+ .ad b
+ 
+@@ -398,6 +384,7 @@ ip xfrm state deleteall	delete all existing state in xfrm
+ ip xfrm state list	print out the list of existing state in xfrm
+ ip xfrm state flush	flush all state in xfrm
+ ip xfrm state count	count all existing state in xfrm
++ip xfrm monitor 	state monitoring for xfrm objects
+ .TE
+ 
+ .TP
+@@ -519,9 +506,7 @@ encapsulates packets with protocol
+ .BR espinudp " or " espinudp-nonike ","
+ .RI "using source port " SPORT ", destination port "  DPORT
+ .RI ", and original address " OADDR "."
+-
+ .sp
+-.PP
+ .TS
+ l l.
+ ip xfrm policy add	add a new policy
+@@ -531,6 +516,7 @@ ip xfrm policy get	get an existing policy
+ ip xfrm policy deleteall	delete all existing xfrm policies
+ ip xfrm policy list	print out the list of xfrm policies
+ ip xfrm policy flush	flush policies
++ip xfrm policy count	count existing policies
+ .TE
+ 
+ .TP
+@@ -625,47 +611,6 @@ and inbound trigger
+ can be
+ .BR required " (default) or " use "."
+ 
+-.sp
+-.PP
+-.TS
+-l l.
+-ip xfrm policy count	count existing policies
+-.TE
+-
+-.PP
+-Use one or more -s options to display more details, including policy hash table
+-information.
+-
+-.sp
+-.PP
+-.TS
+-l l.
+-ip xfrm policy set	configure the policy hash table
+-.TE
+-
+-.PP
+-Security policies whose address prefix lengths are greater than or equal
+-policy hash table thresholds are hashed. Others are stored in the
+-policy_inexact chained list.
+-
+-.TP
+-.I LBITS
+-specifies the minimum local address prefix length of policies that are
+-stored in the Security Policy Database hash table.
+-
+-.TP
+-.I RBITS
+-specifies the minimum remote address prefix length of policies that are
+-stored in the Security Policy Database hash table.
+-
+-.sp
+-.PP
+-.TS
+-l l.
+-ip xfrm monitor 	state monitoring for xfrm objects
+-.TE
+-
+-.PP
+ The xfrm objects to monitor can be optionally specified.
+ 
+ .P
+@@ -684,6 +629,4 @@ originates. Example:
+ .SH AUTHOR
+ Manpage revised by David Ward <david.ward@ll.mit.edu>
+ .br
+-Manpage revised by Christophe Gouault <christophe.gouault@6wind.com>
+-.br
+ Manpage revised by Nicolas Dichtel <nicolas.dichtel@6wind.com>
+-- 
+1.8.3.1
+
diff --git a/SOURCES/iproute2-3.10.0-address.patch b/SOURCES/iproute2-3.10.0-address.patch
new file mode 100644
index 0000000..ed97476
--- /dev/null
+++ b/SOURCES/iproute2-3.10.0-address.patch
@@ -0,0 +1,1443 @@
+commit 9764c8d5063de9d76326f028fce66f6e4e49bb5a
+Author: Pavel Šimerda <psimerda@redhat.com>
+Date:   Thu May 28 12:17:39 2015 +0200
+
+    backport selected ip-link/ip-address features and documentation
+
+diff --git a/ip/ip.c b/ip/ip.c
+index 86f8b45..7f2c206 100644
+--- a/ip/ip.c
++++ b/ip/ip.c
+@@ -22,8 +22,11 @@
+ #include "SNAPSHOT.h"
+ #include "utils.h"
+ #include "ip_common.h"
++#include "namespace.h"
+ 
+ int preferred_family = AF_UNSPEC;
++int human_readable = 0;
++int use_iec = 0;
+ int show_stats = 0;
+ int show_details = 0;
+ int resolve_hosts = 0;
+@@ -33,6 +36,7 @@ char * _SL_ = NULL;
+ int force = 0;
+ int max_flush_loops = 10;
+ int batch_mode = 0;
++bool do_all = false;
+ 
+ struct rtnl_handle rth = { .fd = -1 };
+ 
+@@ -47,11 +51,12 @@ static void usage(void)
+ "                   tunnel | tuntap | maddr | mroute | mrule | monitor | xfrm |\n"
+ "                   netns | l2tp | tcp_metrics | token }\n"
+ "       OPTIONS := { -V[ersion] | -s[tatistics] | -d[etails] | -r[esolve] |\n"
++"                    -h[uman-readable] | -iec |\n"
+ "                    -f[amily] { inet | inet6 | ipx | dnet | bridge | link } |\n"
+ "                    -4 | -6 | -I | -D | -B | -0 |\n"
+ "                    -l[oops] { maximum-addr-flush-attempts } |\n"
+ "                    -o[neline] | -t[imestamp] | -b[atch] [filename] |\n"
+-"                    -rc[vbuf] [size]}\n");
++"                    -rc[vbuf] [size] | -n[etns] name | -a[ll] }\n");
+ 	exit(-1);
+ }
+ 
+@@ -65,7 +70,7 @@ static const struct cmd {
+ 	const char *cmd;
+ 	int (*func)(int argc, char **argv);
+ } cmds[] = {
+-	{ "address", 	do_ipaddr },
++	{ "address",	do_ipaddr },
+ 	{ "addrlabel",	do_ipaddrlabel },
+ 	{ "maddress",	do_multiaddr },
+ 	{ "route",	do_iproute },
+@@ -212,6 +217,11 @@ int main(int argc, char **argv)
+ 			preferred_family = AF_DECnet;
+ 		} else if (strcmp(opt, "-B") == 0) {
+ 			preferred_family = AF_BRIDGE;
++		} else if (matches(opt, "-human") == 0 ||
++			   matches(opt, "-human-readable") == 0) {
++			++human_readable;
++		} else if (matches(opt, "-iec") == 0) {
++			++use_iec;
+ 		} else if (matches(opt, "-stats") == 0 ||
+ 			   matches(opt, "-statistics") == 0) {
+ 			++show_stats;
+@@ -253,6 +263,12 @@ int main(int argc, char **argv)
+ 			rcvbuf = size;
+ 		} else if (matches(opt, "-help") == 0) {
+ 			usage();
++		} else if (matches(opt, "-netns") == 0) {
++			NEXT_ARG();
++			if (netns_switch(argv[1]))
++				exit(-1);
++		} else if (matches(opt, "-all") == 0) {
++			do_all = true;
+ 		} else {
+ 			fprintf(stderr, "Option \"%s\" is unknown, try \"ip -help\".\n", opt);
+ 			exit(-1);
+diff --git a/ip/ipaddress.c b/ip/ipaddress.c
+index 5b9a438..c99a078 100644
+--- a/ip/ipaddress.c
++++ b/ip/ipaddress.c
+@@ -28,6 +28,7 @@
+ #include <linux/netdevice.h>
+ #include <linux/if_arp.h>
+ #include <linux/sockios.h>
++#include <linux/net_namespace.h>
+ 
+ #include "rt_names.h"
+ #include "utils.h"
+@@ -69,7 +70,7 @@ static void usage(void)
+ 	}
+ 	fprintf(stderr, "Usage: ip addr {add|change|replace} IFADDR dev STRING [ LIFETIME ]\n");
+ 	fprintf(stderr, "                                                      [ CONFFLAG-LIST ]\n");
+-	fprintf(stderr, "       ip addr del IFADDR dev STRING\n");
++	fprintf(stderr, "       ip addr del IFADDR dev STRING [mngtmpaddr]\n");
+ 	fprintf(stderr, "       ip addr {show|save|flush} [ dev STRING ] [ scope SCOPE-ID ]\n");
+ 	fprintf(stderr, "                            [ to PREFIX ] [ FLAG-LIST ] [ label PATTERN ] [up]\n");
+ 	fprintf(stderr, "       ip addr {showdump|restore}\n");
+@@ -82,7 +83,7 @@ static void usage(void)
+ 	fprintf(stderr, "           tentative | deprecated | dadfailed | temporary |\n");
+ 	fprintf(stderr, "           CONFFLAG-LIST ]\n");
+ 	fprintf(stderr, "CONFFLAG-LIST := [ CONFFLAG-LIST ] CONFFLAG\n");
+-	fprintf(stderr, "CONFFLAG  := [ home | nodad ]\n");
++	fprintf(stderr, "CONFFLAG  := [ home | nodad | mngtmpaddr | noprefixroute ]\n");
+ 	fprintf(stderr, "LIFETIME := [ valid_lft LFT ] [ preferred_lft LFT ]\n");
+ 	fprintf(stderr, "LFT := forever | SECONDS\n");
+ 
+@@ -223,12 +224,36 @@ static void print_linktype(FILE *fp, struct rtattr *tb)
+ 	}
+ }
+ 
++static void print_af_spec(FILE *fp, struct rtattr *af_spec_attr)
++{
++	struct rtattr *inet6_attr;
++	struct rtattr *tb[IFLA_INET6_MAX + 1];
++
++	inet6_attr = parse_rtattr_one_nested(AF_INET6, af_spec_attr);
++	if (!inet6_attr)
++		return;
++
++	parse_rtattr_nested(tb, IFLA_INET6_MAX, inet6_attr);
++
++	if (tb[IFLA_INET6_ADDR_GEN_MODE]) {
++		switch (rta_getattr_u8(tb[IFLA_INET6_ADDR_GEN_MODE])) {
++		case IN6_ADDR_GEN_MODE_EUI64:
++			fprintf(fp, "addrgenmode eui64 ");
++			break;
++		case IN6_ADDR_GEN_MODE_NONE:
++			fprintf(fp, "addrgenmode none ");
++			break;
++		}
++	}
++}
++
+ static void print_vfinfo(FILE *fp, struct rtattr *vfinfo)
+ {
+ 	struct ifla_vf_mac *vf_mac;
+ 	struct ifla_vf_vlan *vf_vlan;
+ 	struct ifla_vf_tx_rate *vf_tx_rate;
+ 	struct ifla_vf_spoofchk *vf_spoofchk;
++	struct ifla_vf_link_state *vf_linkstate;
+ 	struct rtattr *vf[IFLA_VF_MAX+1];
+ 	struct rtattr *tmp;
+ 	SPRINT_BUF(b1);
+@@ -255,6 +280,20 @@ static void print_vfinfo(FILE *fp, struct rtattr *vfinfo)
+ 	else
+ 		vf_spoofchk = RTA_DATA(vf[IFLA_VF_SPOOFCHK]);
+ 
++	if (vf_spoofchk) {
++		/* Check if the link state vf info type is supported by
++		 * this kernel.
++		 */
++		tmp = (struct rtattr *)((char *)vf[IFLA_VF_SPOOFCHK] +
++				vf[IFLA_VF_SPOOFCHK]->rta_len);
++
++		if (tmp->rta_type != IFLA_VF_LINK_STATE)
++			vf_linkstate = NULL;
++		else
++			vf_linkstate = RTA_DATA(vf[IFLA_VF_LINK_STATE]);
++	} else
++		vf_linkstate = NULL;
++
+ 	fprintf(fp, "\n    vf %d MAC %s", vf_mac->vf,
+ 		ll_addr_n2a((unsigned char *)&vf_mac->mac,
+ 		ETH_ALEN, 0, b1, sizeof(b1)));
+@@ -270,99 +309,203 @@ static void print_vfinfo(FILE *fp, struct rtattr *vfinfo)
+ 		else
+ 			fprintf(fp, ", spoof checking off");
+ 	}
++	if (vf_linkstate) {
++		if (vf_linkstate->link_state == IFLA_VF_LINK_STATE_AUTO)
++			fprintf(fp, ", link-state auto");
++		else if (vf_linkstate->link_state == IFLA_VF_LINK_STATE_ENABLE)
++			fprintf(fp, ", link-state enable");
++		else
++			fprintf(fp, ", link-state disable");
++	}
+ }
+ 
+-static void print_link_stats64(FILE *fp, const struct rtnl_link_stats64 *s) {
+-	fprintf(fp, "%s", _SL_);
++static void print_num(FILE *fp, unsigned width, uint64_t count)
++{
++	const char *prefix = "kMGTPE";
++	const unsigned int base = use_iec ? 1024 : 1000;
++	uint64_t powi = 1;
++	uint16_t powj = 1;
++	uint8_t precision = 2;
++	char buf[64];
++
++	if (!human_readable || count < base) {
++		fprintf(fp, "%-*"PRIu64" ", width, count);
++		return;
++	}
++
++	/* increase value by a factor of 1000/1024 and print
++	 * if result is something a human can read */
++	for(;;) {
++		powi *= base;
++		if (count / base < powi)
++			break;
++
++		if (!prefix[1])
++			break;
++		++prefix;
++	}
++
++	/* try to guess a good number of digits for precision */
++	for (; precision > 0; precision--) {
++		powj *= 10;
++		if (count / powi < powj)
++			break;
++	}
++
++	snprintf(buf, sizeof(buf), "%.*f%c%s", precision,
++		(double) count / powi, *prefix, use_iec ? "i" : "");
++
++	fprintf(fp, "%-*s ", width, buf);
++}
++
++static void print_link_stats64(FILE *fp, const struct rtnl_link_stats64 *s,
++                               const struct rtattr *carrier_changes)
++{
++	/* RX stats */
+ 	fprintf(fp, "    RX: bytes  packets  errors  dropped overrun mcast   %s%s",
+ 		s->rx_compressed ? "compressed" : "", _SL_);
+-	fprintf(fp, "    %-10"PRIu64" %-8"PRIu64" %-7"PRIu64" %-7"PRIu64" %-7"PRIu64" %-7"PRIu64"",
+-		(uint64_t)s->rx_bytes,
+-		(uint64_t)s->rx_packets,
+-		(uint64_t)s->rx_errors,
+-		(uint64_t)s->rx_dropped,
+-		(uint64_t)s->rx_over_errors,
+-		(uint64_t)s->multicast);
++
++	fprintf(fp, "    ");
++	print_num(fp, 10, s->rx_bytes);
++	print_num(fp, 8, s->rx_packets);
++	print_num(fp, 7, s->rx_errors);
++	print_num(fp, 7, s->rx_dropped);
++	print_num(fp, 7, s->rx_over_errors);
++	print_num(fp, 7, s->multicast);
+ 	if (s->rx_compressed)
+-		fprintf(fp, " %-7"PRIu64"",
+-			(uint64_t)s->rx_compressed);
++		print_num(fp, 7, s->rx_compressed);
++
++	/* RX error stats */
+ 	if (show_stats > 1) {
+ 		fprintf(fp, "%s", _SL_);
+-		fprintf(fp, "    RX errors: length  crc     frame   fifo    missed%s", _SL_);
+-		fprintf(fp, "               %-7"PRIu64"  %-7"PRIu64" %-7"PRIu64" %-7"PRIu64" %-7"PRIu64"",
+-			(uint64_t)s->rx_length_errors,
+-			(uint64_t)s->rx_crc_errors,
+-			(uint64_t)s->rx_frame_errors,
+-			(uint64_t)s->rx_fifo_errors,
+-			(uint64_t)s->rx_missed_errors);
++		fprintf(fp, "    RX errors: length   crc     frame   fifo    missed%s", _SL_);
++
++		fprintf(fp, "               ");
++		print_num(fp, 8, s->rx_length_errors);
++		print_num(fp, 7, s->rx_crc_errors);
++		print_num(fp, 7, s->rx_frame_errors);
++		print_num(fp, 7, s->rx_fifo_errors);
++		print_num(fp, 7, s->rx_missed_errors);
+ 	}
+ 	fprintf(fp, "%s", _SL_);
++
++	/* TX stats */
+ 	fprintf(fp, "    TX: bytes  packets  errors  dropped carrier collsns %s%s",
+-		(uint64_t)s->tx_compressed ? "compressed" : "", _SL_);
+-	fprintf(fp, "    %-10"PRIu64" %-8"PRIu64" %-7"PRIu64" %-7"PRIu64" %-7"PRIu64" %-7"PRIu64"",
+-		(uint64_t)s->tx_bytes,
+-		(uint64_t)s->tx_packets,
+-		(uint64_t)s->tx_errors,
+-		(uint64_t)s->tx_dropped,
+-		(uint64_t)s->tx_carrier_errors,
+-		(uint64_t)s->collisions);
++		s->tx_compressed ? "compressed" : "", _SL_);
++
++
++	fprintf(fp, "    ");
++	print_num(fp, 10, s->tx_bytes);
++	print_num(fp, 8, s->tx_packets);
++	print_num(fp, 7, s->tx_errors);
++	print_num(fp, 7, s->tx_dropped);
++	print_num(fp, 7, s->tx_carrier_errors);
++	print_num(fp, 7, s->collisions);
+ 	if (s->tx_compressed)
+-		fprintf(fp, " %-7"PRIu64"",
+-			(uint64_t)s->tx_compressed);
++		print_num(fp, 7, s->tx_compressed);
++
++	/* TX error stats */
+ 	if (show_stats > 1) {
+ 		fprintf(fp, "%s", _SL_);
+-		fprintf(fp, "    TX errors: aborted fifo    window  heartbeat%s", _SL_);
+-		fprintf(fp, "               %-7"PRIu64"  %-7"PRIu64" %-7"PRIu64" %-7"PRIu64"",
+-			(uint64_t)s->tx_aborted_errors,
+-			(uint64_t)s->tx_fifo_errors,
+-			(uint64_t)s->tx_window_errors,
+-			(uint64_t)s->tx_heartbeat_errors);
++		fprintf(fp, "    TX errors: aborted  fifo   window heartbeat");
++                if (carrier_changes)
++			fprintf(fp, " transns");
++		fprintf(fp, "%s", _SL_);
++
++		fprintf(fp, "               ");
++		print_num(fp, 8, s->tx_aborted_errors);
++		print_num(fp, 7, s->tx_fifo_errors);
++		print_num(fp, 7, s->tx_window_errors);
++		print_num(fp, 7, s->tx_heartbeat_errors);
++		if (carrier_changes)
++			print_num(fp, 7, *(uint32_t*)RTA_DATA(carrier_changes));
+ 	}
+ }
+ 
+-static void print_link_stats(FILE *fp, const struct rtnl_link_stats *s)
++static void print_link_stats32(FILE *fp, const struct rtnl_link_stats *s,
++			       const struct rtattr *carrier_changes)
+ {
+-	fprintf(fp, "%s", _SL_);
++	/* RX stats */
+ 	fprintf(fp, "    RX: bytes  packets  errors  dropped overrun mcast   %s%s",
+ 		s->rx_compressed ? "compressed" : "", _SL_);
+-	fprintf(fp, "    %-10u %-8u %-7u %-7u %-7u %-7u",
+-		s->rx_bytes, s->rx_packets, s->rx_errors,
+-		s->rx_dropped, s->rx_over_errors,
+-		s->multicast
+-		);
++
++
++	fprintf(fp, "    ");
++	print_num(fp, 10, s->rx_bytes);
++	print_num(fp, 8, s->rx_packets);
++	print_num(fp, 7, s->rx_errors);
++	print_num(fp, 7, s->rx_dropped);
++	print_num(fp, 7, s->rx_over_errors);
++	print_num(fp, 7, s->multicast);
+ 	if (s->rx_compressed)
+-		fprintf(fp, " %-7u", s->rx_compressed);
++		print_num(fp, 7, s->rx_compressed);
++
++	/* RX error stats */
+ 	if (show_stats > 1) {
+ 		fprintf(fp, "%s", _SL_);
+-		fprintf(fp, "    RX errors: length  crc     frame   fifo    missed%s", _SL_);
+-		fprintf(fp, "               %-7u  %-7u %-7u %-7u %-7u",
+-			s->rx_length_errors,
+-			s->rx_crc_errors,
+-			s->rx_frame_errors,
+-			s->rx_fifo_errors,
+-			s->rx_missed_errors
+-			);
++		fprintf(fp, "    RX errors: length   crc     frame   fifo    missed%s", _SL_);
++		fprintf(fp, "               ");
++		print_num(fp, 8, s->rx_length_errors);
++		print_num(fp, 7, s->rx_crc_errors);
++		print_num(fp, 7, s->rx_frame_errors);
++		print_num(fp, 7, s->rx_fifo_errors);
++		print_num(fp, 7, s->rx_missed_errors);
+ 	}
+ 	fprintf(fp, "%s", _SL_);
++
++	/* TX stats */
+ 	fprintf(fp, "    TX: bytes  packets  errors  dropped carrier collsns %s%s",
+ 		s->tx_compressed ? "compressed" : "", _SL_);
+-	fprintf(fp, "    %-10u %-8u %-7u %-7u %-7u %-7u",
+-		s->tx_bytes, s->tx_packets, s->tx_errors,
+-		s->tx_dropped, s->tx_carrier_errors, s->collisions);
++
++	fprintf(fp, "    ");
++	print_num(fp, 10, s->tx_bytes);
++	print_num(fp, 8, s->tx_packets);
++	print_num(fp, 7, s->tx_errors);
++	print_num(fp, 7, s->tx_dropped);
++	print_num(fp, 7, s->tx_carrier_errors);
++	print_num(fp, 7, s->collisions);
+ 	if (s->tx_compressed)
+-		fprintf(fp, " %-7u", s->tx_compressed);
++		print_num(fp, 7, s->tx_compressed);
++
++	/* TX error stats */
+ 	if (show_stats > 1) {
+ 		fprintf(fp, "%s", _SL_);
+-		fprintf(fp, "    TX errors: aborted fifo    window  heartbeat%s", _SL_);
+-		fprintf(fp, "               %-7u  %-7u %-7u %-7u",
+-			s->tx_aborted_errors,
+-			s->tx_fifo_errors,
+-			s->tx_window_errors,
+-			s->tx_heartbeat_errors
+-			);
++		fprintf(fp, "    TX errors: aborted  fifo   window heartbeat");
++                if (carrier_changes)
++			fprintf(fp, " transns");
++		fprintf(fp, "%s", _SL_);
++
++		fprintf(fp, "               ");
++		print_num(fp, 8, s->tx_aborted_errors);
++		print_num(fp, 7, s->tx_fifo_errors);
++		print_num(fp, 7, s->tx_window_errors);
++		print_num(fp, 7, s->tx_heartbeat_errors);
++		if (carrier_changes)
++			print_num(fp, 7, *(uint32_t*)RTA_DATA(carrier_changes));
+ 	}
+ }
+ 
++static void __print_link_stats(FILE *fp, struct rtattr **tb)
++{
++	if (tb[IFLA_STATS64])
++		print_link_stats64(fp, RTA_DATA(tb[IFLA_STATS64]),
++					tb[IFLA_CARRIER_CHANGES]);
++	else if (tb[IFLA_STATS])
++		print_link_stats32(fp, RTA_DATA(tb[IFLA_STATS]),
++					tb[IFLA_CARRIER_CHANGES]);
++}
++
++static void print_link_stats(FILE *fp, struct nlmsghdr *n)
++{
++	struct ifinfomsg *ifi = NLMSG_DATA(n);
++	struct rtattr * tb[IFLA_MAX+1];
++
++	parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi),
++		     n->nlmsg_len - NLMSG_LENGTH(sizeof(*ifi)));
++	__print_link_stats(fp, tb);
++	fprintf(fp, "%s", _SL_);
++}
++
+ int print_linkinfo(const struct sockaddr_nl *who,
+ 		   struct nlmsghdr *n, void *arg)
+ {
+@@ -411,9 +554,13 @@ int print_linkinfo(const struct sockaddr_nl *who,
+ 		if (iflink == 0)
+ 			fprintf(fp, "@NONE: ");
+ 		else {
+-			fprintf(fp, "@%s: ", ll_idx_n2a(iflink, b1));
+-			m_flag = ll_index_to_flags(iflink);
+-			m_flag = !(m_flag & IFF_UP);
++			if (tb[IFLA_LINK_NETNSID])
++				fprintf(fp, "@if%d: ", iflink);
++			else {
++				fprintf(fp, "@%s: ", ll_idx_n2a(iflink, b1));
++				m_flag = ll_index_to_flags(iflink);
++				m_flag = !(m_flag & IFF_UP);
++			}
+ 		}
+ 	} else {
+ 		fprintf(fp, ": ");
+@@ -461,26 +608,36 @@ int print_linkinfo(const struct sockaddr_nl *who,
+ 		}
+ 	}
+ 
+-	if (do_link && tb[IFLA_PROMISCUITY] && show_details)
++	if (tb[IFLA_LINK_NETNSID]) {
++		int id = *(int*)RTA_DATA(tb[IFLA_LINK_NETNSID]);
++
++		if (id >= 0)
++			fprintf(fp, " link-netnsid %d", id);
++		else
++			fprintf(fp, " link-netnsid unknown");
++	}
++
++	if (tb[IFLA_PROMISCUITY] && show_details)
+ 		fprintf(fp, " promiscuity %u ",
+ 			*(int*)RTA_DATA(tb[IFLA_PROMISCUITY]));
+ 
+-	if (do_link && tb[IFLA_LINKINFO] && show_details)
++	if (tb[IFLA_LINKINFO] && show_details)
+ 		print_linktype(fp, tb[IFLA_LINKINFO]);
+ 
+-	if (do_link && tb[IFLA_IFALIAS]) {
++	if (do_link && tb[IFLA_AF_SPEC] && show_details)
++		print_af_spec(fp, tb[IFLA_AF_SPEC]);
++
++	if ((do_link || show_details) && tb[IFLA_IFALIAS]) {
+ 		fprintf(fp, "%s    alias %s", _SL_,
+ 			rta_getattr_str(tb[IFLA_IFALIAS]));
+ 	}
+ 
+ 	if (do_link && show_stats) {
+-		if (tb[IFLA_STATS64])
+-			print_link_stats64(fp, RTA_DATA(tb[IFLA_STATS64]));
+-		else if (tb[IFLA_STATS])
+-			print_link_stats(fp, RTA_DATA(tb[IFLA_STATS]));
++		fprintf(fp, "%s", _SL_);
++		__print_link_stats(fp, tb);
+ 	}
+ 
+-	if (do_link && tb[IFLA_VFINFO_LIST] && tb[IFLA_NUM_VF]) {
++	if ((do_link || show_details) && tb[IFLA_VFINFO_LIST] && tb[IFLA_NUM_VF]) {
+ 		struct rtattr *i, *vflist = tb[IFLA_VFINFO_LIST];
+ 		int rem = RTA_PAYLOAD(vflist);
+ 		for (i = RTA_DATA(vflist); RTA_OK(i, rem); i = RTA_NEXT(i, rem))
+@@ -489,7 +646,7 @@ int print_linkinfo(const struct sockaddr_nl *who,
+ 
+ 	fprintf(fp, "\n");
+ 	fflush(fp);
+-	return 0;
++	return 1;
+ }
+ 
+ static int flush_update(void)
+@@ -512,10 +669,17 @@ static int set_lifetime(unsigned int *lifetime, char *argv)
+ 	return 0;
+ }
+ 
++static unsigned int get_ifa_flags(struct ifaddrmsg *ifa,
++				  struct rtattr *ifa_flags_attr)
++{
++	return ifa_flags_attr ? rta_getattr_u32(ifa_flags_attr) :
++				ifa->ifa_flags;
++}
++
+ int print_addrinfo(const struct sockaddr_nl *who, struct nlmsghdr *n,
+ 		   void *arg)
+ {
+-	FILE *fp = (FILE*)arg;
++	FILE *fp = arg;
+ 	struct ifaddrmsg *ifa = NLMSG_DATA(n);
+ 	int len = n->nlmsg_len;
+ 	int deprecated = 0;
+@@ -536,7 +700,10 @@ int print_addrinfo(const struct sockaddr_nl *who, struct nlmsghdr *n,
+ 	if (filter.flushb && n->nlmsg_type != RTM_NEWADDR)
+ 		return 0;
+ 
+-	parse_rtattr(rta_tb, IFA_MAX, IFA_RTA(ifa), n->nlmsg_len - NLMSG_LENGTH(sizeof(*ifa)));
++	parse_rtattr(rta_tb, IFA_MAX, IFA_RTA(ifa),
++		     n->nlmsg_len - NLMSG_LENGTH(sizeof(*ifa)));
++
++	ifa_flags = get_ifa_flags(ifa, rta_tb[IFA_FLAGS]);
+ 
+ 	if (!rta_tb[IFA_LOCAL])
+ 		rta_tb[IFA_LOCAL] = rta_tb[IFA_ADDRESS];
+@@ -547,7 +714,7 @@ int print_addrinfo(const struct sockaddr_nl *who, struct nlmsghdr *n,
+ 		return 0;
+ 	if ((filter.scope^ifa->ifa_scope)&filter.scopemask)
+ 		return 0;
+-	if ((filter.flags^ifa->ifa_flags)&filter.flagmask)
++	if ((filter.flags ^ ifa_flags) & filter.flagmask)
+ 		return 0;
+ 	if (filter.label) {
+ 		SPRINT_BUF(b1);
+@@ -613,7 +780,8 @@ int print_addrinfo(const struct sockaddr_nl *who, struct nlmsghdr *n,
+ 					      abuf, sizeof(abuf)));
+ 
+ 		if (rta_tb[IFA_ADDRESS] == NULL ||
+-		    memcmp(RTA_DATA(rta_tb[IFA_ADDRESS]), RTA_DATA(rta_tb[IFA_LOCAL]), 4) == 0) {
++		    memcmp(RTA_DATA(rta_tb[IFA_ADDRESS]), RTA_DATA(rta_tb[IFA_LOCAL]),
++			   ifa->ifa_family == AF_INET ? 4 : 16) == 0) {
+ 			fprintf(fp, "/%d ", ifa->ifa_prefixlen);
+ 		} else {
+ 			fprintf(fp, " peer %s/%d ",
+@@ -640,36 +808,43 @@ int print_addrinfo(const struct sockaddr_nl *who, struct nlmsghdr *n,
+ 				    abuf, sizeof(abuf)));
+ 	}
+ 	fprintf(fp, "scope %s ", rtnl_rtscope_n2a(ifa->ifa_scope, b1, sizeof(b1)));
+-	ifa_flags = ifa->ifa_flags;
+-	if (ifa->ifa_flags&IFA_F_SECONDARY) {
++	if (ifa_flags & IFA_F_SECONDARY) {
+ 		ifa_flags &= ~IFA_F_SECONDARY;
+ 		if (ifa->ifa_family == AF_INET6)
+ 			fprintf(fp, "temporary ");
+ 		else
+ 			fprintf(fp, "secondary ");
+ 	}
+-	if (ifa->ifa_flags&IFA_F_TENTATIVE) {
++	if (ifa_flags & IFA_F_TENTATIVE) {
+ 		ifa_flags &= ~IFA_F_TENTATIVE;
+ 		fprintf(fp, "tentative ");
+ 	}
+-	if (ifa->ifa_flags&IFA_F_DEPRECATED) {
++	if (ifa_flags & IFA_F_DEPRECATED) {
+ 		ifa_flags &= ~IFA_F_DEPRECATED;
+ 		deprecated = 1;
+ 		fprintf(fp, "deprecated ");
+ 	}
+-	if (ifa->ifa_flags&IFA_F_HOMEADDRESS) {
++	if (ifa_flags & IFA_F_HOMEADDRESS) {
+ 		ifa_flags &= ~IFA_F_HOMEADDRESS;
+ 		fprintf(fp, "home ");
+ 	}
+-	if (ifa->ifa_flags&IFA_F_NODAD) {
++	if (ifa_flags & IFA_F_NODAD) {
+ 		ifa_flags &= ~IFA_F_NODAD;
+ 		fprintf(fp, "nodad ");
+ 	}
+-	if (!(ifa->ifa_flags&IFA_F_PERMANENT)) {
++	if (ifa_flags & IFA_F_MANAGETEMPADDR) {
++		ifa_flags &= ~IFA_F_MANAGETEMPADDR;
++		fprintf(fp, "mngtmpaddr ");
++	}
++	if (ifa_flags & IFA_F_NOPREFIXROUTE) {
++		ifa_flags &= ~IFA_F_NOPREFIXROUTE;
++		fprintf(fp, "noprefixroute ");
++	}
++	if (!(ifa_flags & IFA_F_PERMANENT)) {
+ 		fprintf(fp, "dynamic ");
+ 	} else
+ 		ifa_flags &= ~IFA_F_PERMANENT;
+-	if (ifa->ifa_flags&IFA_F_DADFAILED) {
++	if (ifa_flags & IFA_F_DADFAILED) {
+ 		ifa_flags &= ~IFA_F_DADFAILED;
+ 		fprintf(fp, "dadfailed ");
+ 	}
+@@ -896,6 +1071,8 @@ static void ipaddr_filter(struct nlmsg_chain *linfo, struct nlmsg_chain *ainfo)
+ 		for (a = ainfo->head; a; a = a->next) {
+ 			struct nlmsghdr *n = &a->h;
+ 			struct ifaddrmsg *ifa = NLMSG_DATA(n);
++			struct rtattr *tb[IFA_MAX + 1];
++			unsigned int ifa_flags;
+ 
+ 			if (ifa->ifa_index != ifi->ifi_index)
+ 				continue;
+@@ -904,11 +1081,13 @@ static void ipaddr_filter(struct nlmsg_chain *linfo, struct nlmsg_chain *ainfo)
+ 				continue;
+ 			if ((filter.scope^ifa->ifa_scope)&filter.scopemask)
+ 				continue;
+-			if ((filter.flags^ifa->ifa_flags)&filter.flagmask)
++
++			parse_rtattr(tb, IFA_MAX, IFA_RTA(ifa), IFA_PAYLOAD(n));
++			ifa_flags = get_ifa_flags(ifa, tb[IFA_FLAGS]);
++
++			if ((filter.flags ^ ifa_flags) & filter.flagmask)
+ 				continue;
+ 			if (filter.pfx.family || filter.label) {
+-				struct rtattr *tb[IFA_MAX+1];
+-				parse_rtattr(tb, IFA_MAX, IFA_RTA(ifa), IFA_PAYLOAD(n));
+ 				if (!tb[IFA_LOCAL])
+ 					tb[IFA_LOCAL] = tb[IFA_ADDRESS];
+ 
+@@ -1084,6 +1263,12 @@ static int ipaddr_list_flush_or_save(int argc, char **argv, int action)
+ 		} else if (strcmp(*argv, "nodad") == 0) {
+ 			filter.flags |= IFA_F_NODAD;
+ 			filter.flagmask |= IFA_F_NODAD;
++		} else if (strcmp(*argv, "mngtmpaddr") == 0) {
++			filter.flags |= IFA_F_MANAGETEMPADDR;
++			filter.flagmask |= IFA_F_MANAGETEMPADDR;
++		} else if (strcmp(*argv, "noprefixroute") == 0) {
++			filter.flags |= IFA_F_NOPREFIXROUTE;
++			filter.flagmask |= IFA_F_NOPREFIXROUTE;
+ 		} else if (strcmp(*argv, "dadfailed") == 0) {
+ 			filter.flags |= IFA_F_DADFAILED;
+ 			filter.flagmask |= IFA_F_DADFAILED;
+@@ -1163,11 +1348,15 @@ static int ipaddr_list_flush_or_save(int argc, char **argv, int action)
+ 	}
+ 
+ 	for (l = linfo.head; l; l = l->next) {
+-		if (no_link || print_linkinfo(NULL, &l->h, stdout) == 0) {
++		int res = 0;
++
++		if (no_link || (res = print_linkinfo(NULL, &l->h, stdout)) >= 0) {
+ 			struct ifinfomsg *ifi = NLMSG_DATA(&l->h);
+ 			if (filter.family != AF_PACKET)
+ 				print_selected_addrinfo(ifi->ifi_index,
+ 							ainfo.head, stdout);
++			if (res > 0 && !do_link && show_stats)
++				print_link_stats(stdout, &l->h);
+ 		}
+ 	}
+ 	fflush(stdout);
+@@ -1222,6 +1411,7 @@ static int ipaddr_modify(int cmd, int flags, int argc, char **argv)
+ 	__u32 preferred_lft = INFINITY_LIFE_TIME;
+ 	__u32 valid_lft = INFINITY_LIFE_TIME;
+ 	struct ifa_cacheinfo cinfo;
++	unsigned int ifa_flags = 0;
+ 
+ 	memset(&req, 0, sizeof(req));
+ 
+@@ -1299,9 +1489,13 @@ static int ipaddr_modify(int cmd, int flags, int argc, char **argv)
+ 			if (set_lifetime(&preferred_lft, *argv))
+ 				invarg("preferred_lft value", *argv);
+ 		} else if (strcmp(*argv, "home") == 0) {
+-			req.ifa.ifa_flags |= IFA_F_HOMEADDRESS;
++			ifa_flags |= IFA_F_HOMEADDRESS;
+ 		} else if (strcmp(*argv, "nodad") == 0) {
+-			req.ifa.ifa_flags |= IFA_F_NODAD;
++			ifa_flags |= IFA_F_NODAD;
++		} else if (strcmp(*argv, "mngtmpaddr") == 0) {
++			ifa_flags |= IFA_F_MANAGETEMPADDR;
++		} else if (strcmp(*argv, "noprefixroute") == 0) {
++			ifa_flags |= IFA_F_NOPREFIXROUTE;
+ 		} else {
+ 			if (strcmp(*argv, "local") == 0) {
+ 				NEXT_ARG();
+@@ -1319,6 +1513,11 @@ static int ipaddr_modify(int cmd, int flags, int argc, char **argv)
+ 		}
+ 		argc--; argv++;
+ 	}
++	if (ifa_flags <= 0xff)
++		req.ifa.ifa_flags = ifa_flags;
++	else
++		addattr32(&req.n, sizeof(req), IFA_FLAGS, ifa_flags);
++
+ 	if (d == NULL) {
+ 		fprintf(stderr, "Not enough information: \"dev\" argument is required.\n");
+ 		return -1;
+diff --git a/ip/iplink.c b/ip/iplink.c
+index dc98019..e17d5df 100644
+--- a/ip/iplink.c
++++ b/ip/iplink.c
+@@ -31,6 +31,7 @@
+ #include "rt_names.h"
+ #include "utils.h"
+ #include "ip_common.h"
++#include "namespace.h"
+ 
+ #define IPLINK_IOCTL_COMPAT	1
+ #ifndef LIBDIR
+@@ -70,6 +71,7 @@ void iplink_usage(void)
+ 	fprintf(stderr, "	                  [ mtu MTU ]\n");
+ 	fprintf(stderr, "	                  [ netns PID ]\n");
+ 	fprintf(stderr, "	                  [ netns NAME ]\n");
++	fprintf(stderr, "	                  [ link-netnsid ID ]\n");
+ 	fprintf(stderr, "			  [ alias NAME ]\n");
+ 	fprintf(stderr, "	                  [ vf NUM [ mac LLADDR ]\n");
+ 	fprintf(stderr, "				   [ vlan VLANID [ qos VLAN-QOS ] ]\n");
+@@ -77,8 +79,11 @@ void iplink_usage(void)
+ 	fprintf(stderr, "				   [ rate TXRATE ] ] \n");
+ 
+ 	fprintf(stderr, "				   [ spoofchk { on | off} ] ] \n");
++	fprintf(stderr, "				   [ query_rss { on | off} ] ] \n");
++	fprintf(stderr, "				   [ state { auto | enable | disable} ] ]\n");
+ 	fprintf(stderr, "			  [ master DEVICE ]\n");
+ 	fprintf(stderr, "			  [ nomaster ]\n");
++	fprintf(stderr, "			  [ addrgenmode { eui64 | none } ]\n");
+ 	fprintf(stderr, "       ip link show [ DEVICE | group GROUP ] [up]\n");
+ 
+ 	if (iplink_have_newlink()) {
+@@ -144,6 +149,15 @@ static int get_link_mode(const char *mode)
+ 	return -1;
+ }
+ 
++static int get_addr_gen_mode(const char *mode)
++{
++	if (strcasecmp(mode, "eui64") == 0)
++		return IN6_ADDR_GEN_MODE_EUI64;
++	if (strcasecmp(mode, "none") == 0)
++		return IN6_ADDR_GEN_MODE_NONE;
++	return -1;
++}
++
+ #if IPLINK_IOCTL_COMPAT
+ static int have_rtnl_newlink = -1;
+ 
+@@ -176,8 +190,13 @@ static int iplink_have_newlink(void)
+ 		req.n.nlmsg_type = RTM_NEWLINK;
+ 		req.i.ifi_family = AF_UNSPEC;
+ 
+-		rtnl_send(&rth, &req.n, req.n.nlmsg_len);
+-		rtnl_listen(&rth, accept_msg, NULL);
++		if (rtnl_send(&rth, &req.n, req.n.nlmsg_len) < 0) {
++			perror("Could not check for "
++				"link configuration over netlink support");
++			have_rtnl_newlink = 0;
++		} else {
++			rtnl_listen(&rth, accept_msg, NULL);
++		}
+ 	}
+ 	return have_rtnl_newlink;
+ }
+@@ -254,7 +273,44 @@ static int iplink_parse_vf(int vf, int *argcp, char ***argvp,
+ 				invarg("Invalid \"spoofchk\" value\n", *argv);
+ 			ivs.vf = vf;
+ 			addattr_l(&req->n, sizeof(*req), IFLA_VF_SPOOFCHK, &ivs, sizeof(ivs));
++		} else if (matches(*argv, "state") == 0) {
++			struct ifla_vf_link_state ivl;
++			NEXT_ARG();
++			if (matches(*argv, "auto") == 0)
++				ivl.link_state = IFLA_VF_LINK_STATE_AUTO;
++			else if (matches(*argv, "enable") == 0)
++				ivl.link_state = IFLA_VF_LINK_STATE_ENABLE;
++			else if (matches(*argv, "disable") == 0)
++				ivl.link_state = IFLA_VF_LINK_STATE_DISABLE;
++			else
++				invarg("Invalid \"state\" value\n", *argv);
++			ivl.vf = vf;
++			addattr_l(&req->n, sizeof(*req), IFLA_VF_LINK_STATE, &ivl, sizeof(ivl));
++		} else if (matches(*argv, "query_rss") == 0) {
++			struct ifla_vf_rss_query_en ivs;
++			NEXT_ARG();
++			if (matches(*argv, "on") == 0)
++				ivs.setting = 1;
++			else if (matches(*argv, "off") == 0)
++				ivs.setting = 0;
++			else
++				invarg("Invalid \"query_rss\" value\n", *argv);
++			ivs.vf = vf;
++			addattr_l(&req->n, sizeof(*req), IFLA_VF_RSS_QUERY_EN, &ivs, sizeof(ivs));
+ 
++		} else if (matches(*argv, "state") == 0) {
++			struct ifla_vf_link_state ivl;
++			NEXT_ARG();
++			if (matches(*argv, "auto") == 0)
++				ivl.link_state = IFLA_VF_LINK_STATE_AUTO;
++			else if (matches(*argv, "enable") == 0)
++				ivl.link_state = IFLA_VF_LINK_STATE_ENABLE;
++			else if (matches(*argv, "disable") == 0)
++				ivl.link_state = IFLA_VF_LINK_STATE_DISABLE;
++			else
++				invarg("Invalid \"state\" value\n", *argv);
++			ivl.vf = vf;
++			addattr_l(&req->n, sizeof(*req), IFLA_VF_LINK_STATE, &ivl, sizeof(ivl));
+ 		} else {
+ 			/* rewind arg */
+ 			PREV_ARG();
+@@ -284,6 +340,7 @@ int iplink_parse(int argc, char **argv, struct iplink_req *req,
+ 	int vf = -1;
+ 	int numtxqueues = -1;
+ 	int numrxqueues = -1;
++	int link_netnsid = -1;
+ 
+ 	*group = -1;
+ 	ret = argc;
+@@ -334,7 +391,7 @@ int iplink_parse(int argc, char **argv, struct iplink_req *req,
+ 			NEXT_ARG();
+ 			if (netns != -1)
+ 				duparg("netns", *argv);
+-			if ((netns = get_netns_fd(*argv)) >= 0)
++			if ((netns = netns_get_fd(*argv)) >= 0)
+ 				addattr_l(&req->n, sizeof(*req), IFLA_NET_NS_FD, &netns, 4);
+ 			else if (get_integer(&netns, *argv, 0) == 0)
+ 				addattr_l(&req->n, sizeof(*req), IFLA_NET_NS_PID, &netns, 4);
+@@ -466,6 +523,26 @@ int iplink_parse(int argc, char **argv, struct iplink_req *req,
+ 				invarg("Invalid \"numrxqueues\" value\n", *argv);
+ 			addattr_l(&req->n, sizeof(*req), IFLA_NUM_RX_QUEUES,
+ 				  &numrxqueues, 4);
++		} else if (matches(*argv, "addrgenmode") == 0) {
++			struct rtattr *afs, *afs6;
++			int mode;
++			NEXT_ARG();
++			mode = get_addr_gen_mode(*argv);
++			if (mode < 0)
++				invarg("Invalid address generation mode\n", *argv);
++			afs = addattr_nest(&req->n, sizeof(*req), IFLA_AF_SPEC);
++			afs6 = addattr_nest(&req->n, sizeof(*req), AF_INET6);
++			addattr8(&req->n, sizeof(*req), IFLA_INET6_ADDR_GEN_MODE, mode);
++			addattr_nest_end(&req->n, afs6);
++			addattr_nest_end(&req->n, afs);
++		} else if (matches(*argv, "link-netnsid") == 0) {
++			NEXT_ARG();
++			if (link_netnsid != -1)
++				duparg("link-netnsid", *argv);
++			if (get_integer(&link_netnsid, *argv, 0))
++				invarg("Invalid \"link-netnsid\" value\n", *argv);
++			addattr32(&req->n, sizeof(*req), IFLA_LINK_NETNSID,
++				  link_netnsid);
+ 		} else {
+ 			if (strcmp(*argv, "dev") == 0) {
+ 				NEXT_ARG();
+diff --git a/ip/iplink_vxlan.c b/ip/iplink_vxlan.c
+index 1025326..43b8abc 100644
+--- a/ip/iplink_vxlan.c
++++ b/ip/iplink_vxlan.c
+@@ -23,11 +23,12 @@
+ 
+ static void explain(void)
+ {
+-	fprintf(stderr, "Usage: ... vxlan id VNI [ group ADDR ] [ local ADDR ]\n");
++	fprintf(stderr, "Usage: ... vxlan id VNI [ { group | remote } ADDR ] [ local ADDR ]\n");
+ 	fprintf(stderr, "                 [ ttl TTL ] [ tos TOS ] [ dev PHYS_DEV ]\n");
+-	fprintf(stderr, "                 [ port MIN MAX ] [ [no]learning ]\n");
+-	fprintf(stderr, "                 [ [no]proxy ] [ [no]rsc ]\n");
++	fprintf(stderr, "                 [ dstport PORT ] [ srcport MIN MAX ]\n");
++	fprintf(stderr, "                 [ [no]learning ] [ [no]proxy ] [ [no]rsc ]\n");
+ 	fprintf(stderr, "                 [ [no]l2miss ] [ [no]l3miss ]\n");
++	fprintf(stderr, "                 [ gbp ]\n");
+ 	fprintf(stderr, "\n");
+ 	fprintf(stderr, "Where: VNI := 0-16777215\n");
+ 	fprintf(stderr, "       ADDR := { IP_ADDRESS | any }\n");
+@@ -42,6 +43,10 @@ static int vxlan_parse_opt(struct link_util *lu, int argc, char **argv,
+ 	int vni_set = 0;
+ 	__u32 saddr = 0;
+ 	__u32 gaddr = 0;
++	__u32 daddr = 0;
++	struct in6_addr saddr6 = IN6ADDR_ANY_INIT;
++	struct in6_addr gaddr6 = IN6ADDR_ANY_INIT;
++	struct in6_addr daddr6 = IN6ADDR_ANY_INIT;
+ 	unsigned link = 0;
+ 	__u8 tos = 0;
+ 	__u8 ttl = 0;
+@@ -53,6 +58,12 @@ static int vxlan_parse_opt(struct link_util *lu, int argc, char **argv,
+ 	__u8 noage = 0;
+ 	__u32 age = 0;
+ 	__u32 maxaddr = 0;
++	__u16 dstport = 0;
++	__u8 gbp = 0;
++	__u8 udpcsum = 0;
++	__u8 udp6zerocsumtx = 0;
++	__u8 udp6zerocsumrx = 0;
++	int dst_port_set = 0;
+ 	struct ifla_vxlan_port_range range = { 0, 0 };
+ 
+ 	while (argc > 0) {
+@@ -65,15 +76,30 @@ static int vxlan_parse_opt(struct link_util *lu, int argc, char **argv,
+ 			vni_set = 1;
+ 		} else if (!matches(*argv, "group")) {
+ 			NEXT_ARG();
+-			gaddr = get_addr32(*argv);
+-
+-			if (!IN_MULTICAST(ntohl(gaddr)))
+-				invarg("invald group address", *argv);
++			if (!inet_get_addr(*argv, &gaddr, &gaddr6)) {
++				fprintf(stderr, "Invalid address \"%s\"\n", *argv);
++				return -1;
++			}
++			if (!IN6_IS_ADDR_MULTICAST(&gaddr6) && !IN_MULTICAST(ntohl(gaddr)))
++				invarg("invalid group address", *argv);
++		} else if (!matches(*argv, "remote")) {
++			NEXT_ARG();
++			if (!inet_get_addr(*argv, &daddr, &daddr6)) {
++				fprintf(stderr, "Invalid address \"%s\"\n", *argv);
++				return -1;
++			}
++			if (IN6_IS_ADDR_MULTICAST(&daddr6) || IN_MULTICAST(ntohl(daddr)))
++				invarg("invalid remote address", *argv);
+ 		} else if (!matches(*argv, "local")) {
+ 			NEXT_ARG();
+-			if (strcmp(*argv, "any"))
+-				saddr = get_addr32(*argv);
+-			if (IN_MULTICAST(ntohl(saddr)))
++			if (strcmp(*argv, "any")) {
++				if (!inet_get_addr(*argv, &saddr, &saddr6)) {
++					fprintf(stderr, "Invalid address \"%s\"\n", *argv);
++					return -1;
++				}
++			}
++
++			if (IN_MULTICAST(ntohl(saddr)) || IN6_IS_ADDR_MULTICAST(&saddr6))
+ 				invarg("invalid local address", *argv);
+ 		} else if (!matches(*argv, "dev")) {
+ 			NEXT_ARG();
+@@ -115,7 +141,8 @@ static int vxlan_parse_opt(struct link_util *lu, int argc, char **argv,
+ 				maxaddr = 0;
+ 			else if (get_u32(&maxaddr, *argv, 0))
+ 				invarg("max addresses", *argv);
+-		} else if (!matches(*argv, "port")) {
++		} else if (!matches(*argv, "port") ||
++			   !matches(*argv, "srcport")) {
+ 			__u16 minport, maxport;
+ 			NEXT_ARG();
+ 			if (get_u16(&minport, *argv, 0))
+@@ -125,6 +152,11 @@ static int vxlan_parse_opt(struct link_util *lu, int argc, char **argv,
+ 				invarg("max port", *argv);
+ 			range.low = htons(minport);
+ 			range.high = htons(maxport);
++		} else if (!matches(*argv, "dstport")){
++			NEXT_ARG();
++			if (get_u16(&dstport, *argv, 0))
++				invarg("dst port", *argv);
++			dst_port_set = 1;
+ 		} else if (!matches(*argv, "nolearning")) {
+ 			learning = 0;
+ 		} else if (!matches(*argv, "learning")) {
+@@ -145,6 +177,20 @@ static int vxlan_parse_opt(struct link_util *lu, int argc, char **argv,
+ 			l3miss = 0;
+ 		} else if (!matches(*argv, "l3miss")) {
+ 			l3miss = 1;
++		} else if (!matches(*argv, "gbp")) {
++			gbp = 1;
++		} else if (!matches(*argv, "udpcsum")) {
++			udpcsum = 1;
++		} else if (!matches(*argv, "noudpcsum")) {
++			udpcsum = 0;
++		} else if (!matches(*argv, "udp6zerocsumtx")) {
++			udp6zerocsumtx = 1;
++		} else if (!matches(*argv, "noudp6zerocsumtx")) {
++			udp6zerocsumtx = 0;
++		} else if (!matches(*argv, "udp6zerocsumrx")) {
++			udp6zerocsumrx = 1;
++		} else if (!matches(*argv, "noudp6zerocsumrx")) {
++			udp6zerocsumrx = 0;
+ 		} else if (matches(*argv, "help") == 0) {
+ 			explain();
+ 			return -1;
+@@ -160,11 +206,35 @@ static int vxlan_parse_opt(struct link_util *lu, int argc, char **argv,
+ 		fprintf(stderr, "vxlan: missing virtual network identifier\n");
+ 		return -1;
+ 	}
++
++	if (!dst_port_set) {
++		fprintf(stderr, "vxlan: destination port not specified\n"
++			"Will use Linux kernel default (non-standard value)\n");
++		fprintf(stderr,
++			"Use 'dstport 4789' to get the IANA assigned value\n"
++			"Use 'dstport 0' to get default and quiet this message\n");
++	}
++	if ((gaddr && daddr) ||
++		(memcmp(&gaddr6, &in6addr_any, sizeof(gaddr6)) &&
++		 memcmp(&daddr6, &in6addr_any, sizeof(daddr6)))) {
++		fprintf(stderr, "vxlan: both group and remote cannot be specified\n");
++		return -1;
++	}
+ 	addattr32(n, 1024, IFLA_VXLAN_ID, vni);
+ 	if (gaddr)
+ 		addattr_l(n, 1024, IFLA_VXLAN_GROUP, &gaddr, 4);
++	else if (daddr)
++		addattr_l(n, 1024, IFLA_VXLAN_GROUP, &daddr, 4);
++	if (memcmp(&gaddr6, &in6addr_any, sizeof(gaddr6)) != 0)
++		addattr_l(n, 1024, IFLA_VXLAN_GROUP6, &gaddr6, sizeof(struct in6_addr));
++	else if (memcmp(&daddr6, &in6addr_any, sizeof(daddr6)) != 0)
++		addattr_l(n, 1024, IFLA_VXLAN_GROUP6, &daddr6, sizeof(struct in6_addr));
++
+ 	if (saddr)
+ 		addattr_l(n, 1024, IFLA_VXLAN_LOCAL, &saddr, 4);
++	else if (memcmp(&saddr6, &in6addr_any, sizeof(saddr6)) != 0)
++		addattr_l(n, 1024, IFLA_VXLAN_LOCAL6, &saddr6, sizeof(struct in6_addr));
++
+ 	if (link)
+ 		addattr32(n, 1024, IFLA_VXLAN_LINK, link);
+ 	addattr8(n, 1024, IFLA_VXLAN_TTL, ttl);
+@@ -174,6 +244,10 @@ static int vxlan_parse_opt(struct link_util *lu, int argc, char **argv,
+ 	addattr8(n, 1024, IFLA_VXLAN_RSC, rsc);
+ 	addattr8(n, 1024, IFLA_VXLAN_L2MISS, l2miss);
+ 	addattr8(n, 1024, IFLA_VXLAN_L3MISS, l3miss);
++	addattr8(n, 1024, IFLA_VXLAN_UDP_CSUM, udpcsum);
++	addattr8(n, 1024, IFLA_VXLAN_UDP_ZERO_CSUM6_TX, udp6zerocsumtx);
++	addattr8(n, 1024, IFLA_VXLAN_UDP_ZERO_CSUM6_RX, udp6zerocsumrx);
++
+ 	if (noage)
+ 		addattr32(n, 1024, IFLA_VXLAN_AGEING, 0);
+ 	else if (age)
+@@ -184,6 +258,13 @@ static int vxlan_parse_opt(struct link_util *lu, int argc, char **argv,
+ 		addattr_l(n, 1024, IFLA_VXLAN_PORT_RANGE,
+ 			  &range, sizeof(range));
+ 
++	if (dstport)
++		addattr16(n, 1024, IFLA_VXLAN_PORT, htons(dstport));
++
++	if (gbp)
++		addattr_l(n, 1024, IFLA_VXLAN_GBP, NULL, 0);
++
++
+ 	return 0;
+ }
+ 
+@@ -208,9 +289,25 @@ static void vxlan_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
+ 
+ 	if (tb[IFLA_VXLAN_GROUP]) {
+ 		__be32 addr = rta_getattr_u32(tb[IFLA_VXLAN_GROUP]);
+-		if (addr)
+-			fprintf(f, "group %s ",
+-				format_host(AF_INET, 4, &addr, s1, sizeof(s1)));
++		if (addr) {
++			if (IN_MULTICAST(ntohl(addr)))
++				fprintf(f, "group %s ",
++					format_host(AF_INET, 4, &addr, s1, sizeof(s1)));
++			else
++				fprintf(f, "remote %s ",
++					format_host(AF_INET, 4, &addr, s1, sizeof(s1)));
++		}
++	} else if (tb[IFLA_VXLAN_GROUP6]) {
++		struct in6_addr addr;
++		memcpy(&addr, RTA_DATA(tb[IFLA_VXLAN_GROUP6]), sizeof(struct in6_addr));
++		if (memcmp(&addr, &in6addr_any, sizeof(addr)) != 0) {
++			if (IN6_IS_ADDR_MULTICAST(&addr))
++				fprintf(f, "group %s ",
++					format_host(AF_INET6, sizeof(struct in6_addr), &addr, s1, sizeof(s1)));
++			else
++				fprintf(f, "remote %s ",
++					format_host(AF_INET6, sizeof(struct in6_addr), &addr, s1, sizeof(s1)));
++		}
+ 	}
+ 
+ 	if (tb[IFLA_VXLAN_LOCAL]) {
+@@ -218,6 +315,12 @@ static void vxlan_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
+ 		if (addr)
+ 			fprintf(f, "local %s ",
+ 				format_host(AF_INET, 4, &addr, s1, sizeof(s1)));
++	} else if (tb[IFLA_VXLAN_LOCAL6]) {
++		struct in6_addr addr;
++		memcpy(&addr, RTA_DATA(tb[IFLA_VXLAN_LOCAL6]), sizeof(struct in6_addr));
++		if (memcmp(&addr, &in6addr_any, sizeof(addr)) != 0)
++			fprintf(f, "local %s ",
++				format_host(AF_INET6, sizeof(struct in6_addr), &addr, s1, sizeof(s1)));
+ 	}
+ 
+ 	if (tb[IFLA_VXLAN_LINK] &&
+@@ -233,9 +336,13 @@ static void vxlan_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
+ 	if (tb[IFLA_VXLAN_PORT_RANGE]) {
+ 		const struct ifla_vxlan_port_range *r
+ 			= RTA_DATA(tb[IFLA_VXLAN_PORT_RANGE]);
+-		fprintf(f, "port %u %u ", ntohs(r->low), ntohs(r->high));
++		fprintf(f, "srcport %u %u ", ntohs(r->low), ntohs(r->high));
+ 	}
+ 
++	if (tb[IFLA_VXLAN_PORT])
++		fprintf(f, "dstport %u ",
++			ntohs(rta_getattr_u16(tb[IFLA_VXLAN_PORT])));
++
+ 	if (tb[IFLA_VXLAN_LEARNING] &&
+ 	    !rta_getattr_u8(tb[IFLA_VXLAN_LEARNING]))
+ 		fputs("nolearning ", f);
+@@ -277,6 +384,20 @@ static void vxlan_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
+ 	if (tb[IFLA_VXLAN_LIMIT] &&
+ 	    (maxaddr = rta_getattr_u32(tb[IFLA_VXLAN_LIMIT]) != 0))
+ 		    fprintf(f, "maxaddr %u ", maxaddr);
++
++	if (tb[IFLA_VXLAN_UDP_CSUM] && rta_getattr_u8(tb[IFLA_VXLAN_UDP_CSUM]))
++		fputs("udpcsum ", f);
++
++	if (tb[IFLA_VXLAN_UDP_ZERO_CSUM6_TX] &&
++	    rta_getattr_u8(tb[IFLA_VXLAN_UDP_ZERO_CSUM6_TX]))
++		fputs("udp6zerocsumtx ", f);
++
++	if (tb[IFLA_VXLAN_UDP_ZERO_CSUM6_RX] &&
++	    rta_getattr_u8(tb[IFLA_VXLAN_UDP_ZERO_CSUM6_RX]))
++		fputs("udp6zerocsumrx ", f);
++
++	if (tb[IFLA_VXLAN_GBP])
++		fputs("gbp ", f);
+ }
+ 
+ struct link_util vxlan_link_util = {
+diff --git a/lib/libnetlink.c b/lib/libnetlink.c
+index 9e2a795..baac6ae 100644
+--- a/lib/libnetlink.c
++++ b/lib/libnetlink.c
+@@ -701,6 +701,18 @@ int parse_rtattr_byindex(struct rtattr *tb[], int max, struct rtattr *rta, int l
+ 	return i;
+ }
+ 
++struct rtattr *parse_rtattr_one(int type, struct rtattr *rta, int len)
++{
++	while (RTA_OK(rta, len)) {
++		if (rta->rta_type == type)
++			return rta;
++		rta = RTA_NEXT(rta, len);
++	}
++	if (len)
++		fprintf(stderr, "!!!Deficit %d, rta_len=%d\n", len, rta->rta_len);
++	return NULL;
++}
++
+ int __parse_rtattr_nested_compat(struct rtattr *tb[], int max, struct rtattr *rta,
+ 			         int len)
+ {
+diff --git a/man/man8/ip-link.8.in b/man/man8/ip-link.8.in
+index 86e0bc9..a015b82 100644
+--- a/man/man8/ip-link.8.in
++++ b/man/man8/ip-link.8.in
+@@ -16,6 +16,7 @@ ip-link \- network device configuration
+ .ti -8
+ .IR OPTIONS " := { "
+ \fB\-V\fR[\fIersion\fR] |
++\fB\-h\fR[\fIuman-readable\fR] |
+ \fB\-s\fR[\fItatistics\fR] |
+ \fB\-r\fR[\fIesolve\fR] |
+ \fB\-f\fR[\fIamily\fR] {
+@@ -120,9 +121,11 @@ ip-link \- network device configuration
+ ] |
+ .br
+ .B master
+-.IR DEVICE
++.IR DEVICE " |"
+ .br
+-.B nomaster
++.B nomaster " |"
++.br
++.B addrgenmode { eui64 | none }
+ .BR " }"
+ 
+ 
+@@ -197,6 +200,65 @@ specifies the number of transmit queues for new device.
+ specifies the number of receive queues for new device.
+ 
+ .TP
++VLAN Type Support
++For a link of type
++.I VLAN
++the following additional arguments are supported:
++
++.BI "ip link add link " DEVICE
++.BI name " NAME "
++.BI type " vlan "
++.R " [ "
++.BI protocol " VLAN_PROTO "
++.R " ] "
++.BI id " VLANID "
++.R " [ "
++.BR reorder_hdr " { " on " | " off " } "
++.R " ] "
++.R " [ "
++.BR gvrp " { " on " | " off " } "
++.R " ] "
++.R " [ "
++.BR mvrp " { " on " | " off " } "
++.R " ] "
++.R " [ "
++.BR loose_binding " { " on " | " off " } "
++.R " ] "
++.R " [ "
++.BI ingress-qos-map " QOS-MAP "
++.R " ] "
++.R " [ "
++.BI egress-qos-map " QOS-MAP "
++.R " ] "
++
++.in +8
++.sp
++.BI protocol " VLAN_PROTO "
++- either 802.1Q or 802.1ad.
++
++.BI id " VLANID "
++- specifies the VID.
++
++.BR reorder_hdr " { " on " | " off " } "
++- specifies whether ethernet headers are reordered or not.
++
++.BR gvrp " { " on " | " off " } "
++- specifies whether this VLAN should be registered using GARP VLAN Registration Protocol.
++
++.BR mvrp " { " on " | " off " } "
++- specifies whether this VLAN should be registered using Multiple VLAN Registration Protocol.
++
++.BR loose_binding " { " on " | " off " } "
++- specifies whether the VLAN device state is bound to the physical device state.
++
++.BI ingress-qos-map " QOS-MAP "
++- defines a mapping between priority code points on incoming frames.  The format is FROM:TO with multiple mappings separated by spaces.
++
++.BI egress-qos-map " QOS-MAP "
++- the same as ingress-qos-map but for outgoing frames.
++.in -8
++
++.TP
+ VXLAN Type Support
+ For a link of type 
+ .I VXLAN
+@@ -206,8 +268,8 @@ the following additional arguments are supported:
+ .BI type " vxlan " id " ID
+ .R " [ "
+ .BI dev " PHYS_DEV "
+-.R " ] [ "
+-.BI group " IPADDR "
++.RB " ] [ { " group " | " remote " } "
++.I IPADDR
+ .R " ] [ "
+ .BI local " IPADDR "
+ .R " ] [ "
+@@ -226,6 +288,8 @@ the following additional arguments are supported:
+ .I "[no]l2miss "
+ .R " ] [ "
+ .I "[no]l3miss "
++.R " ] [ "
++.B gbp
+ .R " ]"
+ 
+ .in +8
+@@ -240,6 +304,17 @@ Identifier) to use.
+ .sp
+ .BI group " IPADDR"
+ - specifies the multicast IP address to join.
++This parameter cannot be specified with the
++.B remote
++parameter.
++
++.sp
++.BI remote " IPADDR"
++- specifies the unicast destination IP address to use in outgoing packets
++when the destination link layer address is not known in the VXLAN device
++forwarding database.  This parameter cannot be specified with the
++.B group
++parameter.
+ 
+ .sp
+ .BI local " IPADDR"
+@@ -279,6 +354,49 @@ are entered into the VXLAN device forwarding database.
+ .I [no]l3miss
+ - specifies if netlink IP ADDR miss notifications are generated.
+ 
++.sp
++.B gbp
++- enables the Group Policy extension (VXLAN-GBP).
++
++.in +4
++Allows to transport group policy context across VXLAN network peers.
++If enabled, includes the mark of a packet in the VXLAN header for outgoing
++packets and fills the packet mark based on the information found in the
++VXLAN header for incomming packets.
++
++Format of upper 16 bits of packet mark (flags);
++
++.in +2
+++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
++.br
++|-|-|-|-|-|-|-|-|-|D|-|-|A|-|-|-|
++.br
+++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
++
++.B D :=
++Don't Learn bit. When set, this bit indicates that the egress
++VTEP MUST NOT learn the source address of the encapsulated frame.
++
++.B A :=
++Indicates that the group policy has already been applied to
++this packet. Policies MUST NOT be applied by devices when the A bit is set.
++.in -2
++
++Format of lower 16 bits of packet mark (policy ID):
++
++.in +2
+++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
++.br
++|        Group Policy ID        |
++.br
+++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
++.in -2
++
++Example:
++  iptables -A OUTPUT [...] -j MARK --set-mark 0x800FF
++
++.in -4
++
+ .in -8
+ 
+ .SS ip link delete - delete virtual link
+@@ -366,14 +484,29 @@ the interface is
+ .IR "POINTOPOINT" .
+ 
+ .TP
+-.BI netns " PID"
+-move the device to the network namespace associated with the process
+-.IR "PID".
+-
+-.TP
+-.BI netns " NETNSNAME"
++.BI netns " NETNSNAME " \fR| " PID"
+ move the device to the network namespace associated with name
+-.IR "NETNSNAME".
++.IR "NETNSNAME " or
++.RI process " PID".
++
++Some devices are not allowed to change network namespace: loopback, bridge,
++ppp, wireless. These are network namespace local devices. In such case
++.B ip
++tool will return "Invalid argument" error. It is possible to find out if device is local
++to a single network namespace by checking
++.B netns-local
++flag in the output of the
++.BR ethtool ":"
++
++.in +8
++.B ethtool -k
++.I DEVICE
++.in -8
++
++To change network namespace for wireless devices the
++.B iw
++tool can be used. But it allows to change network namespace only for physical devices and by process
++.IR PID .
+ 
+ .TP
+ .BI alias " NAME"
+@@ -442,6 +575,10 @@ set master device of the device (enslave device).
+ .BI nomaster
+ unset master device of the device (release device).
+ 
++.TP
++.BR "addrgenmode eui64 " or " addrgenmode none"
++allow to ipv6 set address generation mode
++
+ .PP
+ .B Warning:
+ If multiple parameter changes are requested,
+@@ -471,6 +608,27 @@ specifies what group of devices to show.
+ .B up
+ only display running interfaces.
+ 
++.TP
++The show command has additional formatting options:
++
++.RS
++.TP
++.BR "\-s" , " \-stats", " \-statistics"
++output more statistics about packet usage.
++
++.TP
++.BR "\-d", " \-details"
++output more detailed information.
++
++.TP
++.BR "\-h", " \-human", " \-human-readble"
++output statistics with human readable values number followed by suffix
++
++.TP
++.BR "\-iec"
++print human readable rates in IEC units (ie. 1K = 1024).
++.RE
++
+ .SH "EXAMPLES"
+ .PP
+ ip link show
+@@ -495,7 +653,8 @@ Removes vlan device.
+ 
+ .SH SEE ALSO
+ .br
+-.BR ip (8)
++.BR ip (8),
++.BR ip-netns (8)
+ 
+ .SH AUTHOR
+ Original Manpage by Michail Litvak <mci@owl.openwall.com>
+diff --git a/man/man8/ip.8 b/man/man8/ip.8
+index 9065b3a..0713756 100644
+--- a/man/man8/ip.8
++++ b/man/man8/ip.8
+@@ -31,7 +31,8 @@ ip \- show / manipulate routing, devices, policy routing and tunnels
+ \fB\-r\fR[\fIesolve\fR] |
+ \fB\-f\fR[\fIamily\fR] {
+ .BR inet " | " inet6 " | " ipx " | " dnet " | " link " } | "
+-\fB\-o\fR[\fIneline\fR] }
++\fB\-o\fR[\fIneline\fR] |
++\fB\-n\fR[\fIetns\fR] name }
+ 
+ 
+ .SH OPTIONS
+@@ -130,6 +131,26 @@ the output.
+ use the system's name resolver to print DNS names instead of
+ host addresses.
+ 
++.TP
++.BR "\-n" , " \-net" , " \-netns " <NETNS>
++switches
++.B ip
++to the specified network namespace
++.IR NETNS .
++Actually it just simplifies executing of:
++
++.B ip netns exec
++.IR NETNS
++.B ip
++.RI "[ " OPTIONS " ] " OBJECT " { " COMMAND " | "
++.BR help " }"
++
++to
++
++.B ip
++.RI "-n[etns] " NETNS " [ " OPTIONS " ] " OBJECT " { " COMMAND " | "
++.BR help " }"
++
+ .SH IP - COMMAND SYNTAX
+ 
+ .SS
diff --git a/SOURCES/iproute2-3.10.0-backport-additional-INET_DIAG-flags-in-inet_diag.h.patch b/SOURCES/iproute2-3.10.0-backport-additional-INET_DIAG-flags-in-inet_diag.h.patch
new file mode 100644
index 0000000..3cee455
--- /dev/null
+++ b/SOURCES/iproute2-3.10.0-backport-additional-INET_DIAG-flags-in-inet_diag.h.patch
@@ -0,0 +1,29 @@
+From da2469f770c19421ed5bbc575f76abd7f3affc10 Mon Sep 17 00:00:00 2001
+From: Phil Sutter <psutter@redhat.com>
+Date: Sun, 2 Aug 2015 07:29:09 -0400
+Subject: [PATCH 1/2] backport additional INET_DIAG flags in inet_diag.h
+
+---
+ include/linux/inet_diag.h | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/include/linux/inet_diag.h b/include/linux/inet_diag.h
+index 7438dad..f1d4b59 100644
+--- a/include/linux/inet_diag.h
++++ b/include/linux/inet_diag.h
+@@ -111,9 +111,11 @@ enum {
+ 	INET_DIAG_SKMEMINFO,
+ 	INET_DIAG_SHUTDOWN,
+ 	INET_DIAG_DCTCPINFO,
++	INET_DIAG_PROTOCOL,  /* response attribute only */
++	INET_DIAG_SKV6ONLY,
+ };
+ 
+-#define INET_DIAG_MAX INET_DIAG_DCTCPINFO
++#define INET_DIAG_MAX INET_DIAG_SKV6ONLY
+ 
+ /* INET_DIAG_MEM */
+ 
+-- 
+1.8.3.1
+
diff --git a/SOURCES/iproute2-3.10.0-bridge-Add-master-device-name-to-bridge-fdb-show.patch b/SOURCES/iproute2-3.10.0-bridge-Add-master-device-name-to-bridge-fdb-show.patch
new file mode 100644
index 0000000..e3b55b5
--- /dev/null
+++ b/SOURCES/iproute2-3.10.0-bridge-Add-master-device-name-to-bridge-fdb-show.patch
@@ -0,0 +1,68 @@
+From 52296b5871435812cb2a05bcc3166968e170d783 Mon Sep 17 00:00:00 2001
+From: Roopa Prabhu <roopa@cumulusnetworks.com>
+Date: Sat, 7 Jun 2014 22:23:42 -0700
+Subject: [PATCH] bridge: Add master device name to bridge fdb show
+
+This patch adds master dev name from NDA_MASTER netlink attribute
+ to bridge fdb show output
+
+current iproute2 tries to print 'master' in the output if NTF_MASTER
+is present. But, kernel today does not set NTF_MASTER during dump
+requests. Which means I have not seen iproute2 bridge cmd print 'master' atall.
+This patch overrides the NTF_MASTER flag if NDA_MASTER attribute is present.
+
+Example output:
+
+before this patch:
+# bridge fdb show
+44:38:39:00:27:ba dev bond2.2003 permanent
+44:38:39:00:27:bb dev bond4.2003 permanent
+44:38:39:00:27:bc dev bond2.2004 permanent
+
+After this patch:
+# bridge fdb show
+44:38:39:00:27:ba dev bond2.2003 master br-2003 permanent
+44:38:39:00:27:bb dev bond4.2003 master br-2003 permanent
+44:38:39:00:27:bc dev bond2.2004 master br-2004 permanent
+
+For comparision with the above, below is the output for NTF_SELF today,
+# bridge fdb show
+33:33:00:00:00:01 dev eth0 self permanent
+01:00:5e:00:00:01 dev eth0 self permanent
+33:33:ff:00:01:cc dev eth0 self permanent
+
+If change in output is a concern, 'master' can be put at the end of the fdb
+output line or made optional with -d[etails] option.
+
+change from v1 to v2:
+    use 'bridge' instead of 'master' in fdb show output
+
+change from v2 to v3:
+    use 'master' instead of 'bridge' in fdb show output
+    (master could also be a vxlan device)
+
+Signed-off-by: Wilson Kok <wkok@cumulusnetworks.com>
+Signed-off-by: Roopa Prabhu <roopa@cumulusnetworks.com>
+---
+ bridge/fdb.c | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+diff --git a/bridge/fdb.c b/bridge/fdb.c
+index f725012..615541e 100644
+--- a/bridge/fdb.c
++++ b/bridge/fdb.c
+@@ -145,7 +145,10 @@ int print_fdb(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
+ 	}
+ 	if (r->ndm_flags & NTF_SELF)
+ 		fprintf(fp, "self ");
+-	if (r->ndm_flags & NTF_MASTER)
++	if (tb[NDA_MASTER])
++		fprintf(fp, "master %s ",
++			ll_index_to_name(rta_getattr_u32(tb[NDA_MASTER])));
++	else if (r->ndm_flags & NTF_MASTER)
+ 		fprintf(fp, "master ");
+ 	if (r->ndm_flags & NTF_ROUTER)
+ 		fprintf(fp, "router ");
+-- 
+1.8.3.1
+
diff --git a/SOURCES/iproute2-3.10.0-bridge-fdb-additional-man-changes.patch b/SOURCES/iproute2-3.10.0-bridge-fdb-additional-man-changes.patch
deleted file mode 100644
index 9267011..0000000
--- a/SOURCES/iproute2-3.10.0-bridge-fdb-additional-man-changes.patch
+++ /dev/null
@@ -1,44 +0,0 @@
-diff --git a/man/man8/bridge.8 b/man/man8/bridge.8
-index e313400..927a492 100644
---- a/man/man8/bridge.8
-+++ b/man/man8/bridge.8
-@@ -44,12 +44,12 @@ bridge \- show / manipulate bridge addresses and devices
- .IR DEV " ]"
- 
- .ti -8
--.BR "bridge fdb" " { " add " | " append " | " del " } "
-+.BR "bridge fdb" " { " add " | " append " | " del " | " replace " } "
- .I LLADDR
- .B  dev
- .IR DEV " { "
- .BR local " | " temp " } { "
--.BR self " } { " embedded " } { " router " } [ "
-+.BR self " } { " router " } [ "
- .B  dst
- .IR IPADDR " ] [ "
- .B vni
-@@ -275,10 +275,6 @@ the interface to which this address is associated.
- - the address is associated with a software fdb (default)
- .sp
- 
--.B embedded
--- the address is associated with an offloaded fdb
--.sp
--
- .B router
- - the destination address is associated with a router.
- Valid if the referenced device is a VXLAN type device and has
-@@ -333,6 +329,13 @@ This command removes an existing fdb entry.
- 
- .PP
- The arguments are the same as with
-+.BR "bridge fdb add" .
-+
-+.SS bridge fdb replace - replace a forwarding database entry
-+This command replaces an already present fdb entry.
-+
-+.PP
-+The arguments are the same as with
- .BR "bridge fdb add" ,
- 
- .SS bridge fdb show - list forwarding entries.
diff --git a/SOURCES/iproute2-3.10.0-bridge-fdb-replace.patch b/SOURCES/iproute2-3.10.0-bridge-fdb-replace.patch
deleted file mode 100644
index 0c7f4dd..0000000
--- a/SOURCES/iproute2-3.10.0-bridge-fdb-replace.patch
+++ /dev/null
@@ -1,22 +0,0 @@
-diff --git a/bridge/fdb.c b/bridge/fdb.c
-index 591fbbe..e2e53f1 100644
---- a/bridge/fdb.c
-+++ b/bridge/fdb.c
-@@ -30,7 +30,7 @@ int filter_index;
- 
- static void usage(void)
- {
--	fprintf(stderr, "Usage: bridge fdb { add | append | del } ADDR dev DEV {self|master} [ temp ]\n"
-+	fprintf(stderr, "Usage: bridge fdb { add | append | del | replace } ADDR dev DEV {self|master} [ temp ]\n"
- 		        "              [router] [ dst IPADDR] [ vlan VID ]\n"
- 		        "              [ port PORT] [ vni VNI ] [via DEV]\n");
- 	fprintf(stderr, "       bridge fdb {show} [ dev DEV ]\n");
-@@ -334,6 +334,8 @@ int do_fdb(int argc, char **argv)
- 			return fdb_modify(RTM_NEWNEIGH, NLM_F_CREATE|NLM_F_EXCL, argc-1, argv+1);
- 		if (matches(*argv, "append") == 0)
- 			return fdb_modify(RTM_NEWNEIGH, NLM_F_CREATE|NLM_F_APPEND, argc-1, argv+1);
-+		if (matches(*argv, "replace") == 0)
-+			return fdb_modify(RTM_NEWNEIGH, NLM_F_CREATE|NLM_F_REPLACE, argc-1, argv+1);
- 		if (matches(*argv, "delete") == 0)
- 			return fdb_modify(RTM_DELNEIGH, 0, argc-1, argv+1);
- 		if (matches(*argv, "show") == 0 ||
diff --git a/SOURCES/iproute2-3.10.0-bridge.patch b/SOURCES/iproute2-3.10.0-bridge.patch
new file mode 100644
index 0000000..7d04738
--- /dev/null
+++ b/SOURCES/iproute2-3.10.0-bridge.patch
@@ -0,0 +1,323 @@
+commit 2a9f06affaf089608a8137decaa17c5aee71ed6f
+Author: Pavel Šimerda <psimerda@redhat.com>
+Date:   Thu May 28 12:17:38 2015 +0200
+
+    backport selected bridge features and documentation
+
+diff --git a/bridge/Makefile b/bridge/Makefile
+index 1fb8320..9800753 100644
+--- a/bridge/Makefile
++++ b/bridge/Makefile
+@@ -2,6 +2,10 @@ BROBJ = bridge.o fdb.o monitor.o link.o mdb.o vlan.o
+ 
+ include ../Config
+ 
++ifeq ($(IP_CONFIG_SETNS),y)
++	CFLAGS += -DHAVE_SETNS
++endif
++
+ all: bridge
+ 
+ bridge: $(BROBJ) $(LIBNETLINK) 
+diff --git a/bridge/bridge.c b/bridge/bridge.c
+index ee08f90..5fcc552 100644
+--- a/bridge/bridge.c
++++ b/bridge/bridge.c
+@@ -13,6 +13,7 @@
+ #include "SNAPSHOT.h"
+ #include "utils.h"
+ #include "br_common.h"
++#include "namespace.h"
+ 
+ struct rtnl_handle rth = { .fd = -1 };
+ int preferred_family = AF_UNSPEC;
+@@ -31,7 +32,7 @@ static void usage(void)
+ "Usage: bridge [ OPTIONS ] OBJECT { COMMAND | help }\n"
+ "where  OBJECT := { link | fdb | mdb | vlan | monitor }\n"
+ "       OPTIONS := { -V[ersion] | -s[tatistics] | -d[etails] |\n"
+-"                    -o[neline] | -t[imestamp] \n");
++"                    -o[neline] | -t[imestamp] | -n[etns] name }\n");
+ 	exit(-1);
+ }
+ 
+@@ -112,6 +113,10 @@ main(int argc, char **argv)
+ 			preferred_family = AF_INET;
+ 		} else if (strcmp(opt, "-6") == 0) {
+ 			preferred_family = AF_INET6;
++		} else if (matches(opt, "-netns") == 0) {
++			NEXT_ARG();
++			if (netns_switch(argv[1]))
++				exit(-1);
+ 		} else {
+ 			fprintf(stderr, "Option \"%s\" is unknown, try \"bridge help\".\n", opt);
+ 			exit(-1);
+diff --git a/bridge/fdb.c b/bridge/fdb.c
+index 591fbbe..f725012 100644
+--- a/bridge/fdb.c
++++ b/bridge/fdb.c
+@@ -30,7 +30,7 @@ int filter_index;
+ 
+ static void usage(void)
+ {
+-	fprintf(stderr, "Usage: bridge fdb { add | append | del } ADDR dev DEV {self|master} [ temp ]\n"
++	fprintf(stderr, "Usage: bridge fdb { add | append | del | replace } ADDR dev DEV {self|master} [ temp ]\n"
+ 		        "              [router] [ dst IPADDR] [ vlan VID ]\n"
+ 		        "              [ port PORT] [ vni VNI ] [via DEV]\n");
+ 	fprintf(stderr, "       bridge fdb {show} [ dev DEV ]\n");
+@@ -125,12 +125,16 @@ int print_fdb(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
+ 		if (ifindex) {
+ 			char ifname[IF_NAMESIZE];
+ 
+-			if (if_indextoname(ifindex, ifname))
++			if (!tb[NDA_LINK_NETNSID] &&
++			    if_indextoname(ifindex, ifname))
+ 				fprintf(fp, "via %s ", ifname);
+ 			else
+ 				fprintf(fp, "via ifindex %u ", ifindex);
+ 		}
+ 	}
++	if (tb[NDA_LINK_NETNSID])
++		fprintf(fp, "link-netnsid %d ",
++			rta_getattr_u32(tb[NDA_LINK_NETNSID]));
+ 
+ 	if (show_stats && tb[NDA_CACHEINFO]) {
+ 		struct nda_cacheinfo *ci = RTA_DATA(tb[NDA_CACHEINFO]);
+@@ -334,6 +338,8 @@ int do_fdb(int argc, char **argv)
+ 			return fdb_modify(RTM_NEWNEIGH, NLM_F_CREATE|NLM_F_EXCL, argc-1, argv+1);
+ 		if (matches(*argv, "append") == 0)
+ 			return fdb_modify(RTM_NEWNEIGH, NLM_F_CREATE|NLM_F_APPEND, argc-1, argv+1);
++		if (matches(*argv, "replace") == 0)
++			return fdb_modify(RTM_NEWNEIGH, NLM_F_CREATE|NLM_F_REPLACE, argc-1, argv+1);
+ 		if (matches(*argv, "delete") == 0)
+ 			return fdb_modify(RTM_DELNEIGH, 0, argc-1, argv+1);
+ 		if (matches(*argv, "show") == 0 ||
+diff --git a/bridge/monitor.c b/bridge/monitor.c
+index e96fcaf..76e7d47 100644
+--- a/bridge/monitor.c
++++ b/bridge/monitor.c
+@@ -132,12 +132,15 @@ int do_monitor(int argc, char **argv)
+ 
+ 	if (file) {
+ 		FILE *fp;
++		int err;
+ 		fp = fopen(file, "r");
+ 		if (fp == NULL) {
+ 			perror("Cannot fopen");
+ 			exit(-1);
+ 		}
+-		return rtnl_from_file(fp, accept_msg, stdout);
++		err = rtnl_from_file(fp, accept_msg, stdout);
++		fclose(fp);
++		return err;
+ 	}
+ 
+ 	if (rtnl_open(&rth, groups) < 0)
+diff --git a/man/man8/bridge.8 b/man/man8/bridge.8
+index 66678b5..9db2aec 100644
+--- a/man/man8/bridge.8
++++ b/man/man8/bridge.8
+@@ -13,13 +13,14 @@ bridge \- show / manipulate bridge addresses and devices
+ 
+ .ti -8
+ .IR OBJECT " := { "
+-.BR link " | " fdb " | " vlan " | " monitor " }"
++.BR link " | " fdb " | " mdb " | " vlan " | " monitor " }"
+ .sp
+ 
+ .ti -8
+ .IR OPTIONS " := { "
+ \fB\-V\fR[\fIersion\fR] |
+-\fB\-s\fR[\fItatistics\fR] }
++\fB\-s\fR[\fItatistics\fR] |
++\fB\-n\fR[\fIetns\fR] name }
+ 
+ .ti -8
+ .BR "bridge link set"
+@@ -44,12 +45,12 @@ bridge \- show / manipulate bridge addresses and devices
+ .IR DEV " ]"
+ 
+ .ti -8
+-.BR "bridge fdb" " { " add " | " append " | " del " } "
++.BR "bridge fdb" " { " add " | " append " | " del " | " replace " } "
+ .I LLADDR
+ .B  dev
+ .IR DEV " { "
+ .BR local " | " temp " } { "
+-.BR self " } { " embedded " } { " router " } [ "
++.BR self " } { " router " } [ "
+ .B  dst
+ .IR IPADDR " ] [ "
+ .B vni
+@@ -65,6 +66,21 @@ bridge \- show / manipulate bridge addresses and devices
+ .IR DEV " ]"
+ 
+ .ti -8
++.BR "bridge mdb" " { " add " | " del " } "
++.B  dev
++.IR DEV
++.B port
++.IR PORT
++.B grp
++.IR GROUP " [ "
++.BR permanent " | " temp " ]"
++
++.ti -8
++.BR "bridge mdb show " [ "
++.B  dev
++.IR DEV " ]"
++
++.ti -8
+ .BR "bridge vlan" " { " add " | " del " } "
+ .B  dev
+ .IR DEV
+@@ -79,7 +95,7 @@ bridge \- show / manipulate bridge addresses and devices
+ .IR DEV " ]"
+ 
+ .ti -8
+-.BR "bridge monitor" " [ " all " | " neigh " | " link " ]"
++.BR "bridge monitor" " [ " all " | " neigh " | " link " | " mdb " ]"
+ 
+ .SH OPTIONS
+ 
+@@ -95,6 +111,26 @@ output more information.  If this option
+ is given multiple times, the amount of information increases.
+ As a rule, the information is statistics or some time values.
+ 
++.TP
++.BR "\-n" , " \-net" , " \-netns " <NETNS>
++switches
++.B bridge
++to the specified network namespace
++.IR NETNS .
++Actually it just simplifies executing of:
++
++.B ip netns exec
++.IR NETNS
++.B bridge
++.RI "[ " OPTIONS " ] " OBJECT " { " COMMAND " | "
++.BR help " }"
++
++to
++
++.B bridge
++.RI "-n[etns] " NETNS " [ " OPTIONS " ] " OBJECT " { " COMMAND " | "
++.BR help " }"
++
+ 
+ .SH BRIDGE - COMMAND SYNTAX
+ 
+@@ -110,6 +146,10 @@ As a rule, the information is statistics or some time values.
+ - Forwarding Database entry.
+ 
+ .TP
++.B mdb
++- Multicast group database entry.
++
++.TP
+ .B vlan
+ - VLAN filter list.
+ 
+@@ -256,10 +296,6 @@ the interface to which this address is associated.
+ - the address is associated with a software fdb (default)
+ .sp
+ 
+-.B embedded
+-- the address is associated with an offloaded fdb
+-.sp
+-
+ .B router
+ - the destination address is associated with a router.
+ Valid if the referenced device is a VXLAN type device and has
+@@ -314,6 +350,13 @@ This command removes an existing fdb entry.
+ 
+ .PP
+ The arguments are the same as with
++.BR "bridge fdb add" .
++
++.SS bridge fdb replace - replace a forwarding database entry
++This command replaces an already present fdb entry.
++
++.PP
++The arguments are the same as with
+ .BR "bridge fdb add" ,
+ 
+ .SS bridge fdb show - list forwarding entries.
+@@ -326,6 +369,69 @@ With the
+ option, the command becomes verbose.  It prints out the last updated
+ and last used time for each entry.
+ 
++.SH bridge mdb - multicast group database management
++
++.B mdb
++objects contain known IP multicast group addresses on a link.
++
++.P
++The corresponding commands display mdb entries, add new entries,
++and delete old ones.
++
++.SS bridge mdb add - add a new multicast group database entry
++
++This command creates a new mdb entry.
++
++.TP
++.BI dev " DEV"
++the interface where this group address is associated.
++
++.TP
++.BI port " PORT"
++the port whose link is known to have members of this multicast group.
++
++.TP
++.BI grp " GROUP"
++the IP multicast group address whose members reside on the link connected to
++the port.
++
++.B permanent
++- the mdb entry is permanent
++.sp
++
++.B temp
++- the mdb entry is temporary (default)
++.sp
++
++.in -8
++.SS bridge mdb delete - delete a multicast group database entry
++This command removes an existing mdb entry.
++
++.PP
++The arguments are the same as with
++.BR "bridge mdb add" .
++
++.SS bridge mdb show - list multicast group database entries
++
++This command displays the current multicast group membership table. The table
++is populated by IGMP and MLD snooping in the bridge driver automatically. It
++can be altered by
++.B bridge mdb add
++and
++.B bridge mdb del
++commands manually too.
++
++.TP
++.BI dev " DEV"
++the interface only whose entries should be listed. Default is to list all
++bridge interfaces.
++
++.PP
++With the
++.B -details
++option, the command becomes verbose.  It prints out the ports known to have
++a connected router.
++
+ .SH bridge vlan - VLAN filter list
+ 
+ .B vlan
+@@ -395,7 +501,7 @@ command is the first in the command line and then the object list follows:
+ .I OBJECT-LIST
+ is the list of object types that we want to monitor.
+ It may contain
+-.BR link ",  and " fdb "."
++.BR link ",  " fdb ", and " mdb "."
+ If no
+ .B file
+ argument is given,
diff --git a/SOURCES/iproute2-3.10.0-document-vlan.patch b/SOURCES/iproute2-3.10.0-document-vlan.patch
deleted file mode 100644
index 5b3522b..0000000
--- a/SOURCES/iproute2-3.10.0-document-vlan.patch
+++ /dev/null
@@ -1,89 +0,0 @@
-From ab56f5d7a75d14a420b166b84e1d4afb980ea263 Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Petr=20=C5=A0abata?= <contyk@redhat.com>
-Date: Fri, 8 Nov 2013 12:47:45 +0900
-Subject: [PATCH] iproute2: Document type vlan option in ip-link(8)
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-This patch adds the VLAN Type support section to the ip-link
-manual page.
-
-Signed-off-by: Petr Šabata <contyk@redhat.com>
----
- man/man8/ip-link.8.in | 59 +++++++++++++++++++++++++++++++++++++++++++++++++++
- 1 file changed, 59 insertions(+)
-
-diff --git a/man/man8/ip-link.8.in b/man/man8/ip-link.8.in
-index 8b68c78..4eddbcd 100644
---- a/man/man8/ip-link.8.in
-+++ b/man/man8/ip-link.8.in
-@@ -213,6 +213,65 @@ specifies the number of transmit queues for new device.
- specifies the number of receive queues for new device.
- 
- .TP
-+VLAN Type Support
-+For a link of type
-+.I VLAN
-+the following additional arguments are supported:
-+
-+.BI "ip link add link " DEVICE
-+.BI name " NAME "
-+.BI type " vlan "
-+.R " [ "
-+.BI protocol " VLAN_PROTO "
-+.R " ] "
-+.BI id " VLANID "
-+.R " [ "
-+.BR reorder_hdr " { " on " | " off " } "
-+.R " ] "
-+.R " [ "
-+.BR gvrp " { " on " | " off " } "
-+.R " ] "
-+.R " [ "
-+.BR mvrp " { " on " | " off " } "
-+.R " ] "
-+.R " [ "
-+.BR loose_binding " { " on " | " off " } "
-+.R " ] "
-+.R " [ "
-+.BI ingress-qos-map " QOS-MAP "
-+.R " ] "
-+.R " [ "
-+.BI egress-qos-map " QOS-MAP "
-+.R " ] "
-+
-+.in +8
-+.sp
-+.BI protocol " VLAN_PROTO "
-+- either 802.1Q or 802.1ad.
-+
-+.BI id " VLANID "
-+- specifies the VID.
-+
-+.BR reorder_hdr " { " on " | " off " } "
-+- specifies whether ethernet headers are reordered or not.
-+
-+.BR gvrp " { " on " | " off " } "
-+- specifies whether this VLAN should be registered using GARP VLAN Registration Protocol.
-+
-+.BR mvrp " { " on " | " off " } "
-+- specifies whether this VLAN should be registered using Multiple VLAN Registration Protocol.
-+
-+.BR loose_binding " { " on " | " off " } "
-+- specifies whether the VLAN device state is bound to the physical device state.
-+
-+.BI ingress-qos-map " QOS-MAP "
-+- defines a mapping between priority code points on incoming frames.  The format is FROM:TO with multiple mappings separated by spaces.
-+
-+.BI egress-qos-map " QOS-MAP "
-+- the same as ingress-qos-map but for outgoing frames.
-+.in -8
-+
-+.TP
- VXLAN Type Support
- For a link of type 
- .I VXLAN
--- 
-1.8.3.1
-
diff --git a/SOURCES/iproute2-3.10.0-fix-ip-tunnel-command-for-vti-tunnels-with-io-key-gi.patch b/SOURCES/iproute2-3.10.0-fix-ip-tunnel-command-for-vti-tunnels-with-io-key-gi.patch
new file mode 100644
index 0000000..a48f70b
--- /dev/null
+++ b/SOURCES/iproute2-3.10.0-fix-ip-tunnel-command-for-vti-tunnels-with-io-key-gi.patch
@@ -0,0 +1,304 @@
+From ac525bc5be98547620bc8d9df9e040438f60f2a8 Mon Sep 17 00:00:00 2001
+From: Phil Sutter <psutter@redhat.com>
+Date: Fri, 7 Aug 2015 13:18:13 +0200
+Subject: [PATCH] fix ip tunnel command for vti tunnels with [io]key given
+
+This patch folds five upstream commits:
+- 30d07e9 iproute2: spelling: noptmudisc -> nopmtudisc
+- 1c28bd5 iptunnel: Allow GRE_KEY for vti interface
+- 0612519 Remove trailing whitespace
+- 0cb6bb5 do not exit silently when link is not found
+- 23d526c fix ip tunnel for vti tunnels with ikey
+---
+ ip/ipaddress.c    |  2 +-
+ ip/ipaddrlabel.c  |  2 +-
+ ip/iplink_vxlan.c |  5 ++++-
+ ip/iproute.c      |  2 +-
+ ip/iptunnel.c     | 36 ++++++++++++++++++++----------------
+ ip/ipxfrm.c       |  4 ++--
+ ip/link_gre.c     |  7 +++++--
+ ip/link_gre6.c    |  5 ++++-
+ ip/link_iptnl.c   |  2 +-
+ ip/link_vti.c     |  5 ++++-
+ ip/tunnel.c       |  2 +-
+ ip/xfrm_state.c   |  2 +-
+ 12 files changed, 45 insertions(+), 29 deletions(-)
+
+diff --git a/ip/ipaddress.c b/ip/ipaddress.c
+index c99a078..4650a2e 100644
+--- a/ip/ipaddress.c
++++ b/ip/ipaddress.c
+@@ -126,7 +126,7 @@ static void print_link_flags(FILE *fp, unsigned flags, unsigned mdown)
+ }
+ 
+ static const char *oper_states[] = {
+-	"UNKNOWN", "NOTPRESENT", "DOWN", "LOWERLAYERDOWN", 
++	"UNKNOWN", "NOTPRESENT", "DOWN", "LOWERLAYERDOWN",
+ 	"TESTING", "DORMANT",	 "UP"
+ };
+ 
+diff --git a/ip/ipaddrlabel.c b/ip/ipaddrlabel.c
+index 1789d9c..301074b 100644
+--- a/ip/ipaddrlabel.c
++++ b/ip/ipaddrlabel.c
+@@ -134,7 +134,7 @@ static int ipaddrlabel_modify(int cmd, int argc, char **argv)
+ 	inet_prefix prefix;
+ 	uint32_t label = 0xffffffffUL;
+ 	char *p = NULL;
+-	char *l = NULL;        
++	char *l = NULL;
+ 
+ 	memset(&req, 0, sizeof(req));
+ 	memset(&prefix, 0, sizeof(prefix));
+diff --git a/ip/iplink_vxlan.c b/ip/iplink_vxlan.c
+index 43b8abc..2f3a84c 100644
+--- a/ip/iplink_vxlan.c
++++ b/ip/iplink_vxlan.c
+@@ -104,8 +104,11 @@ static int vxlan_parse_opt(struct link_util *lu, int argc, char **argv,
+ 		} else if (!matches(*argv, "dev")) {
+ 			NEXT_ARG();
+ 			link = if_nametoindex(*argv);
+-			if (link == 0)
++			if (link == 0) {
++				fprintf(stderr, "Cannot find device \"%s\"\n",
++					*argv);
+ 				exit(-1);
++			}
+ 		} else if (!matches(*argv, "ttl") ||
+ 			   !matches(*argv, "hoplimit")) {
+ 			unsigned uval;
+diff --git a/ip/iproute.c b/ip/iproute.c
+index 984d970..207301c 100644
+--- a/ip/iproute.c
++++ b/ip/iproute.c
+@@ -837,7 +837,7 @@ static int iproute_modify(int cmd, unsigned flags, int argc, char **argv)
+ 			}
+ 			if (get_time_rtt(&rtt, *argv, &raw))
+ 				invarg("\"rtt\" value is invalid\n", *argv);
+-			rta_addattr32(mxrta, sizeof(mxbuf), RTAX_RTT, 
++			rta_addattr32(mxrta, sizeof(mxbuf), RTAX_RTT,
+ 				(raw) ? rtt : rtt * 8);
+ 		} else if (strcmp(*argv, "rto_min") == 0) {
+ 			unsigned rto_min;
+diff --git a/ip/iptunnel.c b/ip/iptunnel.c
+index 9099503..29188c4 100644
+--- a/ip/iptunnel.c
++++ b/ip/iptunnel.c
+@@ -240,8 +240,9 @@ static int parse_args(int argc, char **argv, int cmd, struct ip_tunnel_parm *p)
+ 		}
+ 	}
+ 
+-	if (p->iph.protocol == IPPROTO_IPIP || p->iph.protocol == IPPROTO_IPV6) {
+-		if ((p->i_flags & GRE_KEY) || (p->o_flags & GRE_KEY)) {
++	if ((p->i_flags & GRE_KEY) || (p->o_flags & GRE_KEY)) {
++		if (!(p->i_flags & VTI_ISVTI) &&
++		    (p->iph.protocol != IPPROTO_GRE)) {
+ 			fprintf(stderr, "Keys are not allowed with ipip and sit tunnels\n");
+ 			return -1;
+ 		}
+@@ -249,8 +250,11 @@ static int parse_args(int argc, char **argv, int cmd, struct ip_tunnel_parm *p)
+ 
+ 	if (medium[0]) {
+ 		p->link = if_nametoindex(medium);
+-		if (p->link == 0)
++		if (p->link == 0) {
++			fprintf(stderr, "Cannot find device \"%s\"\n",
++				medium);
+ 			return -1;
++		}
+ 	}
+ 
+ 	if (p->i_key == 0 && IN_MULTICAST(ntohl(p->iph.daddr))) {
+@@ -280,16 +284,16 @@ static int do_add(int cmd, int argc, char **argv)
+ 		return -1;
+ 
+ 	if (p.iph.ttl && p.iph.frag_off == 0) {
+-		fprintf(stderr, "ttl != 0 and noptmudisc are incompatible\n");
++		fprintf(stderr, "ttl != 0 and nopmtudisc are incompatible\n");
+ 		return -1;
+ 	}
+ 
+ 	switch (p.iph.protocol) {
+ 	case IPPROTO_IPIP:
+-		if (p.i_flags != VTI_ISVTI)
+-			return tnl_add_ioctl(cmd, "tunl0", p.name, &p);
+-		else
++		if (p.i_flags & VTI_ISVTI)
+ 			return tnl_add_ioctl(cmd, "ip_vti0", p.name, &p);
++		else
++			return tnl_add_ioctl(cmd, "tunl0", p.name, &p);
+ 	case IPPROTO_GRE:
+ 		return tnl_add_ioctl(cmd, "gre0", p.name, &p);
+ 	case IPPROTO_IPV6:
+@@ -310,10 +314,10 @@ static int do_del(int argc, char **argv)
+ 
+ 	switch (p.iph.protocol) {
+ 	case IPPROTO_IPIP:
+-		if (p.i_flags != VTI_ISVTI)
+-			return tnl_del_ioctl("tunl0", p.name, &p);
+-		else
++		if (p.i_flags & VTI_ISVTI)
+ 			return tnl_del_ioctl("ip_vti0", p.name, &p);
++		else
++			return tnl_del_ioctl("tunl0", p.name, &p);
+ 	case IPPROTO_GRE:
+ 		return tnl_del_ioctl("gre0", p.name, &p);
+ 	case IPPROTO_IPV6:
+@@ -344,16 +348,16 @@ static void print_tunnel(struct ip_tunnel_parm *p)
+ 	if (p->iph.protocol == IPPROTO_IPV6 && (p->i_flags & SIT_ISATAP)) {
+ 		struct ip_tunnel_prl prl[16];
+ 		int i;
+-		
++
+ 		memset(prl, 0, sizeof(prl));
+ 		prl[0].datalen = sizeof(prl) - sizeof(prl[0]);
+ 		prl[0].addr = htonl(INADDR_ANY);
+-	
++
+ 		if (!tnl_prl_ioctl(SIOCGETPRL, p->name, prl))
+ 			for (i = 1; i < sizeof(prl) / sizeof(prl[0]); i++)
+ 		{
+ 			if (prl[i].addr != htonl(INADDR_ANY)) {
+-				printf(" %s %s ", 
++				printf(" %s %s ",
+ 					(prl[i].flags & PRL_DEFAULT) ? "pdr" : "pr",
+ 					format_host(AF_INET, 4, &prl[i].addr, s1, sizeof(s1)));
+ 			}
+@@ -502,10 +506,10 @@ static int do_show(int argc, char **argv)
+ 
+ 	switch (p.iph.protocol) {
+ 	case IPPROTO_IPIP:
+-		if (p.i_flags != VTI_ISVTI)
+-			err = tnl_get_ioctl(p.name[0] ? p.name : "tunl0", &p);
+-		else
++		if (p.i_flags & VTI_ISVTI)
+ 			err = tnl_get_ioctl(p.name[0] ? p.name : "ip_vti0", &p);
++		else
++			err = tnl_get_ioctl(p.name[0] ? p.name : "tunl0", &p);
+ 		break;
+ 	case IPPROTO_GRE:
+ 		err = tnl_get_ioctl(p.name[0] ? p.name : "gre0", &p);
+diff --git a/ip/ipxfrm.c b/ip/ipxfrm.c
+index 020159c..a6ec4cf 100644
+--- a/ip/ipxfrm.c
++++ b/ip/ipxfrm.c
+@@ -358,7 +358,7 @@ void xfrm_stats_print(struct xfrm_stats *s, FILE *fp, const char *prefix)
+ 
+ 	if (prefix)
+ 		fputs(prefix, fp);
+-	fprintf(fp, "  replay-window %u replay %u failed %u%s", 
++	fprintf(fp, "  replay-window %u replay %u failed %u%s",
+ 		s->replay_window, s->replay, s->integrity_failed, _SL_);
+ }
+ 
+@@ -409,7 +409,7 @@ void xfrm_lifetime_print(struct xfrm_lifetime_cfg *cfg,
+ 
+ 		if (prefix)
+ 			fputs(prefix, fp);
+-		fprintf(fp, "  expire add: soft %llu(sec), hard %llu(sec)%s", 
++		fprintf(fp, "  expire add: soft %llu(sec), hard %llu(sec)%s",
+ 			(unsigned long long) cfg->soft_add_expires_seconds,
+ 			(unsigned long long) cfg->hard_add_expires_seconds,
+ 			_SL_);
+diff --git a/ip/link_gre.c b/ip/link_gre.c
+index 7e0b896..fda84d8 100644
+--- a/ip/link_gre.c
++++ b/ip/link_gre.c
+@@ -207,8 +207,11 @@ get_failed:
+ 		} else if (!matches(*argv, "dev")) {
+ 			NEXT_ARG();
+ 			link = if_nametoindex(*argv);
+-			if (link == 0)
++			if (link == 0) {
++				fprintf(stderr, "Cannot find device \"%s\"\n",
++					*argv);
+ 				exit(-1);
++			}
+ 		} else if (!matches(*argv, "ttl") ||
+ 			   !matches(*argv, "hoplimit")) {
+ 			unsigned uval;
+@@ -233,7 +236,7 @@ get_failed:
+ 				tos = uval;
+ 			} else
+ 				tos = 1;
+-		} else 
++		} else
+ 			usage();
+ 		argc--; argv++;
+ 	}
+diff --git a/ip/link_gre6.c b/ip/link_gre6.c
+index 4c9c536..c7183e2 100644
+--- a/ip/link_gre6.c
++++ b/ip/link_gre6.c
+@@ -225,8 +225,11 @@ get_failed:
+ 		} else if (!matches(*argv, "dev")) {
+ 			NEXT_ARG();
+ 			link = if_nametoindex(*argv);
+-			if (link == 0)
++			if (link == 0) {
++				fprintf(stderr, "Cannot find device \"%s\"\n",
++					*argv);
+ 				exit(-1);
++			}
+ 		} else if (!matches(*argv, "ttl") ||
+ 			   !matches(*argv, "hoplimit")) {
+ 			__u8 uval;
+diff --git a/ip/link_iptnl.c b/ip/link_iptnl.c
+index b00d8d9..768c4ef 100644
+--- a/ip/link_iptnl.c
++++ b/ip/link_iptnl.c
+@@ -212,7 +212,7 @@ get_failed:
+ 	}
+ 
+ 	if (ttl && pmtudisc == 0) {
+-		fprintf(stderr, "ttl != 0 and noptmudisc are incompatible\n");
++		fprintf(stderr, "ttl != 0 and nopmtudisc are incompatible\n");
+ 		exit(-1);
+ 	}
+ 
+diff --git a/ip/link_vti.c b/ip/link_vti.c
+index 77a7482..6274c83 100644
+--- a/ip/link_vti.c
++++ b/ip/link_vti.c
+@@ -171,8 +171,11 @@ get_failed:
+ 		} else if (!matches(*argv, "dev")) {
+ 			NEXT_ARG();
+ 			link = if_nametoindex(*argv);
+-			if (link == 0)
++			if (link == 0) {
++				fprintf(stderr, "Cannot find device \"%s\"\n",
++					*argv);
+ 				exit(-1);
++			}
+ 		} else
+ 			usage();
+ 		argc--; argv++;
+diff --git a/ip/tunnel.c b/ip/tunnel.c
+index a6a2846..a1a7660 100644
+--- a/ip/tunnel.c
++++ b/ip/tunnel.c
+@@ -122,7 +122,7 @@ int tnl_del_ioctl(const char *basedev, const char *name, void *p)
+ 	return err;
+ }
+ 
+-static int tnl_gen_ioctl(int cmd, const char *name, 
++static int tnl_gen_ioctl(int cmd, const char *name,
+ 			 void *p, int skiperr)
+ {
+ 	struct ifreq ifr;
+diff --git a/ip/xfrm_state.c b/ip/xfrm_state.c
+index 160ab32..208c49c 100644
+--- a/ip/xfrm_state.c
++++ b/ip/xfrm_state.c
+@@ -1193,7 +1193,7 @@ static int print_sadinfo(struct nlmsghdr *n, void *arg)
+ 				fprintf(fp,"BAD SAD length returned\n");
+ 				return -1;
+ 			}
+-				
++
+ 			si = RTA_DATA(tb[XFRMA_SAD_HINFO]);
+ 			fprintf(fp," (buckets ");
+ 			fprintf(fp,"count %d", si->sadhcnt);
+-- 
+1.8.3.1
+
diff --git a/SOURCES/iproute2-3.10.0-fq-allow-options-of-fair-queue-set-to-0U.patch b/SOURCES/iproute2-3.10.0-fq-allow-options-of-fair-queue-set-to-0U.patch
new file mode 100644
index 0000000..4e5344c
--- /dev/null
+++ b/SOURCES/iproute2-3.10.0-fq-allow-options-of-fair-queue-set-to-0U.patch
@@ -0,0 +1,148 @@
+From 2adc0d473370b683726e2ea019c6d1cc302823ce Mon Sep 17 00:00:00 2001
+From: Yang Yingliang <yangyingliang@huawei.com>
+Date: Thu, 29 May 2014 12:04:34 +0800
+Subject: [PATCH 2/2] fq: allow options of fair queue set to ~0U
+
+Some options of fair queue cannot be (~0U). It leads to maxrate
+cannot be reset to unlimited because it cannot be (~0U). Allow
+the options being ~0U.
+
+Tested by the following command:
+ # tc qdisc add dev eth4 root handle 1: fq limit 2000 flow_limit 200 maxrate 100mbit quantum 2000 initial_quantum 1600
+ # tc -s -d qdisc show
+qdisc fq 1: dev eth4 root refcnt 2 limit 2000p flow_limit 200p buckets 1024 quantum 2000 initial_quantum 1600 maxrate 100Mbit
+ Sent 1492 bytes 10 pkt (dropped 0, overlimits 0 requeues 0)
+ backlog 0b 0p requeues 0
+  1 flows (0 inactive, 0 throttled)
+  0 gc, 0 highprio, 0 throttled
+
+ # tc qdisc change dev eth4 root handle 1: fq limit 4294967295 flow_limit 4294967295 maxrate 34359738360 quantum 4294967295 initial_quantum 4294967295
+ # tc -s -d qdisc show
+qdisc fq 1: dev eth4 root refcnt 2 limit 4294967295p flow_limit 4294967295p buckets 1024 quantum 4294967295 initial_quantum 4294967295
+ Sent 38372 bytes 216 pkt (dropped 0, overlimits 0 requeues 0)
+ backlog 0b 0p requeues 0
+  2 flows (1 inactive, 0 throttled)
+  0 gc, 2 highprio, 7 throttled
+
+Suggested-by: Eric Dumazet <edumazet@google.com>
+Signed-off-by: Yang Yingliang <yangyingliang@huawei.com>
+---
+ tc/q_fq.c | 37 +++++++++++++++++++++++++------------
+ 1 file changed, 25 insertions(+), 12 deletions(-)
+
+diff --git a/tc/q_fq.c b/tc/q_fq.c
+index c1f658e..e7288c2 100644
+--- a/tc/q_fq.c
++++ b/tc/q_fq.c
+@@ -44,6 +44,7 @@
+ #include <netinet/in.h>
+ #include <arpa/inet.h>
+ #include <string.h>
++#include <stdbool.h>
+ 
+ #include "utils.h"
+ #include "tc_util.h"
+@@ -71,13 +72,19 @@ static unsigned int ilog2(unsigned int val)
+ static int fq_parse_opt(struct qdisc_util *qu, int argc, char **argv,
+ 			struct nlmsghdr *n)
+ {
+-	unsigned int plimit = ~0U;
+-	unsigned int flow_plimit = ~0U;
+-	unsigned int quantum = ~0U;
+-	unsigned int initial_quantum = ~0U;
++	unsigned int plimit;
++	unsigned int flow_plimit;
++	unsigned int quantum;
++	unsigned int initial_quantum;
+ 	unsigned int buckets = 0;
+-	unsigned int maxrate = ~0U;
+-	unsigned int defrate = ~0U;
++	unsigned int maxrate;
++	unsigned int defrate;
++	bool set_plimit = false;
++	bool set_flow_plimit = false;
++	bool set_quantum = false;
++	bool set_initial_quantum = false;
++	bool set_maxrate = false;
++	bool set_defrate = false;
+ 	int pacing = -1;
+ 	struct rtattr *tail;
+ 
+@@ -88,12 +95,14 @@ static int fq_parse_opt(struct qdisc_util *qu, int argc, char **argv,
+ 				fprintf(stderr, "Illegal \"limit\"\n");
+ 				return -1;
+ 			}
++			set_plimit = true;
+ 		} else if (strcmp(*argv, "flow_limit") == 0) {
+ 			NEXT_ARG();
+ 			if (get_unsigned(&flow_plimit, *argv, 0)) {
+ 				fprintf(stderr, "Illegal \"flow_limit\"\n");
+ 				return -1;
+ 			}
++			set_flow_plimit = true;
+ 		} else if (strcmp(*argv, "buckets") == 0) {
+ 			NEXT_ARG();
+ 			if (get_unsigned(&buckets, *argv, 0)) {
+@@ -106,24 +115,28 @@ static int fq_parse_opt(struct qdisc_util *qu, int argc, char **argv,
+ 				fprintf(stderr, "Illegal \"maxrate\"\n");
+ 				return -1;
+ 			}
++			set_maxrate = true;
+ 		} else if (strcmp(*argv, "defrate") == 0) {
+ 			NEXT_ARG();
+ 			if (get_rate(&defrate, *argv)) {
+ 				fprintf(stderr, "Illegal \"defrate\"\n");
+ 				return -1;
+ 			}
++			set_defrate = true;
+ 		} else if (strcmp(*argv, "quantum") == 0) {
+ 			NEXT_ARG();
+ 			if (get_unsigned(&quantum, *argv, 0)) {
+ 				fprintf(stderr, "Illegal \"quantum\"\n");
+ 				return -1;
+ 			}
++			set_quantum = true;
+ 		} else if (strcmp(*argv, "initial_quantum") == 0) {
+ 			NEXT_ARG();
+ 			if (get_unsigned(&initial_quantum, *argv, 0)) {
+ 				fprintf(stderr, "Illegal \"initial_quantum\"\n");
+ 				return -1;
+ 			}
++			set_initial_quantum = true;
+ 		} else if (strcmp(*argv, "pacing") == 0) {
+ 			pacing = 1;
+ 		} else if (strcmp(*argv, "nopacing") == 0) {
+@@ -147,24 +160,24 @@ static int fq_parse_opt(struct qdisc_util *qu, int argc, char **argv,
+ 		addattr_l(n, 1024, TCA_FQ_BUCKETS_LOG,
+ 			  &log, sizeof(log));
+ 	}
+-	if (plimit != ~0U)
++	if (set_plimit)
+ 		addattr_l(n, 1024, TCA_FQ_PLIMIT,
+ 			  &plimit, sizeof(plimit));
+-	if (flow_plimit != ~0U)
++	if (set_flow_plimit)
+ 		addattr_l(n, 1024, TCA_FQ_FLOW_PLIMIT,
+ 			  &flow_plimit, sizeof(flow_plimit));
+-	if (quantum != ~0U)
++	if (set_quantum)
+ 		addattr_l(n, 1024, TCA_FQ_QUANTUM, &quantum, sizeof(quantum));
+-	if (initial_quantum != ~0U)
++	if (set_initial_quantum)
+ 		addattr_l(n, 1024, TCA_FQ_INITIAL_QUANTUM,
+ 			  &initial_quantum, sizeof(initial_quantum));
+ 	if (pacing != -1)
+ 		addattr_l(n, 1024, TCA_FQ_RATE_ENABLE,
+ 			  &pacing, sizeof(pacing));
+-	if (maxrate != ~0U)
++	if (set_maxrate)
+ 		addattr_l(n, 1024, TCA_FQ_FLOW_MAX_RATE,
+ 			  &maxrate, sizeof(maxrate));
+-	if (defrate != ~0U)
++	if (set_defrate)
+ 		addattr_l(n, 1024, TCA_FQ_FLOW_DEFAULT_RATE,
+ 			  &defrate, sizeof(defrate));
+ 	tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail;
+-- 
+1.8.3.1
+
diff --git a/SOURCES/iproute2-3.10.0-ip-link-fix-and-extend-documentation.patch b/SOURCES/iproute2-3.10.0-ip-link-fix-and-extend-documentation.patch
new file mode 100644
index 0000000..5b9bb39
--- /dev/null
+++ b/SOURCES/iproute2-3.10.0-ip-link-fix-and-extend-documentation.patch
@@ -0,0 +1,168 @@
+From 8951dc99dc6a881e95420d0591bcb374f0c373d7 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Pavel=20=C5=A0imerda?= <psimerda@redhat.com>
+Date: Wed, 12 Aug 2015 22:04:07 +0200
+Subject: [PATCH] ip-link: fix and extend documentation
+
+ * Add `can` to list of supported link types
+ * Document `addrgenmode`
+ * Document `link-netnsid`
+ * Document VLAN link type
+ * Improve VXLAN link type documentation
+    - Fix VXLAN srcport/dstport docs
+    - Document `udpcsum`, `udp6zerocsumtx` and `udp6zerocsumrx`
+---
+ man/man8/ip-link.8.in | 96 +++++++++++++++++++++++++++++++++++++++++++++++++--
+ 1 file changed, 93 insertions(+), 3 deletions(-)
+
+diff --git a/man/man8/ip-link.8.in b/man/man8/ip-link.8.in
+index 844127d..a45bc05 100644
+--- a/man/man8/ip-link.8.in
++++ b/man/man8/ip-link.8.in
+@@ -126,6 +126,8 @@ ip-link \- network device configuration
+ .B nomaster " |"
+ .br
+ .B addrgenmode { eui64 | none }
++.br
++.B link-netnsid ID
+ .BR " }"
+ 
+ 
+@@ -259,6 +261,66 @@ the following additional arguments are supported:
+ .in -8
+ 
+ .TP
++VLAN Type Support
++For a link of type
++.I VLAN
++the following additional arguments are supported:
++
++.BI "ip link add
++.BI link " DEVICE "
++.BI name " NAME "
++.BI type " vlan "
++.R " [ "
++.BI protocol " VLAN_PROTO "
++.R " ] "
++.BI id " VLANID "
++.R " [ "
++.BR reorder_hdr " { " on " | " off " } "
++.R " ] "
++.R " [ "
++.BR gvrp " { " on " | " off " } "
++.R " ] "
++.R " [ "
++.BR mvrp " { " on " | " off " } "
++.R " ] "
++.R " [ "
++.BR loose_binding " { " on " | " off " } "
++.R " ] "
++.R " [ "
++.BI ingress-qos-map " QOS-MAP "
++.R " ] "
++.R " [ "
++.BI egress-qos-map " QOS-MAP "
++.R " ] "
++
++.in +8
++.sp
++.BI protocol " VLAN_PROTO "
++- either 802.1Q or 802.1ad.
++
++.BI id " VLANID "
++- specifies the VLAN Identifer to use. Note that numbers with a leading " 0 " or " 0x " are interpreted as octal or hexadeimal, respectively.
++
++.BR reorder_hdr " { " on " | " off " } "
++- specifies whether ethernet headers are reordered or not.
++
++.BR gvrp " { " on " | " off " } "
++- specifies whether this VLAN should be registered using GARP VLAN Registration Protocol.
++
++.BR mvrp " { " on " | " off " } "
++- specifies whether this VLAN should be registered using Multiple VLAN Registration Protocol.
++
++.BR loose_binding " { " on " | " off " } "
++- specifies whether the VLAN device state is bound to the physical device state.
++
++.BI ingress-qos-map " QOS-MAP "
++- defines a mapping between priority code points on incoming frames.  The format is FROM:TO with multiple mappings separated by spaces.
++
++.BI egress-qos-map " QOS-MAP "
++- the same as ingress-qos-map but for outgoing frames.
++.in -8
++
++.TP
+ VXLAN Type Support
+ For a link of type 
+ .I VXLAN
+@@ -277,7 +339,9 @@ the following additional arguments are supported:
+ .R " ] [ "
+ .BI tos " TOS "
+ .R " ] [ "
+-.BI port " MIN MAX "
++.BI dstport " PORT "
++.R " ] [ "
++.BI srcport " MIN MAX "
+ .R " ] [ "
+ .I "[no]learning "
+ .R " ] [ "
+@@ -289,6 +353,12 @@ the following additional arguments are supported:
+ .R " ] [ "
+ .I "[no]l3miss "
+ .R " ] [ "
++.I "[no]udpcsum "
++.R " ] [ "
++.I "[no]udp6zerocsumtx "
++.R " ] [ "
++.I "[no]udp6zerocsumrx "
++.R " ] [ "
+ .B gbp
+ .R " ]"
+ 
+@@ -329,7 +399,11 @@ parameter.
+ - specifies the TOS value to use in outgoing packets.
+ 
+ .sp
+-.BI port " MIN MAX"
++.BI dstport " PORT"
++- specifies the UDP destination port to communicate to the remote VXLAN tunnel endpoint.
++
++.sp
++.BI srcport " MIN MAX"
+ - specifies the range of port numbers to use as UDP
+ source ports to communicate to the remote VXLAN tunnel endpoint.
+ 
+@@ -355,6 +429,18 @@ are entered into the VXLAN device forwarding database.
+ - specifies if netlink IP ADDR miss notifications are generated.
+ 
+ .sp
++.I [no]udpcsum
++- specifies if UDP checksum is filled in
++
++.sp
++.I [no]udp6zerocsumtx
++- specifies if UDP checksum is filled in
++
++.sp
++.I [no]udp6zerocsumrx
++- specifies if UDP checksum is received
++
++.sp
+ .B gbp
+ - enables the Group Policy extension (VXLAN-GBP).
+ 
+@@ -577,7 +663,11 @@ unset master device of the device (release device).
+ 
+ .TP
+ .BR "addrgenmode eui64 " or " addrgenmode none"
+-allow to ipv6 set address generation mode
++set IPv6 address generation mode
++
++.TP
++.BR "link-netnsid "
++set peer netnsid for a cross-netns interface
+ 
+ .PP
+ .B Warning:
+-- 
+1.8.3.1
+
diff --git a/SOURCES/iproute2-3.10.0-ip-link-fix-minor-typo-in-manpage.patch b/SOURCES/iproute2-3.10.0-ip-link-fix-minor-typo-in-manpage.patch
new file mode 100644
index 0000000..53166c4
--- /dev/null
+++ b/SOURCES/iproute2-3.10.0-ip-link-fix-minor-typo-in-manpage.patch
@@ -0,0 +1,28 @@
+From e9693b8ac04691c603a6ccbe3f5fb996fd804eb9 Mon Sep 17 00:00:00 2001
+From: Phil Sutter <phil@nwl.cc>
+Date: Tue, 11 Aug 2015 19:14:11 +0200
+Subject: [PATCH] ip-link: fix minor typo in manpage
+
+Change '-human-readble' to '-human-readable'.
+
+Signed-off-by: Phil Sutter <phil@nwl.cc>
+---
+ man/man8/ip-link.8.in | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/man/man8/ip-link.8.in b/man/man8/ip-link.8.in
+index a015b82..844127d 100644
+--- a/man/man8/ip-link.8.in
++++ b/man/man8/ip-link.8.in
+@@ -621,7 +621,7 @@ output more statistics about packet usage.
+ output more detailed information.
+ 
+ .TP
+-.BR "\-h", " \-human", " \-human-readble"
++.BR "\-h", " \-human", " \-human-readable"
+ output statistics with human readable values number followed by suffix
+ 
+ .TP
+-- 
+1.8.3.1
+
diff --git a/SOURCES/iproute2-3.10.0-ip-rule.patch b/SOURCES/iproute2-3.10.0-ip-rule.patch
new file mode 100644
index 0000000..d86597a
--- /dev/null
+++ b/SOURCES/iproute2-3.10.0-ip-rule.patch
@@ -0,0 +1,35 @@
+diff --git a/man/man8/ip-rule.8 b/man/man8/ip-rule.8
+index dd925be..0c45a6f 100644
+--- a/man/man8/ip-rule.8
++++ b/man/man8/ip-rule.8
+@@ -108,8 +108,6 @@ The
+ .B local
+ table is a special routing table containing
+ high priority control routes for local and broadcast addresses.
+-.sp
+-Rule 0 is special. It cannot be deleted or overridden.
+ 
+ .TP
+ 2.
+--- iproute2-3.10.0/man/man8/ip-rule.8.orig	2015-07-08 18:04:55.918190531 +0200
++++ iproute2-3.10.0/man/man8/ip-rule.8	2015-07-08 18:05:46.778190024 +0200
+@@ -41,7 +41,7 @@
+ .IR TABLE_ID " ] [ "
+ .B  nat
+ .IR ADDRESS " ] [ "
+-.BR prohibit " | " reject " | " unreachable " ] [ " realms
++.BR prohibit " | " unreachable " ] [ " realms
+ .RI "[" SRCREALM "/]" DSTREALM " ]"
+ 
+ .ti -8
+--- iproute2-3.10.0/ip/iprule.c.orig	2015-07-08 18:07:17.018189125 +0200
++++ iproute2-3.10.0/ip/iprule.c	2015-07-08 18:07:32.448188972 +0200
+@@ -36,7 +36,7 @@
+ 	fprintf(stderr, "SELECTOR := [ not ] [ from PREFIX ] [ to PREFIX ] [ tos TOS ] [ fwmark FWMARK[/MASK] ]\n");
+ 	fprintf(stderr, "            [ iif STRING ] [ oif STRING ] [ pref NUMBER ]\n");
+ 	fprintf(stderr, "ACTION := [ table TABLE_ID ]\n");
+-	fprintf(stderr, "          [ prohibit | reject | unreachable ]\n");
++	fprintf(stderr, "          [ prohibit | unreachable ]\n");
+ 	fprintf(stderr, "          [ realms [SRCREALM/]DSTREALM ]\n");
+ 	fprintf(stderr, "          [ goto NUMBER ]\n");
+ 	fprintf(stderr, "TABLE_ID := [ local | main | default | NUMBER ]\n");
diff --git a/SOURCES/iproute2-3.10.0-ip-xfrm-monitor-allows-to-monitor-in-several-netns.patch b/SOURCES/iproute2-3.10.0-ip-xfrm-monitor-allows-to-monitor-in-several-netns.patch
new file mode 100644
index 0000000..885397a
--- /dev/null
+++ b/SOURCES/iproute2-3.10.0-ip-xfrm-monitor-allows-to-monitor-in-several-netns.patch
@@ -0,0 +1,834 @@
+From 3873ff54417f7e514197d069bcad187ca2ec3b86 Mon Sep 17 00:00:00 2001
+From: Phil Sutter <psutter@redhat.com>
+Date: Mon, 10 Aug 2015 17:26:16 +0200
+Subject: [PATCH] {ip,xfrm}monitor: allows to monitor in several netns
+
+This is a combination of six commits:
+
+commit c1f4d1640efa2ba2219861852b351d5c369c3715
+Author: Phil Sutter <psutter@redhat.com>
+Date:   Mon Aug 10 17:26:16 2015 +0200
+
+    include/linux/netlink.h: add NETLINK_LISTEN_ALL_NSID
+
+    This is a selective backport for the following patches and will be replaced by
+    full linux header update backports soon.
+
+commit 2503247d58c36f9197144790455626bae105342a
+Author: Nicolas Dichtel <nicolas.dichtel@6wind.com>
+Date:   Wed May 20 16:19:57 2015 +0200
+
+    man: update ip monitor page
+
+    Add label option.
+
+    Signed-off-by: Nicolas Dichtel <nicolas.dichtel@6wind.com>
+
+commit 0628cddd9d5c0cb9ed0e0aba136e50de93487150
+Author: Nicolas Dichtel <nicolas.dichtel@6wind.com>
+Date:   Wed May 20 16:19:58 2015 +0200
+
+    libnetlink: introduce rtnl_listen_filter_t
+
+    There is no functional change with this commit. It only prepares the next one.
+
+    Signed-off-by: Nicolas Dichtel <nicolas.dichtel@6wind.com>
+
+commit 3b0006f8183e09eda5f2f11667f2b9d36fcd8c16
+Author: Nicolas Dichtel <nicolas.dichtel@6wind.com>
+Date:   Wed May 20 16:19:59 2015 +0200
+
+    ipmonitor: introduce print_headers
+
+    The goal of this patch is to avoid code duplication.
+
+    Signed-off-by: Nicolas Dichtel <nicolas.dichtel@6wind.com>
+
+commit 449b824ad19679f66164e1e97513f36eee0d004e
+Author: Nicolas Dichtel <nicolas.dichtel@6wind.com>
+Date:   Wed May 20 16:20:00 2015 +0200
+
+    ipmonitor: allows to monitor in several netns
+
+    With this patch, it's now possible to listen in all netns that have an nsid
+    assigned into the netns where the socket is opened.
+
+    Signed-off-by: Nicolas Dichtel <nicolas.dichtel@6wind.com>
+
+commit b6ec53e3008aaf2acc3db146e24bc9a365e4b6c2
+Author: Nicolas Dichtel <nicolas.dichtel@6wind.com>
+Date:   Wed May 20 16:20:01 2015 +0200
+
+    xfrmmonitor: allows to monitor in several netns
+
+    With this patch, it's now possible to listen in all netns that have an nsid
+    assigned into the netns where is socket is opened.
+
+    Signed-off-by: Nicolas Dichtel <nicolas.dichtel@6wind.com>
+
+There were multiple conflicts to resolve due to the following missing commits:
+- c16298b ip xfrm mon: Add objects list to the usage output
+- 2271779 ip monitor: Dont print timestamp or banner-label for cloned routes
+- 0018565 add ability to filter neighbour discovery by protocol
+- 488c41d ip: Add label option to ip monitor
+- e557212 netlink: extend buffers to 16K
+- 093b764 ip monitor: Allow to filter events by dev
+---
+ bridge/monitor.c        |  1 +
+ genl/ctrl.c             | 17 ++++++++++-----
+ include/libnetlink.h    | 15 +++++++++++--
+ include/linux/netlink.h |  1 +
+ ip/ip_common.h          |  1 +
+ ip/ipaddress.c          |  8 +++++--
+ ip/iplink.c             |  1 +
+ ip/ipmonitor.c          | 58 ++++++++++++++++++++++++++++++-------------------
+ ip/ipnetconf.c          | 11 ++++++++--
+ ip/ipnetns.c            |  1 +
+ ip/iproute.c            |  9 +++++---
+ ip/rtmon.c              | 12 +++++++---
+ ip/xfrm_monitor.c       | 15 ++++++++++++-
+ lib/libnetlink.c        | 49 +++++++++++++++++++++++++++++++++++++----
+ man/man3/libnetlink.3   |  7 +++---
+ man/man8/ip-monitor.8   | 36 ++++++++++++++++++++++++++++++
+ man/man8/ip-xfrm.8      | 21 +++++++++++++++++-
+ tc/tc_monitor.c         |  1 +
+ 18 files changed, 216 insertions(+), 48 deletions(-)
+
+diff --git a/bridge/monitor.c b/bridge/monitor.c
+index 76e7d47..82cdff0 100644
+--- a/bridge/monitor.c
++++ b/bridge/monitor.c
+@@ -47,6 +47,7 @@ static int show_mark(FILE *fp, const struct nlmsghdr *n)
+ }
+ 
+ static int accept_msg(const struct sockaddr_nl *who,
++		      struct rtnl_ctrl_data *ctrl,
+ 		      struct nlmsghdr *n, void *arg)
+ {
+ 	FILE *fp = arg;
+diff --git a/genl/ctrl.c b/genl/ctrl.c
+index 7c42578..48cbc35 100644
+--- a/genl/ctrl.c
++++ b/genl/ctrl.c
+@@ -177,8 +177,9 @@ static int print_ctrl_grp(FILE *fp, struct rtattr *arg, __u32 ctrl_ver)
+ /*
+  * The controller sends one nlmsg per family
+ */
+-static int print_ctrl(const struct sockaddr_nl *who, struct nlmsghdr *n,
+-		      void *arg)
++static int print_ctrl(const struct sockaddr_nl *who,
++		      struct rtnl_ctrl_data *ctrl,
++		      struct nlmsghdr *n, void *arg)
+ {
+ 	struct rtattr *tb[CTRL_ATTR_MAX + 1];
+ 	struct genlmsghdr *ghdr = NLMSG_DATA(n);
+@@ -281,6 +282,12 @@ static int print_ctrl(const struct sockaddr_nl *who, struct nlmsghdr *n,
+ 	return 0;
+ }
+ 
++static int print_ctrl2(const struct sockaddr_nl *who,
++		      struct nlmsghdr *n, void *arg)
++{
++	return print_ctrl(who, NULL, n, arg);
++}
++
+ static int ctrl_list(int cmd, int argc, char **argv)
+ {
+ 	struct rtnl_handle rth;
+@@ -339,7 +346,7 @@ static int ctrl_list(int cmd, int argc, char **argv)
+ 			goto ctrl_done;
+ 		}
+ 
+-		if (print_ctrl(NULL, nlh, (void *) stdout) < 0) {
++		if (print_ctrl2(NULL, nlh, (void *) stdout) < 0) {
+ 			fprintf(stderr, "Dump terminated\n");
+ 			goto ctrl_done;
+ 		}
+@@ -355,7 +362,7 @@ static int ctrl_list(int cmd, int argc, char **argv)
+ 			goto ctrl_done;
+ 		}
+ 
+-		rtnl_dump_filter(&rth, print_ctrl, stdout);
++		rtnl_dump_filter(&rth, print_ctrl2, stdout);
+ 
+         }
+ 
+@@ -408,5 +415,5 @@ static int parse_ctrl(struct genl_util *a, int argc, char **argv)
+ struct genl_util ctrl_genl_util = {
+ 	.name = "ctrl",
+ 	.parse_genlopt = parse_ctrl,
+-	.print_genlopt = print_ctrl,
++	.print_genlopt = print_ctrl2,
+ };
+diff --git a/include/libnetlink.h b/include/libnetlink.h
+index 5dcc0c3..ae93336 100644
+--- a/include/libnetlink.h
++++ b/include/libnetlink.h
+@@ -19,6 +19,8 @@ struct rtnl_handle
+ 	__u32			seq;
+ 	__u32			dump;
+ 	FILE		       *dump_fp;
++#define RTNL_HANDLE_F_LISTEN_ALL_NSID		0x01
++	int			flags;
+ };
+ 
+ extern int rcvbuf;
+@@ -31,9 +33,17 @@ extern int rtnl_wilddump_req_filter(struct rtnl_handle *rth, int fam, int type,
+ 				    __u32 filt_mask);
+ extern int rtnl_dump_request(struct rtnl_handle *rth, int type, void *req, int len);
+ 
++struct rtnl_ctrl_data {
++	int	nsid;
++};
++
+ typedef int (*rtnl_filter_t)(const struct sockaddr_nl *,
+ 			     struct nlmsghdr *n, void *);
+ 
++typedef int (*rtnl_listen_filter_t)(const struct sockaddr_nl *,
++				    struct rtnl_ctrl_data *,
++				    struct nlmsghdr *n, void *);
++
+ struct rtnl_dump_filter_arg
+ {
+ 	rtnl_filter_t filter;
+@@ -105,9 +115,10 @@ static inline const char *rta_getattr_str(const struct rtattr *rta)
+ 	return (const char *)RTA_DATA(rta);
+ }
+ 
+-extern int rtnl_listen(struct rtnl_handle *, rtnl_filter_t handler,
++extern int rtnl_listen_all_nsid(struct rtnl_handle *);
++extern int rtnl_listen(struct rtnl_handle *, rtnl_listen_filter_t handler,
+ 		       void *jarg);
+-extern int rtnl_from_file(FILE *, rtnl_filter_t handler,
++extern int rtnl_from_file(FILE *, rtnl_listen_filter_t handler,
+ 		       void *jarg);
+ 
+ #define NLMSG_TAIL(nmsg) \
+diff --git a/include/linux/netlink.h b/include/linux/netlink.h
+index e0a09df..0c89ddd 100644
+--- a/include/linux/netlink.h
++++ b/include/linux/netlink.h
+@@ -108,6 +108,7 @@ struct nlmsgerr {
+ #define NETLINK_NO_ENOBUFS	5
+ #define NETLINK_RX_RING		6
+ #define NETLINK_TX_RING		7
++#define NETLINK_LISTEN_ALL_NSID	8
+ 
+ struct nl_pktinfo {
+ 	__u32	group;
+diff --git a/ip/ip_common.h b/ip/ip_common.h
+index 85529f0..bd36924 100644
+--- a/ip/ip_common.h
++++ b/ip/ip_common.h
+@@ -29,6 +29,7 @@ extern int print_prefix(const struct sockaddr_nl *who,
+ extern int print_rule(const struct sockaddr_nl *who,
+ 		      struct nlmsghdr *n, void *arg);
+ extern int print_netconf(const struct sockaddr_nl *who,
++			 struct rtnl_ctrl_data *ctrl,
+ 			 struct nlmsghdr *n, void *arg);
+ extern void netns_map_init(void);
+ extern int print_nsid(const struct sockaddr_nl *who,
+diff --git a/ip/ipaddress.c b/ip/ipaddress.c
+index 4650a2e..30fda4f 100644
+--- a/ip/ipaddress.c
++++ b/ip/ipaddress.c
+@@ -1007,7 +1007,9 @@ static int save_nlmsg(const struct sockaddr_nl *who, struct nlmsghdr *n,
+ 	return ret == n->nlmsg_len ? 0 : ret;
+ }
+ 
+-static int show_handler(const struct sockaddr_nl *nl, struct nlmsghdr *n, void *arg)
++static int show_handler(const struct sockaddr_nl *nl,
++			struct rtnl_ctrl_data *ctrl,
++			struct nlmsghdr *n, void *arg)
+ {
+ 	struct ifaddrmsg *ifa = NLMSG_DATA(n);
+ 
+@@ -1024,7 +1026,9 @@ static int ipaddr_showdump(void)
+ 	exit(rtnl_from_file(stdin, &show_handler, NULL));
+ }
+ 
+-static int restore_handler(const struct sockaddr_nl *nl, struct nlmsghdr *n, void *arg)
++static int restore_handler(const struct sockaddr_nl *nl,
++			   struct rtnl_ctrl_data *ctrl,
++			   struct nlmsghdr *n, void *arg)
+ {
+ 	int ret;
+ 
+diff --git a/ip/iplink.c b/ip/iplink.c
+index e47cbdd..86ea23e 100644
+--- a/ip/iplink.c
++++ b/ip/iplink.c
+@@ -163,6 +163,7 @@ static int get_addr_gen_mode(const char *mode)
+ static int have_rtnl_newlink = -1;
+ 
+ static int accept_msg(const struct sockaddr_nl *who,
++		      struct rtnl_ctrl_data *ctrl,
+ 		      struct nlmsghdr *n, void *arg)
+ {
+ 	struct nlmsgerr *err = (struct nlmsgerr *)NLMSG_DATA(n);
+diff --git a/ip/ipmonitor.c b/ip/ipmonitor.c
+index 148cf1e..131b6ac 100644
+--- a/ip/ipmonitor.c
++++ b/ip/ipmonitor.c
+@@ -26,18 +26,36 @@
+ 
+ static void usage(void) __attribute__((noreturn));
+ int prefix_banner;
++int listen_all_nsid;
+ 
+ static void usage(void)
+ {
+-	fprintf(stderr, "Usage: ip monitor [ all | LISTofOBJECTS ] [ FILE ]\n");
++	fprintf(stderr, "Usage: ip monitor [ all | LISTofOBJECTS ] [ FILE ] "
++			"[all-nsid] [dev DEVICE]\n");
+ 	fprintf(stderr, "LISTofOBJECTS := link | address | route | mroute | prefix |\n");
+ 	fprintf(stderr, "                 neigh | netconf | nsid\n");
+ 	fprintf(stderr, "FILE := file FILENAME\n");
+ 	exit(-1);
+ }
+ 
++static void print_headers(FILE *fp, char *label, struct rtnl_ctrl_data *ctrl)
++{
++	if (timestamp)
++		print_timestamp(fp);
++
++	if (listen_all_nsid) {
++		if (ctrl == NULL || ctrl->nsid < 0)
++			fprintf(fp, "[nsid current]");
++		else
++			fprintf(fp, "[nsid %d]", ctrl->nsid);
++	}
++
++	if (prefix_banner)
++		fprintf(fp, "%s", label);
++}
+ 
+ static int accept_msg(const struct sockaddr_nl *who,
++		      struct rtnl_ctrl_data *ctrl,
+ 		      struct nlmsghdr *n, void *arg)
+ {
+ 	FILE *fp = (FILE*)arg;
+@@ -56,59 +74,51 @@ static int accept_msg(const struct sockaddr_nl *who,
+ 
+ 		if (r->rtm_family == RTNL_FAMILY_IPMR ||
+ 		    r->rtm_family == RTNL_FAMILY_IP6MR) {
+-			if (prefix_banner)
+-				fprintf(fp, "[MROUTE]");
++			print_headers(fp, "[MROUTE]", ctrl);
+ 			print_mroute(who, n, arg);
+ 			return 0;
+ 		} else {
+-			if (prefix_banner)
+-				fprintf(fp, "[ROUTE]");
++			print_headers(fp, "[ROUTE]", ctrl);
+ 			print_route(who, n, arg);
+ 			return 0;
+ 		}
+ 	}
++
+ 	if (n->nlmsg_type == RTM_NEWLINK || n->nlmsg_type == RTM_DELLINK) {
+ 		ll_remember_index(who, n, NULL);
+-		if (prefix_banner)
+-			fprintf(fp, "[LINK]");
++		print_headers(fp, "[LINK]", ctrl);
+ 		print_linkinfo(who, n, arg);
+ 		return 0;
+ 	}
+ 	if (n->nlmsg_type == RTM_NEWADDR || n->nlmsg_type == RTM_DELADDR) {
+-		if (prefix_banner)
+-			fprintf(fp, "[ADDR]");
++		print_headers(fp, "[ADDR]", ctrl);
+ 		print_addrinfo(who, n, arg);
+ 		return 0;
+ 	}
+ 	if (n->nlmsg_type == RTM_NEWADDRLABEL || n->nlmsg_type == RTM_DELADDRLABEL) {
+-		if (prefix_banner)
+-			fprintf(fp, "[ADDRLABEL]");
++		print_headers(fp, "[ADDRLABEL]", ctrl);
+ 		print_addrlabel(who, n, arg);
+ 		return 0;
+ 	}
+ 	if (n->nlmsg_type == RTM_NEWNEIGH || n->nlmsg_type == RTM_DELNEIGH ||
+ 	    n->nlmsg_type == RTM_GETNEIGH) {
+-		if (prefix_banner)
+-			fprintf(fp, "[NEIGH]");
++		print_headers(fp, "[NEIGH]", ctrl);
+ 		print_neigh(who, n, arg);
+ 		return 0;
+ 	}
+ 	if (n->nlmsg_type == RTM_NEWPREFIX) {
+-		if (prefix_banner)
+-			fprintf(fp, "[PREFIX]");
++		print_headers(fp, "[PREFIX]", ctrl);
+ 		print_prefix(who, n, arg);
+ 		return 0;
+ 	}
+ 	if (n->nlmsg_type == RTM_NEWRULE || n->nlmsg_type == RTM_DELRULE) {
+-		if (prefix_banner)
+-			fprintf(fp, "[RULE]");
++		print_headers(fp, "[RULE]", ctrl);
+ 		print_rule(who, n, arg);
+ 		return 0;
+ 	}
+ 	if (n->nlmsg_type == RTM_NEWNETCONF) {
+-		if (prefix_banner)
+-			fprintf(fp, "[NETCONF]");
+-		print_netconf(who, n, arg);
++		print_headers(fp, "[NETCONF]", ctrl);
++		print_netconf(who, ctrl, n, arg);
+ 		return 0;
+ 	}
+ 	if (n->nlmsg_type == 15) {
+@@ -128,8 +138,7 @@ static int accept_msg(const struct sockaddr_nl *who,
+ 	    n->nlmsg_type == RTM_DELTFILTER)
+ 		return 0;
+ 	if (n->nlmsg_type == RTM_NEWNSID || n->nlmsg_type == RTM_DELNSID) {
+-		if (prefix_banner)
+-			fprintf(fp, "[NSID]");
++		print_headers(fp, "[NSID]", ctrl);
+ 		print_nsid(who, n, arg);
+ 		return 0;
+ 	}
+@@ -166,6 +175,8 @@ int do_ipmonitor(int argc, char **argv)
+ 		if (matches(*argv, "file") == 0) {
+ 			NEXT_ARG();
+ 			file = *argv;
++		} else if (matches(*argv, "all-nsid") == 0) {
++			listen_all_nsid = 1;
+ 		} else if (matches(*argv, "link") == 0) {
+ 			llink=1;
+ 			groups = 0;
+@@ -250,6 +261,9 @@ int do_ipmonitor(int argc, char **argv)
+ 
+ 	if (rtnl_open(&rth, groups) < 0)
+ 		exit(1);
++	if (listen_all_nsid && rtnl_listen_all_nsid(&rth) < 0)
++		exit(1);
++
+ 	ll_init_map(&rth);
+ 	netns_map_init();
+ 
+diff --git a/ip/ipnetconf.c b/ip/ipnetconf.c
+index 9a77ecb..8e42132 100644
+--- a/ip/ipnetconf.c
++++ b/ip/ipnetconf.c
+@@ -40,7 +40,8 @@ static void usage(void)
+ 
+ #define NETCONF_RTA(r)	((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct netconfmsg))))
+ 
+-int print_netconf(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
++int print_netconf(const struct sockaddr_nl *who, struct rtnl_ctrl_data *ctrl,
++		  struct nlmsghdr *n, void *arg)
+ {
+ 	FILE *fp = (FILE*)arg;
+ 	struct netconfmsg *ncm = NLMSG_DATA(n);
+@@ -119,6 +120,12 @@ int print_netconf(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
+ 	return 0;
+ }
+ 
++static int print_netconf2(const struct sockaddr_nl *who,
++			  struct nlmsghdr *n, void *arg)
++{
++	return print_netconf(who, NULL, n, arg);
++}
++
+ static void ipnetconf_reset_filter(void)
+ {
+ 	memset(&filter, 0, sizeof(filter));
+@@ -169,7 +176,7 @@ dump:
+ 			perror("Cannot send dump request");
+ 			exit(1);
+ 		}
+-		if (rtnl_dump_filter(&rth, print_netconf, stdout) < 0) {
++		if (rtnl_dump_filter(&rth, print_netconf2, stdout) < 0) {
+ 			fprintf(stderr, "Dump terminated\n");
+ 			exit(1);
+ 		}
+diff --git a/ip/ipnetns.c b/ip/ipnetns.c
+index 438d59b..019f954 100644
+--- a/ip/ipnetns.c
++++ b/ip/ipnetns.c
+@@ -43,6 +43,7 @@ static struct rtnl_handle rtnsh = { .fd = -1 };
+ static int have_rtnl_getnsid = -1;
+ 
+ static int ipnetns_accept_msg(const struct sockaddr_nl *who,
++			      struct rtnl_ctrl_data *ctrl,
+ 			      struct nlmsghdr *n, void *arg)
+ {
+ 	struct nlmsgerr *err = (struct nlmsgerr *)NLMSG_DATA(n);
+diff --git a/ip/iproute.c b/ip/iproute.c
+index 207301c..20980ab 100644
+--- a/ip/iproute.c
++++ b/ip/iproute.c
+@@ -1539,8 +1539,9 @@ static int iproute_get(int argc, char **argv)
+ 	exit(0);
+ }
+ 
+-static int restore_handler(const struct sockaddr_nl *nl, struct nlmsghdr *n,
+-			   void *arg)
++static int restore_handler(const struct sockaddr_nl *nl,
++			   struct rtnl_ctrl_data *ctrl,
++			   struct nlmsghdr *n, void *arg)
+ {
+ 	int ret;
+ 
+@@ -1582,7 +1583,9 @@ static int iproute_restore(void)
+ 	exit(rtnl_from_file(stdin, &restore_handler, NULL));
+ }
+ 
+-static int show_handler(const struct sockaddr_nl *nl, struct nlmsghdr *n, void *arg)
++static int show_handler(const struct sockaddr_nl *nl,
++			struct rtnl_ctrl_data *ctrl,
++			struct nlmsghdr *n, void *arg)
+ {
+ 	print_route(nl, n, stdout);
+ 	return 0;
+diff --git a/ip/rtmon.c b/ip/rtmon.c
+index 9227eac..5094d22 100644
+--- a/ip/rtmon.c
++++ b/ip/rtmon.c
+@@ -45,8 +45,8 @@ static void write_stamp(FILE *fp)
+ 	fwrite((void*)n1, 1, NLMSG_ALIGN(n1->nlmsg_len), fp);
+ }
+ 
+-static int dump_msg(const struct sockaddr_nl *who, struct nlmsghdr *n,
+-		    void *arg)
++static int dump_msg(const struct sockaddr_nl *who, struct rtnl_ctrl_data *ctrl,
++		    struct nlmsghdr *n, void *arg)
+ {
+ 	FILE *fp = (FILE*)arg;
+ 	if (!init_phase)
+@@ -56,6 +56,12 @@ static int dump_msg(const struct sockaddr_nl *who, struct nlmsghdr *n,
+ 	return 0;
+ }
+ 
++static int dump_msg2(const struct sockaddr_nl *who,
++		     struct nlmsghdr *n, void *arg)
++{
++	return dump_msg(who, NULL, n, arg);
++}
++
+ static void usage(void)
+ {
+ 	fprintf(stderr, "Usage: rtmon file FILE [ all | LISTofOBJECTS]\n");
+@@ -163,7 +169,7 @@ main(int argc, char **argv)
+ 
+ 	write_stamp(fp);
+ 
+-	if (rtnl_dump_filter(&rth, dump_msg, fp) < 0) {
++	if (rtnl_dump_filter(&rth, dump_msg2, fp) < 0) {
+ 		fprintf(stderr, "Dump terminated\n");
+ 		return 1;
+ 	}
+diff --git a/ip/xfrm_monitor.c b/ip/xfrm_monitor.c
+index 292193e..228aaf2 100644
+--- a/ip/xfrm_monitor.c
++++ b/ip/xfrm_monitor.c
+@@ -36,10 +36,11 @@
+ #include "ip_common.h"
+ 
+ static void usage(void) __attribute__((noreturn));
++int listen_all_nsid;
+ 
+ static void usage(void)
+ {
+-	fprintf(stderr, "Usage: ip xfrm monitor [ all | LISTofXFRM-OBJECTS ]\n");
++	fprintf(stderr, "Usage: ip xfrm monitor [all-nsid] [ all | LISTofXFRM-OBJECTS ]\n");
+ 	exit(-1);
+ }
+ 
+@@ -291,6 +292,7 @@ static int xfrm_mapping_print(const struct sockaddr_nl *who,
+ }
+ 
+ static int xfrm_accept_msg(const struct sockaddr_nl *who,
++			   struct rtnl_ctrl_data *ctrl,
+ 			   struct nlmsghdr *n, void *arg)
+ {
+ 	FILE *fp = (FILE*)arg;
+@@ -298,6 +300,13 @@ static int xfrm_accept_msg(const struct sockaddr_nl *who,
+ 	if (timestamp)
+ 		print_timestamp(fp);
+ 
++	if (listen_all_nsid) {
++		if (ctrl == NULL || ctrl->nsid < 0)
++			fprintf(fp, "[nsid current]");
++		else
++			fprintf(fp, "[nsid %d]", ctrl->nsid);
++	}
++
+ 	switch (n->nlmsg_type) {
+ 	case XFRM_MSG_NEWSA:
+ 	case XFRM_MSG_DELSA:
+@@ -360,6 +369,8 @@ int do_xfrm_monitor(int argc, char **argv)
+ 		if (matches(*argv, "file") == 0) {
+ 			NEXT_ARG();
+ 			file = *argv;
++		} else if (matches(*argv, "all-nsid") == 0) {
++			listen_all_nsid = 1;
+ 		} else if (matches(*argv, "acquire") == 0) {
+ 			lacquire=1;
+ 			groups = 0;
+@@ -412,6 +423,8 @@ int do_xfrm_monitor(int argc, char **argv)
+ 
+ 	if (rtnl_open_byproto(&rth, groups, NETLINK_XFRM) < 0)
+ 		exit(1);
++	if (listen_all_nsid && rtnl_listen_all_nsid(&rth) < 0)
++		exit(1);
+ 
+ 	if (rtnl_listen(&rth, xfrm_accept_msg, (void*)stdout) < 0)
+ 		exit(2);
+diff --git a/lib/libnetlink.c b/lib/libnetlink.c
+index baac6ae..0a989f4 100644
+--- a/lib/libnetlink.c
++++ b/lib/libnetlink.c
+@@ -25,6 +25,10 @@
+ 
+ #include "libnetlink.h"
+ 
++#ifndef SOL_NETLINK
++#define SOL_NETLINK 270
++#endif
++
+ int rcvbuf = 1024 * 1024;
+ 
+ void rtnl_close(struct rtnl_handle *rth)
+@@ -406,8 +410,21 @@ int rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n, pid_t peer,
+ 	}
+ }
+ 
++int rtnl_listen_all_nsid(struct rtnl_handle *rth)
++{
++	unsigned int on = 1;
++
++	if (setsockopt(rth->fd, SOL_NETLINK, NETLINK_LISTEN_ALL_NSID, &on,
++		       sizeof(on)) < 0) {
++		perror("NETLINK_LISTEN_ALL_NSID");
++		return -1;
++	}
++	rth->flags |= RTNL_HANDLE_F_LISTEN_ALL_NSID;
++	return 0;
++}
++
+ int rtnl_listen(struct rtnl_handle *rtnl,
+-		rtnl_filter_t handler,
++		rtnl_listen_filter_t handler,
+ 		void *jarg)
+ {
+ 	int status;
+@@ -421,6 +438,12 @@ int rtnl_listen(struct rtnl_handle *rtnl,
+ 		.msg_iovlen = 1,
+ 	};
+ 	char   buf[8192];
++	char   cmsgbuf[BUFSIZ];
++
++	if (rtnl->flags & RTNL_HANDLE_F_LISTEN_ALL_NSID) {
++		msg.msg_control = &cmsgbuf;
++		msg.msg_controllen = sizeof(cmsgbuf);
++	}
+ 
+ 	memset(&nladdr, 0, sizeof(nladdr));
+ 	nladdr.nl_family = AF_NETLINK;
+@@ -429,6 +452,9 @@ int rtnl_listen(struct rtnl_handle *rtnl,
+ 
+ 	iov.iov_base = buf;
+ 	while (1) {
++		struct rtnl_ctrl_data ctrl;
++		struct cmsghdr *cmsg;
++
+ 		iov.iov_len = sizeof(buf);
+ 		status = recvmsg(rtnl->fd, &msg, 0);
+ 
+@@ -449,6 +475,21 @@ int rtnl_listen(struct rtnl_handle *rtnl,
+ 			fprintf(stderr, "Sender address length == %d\n", msg.msg_namelen);
+ 			exit(1);
+ 		}
++
++		if (rtnl->flags & RTNL_HANDLE_F_LISTEN_ALL_NSID) {
++			memset(&ctrl, 0, sizeof(ctrl));
++			ctrl.nsid = -1;
++			for (cmsg = CMSG_FIRSTHDR(&msg); cmsg;
++			     cmsg = CMSG_NXTHDR(&msg, cmsg))
++				if (cmsg->cmsg_level == SOL_NETLINK &&
++				    cmsg->cmsg_type == NETLINK_LISTEN_ALL_NSID &&
++				    cmsg->cmsg_len == CMSG_LEN(sizeof(int))) {
++					int *data = (int *)CMSG_DATA(cmsg);
++
++					ctrl.nsid = *data;
++				}
++		}
++
+ 		for (h = (struct nlmsghdr*)buf; status >= sizeof(*h); ) {
+ 			int err;
+ 			int len = h->nlmsg_len;
+@@ -463,7 +504,7 @@ int rtnl_listen(struct rtnl_handle *rtnl,
+ 				exit(1);
+ 			}
+ 
+-			err = handler(&nladdr, h, jarg);
++			err = handler(&nladdr, &ctrl, h, jarg);
+ 			if (err < 0)
+ 				return err;
+ 
+@@ -481,7 +522,7 @@ int rtnl_listen(struct rtnl_handle *rtnl,
+ 	}
+ }
+ 
+-int rtnl_from_file(FILE *rtnl, rtnl_filter_t handler,
++int rtnl_from_file(FILE *rtnl, rtnl_listen_filter_t handler,
+ 		   void *jarg)
+ {
+ 	int status;
+@@ -529,7 +570,7 @@ int rtnl_from_file(FILE *rtnl, rtnl_filter_t handler,
+ 			return -1;
+ 		}
+ 
+-		err = handler(&nladdr, h, jarg);
++		err = handler(&nladdr, NULL, h, jarg);
+ 		if (err < 0)
+ 			return err;
+ 	}
+diff --git a/man/man3/libnetlink.3 b/man/man3/libnetlink.3
+index e999bd6..99be9cc 100644
+--- a/man/man3/libnetlink.3
++++ b/man/man3/libnetlink.3
+@@ -33,7 +33,8 @@ int rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n, pid_t peer,
+ 	      void *jarg)
+ .sp
+ int rtnl_listen(struct rtnl_handle *rtnl, 
+-	      int (*handler)(struct sockaddr_nl *,struct nlmsghdr *n, void *),
++	      int (*handler)(struct sockaddr_nl *, struct rtnl_ctrl_data *,
++			     struct nlmsghdr *n, void *),
+ 	      void *jarg)
+ .sp
+ int rtnl_from_file(FILE *rtnl, 
+@@ -108,8 +109,8 @@ rtnl_listen
+ Receive netlink data after a request and pass it to 
+ .I handler.
+ .B handler
+-is a callback that gets the message source address, the message itself,
+-and the
++is a callback that gets the message source address, anscillary data, the message
++itself, and the
+ .B jarg
+ cookie as arguments. It will get called for all received messages.
+ Only one message bundle is received. If there is a message
+diff --git a/man/man8/ip-monitor.8 b/man/man8/ip-monitor.8
+index a710b34..91099f8 100644
+--- a/man/man8/ip-monitor.8
++++ b/man/man8/ip-monitor.8
+@@ -11,6 +11,10 @@ ip-monitor, rtmon \- state monitoring
+ .BR  "monitor" " [ " all " |"
+ .IR OBJECT-LIST " ] ["
+ .BI file " FILENAME "
++] [
++.BI label
++] [
++.BI all-nsid
+ ]
+ .sp
+ 
+@@ -26,6 +30,10 @@ command is the first in the command line and then the object list follows:
+ .BR "ip monitor" " [ " all " |"
+ .IR OBJECT-LIST " ] ["
+ .BI file " FILENAME "
++] [
++.BI label
++] [
++.BI all-nsid
+ ]
+ 
+ .I OBJECT-LIST
+@@ -42,6 +50,32 @@ described in previous sections.
+ 
+ .P
+ If the
++.BI label
++option is set, a prefix is displayed before each message to
++show the family of the message. For example:
++.sp
++.in +2
++[NEIGH]10.16.0.112 dev eth0 lladdr 00:04:23:df:2f:d0 REACHABLE
++[LINK]3: eth1: <BROADCAST,MULTICAST> mtu 1500 qdisc pfifo_fast state DOWN group default
++    link/ether 52:54:00:12:34:57 brd ff:ff:ff:ff:ff:ff
++.in -2
++.sp
++
++.P
++If the
++.BI all-nsid
++option is set, the program listens to all network namespaces that have a
++nsid assigned into the network namespace were the program is running.
++A prefix is displayed to show the network namespace where the message
++originates. Example:
++.sp
++.in +2
++[nsid 0]10.16.0.112 dev eth0 lladdr 00:04:23:df:2f:d0 REACHABLE
++.in -2
++.sp
++
++.P
++If the
+ .BI file
+ option is given, the program does not listen on RTNETLINK,
+ but opens the given file, and dumps its contents. The file
+@@ -75,3 +109,5 @@ of starting.
+ 
+ .SH AUTHOR
+ Original Manpage by Michail Litvak <mci@owl.openwall.com>
++.br
++Manpage revised by Nicolas Dichtel <nicolas.dichtel@6wind.com>
+diff --git a/man/man8/ip-xfrm.8 b/man/man8/ip-xfrm.8
+index e305c0b..aea4fda 100644
+--- a/man/man8/ip-xfrm.8
++++ b/man/man8/ip-xfrm.8
+@@ -359,7 +359,11 @@ ip-xfrm \- transform configuration
+ .BR required " | " use
+ 
+ .ti -8
+-.BR "ip xfrm monitor" " [ " all " |"
++.BR "ip xfrm monitor" " ["
++.BI all-nsid
++] [
++.BI all
++ |
+ .IR LISTofXFRM-OBJECTS " ]"
+ 
+ .ti -8
+@@ -664,7 +668,22 @@ ip xfrm monitor 	state monitoring for xfrm objects
+ .PP
+ The xfrm objects to monitor can be optionally specified.
+ 
++.P
++If the
++.BI all-nsid
++option is set, the program listens to all network namespaces that have a
++nsid assigned into the network namespace were the program is running.
++A prefix is displayed to show the network namespace where the message
++originates. Example:
++.sp
++.in +2
++[nsid 1]Flushed state proto 0
++.in -2
++.sp
++
+ .SH AUTHOR
+ Manpage revised by David Ward <david.ward@ll.mit.edu>
+ .br
+ Manpage revised by Christophe Gouault <christophe.gouault@6wind.com>
++.br
++Manpage revised by Nicolas Dichtel <nicolas.dichtel@6wind.com>
+diff --git a/tc/tc_monitor.c b/tc/tc_monitor.c
+index 0efe034..cae3616 100644
+--- a/tc/tc_monitor.c
++++ b/tc/tc_monitor.c
+@@ -36,6 +36,7 @@ static void usage(void)
+ 
+ 
+ static int accept_tcmsg(const struct sockaddr_nl *who,
++			struct rtnl_ctrl_data *ctrl,
+ 			struct nlmsghdr *n, void *arg)
+ {
+ 	FILE *fp = (FILE*)arg;
+-- 
+1.8.3.1
+
diff --git a/SOURCES/iproute2-3.10.0-ipadress-fix-display-of-IPv6-peer-address.patch b/SOURCES/iproute2-3.10.0-ipadress-fix-display-of-IPv6-peer-address.patch
deleted file mode 100644
index f59e8b2..0000000
--- a/SOURCES/iproute2-3.10.0-ipadress-fix-display-of-IPv6-peer-address.patch
+++ /dev/null
@@ -1,14 +0,0 @@
-diff --git a/ip/ipaddress.c b/ip/ipaddress.c
-index 5b9a438..2b3707a 100644
---- a/ip/ipaddress.c
-+++ b/ip/ipaddress.c
-@@ -613,7 +613,8 @@ int print_addrinfo(const struct sockaddr_nl *who, struct nlmsghdr *n,
- 					      abuf, sizeof(abuf)));
- 
- 		if (rta_tb[IFA_ADDRESS] == NULL ||
--		    memcmp(RTA_DATA(rta_tb[IFA_ADDRESS]), RTA_DATA(rta_tb[IFA_LOCAL]), 4) == 0) {
-+		    memcmp(RTA_DATA(rta_tb[IFA_ADDRESS]), RTA_DATA(rta_tb[IFA_LOCAL]),
-+			   ifa->ifa_family == AF_INET ? 4 : 16) == 0) {
- 			fprintf(fp, "/%d ", ifa->ifa_prefixlen);
- 		} else {
- 			fprintf(fp, " peer %s/%d ",
diff --git a/SOURCES/iproute2-3.10.0-lib.patch b/SOURCES/iproute2-3.10.0-lib.patch
new file mode 100644
index 0000000..2c97fe9
--- /dev/null
+++ b/SOURCES/iproute2-3.10.0-lib.patch
@@ -0,0 +1,505 @@
+commit f389090cd1dc2f9945c19f837ade98bd733015cb
+Author: Pavel Šimerda <psimerda@redhat.com>
+Date:   Thu May 28 23:39:22 2015 +0200
+
+    backport selected library functions
+
+diff --git a/include/libnetlink.h b/include/libnetlink.h
+index ec3d657..5dcc0c3 100644
+--- a/include/libnetlink.h
++++ b/include/libnetlink.h
+@@ -18,6 +18,7 @@ struct rtnl_handle
+ 	struct sockaddr_nl	peer;
+ 	__u32			seq;
+ 	__u32			dump;
++	FILE		       *dump_fp;
+ };
+ 
+ extern int rcvbuf;
+@@ -68,11 +69,15 @@ extern int parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int le
+ extern int parse_rtattr_flags(struct rtattr *tb[], int max, struct rtattr *rta,
+ 			      int len, unsigned short flags);
+ extern int parse_rtattr_byindex(struct rtattr *tb[], int max, struct rtattr *rta, int len);
++extern struct rtattr *parse_rtattr_one(int type, struct rtattr *rta, int len);
+ extern int __parse_rtattr_nested_compat(struct rtattr *tb[], int max, struct rtattr *rta, int len);
+ 
+ #define parse_rtattr_nested(tb, max, rta) \
+ 	(parse_rtattr((tb), (max), RTA_DATA(rta), RTA_PAYLOAD(rta)))
+ 
++#define parse_rtattr_one_nested(type, rta) \
++	(parse_rtattr_one(type, RTA_DATA(rta), RTA_PAYLOAD(rta)))
++
+ #define parse_rtattr_nested_compat(tb, max, rta, data, len) \
+ 	({ data = RTA_PAYLOAD(rta) >= len ? RTA_DATA(rta) : NULL;	\
+ 		__parse_rtattr_nested_compat(tb, max, rta, len); })
+@@ -140,5 +145,17 @@ extern int rtnl_from_file(FILE *, rtnl_filter_t handler,
+ #define NDTA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ndtmsg))
+ #endif
+ 
++#ifndef NETNS_RTA
++#define NETNS_RTA(r) \
++	((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct rtgenmsg))))
++#endif
++#ifndef NETNS_PAYLOAD
++#define NETNS_PAYLOAD(n)	NLMSG_PAYLOAD(n,sizeof(struct rtgenmsg))
++#endif
++
++/* User defined nlmsg_type which is used mostly for logging netlink
++ * messages from dump file */
++#define NLMSG_TSTAMP	15
++
+ #endif /* __LIBNETLINK_H__ */
+ 
+diff --git a/include/namespace.h b/include/namespace.h
+new file mode 100644
+index 0000000..a2ac7dc
+--- /dev/null
++++ b/include/namespace.h
+@@ -0,0 +1,54 @@
++#ifndef __NAMESPACE_H__
++#define __NAMESPACE_H__ 1
++
++#include <sched.h>
++#include <sys/mount.h>
++#include <sys/syscall.h>
++#include <errno.h>
++
++#define NETNS_RUN_DIR "/var/run/netns"
++#define NETNS_ETC_DIR "/etc/netns"
++
++#ifndef CLONE_NEWNET
++#define CLONE_NEWNET 0x40000000	/* New network namespace (lo, device, names sockets, etc) */
++#endif
++
++#ifndef MNT_DETACH
++#define MNT_DETACH	0x00000002	/* Just detach from the tree */
++#endif /* MNT_DETACH */
++
++/* sys/mount.h may be out too old to have these */
++#ifndef MS_REC
++#define MS_REC		16384
++#endif
++
++#ifndef MS_SLAVE
++#define MS_SLAVE	(1 << 19)
++#endif
++
++#ifndef MS_SHARED
++#define MS_SHARED	(1 << 20)
++#endif
++
++#ifndef HAVE_SETNS
++static inline int setns(int fd, int nstype)
++{
++#ifdef __NR_setns
++	return syscall(__NR_setns, fd, nstype);
++#else
++	errno = ENOSYS;
++	return -1;
++#endif
++}
++#endif /* HAVE_SETNS */
++
++extern int netns_switch(char *netns);
++extern int netns_get_fd(const char *netns);
++extern int netns_foreach(int (*func)(char *nsname, void *arg), void *arg);
++
++struct netns_func {
++	int (*func)(char *nsname, void *arg);
++	void *arg;
++};
++
++#endif /* __NAMESPACE_H__ */
+diff --git a/include/rt_names.h b/include/rt_names.h
+index 37adbd3..c0ea4f9 100644
+--- a/include/rt_names.h
++++ b/include/rt_names.h
+@@ -8,6 +8,7 @@ const char *rtnl_rtscope_n2a(int id, char *buf, int len);
+ const char *rtnl_rttable_n2a(__u32 id, char *buf, int len);
+ const char *rtnl_rtrealm_n2a(int id, char *buf, int len);
+ const char *rtnl_dsfield_n2a(int id, char *buf, int len);
++const char *rtnl_group_n2a(int id, char *buf, int len);
+ 
+ int rtnl_rtprot_a2n(__u32 *id, const char *arg);
+ int rtnl_rtscope_a2n(__u32 *id, const char *arg);
+@@ -28,5 +29,7 @@ int ll_addr_a2n(char *lladdr, int len, const char *arg);
+ const char * ll_proto_n2a(unsigned short id, char *buf, int len);
+ int ll_proto_a2n(unsigned short *id, const char *buf);
+ 
++const char *nl_proto_n2a(int id, char *buf, int len);
++int nl_proto_a2n(__u32 *id, const char *arg);
+ 
+ #endif
+diff --git a/include/utils.h b/include/utils.h
+index 24ff19f..ca05b02 100644
+--- a/include/utils.h
++++ b/include/utils.h
+@@ -5,12 +5,15 @@
+ #include <asm/types.h>
+ #include <resolv.h>
+ #include <stdlib.h>
++#include <stdbool.h>
+ 
+ #include "libnetlink.h"
+ #include "ll_map.h"
+ #include "rtm_map.h"
+ 
+ extern int preferred_family;
++extern int human_readable;
++extern int use_iec;
+ extern int show_stats;
+ extern int show_details;
+ extern int show_raw;
+@@ -20,6 +23,7 @@ extern int timestamp;
+ extern char * _SL_;
+ extern int max_flush_loops;
+ extern int batch_mode;
++extern bool do_all;
+ 
+ #ifndef IPPROTO_ESP
+ #define IPPROTO_ESP	50
+@@ -151,9 +155,16 @@ int print_timestamp(FILE *fp);
+ extern int cmdlineno;
+ extern ssize_t getcmdline(char **line, size_t *len, FILE *in);
+ extern int makeargs(char *line, char *argv[], int maxargs);
++extern int inet_get_addr(const char *src, __u32 *dst, struct in6_addr *dst6);
+ 
+ struct iplink_req;
+ int iplink_parse(int argc, char **argv, struct iplink_req *req,
+ 		char **name, char **type, char **link, char **dev,
+ 		int *group);
++
++extern int do_each_netns(int (*func)(char *nsname, void *arg), void *arg,
++		bool show_label);
++
++char *int_to_str(int val, char *buf);
++
+ #endif /* __UTILS_H__ */
+diff --git a/lib/Makefile b/lib/Makefile
+index a42b885..66f89f1 100644
+--- a/lib/Makefile
++++ b/lib/Makefile
+@@ -1,8 +1,12 @@
+ include ../Config
+ 
++ifeq ($(IP_CONFIG_SETNS),y)
++	CFLAGS += -DHAVE_SETNS
++endif
++
+ CFLAGS += -fPIC
+ 
+-UTILOBJ=utils.o rt_names.o ll_types.o ll_proto.o ll_addr.o inet_proto.o
++UTILOBJ=utils.o rt_names.o ll_types.o ll_proto.o ll_addr.o inet_proto.o namespace.o
+ 
+ NLOBJ=libgenl.o ll_map.o libnetlink.o
+ 
+diff --git a/lib/namespace.c b/lib/namespace.c
+new file mode 100644
+index 0000000..c03a103
+--- /dev/null
++++ b/lib/namespace.c
+@@ -0,0 +1,123 @@
++/*
++ * namespace.c
++ *
++ *		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.
++ */
++
++#include <fcntl.h>
++#include <dirent.h>
++
++#include "utils.h"
++#include "namespace.h"
++
++static void bind_etc(const char *name)
++{
++	char etc_netns_path[MAXPATHLEN];
++	char netns_name[MAXPATHLEN];
++	char etc_name[MAXPATHLEN];
++	struct dirent *entry;
++	DIR *dir;
++
++	snprintf(etc_netns_path, sizeof(etc_netns_path), "%s/%s", NETNS_ETC_DIR, name);
++	dir = opendir(etc_netns_path);
++	if (!dir)
++		return;
++
++	while ((entry = readdir(dir)) != NULL) {
++		if (strcmp(entry->d_name, ".") == 0)
++			continue;
++		if (strcmp(entry->d_name, "..") == 0)
++			continue;
++		snprintf(netns_name, sizeof(netns_name), "%s/%s", etc_netns_path, entry->d_name);
++		snprintf(etc_name, sizeof(etc_name), "/etc/%s", entry->d_name);
++		if (mount(netns_name, etc_name, "none", MS_BIND, NULL) < 0) {
++			fprintf(stderr, "Bind %s -> %s failed: %s\n",
++				netns_name, etc_name, strerror(errno));
++		}
++	}
++	closedir(dir);
++}
++
++int netns_switch(char *name)
++{
++	char net_path[MAXPATHLEN];
++	int netns;
++
++	snprintf(net_path, sizeof(net_path), "%s/%s", NETNS_RUN_DIR, name);
++	netns = open(net_path, O_RDONLY | O_CLOEXEC);
++	if (netns < 0) {
++		fprintf(stderr, "Cannot open network namespace \"%s\": %s\n",
++			name, strerror(errno));
++		return -1;
++	}
++
++	if (setns(netns, CLONE_NEWNET) < 0) {
++		fprintf(stderr, "setting the network namespace \"%s\" failed: %s\n",
++			name, strerror(errno));
++		return -1;
++	}
++
++	if (unshare(CLONE_NEWNS) < 0) {
++		fprintf(stderr, "unshare failed: %s\n", strerror(errno));
++		return -1;
++	}
++	/* Don't let any mounts propagate back to the parent */
++	if (mount("", "/", "none", MS_SLAVE | MS_REC, NULL)) {
++		fprintf(stderr, "\"mount --make-rslave /\" failed: %s\n",
++			strerror(errno));
++		return -1;
++	}
++	/* Mount a version of /sys that describes the network namespace */
++	if (umount2("/sys", MNT_DETACH) < 0) {
++		fprintf(stderr, "umount of /sys failed: %s\n", strerror(errno));
++		return -1;
++	}
++	if (mount(name, "/sys", "sysfs", 0, NULL) < 0) {
++		fprintf(stderr, "mount of /sys failed: %s\n",strerror(errno));
++		return -1;
++	}
++
++	/* Setup bind mounts for config files in /etc */
++	bind_etc(name);
++	return 0;
++}
++
++int netns_get_fd(const char *name)
++{
++	char pathbuf[MAXPATHLEN];
++	const char *path, *ptr;
++
++	path = name;
++	ptr = strchr(name, '/');
++	if (!ptr) {
++		snprintf(pathbuf, sizeof(pathbuf), "%s/%s",
++			NETNS_RUN_DIR, name );
++		path = pathbuf;
++	}
++	return open(path, O_RDONLY);
++}
++
++int netns_foreach(int (*func)(char *nsname, void *arg), void *arg)
++{
++	DIR *dir;
++	struct dirent *entry;
++
++	dir = opendir(NETNS_RUN_DIR);
++	if (!dir)
++		return -1;
++
++	while ((entry = readdir(dir)) != NULL) {
++		if (strcmp(entry->d_name, ".") == 0)
++			continue;
++		if (strcmp(entry->d_name, "..") == 0)
++			continue;
++		if (func(entry->d_name, arg))
++			break;
++	}
++
++	closedir(dir);
++	return 0;
++}
+diff --git a/lib/rt_names.c b/lib/rt_names.c
+index 02f1417..c2e60de 100644
+--- a/lib/rt_names.c
++++ b/lib/rt_names.c
+@@ -500,3 +500,104 @@ int rtnl_group_a2n(int *id, const char *arg)
+ 	*id = i;
+ 	return 0;
+ }
++
++const char *rtnl_group_n2a(int id, char *buf, int len)
++{
++	struct rtnl_hash_entry *entry;
++	int i;
++
++	if (!rtnl_group_init)
++		rtnl_group_initialize();
++
++	for (i=0; i<256; i++) {
++		entry = rtnl_group_hash[i];
++		if (entry && entry->id == id) {
++			return entry->name;
++		}
++	}
++
++	snprintf(buf, len, "%d", id);
++	return buf;
++}
++
++static char *nl_proto_tab[256] = {
++	[NETLINK_ROUTE]          = "rtnl",
++	[NETLINK_UNUSED]         = "unused",
++	[NETLINK_USERSOCK]       = "usersock",
++	[NETLINK_FIREWALL]       = "fw",
++	[NETLINK_SOCK_DIAG]      = "tcpdiag",
++	[NETLINK_NFLOG]          = "nflog",
++	[NETLINK_XFRM]           = "xfrm",
++	[NETLINK_SELINUX]        = "selinux",
++	[NETLINK_ISCSI]          = "iscsi",
++	[NETLINK_AUDIT]          = "audit",
++	[NETLINK_FIB_LOOKUP]     = "fiblookup",
++	[NETLINK_CONNECTOR]      = "connector",
++	[NETLINK_NETFILTER]      = "nft",
++	[NETLINK_IP6_FW]         = "ip6fw",
++	[NETLINK_DNRTMSG]        = "dec-rt",
++	[NETLINK_KOBJECT_UEVENT] = "uevent",
++	[NETLINK_GENERIC]        = "genl",
++	[NETLINK_SCSITRANSPORT]  = "scsi-trans",
++	[NETLINK_ECRYPTFS]       = "ecryptfs",
++	[NETLINK_RDMA]           = "rdma",
++	[NETLINK_CRYPTO]         = "crypto",
++};
++
++static int nl_proto_init;
++
++static void nl_proto_initialize(void)
++{
++	nl_proto_init = 1;
++	rtnl_tab_initialize(CONFDIR "/nl_protos",
++			    nl_proto_tab, 256);
++}
++
++const char *nl_proto_n2a(int id, char *buf, int len)
++{
++	if (id < 0 || id >= 256) {
++		snprintf(buf, len, "%u", id);
++		return buf;
++	}
++
++	if (!nl_proto_init)
++		nl_proto_initialize();
++
++	if (nl_proto_tab[id])
++		return nl_proto_tab[id];
++
++	snprintf(buf, len, "%u", id);
++	return buf;
++}
++
++int nl_proto_a2n(__u32 *id, const char *arg)
++{
++	static char *cache = NULL;
++	static unsigned long res;
++	char *end;
++	int i;
++
++	if (cache && strcmp(cache, arg) == 0) {
++		*id = res;
++		return 0;
++	}
++
++	if (!nl_proto_init)
++		nl_proto_initialize();
++
++	for (i = 0; i < 256; i++) {
++		if (nl_proto_tab[i] &&
++		    strcmp(nl_proto_tab[i], arg) == 0) {
++			cache = nl_proto_tab[i];
++			res = i;
++			*id = res;
++			return 0;
++		}
++	}
++
++	res = strtoul(arg, &end, 0);
++	if (!end || end == arg || *end || res > 255)
++		return -1;
++	*id = res;
++	return 0;
++}
+diff --git a/lib/utils.c b/lib/utils.c
+index 0f9de02..299b485 100644
+--- a/lib/utils.c
++++ b/lib/utils.c
+@@ -31,6 +31,7 @@
+ 
+ 
+ #include "utils.h"
++#include "namespace.h"
+ 
+ int get_integer(int *val, const char *arg, int base)
+ {
+@@ -864,3 +865,44 @@ int makeargs(char *line, char *argv[], int maxargs)
+ 
+ 	return argc;
+ }
++
++int inet_get_addr(const char *src, __u32 *dst, struct in6_addr *dst6)
++{
++	if (strchr(src, ':'))
++		return inet_pton(AF_INET6, src, dst6);
++	else
++		return inet_pton(AF_INET, src, dst);
++}
++
++static int on_netns(char *nsname, void *arg)
++{
++	struct netns_func *f = arg;
++
++	if (netns_switch(nsname))
++		return -1;
++
++	return f->func(nsname, f->arg);
++}
++
++static int on_netns_label(char *nsname, void *arg)
++{
++	printf("\nnetns: %s\n", nsname);
++	return on_netns(nsname, arg);
++}
++
++int do_each_netns(int (*func)(char *nsname, void *arg), void *arg,
++		bool show_label)
++{
++	struct netns_func nsf = { .func = func, .arg = arg };
++
++	if (show_label)
++		return netns_foreach(on_netns_label, &nsf);
++
++	return netns_foreach(on_netns, &nsf);
++}
++
++char *int_to_str(int val, char *buf)
++{
++	sprintf(buf, "%d", val);
++	return buf;
++}
+diff --git a/misc/Makefile b/misc/Makefile
+index a59ff87..a516bd8 100644
+--- a/misc/Makefile
++++ b/misc/Makefile
+@@ -5,6 +5,10 @@ TARGETS=ss nstat ifstat rtacct arpd lnstat
+ 
+ include ../Config
+ 
++ifeq ($(IP_CONFIG_SETNS),y)
++	CFLAGS += -DHAVE_SETNS
++endif
++
+ all: $(TARGETS)
+ 
+ ss: $(SSOBJ)
diff --git a/SOURCES/iproute2-3.10.0-linux.patch b/SOURCES/iproute2-3.10.0-linux.patch
new file mode 100644
index 0000000..8b840df
--- /dev/null
+++ b/SOURCES/iproute2-3.10.0-linux.patch
@@ -0,0 +1,2459 @@
+diff --git a/include/linux/bpf.h b/include/linux/bpf.h
+new file mode 100644
+index 0000000..08aab3a
+--- /dev/null
++++ b/include/linux/bpf.h
+@@ -0,0 +1,226 @@
++/* Copyright (c) 2011-2014 PLUMgrid, http://plumgrid.com
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of version 2 of the GNU General Public
++ * License as published by the Free Software Foundation.
++ */
++#ifndef __LINUX_BPF_H__
++#define __LINUX_BPF_H__
++
++#include <linux/types.h>
++#include <linux/bpf_common.h>
++
++/* Extended instruction set based on top of classic BPF */
++
++/* instruction classes */
++#define BPF_ALU64	0x07	/* alu mode in double word width */
++
++/* ld/ldx fields */
++#define BPF_DW		0x18	/* double word */
++#define BPF_XADD	0xc0	/* exclusive add */
++
++/* alu/jmp fields */
++#define BPF_MOV		0xb0	/* mov reg to reg */
++#define BPF_ARSH	0xc0	/* sign extending arithmetic shift right */
++
++/* change endianness of a register */
++#define BPF_END		0xd0	/* flags for endianness conversion: */
++#define BPF_TO_LE	0x00	/* convert to little-endian */
++#define BPF_TO_BE	0x08	/* convert to big-endian */
++#define BPF_FROM_LE	BPF_TO_LE
++#define BPF_FROM_BE	BPF_TO_BE
++
++#define BPF_JNE		0x50	/* jump != */
++#define BPF_JSGT	0x60	/* SGT is signed '>', GT in x86 */
++#define BPF_JSGE	0x70	/* SGE is signed '>=', GE in x86 */
++#define BPF_CALL	0x80	/* function call */
++#define BPF_EXIT	0x90	/* function return */
++
++/* Register numbers */
++enum {
++	BPF_REG_0 = 0,
++	BPF_REG_1,
++	BPF_REG_2,
++	BPF_REG_3,
++	BPF_REG_4,
++	BPF_REG_5,
++	BPF_REG_6,
++	BPF_REG_7,
++	BPF_REG_8,
++	BPF_REG_9,
++	BPF_REG_10,
++	__MAX_BPF_REG,
++};
++
++/* BPF has 10 general purpose 64-bit registers and stack frame. */
++#define MAX_BPF_REG	__MAX_BPF_REG
++
++struct bpf_insn {
++	__u8	code;		/* opcode */
++	__u8	dst_reg:4;	/* dest register */
++	__u8	src_reg:4;	/* source register */
++	__s16	off;		/* signed offset */
++	__s32	imm;		/* signed immediate constant */
++};
++
++/* BPF syscall commands */
++enum bpf_cmd {
++	/* create a map with given type and attributes
++	 * fd = bpf(BPF_MAP_CREATE, union bpf_attr *, u32 size)
++	 * returns fd or negative error
++	 * map is deleted when fd is closed
++	 */
++	BPF_MAP_CREATE,
++
++	/* lookup key in a given map
++	 * err = bpf(BPF_MAP_LOOKUP_ELEM, union bpf_attr *attr, u32 size)
++	 * Using attr->map_fd, attr->key, attr->value
++	 * returns zero and stores found elem into value
++	 * or negative error
++	 */
++	BPF_MAP_LOOKUP_ELEM,
++
++	/* create or update key/value pair in a given map
++	 * err = bpf(BPF_MAP_UPDATE_ELEM, union bpf_attr *attr, u32 size)
++	 * Using attr->map_fd, attr->key, attr->value, attr->flags
++	 * returns zero or negative error
++	 */
++	BPF_MAP_UPDATE_ELEM,
++
++	/* find and delete elem by key in a given map
++	 * err = bpf(BPF_MAP_DELETE_ELEM, union bpf_attr *attr, u32 size)
++	 * Using attr->map_fd, attr->key
++	 * returns zero or negative error
++	 */
++	BPF_MAP_DELETE_ELEM,
++
++	/* lookup key in a given map and return next key
++	 * err = bpf(BPF_MAP_GET_NEXT_KEY, union bpf_attr *attr, u32 size)
++	 * Using attr->map_fd, attr->key, attr->next_key
++	 * returns zero and stores next key or negative error
++	 */
++	BPF_MAP_GET_NEXT_KEY,
++
++	/* verify and load eBPF program
++	 * prog_fd = bpf(BPF_PROG_LOAD, union bpf_attr *attr, u32 size)
++	 * Using attr->prog_type, attr->insns, attr->license
++	 * returns fd or negative error
++	 */
++	BPF_PROG_LOAD,
++};
++
++enum bpf_map_type {
++	BPF_MAP_TYPE_UNSPEC,
++	BPF_MAP_TYPE_HASH,
++	BPF_MAP_TYPE_ARRAY,
++};
++
++enum bpf_prog_type {
++	BPF_PROG_TYPE_UNSPEC,
++	BPF_PROG_TYPE_SOCKET_FILTER,
++	BPF_PROG_TYPE_SCHED_CLS,
++	BPF_PROG_TYPE_SCHED_ACT,
++};
++
++#define BPF_PSEUDO_MAP_FD	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 */
++#define BPF_EXIST	2 /* update existing element */
++
++union bpf_attr {
++	struct { /* anonymous struct used by BPF_MAP_CREATE command */
++		__u32	map_type;	/* one of enum bpf_map_type */
++		__u32	key_size;	/* size of key in bytes */
++		__u32	value_size;	/* size of value in bytes */
++		__u32	max_entries;	/* max number of entries in a map */
++	};
++
++	struct { /* anonymous struct used by BPF_MAP_*_ELEM commands */
++		__u32		map_fd;
++		__aligned_u64	key;
++		union {
++			__aligned_u64 value;
++			__aligned_u64 next_key;
++		};
++		__u64		flags;
++	};
++
++	struct { /* anonymous struct used by BPF_PROG_LOAD command */
++		__u32		prog_type;	/* one of enum bpf_prog_type */
++		__u32		insn_cnt;
++		__aligned_u64	insns;
++		__aligned_u64	license;
++		__u32		log_level;	/* verbosity level of verifier */
++		__u32		log_size;	/* size of user buffer */
++		__aligned_u64	log_buf;	/* user supplied buffer */
++	};
++} __attribute__((aligned(8)));
++
++/* integer value in 'imm' field of BPF_CALL instruction selects which helper
++ * function eBPF program intends to call
++ */
++enum bpf_func_id {
++	BPF_FUNC_unspec,
++	BPF_FUNC_map_lookup_elem, /* void *map_lookup_elem(&map, &key) */
++	BPF_FUNC_map_update_elem, /* int map_update_elem(&map, &key, &value, flags) */
++	BPF_FUNC_map_delete_elem, /* int map_delete_elem(&map, &key) */
++	BPF_FUNC_get_prandom_u32, /* u32 prandom_u32(void) */
++	BPF_FUNC_get_smp_processor_id, /* u32 raw_smp_processor_id(void) */
++
++	/**
++	 * skb_store_bytes(skb, offset, from, len, flags) - store bytes into packet
++	 * @skb: pointer to skb
++	 * @offset: offset within packet from skb->data
++	 * @from: pointer where to copy bytes from
++	 * @len: number of bytes to store into packet
++	 * @flags: bit 0 - if true, recompute skb->csum
++	 *         other bits - reserved
++	 * Return: 0 on success
++	 */
++	BPF_FUNC_skb_store_bytes,
++
++	/**
++	 * l3_csum_replace(skb, offset, from, to, flags) - recompute IP checksum
++	 * @skb: pointer to skb
++	 * @offset: offset within packet where IP checksum is located
++	 * @from: old value of header field
++	 * @to: new value of header field
++	 * @flags: bits 0-3 - size of header field
++	 *         other bits - reserved
++	 * Return: 0 on success
++	 */
++	BPF_FUNC_l3_csum_replace,
++
++	/**
++	 * l4_csum_replace(skb, offset, from, to, flags) - recompute TCP/UDP checksum
++	 * @skb: pointer to skb
++	 * @offset: offset within packet where TCP/UDP checksum is located
++	 * @from: old value of header field
++	 * @to: new value of header field
++	 * @flags: bits 0-3 - size of header field
++	 *         bit 4 - is pseudo header
++	 *         other bits - reserved
++	 * Return: 0 on success
++	 */
++	BPF_FUNC_l4_csum_replace,
++	__BPF_FUNC_MAX_ID,
++};
++
++/* user accessible mirror of in-kernel sk_buff.
++ * new fields can only be added to the end of this structure
++ */
++struct __sk_buff {
++	__u32 len;
++	__u32 pkt_type;
++	__u32 mark;
++	__u32 queue_mapping;
++	__u32 protocol;
++	__u32 vlan_present;
++	__u32 vlan_tci;
++	__u32 vlan_proto;
++	__u32 priority;
++};
++
++#endif /* __LINUX_BPF_H__ */
+diff --git a/include/linux/bpf_common.h b/include/linux/bpf_common.h
+new file mode 100644
+index 0000000..afe7433
+--- /dev/null
++++ b/include/linux/bpf_common.h
+@@ -0,0 +1,55 @@
++#ifndef __LINUX_BPF_COMMON_H__
++#define __LINUX_BPF_COMMON_H__
++
++/* Instruction classes */
++#define BPF_CLASS(code) ((code) & 0x07)
++#define		BPF_LD		0x00
++#define		BPF_LDX		0x01
++#define		BPF_ST		0x02
++#define		BPF_STX		0x03
++#define		BPF_ALU		0x04
++#define		BPF_JMP		0x05
++#define		BPF_RET		0x06
++#define		BPF_MISC        0x07
++
++/* ld/ldx fields */
++#define BPF_SIZE(code)  ((code) & 0x18)
++#define		BPF_W		0x00
++#define		BPF_H		0x08
++#define		BPF_B		0x10
++#define BPF_MODE(code)  ((code) & 0xe0)
++#define		BPF_IMM		0x00
++#define		BPF_ABS		0x20
++#define		BPF_IND		0x40
++#define		BPF_MEM		0x60
++#define		BPF_LEN		0x80
++#define		BPF_MSH		0xa0
++
++/* alu/jmp fields */
++#define BPF_OP(code)    ((code) & 0xf0)
++#define		BPF_ADD		0x00
++#define		BPF_SUB		0x10
++#define		BPF_MUL		0x20
++#define		BPF_DIV		0x30
++#define		BPF_OR		0x40
++#define		BPF_AND		0x50
++#define		BPF_LSH		0x60
++#define		BPF_RSH		0x70
++#define		BPF_NEG		0x80
++#define		BPF_MOD		0x90
++#define		BPF_XOR		0xa0
++
++#define		BPF_JA		0x00
++#define		BPF_JEQ		0x10
++#define		BPF_JGT		0x20
++#define		BPF_JGE		0x30
++#define		BPF_JSET        0x40
++#define BPF_SRC(code)   ((code) & 0x08)
++#define		BPF_K		0x00
++#define		BPF_X		0x08
++
++#ifndef BPF_MAXINSNS
++#define BPF_MAXINSNS 4096
++#endif
++
++#endif /* __LINUX_BPF_COMMON_H__ */
+diff --git a/include/linux/can.h b/include/linux/can.h
+index e52958d..d9ba97f 100644
+--- a/include/linux/can.h
++++ b/include/linux/can.h
+@@ -8,10 +8,42 @@
+  * Copyright (c) 2002-2007 Volkswagen Group Electronic Research
+  * All rights reserved.
+  *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ *    notice, this list of conditions and the following disclaimer.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ *    notice, this list of conditions and the following disclaimer in the
++ *    documentation and/or other materials provided with the distribution.
++ * 3. Neither the name of Volkswagen nor the names of its contributors
++ *    may be used to endorse or promote products derived from this software
++ *    without specific prior written permission.
++ *
++ * Alternatively, provided that this notice is retained in full, this
++ * software may be distributed under the terms of the GNU General
++ * Public License ("GPL") version 2, in which case the provisions of the
++ * GPL apply INSTEAD OF those given above.
++ *
++ * The provided data structures and external interfaces from this code
++ * are not restricted to be used by modules with a GPL compatible license.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
++ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
++ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
++ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
++ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
++ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
++ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
++ * DAMAGE.
+  */
+ 
+-#ifndef CAN_H
+-#define CAN_H
++#ifndef _CAN_H
++#define _CAN_H
+ 
+ #include <linux/types.h>
+ #include <linux/socket.h>
+@@ -159,4 +191,4 @@ struct can_filter {
+ 
+ #define CAN_INV_FILTER 0x20000000U /* to be set in can_filter.can_id */
+ 
+-#endif /* CAN_H */
++#endif /* !_UAPI_CAN_H */
+diff --git a/include/linux/can/netlink.h b/include/linux/can/netlink.h
+index 14966dd..6d4ec2a 100644
+--- a/include/linux/can/netlink.h
++++ b/include/linux/can/netlink.h
+@@ -5,10 +5,18 @@
+  *
+  * Copyright (c) 2009 Wolfgang Grandegger <wg@grandegger.com>
+  *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the version 2 of the GNU General Public License
++ * as published by the Free Software Foundation
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
+  */
+ 
+-#ifndef CAN_NETLINK_H
+-#define CAN_NETLINK_H
++#ifndef _CAN_NETLINK_H
++#define _CAN_NETLINK_H
+ 
+ #include <linux/types.h>
+ 
+@@ -84,10 +92,13 @@ struct can_ctrlmode {
+ };
+ 
+ #define CAN_CTRLMODE_LOOPBACK		0x01	/* Loopback mode */
+-#define CAN_CTRLMODE_LISTENONLY		0x02 	/* Listen-only mode */
++#define CAN_CTRLMODE_LISTENONLY		0x02	/* Listen-only mode */
+ #define CAN_CTRLMODE_3_SAMPLES		0x04	/* Triple sampling mode */
+ #define CAN_CTRLMODE_ONE_SHOT		0x08	/* One-Shot mode */
+ #define CAN_CTRLMODE_BERR_REPORTING	0x10	/* Bus-error reporting */
++#define CAN_CTRLMODE_FD			0x20	/* CAN FD mode */
++#define CAN_CTRLMODE_PRESUME_ACK	0x40	/* Ignore missing CAN ACKs */
++#define CAN_CTRLMODE_FD_NON_ISO		0x80	/* CAN FD in non-ISO mode */
+ 
+ /*
+  * CAN device statistics
+@@ -114,9 +125,11 @@ enum {
+ 	IFLA_CAN_RESTART_MS,
+ 	IFLA_CAN_RESTART,
+ 	IFLA_CAN_BERR_COUNTER,
++	IFLA_CAN_DATA_BITTIMING,
++	IFLA_CAN_DATA_BITTIMING_CONST,
+ 	__IFLA_CAN_MAX
+ };
+ 
+ #define IFLA_CAN_MAX	(__IFLA_CAN_MAX - 1)
+ 
+-#endif /* CAN_NETLINK_H */
++#endif /* !_UAPI_CAN_NETLINK_H */
+diff --git a/include/linux/fib_rules.h b/include/linux/fib_rules.h
+index 51da65b..2b82d7e 100644
+--- a/include/linux/fib_rules.h
++++ b/include/linux/fib_rules.h
+@@ -44,8 +44,8 @@ enum {
+ 	FRA_FWMARK,	/* mark */
+ 	FRA_FLOW,	/* flow/class id */
+ 	FRA_UNUSED6,
+-	FRA_UNUSED7,
+-	FRA_UNUSED8,
++	FRA_SUPPRESS_IFGROUP,
++	FRA_SUPPRESS_PREFIXLEN,
+ 	FRA_TABLE,	/* Extended table id */
+ 	FRA_FWMASK,	/* mask for netfilter mark */
+ 	FRA_OIFNAME,
+diff --git a/include/linux/filter.h b/include/linux/filter.h
+index 9a46cb6..344781d 100644
+--- a/include/linux/filter.h
++++ b/include/linux/filter.h
+@@ -7,7 +7,7 @@
+ 
+ 
+ #include <linux/types.h>
+-
++#include <linux/bpf_common.h>
+ 
+ /*
+  * Current version of the filter code architecture.
+@@ -32,56 +32,6 @@ struct sock_fprog {	/* Required for SO_ATTACH_FILTER. */
+ 	struct sock_filter *filter;
+ };
+ 
+-/*
+- * Instruction classes
+- */
+-
+-#define BPF_CLASS(code) ((code) & 0x07)
+-#define         BPF_LD          0x00
+-#define         BPF_LDX         0x01
+-#define         BPF_ST          0x02
+-#define         BPF_STX         0x03
+-#define         BPF_ALU         0x04
+-#define         BPF_JMP         0x05
+-#define         BPF_RET         0x06
+-#define         BPF_MISC        0x07
+-
+-/* ld/ldx fields */
+-#define BPF_SIZE(code)  ((code) & 0x18)
+-#define         BPF_W           0x00
+-#define         BPF_H           0x08
+-#define         BPF_B           0x10
+-#define BPF_MODE(code)  ((code) & 0xe0)
+-#define         BPF_IMM         0x00
+-#define         BPF_ABS         0x20
+-#define         BPF_IND         0x40
+-#define         BPF_MEM         0x60
+-#define         BPF_LEN         0x80
+-#define         BPF_MSH         0xa0
+-
+-/* alu/jmp fields */
+-#define BPF_OP(code)    ((code) & 0xf0)
+-#define         BPF_ADD         0x00
+-#define         BPF_SUB         0x10
+-#define         BPF_MUL         0x20
+-#define         BPF_DIV         0x30
+-#define         BPF_OR          0x40
+-#define         BPF_AND         0x50
+-#define         BPF_LSH         0x60
+-#define         BPF_RSH         0x70
+-#define         BPF_NEG         0x80
+-#define		BPF_MOD		0x90
+-#define		BPF_XOR		0xa0
+-
+-#define         BPF_JA          0x00
+-#define         BPF_JEQ         0x10
+-#define         BPF_JGT         0x20
+-#define         BPF_JGE         0x30
+-#define         BPF_JSET        0x40
+-#define BPF_SRC(code)   ((code) & 0x08)
+-#define         BPF_K           0x00
+-#define         BPF_X           0x08
+-
+ /* ret - BPF_K and BPF_X also apply */
+ #define BPF_RVAL(code)  ((code) & 0x18)
+ #define         BPF_A           0x10
+@@ -91,10 +41,6 @@ struct sock_fprog {	/* Required for SO_ATTACH_FILTER. */
+ #define         BPF_TAX         0x00
+ #define         BPF_TXA         0x80
+ 
+-#ifndef BPF_MAXINSNS
+-#define BPF_MAXINSNS 4096
+-#endif
+-
+ /*
+  * Macros for filter block array initializers.
+  */
+@@ -130,7 +76,9 @@ struct sock_fprog {	/* Required for SO_ATTACH_FILTER. */
+ #define SKF_AD_VLAN_TAG	44
+ #define SKF_AD_VLAN_TAG_PRESENT 48
+ #define SKF_AD_PAY_OFFSET	52
+-#define SKF_AD_MAX	56
++#define SKF_AD_RANDOM	56
++#define SKF_AD_VLAN_TPID	60
++#define SKF_AD_MAX	64
+ #define SKF_NET_OFF   (-0x100000)
+ #define SKF_LL_OFF    (-0x200000)
+ 
+diff --git a/include/linux/fou.h b/include/linux/fou.h
+new file mode 100644
+index 0000000..744c323
+--- /dev/null
++++ b/include/linux/fou.h
+@@ -0,0 +1,41 @@
++/* fou.h - FOU Interface */
++
++#ifndef _LINUX_FOU_H
++#define _LINUX_FOU_H
++
++/* NETLINK_GENERIC related info
++ */
++#define FOU_GENL_NAME		"fou"
++#define FOU_GENL_VERSION	0x1
++
++enum {
++	FOU_ATTR_UNSPEC,
++	FOU_ATTR_PORT,				/* u16 */
++	FOU_ATTR_AF,				/* u8 */
++	FOU_ATTR_IPPROTO,			/* u8 */
++	FOU_ATTR_TYPE,				/* u8 */
++	FOU_ATTR_REMCSUM_NOPARTIAL,		/* flag */
++
++	__FOU_ATTR_MAX,
++};
++
++#define FOU_ATTR_MAX		(__FOU_ATTR_MAX - 1)
++
++enum {
++	FOU_CMD_UNSPEC,
++	FOU_CMD_ADD,
++	FOU_CMD_DEL,
++	FOU_CMD_GET,
++
++	__FOU_CMD_MAX,
++};
++
++enum {
++	FOU_ENCAP_UNSPEC,
++	FOU_ENCAP_DIRECT,
++	FOU_ENCAP_GUE,
++};
++
++#define FOU_CMD_MAX	(__FOU_CMD_MAX - 1)
++
++#endif /* _LINUX_FOU_H */
+diff --git a/include/linux/gen_stats.h b/include/linux/gen_stats.h
+index 552c8a0..6487317 100644
+--- a/include/linux/gen_stats.h
++++ b/include/linux/gen_stats.h
+@@ -9,6 +9,7 @@ enum {
+ 	TCA_STATS_RATE_EST,
+ 	TCA_STATS_QUEUE,
+ 	TCA_STATS_APP,
++	TCA_STATS_RATE_EST64,
+ 	__TCA_STATS_MAX,
+ };
+ #define TCA_STATS_MAX (__TCA_STATS_MAX - 1)
+@@ -38,6 +39,16 @@ struct gnet_stats_rate_est {
+ };
+ 
+ /**
++ * struct gnet_stats_rate_est64 - rate estimator
++ * @bps: current byte rate
++ * @pps: current packet rate
++ */
++struct gnet_stats_rate_est64 {
++	__u64	bps;
++	__u64	pps;
++};
++
++/**
+  * struct gnet_stats_queue - queuing statistics
+  * @qlen: queue length
+  * @backlog: backlog size of queue
+diff --git a/include/linux/genetlink.h b/include/linux/genetlink.h
+index 1f85a27..8a1d500 100644
+--- a/include/linux/genetlink.h
++++ b/include/linux/genetlink.h
+@@ -27,6 +27,8 @@ struct genlmsghdr {
+  */
+ #define GENL_ID_GENERATE	0
+ #define GENL_ID_CTRL		NLMSG_MIN_TYPE
++#define GENL_ID_VFS_DQUOT	(NLMSG_MIN_TYPE + 1)
++#define GENL_ID_PMCRAID		(NLMSG_MIN_TYPE + 2)
+ 
+ /**************************************************************************
+  * Controller
+diff --git a/include/linux/if.h b/include/linux/if.h
+index 7f261c0..a55a9e0 100644
+--- a/include/linux/if.h
++++ b/include/linux/if.h
+@@ -27,64 +27,91 @@
+ #define	IFALIASZ	256
+ #include <linux/hdlc/ioctl.h>
+ 
+-/* Standard interface flags (netdevice->flags). */
+-#define	IFF_UP		0x1		/* interface is up		*/
+-#define	IFF_BROADCAST	0x2		/* broadcast address valid	*/
+-#define	IFF_DEBUG	0x4		/* turn on debugging		*/
+-#define	IFF_LOOPBACK	0x8		/* is a loopback net		*/
+-#define	IFF_POINTOPOINT	0x10		/* interface is has p-p link	*/
+-#define	IFF_NOTRAILERS	0x20		/* avoid use of trailers	*/
+-#define	IFF_RUNNING	0x40		/* interface RFC2863 OPER_UP	*/
+-#define	IFF_NOARP	0x80		/* no ARP protocol		*/
+-#define	IFF_PROMISC	0x100		/* receive all packets		*/
+-#define	IFF_ALLMULTI	0x200		/* receive all multicast packets*/
+-
+-#define IFF_MASTER	0x400		/* master of a load balancer 	*/
+-#define IFF_SLAVE	0x800		/* slave of a load balancer	*/
+-
+-#define IFF_MULTICAST	0x1000		/* Supports multicast		*/
+-
+-#define IFF_PORTSEL	0x2000          /* can set media type		*/
+-#define IFF_AUTOMEDIA	0x4000		/* auto media select active	*/
+-#define IFF_DYNAMIC	0x8000		/* dialup device with changing addresses*/
+-
+-#define IFF_LOWER_UP	0x10000		/* driver signals L1 up		*/
+-#define IFF_DORMANT	0x20000		/* driver signals dormant	*/
++/**
++ * enum net_device_flags - &struct net_device flags
++ *
++ * These are the &struct net_device flags, they can be set by drivers, the
++ * kernel and some can be triggered by userspace. Userspace can query and
++ * set these flags using userspace utilities but there is also a sysfs
++ * entry available for all dev flags which can be queried and set. These flags
++ * are shared for all types of net_devices. The sysfs entries are available
++ * via /sys/class/net/<dev>/flags. Flags which can be toggled through sysfs
++ * are annotated below, note that only a few flags can be toggled and some
++ * other flags are always always preserved from the original net_device flags
++ * even if you try to set them via sysfs. Flags which are always preserved
++ * are kept under the flag grouping @IFF_VOLATILE. Flags which are __volatile__
++ * are annotated below as such.
++ *
++ * You should have a pretty good reason to be extending these flags.
++ *
++ * @IFF_UP: interface is up. Can be toggled through sysfs.
++ * @IFF_BROADCAST: broadcast address valid. Volatile.
++ * @IFF_DEBUG: turn on debugging. Can be toggled through sysfs.
++ * @IFF_LOOPBACK: is a loopback net. Volatile.
++ * @IFF_POINTOPOINT: interface is has p-p link. Volatile.
++ * @IFF_NOTRAILERS: avoid use of trailers. Can be toggled through sysfs.
++ *	Volatile.
++ * @IFF_RUNNING: interface RFC2863 OPER_UP. Volatile.
++ * @IFF_NOARP: no ARP protocol. Can be toggled through sysfs. Volatile.
++ * @IFF_PROMISC: receive all packets. Can be toggled through sysfs.
++ * @IFF_ALLMULTI: receive all multicast packets. Can be toggled through
++ *	sysfs.
++ * @IFF_MASTER: master of a load balancer. Volatile.
++ * @IFF_SLAVE: slave of a load balancer. Volatile.
++ * @IFF_MULTICAST: Supports multicast. Can be toggled through sysfs.
++ * @IFF_PORTSEL: can set media type. Can be toggled through sysfs.
++ * @IFF_AUTOMEDIA: auto media select active. Can be toggled through sysfs.
++ * @IFF_DYNAMIC: dialup device with changing addresses. Can be toggled
++ *	through sysfs.
++ * @IFF_LOWER_UP: driver signals L1 up. Volatile.
++ * @IFF_DORMANT: driver signals dormant. Volatile.
++ * @IFF_ECHO: echo sent packets. Volatile.
++ */
++enum net_device_flags {
++	IFF_UP				= 1<<0,  /* sysfs */
++	IFF_BROADCAST			= 1<<1,  /* __volatile__ */
++	IFF_DEBUG			= 1<<2,  /* sysfs */
++	IFF_LOOPBACK			= 1<<3,  /* __volatile__ */
++	IFF_POINTOPOINT			= 1<<4,  /* __volatile__ */
++	IFF_NOTRAILERS			= 1<<5,  /* sysfs */
++	IFF_RUNNING			= 1<<6,  /* __volatile__ */
++	IFF_NOARP			= 1<<7,  /* sysfs */
++	IFF_PROMISC			= 1<<8,  /* sysfs */
++	IFF_ALLMULTI			= 1<<9,  /* sysfs */
++	IFF_MASTER			= 1<<10, /* __volatile__ */
++	IFF_SLAVE			= 1<<11, /* __volatile__ */
++	IFF_MULTICAST			= 1<<12, /* sysfs */
++	IFF_PORTSEL			= 1<<13, /* sysfs */
++	IFF_AUTOMEDIA			= 1<<14, /* sysfs */
++	IFF_DYNAMIC			= 1<<15, /* sysfs */
++	IFF_LOWER_UP			= 1<<16, /* __volatile__ */
++	IFF_DORMANT			= 1<<17, /* __volatile__ */
++	IFF_ECHO			= 1<<18, /* __volatile__ */
++};
+ 
+-#define IFF_ECHO	0x40000		/* echo sent packets		*/
++#define IFF_UP				IFF_UP
++#define IFF_BROADCAST			IFF_BROADCAST
++#define IFF_DEBUG			IFF_DEBUG
++#define IFF_LOOPBACK			IFF_LOOPBACK
++#define IFF_POINTOPOINT			IFF_POINTOPOINT
++#define IFF_NOTRAILERS			IFF_NOTRAILERS
++#define IFF_RUNNING			IFF_RUNNING
++#define IFF_NOARP			IFF_NOARP
++#define IFF_PROMISC			IFF_PROMISC
++#define IFF_ALLMULTI			IFF_ALLMULTI
++#define IFF_MASTER			IFF_MASTER
++#define IFF_SLAVE			IFF_SLAVE
++#define IFF_MULTICAST			IFF_MULTICAST
++#define IFF_PORTSEL			IFF_PORTSEL
++#define IFF_AUTOMEDIA			IFF_AUTOMEDIA
++#define IFF_DYNAMIC			IFF_DYNAMIC
++#define IFF_LOWER_UP			IFF_LOWER_UP
++#define IFF_DORMANT			IFF_DORMANT
++#define IFF_ECHO			IFF_ECHO
+ 
+ #define IFF_VOLATILE	(IFF_LOOPBACK|IFF_POINTOPOINT|IFF_BROADCAST|IFF_ECHO|\
+ 		IFF_MASTER|IFF_SLAVE|IFF_RUNNING|IFF_LOWER_UP|IFF_DORMANT)
+ 
+-/* Private (from user) interface flags (netdevice->priv_flags). */
+-#define IFF_802_1Q_VLAN 0x1             /* 802.1Q VLAN device.          */
+-#define IFF_EBRIDGE	0x2		/* Ethernet bridging device.	*/
+-#define IFF_SLAVE_INACTIVE	0x4	/* bonding slave not the curr. active */
+-#define IFF_MASTER_8023AD	0x8	/* bonding master, 802.3ad. 	*/
+-#define IFF_MASTER_ALB	0x10		/* bonding master, balance-alb.	*/
+-#define IFF_BONDING	0x20		/* bonding master or slave	*/
+-#define IFF_SLAVE_NEEDARP 0x40		/* need ARPs for validation	*/
+-#define IFF_ISATAP	0x80		/* ISATAP interface (RFC4214)	*/
+-#define IFF_MASTER_ARPMON 0x100		/* bonding master, ARP mon in use */
+-#define IFF_WAN_HDLC	0x200		/* WAN HDLC device		*/
+-#define IFF_XMIT_DST_RELEASE 0x400	/* dev_hard_start_xmit() is allowed to
+-					 * release skb->dst
+-					 */
+-#define IFF_DONT_BRIDGE 0x800		/* disallow bridging this ether dev */
+-#define IFF_DISABLE_NETPOLL	0x1000	/* disable netpoll at run-time */
+-#define IFF_MACVLAN_PORT	0x2000	/* device used as macvlan port */
+-#define IFF_BRIDGE_PORT	0x4000		/* device used as bridge port */
+-#define IFF_OVS_DATAPATH	0x8000	/* device used as Open vSwitch
+-					 * datapath port */
+-#define IFF_TX_SKB_SHARING	0x10000	/* The interface supports sharing
+-					 * skbs on transmit */
+-#define IFF_UNICAST_FLT	0x20000		/* Supports unicast filtering	*/
+-#define IFF_TEAM_PORT	0x40000		/* device used as team port */
+-#define IFF_SUPP_NOFCS	0x80000		/* device supports sending custom FCS */
+-#define IFF_LIVE_ADDR_CHANGE 0x100000	/* device supports hardware address
+-					 * change when it's running */
+-
+-
+ #define IF_GET_IFACE	0x0001		/* for querying only */
+ #define IF_GET_PROTO	0x0002
+ 
+diff --git a/include/linux/if_addr.h b/include/linux/if_addr.h
+index 58b39f4..26f0ecf 100644
+--- a/include/linux/if_addr.h
++++ b/include/linux/if_addr.h
+@@ -18,6 +18,9 @@ struct ifaddrmsg {
+  * It makes no difference for normally configured broadcast interfaces,
+  * but for point-to-point IFA_ADDRESS is DESTINATION address,
+  * local address is supplied in IFA_LOCAL attribute.
++ *
++ * IFA_FLAGS is a u32 attribute that extends the u8 field ifa_flags.
++ * If present, the value from struct ifaddrmsg will be ignored.
+  */
+ enum {
+ 	IFA_UNSPEC,
+@@ -28,6 +31,7 @@ enum {
+ 	IFA_ANYCAST,
+ 	IFA_CACHEINFO,
+ 	IFA_MULTICAST,
++	IFA_FLAGS,
+ 	__IFA_MAX,
+ };
+ 
+@@ -44,6 +48,10 @@ enum {
+ #define IFA_F_DEPRECATED	0x20
+ #define IFA_F_TENTATIVE		0x40
+ #define IFA_F_PERMANENT		0x80
++#define IFA_F_MANAGETEMPADDR	0x100
++#define IFA_F_NOPREFIXROUTE	0x200
++#define IFA_F_MCAUTOJOIN	0x400
++#define IFA_F_STABLE_PRIVACY	0x800
+ 
+ struct ifa_cacheinfo {
+ 	__u32	ifa_prefered;
+diff --git a/include/linux/if_arp.h b/include/linux/if_arp.h
+index 6a48d55..d001bdb 100644
+--- a/include/linux/if_arp.h
++++ b/include/linux/if_arp.h
+@@ -93,6 +93,8 @@
+ #define ARPHRD_PHONET_PIPE 821		/* PhoNet pipe header		*/
+ #define ARPHRD_CAIF	822		/* CAIF media type		*/
+ #define ARPHRD_IP6GRE	823		/* GRE over IPv6		*/
++#define ARPHRD_NETLINK	824		/* Netlink header		*/
++#define ARPHRD_6LOWPAN	825		/* IPv6 over LoWPAN             */
+ 
+ #define ARPHRD_VOID	  0xFFFF	/* Void type, nothing is known */
+ #define ARPHRD_NONE	  0xFFFE	/* zero header length */
+diff --git a/include/linux/if_bridge.h b/include/linux/if_bridge.h
+index d37e53c..913bd8e 100644
+--- a/include/linux/if_bridge.h
++++ b/include/linux/if_bridge.h
+@@ -14,6 +14,8 @@
+ #define _LINUX_IF_BRIDGE_H
+ 
+ #include <linux/types.h>
++#include <linux/if_ether.h>
++#include <linux/in6.h>
+ 
+ #define SYSFS_BRIDGE_ATTR	"bridge"
+ #define SYSFS_BRIDGE_FDB	"brforward"
+@@ -88,7 +90,7 @@ struct __port_info {
+ };
+ 
+ struct __fdb_entry {
+-	__u8 mac_addr[6];
++	__u8 mac_addr[ETH_ALEN];
+ 	__u8 port_no;
+ 	__u8 is_local;
+ 	__u32 ageing_timer_value;
+@@ -103,6 +105,7 @@ struct __fdb_entry {
+ 
+ #define BRIDGE_MODE_VEB		0	/* Default loopback mode */
+ #define BRIDGE_MODE_VEPA	1	/* 802.1Qbg defined VEPA mode */
++#define BRIDGE_MODE_UNDEF	0xFFFF  /* mode undefined */
+ 
+ /* Bridge management nested attributes
+  * [IFLA_AF_SPEC] = {
+@@ -122,6 +125,8 @@ enum {
+ #define BRIDGE_VLAN_INFO_MASTER	(1<<0)	/* Operate on Bridge device as well */
+ #define BRIDGE_VLAN_INFO_PVID	(1<<1)	/* VLAN is PVID, ingress untagged */
+ #define BRIDGE_VLAN_INFO_UNTAGGED	(1<<2)	/* VLAN egresses untagged */
++#define BRIDGE_VLAN_INFO_RANGE_BEGIN	(1<<3) /* VLAN is start of vlan range */
++#define BRIDGE_VLAN_INFO_RANGE_END	(1<<4) /* VLAN is end of vlan range */
+ 
+ struct bridge_vlan_info {
+ 	__u16 flags;
+diff --git a/include/linux/if_ether.h b/include/linux/if_ether.h
+index 2fc760a..4678e49 100644
+--- a/include/linux/if_ether.h
++++ b/include/linux/if_ether.h
+@@ -68,11 +68,11 @@
+ #define ETH_P_SLOW	0x8809		/* Slow Protocol. See 802.3ad 43B */
+ #define ETH_P_WCCP	0x883E		/* Web-cache coordination protocol
+ 					 * defined in draft-wilson-wrec-wccp-v2-00.txt */
+-#define ETH_P_PPP_DISC	0x8863		/* PPPoE discovery messages     */
+-#define ETH_P_PPP_SES	0x8864		/* PPPoE session messages	*/
+ #define ETH_P_MPLS_UC	0x8847		/* MPLS Unicast traffic		*/
+ #define ETH_P_MPLS_MC	0x8848		/* MPLS Multicast traffic	*/
+ #define ETH_P_ATMMPOA	0x884c		/* MultiProtocol Over ATM	*/
++#define ETH_P_PPP_DISC	0x8863		/* PPPoE discovery messages     */
++#define ETH_P_PPP_SES	0x8864		/* PPPoE session messages	*/
+ #define ETH_P_LINK_CTL	0x886c		/* HPNA, wlan link local tunnel */
+ #define ETH_P_ATMFATE	0x8884		/* Frame-based ATM Transport
+ 					 * over Ethernet
+@@ -85,9 +85,12 @@
+ #define ETH_P_8021AH	0x88E7          /* 802.1ah Backbone Service Tag */
+ #define ETH_P_MVRP	0x88F5          /* 802.1Q MVRP                  */
+ #define ETH_P_1588	0x88F7		/* IEEE 1588 Timesync */
++#define ETH_P_PRP	0x88FB		/* IEC 62439-3 PRP/HSRv0	*/
+ #define ETH_P_FCOE	0x8906		/* Fibre Channel over Ethernet  */
+ #define ETH_P_TDLS	0x890D          /* TDLS */
+ #define ETH_P_FIP	0x8914		/* FCoE Initialization Protocol */
++#define ETH_P_80221	0x8917		/* IEEE 802.21 Media Independent Handover Protocol */
++#define ETH_P_LOOPBACK	0x9000		/* Ethernet loopback packet, per IEEE 802.3 */
+ #define ETH_P_QINQ1	0x9100		/* deprecated QinQ VLAN [ NOT AN OFFICIALLY REGISTERED ID ] */
+ #define ETH_P_QINQ2	0x9200		/* deprecated QinQ VLAN [ NOT AN OFFICIALLY REGISTERED ID ] */
+ #define ETH_P_QINQ3	0x9300		/* deprecated QinQ VLAN [ NOT AN OFFICIALLY REGISTERED ID ] */
+@@ -125,6 +128,7 @@
+ #define ETH_P_PHONET	0x00F5		/* Nokia Phonet frames          */
+ #define ETH_P_IEEE802154 0x00F6		/* IEEE802.15.4 frame		*/
+ #define ETH_P_CAIF	0x00F7		/* ST-Ericsson CAIF protocol	*/
++#define ETH_P_XDSA	0x00F8		/* Multiplexed DSA protocol	*/
+ 
+ /*
+  *	This is an Ethernet frame header.
+diff --git a/include/linux/if_link.h b/include/linux/if_link.h
+index 965dc9f..3d0d613 100644
+--- a/include/linux/if_link.h
++++ b/include/linux/if_link.h
+@@ -143,6 +143,11 @@ enum {
+ 	IFLA_NUM_TX_QUEUES,
+ 	IFLA_NUM_RX_QUEUES,
+ 	IFLA_CARRIER,
++	IFLA_PHYS_PORT_ID,
++	IFLA_CARRIER_CHANGES,
++	IFLA_PHYS_SWITCH_ID,
++	IFLA_LINK_NETNSID,
++	IFLA_PHYS_PORT_NAME,
+ 	__IFLA_MAX
+ };
+ 
+@@ -200,11 +205,33 @@ enum {
+ 	IFLA_INET6_CACHEINFO,	/* time values and max reasm size */
+ 	IFLA_INET6_ICMP6STATS,	/* statistics (icmpv6)		*/
+ 	IFLA_INET6_TOKEN,	/* device token			*/
++	IFLA_INET6_ADDR_GEN_MODE, /* implicit address generator mode */
+ 	__IFLA_INET6_MAX
+ };
+ 
+ #define IFLA_INET6_MAX	(__IFLA_INET6_MAX - 1)
+ 
++enum in6_addr_gen_mode {
++	IN6_ADDR_GEN_MODE_EUI64,
++	IN6_ADDR_GEN_MODE_NONE,
++	IN6_ADDR_GEN_MODE_STABLE_PRIVACY,
++};
++
++/* Bridge section */
++
++enum {
++	IFLA_BR_UNSPEC,
++	IFLA_BR_FORWARD_DELAY,
++	IFLA_BR_HELLO_TIME,
++	IFLA_BR_MAX_AGE,
++	IFLA_BR_AGEING_TIME,
++	IFLA_BR_STP_STATE,
++	IFLA_BR_PRIORITY,
++	__IFLA_BR_MAX,
++};
++
++#define IFLA_BR_MAX	(__IFLA_BR_MAX - 1)
++
+ enum {
+ 	BRIDGE_MODE_UNSPEC,
+ 	BRIDGE_MODE_HAIRPIN,
+@@ -219,6 +246,11 @@ enum {
+ 	IFLA_BRPORT_GUARD,	/* bpdu guard              */
+ 	IFLA_BRPORT_PROTECT,	/* root port protection    */
+ 	IFLA_BRPORT_FAST_LEAVE,	/* multicast fast leave    */
++	IFLA_BRPORT_LEARNING,	/* mac learning */
++	IFLA_BRPORT_UNICAST_FLOOD, /* flood unicast traffic */
++	IFLA_BRPORT_PROXYARP,	/* proxy ARP */
++	IFLA_BRPORT_LEARNING_SYNC, /* mac learning sync from device */
++	IFLA_BRPORT_PROXYARP_WIFI, /* proxy ARP for Wi-Fi */
+ 	__IFLA_BRPORT_MAX
+ };
+ #define IFLA_BRPORT_MAX (__IFLA_BRPORT_MAX - 1)
+@@ -235,6 +267,8 @@ enum {
+ 	IFLA_INFO_KIND,
+ 	IFLA_INFO_DATA,
+ 	IFLA_INFO_XSTATS,
++	IFLA_INFO_SLAVE_KIND,
++	IFLA_INFO_SLAVE_DATA,
+ 	__IFLA_INFO_MAX,
+ };
+ 
+@@ -277,6 +311,10 @@ enum {
+ 	IFLA_MACVLAN_UNSPEC,
+ 	IFLA_MACVLAN_MODE,
+ 	IFLA_MACVLAN_FLAGS,
++	IFLA_MACVLAN_MACADDR_MODE,
++	IFLA_MACVLAN_MACADDR,
++	IFLA_MACVLAN_MACADDR_DATA,
++	IFLA_MACVLAN_MACADDR_COUNT,
+ 	__IFLA_MACVLAN_MAX,
+ };
+ 
+@@ -287,10 +325,33 @@ enum macvlan_mode {
+ 	MACVLAN_MODE_VEPA    = 2, /* talk to other ports through ext bridge */
+ 	MACVLAN_MODE_BRIDGE  = 4, /* talk to bridge ports directly */
+ 	MACVLAN_MODE_PASSTHRU = 8,/* take over the underlying device */
++	MACVLAN_MODE_SOURCE  = 16,/* use source MAC address list to assign */
++};
++
++enum macvlan_macaddr_mode {
++	MACVLAN_MACADDR_ADD,
++	MACVLAN_MACADDR_DEL,
++	MACVLAN_MACADDR_FLUSH,
++	MACVLAN_MACADDR_SET,
+ };
+ 
+ #define MACVLAN_FLAG_NOPROMISC	1
+ 
++/* IPVLAN section */
++enum {
++	IFLA_IPVLAN_UNSPEC,
++	IFLA_IPVLAN_MODE,
++	__IFLA_IPVLAN_MAX
++};
++
++#define IFLA_IPVLAN_MAX (__IFLA_IPVLAN_MAX - 1)
++
++enum ipvlan_mode {
++	IPVLAN_MODE_L2 = 0,
++	IPVLAN_MODE_L3,
++	IPVLAN_MODE_MAX
++};
++
+ /* VXLAN section */
+ enum {
+ 	IFLA_VXLAN_UNSPEC,
+@@ -309,6 +370,15 @@ enum {
+ 	IFLA_VXLAN_L2MISS,
+ 	IFLA_VXLAN_L3MISS,
+ 	IFLA_VXLAN_PORT,	/* destination port */
++	IFLA_VXLAN_GROUP6,
++	IFLA_VXLAN_LOCAL6,
++	IFLA_VXLAN_UDP_CSUM,
++	IFLA_VXLAN_UDP_ZERO_CSUM6_TX,
++	IFLA_VXLAN_UDP_ZERO_CSUM6_RX,
++	IFLA_VXLAN_REMCSUM_TX,
++	IFLA_VXLAN_REMCSUM_RX,
++	IFLA_VXLAN_GBP,
++	IFLA_VXLAN_REMCSUM_NOPARTIAL,
+ 	__IFLA_VXLAN_MAX
+ };
+ #define IFLA_VXLAN_MAX	(__IFLA_VXLAN_MAX - 1)
+@@ -318,6 +388,63 @@ struct ifla_vxlan_port_range {
+ 	__be16	high;
+ };
+ 
++/* Bonding section */
++
++enum {
++	IFLA_BOND_UNSPEC,
++	IFLA_BOND_MODE,
++	IFLA_BOND_ACTIVE_SLAVE,
++	IFLA_BOND_MIIMON,
++	IFLA_BOND_UPDELAY,
++	IFLA_BOND_DOWNDELAY,
++	IFLA_BOND_USE_CARRIER,
++	IFLA_BOND_ARP_INTERVAL,
++	IFLA_BOND_ARP_IP_TARGET,
++	IFLA_BOND_ARP_VALIDATE,
++	IFLA_BOND_ARP_ALL_TARGETS,
++	IFLA_BOND_PRIMARY,
++	IFLA_BOND_PRIMARY_RESELECT,
++	IFLA_BOND_FAIL_OVER_MAC,
++	IFLA_BOND_XMIT_HASH_POLICY,
++	IFLA_BOND_RESEND_IGMP,
++	IFLA_BOND_NUM_PEER_NOTIF,
++	IFLA_BOND_ALL_SLAVES_ACTIVE,
++	IFLA_BOND_MIN_LINKS,
++	IFLA_BOND_LP_INTERVAL,
++	IFLA_BOND_PACKETS_PER_SLAVE,
++	IFLA_BOND_AD_LACP_RATE,
++	IFLA_BOND_AD_SELECT,
++	IFLA_BOND_AD_INFO,
++	__IFLA_BOND_MAX,
++};
++
++#define IFLA_BOND_MAX	(__IFLA_BOND_MAX - 1)
++
++enum {
++	IFLA_BOND_AD_INFO_UNSPEC,
++	IFLA_BOND_AD_INFO_AGGREGATOR,
++	IFLA_BOND_AD_INFO_NUM_PORTS,
++	IFLA_BOND_AD_INFO_ACTOR_KEY,
++	IFLA_BOND_AD_INFO_PARTNER_KEY,
++	IFLA_BOND_AD_INFO_PARTNER_MAC,
++	__IFLA_BOND_AD_INFO_MAX,
++};
++
++#define IFLA_BOND_AD_INFO_MAX	(__IFLA_BOND_AD_INFO_MAX - 1)
++
++enum {
++	IFLA_BOND_SLAVE_UNSPEC,
++	IFLA_BOND_SLAVE_STATE,
++	IFLA_BOND_SLAVE_MII_STATUS,
++	IFLA_BOND_SLAVE_LINK_FAILURE_COUNT,
++	IFLA_BOND_SLAVE_PERM_HWADDR,
++	IFLA_BOND_SLAVE_QUEUE_ID,
++	IFLA_BOND_SLAVE_AD_AGGREGATOR_ID,
++	__IFLA_BOND_SLAVE_MAX,
++};
++
++#define IFLA_BOND_SLAVE_MAX	(__IFLA_BOND_SLAVE_MAX - 1)
++
+ /* SR-IOV virtual function management section */
+ 
+ enum {
+@@ -332,8 +459,13 @@ enum {
+ 	IFLA_VF_UNSPEC,
+ 	IFLA_VF_MAC,		/* Hardware queue specific attributes */
+ 	IFLA_VF_VLAN,
+-	IFLA_VF_TX_RATE,	/* TX Bandwidth Allocation */
++	IFLA_VF_TX_RATE,	/* Max TX Bandwidth Allocation */
+ 	IFLA_VF_SPOOFCHK,	/* Spoof Checking on/off switch */
++	IFLA_VF_LINK_STATE,	/* link state enable/disable/auto switch */
++	IFLA_VF_RATE,		/* Min and Max TX Bandwidth Allocation */
++	IFLA_VF_RSS_QUERY_EN,	/* RSS Redirection Table and Hash Key query
++				 * on/off switch
++				 */
+ 	__IFLA_VF_MAX,
+ };
+ 
+@@ -355,11 +487,34 @@ struct ifla_vf_tx_rate {
+ 	__u32 rate; /* Max TX bandwidth in Mbps, 0 disables throttling */
+ };
+ 
++struct ifla_vf_rate {
++	__u32 vf;
++	__u32 min_tx_rate; /* Min Bandwidth in Mbps */
++	__u32 max_tx_rate; /* Max Bandwidth in Mbps */
++};
++
+ struct ifla_vf_spoofchk {
+ 	__u32 vf;
+ 	__u32 setting;
+ };
+ 
++enum {
++	IFLA_VF_LINK_STATE_AUTO,	/* link state of the uplink */
++	IFLA_VF_LINK_STATE_ENABLE,	/* link always up */
++	IFLA_VF_LINK_STATE_DISABLE,	/* link always down */
++	__IFLA_VF_LINK_STATE_MAX,
++};
++
++struct ifla_vf_link_state {
++	__u32 vf;
++	__u32 link_state;
++};
++
++struct ifla_vf_rss_query_en {
++	__u32 vf;
++	__u32 setting;
++};
++
+ /* VF ports management section
+  *
+  *	Nested layout of set/get msg is:
+@@ -450,4 +605,19 @@ enum {
+ 
+ #define IFLA_IPOIB_MAX (__IFLA_IPOIB_MAX - 1)
+ 
++
++/* HSR section */
++
++enum {
++	IFLA_HSR_UNSPEC,
++	IFLA_HSR_SLAVE1,
++	IFLA_HSR_SLAVE2,
++	IFLA_HSR_MULTICAST_SPEC,	/* Last byte of supervision addr */
++	IFLA_HSR_SUPERVISION_ADDR,	/* Supervision frame multicast addr */
++	IFLA_HSR_SEQ_NR,
++	__IFLA_HSR_MAX,
++};
++
++#define IFLA_HSR_MAX (__IFLA_HSR_MAX - 1)
++
+ #endif /* _LINUX_IF_LINK_H */
+diff --git a/include/linux/if_tun.h b/include/linux/if_tun.h
+index dffb192..ffee583 100644
+--- a/include/linux/if_tun.h
++++ b/include/linux/if_tun.h
+@@ -22,21 +22,11 @@
+ 
+ /* Read queue size */
+ #define TUN_READQ_SIZE	500
+-
+-/* TUN device flags */
+-#define TUN_TUN_DEV 	0x0001	
+-#define TUN_TAP_DEV	0x0002
++/* TUN device type flags: deprecated. Use IFF_TUN/IFF_TAP instead. */
++#define TUN_TUN_DEV 	IFF_TUN
++#define TUN_TAP_DEV	IFF_TAP
+ #define TUN_TYPE_MASK   0x000f
+ 
+-#define TUN_FASYNC	0x0010
+-#define TUN_NOCHECKSUM	0x0020
+-#define TUN_NO_PI	0x0040
+-/* This flag has no real effect */
+-#define TUN_ONE_QUEUE	0x0080
+-#define TUN_PERSIST 	0x0100	
+-#define TUN_VNET_HDR 	0x0200
+-#define TUN_TAP_MQ      0x0400
+-
+ /* Ioctl defines */
+ #define TUNSETNOCSUM  _IOW('T', 200, int) 
+ #define TUNSETDEBUG   _IOW('T', 201, int) 
+@@ -56,6 +46,10 @@
+ #define TUNGETVNETHDRSZ _IOR('T', 215, int)
+ #define TUNSETVNETHDRSZ _IOW('T', 216, int)
+ #define TUNSETQUEUE  _IOW('T', 217, int)
++#define TUNSETIFINDEX	_IOW('T', 218, unsigned int)
++#define TUNGETFILTER _IOR('T', 219, struct sock_fprog)
++#define TUNSETVNETLE _IOW('T', 220, int)
++#define TUNGETVNETLE _IOR('T', 221, int)
+ 
+ /* TUNSETIFF ifr flags */
+ #define IFF_TUN		0x0001
+@@ -68,6 +62,12 @@
+ #define IFF_MULTI_QUEUE 0x0100
+ #define IFF_ATTACH_QUEUE 0x0200
+ #define IFF_DETACH_QUEUE 0x0400
++/* read-only flag */
++#define IFF_PERSIST	0x0800
++#define IFF_NOFILTER	0x1000
++
++/* Socket options */
++#define TUN_TX_TIMESTAMP 1
+ 
+ /* Features for GSO (TUNSETOFFLOAD). */
+ #define TUN_F_CSUM	0x01	/* You can hand me unchecksummed packets. */
+diff --git a/include/linux/if_tunnel.h b/include/linux/if_tunnel.h
+index 9f471ca..102ce7a 100644
+--- a/include/linux/if_tunnel.h
++++ b/include/linux/if_tunnel.h
+@@ -53,10 +53,24 @@ enum {
+ 	IFLA_IPTUN_6RD_RELAY_PREFIX,
+ 	IFLA_IPTUN_6RD_PREFIXLEN,
+ 	IFLA_IPTUN_6RD_RELAY_PREFIXLEN,
++	IFLA_IPTUN_ENCAP_TYPE,
++	IFLA_IPTUN_ENCAP_FLAGS,
++	IFLA_IPTUN_ENCAP_SPORT,
++	IFLA_IPTUN_ENCAP_DPORT,
+ 	__IFLA_IPTUN_MAX,
+ };
+ #define IFLA_IPTUN_MAX	(__IFLA_IPTUN_MAX - 1)
+ 
++enum tunnel_encap_types {
++	TUNNEL_ENCAP_NONE,
++	TUNNEL_ENCAP_FOU,
++	TUNNEL_ENCAP_GUE,
++};
++
++#define TUNNEL_ENCAP_FLAG_CSUM		(1<<0)
++#define TUNNEL_ENCAP_FLAG_CSUM6		(1<<1)
++#define TUNNEL_ENCAP_FLAG_REMCSUM	(1<<2)
++
+ /* SIT-mode i_flags */
+ #define	SIT_ISATAP	0x0001
+ 
+@@ -94,13 +108,17 @@ enum {
+ 	IFLA_GRE_ENCAP_LIMIT,
+ 	IFLA_GRE_FLOWINFO,
+ 	IFLA_GRE_FLAGS,
++	IFLA_GRE_ENCAP_TYPE,
++	IFLA_GRE_ENCAP_FLAGS,
++	IFLA_GRE_ENCAP_SPORT,
++	IFLA_GRE_ENCAP_DPORT,
+ 	__IFLA_GRE_MAX,
+ };
+ 
+ #define IFLA_GRE_MAX	(__IFLA_GRE_MAX - 1)
+ 
+ /* VTI-mode i_flags */
+-#define VTI_ISVTI 0x0001
++#define VTI_ISVTI ((__be16)0x0001)
+ 
+ enum {
+ 	IFLA_VTI_UNSPEC,
+diff --git a/include/linux/in6.h b/include/linux/in6.h
+new file mode 100644
+index 0000000..994f4c2
+--- /dev/null
++++ b/include/linux/in6.h
+@@ -0,0 +1,293 @@
++/*
++ *	Types and definitions for AF_INET6 
++ *	Linux INET6 implementation 
++ *
++ *	Authors:
++ *	Pedro Roque		<roque@di.fc.ul.pt>	
++ *
++ *	Sources:
++ *	IPv6 Program Interfaces for BSD Systems
++ *      <draft-ietf-ipngwg-bsd-api-05.txt>
++ *
++ *	Advanced Sockets API for IPv6
++ *	<draft-stevens-advanced-api-00.txt>
++ *
++ *	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.
++ */
++
++#ifndef _LINUX_IN6_H
++#define _LINUX_IN6_H
++
++#include <linux/types.h>
++#include <linux/libc-compat.h>
++
++/*
++ *	IPv6 address structure
++ */
++
++#if __UAPI_DEF_IN6_ADDR
++struct in6_addr {
++	union {
++		__u8		u6_addr8[16];
++#if __UAPI_DEF_IN6_ADDR_ALT
++		__be16		u6_addr16[8];
++		__be32		u6_addr32[4];
++#endif
++	} in6_u;
++#define s6_addr			in6_u.u6_addr8
++#if __UAPI_DEF_IN6_ADDR_ALT
++#define s6_addr16		in6_u.u6_addr16
++#define s6_addr32		in6_u.u6_addr32
++#endif
++};
++#endif /* __UAPI_DEF_IN6_ADDR */
++
++#if __UAPI_DEF_SOCKADDR_IN6
++struct sockaddr_in6 {
++	unsigned short int	sin6_family;    /* AF_INET6 */
++	__be16			sin6_port;      /* Transport layer port # */
++	__be32			sin6_flowinfo;  /* IPv6 flow information */
++	struct in6_addr		sin6_addr;      /* IPv6 address */
++	__u32			sin6_scope_id;  /* scope id (new in RFC2553) */
++};
++#endif /* __UAPI_DEF_SOCKADDR_IN6 */
++
++#if __UAPI_DEF_IPV6_MREQ
++struct ipv6_mreq {
++	/* IPv6 multicast address of group */
++	struct in6_addr ipv6mr_multiaddr;
++
++	/* local IPv6 address of interface */
++	int		ipv6mr_ifindex;
++};
++#endif /* __UAPI_DEF_IVP6_MREQ */
++
++#define ipv6mr_acaddr	ipv6mr_multiaddr
++
++struct in6_flowlabel_req {
++	struct in6_addr	flr_dst;
++	__be32	flr_label;
++	__u8	flr_action;
++	__u8	flr_share;
++	__u16	flr_flags;
++	__u16 	flr_expires;
++	__u16	flr_linger;
++	__u32	__flr_pad;
++	/* Options in format of IPV6_PKTOPTIONS */
++};
++
++#define IPV6_FL_A_GET	0
++#define IPV6_FL_A_PUT	1
++#define IPV6_FL_A_RENEW	2
++
++#define IPV6_FL_F_CREATE	1
++#define IPV6_FL_F_EXCL		2
++#define IPV6_FL_F_REFLECT	4
++#define IPV6_FL_F_REMOTE	8
++
++#define IPV6_FL_S_NONE		0
++#define IPV6_FL_S_EXCL		1
++#define IPV6_FL_S_PROCESS	2
++#define IPV6_FL_S_USER		3
++#define IPV6_FL_S_ANY		255
++
++
++/*
++ *	Bitmask constant declarations to help applications select out the 
++ *	flow label and priority fields.
++ *
++ *	Note that this are in host byte order while the flowinfo field of
++ *	sockaddr_in6 is in network byte order.
++ */
++
++#define IPV6_FLOWINFO_FLOWLABEL		0x000fffff
++#define IPV6_FLOWINFO_PRIORITY		0x0ff00000
++
++/* These definitions are obsolete */
++#define IPV6_PRIORITY_UNCHARACTERIZED	0x0000
++#define IPV6_PRIORITY_FILLER		0x0100
++#define IPV6_PRIORITY_UNATTENDED	0x0200
++#define IPV6_PRIORITY_RESERVED1		0x0300
++#define IPV6_PRIORITY_BULK		0x0400
++#define IPV6_PRIORITY_RESERVED2		0x0500
++#define IPV6_PRIORITY_INTERACTIVE	0x0600
++#define IPV6_PRIORITY_CONTROL		0x0700
++#define IPV6_PRIORITY_8			0x0800
++#define IPV6_PRIORITY_9			0x0900
++#define IPV6_PRIORITY_10		0x0a00
++#define IPV6_PRIORITY_11		0x0b00
++#define IPV6_PRIORITY_12		0x0c00
++#define IPV6_PRIORITY_13		0x0d00
++#define IPV6_PRIORITY_14		0x0e00
++#define IPV6_PRIORITY_15		0x0f00
++
++/*
++ *	IPV6 extension headers
++ */
++#if __UAPI_DEF_IPPROTO_V6
++#define IPPROTO_HOPOPTS		0	/* IPv6 hop-by-hop options	*/
++#define IPPROTO_ROUTING		43	/* IPv6 routing header		*/
++#define IPPROTO_FRAGMENT	44	/* IPv6 fragmentation header	*/
++#define IPPROTO_ICMPV6		58	/* ICMPv6			*/
++#define IPPROTO_NONE		59	/* IPv6 no next header		*/
++#define IPPROTO_DSTOPTS		60	/* IPv6 destination options	*/
++#define IPPROTO_MH		135	/* IPv6 mobility header		*/
++#endif /* __UAPI_DEF_IPPROTO_V6 */
++
++/*
++ *	IPv6 TLV options.
++ */
++#define IPV6_TLV_PAD1		0
++#define IPV6_TLV_PADN		1
++#define IPV6_TLV_ROUTERALERT	5
++#define IPV6_TLV_JUMBO		194
++#define IPV6_TLV_HAO		201	/* home address option */
++
++/*
++ *	IPV6 socket options
++ */
++#if __UAPI_DEF_IPV6_OPTIONS
++#define IPV6_ADDRFORM		1
++#define IPV6_2292PKTINFO	2
++#define IPV6_2292HOPOPTS	3
++#define IPV6_2292DSTOPTS	4
++#define IPV6_2292RTHDR		5
++#define IPV6_2292PKTOPTIONS	6
++#define IPV6_CHECKSUM		7
++#define IPV6_2292HOPLIMIT	8
++#define IPV6_NEXTHOP		9
++#define IPV6_AUTHHDR		10	/* obsolete */
++#define IPV6_FLOWINFO		11
++
++#define IPV6_UNICAST_HOPS	16
++#define IPV6_MULTICAST_IF	17
++#define IPV6_MULTICAST_HOPS	18
++#define IPV6_MULTICAST_LOOP	19
++#define IPV6_ADD_MEMBERSHIP	20
++#define IPV6_DROP_MEMBERSHIP	21
++#define IPV6_ROUTER_ALERT	22
++#define IPV6_MTU_DISCOVER	23
++#define IPV6_MTU		24
++#define IPV6_RECVERR		25
++#define IPV6_V6ONLY		26
++#define IPV6_JOIN_ANYCAST	27
++#define IPV6_LEAVE_ANYCAST	28
++
++/* IPV6_MTU_DISCOVER values */
++#define IPV6_PMTUDISC_DONT		0
++#define IPV6_PMTUDISC_WANT		1
++#define IPV6_PMTUDISC_DO		2
++#define IPV6_PMTUDISC_PROBE		3
++/* same as IPV6_PMTUDISC_PROBE, provided for symetry with IPv4
++ * also see comments on IP_PMTUDISC_INTERFACE
++ */
++#define IPV6_PMTUDISC_INTERFACE		4
++/* weaker version of IPV6_PMTUDISC_INTERFACE, which allows packets to
++ * get fragmented if they exceed the interface mtu
++ */
++#define IPV6_PMTUDISC_OMIT		5
++
++/* Flowlabel */
++#define IPV6_FLOWLABEL_MGR	32
++#define IPV6_FLOWINFO_SEND	33
++
++#define IPV6_IPSEC_POLICY	34
++#define IPV6_XFRM_POLICY	35
++#endif
++
++/*
++ * Multicast:
++ * Following socket options are shared between IPv4 and IPv6.
++ *
++ * MCAST_JOIN_GROUP		42
++ * MCAST_BLOCK_SOURCE		43
++ * MCAST_UNBLOCK_SOURCE		44
++ * MCAST_LEAVE_GROUP		45
++ * MCAST_JOIN_SOURCE_GROUP	46
++ * MCAST_LEAVE_SOURCE_GROUP	47
++ * MCAST_MSFILTER		48
++ */
++
++/*
++ * Advanced API (RFC3542) (1)
++ *
++ * Note: IPV6_RECVRTHDRDSTOPTS does not exist. see net/ipv6/datagram.c.
++ */
++
++#define IPV6_RECVPKTINFO	49
++#define IPV6_PKTINFO		50
++#define IPV6_RECVHOPLIMIT	51
++#define IPV6_HOPLIMIT		52
++#define IPV6_RECVHOPOPTS	53
++#define IPV6_HOPOPTS		54
++#define IPV6_RTHDRDSTOPTS	55
++#define IPV6_RECVRTHDR		56
++#define IPV6_RTHDR		57
++#define IPV6_RECVDSTOPTS	58
++#define IPV6_DSTOPTS		59
++#define IPV6_RECVPATHMTU	60
++#define IPV6_PATHMTU		61
++#define IPV6_DONTFRAG		62
++#if 0	/* not yet */
++#define IPV6_USE_MIN_MTU	63
++#endif
++
++/*
++ * Netfilter (1)
++ *
++ * Following socket options are used in ip6_tables;
++ * see include/linux/netfilter_ipv6/ip6_tables.h.
++ *
++ * IP6T_SO_SET_REPLACE / IP6T_SO_GET_INFO		64
++ * IP6T_SO_SET_ADD_COUNTERS / IP6T_SO_GET_ENTRIES	65
++ */
++
++/*
++ * Advanced API (RFC3542) (2)
++ */
++#define IPV6_RECVTCLASS		66
++#define IPV6_TCLASS		67
++
++/*
++ * Netfilter (2)
++ *
++ * Following socket options are used in ip6_tables;
++ * see include/linux/netfilter_ipv6/ip6_tables.h.
++ *
++ * IP6T_SO_GET_REVISION_MATCH	68
++ * IP6T_SO_GET_REVISION_TARGET	69
++ * IP6T_SO_ORIGINAL_DST		80
++ */
++
++#define IPV6_AUTOFLOWLABEL	70
++/* RFC5014: Source address selection */
++#define IPV6_ADDR_PREFERENCES	72
++
++#define IPV6_PREFER_SRC_TMP		0x0001
++#define IPV6_PREFER_SRC_PUBLIC		0x0002
++#define IPV6_PREFER_SRC_PUBTMP_DEFAULT	0x0100
++#define IPV6_PREFER_SRC_COA		0x0004
++#define IPV6_PREFER_SRC_HOME		0x0400
++#define IPV6_PREFER_SRC_CGA		0x0008
++#define IPV6_PREFER_SRC_NONCGA		0x0800
++
++/* RFC5082: Generalized Ttl Security Mechanism */
++#define IPV6_MINHOPCOUNT		73
++
++#define IPV6_ORIGDSTADDR        74
++#define IPV6_RECVORIGDSTADDR    IPV6_ORIGDSTADDR
++#define IPV6_TRANSPARENT        75
++#define IPV6_UNICAST_IF         76
++
++/*
++ * Multicast Routing:
++ * see include/uapi/linux/mroute6.h.
++ *
++ * MRT6_BASE			200
++ * ...
++ * MRT6_MAX
++ */
++#endif /* _LINUX_IN6_H */
+diff --git a/include/linux/inet_diag.h b/include/linux/inet_diag.h
+index e34f247..7438dad 100644
+--- a/include/linux/inet_diag.h
++++ b/include/linux/inet_diag.h
+@@ -110,10 +110,10 @@ enum {
+ 	INET_DIAG_TCLASS,
+ 	INET_DIAG_SKMEMINFO,
+ 	INET_DIAG_SHUTDOWN,
++	INET_DIAG_DCTCPINFO,
+ };
+ 
+-#define INET_DIAG_MAX INET_DIAG_SHUTDOWN
+-
++#define INET_DIAG_MAX INET_DIAG_DCTCPINFO
+ 
+ /* INET_DIAG_MEM */
+ 
+@@ -133,5 +133,14 @@ struct tcpvegas_info {
+ 	__u32	tcpv_minrtt;
+ };
+ 
++/* INET_DIAG_DCTCPINFO */
++
++struct tcp_dctcp_info {
++	__u16	dctcp_enabled;
++	__u16	dctcp_ce_state;
++	__u32	dctcp_alpha;
++	__u32	dctcp_ab_ecn;
++	__u32	dctcp_ab_tot;
++};
+ 
+ #endif /* _INET_DIAG_H_ */
+diff --git a/include/linux/l2tp.h b/include/linux/l2tp.h
+index c4bec82..5b0e36d 100644
+--- a/include/linux/l2tp.h
++++ b/include/linux/l2tp.h
+@@ -122,6 +122,8 @@ enum {
+ 	L2TP_ATTR_STATS,		/* nested */
+ 	L2TP_ATTR_IP6_SADDR,		/* struct in6_addr */
+ 	L2TP_ATTR_IP6_DADDR,		/* struct in6_addr */
++	L2TP_ATTR_UDP_ZERO_CSUM6_TX,	/* u8 */
++	L2TP_ATTR_UDP_ZERO_CSUM6_RX,	/* u8 */
+ 	__L2TP_ATTR_MAX,
+ };
+ 
+@@ -174,5 +176,6 @@ enum l2tp_seqmode {
+  */
+ #define L2TP_GENL_NAME		"l2tp"
+ #define L2TP_GENL_VERSION	0x1
++#define L2TP_GENL_MCGROUP       "l2tp"
+ 
+ #endif /* _LINUX_L2TP_H_ */
+diff --git a/include/linux/libc-compat.h b/include/linux/libc-compat.h
+new file mode 100644
+index 0000000..990332e
+--- /dev/null
++++ b/include/linux/libc-compat.h
+@@ -0,0 +1,121 @@
++/*
++ * Compatibility interface for userspace libc header coordination:
++ *
++ * Define compatibility macros that are used to control the inclusion or
++ * exclusion of UAPI structures and definitions in coordination with another
++ * userspace C library.
++ *
++ * This header is intended to solve the problem of UAPI definitions that
++ * conflict with userspace definitions. If a UAPI header has such conflicting
++ * definitions then the solution is as follows:
++ *
++ * * Synchronize the UAPI header and the libc headers so either one can be
++ *   used and such that the ABI is preserved. If this is not possible then
++ *   no simple compatibility interface exists (you need to write translating
++ *   wrappers and rename things) and you can't use this interface.
++ *
++ * Then follow this process:
++ *
++ * (a) Include libc-compat.h in the UAPI header.
++ *      e.g. #include <linux/libc-compat.h>
++ *     This include must be as early as possible.
++ *
++ * (b) In libc-compat.h add enough code to detect that the comflicting
++ *     userspace libc header has been included first.
++ *
++ * (c) If the userspace libc header has been included first define a set of
++ *     guard macros of the form __UAPI_DEF_FOO and set their values to 1, else
++ *     set their values to 0.
++ *
++ * (d) Back in the UAPI header with the conflicting definitions, guard the
++ *     definitions with:
++ *     #if __UAPI_DEF_FOO
++ *       ...
++ *     #endif
++ *
++ * This fixes the situation where the linux headers are included *after* the
++ * libc headers. To fix the problem with the inclusion in the other order the
++ * userspace libc headers must be fixed like this:
++ *
++ * * For all definitions that conflict with kernel definitions wrap those
++ *   defines in the following:
++ *   #if !__UAPI_DEF_FOO
++ *     ...
++ *   #endif
++ *
++ * This prevents the redefinition of a construct already defined by the kernel.
++ */
++#ifndef _LIBC_COMPAT_H
++#define _LIBC_COMPAT_H
++
++/* We have included glibc headers... */
++#if defined(__GLIBC__)
++
++/* Coordinate with glibc netinet/in.h header. */
++#if defined(_NETINET_IN_H)
++
++/* GLIBC headers included first so don't define anything
++ * that would already be defined. */
++#define __UAPI_DEF_IN6_ADDR		0
++/* The exception is the in6_addr macros which must be defined
++ * if the glibc code didn't define them. This guard matches
++ * the guard in glibc/inet/netinet/in.h which defines the
++ * additional in6_addr macros e.g. s6_addr16, and s6_addr32. */
++#if defined(__USE_MISC) || defined (__USE_GNU)
++#define __UAPI_DEF_IN6_ADDR_ALT		0
++#else
++#define __UAPI_DEF_IN6_ADDR_ALT		1
++#endif
++#define __UAPI_DEF_SOCKADDR_IN6		0
++#define __UAPI_DEF_IPV6_MREQ		0
++#define __UAPI_DEF_IPPROTO_V6		0
++#define __UAPI_DEF_IPV6_OPTIONS		0
++#define __UAPI_DEF_IN6_PKTINFO		0
++#define __UAPI_DEF_IP6_MTUINFO		0
++
++#else
++
++/* Linux headers included first, and we must define everything
++ * we need. The expectation is that glibc will check the
++ * __UAPI_DEF_* defines and adjust appropriately. */
++#define __UAPI_DEF_IN6_ADDR		1
++/* We unconditionally define the in6_addr macros and glibc must
++ * coordinate. */
++#define __UAPI_DEF_IN6_ADDR_ALT		1
++#define __UAPI_DEF_SOCKADDR_IN6		1
++#define __UAPI_DEF_IPV6_MREQ		1
++#define __UAPI_DEF_IPPROTO_V6		1
++#define __UAPI_DEF_IPV6_OPTIONS		1
++#define __UAPI_DEF_IN6_PKTINFO		1
++#define __UAPI_DEF_IP6_MTUINFO		1
++
++#endif /* _NETINET_IN_H */
++
++/* Definitions for xattr.h */
++#if defined(_SYS_XATTR_H)
++#define __UAPI_DEF_XATTR		0
++#else
++#define __UAPI_DEF_XATTR		1
++#endif
++
++/* If we did not see any headers from any supported C libraries,
++ * or we are being included in the kernel, then define everything
++ * that we need. */
++#else /* !defined(__GLIBC__) */
++
++/* Definitions for in6.h */
++#define __UAPI_DEF_IN6_ADDR		1
++#define __UAPI_DEF_IN6_ADDR_ALT		1
++#define __UAPI_DEF_SOCKADDR_IN6		1
++#define __UAPI_DEF_IPV6_MREQ		1
++#define __UAPI_DEF_IPPROTO_V6		1
++#define __UAPI_DEF_IPV6_OPTIONS		1
++#define __UAPI_DEF_IN6_PKTINFO		1
++#define __UAPI_DEF_IP6_MTUINFO		1
++
++/* Definitions for xattr.h */
++#define __UAPI_DEF_XATTR		1
++
++#endif /* __GLIBC__ */
++
++#endif /* _LIBC_COMPAT_H */
+diff --git a/include/linux/mpls.h b/include/linux/mpls.h
+new file mode 100644
+index 0000000..0893902
+--- /dev/null
++++ b/include/linux/mpls.h
+@@ -0,0 +1,34 @@
++#ifndef _MPLS_H
++#define _MPLS_H
++
++#include <linux/types.h>
++#include <asm/byteorder.h>
++
++/* Reference: RFC 5462, RFC 3032
++ *
++ *  0                   1                   2                   3
++ *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
++ * |                Label                  | TC  |S|       TTL     |
++ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
++ *
++ *	Label:  Label Value, 20 bits
++ *	TC:     Traffic Class field, 3 bits
++ *	S:      Bottom of Stack, 1 bit
++ *	TTL:    Time to Live, 8 bits
++ */
++
++struct mpls_label {
++	__be32 entry;
++};
++
++#define MPLS_LS_LABEL_MASK      0xFFFFF000
++#define MPLS_LS_LABEL_SHIFT     12
++#define MPLS_LS_TC_MASK         0x00000E00
++#define MPLS_LS_TC_SHIFT        9
++#define MPLS_LS_S_MASK          0x00000100
++#define MPLS_LS_S_SHIFT         8
++#define MPLS_LS_TTL_MASK        0x000000FF
++#define MPLS_LS_TTL_SHIFT       0
++
++#endif /* _MPLS_H */
+diff --git a/include/linux/neighbour.h b/include/linux/neighbour.h
+index f175212..2e35c61 100644
+--- a/include/linux/neighbour.h
++++ b/include/linux/neighbour.h
+@@ -24,6 +24,8 @@ enum {
+ 	NDA_PORT,
+ 	NDA_VNI,
+ 	NDA_IFINDEX,
++	NDA_MASTER,
++	NDA_LINK_NETNSID,
+ 	__NDA_MAX
+ };
+ 
+@@ -34,11 +36,11 @@ enum {
+  */
+ 
+ #define NTF_USE		0x01
+-#define NTF_PROXY	0x08	/* == ATF_PUBL */
+-#define NTF_ROUTER	0x80
+-
+ #define NTF_SELF	0x02
+ #define NTF_MASTER	0x04
++#define NTF_PROXY	0x08	/* == ATF_PUBL */
++#define NTF_EXT_LEARNED	0x10
++#define NTF_ROUTER	0x80
+ 
+ /*
+  *	Neighbor Cache Entry States.
+@@ -58,7 +60,7 @@ enum {
+ 
+ /* NUD_NOARP & NUD_PERMANENT are pseudostates, they never change
+    and make no address resolution or NUD.
+-   NUD_PERMANENT is also cannot be deleted by garbage collectors.
++   NUD_PERMANENT also cannot be deleted by garbage collectors.
+  */
+ 
+ struct nda_cacheinfo {
+@@ -124,6 +126,7 @@ enum {
+ 	NDTPA_PROXY_QLEN,		/* u32 */
+ 	NDTPA_LOCKTIME,			/* u64, msecs */
+ 	NDTPA_QUEUE_LENBYTES,		/* u32 */
++	NDTPA_MCAST_REPROBES,		/* u32 */
+ 	__NDTPA_MAX
+ };
+ #define NDTPA_MAX (__NDTPA_MAX - 1)
+diff --git a/include/linux/net_namespace.h b/include/linux/net_namespace.h
+new file mode 100644
+index 0000000..9a92b7e
+--- /dev/null
++++ b/include/linux/net_namespace.h
+@@ -0,0 +1,23 @@
++/* Copyright (c) 2015 6WIND S.A.
++ * Author: Nicolas Dichtel <nicolas.dichtel@6wind.com>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms and conditions of the GNU General Public License,
++ * version 2, as published by the Free Software Foundation.
++ */
++#ifndef _LINUX_NET_NAMESPACE_H_
++#define _LINUX_NET_NAMESPACE_H_
++
++/* Attributes of RTM_NEWNSID/RTM_GETNSID messages */
++enum {
++	NETNSA_NONE,
++#define NETNSA_NSID_NOT_ASSIGNED -1
++	NETNSA_NSID,
++	NETNSA_PID,
++	NETNSA_FD,
++	__NETNSA_MAX,
++};
++
++#define NETNSA_MAX		(__NETNSA_MAX - 1)
++
++#endif /* _LINUX_NET_NAMESPACE_H_ */
+diff --git a/include/linux/netconf.h b/include/linux/netconf.h
+index 52c4424..6ceb170 100644
+--- a/include/linux/netconf.h
++++ b/include/linux/netconf.h
+@@ -14,6 +14,7 @@ enum {
+ 	NETCONFA_FORWARDING,
+ 	NETCONFA_RP_FILTER,
+ 	NETCONFA_MC_FORWARDING,
++	NETCONFA_PROXY_NEIGH,
+ 	__NETCONFA_MAX
+ };
+ #define NETCONFA_MAX	(__NETCONFA_MAX - 1)
+diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
+index adc7260..66fceb4 100644
+--- a/include/linux/netdevice.h
++++ b/include/linux/netdevice.h
+@@ -37,6 +37,12 @@
+ #define INIT_NETDEV_GROUP	0
+ 
+ 
++/* interface name assignment types (sysfs name_assign_type attribute) */
++#define NET_NAME_UNKNOWN	0	/* unknown origin (not exposed to userspace) */
++#define NET_NAME_ENUM		1	/* enumerated by kernel */
++#define NET_NAME_PREDICTABLE	2	/* predictably named by the kernel */
++#define NET_NAME_USER		3	/* provided by user-space */
++#define NET_NAME_RENAMED	4	/* renamed by user-space */
+ 
+ /* Media selection options. */
+ enum {
+@@ -49,5 +55,11 @@ enum {
+         IF_PORT_100BASEFX
+ };
+ 
++/* hardware address assignment types */
++#define NET_ADDR_PERM		0	/* address is permanent (default) */
++#define NET_ADDR_RANDOM		1	/* address is generated randomly */
++#define NET_ADDR_STOLEN		2	/* address is stolen from other device */
++#define NET_ADDR_SET		3	/* address is set using
++					 * dev_set_mac_address() */
+ 
+ #endif /* _LINUX_NETDEVICE_H */
+diff --git a/include/linux/netfilter.h b/include/linux/netfilter.h
+index f05c3d9..be0bc18 100644
+--- a/include/linux/netfilter.h
++++ b/include/linux/netfilter.h
+@@ -51,6 +51,7 @@ enum nf_inet_hooks {
+ 
+ enum {
+ 	NFPROTO_UNSPEC =  0,
++	NFPROTO_INET   =  1,
+ 	NFPROTO_IPV4   =  2,
+ 	NFPROTO_ARP    =  3,
+ 	NFPROTO_BRIDGE =  7,
+diff --git a/include/linux/netlink_diag.h b/include/linux/netlink_diag.h
+index 4e31db4..f2159d3 100644
+--- a/include/linux/netlink_diag.h
++++ b/include/linux/netlink_diag.h
+@@ -33,6 +33,7 @@ struct netlink_diag_ring {
+ };
+ 
+ enum {
++	/* NETLINK_DIAG_NONE, standard nl API requires this attribute!  */
+ 	NETLINK_DIAG_MEMINFO,
+ 	NETLINK_DIAG_GROUPS,
+ 	NETLINK_DIAG_RX_RING,
+diff --git a/include/linux/packet_diag.h b/include/linux/packet_diag.h
+index b2cc0cd..d08c63f 100644
+--- a/include/linux/packet_diag.h
++++ b/include/linux/packet_diag.h
+@@ -29,6 +29,7 @@ struct packet_diag_msg {
+ };
+ 
+ enum {
++	/* PACKET_DIAG_NONE, standard nl API requires this attribute!  */
+ 	PACKET_DIAG_INFO,
+ 	PACKET_DIAG_MCLIST,
+ 	PACKET_DIAG_RX_RING,
+diff --git a/include/linux/pkt_cls.h b/include/linux/pkt_cls.h
+index 082eafa..bf08e76 100644
+--- a/include/linux/pkt_cls.h
++++ b/include/linux/pkt_cls.h
+@@ -388,6 +388,22 @@ enum {
+ 
+ #define TCA_CGROUP_MAX (__TCA_CGROUP_MAX - 1)
+ 
++/* BPF classifier */
++
++enum {
++	TCA_BPF_UNSPEC,
++	TCA_BPF_ACT,
++	TCA_BPF_POLICE,
++	TCA_BPF_CLASSID,
++	TCA_BPF_OPS_LEN,
++	TCA_BPF_OPS,
++	TCA_BPF_FD,
++	TCA_BPF_NAME,
++	__TCA_BPF_MAX,
++};
++
++#define TCA_BPF_MAX (__TCA_BPF_MAX - 1)
++
+ /* Extended Matches */
+ 
+ struct tcf_ematch_tree_hdr {
+diff --git a/include/linux/pkt_sched.h b/include/linux/pkt_sched.h
+index dbd71b0..534b847 100644
+--- a/include/linux/pkt_sched.h
++++ b/include/linux/pkt_sched.h
+@@ -73,9 +73,17 @@ struct tc_estimator {
+ #define TC_H_ROOT	(0xFFFFFFFFU)
+ #define TC_H_INGRESS    (0xFFFFFFF1U)
+ 
++/* Need to corrospond to iproute2 tc/tc_core.h "enum link_layer" */
++enum tc_link_layer {
++	TC_LINKLAYER_UNAWARE, /* Indicate unaware old iproute2 util */
++	TC_LINKLAYER_ETHERNET,
++	TC_LINKLAYER_ATM,
++};
++#define TC_LINKLAYER_MASK 0x0F /* limit use to lower 4 bits */
++
+ struct tc_ratespec {
+ 	unsigned char	cell_log;
+-	unsigned char	__reserved;
++	__u8		linklayer; /* lower 4 bits */
+ 	unsigned short	overhead;
+ 	short		cell_align;
+ 	unsigned short	mpu;
+@@ -163,6 +171,10 @@ enum {
+ 	TCA_TBF_PARMS,
+ 	TCA_TBF_RTAB,
+ 	TCA_TBF_PTAB,
++	TCA_TBF_RATE64,
++	TCA_TBF_PRATE64,
++	TCA_TBF_BURST,
++	TCA_TBF_PBURST,
+ 	__TCA_TBF_MAX,
+ };
+ 
+@@ -349,6 +361,8 @@ enum {
+ 	TCA_HTB_CTAB,
+ 	TCA_HTB_RTAB,
+ 	TCA_HTB_DIRECT_QLEN,
++	TCA_HTB_RATE64,
++	TCA_HTB_CEIL64,
+ 	__TCA_HTB_MAX,
+ };
+ 
+@@ -511,6 +525,7 @@ enum {
+ 	TCA_NETEM_LOSS,
+ 	TCA_NETEM_RATE,
+ 	TCA_NETEM_ECN,
++	TCA_NETEM_RATE64,
+ 	__TCA_NETEM_MAX,
+ };
+ 
+@@ -736,4 +751,98 @@ struct tc_fq_codel_xstats {
+ 	};
+ };
+ 
++/* FQ */
++
++enum {
++	TCA_FQ_UNSPEC,
++
++	TCA_FQ_PLIMIT,		/* limit of total number of packets in queue */
++
++	TCA_FQ_FLOW_PLIMIT,	/* limit of packets per flow */
++
++	TCA_FQ_QUANTUM,		/* RR quantum */
++
++	TCA_FQ_INITIAL_QUANTUM,		/* RR quantum for new flow */
++
++	TCA_FQ_RATE_ENABLE,	/* enable/disable rate limiting */
++
++	TCA_FQ_FLOW_DEFAULT_RATE,/* obsolete, do not use */
++
++	TCA_FQ_FLOW_MAX_RATE,	/* per flow max rate */
++
++	TCA_FQ_BUCKETS_LOG,	/* log2(number of buckets) */
++
++	TCA_FQ_FLOW_REFILL_DELAY,	/* flow credit refill delay in usec */
++
++	TCA_FQ_ORPHAN_MASK,	/* mask applied to orphaned skb hashes */
++
++	__TCA_FQ_MAX
++};
++
++#define TCA_FQ_MAX	(__TCA_FQ_MAX - 1)
++
++struct tc_fq_qd_stats {
++	__u64	gc_flows;
++	__u64	highprio_packets;
++	__u64	tcp_retrans;
++	__u64	throttled;
++	__u64	flows_plimit;
++	__u64	pkts_too_long;
++	__u64	allocation_errors;
++	__s64	time_next_delayed_flow;
++	__u32	flows;
++	__u32	inactive_flows;
++	__u32	throttled_flows;
++	__u32	pad;
++};
++
++/* Heavy-Hitter Filter */
++
++enum {
++	TCA_HHF_UNSPEC,
++	TCA_HHF_BACKLOG_LIMIT,
++	TCA_HHF_QUANTUM,
++	TCA_HHF_HH_FLOWS_LIMIT,
++	TCA_HHF_RESET_TIMEOUT,
++	TCA_HHF_ADMIT_BYTES,
++	TCA_HHF_EVICT_TIMEOUT,
++	TCA_HHF_NON_HH_WEIGHT,
++	__TCA_HHF_MAX
++};
++
++#define TCA_HHF_MAX	(__TCA_HHF_MAX - 1)
++
++struct tc_hhf_xstats {
++	__u32	drop_overlimit; /* number of times max qdisc packet limit
++				 * was hit
++				 */
++	__u32	hh_overlimit;   /* number of times max heavy-hitters was hit */
++	__u32	hh_tot_count;   /* number of captured heavy-hitters so far */
++	__u32	hh_cur_count;   /* number of current heavy-hitters */
++};
++
++/* PIE */
++enum {
++	TCA_PIE_UNSPEC,
++	TCA_PIE_TARGET,
++	TCA_PIE_LIMIT,
++	TCA_PIE_TUPDATE,
++	TCA_PIE_ALPHA,
++	TCA_PIE_BETA,
++	TCA_PIE_ECN,
++	TCA_PIE_BYTEMODE,
++	__TCA_PIE_MAX
++};
++#define TCA_PIE_MAX   (__TCA_PIE_MAX - 1)
++
++struct tc_pie_xstats {
++	__u32 prob;             /* current probability */
++	__u32 delay;            /* current delay in ms */
++	__u32 avg_dq_rate;      /* current average dq_rate in bits/pie_time */
++	__u32 packets_in;       /* total number of packets enqueued */
++	__u32 dropped;          /* packets dropped due to pie_action */
++	__u32 overlimit;        /* dropped due to lack of space in queue */
++	__u32 maxq;             /* maximum queue size */
++	__u32 ecn_mark;         /* packets marked with ecn*/
++};
+ #endif
+diff --git a/include/linux/rtnetlink.h b/include/linux/rtnetlink.h
+index 93370bd..702b19b 100644
+--- a/include/linux/rtnetlink.h
++++ b/include/linux/rtnetlink.h
+@@ -132,6 +132,13 @@ enum {
+ 	RTM_GETMDB = 86,
+ #define RTM_GETMDB RTM_GETMDB
+ 
++	RTM_NEWNSID = 88,
++#define RTM_NEWNSID RTM_NEWNSID
++	RTM_DELNSID = 89,
++#define RTM_DELNSID RTM_DELNSID
++	RTM_GETNSID = 90,
++#define RTM_GETNSID RTM_GETNSID
++
+ 	__RTM_MAX,
+ #define RTM_MAX		(((__RTM_MAX + 3) & ~3) - 1)
+ };
+@@ -235,6 +242,7 @@ enum {
+ #define RTPROT_NTK	15	/* Netsukuku */
+ #define RTPROT_DHCP	16      /* DHCP client */
+ #define RTPROT_MROUTED	17      /* Multicast daemon */
++#define RTPROT_BABEL	42      /* Babel daemon */
+ 
+ /* rtm_scope
+ 
+@@ -297,6 +305,9 @@ enum rtattr_type_t {
+ 	RTA_TABLE,
+ 	RTA_MARK,
+ 	RTA_MFC_STATS,
++	RTA_VIA,
++	RTA_NEWDST,
++	RTA_PREF,
+ 	__RTA_MAX
+ };
+ 
+@@ -326,6 +337,7 @@ struct rtnexthop {
+ #define RTNH_F_DEAD		1	/* Nexthop is dead (used by multipath)	*/
+ #define RTNH_F_PERVASIVE	2	/* Do recursive gateway lookup	*/
+ #define RTNH_F_ONLINK		4	/* Gateway is forced on link	*/
++#define RTNH_F_EXTERNAL		8	/* Route installed externally	*/
+ 
+ /* Macros to handle hexthops */
+ 
+@@ -338,6 +350,12 @@ struct rtnexthop {
+ #define RTNH_SPACE(len)	RTNH_ALIGN(RTNH_LENGTH(len))
+ #define RTNH_DATA(rtnh)   ((struct rtattr*)(((char*)(rtnh)) + RTNH_LENGTH(0)))
+ 
++/* RTA_VIA */
++struct rtvia {
++	__kernel_sa_family_t	rtvia_family;
++	__u8			rtvia_addr[0];
++};
++
+ /* RTM_CACHEINFO */
+ 
+ struct rta_cacheinfo {
+@@ -386,6 +404,10 @@ enum {
+ #define RTAX_RTO_MIN RTAX_RTO_MIN
+ 	RTAX_INITRWND,
+ #define RTAX_INITRWND RTAX_INITRWND
++	RTAX_QUICKACK,
++#define RTAX_QUICKACK RTAX_QUICKACK
++	RTAX_CC_ALGO,
++#define RTAX_CC_ALGO RTAX_CC_ALGO
+ 	__RTAX_MAX
+ };
+ 
+@@ -611,6 +633,10 @@ enum rtnetlink_groups {
+ #define RTNLGRP_IPV6_NETCONF	RTNLGRP_IPV6_NETCONF
+ 	RTNLGRP_MDB,
+ #define RTNLGRP_MDB		RTNLGRP_MDB
++	RTNLGRP_MPLS_ROUTE,
++#define RTNLGRP_MPLS_ROUTE	RTNLGRP_MPLS_ROUTE
++	RTNLGRP_NSID,
++#define RTNLGRP_NSID		RTNLGRP_NSID
+ 	__RTNLGRP_MAX
+ };
+ #define RTNLGRP_MAX	(__RTNLGRP_MAX - 1)
+@@ -629,6 +655,7 @@ struct tcamsg {
+ /* New extended info filters for IFLA_EXT_MASK */
+ #define RTEXT_FILTER_VF		(1 << 0)
+ #define RTEXT_FILTER_BRVLAN	(1 << 1)
++#define RTEXT_FILTER_BRVLAN_COMPRESSED	(1 << 2)
+ 
+ /* End of information exported to user level */
+ 
+diff --git a/include/linux/tc_act/tc_bpf.h b/include/linux/tc_act/tc_bpf.h
+new file mode 100644
+index 0000000..07f17cc
+--- /dev/null
++++ b/include/linux/tc_act/tc_bpf.h
+@@ -0,0 +1,33 @@
++/*
++ * Copyright (c) 2015 Jiri Pirko <jiri@resnulli.us>
++ *
++ * 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.
++ */
++
++#ifndef __LINUX_TC_BPF_H
++#define __LINUX_TC_BPF_H
++
++#include <linux/pkt_cls.h>
++
++#define TCA_ACT_BPF 13
++
++struct tc_act_bpf {
++	tc_gen;
++};
++
++enum {
++	TCA_ACT_BPF_UNSPEC,
++	TCA_ACT_BPF_TM,
++	TCA_ACT_BPF_PARMS,
++	TCA_ACT_BPF_OPS_LEN,
++	TCA_ACT_BPF_OPS,
++	TCA_ACT_BPF_FD,
++	TCA_ACT_BPF_NAME,
++	__TCA_ACT_BPF_MAX,
++};
++#define TCA_ACT_BPF_MAX (__TCA_ACT_BPF_MAX - 1)
++
++#endif
+diff --git a/include/linux/tc_act/tc_connmark.h b/include/linux/tc_act/tc_connmark.h
+new file mode 100644
+index 0000000..994b097
+--- /dev/null
++++ b/include/linux/tc_act/tc_connmark.h
+@@ -0,0 +1,22 @@
++#ifndef __UAPI_TC_CONNMARK_H
++#define __UAPI_TC_CONNMARK_H
++
++#include <linux/types.h>
++#include <linux/pkt_cls.h>
++
++#define TCA_ACT_CONNMARK 14
++
++struct tc_connmark {
++	tc_gen;
++	__u16 zone;
++};
++
++enum {
++	TCA_CONNMARK_UNSPEC,
++	TCA_CONNMARK_PARMS,
++	TCA_CONNMARK_TM,
++	__TCA_CONNMARK_MAX
++};
++#define TCA_CONNMARK_MAX (__TCA_CONNMARK_MAX - 1)
++
++#endif
+diff --git a/include/linux/tc_act/tc_defact.h b/include/linux/tc_act/tc_defact.h
+new file mode 100644
+index 0000000..17dddb4
+--- /dev/null
++++ b/include/linux/tc_act/tc_defact.h
+@@ -0,0 +1,19 @@
++#ifndef __LINUX_TC_DEF_H
++#define __LINUX_TC_DEF_H
++
++#include <linux/pkt_cls.h>
++
++struct tc_defact {
++	tc_gen;
++};
++
++enum {
++	TCA_DEF_UNSPEC,
++	TCA_DEF_TM,
++	TCA_DEF_PARMS,
++	TCA_DEF_DATA,
++	__TCA_DEF_MAX
++};
++#define TCA_DEF_MAX (__TCA_DEF_MAX - 1)
++
++#endif
+diff --git a/include/linux/tc_act/tc_ipt.h b/include/linux/tc_act/tc_ipt.h
+index a233556..130aaad 100644
+--- a/include/linux/tc_act/tc_ipt.h
++++ b/include/linux/tc_act/tc_ipt.h
+@@ -4,6 +4,7 @@
+ #include <linux/pkt_cls.h>
+ 
+ #define TCA_ACT_IPT 6
++#define TCA_ACT_XT 10
+ 
+ enum {
+ 	TCA_IPT_UNSPEC,
+diff --git a/include/linux/tc_act/tc_vlan.h b/include/linux/tc_act/tc_vlan.h
+new file mode 100644
+index 0000000..f7b8d44
+--- /dev/null
++++ b/include/linux/tc_act/tc_vlan.h
+@@ -0,0 +1,35 @@
++/*
++ * Copyright (c) 2014 Jiri Pirko <jiri@resnulli.us>
++ *
++ * 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.
++ */
++
++#ifndef __LINUX_TC_VLAN_H
++#define __LINUX_TC_VLAN_H
++
++#include <linux/pkt_cls.h>
++
++#define TCA_ACT_VLAN 12
++
++#define TCA_VLAN_ACT_POP	1
++#define TCA_VLAN_ACT_PUSH	2
++
++struct tc_vlan {
++	tc_gen;
++	int v_action;
++};
++
++enum {
++	TCA_VLAN_UNSPEC,
++	TCA_VLAN_TM,
++	TCA_VLAN_PARMS,
++	TCA_VLAN_PUSH_VLAN_ID,
++	TCA_VLAN_PUSH_VLAN_PROTOCOL,
++	__TCA_VLAN_MAX,
++};
++#define TCA_VLAN_MAX (__TCA_VLAN_MAX - 1)
++
++#endif
+diff --git a/include/linux/tcp.h b/include/linux/tcp.h
+index 1eb04d3..f96e015 100644
+--- a/include/linux/tcp.h
++++ b/include/linux/tcp.h
+@@ -111,6 +111,7 @@ enum {
+ #define TCP_REPAIR_OPTIONS	22
+ #define TCP_FASTOPEN		23	/* Enable FastOpen on listeners */
+ #define TCP_TIMESTAMP		24
++#define TCP_NOTSENT_LOWAT	25	/* limit number of unsent bytes in write queue */
+ 
+ struct tcp_repair_opt {
+ 	__u32	opt_code;
+@@ -185,6 +186,9 @@ struct tcp_info {
+ 	__u32	tcpi_rcv_space;
+ 
+ 	__u32	tcpi_total_retrans;
++
++	__u64	tcpi_pacing_rate;
++	__u64	tcpi_max_pacing_rate;
+ };
+ 
+ /* for TCP_MD5SIG socket option */
+diff --git a/include/linux/tcp_metrics.h b/include/linux/tcp_metrics.h
+index cb5157b..9353392 100644
+--- a/include/linux/tcp_metrics.h
++++ b/include/linux/tcp_metrics.h
+@@ -11,12 +11,15 @@
+ #define TCP_METRICS_GENL_VERSION	0x1
+ 
+ enum tcp_metric_index {
+-	TCP_METRIC_RTT,
+-	TCP_METRIC_RTTVAR,
++	TCP_METRIC_RTT,		/* in ms units */
++	TCP_METRIC_RTTVAR,	/* in ms units */
+ 	TCP_METRIC_SSTHRESH,
+ 	TCP_METRIC_CWND,
+ 	TCP_METRIC_REORDERING,
+ 
++	TCP_METRIC_RTT_US,	/* in usec units */
++	TCP_METRIC_RTTVAR_US,	/* in usec units */
++
+ 	/* Always last.  */
+ 	__TCP_METRIC_MAX,
+ };
+@@ -35,6 +38,8 @@ enum {
+ 	TCP_METRICS_ATTR_FOPEN_SYN_DROPS,	/* u16, count of drops */
+ 	TCP_METRICS_ATTR_FOPEN_SYN_DROP_TS,	/* msecs age */
+ 	TCP_METRICS_ATTR_FOPEN_COOKIE,		/* binary */
++	TCP_METRICS_ATTR_SADDR_IPV4,		/* u32 */
++	TCP_METRICS_ATTR_SADDR_IPV6,		/* binary */
+ 
+ 	__TCP_METRICS_ATTR_MAX,
+ };
+diff --git a/include/linux/unix_diag.h b/include/linux/unix_diag.h
+index b9e2a6a..1eb0b8d 100644
+--- a/include/linux/unix_diag.h
++++ b/include/linux/unix_diag.h
+@@ -31,6 +31,7 @@ struct unix_diag_msg {
+ };
+ 
+ enum {
++	/* UNIX_DIAG_NONE, standard nl API requires this attribute!  */
+ 	UNIX_DIAG_NAME,
+ 	UNIX_DIAG_VFS,
+ 	UNIX_DIAG_PEER,
+diff --git a/include/linux/xfrm.h b/include/linux/xfrm.h
+index 341c3c9..b8f5451 100644
+--- a/include/linux/xfrm.h
++++ b/include/linux/xfrm.h
+@@ -1,6 +1,7 @@
+ #ifndef _LINUX_XFRM_H
+ #define _LINUX_XFRM_H
+ 
++#include <linux/in6.h>
+ #include <linux/types.h>
+ 
+ /* All of the structures in this file may not change size as they are
+@@ -13,6 +14,7 @@
+ typedef union {
+ 	__be32		a4;
+ 	__be32		a6[4];
++	struct in6_addr	in6;
+ } xfrm_address_t;
+ 
+ /* Ident of a specific xfrm_state. It is used on input to lookup
+@@ -298,6 +300,8 @@ enum xfrm_attr_type_t {
+ 	XFRMA_TFCPAD,		/* __u32 */
+ 	XFRMA_REPLAY_ESN_VAL,	/* struct xfrm_replay_esn */
+ 	XFRMA_SA_EXTRA_FLAGS,	/* __u32 */
++	XFRMA_PROTO,		/* __u8 */
++	XFRMA_ADDRESS_FILTER,	/* struct xfrm_address_filter */
+ 	__XFRMA_MAX
+ 
+ #define XFRMA_MAX (__XFRMA_MAX - 1)
+@@ -326,6 +330,8 @@ enum xfrm_spdattr_type_t {
+ 	XFRMA_SPD_UNSPEC,
+ 	XFRMA_SPD_INFO,
+ 	XFRMA_SPD_HINFO,
++	XFRMA_SPD_IPV4_HTHRESH,
++	XFRMA_SPD_IPV6_HTHRESH,
+ 	__XFRMA_SPD_MAX
+ 
+ #define XFRMA_SPD_MAX (__XFRMA_SPD_MAX - 1)
+@@ -345,6 +351,11 @@ struct xfrmu_spdhinfo {
+ 	__u32 spdhmcnt;
+ };
+ 
++struct xfrmu_spdhthresh {
++	__u8 lbits;
++	__u8 rbits;
++};
++
+ struct xfrm_usersa_info {
+ 	struct xfrm_selector		sel;
+ 	struct xfrm_id			id;
+@@ -474,6 +485,14 @@ struct xfrm_user_mapping {
+ 	__be16				new_sport;
+ };
+ 
++struct xfrm_address_filter {
++	xfrm_address_t			saddr;
++	xfrm_address_t			daddr;
++	__u16				family;
++	__u8				splen;
++	__u8				dplen;
++};
++
+ /* backwards compatibility for userspace */
+ #define XFRMGRP_ACQUIRE		1
+ #define XFRMGRP_EXPIRE		2
+diff --git a/ip/xfrm_monitor.c b/ip/xfrm_monitor.c
+index 50116a7..773b143 100644
+--- a/ip/xfrm_monitor.c
++++ b/ip/xfrm_monitor.c
+@@ -27,7 +27,9 @@
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <string.h>
++#include <netinet/in.h>
+ #include <linux/xfrm.h>
++
+ #include "utils.h"
+ #include "xfrm.h"
+ #include "ip_common.h"
diff --git a/SOURCES/iproute2-3.10.0-man-ip-Add-missing-details-option.patch b/SOURCES/iproute2-3.10.0-man-ip-Add-missing-details-option.patch
new file mode 100644
index 0000000..308a85b
--- /dev/null
+++ b/SOURCES/iproute2-3.10.0-man-ip-Add-missing-details-option.patch
@@ -0,0 +1,28 @@
+From 4634f27c656a5fad22f6ed93963b78947450907f Mon Sep 17 00:00:00 2001
+From: vadimk <vadim4j@gmail.com>
+Date: Mon, 27 Oct 2014 17:22:58 +0200
+Subject: [PATCH] man ip: Add missing '-details' option
+
+Signed-off-by: Vadim Kochan <vadim4j@gmail.com>
+---
+ man/man8/ip.8 | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+diff --git a/man/man8/ip.8 b/man/man8/ip.8
+index 0713756..0bae59e 100644
+--- a/man/man8/ip.8
++++ b/man/man8/ip.8
+@@ -60,6 +60,10 @@ appears twice or more, the amount of information increases.
+ As a rule, the information is statistics or some time values.
+ 
+ .TP
++.BR "\-d" , " \-details"
++Output more detailed information.
++
++.TP
+ .BR "\-l" , " \-loops " <COUNT>
+ Specify maximum number of loops the 'ip addr flush' logic
+ will attempt before giving up.  The default is 10.
+-- 
+1.8.3.1
+
diff --git a/SOURCES/iproute2-3.10.0-misc-ss-don-t-imply-a-when-A-was-specified.patch b/SOURCES/iproute2-3.10.0-misc-ss-don-t-imply-a-when-A-was-specified.patch
new file mode 100644
index 0000000..0caf474
--- /dev/null
+++ b/SOURCES/iproute2-3.10.0-misc-ss-don-t-imply-a-when-A-was-specified.patch
@@ -0,0 +1,26 @@
+From 9aeb98263755ab24bd000da8ebf256dea5f21e1f Mon Sep 17 00:00:00 2001
+From: Phil Sutter <phil@nwl.cc>
+Date: Fri, 7 Aug 2015 15:31:27 +0200
+Subject: [PATCH] misc/ss: don't imply -a when -A was specified
+
+Signed-off-by: Phil Sutter <phil@nwl.cc>
+---
+ misc/ss.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/misc/ss.c b/misc/ss.c
+index c443c35..951e1eb 100644
+--- a/misc/ss.c
++++ b/misc/ss.c
+@@ -3505,6 +3505,8 @@ int main(int argc, char *argv[])
+ 			char *p, *p1;
+ 			if (!saw_query) {
+ 				current_filter.dbs = 0;
++				state_filter = state_filter ?
++				               state_filter : SS_CONN;
+ 				saw_query = 1;
+ 				do_default = 0;
+ 			}
+-- 
+1.8.3.1
+
diff --git a/SOURCES/iproute2-3.10.0-netns.patch b/SOURCES/iproute2-3.10.0-netns.patch
new file mode 100644
index 0000000..7589f44
--- /dev/null
+++ b/SOURCES/iproute2-3.10.0-netns.patch
@@ -0,0 +1,730 @@
+commit 99ea60996425f1baa6bcb07d01323b80129c2141
+Author: Pavel Šimerda <psimerda@redhat.com>
+Date:   Mon Jun 1 18:56:09 2015 +0200
+
+    backport selected ip-netns features
+
+diff --git a/ip/ipnetns.c b/ip/ipnetns.c
+index 794a498..24df167 100644
+--- a/ip/ipnetns.c
++++ b/ip/ipnetns.c
+@@ -15,180 +15,151 @@
+ #include <unistd.h>
+ #include <ctype.h>
+ 
++#include <linux/net_namespace.h>
++
+ #include "utils.h"
+ #include "ip_common.h"
+-
+-#define NETNS_RUN_DIR "/var/run/netns"
+-#define NETNS_ETC_DIR "/etc/netns"
+-
+-#ifndef CLONE_NEWNET
+-#define CLONE_NEWNET 0x40000000	/* New network namespace (lo, device, names sockets, etc) */
+-#endif
+-
+-#ifndef MNT_DETACH
+-#define MNT_DETACH	0x00000002	/* Just detach from the tree */
+-#endif /* MNT_DETACH */
+-
+-/* sys/mount.h may be out too old to have these */
+-#ifndef MS_REC
+-#define MS_REC		16384
+-#endif
+-
+-#ifndef MS_SLAVE
+-#define MS_SLAVE	(1 << 19)
+-#endif
+-
+-#ifndef MS_SHARED
+-#define MS_SHARED	(1 << 20)
+-#endif
+-
+-#ifndef HAVE_SETNS
+-static int setns(int fd, int nstype)
+-{
+-#ifdef __NR_setns
+-	return syscall(__NR_setns, fd, nstype);
+-#else
+-	errno = ENOSYS;
+-	return -1;
+-#endif
+-}
+-#endif /* HAVE_SETNS */
++#include "namespace.h"
+ 
+ static int usage(void)
+ {
+ 	fprintf(stderr, "Usage: ip netns list\n");
+ 	fprintf(stderr, "       ip netns add NAME\n");
+-	fprintf(stderr, "       ip netns delete NAME\n");
+-	fprintf(stderr, "       ip netns identify PID\n");
++	fprintf(stderr, "       ip netns set NAME NETNSID\n");
++	fprintf(stderr, "       ip [-all] netns delete [NAME]\n");
++	fprintf(stderr, "       ip netns identify [PID]\n");
+ 	fprintf(stderr, "       ip netns pids NAME\n");
+-	fprintf(stderr, "       ip netns exec NAME cmd ...\n");
++	fprintf(stderr, "       ip [-all] netns exec [NAME] cmd ...\n");
+ 	fprintf(stderr, "       ip netns monitor\n");
+ 	exit(-1);
+ }
+ 
+-int get_netns_fd(const char *name)
++static int have_rtnl_getnsid = -1;
++
++static int ipnetns_accept_msg(const struct sockaddr_nl *who,
++			      struct nlmsghdr *n, void *arg)
+ {
+-	char pathbuf[MAXPATHLEN];
+-	const char *path, *ptr;
++	struct nlmsgerr *err = (struct nlmsgerr *)NLMSG_DATA(n);
+ 
+-	path = name;
+-	ptr = strchr(name, '/');
+-	if (!ptr) {
+-		snprintf(pathbuf, sizeof(pathbuf), "%s/%s",
+-			NETNS_RUN_DIR, name );
+-		path = pathbuf;
+-	}
+-	return open(path, O_RDONLY);
++	if (n->nlmsg_type == NLMSG_ERROR &&
++	    (err->error == -EOPNOTSUPP || err->error == -EINVAL))
++		have_rtnl_getnsid = 0;
++	else
++		have_rtnl_getnsid = 1;
++	return -1;
+ }
+ 
+-static int netns_list(int argc, char **argv)
++static int ipnetns_have_nsid(void)
+ {
+-	struct dirent *entry;
+-	DIR *dir;
++	struct {
++		struct nlmsghdr n;
++		struct rtgenmsg g;
++		char            buf[1024];
++	} req;
++	int fd;
+ 
+-	dir = opendir(NETNS_RUN_DIR);
+-	if (!dir)
+-		return 0;
++	if (have_rtnl_getnsid < 0) {
++		memset(&req, 0, sizeof(req));
++		req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg));
++		req.n.nlmsg_flags = NLM_F_REQUEST;
++		req.n.nlmsg_type = RTM_GETNSID;
++		req.g.rtgen_family = AF_UNSPEC;
+ 
+-	while ((entry = readdir(dir)) != NULL) {
+-		if (strcmp(entry->d_name, ".") == 0)
+-			continue;
+-		if (strcmp(entry->d_name, "..") == 0)
+-			continue;
+-		printf("%s\n", entry->d_name);
++		fd = open("/proc/self/ns/net", O_RDONLY);
++		if (fd < 0) {
++			perror("open(\"/proc/self/ns/net\")");
++			exit(1);
++		}
++
++		addattr32(&req.n, 1024, NETNSA_FD, fd);
++
++		if (rtnl_send(&rth, &req.n, req.n.nlmsg_len) < 0) {
++			perror("request send failed");
++			exit(1);
++		}
++		rtnl_listen(&rth, ipnetns_accept_msg, NULL);
++		close(fd);
+ 	}
+-	closedir(dir);
+-	return 0;
++
++	return have_rtnl_getnsid;
+ }
+ 
+-static void bind_etc(const char *name)
++static int get_netnsid_from_name(const char *name)
++{
++	struct {
++		struct nlmsghdr n;
++		struct rtgenmsg g;
++		char            buf[1024];
++	} req, answer;
++	struct rtattr *tb[NETNSA_MAX + 1];
++	struct rtgenmsg *rthdr;
++	int len, fd;
++
++	memset(&req, 0, sizeof(req));
++	req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg));
++	req.n.nlmsg_flags = NLM_F_REQUEST;
++	req.n.nlmsg_type = RTM_GETNSID;
++	req.g.rtgen_family = AF_UNSPEC;
++
++	fd = netns_get_fd(name);
++	if (fd < 0)
++		return fd;
++
++	addattr32(&req.n, 1024, NETNSA_FD, fd);
++	if (rtnl_talk(&rth, &req.n, 0, 0, &answer.n) < 0) {
++		close(fd);
++		return -2;
++	}
++	close(fd);
++
++	/* Validate message and parse attributes */
++	if (answer.n.nlmsg_type == NLMSG_ERROR)
++		return -1;
++
++	rthdr = NLMSG_DATA(&answer.n);
++	len = answer.n.nlmsg_len - NLMSG_SPACE(sizeof(*rthdr));
++	if (len < 0)
++		return -1;
++
++	parse_rtattr(tb, NETNSA_MAX, NETNS_RTA(rthdr), len);
++
++	if (tb[NETNSA_NSID])
++		return rta_getattr_u32(tb[NETNSA_NSID]);
++
++	return -1;
++}
++
++static int netns_list(int argc, char **argv)
+ {
+-	char etc_netns_path[MAXPATHLEN];
+-	char netns_name[MAXPATHLEN];
+-	char etc_name[MAXPATHLEN];
+ 	struct dirent *entry;
+ 	DIR *dir;
++	int id;
+ 
+-	snprintf(etc_netns_path, sizeof(etc_netns_path), "%s/%s", NETNS_ETC_DIR, name);
+-	dir = opendir(etc_netns_path);
++	dir = opendir(NETNS_RUN_DIR);
+ 	if (!dir)
+-		return;
++		return 0;
+ 
+ 	while ((entry = readdir(dir)) != NULL) {
+ 		if (strcmp(entry->d_name, ".") == 0)
+ 			continue;
+ 		if (strcmp(entry->d_name, "..") == 0)
+ 			continue;
+-		snprintf(netns_name, sizeof(netns_name), "%s/%s", etc_netns_path, entry->d_name);
+-		snprintf(etc_name, sizeof(etc_name), "/etc/%s", entry->d_name);
+-		if (mount(netns_name, etc_name, "none", MS_BIND, NULL) < 0) {
+-			fprintf(stderr, "Bind %s -> %s failed: %s\n",
+-				netns_name, etc_name, strerror(errno));
++		printf("%s", entry->d_name);
++		if (ipnetns_have_nsid()) {
++			id = get_netnsid_from_name(entry->d_name);
++			if (id >= 0)
++				printf(" (id: %d)", id);
+ 		}
++		printf("\n");
+ 	}
+ 	closedir(dir);
++	return 0;
+ }
+ 
+-static int netns_exec(int argc, char **argv)
++static int cmd_exec(const char *cmd, char **argv, bool do_fork)
+ {
+-	/* Setup the proper environment for apps that are not netns
+-	 * aware, and execute a program in that environment.
+-	 */
+-	const char *name, *cmd;
+-	char net_path[MAXPATHLEN];
+-	int netns;
+-
+-	if (argc < 1) {
+-		fprintf(stderr, "No netns name specified\n");
+-		return -1;
+-	}
+-	if (argc < 2) {
+-		fprintf(stderr, "No command specified\n");
+-		return -1;
+-	}
+-
+-	name = argv[0];
+-	cmd = argv[1];
+-	snprintf(net_path, sizeof(net_path), "%s/%s", NETNS_RUN_DIR, name);
+-	netns = open(net_path, O_RDONLY | O_CLOEXEC);
+-	if (netns < 0) {
+-		fprintf(stderr, "Cannot open network namespace \"%s\": %s\n",
+-			name, strerror(errno));
+-		return -1;
+-	}
+-
+-	if (setns(netns, CLONE_NEWNET) < 0) {
+-		fprintf(stderr, "seting the network namespace \"%s\" failed: %s\n",
+-			name, strerror(errno));
+-		return -1;
+-	}
+-
+-	if (unshare(CLONE_NEWNS) < 0) {
+-		fprintf(stderr, "unshare failed: %s\n", strerror(errno));
+-		return -1;
+-	}
+-	/* Don't let any mounts propogate back to the parent */
+-	if (mount("", "/", "none", MS_SLAVE | MS_REC, NULL)) {
+-		fprintf(stderr, "\"mount --make-rslave /\" failed: %s\n",
+-			strerror(errno));
+-		return -1;
+-	}
+-	/* Mount a version of /sys that describes the network namespace */
+-	if (umount2("/sys", MNT_DETACH) < 0) {
+-		fprintf(stderr, "umount of /sys failed: %s\n", strerror(errno));
+-		return -1;
+-	}
+-	if (mount(name, "/sys", "sysfs", 0, NULL) < 0) {
+-		fprintf(stderr, "mount of /sys failed: %s\n",strerror(errno));
+-		return -1;
+-	}
+-
+-	/* Setup bind mounts for config files in /etc */
+-	bind_etc(name);
+-
+ 	fflush(stdout);
+-
+-	if (batch_mode) {
++	if (do_fork) {
+ 		int status;
+ 		pid_t pid;
+ 
+@@ -205,20 +176,57 @@ static int netns_exec(int argc, char **argv)
+ 				exit(1);
+ 			}
+ 
+-			/* If child failed, propogate status */
+-			if (WIFEXITED(status))
+-				exit(WEXITSTATUS(status));
++			if (WIFEXITED(status)) {
++				return WEXITSTATUS(status);
++			}
+ 
+-			return 0;
++			exit(1);
+ 		}
+ 	}
+ 
+-	if (execvp(cmd, argv + 1)  < 0)
++	if (execvp(cmd, argv)  < 0)
+ 		fprintf(stderr, "exec of \"%s\" failed: %s\n",
+-			cmd, strerror(errno));
++				cmd, strerror(errno));
+ 	_exit(1);
+ }
+ 
++static int on_netns_exec(char *nsname, void *arg)
++{
++	char **argv = arg;
++	cmd_exec(argv[1], argv + 1, true);
++	return 0;
++}
++
++static int netns_exec(int argc, char **argv)
++{
++	/* Setup the proper environment for apps that are not netns
++	 * aware, and execute a program in that environment.
++	 */
++	const char *cmd;
++
++	if (argc < 1 && !do_all) {
++		fprintf(stderr, "No netns name specified\n");
++		return -1;
++	}
++	if ((argc < 2 && !do_all) || (argc < 1 && do_all)) {
++		fprintf(stderr, "No command specified\n");
++		return -1;
++	}
++
++	if (do_all)
++		return do_each_netns(on_netns_exec, --argv, 1);
++
++	if (netns_switch(argv[0]))
++		return -1;
++
++	/* ip must return the status of the child,
++	 * but do_cmd() will add a minus to this,
++	 * so let's add another one here to cancel it.
++	 */
++	cmd = argv[1];
++	return -cmd_exec(cmd, argv + 1, !!batch_mode);
++}
++
+ static int is_pid(const char *str)
+ {
+ 	int ch;
+@@ -282,7 +290,7 @@ static int netns_pids(int argc, char **argv)
+ 	}
+ 	closedir(dir);
+ 	return 0;
+-	
++
+ }
+ 
+ static int netns_identify(int argc, char **argv)
+@@ -295,19 +303,17 @@ static int netns_identify(int argc, char **argv)
+ 	struct dirent *entry;
+ 
+ 	if (argc < 1) {
+-		fprintf(stderr, "No pid specified\n");
+-		return -1;
+-	}
+-	if (argc > 1) {
++		pidstr = "self";
++	} else if (argc > 1) {
+ 		fprintf(stderr, "extra arguments specified\n");
+ 		return -1;
+-	}
+-	pidstr = argv[0];
+-
+-	if (!is_pid(pidstr)) {
+-		fprintf(stderr, "Specified string '%s' is not a pid\n",
+-			pidstr);
+-		return -1;
++	} else {
++		pidstr = argv[0];
++		if (!is_pid(pidstr)) {
++			fprintf(stderr, "Specified string '%s' is not a pid\n",
++					pidstr);
++			return -1;
++		}
+ 	}
+ 
+ 	snprintf(net_path, sizeof(net_path), "/proc/%s/ns/net", pidstr);
+@@ -355,21 +361,14 @@ static int netns_identify(int argc, char **argv)
+ 	}
+ 	closedir(dir);
+ 	return 0;
+-	
++
+ }
+ 
+-static int netns_delete(int argc, char **argv)
++static int on_netns_del(char *nsname, void *arg)
+ {
+-	const char *name;
+ 	char netns_path[MAXPATHLEN];
+ 
+-	if (argc < 1) {
+-		fprintf(stderr, "No netns name specified\n");
+-		return -1;
+-	}
+-
+-	name = argv[0];
+-	snprintf(netns_path, sizeof(netns_path), "%s/%s", NETNS_RUN_DIR, name);
++	snprintf(netns_path, sizeof(netns_path), "%s/%s", NETNS_RUN_DIR, nsname);
+ 	umount2(netns_path, MNT_DETACH);
+ 	if (unlink(netns_path) < 0) {
+ 		fprintf(stderr, "Cannot remove namespace file \"%s\": %s\n",
+@@ -379,6 +378,33 @@ static int netns_delete(int argc, char **argv)
+ 	return 0;
+ }
+ 
++static int netns_delete(int argc, char **argv)
++{
++	if (argc < 1 && !do_all) {
++		fprintf(stderr, "No netns name specified\n");
++		return -1;
++	}
++
++	if (do_all)
++		return netns_foreach(on_netns_del, NULL);
++
++	return on_netns_del(argv[0], NULL);
++}
++
++static int create_netns_dir(void)
++{
++	/* Create the base netns directory if it doesn't exist */
++	if (mkdir(NETNS_RUN_DIR, S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH)) {
++		if (errno != EEXIST) {
++			fprintf(stderr, "mkdir %s failed: %s\n",
++				NETNS_RUN_DIR, strerror(errno));
++			return -1;
++		}
++	}
++
++	return 0;
++}
++
+ static int netns_add(int argc, char **argv)
+ {
+ 	/* This function creates a new network namespace and
+@@ -402,10 +428,10 @@ static int netns_add(int argc, char **argv)
+ 
+ 	snprintf(netns_path, sizeof(netns_path), "%s/%s", NETNS_RUN_DIR, name);
+ 
+-	/* Create the base netns directory if it doesn't exist */
+-	mkdir(NETNS_RUN_DIR, S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH);
++	if (create_netns_dir())
++		return -1;
+ 
+-	/* Make it possible for network namespace mounts to propogate between
++	/* Make it possible for network namespace mounts to propagate between
+ 	 * mount namespaces.  This makes it likely that a unmounting a network
+ 	 * namespace file in one namespace will unmount the network namespace
+ 	 * file in all namespaces allowing the network namespace to be freed
+@@ -431,7 +457,7 @@ static int netns_add(int argc, char **argv)
+ 	/* Create the filesystem state */
+ 	fd = open(netns_path, O_RDONLY|O_CREAT|O_EXCL, 0);
+ 	if (fd < 0) {
+-		fprintf(stderr, "Cannot not create namespace file \"%s\": %s\n",
++		fprintf(stderr, "Cannot create namespace file \"%s\": %s\n",
+ 			netns_path, strerror(errno));
+ 		return -1;
+ 	}
+@@ -454,6 +480,61 @@ out_delete:
+ 	return -1;
+ }
+ 
++static int set_netnsid_from_name(const char *name, int nsid)
++{
++	struct {
++		struct nlmsghdr n;
++		struct rtgenmsg g;
++		char            buf[1024];
++	} req;
++	int fd, err = 0;
++
++	memset(&req, 0, sizeof(req));
++	req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg));
++	req.n.nlmsg_flags = NLM_F_REQUEST;
++	req.n.nlmsg_type = RTM_NEWNSID;
++	req.g.rtgen_family = AF_UNSPEC;
++
++	fd = netns_get_fd(name);
++	if (fd < 0)
++		return fd;
++
++	addattr32(&req.n, 1024, NETNSA_FD, fd);
++	addattr32(&req.n, 1024, NETNSA_NSID, nsid);
++	if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0)
++		err = -2;
++
++	close(fd);
++	return err;
++}
++
++static int netns_set(int argc, char **argv)
++{
++	char netns_path[MAXPATHLEN];
++	const char *name;
++	int netns, nsid;
++
++	if (argc < 1) {
++		fprintf(stderr, "No netns name specified\n");
++		return -1;
++	}
++	if (argc < 2) {
++		fprintf(stderr, "No nsid specified\n");
++		return -1;
++	}
++	name = argv[0];
++	nsid = atoi(argv[1]);
++
++	snprintf(netns_path, sizeof(netns_path), "%s/%s", NETNS_RUN_DIR, name);
++	netns = open(netns_path, O_RDONLY | O_CLOEXEC);
++	if (netns < 0) {
++		fprintf(stderr, "Cannot open network namespace \"%s\": %s\n",
++			name, strerror(errno));
++		return -1;
++	}
++
++	return set_netnsid_from_name(name, nsid);
++}
+ 
+ static int netns_monitor(int argc, char **argv)
+ {
+@@ -466,6 +547,10 @@ static int netns_monitor(int argc, char **argv)
+ 			strerror(errno));
+ 		return -1;
+ 	}
++
++	if (create_netns_dir())
++		return -1;
++
+ 	if (inotify_add_watch(fd, NETNS_RUN_DIR, IN_CREATE | IN_DELETE) < 0) {
+ 		fprintf(stderr, "inotify_add_watch failed: %s\n",
+ 			strerror(errno));
+@@ -505,6 +590,9 @@ int do_netns(int argc, char **argv)
+ 	if (matches(*argv, "add") == 0)
+ 		return netns_add(argc-1, argv+1);
+ 
++	if (matches(*argv, "set") == 0)
++		return netns_set(argc-1, argv+1);
++
+ 	if (matches(*argv, "delete") == 0)
+ 		return netns_delete(argc-1, argv+1);
+ 
+diff --git a/man/man8/ip-netns.8 b/man/man8/ip-netns.8
+index 6aa6e93..80a4ad1 100644
+--- a/man/man8/ip-netns.8
++++ b/man/man8/ip-netns.8
+@@ -16,20 +16,28 @@ ip-netns \- process network namespace management
+ .BR "ip netns" " { " list " } "
+ 
+ .ti -8
+-.BR "ip netns" " { " add " | " delete " } "
++.B ip netns add
+ .I NETNSNAME
+ 
+ .ti -8
++.B ip [-all] netns del
++.RI "[ " NETNSNAME " ]"
++
++.ti -8
++.BR "ip netns" " { " set " } "
++.I NETNSNAME NETNSID
++
++.ti -8
+ .BR "ip netns identify"
+-.I PID
++.RI "[ " PID " ]"
+ 
+ .ti -8
+ .BR "ip netns pids"
+ .I NETNSNAME
+ 
+ .ti -8
+-.BR "ip netns exec "
+-.I NETNSNAME command ...
++.BR "ip [-all] netns exec "
++.RI "[ " NETNSNAME " ] " command ...
+ 
+ .ti -8
+ .BR "ip netns monitor"
+@@ -38,12 +46,15 @@ ip-netns \- process network namespace management
+ A network namespace is logically another copy of the network stack,
+ with its own routes, firewall rules, and network devices.
+ 
++By default a process inherits its network namespace from its parent. Initially all
++the processes share the same default network namespace from the init process.
++
+ By convention a named network namespace is an object at
+ .BR "/var/run/netns/" NAME
+-that can be opened.  The file descriptor resulting from opening
++that can be opened. The file descriptor resulting from opening
+ .BR "/var/run/netns/" NAME
+-refers to the specified network namespace.  Holding that file
+-descriptor open keeps the network namespace alive.  The file
++refers to the specified network namespace. Holding that file
++descriptor open keeps the network namespace alive. The file
+ descriptor can be used with the
+ .B setns(2)
+ system call to change the network namespace associated with a task.
+@@ -76,19 +87,64 @@ If NAME is available in /var/run/netns/ this command creates a new
+ network namespace and assigns NAME.
+ 
+ .TP
+-.B ip netns delete NAME - delete the name of a network namespace
++.B ip [-all] netns delete [ NAME ] - delete the name of a network namespace(s)
+ .sp
+ If NAME is present in /var/run/netns it is umounted and the mount
+-point is removed.  If this is the last user of the network namespace the
+-network namespace will be freed, otherwise the network namespace
+-persists until it has no more users.  ip netns delete may fail if
+-the mount point is in use in another mount namespace.
++point is removed. If this is the last user of the network namespace the
++network namespace will be freed and all physical devices will be moved to the
++default one, otherwise the network namespace persists until it has no more
++users. ip netns delete may fail if the mount point is in use in another mount
++namespace.
++
++If
++.B -all
++option was specified then all the network namespace names will be removed.
++
++It is possible to lose the physical device when it was moved to netns and
++then this netns was deleted with a running process:
++
++.RS 10
++$ ip netns add net0
++.RE
++.RS 10
++$ ip link set dev eth0 netns net0
++.RE
++.RS 10
++$ ip netns exec net0 SOME_PROCESS_IN_BACKGROUND
++.RE
++.RS 10
++$ ip netns del net0
++.RE
++
++.RS
++and eth0 will appear in the default netns only after SOME_PROCESS_IN_BACKGROUND
++will exit or will be killed. To prevent this the processes running in net0
++should be killed before deleting the netns:
++
++.RE
++.RS 10
++$ ip netns pids net0 | xargs kill
++.RE
++.RS 10
++$ ip netns del net0
++.RE
+ 
+ .TP
+-.B ip netns identify PID - Report network namespaces names for process
++.B ip netns set NAME NETNSID - assign an id to a peer network namespace
++.sp
++This command assigns a id to a peer network namespace. This id is valid
++only in the current network namespace.
++This id will be used by the kernel in some netlink messages. If no id is
++assigned when the kernel needs it, it will be automatically assigned by
++the kernel.
++Once it is assigned, it's not possible to change it.
++
++.TP
++.B ip netns identify [PID] - Report network namespaces names for process
+ .sp
+ This command walks through /var/run/netns and finds all the network
+-namespace names for network namespace of the specified process.
++namespace names for network namespace of the specified process, if PID is
++not specified then the current process will be used.
+ 
+ .TP
+ .B ip netns pids NAME - Report processes in the named network namespace
+@@ -97,15 +153,25 @@ This command walks through proc and finds all of the process who have
+ the named network namespace as their primary network namespace.
+ 
+ .TP
+-.B ip netns exec NAME cmd ... - Run cmd in the named network namespace
++.B ip [-all] netns exec [ NAME ] cmd ... - Run cmd in the named network namespace
+ .sp
+ This command allows applications that are network namespace unaware
+ to be run in something other than the default network namespace with
+ all of the configuration for the specified network namespace appearing
+-in the customary global locations.  A network namespace and bind mounts
++in the customary global locations. A network namespace and bind mounts
+ are used to move files from their network namespace specific location
+ to their default locations without affecting other processes.
+ 
++If
++.B -all
++option was specified then
++.B cmd
++will be executed synchronously on the each named network namespace even if
++.B cmd
++fails on some of them. Network namespace name is printed on each
++.B cmd
++executing.
++
+ .TP
+ .B ip netns monitor - Report as network namespace names are added and deleted
+ .sp
+--- iproute2-3.10.0/man/man8/ip.8.orig	2015-07-08 19:15:58.468148060 +0200
++++ iproute2-3.10.0/man/man8/ip.8	2015-07-08 19:16:38.078147665 +0200
+@@ -132,7 +132,7 @@
+ host addresses.
+ 
+ .TP
+-.BR "\-n" , " \-net" , " \-netns " <NETNS>
++.BR "\-n" , " \-netns " <NETNS>
+ switches
+ .B ip
+ to the specified network namespace
diff --git a/SOURCES/iproute2-3.10.0-pkt_sched-fq-Fair-Queue-packet-scheduler.patch b/SOURCES/iproute2-3.10.0-pkt_sched-fq-Fair-Queue-packet-scheduler.patch
new file mode 100644
index 0000000..3403906
--- /dev/null
+++ b/SOURCES/iproute2-3.10.0-pkt_sched-fq-Fair-Queue-packet-scheduler.patch
@@ -0,0 +1,354 @@
+From 837c38c3365b63ba486d0b0eb8a963621d8f0ac2 Mon Sep 17 00:00:00 2001
+From: Eric Dumazet <edumazet@google.com>
+Date: Thu, 29 Aug 2013 19:30:36 -0700
+Subject: [PATCH 1/2] pkt_sched: fq: Fair Queue packet scheduler
+
+Support for FQ packet scheduler
+
+$ tc qd add dev eth0 root fq help
+Usage: ... fq [ limit PACKETS ] [ flow_limit PACKETS ]
+              [ quantum BYTES ] [ initial_quantum BYTES ]
+              [ maxrate RATE  ] [ buckets NUMBER ]
+              [ [no]pacing ]
+
+$ tc -s -d qd
+qdisc fq 8002: dev eth0 root refcnt 32 limit 10000p flow_limit 100p
+buckets 256 quantum 3028 initial_quantum 15140
+ Sent 216532416 bytes 148395 pkt (dropped 0, overlimits 0 requeues 14)
+ backlog 0b 0p requeues 14
+  511 flows (511 inactive, 0 throttled)
+  110 gc, 0 highprio, 0 retrans, 1143 throttled, 0 flows_plimit
+
+limit	: max number of packets on whole Qdisc (default 10000)
+
+flow_limit : max number of packets per flow (default 100)
+
+quantum : the max deficit per RR round (default is 2 MTU)
+
+initial_quantum : initial credit for new flows (default is 10 MTU)
+
+maxrate : max per flow rate (default : unlimited)
+
+buckets : number of RB trees (default : 1024) in hash table.
+               (consumes 8 bytes per bucket)
+
+[no]pacing : disable/enable pacing (default is enable)
+
+Usage :
+
+tc qdisc add dev $ETH root fq
+
+tc qdisc del dev $ETH root 2>/dev/null
+tc qdisc add dev $ETH root handle 1: mq
+for i in `seq 1 4`
+do
+  tc qdisc add dev $ETH parent 1:$i est 1sec 4sec fq
+done
+
+Signed-off-by: Eric Dumazet <edumazet@google.com>
+---
+ tc/Makefile |   1 +
+ tc/q_fq.c   | 279 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 280 insertions(+)
+ create mode 100644 tc/q_fq.c
+
+diff --git a/tc/Makefile b/tc/Makefile
+index af6a277..79116f3 100644
+--- a/tc/Makefile
++++ b/tc/Makefile
+@@ -56,6 +56,7 @@ TCMODULES += em_meta.o
+ TCMODULES += q_mqprio.o
+ TCMODULES += q_codel.o
+ TCMODULES += q_fq_codel.o
++TCMODULES += q_fq.o
+ 
+ ifeq ($(TC_CONFIG_IPSET), y)
+   ifeq ($(TC_CONFIG_XT), y)
+diff --git a/tc/q_fq.c b/tc/q_fq.c
+new file mode 100644
+index 0000000..c1f658e
+--- /dev/null
++++ b/tc/q_fq.c
+@@ -0,0 +1,279 @@
++/*
++ * Fair Queue
++ *
++ *  Copyright (C) 2013 Eric Dumazet <edumazet@google.com>
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ *    notice, this list of conditions, and the following disclaimer,
++ *    without modification.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ *    notice, this list of conditions and the following disclaimer in the
++ *    documentation and/or other materials provided with the distribution.
++ * 3. The names of the authors may not be used to endorse or promote products
++ *    derived from this software without specific prior written permission.
++ *
++ * Alternatively, provided that this notice is retained in full, this
++ * software may be distributed under the terms of the GNU General
++ * Public License ("GPL") version 2, in which case the provisions of the
++ * GPL apply INSTEAD OF those given above.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
++ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
++ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
++ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
++ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
++ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
++ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
++ * DAMAGE.
++ *
++ */
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <unistd.h>
++#include <syslog.h>
++#include <fcntl.h>
++#include <sys/socket.h>
++#include <netinet/in.h>
++#include <arpa/inet.h>
++#include <string.h>
++
++#include "utils.h"
++#include "tc_util.h"
++
++static void explain(void)
++{
++	fprintf(stderr, "Usage: ... fq [ limit PACKETS ] [ flow_limit PACKETS ]\n");
++	fprintf(stderr, "              [ quantum BYTES ] [ initial_quantum BYTES ]\n");
++	fprintf(stderr, "              [ maxrate RATE  ] [ buckets NUMBER ]\n");
++	fprintf(stderr, "              [ [no]pacing ]\n");
++}
++
++static unsigned int ilog2(unsigned int val)
++{
++	unsigned int res = 0;
++
++	val--;
++	while (val) {
++		res++;
++		val >>= 1;
++	}
++	return res;
++}
++
++static int fq_parse_opt(struct qdisc_util *qu, int argc, char **argv,
++			struct nlmsghdr *n)
++{
++	unsigned int plimit = ~0U;
++	unsigned int flow_plimit = ~0U;
++	unsigned int quantum = ~0U;
++	unsigned int initial_quantum = ~0U;
++	unsigned int buckets = 0;
++	unsigned int maxrate = ~0U;
++	unsigned int defrate = ~0U;
++	int pacing = -1;
++	struct rtattr *tail;
++
++	while (argc > 0) {
++		if (strcmp(*argv, "limit") == 0) {
++			NEXT_ARG();
++			if (get_unsigned(&plimit, *argv, 0)) {
++				fprintf(stderr, "Illegal \"limit\"\n");
++				return -1;
++			}
++		} else if (strcmp(*argv, "flow_limit") == 0) {
++			NEXT_ARG();
++			if (get_unsigned(&flow_plimit, *argv, 0)) {
++				fprintf(stderr, "Illegal \"flow_limit\"\n");
++				return -1;
++			}
++		} else if (strcmp(*argv, "buckets") == 0) {
++			NEXT_ARG();
++			if (get_unsigned(&buckets, *argv, 0)) {
++				fprintf(stderr, "Illegal \"buckets\"\n");
++				return -1;
++			}
++		} else if (strcmp(*argv, "maxrate") == 0) {
++			NEXT_ARG();
++			if (get_rate(&maxrate, *argv)) {
++				fprintf(stderr, "Illegal \"maxrate\"\n");
++				return -1;
++			}
++		} else if (strcmp(*argv, "defrate") == 0) {
++			NEXT_ARG();
++			if (get_rate(&defrate, *argv)) {
++				fprintf(stderr, "Illegal \"defrate\"\n");
++				return -1;
++			}
++		} else if (strcmp(*argv, "quantum") == 0) {
++			NEXT_ARG();
++			if (get_unsigned(&quantum, *argv, 0)) {
++				fprintf(stderr, "Illegal \"quantum\"\n");
++				return -1;
++			}
++		} else if (strcmp(*argv, "initial_quantum") == 0) {
++			NEXT_ARG();
++			if (get_unsigned(&initial_quantum, *argv, 0)) {
++				fprintf(stderr, "Illegal \"initial_quantum\"\n");
++				return -1;
++			}
++		} else if (strcmp(*argv, "pacing") == 0) {
++			pacing = 1;
++		} else if (strcmp(*argv, "nopacing") == 0) {
++			pacing = 0;
++		} else if (strcmp(*argv, "help") == 0) {
++			explain();
++			return -1;
++		} else {
++			fprintf(stderr, "What is \"%s\"?\n", *argv);
++			explain();
++			return -1;
++		}
++		argc--; argv++;
++	}
++
++	tail = NLMSG_TAIL(n);
++	addattr_l(n, 1024, TCA_OPTIONS, NULL, 0);
++	if (buckets) {
++		unsigned int log = ilog2(buckets);
++
++		addattr_l(n, 1024, TCA_FQ_BUCKETS_LOG,
++			  &log, sizeof(log));
++	}
++	if (plimit != ~0U)
++		addattr_l(n, 1024, TCA_FQ_PLIMIT,
++			  &plimit, sizeof(plimit));
++	if (flow_plimit != ~0U)
++		addattr_l(n, 1024, TCA_FQ_FLOW_PLIMIT,
++			  &flow_plimit, sizeof(flow_plimit));
++	if (quantum != ~0U)
++		addattr_l(n, 1024, TCA_FQ_QUANTUM, &quantum, sizeof(quantum));
++	if (initial_quantum != ~0U)
++		addattr_l(n, 1024, TCA_FQ_INITIAL_QUANTUM,
++			  &initial_quantum, sizeof(initial_quantum));
++	if (pacing != -1)
++		addattr_l(n, 1024, TCA_FQ_RATE_ENABLE,
++			  &pacing, sizeof(pacing));
++	if (maxrate != ~0U)
++		addattr_l(n, 1024, TCA_FQ_FLOW_MAX_RATE,
++			  &maxrate, sizeof(maxrate));
++	if (defrate != ~0U)
++		addattr_l(n, 1024, TCA_FQ_FLOW_DEFAULT_RATE,
++			  &defrate, sizeof(defrate));
++	tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail;
++	return 0;
++}
++
++static int fq_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
++{
++	struct rtattr *tb[TCA_FQ_MAX + 1];
++	unsigned int plimit, flow_plimit;
++	unsigned int buckets_log;
++	int pacing;
++	unsigned int rate, quantum;
++	SPRINT_BUF(b1);
++
++	if (opt == NULL)
++		return 0;
++
++	parse_rtattr_nested(tb, TCA_FQ_MAX, opt);
++
++	if (tb[TCA_FQ_PLIMIT] &&
++	    RTA_PAYLOAD(tb[TCA_FQ_PLIMIT]) >= sizeof(__u32)) {
++		plimit = rta_getattr_u32(tb[TCA_FQ_PLIMIT]);
++		fprintf(f, "limit %up ", plimit);
++	}
++	if (tb[TCA_FQ_FLOW_PLIMIT] &&
++	    RTA_PAYLOAD(tb[TCA_FQ_FLOW_PLIMIT]) >= sizeof(__u32)) {
++		flow_plimit = rta_getattr_u32(tb[TCA_FQ_FLOW_PLIMIT]);
++		fprintf(f, "flow_limit %up ", flow_plimit);
++	}
++	if (tb[TCA_FQ_BUCKETS_LOG] &&
++	    RTA_PAYLOAD(tb[TCA_FQ_BUCKETS_LOG]) >= sizeof(__u32)) {
++		buckets_log = rta_getattr_u32(tb[TCA_FQ_BUCKETS_LOG]);
++		fprintf(f, "buckets %u ", 1U << buckets_log);
++	}
++	if (tb[TCA_FQ_RATE_ENABLE] &&
++	    RTA_PAYLOAD(tb[TCA_FQ_RATE_ENABLE]) >= sizeof(int)) {
++		pacing = rta_getattr_u32(tb[TCA_FQ_RATE_ENABLE]);
++		if (pacing == 0)
++			fprintf(f, "nopacing ");
++	}
++	if (tb[TCA_FQ_QUANTUM] &&
++	    RTA_PAYLOAD(tb[TCA_FQ_QUANTUM]) >= sizeof(__u32)) {
++		quantum = rta_getattr_u32(tb[TCA_FQ_QUANTUM]);
++		fprintf(f, "quantum %u ", quantum);
++	}
++	if (tb[TCA_FQ_INITIAL_QUANTUM] &&
++	    RTA_PAYLOAD(tb[TCA_FQ_INITIAL_QUANTUM]) >= sizeof(__u32)) {
++		quantum = rta_getattr_u32(tb[TCA_FQ_INITIAL_QUANTUM]);
++		fprintf(f, "initial_quantum %u ", quantum);
++	}
++	if (tb[TCA_FQ_FLOW_MAX_RATE] &&
++	    RTA_PAYLOAD(tb[TCA_FQ_FLOW_MAX_RATE]) >= sizeof(__u32)) {
++		rate = rta_getattr_u32(tb[TCA_FQ_FLOW_MAX_RATE]);
++
++		if (rate != ~0U)
++			fprintf(f, "maxrate %s ", sprint_rate(rate, b1));
++	}
++	if (tb[TCA_FQ_FLOW_DEFAULT_RATE] &&
++	    RTA_PAYLOAD(tb[TCA_FQ_FLOW_DEFAULT_RATE]) >= sizeof(__u32)) {
++		rate = rta_getattr_u32(tb[TCA_FQ_FLOW_DEFAULT_RATE]);
++
++		if (rate != 0)
++			fprintf(f, "defrate %s ", sprint_rate(rate, b1));
++	}
++
++	return 0;
++}
++
++static int fq_print_xstats(struct qdisc_util *qu, FILE *f,
++			   struct rtattr *xstats)
++{
++	struct tc_fq_qd_stats *st;
++
++	if (xstats == NULL)
++		return 0;
++
++	if (RTA_PAYLOAD(xstats) < sizeof(*st))
++		return -1;
++
++	st = RTA_DATA(xstats);
++
++	fprintf(f, "  %u flows (%u inactive, %u throttled)",
++		st->flows, st->inactive_flows, st->throttled_flows);
++
++	if (st->time_next_delayed_flow > 0)
++		fprintf(f, ", next packet delay %llu ns", st->time_next_delayed_flow);
++
++	fprintf(f, "\n  %llu gc, %llu highprio",
++		st->gc_flows, st->highprio_packets);
++
++	if (st->tcp_retrans)
++		fprintf(f, ", %llu retrans", st->tcp_retrans);
++
++	fprintf(f, ", %llu throttled", st->throttled);
++
++	if (st->flows_plimit)
++		fprintf(f, ", %llu flows_plimit", st->flows_plimit);
++
++	if (st->pkts_too_long || st->allocation_errors)
++		fprintf(f, "\n  %llu too long pkts, %llu alloc errors\n",
++			st->pkts_too_long, st->allocation_errors);
++
++	return 0;
++}
++
++struct qdisc_util fq_qdisc_util = {
++	.id		= "fq",
++	.parse_qopt	= fq_parse_opt,
++	.print_qopt	= fq_print_opt,
++	.print_xstats	= fq_print_xstats,
++};
+-- 
+1.8.3.1
+
diff --git a/SOURCES/iproute2-3.10.0-route.patch b/SOURCES/iproute2-3.10.0-route.patch
new file mode 100644
index 0000000..f455da1
--- /dev/null
+++ b/SOURCES/iproute2-3.10.0-route.patch
@@ -0,0 +1,29 @@
+commit 922b4822043726dedee2b8e5c3729f7b1e856139
+Author: Pavel Simerda <psimerda@redhat.com>
+Date:   Tue Dec 2 17:45:10 2014 +0100
+
+    ip route: don't assume default route
+    
+    Just print the help when "ip route del" is called without any other
+    arguments.
+    
+    Resolves:
+    
+     * https://bugzilla.redhat.com/show_bug.cgi?id=997965
+    
+    Signed-off-by: Pavel Šimerda <psimerda@redhat.com>
+
+diff --git a/ip/iproute.c b/ip/iproute.c
+index c9cf5d6..32847c6 100644
+--- a/ip/iproute.c
++++ b/ip/iproute.c
+@@ -975,6 +975,9 @@ static int iproute_modify(int cmd, unsigned flags, int argc, char **argv)
+ 		argc--; argv++;
+ 	}
+ 
++	if (!dst_ok)
++		usage();
++
+ 	if (d || nhs_ok)  {
+ 		int idx;
+ 
diff --git a/SOURCES/iproute2-3.10.0-rtnl_send.patch b/SOURCES/iproute2-3.10.0-rtnl_send.patch
deleted file mode 100644
index ea0ee13..0000000
--- a/SOURCES/iproute2-3.10.0-rtnl_send.patch
+++ /dev/null
@@ -1,20 +0,0 @@
-diff --git a/ip/iplink.c b/ip/iplink.c
-index dc98019..15dd84f 100644
---- a/ip/iplink.c
-+++ b/ip/iplink.c
-@@ -176,8 +176,13 @@ static int iplink_have_newlink(void)
- 		req.n.nlmsg_type = RTM_NEWLINK;
- 		req.i.ifi_family = AF_UNSPEC;
- 
--		rtnl_send(&rth, &req.n, req.n.nlmsg_len);
--		rtnl_listen(&rth, accept_msg, NULL);
-+		if (rtnl_send(&rth, &req.n, req.n.nlmsg_len) < 0) {
-+			perror("Could not check for "
-+				"link configuration over netlink support");
-+			have_rtnl_newlink = 0;
-+		} else {
-+			rtnl_listen(&rth, accept_msg, NULL);
-+		}
- 	}
- 	return have_rtnl_newlink;
- }
diff --git a/SOURCES/iproute2-3.10.0-ss-print-value-of-IPV6_V6ONLY-socket-option-if-set.patch b/SOURCES/iproute2-3.10.0-ss-print-value-of-IPV6_V6ONLY-socket-option-if-set.patch
new file mode 100644
index 0000000..6a8a85d
--- /dev/null
+++ b/SOURCES/iproute2-3.10.0-ss-print-value-of-IPV6_V6ONLY-socket-option-if-set.patch
@@ -0,0 +1,33 @@
+From 14809558dba9fe8c9ff2943fbea8cb05f6a1bfbf Mon Sep 17 00:00:00 2001
+From: Phil Sutter <phil@nwl.cc>
+Date: Wed, 24 Jun 2015 13:07:20 +0200
+Subject: [PATCH 2/2] ss: print value of IPV6_V6ONLY socket option if set
+
+If available and set, print 'v6only:1' for AF_INET6 sockets upon request
+of extended information. For IPv6 sockets bound to in6addr_any, this is
+the only way to determine if they will also accept IPv4 requests or not.
+
+Signed-off-by: Phil Sutter <phil@nwl.cc>
+---
+ misc/ss.c | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+diff --git a/misc/ss.c b/misc/ss.c
+index 954a30b..ec08e03 100644
+--- a/misc/ss.c
++++ b/misc/ss.c
+@@ -2026,6 +2026,11 @@ static int inet_show_sock(struct nlmsghdr *nlh, struct filter *f, int protocol)
+ 
+ 	if (show_details) {
+ 		sock_details_print(&s);
++		if (s.local.family == AF_INET6 && tb[INET_DIAG_SKV6ONLY]) {
++			unsigned char v6only;
++			v6only = *(__u8 *)RTA_DATA(tb[INET_DIAG_SKV6ONLY]);
++			printf(" v6only:%u", v6only);
++		}
+ 		if (tb[INET_DIAG_SHUTDOWN]) {
+ 			unsigned char mask;
+ 			mask = *(__u8 *)RTA_DATA(tb[INET_DIAG_SHUTDOWN]);
+-- 
+1.8.3.1
+
diff --git a/SOURCES/iproute2-3.10.0-ss.patch b/SOURCES/iproute2-3.10.0-ss.patch
new file mode 100644
index 0000000..938928f
--- /dev/null
+++ b/SOURCES/iproute2-3.10.0-ss.patch
@@ -0,0 +1,3644 @@
+From 86f398ded8260a68b52de1f6669f5c3ccc69b350 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Pavel=20=C5=A0imerda?= <psimerda@redhat.com>
+Date: Mon, 27 Apr 2015 14:56:19 +0200
+Subject: [PATCH iproute2 3/4] backport 'ss' command from 4.0.0
+
+Patch obtained using the following command.
+
+git diff v3.10.0..v4.0.0 misc/ss* man/man8/ss.8 doc/ss.sgml
+
+Plus added missing hooks to check for SELinux and the following fixup:
+- d2055ea ss: Fix allocation of cong control alg name
+---
+ configure       |   15 +
+ doc/ss.sgml     |    2 +-
+ man/man8/ss.8   |   82 +-
+ misc/Makefile   |    5 +
+ misc/ss.c       | 2321 +++++++++++++++++++++++++++++++------------------------
+ misc/ssfilter.h |    4 +-
+ misc/ssfilter.y |   23 +-
+ 7 files changed, 1419 insertions(+), 1033 deletions(-)
+
+diff --git a/configure b/configure
+index da01c19..d5170f0 100755
+--- a/configure
++++ b/configure
+@@ -231,6 +231,18 @@ EOF
+     rm -f $TMPDIR/ipsettest.c $TMPDIR/ipsettest
+ }
+ 
++check_selinux()
++# SELinux is a compile time option in the ss utility
++{
++	if ${PKG_CONFIG} libselinux --exists
++	then
++		echo "HAVE_SELINUX:=y" >>Config
++		echo "yes"
++	else
++		echo "no"
++	fi
++}
++
+ echo "# Generated config based on" $INCLUDE >Config
+ check_toolchain
+ 
+@@ -253,3 +265,6 @@ check_ipt_lib_dir
+ 
+ echo -n "libc has setns: "
+ check_setns
++
++echo -n "SELinux support: "
++check_selinux
+diff --git a/doc/ss.sgml b/doc/ss.sgml
+index 0b1b533..3024b57 100644
+--- a/doc/ss.sgml
++++ b/doc/ss.sgml
+@@ -3,7 +3,7 @@
+ <article>
+ 
+ <title>SS Utility: Quick Intro
+-<author>Alexey Kuznetosv, <tt/kuznet@ms2.inr.ac.ru/
++<author>Alexey Kuznetsov, <tt/kuznet@ms2.inr.ac.ru/
+ <date>some_negative_number, 20 Sep 2001
+ <abstract>
+ <tt/ss/ is one another utility to investigate sockets.
+diff --git a/man/man8/ss.8 b/man/man8/ss.8
+index e55dd0c..b7fbaef 100644
+--- a/man/man8/ss.8
++++ b/man/man8/ss.8
+@@ -53,6 +53,40 @@ Print summary statistics. This option does not parse socket lists obtaining
+ summary from various sources. It is useful when amount of sockets is so huge
+ that parsing /proc/net/tcp is painful.
+ .TP
++.B \-Z, \-\-context
++As the
++.B \-p
++option but also shows process security context.
++.sp
++For
++.BR netlink (7)
++sockets the initiating process context is displayed as follows:
++.RS
++.RS
++.IP "1." 4
++If valid pid show the process context.
++.IP "2." 4
++If destination is kernel (pid = 0) show kernel initial context.
++.IP "3." 4
++If a unique identifier has been allocated by the kernel or netlink user,
++show context as "unavailable". This will generally indicate that a
++process has more than one netlink socket active.
++.RE
++.RE
++.TP
++.B \-z, \-\-contexts
++As the
++.B \-Z
++option but also shows the socket context. The socket context is
++taken from the associated inode and is not the actual socket
++context held by the kernel. Sockets are typically labeled with the
++context of the creating process, however the context shown will reflect
++any policy role, type and/or range transition rules applied,
++and is therefore a useful reference.
++.TP
++.B \-N NSNAME, \-\-net=NSNAME
++Switch to the specified network namespace name.
++.TP
+ .B \-b, \-\-bpf
+ Show socket BPF filters (only administrators are allowed to get these information).
+ .TP
+@@ -87,7 +121,7 @@ Currently the following families are supported: unix, inet, inet6, link, netlink
+ .B \-A QUERY, \-\-query=QUERY, \-\-socket=QUERY
+ List of socket tables to dump, separated by commas. The following identifiers
+ are understood: all, inet, tcp, udp, raw, unix, packet, netlink, unix_dgram,
+-unix_stream, packet_raw, packet_dgram.
++unix_stream, unix_seqpacket, packet_raw, packet_dgram.
+ .TP
+ .B \-D FILE, \-\-diag=FILE
+ Do not display anything, just dump raw information about TCP sockets to FILE after applying filters. If FILE is - stdout is used.
+@@ -96,13 +130,49 @@ Do not display anything, just dump raw information about TCP sockets to FILE aft
+ Read filter information from FILE.
+ Each line of FILE is interpreted like single command line option. If FILE is - stdin is used.
+ .TP
+-.B FILTER := [ state TCP-STATE ] [ EXPRESSION ]
++.B FILTER := [ state STATE-FILTER ] [ EXPRESSION ]
+ Please take a look at the official documentation (Debian package iproute-doc) for details regarding filters.
++
++.SH STATE-FILTER
++
++.B STATE-FILTER
++allows to construct arbitrary set of states to match. Its syntax is sequence of keywords state and exclude followed by identifier of state.
++.TP
++Available identifiers are:
++
++All standard TCP states:
++.BR established ", " syn-sent ", " syn-recv ", " fin-wait-1 ", " fin-wait-2 ", " time-wait ", " closed ", " close-wait ", " last-ack ", "
++.BR  listen " and " closing.
++
++.B all
++- for all the states
++
++.B connected
++- all the states except for
++.BR listen " and " closed
++
++.B synchronized
++- all the
++.B connected
++states except for
++.B syn-sent
++
++.B bucket
++- states, which are maintained as minisockets, i.e.
++.BR time-wait " and " syn-recv
++
++.B big
++- opposite to
++.B bucket
++
+ .SH USAGE EXAMPLES
+ .TP
+ .B ss -t -a
+ Display all TCP sockets.
+ .TP
++.B ss -t -a -Z
++Display all TCP sockets with process SELinux security contexts.
++.TP
+ .B ss -u -a
+ Display all UDP sockets.
+ .TP
+@@ -116,10 +186,14 @@ Find all local processes connected to X server.
+ List all the tcp sockets in state FIN-WAIT-1 for our apache to network 193.233.7/24 and look at their timers.
+ .SH SEE ALSO
+ .BR ip (8),
+-.BR /usr/share/doc/iproute-doc/ss.html " (package iproute�doc)"
++.BR /usr/share/doc/iproute-doc/ss.html " (package iproute�doc)",
++.br
++.BR RFC " 793 "
++- https://tools.ietf.org/rfc/rfc793.txt (TCP states) 
++
+ .SH AUTHOR
+ .I ss 
+-was written by Alexey Kuznetosv, <kuznet@ms2.inr.ac.ru>.
++was written by Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>.
+ .PP
+ This manual page was written by Michael Prokop <mika@grml.org>
+ for the Debian project (but may be used by others).
+diff --git a/misc/Makefile b/misc/Makefile
+index a516bd8..b7ecba9 100644
+--- a/misc/Makefile
++++ b/misc/Makefile
+@@ -5,6 +5,11 @@ TARGETS=ss nstat ifstat rtacct arpd lnstat
+ 
+ include ../Config
+ 
++ifeq ($(HAVE_SELINUX),y)
++	LDLIBS += $(shell pkg-config --libs libselinux)
++	CFLAGS += $(shell pkg-config --cflags libselinux) -DHAVE_SELINUX
++endif
++
+ ifeq ($(IP_CONFIG_SETNS),y)
+ 	CFLAGS += -DHAVE_SETNS
+ endif
+diff --git a/misc/ss.c b/misc/ss.c
+index c0369f1..954a30b 100644
+--- a/misc/ss.c
++++ b/misc/ss.c
+@@ -25,11 +25,13 @@
+ #include <dirent.h>
+ #include <fnmatch.h>
+ #include <getopt.h>
++#include <stdbool.h>
+ 
+ #include "utils.h"
+ #include "rt_names.h"
+ #include "ll_map.h"
+ #include "libnetlink.h"
++#include "namespace.h"
+ #include "SNAPSHOT.h"
+ 
+ #include <linux/tcp.h>
+@@ -41,6 +43,49 @@
+ #include <linux/packet_diag.h>
+ #include <linux/netlink_diag.h>
+ 
++#define MAGIC_SEQ 123456
++
++#define DIAG_REQUEST(_req, _r)						    \
++	struct {							    \
++		struct nlmsghdr nlh;					    \
++		_r;							    \
++	} _req = {							    \
++		.nlh = {						    \
++			.nlmsg_type = SOCK_DIAG_BY_FAMILY,		    \
++			.nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST,\
++			.nlmsg_seq = MAGIC_SEQ,				    \
++			.nlmsg_len = sizeof(_req),			    \
++		},							    \
++	}
++
++#if HAVE_SELINUX
++#include <selinux/selinux.h>
++#else
++/* Stubs for SELinux functions */
++static int is_selinux_enabled(void)
++{
++	return -1;
++}
++
++static int getpidcon(pid_t pid, char **context)
++{
++	*context = NULL;
++	return -1;
++}
++
++static int getfilecon(char *path, char **context)
++{
++	*context = NULL;
++	return -1;
++}
++
++static int security_get_initial_context(char *name,  char **context)
++{
++	*context = NULL;
++	return -1;
++}
++#endif
++
+ int resolve_hosts = 0;
+ int resolve_services = 1;
+ int preferred_family = AF_UNSPEC;
+@@ -50,6 +95,10 @@ int show_users = 0;
+ int show_mem = 0;
+ int show_tcpinfo = 0;
+ int show_bpf = 0;
++int show_proc_ctx = 0;
++int show_sock_ctx = 0;
++/* If show_users & show_proc_ctx only do user_ent_hash_build() once */
++int user_ent_hash_build_init = 0;
+ 
+ int netid_width;
+ int state_width;
+@@ -71,6 +120,7 @@ enum
+ 	RAW_DB,
+ 	UNIX_DG_DB,
+ 	UNIX_ST_DB,
++	UNIX_SQ_DB,
+ 	PACKET_DG_DB,
+ 	PACKET_R_DB,
+ 	NETLINK_DB,
+@@ -78,8 +128,9 @@ enum
+ };
+ 
+ #define PACKET_DBM ((1<<PACKET_DG_DB)|(1<<PACKET_R_DB))
+-#define UNIX_DBM ((1<<UNIX_DG_DB)|(1<<UNIX_ST_DB))
++#define UNIX_DBM ((1<<UNIX_DG_DB)|(1<<UNIX_ST_DB)|(1<<UNIX_SQ_DB))
+ #define ALL_DB ((1<<MAX_DB)-1)
++#define INET_DBM ((1<<TCP_DB)|(1<<UDP_DB)|(1<<DCCP_DB)|(1<<RAW_DB))
+ 
+ enum {
+ 	SS_UNKNOWN,
+@@ -97,7 +148,8 @@ enum {
+ 	SS_MAX
+ };
+ 
+-#define SS_ALL ((1<<SS_MAX)-1)
++#define SS_ALL ((1 << SS_MAX) - 1)
++#define SS_CONN (SS_ALL & ~((1<<SS_LISTEN)|(1<<SS_CLOSE)|(1<<SS_TIME_WAIT)|(1<<SS_SYN_RECV)))
+ 
+ #include "ssfilter.h"
+ 
+@@ -109,13 +161,127 @@ struct filter
+ 	struct ssfilter *f;
+ };
+ 
+-struct filter default_filter = {
+-	.dbs	=  ~0,
+-	.states = SS_ALL & ~((1<<SS_LISTEN)|(1<<SS_CLOSE)|(1<<SS_TIME_WAIT)|(1<<SS_SYN_RECV)),
+-	.families= (1<<AF_INET)|(1<<AF_INET6),
++static const struct filter default_dbs[MAX_DB] = {
++	[TCP_DB] = {
++		.states   = SS_CONN,
++		.families = (1 << AF_INET) | (1 << AF_INET6),
++	},
++	[DCCP_DB] = {
++		.states   = SS_CONN,
++		.families = (1 << AF_INET) | (1 << AF_INET6),
++	},
++	[UDP_DB] = {
++		.states   = (1 << SS_ESTABLISHED),
++		.families = (1 << AF_INET) | (1 << AF_INET6),
++	},
++	[RAW_DB] = {
++		.states   = (1 << SS_ESTABLISHED),
++		.families = (1 << AF_INET) | (1 << AF_INET6),
++	},
++	[UNIX_DG_DB] = {
++		.states   = (1 << SS_CLOSE),
++		.families = (1 << AF_UNIX),
++	},
++	[UNIX_ST_DB] = {
++		.states   = SS_CONN,
++		.families = (1 << AF_UNIX),
++	},
++	[UNIX_SQ_DB] = {
++		.states   = SS_CONN,
++		.families = (1 << AF_UNIX),
++	},
++	[PACKET_DG_DB] = {
++		.states   = (1 << SS_CLOSE),
++		.families = (1 << AF_PACKET),
++	},
++	[PACKET_R_DB] = {
++		.states   = (1 << SS_CLOSE),
++		.families = (1 << AF_PACKET),
++	},
++	[NETLINK_DB] = {
++		.states   = (1 << SS_CLOSE),
++		.families = (1 << AF_NETLINK),
++	},
++};
++
++static const struct filter default_afs[AF_MAX] = {
++	[AF_INET] = {
++		.dbs    = INET_DBM,
++		.states = SS_CONN,
++	},
++	[AF_INET6] = {
++		.dbs    = INET_DBM,
++		.states = SS_CONN,
++	},
++	[AF_UNIX] = {
++		.dbs    = UNIX_DBM,
++		.states = SS_CONN,
++	},
++	[AF_PACKET] = {
++		.dbs    = PACKET_DBM,
++		.states = (1 << SS_CLOSE),
++	},
++	[AF_NETLINK] = {
++		.dbs    = (1 << NETLINK_DB),
++		.states = (1 << SS_CLOSE),
++	},
+ };
+ 
+-struct filter current_filter;
++static int do_default = 1;
++static struct filter current_filter;
++
++static void filter_db_set(struct filter *f, int db)
++{
++	f->states   |= default_dbs[db].states;
++	f->families |= default_dbs[db].families;
++	f->dbs	    |= 1 << db;
++	do_default   = 0;
++}
++
++static void filter_af_set(struct filter *f, int af)
++{
++	f->dbs		   |= default_afs[af].dbs;
++	f->states	   |= default_afs[af].states;
++	f->families	   |= 1 << af;
++	do_default	    = 0;
++	preferred_family    = af;
++}
++
++static int filter_af_get(struct filter *f, int af)
++{
++	return f->families & (1 << af);
++}
++
++static void filter_default_dbs(struct filter *f)
++{
++	filter_db_set(f, UDP_DB);
++	filter_db_set(f, DCCP_DB);
++	filter_db_set(f, TCP_DB);
++	filter_db_set(f, RAW_DB);
++	filter_db_set(f, UNIX_ST_DB);
++	filter_db_set(f, UNIX_DG_DB);
++	filter_db_set(f, UNIX_SQ_DB);
++	filter_db_set(f, PACKET_R_DB);
++	filter_db_set(f, PACKET_DG_DB);
++	filter_db_set(f, NETLINK_DB);
++}
++
++static void filter_merge(struct filter *af, struct filter *dbf, int states)
++{
++	if (af->families)
++		af->families = (af->families | dbf->families) & af->families;
++	else
++		af->families = dbf->families;
++
++	if (dbf->dbs)
++		af->dbs = (af->dbs | dbf->dbs) & dbf->dbs;
++
++	if (dbf->states)
++		af->states = (af->states | dbf->states) & dbf->states;
++
++	if (states)
++		af->states = (af->states | states) & states;
++}
+ 
+ static FILE *generic_proc_open(const char *env, const char *name)
+ {
+@@ -206,7 +372,9 @@ struct user_ent {
+ 	unsigned int	ino;
+ 	int		pid;
+ 	int		fd;
+-	char		process[0];
++	char		*process;
++	char		*process_ctx;
++	char		*socket_ctx;
+ };
+ 
+ #define USER_ENT_HASH_SIZE	256
+@@ -219,26 +387,50 @@ static int user_ent_hashfn(unsigned int ino)
+ 	return val & (USER_ENT_HASH_SIZE - 1);
+ }
+ 
+-static void user_ent_add(unsigned int ino, const char *process, int pid, int fd)
++static void user_ent_add(unsigned int ino, char *process,
++					int pid, int fd,
++					char *proc_ctx,
++					char *sock_ctx)
+ {
+ 	struct user_ent *p, **pp;
+-	int str_len;
+ 
+-	str_len = strlen(process) + 1;
+-	p = malloc(sizeof(struct user_ent) + str_len);
+-	if (!p)
++	p = malloc(sizeof(struct user_ent));
++	if (!p) {
++		fprintf(stderr, "ss: failed to malloc buffer\n");
+ 		abort();
++	}
+ 	p->next = NULL;
+ 	p->ino = ino;
+ 	p->pid = pid;
+ 	p->fd = fd;
+-	strcpy(p->process, process);
++	p->process = strdup(process);
++	p->process_ctx = strdup(proc_ctx);
++	p->socket_ctx = strdup(sock_ctx);
+ 
+ 	pp = &user_ent_hash[user_ent_hashfn(ino)];
+ 	p->next = *pp;
+ 	*pp = p;
+ }
+ 
++static void user_ent_destroy(void)
++{
++	struct user_ent *p, *p_next;
++	int cnt = 0;
++
++	while (cnt != USER_ENT_HASH_SIZE) {
++		p = user_ent_hash[cnt];
++		while (p) {
++			free(p->process);
++			free(p->process_ctx);
++			free(p->socket_ctx);
++			p_next = p->next;
++			free(p);
++			p = p_next;
++		}
++		cnt++;
++	}
++}
++
+ static void user_ent_hash_build(void)
+ {
+ 	const char *root = getenv("PROC_ROOT") ? : "/proc/";
+@@ -246,6 +438,15 @@ static void user_ent_hash_build(void)
+ 	char name[1024];
+ 	int nameoff;
+ 	DIR *dir;
++	char *pid_context;
++	char *sock_context;
++	const char *no_ctx = "unavailable";
++
++	/* If show_users & show_proc_ctx set only do this once */
++	if (user_ent_hash_build_init != 0)
++		return;
++
++	user_ent_hash_build_init = 1;
+ 
+ 	strcpy(name, root);
+ 	if (strlen(name) == 0 || name[strlen(name)-1] != '/')
+@@ -260,6 +461,7 @@ static void user_ent_hash_build(void)
+ 	while ((d = readdir(dir)) != NULL) {
+ 		struct dirent *d1;
+ 		char process[16];
++		char *p;
+ 		int pid, pos;
+ 		DIR *dir1;
+ 		char crap;
+@@ -267,12 +469,16 @@ static void user_ent_hash_build(void)
+ 		if (sscanf(d->d_name, "%d%c", &pid, &crap) != 1)
+ 			continue;
+ 
++		if (getpidcon(pid, &pid_context) != 0)
++			pid_context = strdup(no_ctx);
++
+ 		sprintf(name + nameoff, "%d/fd/", pid);
+ 		pos = strlen(name);
+ 		if ((dir1 = opendir(name)) == NULL)
+ 			continue;
+ 
+ 		process[0] = '\0';
++		p = process;
+ 
+ 		while ((d1 = readdir(dir1)) != NULL) {
+ 			const char *pattern = "socket:[";
+@@ -280,6 +486,7 @@ static void user_ent_hash_build(void)
+ 			char lnk[64];
+ 			int fd;
+ 			ssize_t link_len;
++			char tmp[1024];
+ 
+ 			if (sscanf(d1->d_name, "%d%c", &fd, &crap) != 1)
+ 				continue;
+@@ -296,55 +503,107 @@ static void user_ent_hash_build(void)
+ 
+ 			sscanf(lnk, "socket:[%u]", &ino);
+ 
+-			if (process[0] == '\0') {
+-				char tmp[1024];
++			snprintf(tmp, sizeof(tmp), "%s/%d/fd/%s",
++					root, pid, d1->d_name);
++
++			if (getfilecon(tmp, &sock_context) <= 0)
++				sock_context = strdup(no_ctx);
++
++			if (*p == '\0') {
+ 				FILE *fp;
+ 
+-				snprintf(tmp, sizeof(tmp), "%s/%d/stat", root, pid);
++				snprintf(tmp, sizeof(tmp), "%s/%d/stat",
++					root, pid);
+ 				if ((fp = fopen(tmp, "r")) != NULL) {
+-					fscanf(fp, "%*d (%[^)])", process);
++					fscanf(fp, "%*d (%[^)])", p);
+ 					fclose(fp);
+ 				}
+ 			}
+-
+-			user_ent_add(ino, process, pid, fd);
++			user_ent_add(ino, p, pid, fd,
++					pid_context, sock_context);
++			free(sock_context);
+ 		}
++		free(pid_context);
+ 		closedir(dir1);
+ 	}
+ 	closedir(dir);
+ }
+ 
+-static int find_users(unsigned ino, char *buf, int buflen)
++enum entry_types {
++	USERS,
++	PROC_CTX,
++	PROC_SOCK_CTX
++};
++
++#define ENTRY_BUF_SIZE 512
++static int find_entry(unsigned ino, char **buf, int type)
+ {
+ 	struct user_ent *p;
+ 	int cnt = 0;
+ 	char *ptr;
++	char **new_buf = buf;
++	int len, new_buf_len;
++	int buf_used = 0;
++	int buf_len = 0;
+ 
+ 	if (!ino)
+ 		return 0;
+ 
+ 	p = user_ent_hash[user_ent_hashfn(ino)];
+-	ptr = buf;
++	ptr = *buf = NULL;
+ 	while (p) {
+ 		if (p->ino != ino)
+ 			goto next;
+ 
+-		if (ptr - buf >= buflen - 1)
+-			break;
++		while (1) {
++			ptr = *buf + buf_used;
++			switch (type) {
++			case USERS:
++				len = snprintf(ptr, buf_len - buf_used,
++					"(\"%s\",pid=%d,fd=%d),",
++					p->process, p->pid, p->fd);
++				break;
++			case PROC_CTX:
++				len = snprintf(ptr, buf_len - buf_used,
++					"(\"%s\",pid=%d,proc_ctx=%s,fd=%d),",
++					p->process, p->pid,
++					p->process_ctx, p->fd);
++				break;
++			case PROC_SOCK_CTX:
++				len = snprintf(ptr, buf_len - buf_used,
++					"(\"%s\",pid=%d,proc_ctx=%s,fd=%d,sock_ctx=%s),",
++					p->process, p->pid,
++					p->process_ctx, p->fd,
++					p->socket_ctx);
++				break;
++			default:
++				fprintf(stderr, "ss: invalid type: %d\n", type);
++				abort();
++			}
+ 
+-		snprintf(ptr, buflen - (ptr - buf),
+-			 "(\"%s\",%d,%d),",
+-			 p->process, p->pid, p->fd);
+-		ptr += strlen(ptr);
++			if (len < 0 || len >= buf_len - buf_used) {
++				new_buf_len = buf_len + ENTRY_BUF_SIZE;
++				*new_buf = realloc(*buf, new_buf_len);
++				if (!new_buf) {
++					fprintf(stderr, "ss: failed to malloc buffer\n");
++					abort();
++				}
++				**buf = **new_buf;
++				buf_len = new_buf_len;
++				continue;
++			} else {
++				buf_used += len;
++				break;
++			}
++		}
+ 		cnt++;
+-
+-	next:
++next:
+ 		p = p->next;
+ 	}
+-
+-	if (ptr != buf)
++	if (buf_used) {
++		ptr = *buf + buf_used;
+ 		ptr[-1] = '\0';
+-
++	}
+ 	return cnt;
+ }
+ 
+@@ -359,7 +618,7 @@ struct slabstat
+ 	int skbs;
+ };
+ 
+-struct slabstat slabstat;
++static struct slabstat slabstat;
+ 
+ static const char *slabstat_ids[] =
+ {
+@@ -375,6 +634,10 @@ static int get_slabstat(struct slabstat *s)
+ 	char buf[256];
+ 	FILE *fp;
+ 	int cnt;
++	static int slabstat_valid;
++
++	if (slabstat_valid)
++		return 0;
+ 
+ 	memset(s, 0, sizeof(*s));
+ 
+@@ -398,10 +661,29 @@ static int get_slabstat(struct slabstat *s)
+ 			break;
+ 	}
+ 
++	slabstat_valid = 1;
++
+ 	fclose(fp);
+ 	return 0;
+ }
+ 
++static inline void sock_addr_set_str(inet_prefix *prefix, char **ptr)
++{
++    memcpy(prefix->data, ptr, sizeof(char *));
++}
++
++static inline char *sock_addr_get_str(const inet_prefix *prefix)
++{
++    char *tmp ;
++    memcpy(&tmp, prefix->data, sizeof(char *));
++    return tmp;
++}
++
++static unsigned long long cookie_sk_get(const uint32_t *cookie)
++{
++	return (((unsigned long long)cookie[1] << 31) << 1) | cookie[0];
++}
++
+ static const char *sstate_name[] = {
+ 	"UNKNOWN",
+ 	[SS_ESTABLISHED] = "ESTAB",
+@@ -432,25 +714,106 @@ static const char *sstate_namel[] = {
+ 	[SS_CLOSING] = "closing",
+ };
+ 
++struct sockstat
++{
++	struct sockstat	   *next;
++	unsigned int	    type;
++	uint16_t	    prot;
++	inet_prefix	    local;
++	inet_prefix	    remote;
++	int		    lport;
++	int		    rport;
++	int		    state;
++	int		    rq, wq;
++	unsigned	    ino;
++	unsigned	    uid;
++	int		    refcnt;
++	unsigned int	    iface;
++	unsigned long long  sk;
++};
++
++struct dctcpstat
++{
++	unsigned int	ce_state;
++	unsigned int	alpha;
++	unsigned int	ab_ecn;
++	unsigned int	ab_tot;
++	bool		enabled;
++};
++
+ struct tcpstat
+ {
+-	inet_prefix	local;
+-	inet_prefix	remote;
+-	int		lport;
+-	int		rport;
+-	int		state;
+-	int		rq, wq;
+-	int		timer;
+-	int		timeout;
+-	int		retrs;
+-	unsigned	ino;
+-	int		probes;
+-	unsigned	uid;
+-	int		refcnt;
+-	unsigned long long sk;
+-	int		rto, ato, qack, cwnd, ssthresh;
++	struct sockstat	    ss;
++	int		    timer;
++	int		    timeout;
++	int		    probes;
++	char		    cong_alg[16];
++	double		    rto, ato, rtt, rttvar;
++	int		    qack, cwnd, ssthresh, backoff;
++	double		    send_bps;
++	int		    snd_wscale;
++	int		    rcv_wscale;
++	int		    mss;
++	unsigned int	    lastsnd;
++	unsigned int	    lastrcv;
++	unsigned int	    lastack;
++	double		    pacing_rate;
++	double		    pacing_rate_max;
++	unsigned int	    unacked;
++	unsigned int	    retrans;
++	unsigned int	    retrans_total;
++	unsigned int	    lost;
++	unsigned int	    sacked;
++	unsigned int	    fackets;
++	unsigned int	    reordering;
++	double		    rcv_rtt;
++	int		    rcv_space;
++	bool		    has_ts_opt;
++	bool		    has_sack_opt;
++	bool		    has_ecn_opt;
++	bool		    has_ecnseen_opt;
++	bool		    has_fastopen_opt;
++	bool		    has_wscale_opt;
++	struct dctcpstat    *dctcp;
+ };
+ 
++static void sock_state_print(struct sockstat *s, const char *sock_name)
++{
++	if (netid_width)
++		printf("%-*s ", netid_width, sock_name);
++	if (state_width)
++		printf("%-*s ", state_width, sstate_name[s->state]);
++
++	printf("%-6d %-6d ", s->rq, s->wq);
++}
++
++static void sock_details_print(struct sockstat *s)
++{
++	if (s->uid)
++		printf(" uid:%u", s->uid);
++
++	printf(" ino:%u", s->ino);
++	printf(" sk:%llx", s->sk);
++}
++
++static void sock_addr_print_width(int addr_len, const char *addr, char *delim,
++		int port_len, const char *port, const char *ifname)
++{
++	if (ifname) {
++		printf("%*s%%%s%s%-*s ", addr_len, addr, ifname, delim,
++				port_len, port);
++	}
++	else {
++		printf("%*s%s%-*s ", addr_len, addr, delim, port_len, port);
++	}
++}
++
++static void sock_addr_print(const char *addr, char *delim, const char *port,
++		const char *ifname)
++{
++	sock_addr_print_width(addr_width, addr, delim, serv_width, port, ifname);
++}
++
+ static const char *tmr_name[] = {
+ 	"off",
+ 	"on",
+@@ -487,12 +850,6 @@ static const char *print_ms_timer(int timeout)
+ 	return buf;
+ }
+ 
+-static const char *print_hz_timer(int timeout)
+-{
+-	int hz = get_user_hz();
+-	return print_ms_timer(((timeout*1000) + hz-1)/hz);
+-}
+-
+ struct scache
+ {
+ 	struct scache *next;
+@@ -639,13 +996,12 @@ static const char *resolve_service(int port)
+ 	return buf;
+ }
+ 
+-static void formatted_print(const inet_prefix *a, int port)
++static void inet_addr_print(const inet_prefix *a, int port, unsigned int ifindex)
+ {
+ 	char buf[1024];
+ 	const char *ap = buf;
+-	int est_len;
+-
+-	est_len = addr_width;
++	int est_len = addr_width;
++	const char *ifname = NULL;
+ 
+ 	if (a->family == AF_INET) {
+ 		if (a->data[0] == 0) {
+@@ -662,7 +1018,14 @@ static void formatted_print(const inet_prefix *a, int port)
+ 		else
+ 			est_len = addr_width + ((est_len-addr_width+3)/4)*4;
+ 	}
+-	printf("%*s:%-*s ", est_len, ap, serv_width, resolve_service(port));
++
++	if (ifindex) {
++		ifname   = ll_index_to_name(ifindex);
++		est_len -= strlen(ifname) + 1;  /* +1 for percent char */
++	}
++
++	sock_addr_print_width(est_len, ap, ":", serv_width, resolve_service(port),
++			ifname);
+ }
+ 
+ struct aafilter
+@@ -694,9 +1057,9 @@ static int inet2_addr_match(const inet_prefix *a, const inet_prefix *p,
+ 
+ static int unix_match(const inet_prefix *a, const inet_prefix *p)
+ {
+-	char *addr, *pattern;
+-	memcpy(&addr, a->data, sizeof(addr));
+-	memcpy(&pattern, p->data, sizeof(pattern));
++	char *addr = sock_addr_get_str(a);
++	char *pattern = sock_addr_get_str(p);
++
+ 	if (pattern == NULL)
+ 		return 1;
+ 	if (addr == NULL)
+@@ -704,7 +1067,7 @@ static int unix_match(const inet_prefix *a, const inet_prefix *p)
+ 	return !fnmatch(pattern, addr, 0);
+ }
+ 
+-static int run_ssfilter(struct ssfilter *f, struct tcpstat *s)
++static int run_ssfilter(struct ssfilter *f, struct sockstat *s)
+ {
+ 	switch (f->type) {
+ 		case SSF_S_AUTO:
+@@ -712,8 +1075,7 @@ static int run_ssfilter(struct ssfilter *f, struct tcpstat *s)
+                 static int low, high=65535;
+ 
+ 		if (s->local.family == AF_UNIX) {
+-			char *p;
+-			memcpy(&p, s->local.data, sizeof(p));
++			char *p = sock_addr_get_str(&s->local);
+ 			return p == NULL || (p[0] == '@' && strlen(p) == 6 &&
+ 					     strspn(p+1, "0123456789abcdef") == 5);
+ 		}
+@@ -894,7 +1256,8 @@ static int ssfilter_bytecompile(struct ssfilter *f, char **bytecode)
+ 
+ 		case SSF_AND:
+ 	{
+-		char *a1, *a2, *a, l1, l2;
++		char *a1, *a2, *a;
++		int l1, l2;
+ 		l1 = ssfilter_bytecompile(f->pred, &a1);
+ 		l2 = ssfilter_bytecompile(f->post, &a2);
+ 		if (!(a = malloc(l1+l2))) abort();
+@@ -907,7 +1270,8 @@ static int ssfilter_bytecompile(struct ssfilter *f, char **bytecode)
+ 	}
+ 		case SSF_OR:
+ 	{
+-		char *a1, *a2, *a, l1, l2;
++		char *a1, *a2, *a;
++		int l1, l2;
+ 		l1 = ssfilter_bytecompile(f->pred, &a1);
+ 		l2 = ssfilter_bytecompile(f->post, &a2);
+ 		if (!(a = malloc(l1+l2+4))) abort();
+@@ -920,7 +1284,8 @@ static int ssfilter_bytecompile(struct ssfilter *f, char **bytecode)
+ 	}
+ 		case SSF_NOT:
+ 	{
+-		char *a1, *a, l1;
++		char *a1, *a;
++		int l1;
+ 		l1 = ssfilter_bytecompile(f->pred, &a1);
+ 		if (!(a = malloc(l1+4))) abort();
+ 		memcpy(a, a1, l1);
+@@ -993,7 +1358,9 @@ static int xll_initted = 0;
+ static void xll_init(void)
+ {
+ 	struct rtnl_handle rth;
+-	rtnl_open(&rth, 0);
++	if (rtnl_open(&rth, 0) < 0)
++		exit(1);
++
+ 	ll_init_map(&rth);
+ 	rtnl_close(&rth);
+ 	xll_initted = 1;
+@@ -1013,15 +1380,13 @@ static int xll_name_to_index(const char *dev)
+ 	return ll_name_to_index(dev);
+ }
+ 
+-void *parse_hostcond(char *addr)
++void *parse_hostcond(char *addr, bool is_port)
+ {
+ 	char *port = NULL;
+-	struct aafilter a;
++	struct aafilter a = { .port = -1 };
+ 	struct aafilter *res;
+ 	int fam = preferred_family;
+-
+-	memset(&a, 0, sizeof(a));
+-	a.port = -1;
++	struct filter *f = &current_filter;
+ 
+ 	if (fam == AF_UNIX || strncmp(addr, "unix:", 5) == 0) {
+ 		char *p;
+@@ -1030,7 +1395,8 @@ void *parse_hostcond(char *addr)
+ 			addr+=5;
+ 		p = strdup(addr);
+ 		a.addr.bitlen = 8*strlen(p);
+-		memcpy(a.addr.data, &p, sizeof(p));
++		sock_addr_set_str(&a.addr, &p);
++		fam = AF_UNIX;
+ 		goto out;
+ 	}
+ 
+@@ -1056,6 +1422,7 @@ void *parse_hostcond(char *addr)
+ 				return NULL;
+ 			a.addr.data[0] = ntohs(tmp);
+ 		}
++		fam = AF_PACKET;
+ 		goto out;
+ 	}
+ 
+@@ -1078,26 +1445,21 @@ void *parse_hostcond(char *addr)
+ 		}
+ 		if (addr[0] && strcmp(addr, "*")) {
+ 			a.addr.bitlen = 32;
+-			if (get_u32(a.addr.data, addr, 0)) {
+-				if (strcmp(addr, "rtnl") == 0)
+-					a.addr.data[0] = 0;
+-				else if (strcmp(addr, "fw") == 0)
+-					a.addr.data[0] = 3;
+-				else if (strcmp(addr, "tcpdiag") == 0)
+-					a.addr.data[0] = 4;
+-				else
+-					return NULL;
+-			}
++			if (nl_proto_a2n(&a.addr.data[0], addr) == -1)
++				return NULL;
+ 		}
++		fam = AF_NETLINK;
+ 		goto out;
+ 	}
+ 
+-	if (strncmp(addr, "inet:", 5) == 0) {
+-		addr += 5;
++	if (fam == AF_INET || !strncmp(addr, "inet:", 5)) {
+ 		fam = AF_INET;
+-	} else if (strncmp(addr, "inet6:", 6) == 0) {
+-		addr += 6;
++		if (!strncmp(addr, "inet:", 5))
++			addr += 5;
++	} else if (fam == AF_INET6 || !strncmp(addr, "inet6:", 6)) {
+ 		fam = AF_INET6;
++		if (!strncmp(addr, "inet6:", 6))
++			addr += 6;
+ 	}
+ 
+ 	/* URL-like literal [] */
+@@ -1111,10 +1473,14 @@ void *parse_hostcond(char *addr)
+ 	} else {
+ 		port = strrchr(strchr(addr, '/') ? : addr, ':');
+ 	}
++
++	if (is_port)
++		port = addr;
++
+ 	if (port && *port) {
+-		if (*port != ':')
+-			return NULL;
+-		*port++ = 0;
++		if (*port == ':')
++			*port++ = 0;
++
+ 		if (*port && *port != '*') {
+ 			if (get_integer(&a.port, port, 0)) {
+ 				struct servent *se1 = NULL;
+@@ -1155,7 +1521,7 @@ void *parse_hostcond(char *addr)
+ 			}
+ 		}
+ 	}
+-	if (addr && *addr && *addr != '*') {
++	if (!is_port && addr && *addr && *addr != '*') {
+ 		if (get_prefix_1(&a.addr, addr, fam)) {
+ 			if (get_dns_host(&a, addr, fam)) {
+ 				fprintf(stderr, "Error: an inet prefix is expected rather than \"%s\".\n", addr);
+@@ -1164,133 +1530,274 @@ void *parse_hostcond(char *addr)
+ 		}
+ 	}
+ 
+-	out:
++out:
++	if (fam != AF_UNSPEC) {
++		f->families = 0;
++		filter_af_set(f, fam);
++		filter_merge(f, f, 0);
++	}
++
+ 	res = malloc(sizeof(*res));
+ 	if (res)
+ 		memcpy(res, &a, sizeof(a));
+ 	return res;
+ }
+ 
+-static int tcp_show_line(char *line, const struct filter *f, int family)
++static char *proto_name(int protocol)
++{
++	switch (protocol) {
++	case IPPROTO_UDP:
++		return "udp";
++	case IPPROTO_TCP:
++		return "tcp";
++	case IPPROTO_DCCP:
++		return "dccp";
++	}
++
++	return "???";
++}
++
++static void inet_stats_print(struct sockstat *s, int protocol)
++{
++	char *buf = NULL;
++
++	sock_state_print(s, proto_name(protocol));
++
++	inet_addr_print(&s->local, s->lport, s->iface);
++	inet_addr_print(&s->remote, s->rport, 0);
++
++	if (show_proc_ctx || show_sock_ctx) {
++		if (find_entry(s->ino, &buf,
++				(show_proc_ctx & show_sock_ctx) ?
++				PROC_SOCK_CTX : PROC_CTX) > 0) {
++			printf(" users:(%s)", buf);
++			free(buf);
++		}
++	} else if (show_users) {
++		if (find_entry(s->ino, &buf, USERS) > 0) {
++			printf(" users:(%s)", buf);
++			free(buf);
++		}
++	}
++}
++
++static int proc_parse_inet_addr(char *loc, char *rem, int family, struct
++		sockstat *s)
++{
++	s->local.family = s->remote.family = family;
++	if (family == AF_INET) {
++		sscanf(loc, "%x:%x", s->local.data, (unsigned*)&s->lport);
++		sscanf(rem, "%x:%x", s->remote.data, (unsigned*)&s->rport);
++		s->local.bytelen = s->remote.bytelen = 4;
++		return 0;
++	} else {
++		sscanf(loc, "%08x%08x%08x%08x:%x",
++		       s->local.data,
++		       s->local.data + 1,
++		       s->local.data + 2,
++		       s->local.data + 3,
++		       &s->lport);
++		sscanf(rem, "%08x%08x%08x%08x:%x",
++		       s->remote.data,
++		       s->remote.data + 1,
++		       s->remote.data + 2,
++		       s->remote.data + 3,
++		       &s->rport);
++		s->local.bytelen = s->remote.bytelen = 16;
++		return 0;
++	}
++	return -1;
++}
++
++static int proc_inet_split_line(char *line, char **loc, char **rem, char **data)
+ {
+-	struct tcpstat s;
+-	char *loc, *rem, *data;
+-	char opt[256];
+-	int n;
+ 	char *p;
+ 
+ 	if ((p = strchr(line, ':')) == NULL)
+ 		return -1;
+-	loc = p+2;
+ 
+-	if ((p = strchr(loc, ':')) == NULL)
++	*loc = p+2;
++	if ((p = strchr(*loc, ':')) == NULL)
+ 		return -1;
+-	p[5] = 0;
+-	rem = p+6;
+ 
+-	if ((p = strchr(rem, ':')) == NULL)
++	p[5] = 0;
++	*rem = p+6;
++	if ((p = strchr(*rem, ':')) == NULL)
+ 		return -1;
++
+ 	p[5] = 0;
+-	data = p+6;
++	*data = p+6;
++	return 0;
++}
+ 
+-	do {
+-		int state = (data[1] >= 'A') ? (data[1] - 'A' + 10) : (data[1] - '0');
++static char *sprint_bw(char *buf, double bw)
++{
++	if (bw > 1000000.)
++		sprintf(buf,"%.1fM", bw / 1000000.);
++	else if (bw > 1000.)
++		sprintf(buf,"%.1fK", bw / 1000.);
++	else
++		sprintf(buf, "%g", bw);
+ 
+-		if (!(f->states & (1<<state)))
+-			return 0;
+-	} while (0);
++	return buf;
++}
+ 
+-	s.local.family = s.remote.family = family;
+-	if (family == AF_INET) {
+-		sscanf(loc, "%x:%x", s.local.data, (unsigned*)&s.lport);
+-		sscanf(rem, "%x:%x", s.remote.data, (unsigned*)&s.rport);
+-		s.local.bytelen = s.remote.bytelen = 4;
+-	} else {
+-		sscanf(loc, "%08x%08x%08x%08x:%x",
+-		       s.local.data,
+-		       s.local.data+1,
+-		       s.local.data+2,
+-		       s.local.data+3,
+-		       &s.lport);
+-		sscanf(rem, "%08x%08x%08x%08x:%x",
+-		       s.remote.data,
+-		       s.remote.data+1,
+-		       s.remote.data+2,
+-		       s.remote.data+3,
+-		       &s.rport);
+-		s.local.bytelen = s.remote.bytelen = 16;
++static void tcp_stats_print(struct tcpstat *s)
++{
++	char b1[64];
++
++	if (s->has_ts_opt)
++		printf(" ts");
++	if (s->has_sack_opt)
++		printf(" sack");
++	if (s->has_ecn_opt)
++		printf(" ecn");
++	if (s->has_ecnseen_opt)
++		printf(" ecnseen");
++	if (s->has_fastopen_opt)
++		printf(" fastopen");
++	if (s->cong_alg[0])
++		printf(" %s", s->cong_alg);
++	if (s->has_wscale_opt)
++		printf(" wscale:%d,%d", s->snd_wscale, s->rcv_wscale);
++	if (s->rto)
++		printf(" rto:%g", s->rto);
++	if (s->backoff)
++		printf(" backoff:%u", s->backoff);
++	if (s->rtt)
++		printf(" rtt:%g/%g", s->rtt, s->rttvar);
++	if (s->ato)
++		printf(" ato:%g", s->ato);
++
++	if (s->qack)
++		printf(" qack:%d", s->qack);
++	if (s->qack & 1)
++		printf(" bidir");
++
++	if (s->mss)
++		printf(" mss:%d", s->mss);
++	if (s->cwnd && s->cwnd != 2)
++		printf(" cwnd:%d", s->cwnd);
++	if (s->ssthresh)
++		printf(" ssthresh:%d", s->ssthresh);
++
++	if (s->dctcp && s->dctcp->enabled) {
++		struct dctcpstat *dctcp = s->dctcp;
++
++		printf(" dctcp:(ce_state:%u,alpha:%u,ab_ecn:%u,ab_tot:%u)",
++				dctcp->ce_state, dctcp->alpha, dctcp->ab_ecn,
++				dctcp->ab_tot);
++	} else if (s->dctcp) {
++		printf(" dctcp:fallback_mode");
++	}
++
++	if (s->send_bps)
++		printf(" send %sbps", sprint_bw(b1, s->send_bps));
++	if (s->lastsnd)
++		printf(" lastsnd:%u", s->lastsnd);
++	if (s->lastrcv)
++		printf(" lastrcv:%u", s->lastrcv);
++	if (s->lastack)
++		printf(" lastack:%u", s->lastack);
++
++	if (s->pacing_rate) {
++		printf(" pacing_rate %sbps", sprint_bw(b1, s->pacing_rate));
++		if (s->pacing_rate_max)
++				printf("/%sbps", sprint_bw(b1,
++							s->pacing_rate_max));
++	}
++
++	if (s->unacked)
++		printf(" unacked:%u", s->unacked);
++	if (s->retrans || s->retrans_total)
++		printf(" retrans:%u/%u", s->retrans, s->retrans_total);
++	if (s->lost)
++		printf(" lost:%u", s->lost);
++	if (s->sacked && s->ss.state != SS_LISTEN)
++		printf(" sacked:%u", s->sacked);
++	if (s->fackets)
++		printf(" fackets:%u", s->fackets);
++	if (s->reordering != 3)
++		printf(" reordering:%d", s->reordering);
++	if (s->rcv_rtt)
++		printf(" rcv_rtt:%g", s->rcv_rtt);
++	if (s->rcv_space)
++		printf(" rcv_space:%d", s->rcv_space);
++}
++
++static void tcp_timer_print(struct tcpstat *s)
++{
++	if (s->timer) {
++		if (s->timer > 4)
++			s->timer = 5;
++		printf(" timer:(%s,%s,%d)",
++				tmr_name[s->timer],
++				print_ms_timer(s->timeout),
++				s->retrans);
+ 	}
++}
+ 
+-	if (f->f && run_ssfilter(f->f, &s) == 0)
++static int tcp_show_line(char *line, const struct filter *f, int family)
++{
++	int rto = 0, ato = 0;
++	struct tcpstat s = {};
++	char *loc, *rem, *data;
++	char opt[256];
++	int n;
++	int hz = get_user_hz();
++
++	if (proc_inet_split_line(line, &loc, &rem, &data))
++		return -1;
++
++	int state = (data[1] >= 'A') ? (data[1] - 'A' + 10) : (data[1] - '0');
++	if (!(f->states & (1 << state)))
++		return 0;
++
++	proc_parse_inet_addr(loc, rem, family, &s.ss);
++
++	if (f->f && run_ssfilter(f->f, &s.ss) == 0)
+ 		return 0;
+ 
+ 	opt[0] = 0;
+ 	n = sscanf(data, "%x %x:%x %x:%x %x %d %d %u %d %llx %d %d %d %d %d %[^\n]\n",
+-		   &s.state, &s.wq, &s.rq,
+-		   &s.timer, &s.timeout, &s.retrs, &s.uid, &s.probes, &s.ino,
+-		   &s.refcnt, &s.sk, &s.rto, &s.ato, &s.qack,
+-		   &s.cwnd, &s.ssthresh, opt);
++		   &s.ss.state, &s.ss.wq, &s.ss.rq,
++		   &s.timer, &s.timeout, &s.retrans, &s.ss.uid, &s.probes,
++		   &s.ss.ino, &s.ss.refcnt, &s.ss.sk, &rto, &ato, &s.qack, &s.cwnd,
++		   &s.ssthresh, opt);
+ 
+ 	if (n < 17)
+ 		opt[0] = 0;
+ 
+ 	if (n < 12) {
+-		s.rto = 0;
++		rto = 0;
+ 		s.cwnd = 2;
+ 		s.ssthresh = -1;
+-		s.ato = s.qack = 0;
++		ato = s.qack = 0;
+ 	}
+ 
+-	if (netid_width)
+-		printf("%-*s ", netid_width, "tcp");
+-	if (state_width)
+-		printf("%-*s ", state_width, sstate_name[s.state]);
++	s.retrans   = s.timer != 1 ? s.probes : s.retrans;
++	s.timeout   = (s.timeout * 1000 + hz - 1) / hz;
++	s.ato	    = (double)ato / hz;
++	s.qack	   /= 2;
++	s.rto	    = (double)rto;
++	s.ssthresh  = s.ssthresh == -1 ? 0 : s.ssthresh;
++	s.rto	    = s.rto != 3 * hz  ? s.rto / hz : 0;
+ 
+-	printf("%-6d %-6d ", s.rq, s.wq);
++	inet_stats_print(&s.ss, IPPROTO_TCP);
+ 
+-	formatted_print(&s.local, s.lport);
+-	formatted_print(&s.remote, s.rport);
++	if (show_options)
++		tcp_timer_print(&s);
+ 
+-	if (show_options) {
+-		if (s.timer) {
+-			if (s.timer > 4)
+-				s.timer = 5;
+-			printf(" timer:(%s,%s,%d)",
+-			       tmr_name[s.timer],
+-			       print_hz_timer(s.timeout),
+-			       s.timer != 1 ? s.probes : s.retrs);
+-		}
+-	}
+-	if (show_tcpinfo) {
+-		int hz = get_user_hz();
+-		if (s.rto && s.rto != 3*hz)
+-			printf(" rto:%g", (double)s.rto/hz);
+-		if (s.ato)
+-			printf(" ato:%g", (double)s.ato/hz);
+-		if (s.cwnd != 2)
+-			printf(" cwnd:%d", s.cwnd);
+-		if (s.ssthresh != -1)
+-			printf(" ssthresh:%d", s.ssthresh);
+-		if (s.qack/2)
+-			printf(" qack:%d", s.qack/2);
+-		if (s.qack&1)
+-			printf(" bidir");
+-	}
+-	if (show_users) {
+-		char ubuf[4096];
+-		if (find_users(s.ino, ubuf, sizeof(ubuf)) > 0)
+-			printf(" users:(%s)", ubuf);
+-	}
+ 	if (show_details) {
+-		if (s.uid)
+-			printf(" uid:%u", (unsigned)s.uid);
+-		printf(" ino:%u", s.ino);
+-		printf(" sk:%llx", s.sk);
++		sock_details_print(&s.ss);
+ 		if (opt[0])
+ 			printf(" opt:\"%s\"", opt);
+ 	}
+-	printf("\n");
+ 
++	if (show_tcpinfo)
++		tcp_stats_print(&s);
++
++	printf("\n");
+ 	return 0;
+ }
+ 
+@@ -1320,23 +1827,27 @@ outerr:
+ 	return ferror(fp) ? -1 : 0;
+ }
+ 
+-static char *sprint_bw(char *buf, double bw)
+-{
+-	if (bw > 1000000.)
+-		sprintf(buf,"%.1fM", bw / 1000000.);
+-	else if (bw > 1000.)
+-		sprintf(buf,"%.1fK", bw / 1000.);
+-	else
+-		sprintf(buf, "%g", bw);
+-
+-	return buf;
+-}
+-
+ static void print_skmeminfo(struct rtattr *tb[], int attrtype)
+ {
+ 	const __u32 *skmeminfo;
+-	if (!tb[attrtype])
++
++	if (!tb[attrtype]) {
++		if (attrtype == INET_DIAG_SKMEMINFO) {
++			if (!tb[INET_DIAG_MEMINFO])
++				return;
++
++			const struct inet_diag_meminfo *minfo =
++				RTA_DATA(tb[INET_DIAG_MEMINFO]);
++
++			printf(" mem:(r%u,w%u,f%u,t%u)",
++					minfo->idiag_rmem,
++					minfo->idiag_wmem,
++					minfo->idiag_fmem,
++					minfo->idiag_tmem);
++		}
+ 		return;
++	}
++
+ 	skmeminfo = RTA_DATA(tb[attrtype]);
+ 
+ 	printf(" skmem:(r%u,rb%u,t%u,tb%u,f%u,w%u,o%u",
+@@ -1355,23 +1866,17 @@ static void print_skmeminfo(struct rtattr *tb[], int attrtype)
+ 	printf(")");
+ }
+ 
++#define TCPI_HAS_OPT(info, opt) !!(info->tcpi_options & (opt))
++
+ static void tcp_show_info(const struct nlmsghdr *nlh, struct inet_diag_msg *r,
+ 		struct rtattr *tb[])
+ {
+-	char b1[64];
+ 	double rtt = 0;
++	struct tcpstat s = {};
+ 
+-	if (tb[INET_DIAG_SKMEMINFO]) {
+-		print_skmeminfo(tb, INET_DIAG_SKMEMINFO);
+-	} else if (tb[INET_DIAG_MEMINFO]) {
+-		const struct inet_diag_meminfo *minfo
+-			= RTA_DATA(tb[INET_DIAG_MEMINFO]);
+-		printf(" mem:(r%u,w%u,f%u,t%u)",
+-		       minfo->idiag_rmem,
+-		       minfo->idiag_wmem,
+-		       minfo->idiag_fmem,
+-		       minfo->idiag_tmem);
+-	}
++	s.ss.state = r->idiag_state;
++
++	print_skmeminfo(tb, INET_DIAG_SKMEMINFO);
+ 
+ 	if (tb[INET_DIAG_INFO]) {
+ 		struct tcp_info *info;
+@@ -1386,37 +1891,48 @@ static void tcp_show_info(const struct nlmsghdr *nlh, struct inet_diag_msg *r,
+ 			info = RTA_DATA(tb[INET_DIAG_INFO]);
+ 
+ 		if (show_options) {
+-			if (info->tcpi_options & TCPI_OPT_TIMESTAMPS)
+-				printf(" ts");
+-			if (info->tcpi_options & TCPI_OPT_SACK)
+-				printf(" sack");
+-			if (info->tcpi_options & TCPI_OPT_ECN)
+-				printf(" ecn");
+-			if (info->tcpi_options & TCPI_OPT_ECN_SEEN)
+-				printf(" ecnseen");
+-			if (info->tcpi_options & TCPI_OPT_SYN_DATA)
+-				printf(" fastopen");
++			s.has_ts_opt	   = TCPI_HAS_OPT(info, TCPI_OPT_TIMESTAMPS);
++			s.has_sack_opt	   = TCPI_HAS_OPT(info, TCPI_OPT_SACK);
++			s.has_ecn_opt	   = TCPI_HAS_OPT(info, TCPI_OPT_ECN);
++			s.has_ecnseen_opt  = TCPI_HAS_OPT(info, TCPI_OPT_ECN_SEEN);
++			s.has_fastopen_opt = TCPI_HAS_OPT(info, TCPI_OPT_SYN_DATA);
+ 		}
+ 
+ 		if (tb[INET_DIAG_CONG])
+-			printf(" %s", rta_getattr_str(tb[INET_DIAG_CONG]));
++			strncpy(s.cong_alg,
++				rta_getattr_str(tb[INET_DIAG_CONG]),
++				sizeof(s.cong_alg) - 1);
++
++		if (TCPI_HAS_OPT(info, TCPI_OPT_WSCALE)) {
++			s.has_wscale_opt  = true;
++			s.snd_wscale	  = info->tcpi_snd_wscale;
++			s.rcv_wscale	  = info->tcpi_rcv_wscale;
++		}
+ 
+-		if (info->tcpi_options & TCPI_OPT_WSCALE)
+-			printf(" wscale:%d,%d", info->tcpi_snd_wscale,
+-			       info->tcpi_rcv_wscale);
+ 		if (info->tcpi_rto && info->tcpi_rto != 3000000)
+-			printf(" rto:%g", (double)info->tcpi_rto/1000);
+-		if (info->tcpi_rtt)
+-			printf(" rtt:%g/%g", (double)info->tcpi_rtt/1000,
+-			       (double)info->tcpi_rttvar/1000);
+-		if (info->tcpi_ato)
+-			printf(" ato:%g", (double)info->tcpi_ato/1000);
+-		if (info->tcpi_snd_mss)
+-			printf(" mss:%d", info->tcpi_snd_mss);
+-		if (info->tcpi_snd_cwnd != 2)
+-			printf(" cwnd:%d", info->tcpi_snd_cwnd);
++			s.rto = (double)info->tcpi_rto / 1000;
++
++		s.backoff	 = info->tcpi_backoff;
++		s.rtt		 = (double)info->tcpi_rtt / 1000;
++		s.rttvar	 = (double)info->tcpi_rttvar / 1000;
++		s.ato		 = (double)info->tcpi_ato / 1000;
++		s.mss		 = info->tcpi_snd_mss;
++		s.rcv_space	 = info->tcpi_rcv_space;
++		s.rcv_rtt	 = (double)info->tcpi_rcv_rtt / 1000;
++		s.lastsnd	 = info->tcpi_last_data_sent;
++		s.lastrcv	 = info->tcpi_last_data_recv;
++		s.lastack	 = info->tcpi_last_ack_recv;
++		s.unacked	 = info->tcpi_unacked;
++		s.retrans	 = info->tcpi_retrans;
++		s.retrans_total  = info->tcpi_total_retrans;
++		s.lost		 = info->tcpi_lost;
++		s.sacked	 = info->tcpi_sacked;
++		s.reordering	 = info->tcpi_reordering;
++		s.rcv_space	 = info->tcpi_rcv_space;
++		s.cwnd		 = info->tcpi_snd_cwnd;
++
+ 		if (info->tcpi_snd_ssthresh < 0xFFFF)
+-			printf(" ssthresh:%d", info->tcpi_snd_ssthresh);
++			s.ssthresh = info->tcpi_snd_ssthresh;
+ 
+ 		rtt = (double) info->tcpi_rtt;
+ 		if (tb[INET_DIAG_VEGASINFO]) {
+@@ -1424,108 +1940,102 @@ static void tcp_show_info(const struct nlmsghdr *nlh, struct inet_diag_msg *r,
+ 				= RTA_DATA(tb[INET_DIAG_VEGASINFO]);
+ 
+ 			if (vinfo->tcpv_enabled &&
+-			    vinfo->tcpv_rtt && vinfo->tcpv_rtt != 0x7fffffff)
++					vinfo->tcpv_rtt && vinfo->tcpv_rtt != 0x7fffffff)
+ 				rtt =  vinfo->tcpv_rtt;
+ 		}
+ 
++		if (tb[INET_DIAG_DCTCPINFO]) {
++			struct dctcpstat *dctcp = malloc(sizeof(struct
++						dctcpstat));
++
++			const struct tcp_dctcp_info *dinfo
++				= RTA_DATA(tb[INET_DIAG_DCTCPINFO]);
++
++			dctcp->enabled	= !!dinfo->dctcp_enabled;
++			dctcp->ce_state = dinfo->dctcp_ce_state;
++			dctcp->alpha	= dinfo->dctcp_alpha;
++			dctcp->ab_ecn	= dinfo->dctcp_ab_ecn;
++			dctcp->ab_tot	= dinfo->dctcp_ab_tot;
++			s.dctcp		= dctcp;
++		}
++
+ 		if (rtt > 0 && info->tcpi_snd_mss && info->tcpi_snd_cwnd) {
+-			printf(" send %sbps",
+-			       sprint_bw(b1, (double) info->tcpi_snd_cwnd *
+-					 (double) info->tcpi_snd_mss * 8000000.
+-					 / rtt));
++			s.send_bps = (double) info->tcpi_snd_cwnd *
++				(double)info->tcpi_snd_mss * 8000000. / rtt;
+ 		}
+ 
+-		if (info->tcpi_unacked)
+-			printf(" unacked:%u", info->tcpi_unacked);
+-		if (info->tcpi_retrans || info->tcpi_total_retrans)
+-			printf(" retrans:%u/%u", info->tcpi_retrans,
+-			       info->tcpi_total_retrans);
+-		if (info->tcpi_lost)
+-			printf(" lost:%u", info->tcpi_lost);
+-		if (info->tcpi_sacked && r->idiag_state != SS_LISTEN)
+-			printf(" sacked:%u", info->tcpi_sacked);
+-		if (info->tcpi_fackets)
+-			printf(" fackets:%u", info->tcpi_fackets);
+-		if (info->tcpi_reordering != 3)
+-			printf(" reordering:%d", info->tcpi_reordering);
+-		if (info->tcpi_rcv_rtt)
+-			printf(" rcv_rtt:%g", (double) info->tcpi_rcv_rtt/1000);
+-		if (info->tcpi_rcv_space)
+-			printf(" rcv_space:%d", info->tcpi_rcv_space);
++		if (info->tcpi_pacing_rate &&
++				info->tcpi_pacing_rate != ~0ULL) {
++			s.pacing_rate = info->tcpi_pacing_rate * 8.;
+ 
++			if (info->tcpi_max_pacing_rate &&
++					info->tcpi_max_pacing_rate != ~0ULL)
++				s.pacing_rate_max = info->tcpi_max_pacing_rate * 8.;
++		}
++		tcp_stats_print(&s);
++		if (s.dctcp)
++			free(s.dctcp);
+ 	}
+ }
+ 
+-static int inet_show_sock(struct nlmsghdr *nlh, struct filter *f)
++static int inet_show_sock(struct nlmsghdr *nlh, struct filter *f, int protocol)
+ {
+ 	struct rtattr * tb[INET_DIAG_MAX+1];
+ 	struct inet_diag_msg *r = NLMSG_DATA(nlh);
+-	struct tcpstat s;
++	struct sockstat s = {};
+ 
+ 	parse_rtattr(tb, INET_DIAG_MAX, (struct rtattr*)(r+1),
+ 		     nlh->nlmsg_len - NLMSG_LENGTH(sizeof(*r)));
+ 
+-	s.state = r->idiag_state;
+-	s.local.family = s.remote.family = r->idiag_family;
+-	s.lport = ntohs(r->id.idiag_sport);
+-	s.rport = ntohs(r->id.idiag_dport);
++	s.state		= r->idiag_state;
++	s.local.family  = s.remote.family = r->idiag_family;
++	s.lport		= ntohs(r->id.idiag_sport);
++	s.rport		= ntohs(r->id.idiag_dport);
++	s.wq		= r->idiag_wqueue;
++	s.rq		= r->idiag_rqueue;
++	s.ino		= r->idiag_inode;
++	s.uid		= r->idiag_uid;
++	s.iface		= r->id.idiag_if;
++	s.sk		= cookie_sk_get(&r->id.idiag_cookie[0]);
++
+ 	if (s.local.family == AF_INET) {
+ 		s.local.bytelen = s.remote.bytelen = 4;
+ 	} else {
+ 		s.local.bytelen = s.remote.bytelen = 16;
+ 	}
++
+ 	memcpy(s.local.data, r->id.idiag_src, s.local.bytelen);
+ 	memcpy(s.remote.data, r->id.idiag_dst, s.local.bytelen);
+ 
+ 	if (f && f->f && run_ssfilter(f->f, &s) == 0)
+ 		return 0;
+ 
+-	if (netid_width)
+-		printf("%-*s ", netid_width, "tcp");
+-	if (state_width)
+-		printf("%-*s ", state_width, sstate_name[s.state]);
+-
+-	printf("%-6d %-6d ", r->idiag_rqueue, r->idiag_wqueue);
+-
+-	formatted_print(&s.local, s.lport);
+-	formatted_print(&s.remote, s.rport);
++	inet_stats_print(&s, protocol);
+ 
+ 	if (show_options) {
+-		if (r->idiag_timer) {
+-			if (r->idiag_timer > 4)
+-				r->idiag_timer = 5;
+-			printf(" timer:(%s,%s,%d)",
+-			       tmr_name[r->idiag_timer],
+-			       print_ms_timer(r->idiag_expires),
+-			       r->idiag_retrans);
+-		}
+-	}
+-	if (show_users) {
+-		char ubuf[4096];
+-		if (find_users(r->idiag_inode, ubuf, sizeof(ubuf)) > 0)
+-			printf(" users:(%s)", ubuf);
++		struct tcpstat t = {};
++
++		t.timer = r->idiag_timer;
++		t.timeout = r->idiag_expires;
++		t.retrans = r->idiag_retrans;
++		tcp_timer_print(&t);
+ 	}
++
+ 	if (show_details) {
+-		if (r->idiag_uid)
+-			printf(" uid:%u", (unsigned)r->idiag_uid);
+-		printf(" ino:%u", r->idiag_inode);
+-		printf(" sk:");
+-		if (r->id.idiag_cookie[1] != 0)
+-			printf("%08x", r->id.idiag_cookie[1]);
+- 		printf("%08x", r->id.idiag_cookie[0]);
++		sock_details_print(&s);
+ 		if (tb[INET_DIAG_SHUTDOWN]) {
+ 			unsigned char mask;
+ 			mask = *(__u8 *)RTA_DATA(tb[INET_DIAG_SHUTDOWN]);
+ 			printf(" %c-%c", mask & 1 ? '-' : '<', mask & 2 ? '-' : '>');
+ 		}
+ 	}
++
+ 	if (show_mem || show_tcpinfo) {
+ 		printf("\n\t");
+ 		tcp_show_info(nlh, r, tb);
+ 	}
+ 
+ 	printf("\n");
+-
+ 	return 0;
+ }
+ 
+@@ -1555,7 +2065,7 @@ static int tcpdiag_send(int fd, int protocol, struct filter *f)
+ 		req.nlh.nlmsg_type = DCCPDIAG_GETSOCK;
+ 	req.nlh.nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST;
+ 	req.nlh.nlmsg_pid = 0;
+-	req.nlh.nlmsg_seq = 123456;
++	req.nlh.nlmsg_seq = MAGIC_SEQ;
+ 	memset(&req.r, 0, sizeof(req.r));
+ 	req.r.idiag_family = AF_INET;
+ 	req.r.idiag_states = f->states;
+@@ -1601,10 +2111,7 @@ static int tcpdiag_send(int fd, int protocol, struct filter *f)
+ static int sockdiag_send(int family, int fd, int protocol, struct filter *f)
+ {
+ 	struct sockaddr_nl nladdr;
+-	struct {
+-		struct nlmsghdr nlh;
+-		struct inet_diag_req_v2 r;
+-	} req;
++	DIAG_REQUEST(req, struct inet_diag_req_v2 r);
+ 	char    *bc = NULL;
+ 	int	bclen;
+ 	struct msghdr msg;
+@@ -1617,11 +2124,6 @@ static int sockdiag_send(int family, int fd, int protocol, struct filter *f)
+ 	memset(&nladdr, 0, sizeof(nladdr));
+ 	nladdr.nl_family = AF_NETLINK;
+ 
+-	req.nlh.nlmsg_len = sizeof(req);
+-	req.nlh.nlmsg_type = SOCK_DIAG_BY_FAMILY;
+-	req.nlh.nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST;
+-	req.nlh.nlmsg_pid = 0;
+-	req.nlh.nlmsg_seq = 123456;
+ 	memset(&req.r, 0, sizeof(req.r));
+ 	req.r.sdiag_family = family;
+ 	req.r.sdiag_protocol = protocol;
+@@ -1665,128 +2167,63 @@ static int sockdiag_send(int family, int fd, int protocol, struct filter *f)
+ 	return 0;
+ }
+ 
+-static int inet_show_netlink(struct filter *f, FILE *dump_fp, int protocol)
+-{
+-	int fd, family;
+-	struct sockaddr_nl nladdr;
+-	struct msghdr msg;
+-	char	buf[8192];
+-	struct iovec iov[3];
+-
+-	if ((fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_INET_DIAG)) < 0)
+-		return -1;
+-
+-	family = PF_INET;
+-again:
+-	if (sockdiag_send(family, fd, protocol, f))
+-		return -1;
+-
+-	memset(&nladdr, 0, sizeof(nladdr));
+-	nladdr.nl_family = AF_NETLINK;
+-
+-	iov[0] = (struct iovec){
+-		.iov_base = buf,
+-		.iov_len = sizeof(buf)
+-	};
+-
+-	while (1) {
+-		int status;
+-		struct nlmsghdr *h;
+-
+-		msg = (struct msghdr) {
+-			(void*)&nladdr, sizeof(nladdr),
+-			iov,	1,
+-			NULL,	0,
+-			0
+-		};
+-
+-		status = recvmsg(fd, &msg, 0);
+-
+-		if (status < 0) {
+-			if (errno == EINTR)
+-				continue;
+-			perror("OVERRUN");
+-			continue;
+-		}
+-		if (status == 0) {
+-			fprintf(stderr, "EOF on netlink\n");
+-			close(fd);
+-			return 0;
+-		}
+-
+-		if (dump_fp)
+-			fwrite(buf, 1, NLMSG_ALIGN(status), dump_fp);
++struct inet_diag_arg {
++	struct filter *f;
++	int protocol;
++};
+ 
+-		h = (struct nlmsghdr*)buf;
+-		while (NLMSG_OK(h, status)) {
+-			int err;
+-			struct inet_diag_msg *r = NLMSG_DATA(h);
++static int show_one_inet_sock(const struct sockaddr_nl *addr,
++		struct nlmsghdr *h, void *arg)
++{
++	int err;
++	struct inet_diag_arg *diag_arg = arg;
++	struct inet_diag_msg *r = NLMSG_DATA(h);
+ 
+-			if (/*h->nlmsg_pid != rth->local.nl_pid ||*/
+-			    h->nlmsg_seq != 123456)
+-				goto skip_it;
++	if (!(diag_arg->f->families & (1 << r->idiag_family)))
++		return 0;
++	if ((err = inet_show_sock(h, NULL, diag_arg->protocol)) < 0)
++		return err;
+ 
+-			if (h->nlmsg_type == NLMSG_DONE)
+-				goto done;
++	return 0;
++}
+ 
+-			if (h->nlmsg_type == NLMSG_ERROR) {
+-				struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h);
+-				if (h->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr))) {
+-					fprintf(stderr, "ERROR truncated\n");
+-				} else {
+-					if (family != PF_UNSPEC) {
+-						family = PF_UNSPEC;
+-						goto again;
+-					}
++static int inet_show_netlink(struct filter *f, FILE *dump_fp, int protocol)
++{
++	int err = 0;
++	struct rtnl_handle rth;
++	int family = PF_INET;
++	struct inet_diag_arg arg = { .f = f, .protocol = protocol };
+ 
+-					errno = -err->error;
+-					if (errno == EOPNOTSUPP) {
+-						close(fd);
+-						return -1;
+-					}
+-					perror("TCPDIAG answers");
+-				}
++	if (rtnl_open_byproto(&rth, 0, NETLINK_SOCK_DIAG))
++		return -1;
++	rth.dump = MAGIC_SEQ;
++	rth.dump_fp = dump_fp;
+ 
+-				goto done;
+-			}
+-			if (!dump_fp) {
+-				if (!(f->families & (1<<r->idiag_family))) {
+-					h = NLMSG_NEXT(h, status);
+-					continue;
+-				}
+-				err = inet_show_sock(h, NULL);
+-				if (err < 0) {
+-					close(fd);
+-					return err;
+-				}
+-			}
++again:
++	if ((err = sockdiag_send(family, rth.fd, protocol, f)))
++		goto Exit;
+ 
+-skip_it:
+-			h = NLMSG_NEXT(h, status);
+-		}
+-		if (msg.msg_flags & MSG_TRUNC) {
+-			fprintf(stderr, "Message truncated\n");
+-			continue;
+-		}
+-		if (status) {
+-			fprintf(stderr, "!!!Remnant of size %d\n", status);
+-			exit(1);
++	if ((err = rtnl_dump_filter(&rth, show_one_inet_sock, &arg))) {
++		if (family != PF_UNSPEC) {
++			family = PF_UNSPEC;
++			goto again;
+ 		}
++		goto Exit;
+ 	}
+-done:
+ 	if (family == PF_INET) {
+ 		family = PF_INET6;
+ 		goto again;
+ 	}
+ 
+-	close(fd);
+-	return 0;
++Exit:
++	rtnl_close(&rth);
++	return err;
+ }
+ 
+ static int tcp_show_netlink_file(struct filter *f)
+ {
+ 	FILE	*fp;
+-	char	buf[8192];
++	char	buf[16384];
+ 
+ 	if ((fp = fopen(getenv("TCPDIAG_FILE"), "r")) == NULL) {
+ 		perror("fopen($TCPDIAG_FILE)");
+@@ -1833,7 +2270,7 @@ static int tcp_show_netlink_file(struct filter *f)
+ 			return -1;
+ 		}
+ 
+-		err = inet_show_sock(h, f);
++		err = inet_show_sock(h, f, IPPROTO_TCP);
+ 		if (err < 0)
+ 			return err;
+ 	}
+@@ -1845,6 +2282,9 @@ static int tcp_show(struct filter *f, int socktype)
+ 	char *buf = NULL;
+ 	int bufsize = 64*1024;
+ 
++	if (!filter_af_get(f, AF_INET) && !filter_af_get(f, AF_INET6))
++		return 0;
++
+ 	dg_proto = TCP_PROTO;
+ 
+ 	if (getenv("TCPDIAG_FILE"))
+@@ -1864,6 +2304,8 @@ static int tcp_show(struct filter *f, int socktype)
+ 	 * it is able to give us some memory for snapshot.
+ 	 */
+ 	if (1) {
++		get_slabstat(&slabstat);
++
+ 		int guess = slabstat.socks+slabstat.tcp_syns;
+ 		if (f->states&(1<<SS_TIME_WAIT))
+ 			guess += slabstat.tcp_tws;
+@@ -1919,53 +2361,19 @@ outerr:
+ 
+ static int dgram_show_line(char *line, const struct filter *f, int family)
+ {
+-	struct tcpstat s;
++	struct sockstat s = {};
+ 	char *loc, *rem, *data;
+ 	char opt[256];
+ 	int n;
+-	char *p;
+ 
+-	if ((p = strchr(line, ':')) == NULL)
++	if (proc_inet_split_line(line, &loc, &rem, &data))
+ 		return -1;
+-	loc = p+2;
+-
+-	if ((p = strchr(loc, ':')) == NULL)
+-		return -1;
+-	p[5] = 0;
+-	rem = p+6;
+ 
+-	if ((p = strchr(rem, ':')) == NULL)
+-		return -1;
+-	p[5] = 0;
+-	data = p+6;
+-
+-	do {
+-		int state = (data[1] >= 'A') ? (data[1] - 'A' + 10) : (data[1] - '0');
+-
+-		if (!(f->states & (1<<state)))
+-			return 0;
+-	} while (0);
++	int state = (data[1] >= 'A') ? (data[1] - 'A' + 10) : (data[1] - '0');
++	if (!(f->states & (1 << state)))
++		return 0;
+ 
+-	s.local.family = s.remote.family = family;
+-	if (family == AF_INET) {
+-		sscanf(loc, "%x:%x", s.local.data, (unsigned*)&s.lport);
+-		sscanf(rem, "%x:%x", s.remote.data, (unsigned*)&s.rport);
+-		s.local.bytelen = s.remote.bytelen = 4;
+-	} else {
+-		sscanf(loc, "%08x%08x%08x%08x:%x",
+-		       s.local.data,
+-		       s.local.data+1,
+-		       s.local.data+2,
+-		       s.local.data+3,
+-		       &s.lport);
+-		sscanf(rem, "%08x%08x%08x%08x:%x",
+-		       s.remote.data,
+-		       s.remote.data+1,
+-		       s.remote.data+2,
+-		       s.remote.data+3,
+-		       &s.rport);
+-		s.local.bytelen = s.remote.bytelen = 16;
+-	}
++	proc_parse_inet_addr(loc, rem, family, &s);
+ 
+ 	if (f->f && run_ssfilter(f->f, &s) == 0)
+ 		return 0;
+@@ -1979,46 +2387,28 @@ static int dgram_show_line(char *line, const struct filter *f, int family)
+ 	if (n < 9)
+ 		opt[0] = 0;
+ 
+-	if (netid_width)
+-		printf("%-*s ", netid_width, dg_proto);
+-	if (state_width)
+-		printf("%-*s ", state_width, sstate_name[s.state]);
++	inet_stats_print(&s, IPPROTO_UDP);
+ 
+-	printf("%-6d %-6d ", s.rq, s.wq);
++	if (show_details && opt[0])
++		printf(" opt:\"%s\"", opt);
+ 
+-	formatted_print(&s.local, s.lport);
+-	formatted_print(&s.remote, s.rport);
+-
+-	if (show_users) {
+-		char ubuf[4096];
+-		if (find_users(s.ino, ubuf, sizeof(ubuf)) > 0)
+-			printf(" users:(%s)", ubuf);
+-	}
+-
+-	if (show_details) {
+-		if (s.uid)
+-			printf(" uid=%u", (unsigned)s.uid);
+-		printf(" ino=%u", s.ino);
+-		printf(" sk=%llx", s.sk);
+-		if (opt[0])
+-			printf(" opt:\"%s\"", opt);
+-	}
+ 	printf("\n");
+-
+ 	return 0;
+ }
+ 
+-
+ static int udp_show(struct filter *f)
+ {
+ 	FILE *fp = NULL;
+ 
+-	if (!getenv("PROC_NET_UDP") && !getenv("PROC_ROOT")
+-	    && inet_show_netlink(f, NULL, IPPROTO_UDP) == 0)
++	if (!filter_af_get(f, AF_INET) && !filter_af_get(f, AF_INET6))
+ 		return 0;
+ 
+ 	dg_proto = UDP_PROTO;
+ 
++	if (!getenv("PROC_NET_UDP") && !getenv("PROC_ROOT")
++	    && inet_show_netlink(f, NULL, IPPROTO_UDP) == 0)
++		return 0;
++
+ 	if (f->families&(1<<AF_INET)) {
+ 		if ((fp = net_udp_open()) == NULL)
+ 			goto outerr;
+@@ -2049,6 +2439,9 @@ static int raw_show(struct filter *f)
+ {
+ 	FILE *fp = NULL;
+ 
++	if (!filter_af_get(f, AF_INET) && !filter_af_get(f, AF_INET6))
++		return 0;
++
+ 	dg_proto = RAW_PROTO;
+ 
+ 	if (f->families&(1<<AF_INET)) {
+@@ -2077,156 +2470,174 @@ outerr:
+ 	} while (0);
+ }
+ 
+-
+-struct unixstat
+-{
+-	struct unixstat *next;
+-	int ino;
+-	int peer;
+-	int rq;
+-	int wq;
+-	int state;
+-	int type;
+-	char *name;
+-};
+-
+-
+-
+ int unix_state_map[] = { SS_CLOSE, SS_SYN_SENT,
+ 			 SS_ESTABLISHED, SS_CLOSING };
+ 
++#define MAX_UNIX_REMEMBER (1024*1024/sizeof(struct sockstat))
+ 
+-#define MAX_UNIX_REMEMBER (1024*1024/sizeof(struct unixstat))
+-
+-static void unix_list_free(struct unixstat *list)
++static void unix_list_free(struct sockstat *list)
+ {
+ 	while (list) {
+-		struct unixstat *s = list;
++		struct sockstat *s = list;
++		char *name = sock_addr_get_str(&s->local);
++
+ 		list = list->next;
+-		if (s->name)
+-			free(s->name);
++
++		if (name)
++			free(name);
+ 		free(s);
+ 	}
+ }
+ 
+-static void unix_list_print(struct unixstat *list, struct filter *f)
++static const char *unix_netid_name(int type)
+ {
+-	struct unixstat *s;
+-	char *peer;
++	const char *netid;
++
++	switch (type) {
++	case SOCK_STREAM:
++		netid = "u_str";
++		break;
++	case SOCK_SEQPACKET:
++		netid = "u_seq";
++		break;
++	case SOCK_DGRAM:
++	default:
++		netid = "u_dgr";
++		break;
++	}
++	return netid;
++}
++
++static bool unix_type_skip(struct sockstat *s, struct filter *f)
++{
++	if (s->type == SOCK_STREAM && !(f->dbs&(1<<UNIX_ST_DB)))
++		return true;
++	if (s->type == SOCK_DGRAM && !(f->dbs&(1<<UNIX_DG_DB)))
++		return true;
++	if (s->type == SOCK_SEQPACKET && !(f->dbs&(1<<UNIX_SQ_DB)))
++		return true;
++	return false;
++}
++
++static bool unix_use_proc(void)
++{
++	return getenv("PROC_NET_UNIX") || getenv("PROC_ROOT");
++}
++
++static void unix_stats_print(struct sockstat *list, struct filter *f)
++{
++	struct sockstat *s;
++	char *local, *peer;
++	char *ctx_buf = NULL;
++	bool use_proc = unix_use_proc();
++	char port_name[30] = {};
+ 
+ 	for (s = list; s; s = s->next) {
+-		if (!(f->states & (1<<s->state)))
+-			continue;
+-		if (s->type == SOCK_STREAM && !(f->dbs&(1<<UNIX_ST_DB)))
++		if (!(f->states & (1 << s->state)))
+ 			continue;
+-		if (s->type == SOCK_DGRAM && !(f->dbs&(1<<UNIX_DG_DB)))
++		if (unix_type_skip(s, f))
+ 			continue;
+ 
+-		peer = "*";
+-		if (s->peer) {
+-			struct unixstat *p;
++		local = sock_addr_get_str(&s->local);
++		peer  = "*";
++
++		if (s->rport && use_proc) {
++			struct sockstat *p;
++
+ 			for (p = list; p; p = p->next) {
+-				if (s->peer == p->ino)
++				if (s->rport == p->lport)
+ 					break;
+ 			}
++
+ 			if (!p) {
+ 				peer = "?";
+ 			} else {
+-				peer = p->name ? : "*";
++				peer = sock_addr_get_str(&p->local);
++				peer = peer ? : "*";
+ 			}
+ 		}
+ 
+-		if (f->f) {
+-			struct tcpstat tst;
+-			tst.local.family = AF_UNIX;
+-			tst.remote.family = AF_UNIX;
+-			memcpy(tst.local.data, &s->name, sizeof(s->name));
++		if (use_proc && f->f) {
+ 			if (strcmp(peer, "*") == 0)
+-				memset(tst.remote.data, 0, sizeof(peer));
++				memset(s->remote.data, 0, sizeof(char *));
+ 			else
+-				memcpy(tst.remote.data, &peer, sizeof(peer));
+-			if (run_ssfilter(f->f, &tst) == 0)
++				sock_addr_set_str(&s->remote, &peer);
++
++			if (run_ssfilter(f->f, s) == 0)
+ 				continue;
+ 		}
+ 
+-		if (netid_width)
+-			printf("%-*s ", netid_width,
+-			       s->type == SOCK_STREAM ? "u_str" : "u_dgr");
+-		if (state_width)
+-			printf("%-*s ", state_width, sstate_name[s->state]);
+-		printf("%-6d %-6d ", s->rq, s->wq);
+-		printf("%*s %-*d %*s %-*d",
+-		       addr_width, s->name ? : "*", serv_width, s->ino,
+-		       addr_width, peer, serv_width, s->peer);
+-		if (show_users) {
+-			char ubuf[4096];
+-			if (find_users(s->ino, ubuf, sizeof(ubuf)) > 0)
+-				printf(" users:(%s)", ubuf);
++		sock_state_print(s, unix_netid_name(s->type));
++
++		sock_addr_print(local ?: "*", " ",
++				int_to_str(s->lport, port_name), NULL);
++		sock_addr_print(peer, " ", int_to_str(s->rport, port_name),
++				NULL);
++
++		if (show_proc_ctx || show_sock_ctx) {
++			if (find_entry(s->ino, &ctx_buf,
++					(show_proc_ctx & show_sock_ctx) ?
++					PROC_SOCK_CTX : PROC_CTX) > 0) {
++				printf(" users:(%s)", ctx_buf);
++				free(ctx_buf);
++			}
++		} else if (show_users) {
++			if (find_entry(s->ino, &ctx_buf, USERS) > 0) {
++				printf(" users:(%s)", ctx_buf);
++				free(ctx_buf);
++			}
+ 		}
+ 		printf("\n");
+ 	}
+ }
+ 
+-static int unix_show_sock(struct nlmsghdr *nlh, struct filter *f)
++static int unix_show_sock(const struct sockaddr_nl *addr, struct nlmsghdr *nlh,
++		void *arg)
+ {
++	struct filter *f = (struct filter *)arg;
+ 	struct unix_diag_msg *r = NLMSG_DATA(nlh);
+ 	struct rtattr *tb[UNIX_DIAG_MAX+1];
+-	char name[128];
+-	int peer_ino;
+-	__u32 rqlen, wqlen;
++	char *name = NULL;
++	struct sockstat stat = {};
+ 
+ 	parse_rtattr(tb, UNIX_DIAG_MAX, (struct rtattr*)(r+1),
+ 		     nlh->nlmsg_len - NLMSG_LENGTH(sizeof(*r)));
+ 
+-	if (netid_width)
+-		printf("%-*s ", netid_width,
+-				r->udiag_type == SOCK_STREAM ? "u_str" : "u_dgr");
+-	if (state_width)
+-		printf("%-*s ", state_width, sstate_name[r->udiag_state]);
++	stat.type  = r->udiag_type;
++	stat.state = r->udiag_state;
++	stat.ino   = stat.lport = r->udiag_ino;
++	stat.local.family = stat.remote.family = AF_UNIX;
++
++	if (unix_type_skip(&stat, f))
++		return 0;
+ 
+ 	if (tb[UNIX_DIAG_RQLEN]) {
+ 		struct unix_diag_rqlen *rql = RTA_DATA(tb[UNIX_DIAG_RQLEN]);
+-		rqlen = rql->udiag_rqueue;
+-		wqlen = rql->udiag_wqueue;
+-	} else {
+-		rqlen = 0;
+-		wqlen = 0;
++		stat.rq = rql->udiag_rqueue;
++		stat.wq = rql->udiag_wqueue;
+ 	}
+-
+-	printf("%-6u %-6u ", rqlen, wqlen);
+-
+ 	if (tb[UNIX_DIAG_NAME]) {
+ 		int len = RTA_PAYLOAD(tb[UNIX_DIAG_NAME]);
+ 
++		name = malloc(len + 1);
+ 		memcpy(name, RTA_DATA(tb[UNIX_DIAG_NAME]), len);
+ 		name[len] = '\0';
+ 		if (name[0] == '\0')
+ 			name[0] = '@';
+-	} else
+-		sprintf(name, "*");
+-
++		sock_addr_set_str(&stat.local, &name);
++	}
+ 	if (tb[UNIX_DIAG_PEER])
+-		peer_ino = rta_getattr_u32(tb[UNIX_DIAG_PEER]);
+-	else
+-		peer_ino = 0;
++		stat.rport = rta_getattr_u32(tb[UNIX_DIAG_PEER]);
+ 
+-	printf("%*s %-*d %*s %-*d",
+-			addr_width, name,
+-			serv_width, r->udiag_ino,
+-			addr_width, "*", /* FIXME */
+-			serv_width, peer_ino);
++	if (f->f && run_ssfilter(f->f, &stat) == 0)
++		return 0;
+ 
+-	if (show_users) {
+-		char ubuf[4096];
+-		if (find_users(r->udiag_ino, ubuf, sizeof(ubuf)) > 0)
+-			printf(" users:(%s)", ubuf);
+-	}
++	unix_stats_print(&stat, f);
+ 
+ 	if (show_mem) {
+-		printf("\n\t");
++		printf("\t");
+ 		print_skmeminfo(tb, UNIX_DIAG_MEMINFO);
+ 	}
+-
+ 	if (show_details) {
+ 		if (tb[UNIX_DIAG_SHUTDOWN]) {
+ 			unsigned char mask;
+@@ -2234,107 +2645,40 @@ static int unix_show_sock(struct nlmsghdr *nlh, struct filter *f)
+ 			printf(" %c-%c", mask & 1 ? '-' : '<', mask & 2 ? '-' : '>');
+ 		}
+ 	}
++	if (show_mem || show_details)
++		printf("\n");
+ 
+-	printf("\n");
+-
++	if (name)
++		free(name);
+ 	return 0;
+ }
+ 
+-static int handle_netlink_request(struct filter *f, FILE *dump_fp,
+-				  struct nlmsghdr *req, size_t size,
+-				  int (* show_one_sock)(struct nlmsghdr *nlh, struct filter *f))
++static int handle_netlink_request(struct filter *f, struct nlmsghdr *req,
++		size_t size, rtnl_filter_t show_one_sock)
+ {
+-	int fd;
+-	char	buf[8192];
++	int ret = -1;
++	struct rtnl_handle rth;
+ 
+-	if ((fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_INET_DIAG)) < 0)
++	if (rtnl_open_byproto(&rth, 0, NETLINK_SOCK_DIAG))
+ 		return -1;
+ 
+-	if (send(fd, req, size, 0) < 0) {
+-		close(fd);
+-		return -1;
+-	}
+-
+-	while (1) {
+-		ssize_t status;
+-		struct nlmsghdr *h;
+-		struct sockaddr_nl nladdr;
+-		socklen_t slen = sizeof(nladdr);
+-
+-		status = recvfrom(fd, buf, sizeof(buf), 0,
+-				  (struct sockaddr *) &nladdr, &slen);
+-		if (status < 0) {
+-			if (errno == EINTR)
+-				continue;
+-			perror("OVERRUN");
+-			continue;
+-		}
+-		if (status == 0) {
+-			fprintf(stderr, "EOF on netlink\n");
+-			goto close_it;
+-		}
+-
+-		if (dump_fp)
+-			fwrite(buf, 1, NLMSG_ALIGN(status), dump_fp);
+-
+-		h = (struct nlmsghdr*)buf;
+-		while (NLMSG_OK(h, status)) {
+-			int err;
+-
+-			if (/*h->nlmsg_pid != rth->local.nl_pid ||*/
+-			    h->nlmsg_seq != 123456)
+-				goto skip_it;
+-
+-			if (h->nlmsg_type == NLMSG_DONE)
+-				goto close_it;
++	rth.dump = MAGIC_SEQ;
+ 
+-			if (h->nlmsg_type == NLMSG_ERROR) {
+-				struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h);
+-				if (h->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr))) {
+-					fprintf(stderr, "ERROR truncated\n");
+-				} else {
+-					errno = -err->error;
+-					if (errno != ENOENT)
+-						fprintf(stderr, "DIAG answers %d\n", errno);
+-				}
+-				close(fd);
+-				return -1;
+-			}
+-			if (!dump_fp) {
+-				err = show_one_sock(h, f);
+-				if (err < 0) {
+-					close(fd);
+-					return err;
+-				}
+-			}
++	if (rtnl_send(&rth, req, size) < 0)
++		goto Exit;
+ 
+-skip_it:
+-			h = NLMSG_NEXT(h, status);
+-		}
++	if (rtnl_dump_filter(&rth, show_one_sock, f))
++		goto Exit;
+ 
+-		if (status) {
+-			fprintf(stderr, "!!!Remnant of size %zd\n", status);
+-			exit(1);
+-		}
+-	}
+-
+-close_it:
+-	close(fd);
+-	return 0;
++	ret = 0;
++Exit:
++	rtnl_close(&rth);
++	return ret;
+ }
+ 
+-static int unix_show_netlink(struct filter *f, FILE *dump_fp)
++static int unix_show_netlink(struct filter *f)
+ {
+-	struct {
+-		struct nlmsghdr nlh;
+-		struct unix_diag_req r;
+-	} req;
+-
+-	memset(&req, 0, sizeof(req));
+-	req.nlh.nlmsg_len = sizeof(req);
+-	req.nlh.nlmsg_type = SOCK_DIAG_BY_FAMILY;
+-	req.nlh.nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST;
+-	req.nlh.nlmsg_seq = 123456;
++	DIAG_REQUEST(req, struct unix_diag_req r);
+ 
+ 	req.r.sdiag_family = AF_UNIX;
+ 	req.r.udiag_states = f->states;
+@@ -2342,8 +2686,7 @@ static int unix_show_netlink(struct filter *f, FILE *dump_fp)
+ 	if (show_mem)
+ 		req.r.udiag_show |= UDIAG_SHOW_MEMINFO;
+ 
+-	return handle_netlink_request(f, dump_fp, &req.nlh,
+-					sizeof(req), unix_show_sock);
++	return handle_netlink_request(f, &req.nlh, sizeof(req), unix_show_sock);
+ }
+ 
+ static int unix_show(struct filter *f)
+@@ -2353,10 +2696,12 @@ static int unix_show(struct filter *f)
+ 	char name[128];
+ 	int  newformat = 0;
+ 	int  cnt;
+-	struct unixstat *list = NULL;
++	struct sockstat *list = NULL;
+ 
+-	if (!getenv("PROC_NET_UNIX") && !getenv("PROC_ROOT")
+-	    && unix_show_netlink(f, NULL) == 0)
++	if (!filter_af_get(f, AF_UNIX))
++		return 0;
++
++	if (!unix_use_proc() && unix_show_netlink(f) == 0)
+ 		return 0;
+ 
+ 	if ((fp = net_unix_open()) == NULL)
+@@ -2368,30 +2713,30 @@ static int unix_show(struct filter *f)
+ 	cnt = 0;
+ 
+ 	while (fgets(buf, sizeof(buf)-1, fp)) {
+-		struct unixstat *u, **insp;
++		struct sockstat *u, **insp;
+ 		int flags;
+ 
+ 		if (!(u = malloc(sizeof(*u))))
+ 			break;
+-		u->name = NULL;
+ 
+ 		if (sscanf(buf, "%x: %x %x %x %x %x %d %s",
+-			   &u->peer, &u->rq, &u->wq, &flags, &u->type,
++			   &u->rport, &u->rq, &u->wq, &flags, &u->type,
+ 			   &u->state, &u->ino, name) < 8)
+ 			name[0] = 0;
+ 
+-		if (flags&(1<<16)) {
++		u->lport = u->ino;
++		u->local.family = u->remote.family = AF_UNIX;
++
++		if (flags & (1 << 16)) {
+ 			u->state = SS_LISTEN;
+ 		} else {
+ 			u->state = unix_state_map[u->state-1];
+-			if (u->type == SOCK_DGRAM &&
+-			    u->state == SS_CLOSE &&
+-			    u->peer)
++			if (u->type == SOCK_DGRAM && u->state == SS_CLOSE && u->rport)
+ 				u->state = SS_ESTABLISHED;
+ 		}
+ 
+ 		if (!newformat) {
+-			u->peer = 0;
++			u->rport = 0;
+ 			u->rq = 0;
+ 			u->wq = 0;
+ 		}
+@@ -2408,12 +2753,11 @@ static int unix_show(struct filter *f)
+ 		*insp = u;
+ 
+ 		if (name[0]) {
+-			if ((u->name = malloc(strlen(name)+1)) == NULL)
+-				break;
+-			strcpy(u->name, name);
++			char *tmp = strdup(name);
++			sock_addr_set_str(&u->local, &tmp);
+ 		}
+ 		if (++cnt > MAX_UNIX_REMEMBER) {
+-			unix_list_print(list, f);
++			unix_stats_print(list, f);
+ 			unix_list_free(list);
+ 			list = NULL;
+ 			cnt = 0;
+@@ -2421,7 +2765,7 @@ static int unix_show(struct filter *f)
+ 	}
+ 	fclose(fp);
+ 	if (list) {
+-		unix_list_print(list, f);
++		unix_stats_print(list, f);
+ 		unix_list_free(list);
+ 		list = NULL;
+ 		cnt = 0;
+@@ -2430,11 +2774,62 @@ static int unix_show(struct filter *f)
+ 	return 0;
+ }
+ 
+-static int packet_show_sock(struct nlmsghdr *nlh, struct filter *f)
++static int packet_stats_print(struct sockstat *s, const struct filter *f)
+ {
++	char *buf = NULL;
++	const char *addr, *port;
++	char ll_name[16];
++
++	if (f->f) {
++		s->local.family = AF_PACKET;
++		s->remote.family = AF_PACKET;
++		s->local.data[0] = s->prot;
++		if (run_ssfilter(f->f, s) == 0)
++			return 1;
++	}
++
++	sock_state_print(s, s->type == SOCK_RAW ? "p_raw" : "p_dgr");
++
++	if (s->prot == 3)
++		addr = "*";
++	else
++		addr = ll_proto_n2a(htons(s->prot), ll_name, sizeof(ll_name));
++
++	if (s->iface == 0)
++		port = "*";
++	else
++		port = xll_index_to_name(s->iface);
++
++	sock_addr_print(addr, ":", port, NULL);
++	sock_addr_print("", "*", "", NULL);
++
++	if (show_proc_ctx || show_sock_ctx) {
++		if (find_entry(s->ino, &buf,
++					(show_proc_ctx & show_sock_ctx) ?
++					PROC_SOCK_CTX : PROC_CTX) > 0) {
++			printf(" users:(%s)", buf);
++			free(buf);
++		}
++	} else if (show_users) {
++		if (find_entry(s->ino, &buf, USERS) > 0) {
++			printf(" users:(%s)", buf);
++			free(buf);
++		}
++	}
++
++	if (show_details)
++		sock_details_print(s);
++
++	return 0;
++}
++
++static int packet_show_sock(const struct sockaddr_nl *addr,
++		struct nlmsghdr *nlh, void *arg)
++{
++	const struct filter *f = arg;
+ 	struct packet_diag_msg *r = NLMSG_DATA(nlh);
+ 	struct rtattr *tb[PACKET_DIAG_MAX+1];
+-	__u32 rq;
++	struct sockstat stat = {};
+ 
+ 	parse_rtattr(tb, PACKET_DIAG_MAX, (struct rtattr*)(r+1),
+ 		     nlh->nlmsg_len - NLMSG_LENGTH(sizeof(*r)));
+@@ -2443,56 +2838,27 @@ static int packet_show_sock(struct nlmsghdr *nlh, struct filter *f)
+ 	if (!tb[PACKET_DIAG_MEMINFO])
+ 		return -1;
+ 
+-	if (netid_width)
+-		printf("%-*s ", netid_width,
+-				r->pdiag_type == SOCK_RAW ? "p_raw" : "p_dgr");
+-	if (state_width)
+-		printf("%-*s ", state_width, "UNCONN");
++	stat.type   = r->pdiag_type;
++	stat.prot   = r->pdiag_num;
++	stat.ino    = r->pdiag_ino;
++	stat.state  = SS_CLOSE;
++	stat.sk	    = cookie_sk_get(&r->pdiag_cookie[0]);
+ 
+ 	if (tb[PACKET_DIAG_MEMINFO]) {
+ 		__u32 *skmeminfo = RTA_DATA(tb[PACKET_DIAG_MEMINFO]);
+-
+-		rq = skmeminfo[SK_MEMINFO_RMEM_ALLOC];
+-	} else
+-		rq = 0;
+-	printf("%-6d %-6d ", rq, 0);
+-
+-	if (r->pdiag_num == 3) {
+-		printf("%*s:", addr_width, "*");
+-	} else {
+-		char tb2[16];
+-		printf("%*s:", addr_width,
+-		       ll_proto_n2a(htons(r->pdiag_num), tb2, sizeof(tb2)));
++		stat.rq = skmeminfo[SK_MEMINFO_RMEM_ALLOC];
+ 	}
++
+ 	if (tb[PACKET_DIAG_INFO]) {
+ 		struct packet_diag_info *pinfo = RTA_DATA(tb[PACKET_DIAG_INFO]);
+-
+-		if (pinfo->pdi_index == 0)
+-			printf("%-*s ", serv_width, "*");
+-		else
+-			printf("%-*s ", serv_width, xll_index_to_name(pinfo->pdi_index));
+-	} else
+-		printf("%-*s ", serv_width, "*");
+-
+-	printf("%*s*%-*s",
+-	       addr_width, "", serv_width, "");
+-
+-	if (show_users) {
+-		char ubuf[4096];
+-		if (find_users(r->pdiag_ino, ubuf, sizeof(ubuf)) > 0)
+-			printf(" users:(%s)", ubuf);
++		stat.lport = stat.iface = pinfo->pdi_index;
+ 	}
+-	if (show_details) {
+-		__u32 uid = 0;
+ 
+-		if (tb[PACKET_DIAG_UID])
+-			uid = *(__u32 *)RTA_DATA(tb[PACKET_DIAG_UID]);
++	if (tb[PACKET_DIAG_UID])
++		stat.uid = *(__u32 *)RTA_DATA(tb[PACKET_DIAG_UID]);
+ 
+-		printf(" ino=%u uid=%u sk=", r->pdiag_ino, uid);
+-		if (r->pdiag_cookie[1] != 0)
+-			printf("%08x", r->pdiag_cookie[1]);
+-		printf("%08x", r->pdiag_cookie[0]);
+-	}
++	if (packet_stats_print(&stat, f))
++		return 0;
+ 
+ 	if (show_bpf && tb[PACKET_DIAG_FILTER]) {
+ 		struct sock_filter *fil =
+@@ -2512,244 +2878,154 @@ static int packet_show_sock(struct nlmsghdr *nlh, struct filter *f)
+ 	return 0;
+ }
+ 
+-static int packet_show_netlink(struct filter *f, FILE *dump_fp)
++static int packet_show_netlink(struct filter *f)
+ {
+-	int fd;
+-	struct {
+-		struct nlmsghdr nlh;
+-		struct packet_diag_req r;
+-	} req;
+-	char	buf[8192];
+-
+-	if ((fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_INET_DIAG)) < 0)
+-		return -1;
+-
+-	memset(&req, 0, sizeof(req));
+-	req.nlh.nlmsg_len = sizeof(req);
+-	req.nlh.nlmsg_type = SOCK_DIAG_BY_FAMILY;
+-	req.nlh.nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST;
+-	req.nlh.nlmsg_seq = 123456;
++	DIAG_REQUEST(req, struct packet_diag_req r);
+ 
+ 	req.r.sdiag_family = AF_PACKET;
+ 	req.r.pdiag_show = PACKET_SHOW_INFO | PACKET_SHOW_MEMINFO | PACKET_SHOW_FILTER;
+ 
+-	if (send(fd, &req, sizeof(req), 0) < 0) {
+-		close(fd);
+-		return -1;
+-	}
+-
+-	while (1) {
+-		ssize_t status;
+-		struct nlmsghdr *h;
+-		struct sockaddr_nl nladdr;
+-		socklen_t slen = sizeof(nladdr);
+-
+-		status = recvfrom(fd, buf, sizeof(buf), 0,
+-				  (struct sockaddr *) &nladdr, &slen);
+-		if (status < 0) {
+-			if (errno == EINTR)
+-				continue;
+-			perror("OVERRUN");
+-			continue;
+-		}
+-		if (status == 0) {
+-			fprintf(stderr, "EOF on netlink\n");
+-			goto close_it;
+-		}
+-
+-		if (dump_fp)
+-			fwrite(buf, 1, NLMSG_ALIGN(status), dump_fp);
+-
+-		h = (struct nlmsghdr*)buf;
+-		while (NLMSG_OK(h, status)) {
+-			int err;
++	return handle_netlink_request(f, &req.nlh, sizeof(req), packet_show_sock);
++}
+ 
+-			if (h->nlmsg_seq != 123456)
+-				goto skip_it;
++static int packet_show_line(char *buf, const struct filter *f, int fam)
++{
++	unsigned long long sk;
++	struct sockstat stat = {};
++	int type, prot, iface, state, rq, uid, ino;
+ 
+-			if (h->nlmsg_type == NLMSG_DONE)
+-				goto close_it;
++	sscanf(buf, "%llx %*d %d %x %d %d %u %u %u",
++			&sk,
++			&type, &prot, &iface, &state,
++			&rq, &uid, &ino);
+ 
+-			if (h->nlmsg_type == NLMSG_ERROR) {
+-				struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h);
+-				if (h->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr))) {
+-					fprintf(stderr, "ERROR truncated\n");
+-				} else {
+-					errno = -err->error;
+-					if (errno != ENOENT)
+-						fprintf(stderr, "UDIAG answers %d\n", errno);
+-				}
+-				close(fd);
+-				return -1;
+-			}
+-			if (!dump_fp) {
+-				err = packet_show_sock(h, f);
+-				if (err < 0) {
+-					close(fd);
+-					return err;
+-				}
+-			}
++	if (stat.type == SOCK_RAW && !(f->dbs&(1<<PACKET_R_DB)))
++		return 0;
++	if (stat.type == SOCK_DGRAM && !(f->dbs&(1<<PACKET_DG_DB)))
++		return 0;
+ 
+-skip_it:
+-			h = NLMSG_NEXT(h, status);
+-		}
++	stat.type  = type;
++	stat.prot  = prot;
++	stat.lport = stat.iface = iface;
++	stat.state = state;
++	stat.rq    = rq;
++	stat.uid   = uid;
++	stat.ino   = ino;
++	stat.state = SS_CLOSE;
+ 
+-		if (status) {
+-			fprintf(stderr, "!!!Remnant of size %zd\n", status);
+-			exit(1);
+-		}
+-	}
++	if (packet_stats_print(&stat, f))
++		return 0;
+ 
+-close_it:
+-	close(fd);
++	printf("\n");
+ 	return 0;
+ }
+ 
+-
+ static int packet_show(struct filter *f)
+ {
+ 	FILE *fp;
+-	char buf[256];
+-	int type;
+-	int prot;
+-	int iface;
+-	int state;
+-	int rq;
+-	int uid;
+-	int ino;
+-	unsigned long long sk;
+ 
+-	if (!(f->states & (1<<SS_CLOSE)))
++	if (!filter_af_get(f, AF_PACKET) || !(f->states & (1 << SS_CLOSE)))
+ 		return 0;
+ 
+-	if (packet_show_netlink(f, NULL) == 0)
++	if (!getenv("PROC_NET_PACKET") && !getenv("PROC_ROOT") &&
++			packet_show_netlink(f) == 0)
+ 		return 0;
+ 
+ 	if ((fp = net_packet_open()) == NULL)
+ 		return -1;
+-	fgets(buf, sizeof(buf)-1, fp);
+-
+-	while (fgets(buf, sizeof(buf)-1, fp)) {
+-		sscanf(buf, "%llx %*d %d %x %d %d %u %u %u",
+-		       &sk,
+-		       &type, &prot, &iface, &state,
+-		       &rq, &uid, &ino);
+-
+-		if (type == SOCK_RAW && !(f->dbs&(1<<PACKET_R_DB)))
+-			continue;
+-		if (type == SOCK_DGRAM && !(f->dbs&(1<<PACKET_DG_DB)))
+-			continue;
+-		if (f->f) {
+-			struct tcpstat tst;
+-			tst.local.family = AF_PACKET;
+-			tst.remote.family = AF_PACKET;
+-			tst.rport = 0;
+-			tst.lport = iface;
+-			tst.local.data[0] = prot;
+-			tst.remote.data[0] = 0;
+-			if (run_ssfilter(f->f, &tst) == 0)
+-				continue;
+-		}
+-
+-		if (netid_width)
+-			printf("%-*s ", netid_width,
+-			       type == SOCK_RAW ? "p_raw" : "p_dgr");
+-		if (state_width)
+-			printf("%-*s ", state_width, "UNCONN");
+-		printf("%-6d %-6d ", rq, 0);
+-		if (prot == 3) {
+-			printf("%*s:", addr_width, "*");
+-		} else {
+-			char tb[16];
+-			printf("%*s:", addr_width,
+-			       ll_proto_n2a(htons(prot), tb, sizeof(tb)));
+-		}
+-		if (iface == 0) {
+-			printf("%-*s ", serv_width, "*");
+-		} else {
+-			printf("%-*s ", serv_width, xll_index_to_name(iface));
+-		}
+-		printf("%*s*%-*s",
+-		       addr_width, "", serv_width, "");
+-
+-		if (show_users) {
+-			char ubuf[4096];
+-			if (find_users(ino, ubuf, sizeof(ubuf)) > 0)
+-				printf(" users:(%s)", ubuf);
+-		}
+-		if (show_details) {
+-			printf(" ino=%u uid=%u sk=%llx", ino, uid, sk);
+-		}
+-		printf("\n");
+-	}
++	if (generic_record_read(fp, packet_show_line, f, AF_PACKET))
++		return -1;
+ 
+ 	return 0;
+ }
+ 
+-static void netlink_show_one(struct filter *f,
++static int netlink_show_one(struct filter *f,
+ 				int prot, int pid, unsigned groups,
+ 				int state, int dst_pid, unsigned dst_group,
+ 				int rq, int wq,
+ 				unsigned long long sk, unsigned long long cb)
+ {
++	struct sockstat st;
++	SPRINT_BUF(prot_buf) = {};
++	const char *prot_name;
++	char procname[64] = {};
++
++	st.state = SS_CLOSE;
++	st.rq	 = rq;
++	st.wq	 = wq;
++
+ 	if (f->f) {
+-		struct tcpstat tst;
+-		tst.local.family = AF_NETLINK;
+-		tst.remote.family = AF_NETLINK;
+-		tst.rport = -1;
+-		tst.lport = pid;
+-		tst.local.data[0] = prot;
+-		tst.remote.data[0] = 0;
+-		if (run_ssfilter(f->f, &tst) == 0)
+-			return;
++		st.local.family = AF_NETLINK;
++		st.remote.family = AF_NETLINK;
++		st.rport = -1;
++		st.lport = pid;
++		st.local.data[0] = prot;
++		if (run_ssfilter(f->f, &st) == 0)
++			return 1;
+ 	}
+ 
+-	if (netid_width)
+-		printf("%-*s ", netid_width, "nl");
+-	if (state_width)
+-		printf("%-*s ", state_width, "UNCONN");
+-	printf("%-6d %-6d ", rq, wq);
+-	if (resolve_services && prot == 0)
+-		printf("%*s:", addr_width, "rtnl");
+-	else if (resolve_services && prot == 3)
+-		printf("%*s:", addr_width, "fw");
+-	else if (resolve_services && prot == 4)
+-		printf("%*s:", addr_width, "tcpdiag");
++	sock_state_print(&st, "nl");
++
++	if (resolve_services)
++		prot_name = nl_proto_n2a(prot, prot_buf, sizeof(prot_buf));
+ 	else
+-		printf("%*d:", addr_width, prot);
++		prot_name = int_to_str(prot, prot_buf);
++
+ 	if (pid == -1) {
+-		printf("%-*s ", serv_width, "*");
++		procname[0] = '*';
+ 	} else if (resolve_services) {
+ 		int done = 0;
+ 		if (!pid) {
+ 			done = 1;
+-			printf("%-*s ", serv_width, "kernel");
++			strncpy(procname, "kernel", 6);
+ 		} else if (pid > 0) {
+-			char procname[64];
+ 			FILE *fp;
+ 			sprintf(procname, "%s/%d/stat",
+ 				getenv("PROC_ROOT") ? : "/proc", pid);
+ 			if ((fp = fopen(procname, "r")) != NULL) {
+ 				if (fscanf(fp, "%*d (%[^)])", procname) == 1) {
+ 					sprintf(procname+strlen(procname), "/%d", pid);
+-					printf("%-*s ", serv_width, procname);
+ 					done = 1;
+ 				}
+ 				fclose(fp);
+ 			}
+ 		}
+ 		if (!done)
+-			printf("%-*d ", serv_width, pid);
++			int_to_str(pid, procname);
+ 	} else {
+-		printf("%-*d ", serv_width, pid);
++		int_to_str(pid, procname);
+ 	}
+ 
++	sock_addr_print(prot_name, ":", procname, NULL);
++
+ 	if (state == NETLINK_CONNECTED) {
+-		printf("%*d:%-*d",
+-		       addr_width, dst_group, serv_width, dst_pid);
++		char dst_group_buf[30];
++		char dst_pid_buf[30];
++		sock_addr_print(int_to_str(dst_group, dst_group_buf), ":",
++				int_to_str(dst_pid, dst_pid_buf), NULL);
+ 	} else {
+-		printf("%*s*%-*s",
+-		       addr_width, "", serv_width, "");
++		sock_addr_print("", "*", "", NULL);
++	}
++
++	char *pid_context = NULL;
++	if (show_proc_ctx) {
++		/* The pid value will either be:
++		 *   0 if destination kernel - show kernel initial context.
++		 *   A valid process pid - use getpidcon.
++		 *   A unique value allocated by the kernel or netlink user
++		 *   to the process - show context as "not available".
++		 */
++		if (!pid)
++			security_get_initial_context("kernel", &pid_context);
++		else if (pid > 0)
++			getpidcon(pid, &pid_context);
++
++		if (pid_context != NULL) {
++			printf("proc_ctx=%-*s ", serv_width, pid_context);
++			free(pid_context);
++		} else {
++			printf("proc_ctx=%-*s ", serv_width, "unavailable");
++		}
+ 	}
+ 
+ 	if (show_details) {
+@@ -2757,11 +3033,13 @@ static void netlink_show_one(struct filter *f,
+ 	}
+ 	printf("\n");
+ 
+-	return;
++	return 0;
+ }
+ 
+-static int netlink_show_sock(struct nlmsghdr *nlh, struct filter *f)
++static int netlink_show_sock(const struct sockaddr_nl *addr,
++		struct nlmsghdr *nlh, void *arg)
+ {
++	struct filter *f = (struct filter *)arg;
+ 	struct netlink_diag_msg *r = NLMSG_DATA(nlh);
+ 	struct rtattr *tb[NETLINK_DIAG_MAX+1];
+ 	int rq = 0, wq = 0;
+@@ -2781,9 +3059,11 @@ static int netlink_show_sock(struct nlmsghdr *nlh, struct filter *f)
+ 		wq = skmeminfo[SK_MEMINFO_WMEM_ALLOC];
+ 	}
+ 
+-	netlink_show_one(f, r->ndiag_protocol, r->ndiag_portid, groups,
++	if (netlink_show_one(f, r->ndiag_protocol, r->ndiag_portid, groups,
+ 			 r->ndiag_state, r->ndiag_dst_portid, r->ndiag_dst_group,
+-			 rq, wq, 0, 0);
++			 rq, wq, 0, 0)) {
++		return 0;
++	}
+ 
+ 	if (show_mem) {
+ 		printf("\t");
+@@ -2794,25 +3074,15 @@ static int netlink_show_sock(struct nlmsghdr *nlh, struct filter *f)
+ 	return 0;
+ }
+ 
+-static int netlink_show_netlink(struct filter *f, FILE *dump_fp)
++static int netlink_show_netlink(struct filter *f)
+ {
+-	struct {
+-		struct nlmsghdr nlh;
+-		struct netlink_diag_req r;
+-	} req;
+-
+-	memset(&req, 0, sizeof(req));
+-	req.nlh.nlmsg_len = sizeof(req);
+-	req.nlh.nlmsg_type = SOCK_DIAG_BY_FAMILY;
+-	req.nlh.nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST;
+-	req.nlh.nlmsg_seq = 123456;
++	DIAG_REQUEST(req, struct netlink_diag_req r);
+ 
+ 	req.r.sdiag_family = AF_NETLINK;
+ 	req.r.sdiag_protocol = NDIAG_PROTO_ALL;
+ 	req.r.ndiag_show = NDIAG_SHOW_GROUPS | NDIAG_SHOW_MEMINFO;
+ 
+-	return handle_netlink_request(f, dump_fp, &req.nlh,
+-					sizeof(req), netlink_show_sock);
++	return handle_netlink_request(f, &req.nlh, sizeof(req), netlink_show_sock);
+ }
+ 
+ static int netlink_show(struct filter *f)
+@@ -2824,11 +3094,11 @@ static int netlink_show(struct filter *f)
+ 	int rq, wq, rc;
+ 	unsigned long long sk, cb;
+ 
+-	if (!(f->states & (1<<SS_CLOSE)))
++	if (!filter_af_get(f, AF_NETLINK) || !(f->states & (1 << SS_CLOSE)))
+ 		return 0;
+ 
+ 	if (!getenv("PROC_NET_NETLINK") && !getenv("PROC_ROOT") &&
+-		netlink_show_netlink(f, NULL) == 0)
++		netlink_show_netlink(f) == 0)
+ 		return 0;
+ 
+ 	if ((fp = net_netlink_open()) == NULL)
+@@ -2898,7 +3168,7 @@ static int get_snmp_int(char *proto, char *key, int *result)
+ 
+ /* Get stats from sockstat */
+ 
+-struct sockstat
++struct ssummary
+ {
+ 	int socks;
+ 	int tcp_mem;
+@@ -2917,7 +3187,7 @@ struct sockstat
+ 	int frag6_mem;
+ };
+ 
+-static void get_sockstat_line(char *line, struct sockstat *s)
++static void get_sockstat_line(char *line, struct ssummary *s)
+ {
+ 	char id[256], rem[256];
+ 
+@@ -2946,7 +3216,7 @@ static void get_sockstat_line(char *line, struct sockstat *s)
+ 		       &s->tcp_orphans, &s->tcp_tws, &s->tcp_total, &s->tcp_mem);
+ }
+ 
+-static int get_sockstat(struct sockstat *s)
++static int get_sockstat(struct ssummary *s)
+ {
+ 	char buf[256];
+ 	FILE *fp;
+@@ -2970,7 +3240,7 @@ static int get_sockstat(struct sockstat *s)
+ 
+ static int print_summary(void)
+ {
+-	struct sockstat s;
++	struct ssummary s;
+ 	struct snmpstat sn;
+ 
+ 	if (get_sockstat(&s) < 0)
+@@ -2978,6 +3248,8 @@ static int print_summary(void)
+ 	if (get_snmp_int("Tcp:", "CurrEstab", &sn.tcp_estab) < 0)
+ 		perror("ss: get_snmpstat");
+ 
++	get_slabstat(&slabstat);
++
+ 	printf("Total: %d (kernel %d)\n", s.socks, slabstat.socks);
+ 
+ 	printf("TCP:   %d (estab %d, closed %d, orphaned %d, synrecv %d, timewait %d/%d), ports %d\n",
+@@ -3013,36 +3285,45 @@ static void _usage(FILE *dest)
+ 	fprintf(dest,
+ "Usage: ss [ OPTIONS ]\n"
+ "       ss [ OPTIONS ] [ FILTER ]\n"
+-"   -h, --help		this message\n"
+-"   -V, --version	output version information\n"
+-"   -n, --numeric	don't resolve service names\n"
++"   -h, --help          this message\n"
++"   -V, --version       output version information\n"
++"   -n, --numeric       don't resolve service names\n"
+ "   -r, --resolve       resolve host names\n"
+-"   -a, --all		display all sockets\n"
+-"   -l, --listening	display listening sockets\n"
++"   -a, --all           display all sockets\n"
++"   -l, --listening     display listening sockets\n"
+ "   -o, --options       show timer information\n"
+ "   -e, --extended      show detailed socket information\n"
+ "   -m, --memory        show socket memory usage\n"
+-"   -p, --processes	show process using socket\n"
+-"   -i, --info		show internal TCP information\n"
+-"   -s, --summary	show socket usage summary\n"
++"   -p, --processes     show process using socket\n"
++"   -i, --info          show internal TCP information\n"
++"   -s, --summary       show socket usage summary\n"
+ "   -b, --bpf           show bpf filter socket information\n"
++"   -Z, --context       display process SELinux security contexts\n"
++"   -z, --contexts      display process and socket SELinux security contexts\n"
++"   -N, --net           switch to the specified network namespace name\n"
+ "\n"
+ "   -4, --ipv4          display only IP version 4 sockets\n"
+ "   -6, --ipv6          display only IP version 6 sockets\n"
+-"   -0, --packet	display PACKET sockets\n"
+-"   -t, --tcp		display only TCP sockets\n"
+-"   -u, --udp		display only UDP sockets\n"
+-"   -d, --dccp		display only DCCP sockets\n"
+-"   -w, --raw		display only RAW sockets\n"
+-"   -x, --unix		display only Unix domain sockets\n"
++"   -0, --packet        display PACKET sockets\n"
++"   -t, --tcp           display only TCP sockets\n"
++"   -u, --udp           display only UDP sockets\n"
++"   -d, --dccp          display only DCCP sockets\n"
++"   -w, --raw           display only RAW sockets\n"
++"   -x, --unix          display only Unix domain sockets\n"
+ "   -f, --family=FAMILY display sockets of type FAMILY\n"
+ "\n"
+ "   -A, --query=QUERY, --socket=QUERY\n"
+-"       QUERY := {all|inet|tcp|udp|raw|unix|packet|netlink}[,QUERY]\n"
++"       QUERY := {all|inet|tcp|udp|raw|unix|unix_dgram|unix_stream|unix_seqpacket|packet|netlink}[,QUERY]\n"
+ "\n"
+ "   -D, --diag=FILE     Dump raw information about TCP sockets to FILE\n"
+ "   -F, --filter=FILE   read filter information from FILE\n"
+-"       FILTER := [ state TCP-STATE ] [ EXPRESSION ]\n"
++"       FILTER := [ state STATE-FILTER ] [ EXPRESSION ]\n"
++"       STATE-FILTER := {all|connected|synchronized|bucket|big|TCP-STATES}\n"
++"         TCP-STATES := {established|syn-sent|syn-recv|fin-wait-{1,2}|time-wait|closed|close-wait|last-ack|listen|closing}\n"
++"          connected := {established|syn-sent|syn-recv|fin-wait-{1,2}|time-wait|close-wait|last-ack|closing}\n"
++"       synchronized := {established|syn-recv|fin-wait-{1,2}|time-wait|close-wait|last-ack|closing}\n"
++"             bucket := {syn-recv|time-wait}\n"
++"                big := {established|syn-sent|fin-wait-{1,2}|closed|close-wait|last-ack|listen|closing}\n"
+ 		);
+ }
+ 
+@@ -3085,7 +3366,9 @@ static int scan_state(const char *state)
+ 		if (strcasecmp(state, sstate_namel[i]) == 0)
+ 			return (1<<i);
+ 	}
+-	return 0;
++
++	fprintf(stderr, "ss: wrong state name: %s\n", state);
++	exit(-1);
+ }
+ 
+ static const struct option long_opts[] = {
+@@ -3115,25 +3398,25 @@ static const struct option long_opts[] = {
+ 	{ "filter", 1, 0, 'F' },
+ 	{ "version", 0, 0, 'V' },
+ 	{ "help", 0, 0, 'h' },
++	{ "context", 0, 0, 'Z' },
++	{ "contexts", 0, 0, 'z' },
++	{ "net", 1, 0, 'N' },
+ 	{ 0 }
+ 
+ };
+ 
+ int main(int argc, char *argv[])
+ {
+-	int do_default = 1;
+ 	int saw_states = 0;
+ 	int saw_query = 0;
+ 	int do_summary = 0;
+ 	const char *dump_tcpdiag = NULL;
+ 	FILE *filter_fp = NULL;
+ 	int ch;
++	struct filter dbs_filter = {};
++	int state_filter = 0;
+ 
+-	memset(&current_filter, 0, sizeof(current_filter));
+-
+-	current_filter.states = default_filter.states;
+-
+-	while ((ch = getopt_long(argc, argv, "dhaletuwxnro460spbf:miA:D:F:vV",
++	while ((ch = getopt_long(argc, argv, "dhaletuwxnro460spbf:miA:D:F:vVzZN:",
+ 				 long_opts, NULL)) != EOF) {
+ 		switch(ch) {
+ 		case 'n':
+@@ -3164,55 +3447,51 @@ int main(int argc, char *argv[])
+ 			show_bpf++;
+ 			break;
+ 		case 'd':
+-			current_filter.dbs |= (1<<DCCP_DB);
+-			do_default = 0;
++			filter_db_set(&dbs_filter, DCCP_DB);
+ 			break;
+ 		case 't':
+-			current_filter.dbs |= (1<<TCP_DB);
+-			do_default = 0;
++			filter_db_set(&dbs_filter, TCP_DB);
+ 			break;
+ 		case 'u':
+-			current_filter.dbs |= (1<<UDP_DB);
+-			do_default = 0;
++			filter_db_set(&dbs_filter, UDP_DB);
+ 			break;
+ 		case 'w':
+-			current_filter.dbs |= (1<<RAW_DB);
+-			do_default = 0;
++			filter_db_set(&dbs_filter, RAW_DB);
+ 			break;
+ 		case 'x':
+-			current_filter.dbs |= UNIX_DBM;
+-			do_default = 0;
++			filter_af_set(&current_filter, AF_UNIX);
+ 			break;
+ 		case 'a':
+-			current_filter.states = SS_ALL;
++			state_filter = SS_ALL;
+ 			break;
+ 		case 'l':
+-			current_filter.states = (1<<SS_LISTEN) | (1<<SS_CLOSE);
++			state_filter = (1 << SS_LISTEN) | (1 << SS_CLOSE);
+ 			break;
+ 		case '4':
+-			preferred_family = AF_INET;
++			filter_af_set(&current_filter, AF_INET);
+ 			break;
+ 		case '6':
+-			preferred_family = AF_INET6;
++			filter_af_set(&current_filter, AF_INET6);
+ 			break;
+ 		case '0':
+-			preferred_family = AF_PACKET;
++			filter_af_set(&current_filter, AF_PACKET);
+ 			break;
+ 		case 'f':
+ 			if (strcmp(optarg, "inet") == 0)
+-				preferred_family = AF_INET;
++				filter_af_set(&current_filter, AF_INET);
+ 			else if (strcmp(optarg, "inet6") == 0)
+-				preferred_family = AF_INET6;
++				filter_af_set(&current_filter, AF_INET6);
+ 			else if (strcmp(optarg, "link") == 0)
+-				preferred_family = AF_PACKET;
++				filter_af_set(&current_filter, AF_PACKET);
+ 			else if (strcmp(optarg, "unix") == 0)
+-				preferred_family = AF_UNIX;
++				filter_af_set(&current_filter, AF_UNIX);
+ 			else if (strcmp(optarg, "netlink") == 0)
+-				preferred_family = AF_NETLINK;
++				filter_af_set(&current_filter, AF_NETLINK);
+ 			else if (strcmp(optarg, "help") == 0)
+ 				help();
+ 			else {
+-				fprintf(stderr, "ss: \"%s\" is invalid family\n", optarg);
++				fprintf(stderr, "ss: \"%s\" is invalid family\n",
++						optarg);
+ 				usage();
+ 			}
+ 			break;
+@@ -3229,35 +3508,44 @@ int main(int argc, char *argv[])
+ 				if ((p1 = strchr(p, ',')) != NULL)
+ 					*p1 = 0;
+ 				if (strcmp(p, "all") == 0) {
+-					current_filter.dbs = ALL_DB;
++					filter_default_dbs(&dbs_filter);
+ 				} else if (strcmp(p, "inet") == 0) {
+-					current_filter.dbs |= (1<<TCP_DB)|(1<<DCCP_DB)|(1<<UDP_DB)|(1<<RAW_DB);
++					filter_db_set(&dbs_filter, UDP_DB);
++					filter_db_set(&dbs_filter, DCCP_DB);
++					filter_db_set(&dbs_filter, TCP_DB);
++					filter_db_set(&dbs_filter, RAW_DB);
+ 				} else if (strcmp(p, "udp") == 0) {
+-					current_filter.dbs |= (1<<UDP_DB);
++					filter_db_set(&dbs_filter, UDP_DB);
+ 				} else if (strcmp(p, "dccp") == 0) {
+-					current_filter.dbs |= (1<<DCCP_DB);
++					filter_db_set(&dbs_filter, DCCP_DB);
+ 				} else if (strcmp(p, "tcp") == 0) {
+-					current_filter.dbs |= (1<<TCP_DB);
++					filter_db_set(&dbs_filter, TCP_DB);
+ 				} else if (strcmp(p, "raw") == 0) {
+-					current_filter.dbs |= (1<<RAW_DB);
++					filter_db_set(&dbs_filter, RAW_DB);
+ 				} else if (strcmp(p, "unix") == 0) {
+-					current_filter.dbs |= UNIX_DBM;
++					filter_db_set(&dbs_filter, UNIX_ST_DB);
++					filter_db_set(&dbs_filter, UNIX_DG_DB);
++					filter_db_set(&dbs_filter, UNIX_SQ_DB);
+ 				} else if (strcasecmp(p, "unix_stream") == 0 ||
+ 					   strcmp(p, "u_str") == 0) {
+-					current_filter.dbs |= (1<<UNIX_ST_DB);
++					filter_db_set(&dbs_filter, UNIX_ST_DB);
+ 				} else if (strcasecmp(p, "unix_dgram") == 0 ||
+ 					   strcmp(p, "u_dgr") == 0) {
+-					current_filter.dbs |= (1<<UNIX_DG_DB);
++					filter_db_set(&dbs_filter, UNIX_DG_DB);
++				} else if (strcasecmp(p, "unix_seqpacket") == 0 ||
++					   strcmp(p, "u_seq") == 0) {
++					filter_db_set(&dbs_filter, UNIX_SQ_DB);
+ 				} else if (strcmp(p, "packet") == 0) {
+-					current_filter.dbs |= PACKET_DBM;
++					filter_db_set(&dbs_filter, PACKET_R_DB);
++					filter_db_set(&dbs_filter, PACKET_DG_DB);
+ 				} else if (strcmp(p, "packet_raw") == 0 ||
+ 					   strcmp(p, "p_raw") == 0) {
+-					current_filter.dbs |= (1<<PACKET_R_DB);
++					filter_db_set(&dbs_filter, PACKET_R_DB);
+ 				} else if (strcmp(p, "packet_dgram") == 0 ||
+ 					   strcmp(p, "p_dgr") == 0) {
+-					current_filter.dbs |= (1<<PACKET_DG_DB);
++					filter_db_set(&dbs_filter, PACKET_DG_DB);
+ 				} else if (strcmp(p, "netlink") == 0) {
+-					current_filter.dbs |= (1<<NETLINK_DB);
++					filter_db_set(&dbs_filter, NETLINK_DB);
+ 				} else {
+ 					fprintf(stderr, "ss: \"%s\" is illegal socket table id\n", p);
+ 					usage();
+@@ -3290,6 +3578,20 @@ int main(int argc, char *argv[])
+ 		case 'V':
+ 			printf("ss utility, iproute2-ss%s\n", SNAPSHOT);
+ 			exit(0);
++		case 'z':
++			show_sock_ctx++;
++		case 'Z':
++			if (is_selinux_enabled() <= 0) {
++				fprintf(stderr, "ss: SELinux is not enabled.\n");
++				exit(1);
++			}
++			show_proc_ctx++;
++			user_ent_hash_build();
++			break;
++		case 'N':
++			if (netns_switch(optarg))
++				exit(1);
++			break;
+ 		case 'h':
+ 		case '?':
+ 			help();
+@@ -3301,65 +3603,12 @@ int main(int argc, char *argv[])
+ 	argc -= optind;
+ 	argv += optind;
+ 
+-	get_slabstat(&slabstat);
+-
+ 	if (do_summary) {
+ 		print_summary();
+ 		if (do_default && argc == 0)
+ 			exit(0);
+ 	}
+ 
+-	if (do_default)
+-		current_filter.dbs = default_filter.dbs;
+-
+-	if (preferred_family == AF_UNSPEC) {
+-		if (!(current_filter.dbs&~UNIX_DBM))
+-			preferred_family = AF_UNIX;
+-		else if (!(current_filter.dbs&~PACKET_DBM))
+-			preferred_family = AF_PACKET;
+-		else if (!(current_filter.dbs&~(1<<NETLINK_DB)))
+-			preferred_family = AF_NETLINK;
+-	}
+-
+-	if (preferred_family != AF_UNSPEC) {
+-		int mask2;
+-		if (preferred_family == AF_INET ||
+-		    preferred_family == AF_INET6) {
+-			mask2= current_filter.dbs;
+-		} else if (preferred_family == AF_PACKET) {
+-			mask2 = PACKET_DBM;
+-		} else if (preferred_family == AF_UNIX) {
+-			mask2 = UNIX_DBM;
+-		} else if (preferred_family == AF_NETLINK) {
+-			mask2 = (1<<NETLINK_DB);
+-		} else {
+-			mask2 = 0;
+-		}
+-
+-		if (do_default)
+-			current_filter.dbs = mask2;
+-		else
+-			current_filter.dbs &= mask2;
+-		current_filter.families = (1<<preferred_family);
+-	} else {
+-		if (!do_default)
+-			current_filter.families = ~0;
+-		else
+-			current_filter.families = default_filter.families;
+-	}
+-	if (current_filter.dbs == 0) {
+-		fprintf(stderr, "ss: no socket tables to show with such filter.\n");
+-		exit(0);
+-	}
+-	if (current_filter.families == 0) {
+-		fprintf(stderr, "ss: no families to show with such filter.\n");
+-		exit(0);
+-	}
+-
+-	if (resolve_services && resolve_hosts &&
+-	    (current_filter.dbs&(UNIX_DBM|(1<<TCP_DB)|(1<<UDP_DB)|(1<<DCCP_DB))))
+-		init_service_resolver();
+-
+ 	/* Now parse filter... */
+ 	if (argc == 0 && filter_fp) {
+ 		if (ssfilter_parse(&current_filter.f, 0, NULL, filter_fp))
+@@ -3370,24 +3619,43 @@ int main(int argc, char *argv[])
+ 		if (strcmp(*argv, "state") == 0) {
+ 			NEXT_ARG();
+ 			if (!saw_states)
+-				current_filter.states = 0;
+-			current_filter.states |= scan_state(*argv);
++				state_filter = 0;
++			state_filter |= scan_state(*argv);
+ 			saw_states = 1;
+ 		} else if (strcmp(*argv, "exclude") == 0 ||
+ 			   strcmp(*argv, "excl") == 0) {
+ 			NEXT_ARG();
+ 			if (!saw_states)
+-				current_filter.states = SS_ALL;
+-			current_filter.states &= ~scan_state(*argv);
++				state_filter = SS_ALL;
++			state_filter &= ~scan_state(*argv);
+ 			saw_states = 1;
+ 		} else {
+-			if (ssfilter_parse(&current_filter.f, argc, argv, filter_fp))
+-				usage();
+ 			break;
+ 		}
+ 		argc--; argv++;
+ 	}
+ 
++	if (do_default) {
++		state_filter = state_filter ? state_filter : SS_CONN;
++		filter_default_dbs(&current_filter);
++		filter_merge(&current_filter, &current_filter, state_filter);
++	} else {
++		filter_merge(&current_filter, &dbs_filter, state_filter);
++	}
++
++	if (resolve_services && resolve_hosts &&
++	    (current_filter.dbs&(UNIX_DBM|(1<<TCP_DB)|(1<<UDP_DB)|(1<<DCCP_DB))))
++		init_service_resolver();
++
++
++	if (current_filter.dbs == 0) {
++		fprintf(stderr, "ss: no socket tables to show with such filter.\n");
++		exit(0);
++	}
++	if (current_filter.families == 0) {
++		fprintf(stderr, "ss: no families to show with such filter.\n");
++		exit(0);
++	}
+ 	if (current_filter.states == 0) {
+ 		fprintf(stderr, "ss: no socket states to show with such filter.\n");
+ 		exit(0);
+@@ -3411,6 +3679,9 @@ int main(int argc, char *argv[])
+ 		exit(0);
+ 	}
+ 
++	if (ssfilter_parse(&current_filter.f, argc, argv, filter_fp))
++		usage();
++
+ 	netid_width = 0;
+ 	if (current_filter.dbs&(current_filter.dbs-1))
+ 		netid_width = 5;
+@@ -3457,6 +3728,10 @@ int main(int argc, char *argv[])
+ 		printf("%-*s ", state_width, "State");
+ 	printf("%-6s %-6s ", "Recv-Q", "Send-Q");
+ 
++	/* Make enough space for the local/remote port field */
++	addr_width -= 13;
++	serv_width += 13;
++
+ 	printf("%*s:%-*s %*s:%-*s\n",
+ 	       addr_width, "Local Address", serv_width, "Port",
+ 	       addr_width, "Peer Address", serv_width, "Port");
+@@ -3477,5 +3752,9 @@ int main(int argc, char *argv[])
+ 		tcp_show(&current_filter, IPPROTO_TCP);
+ 	if (current_filter.dbs & (1<<DCCP_DB))
+ 		tcp_show(&current_filter, IPPROTO_DCCP);
++
++	if (show_users || show_proc_ctx || show_sock_ctx)
++		user_ent_destroy();
++
+ 	return 0;
+ }
+diff --git a/misc/ssfilter.h b/misc/ssfilter.h
+index 00b92e3..b20092b 100644
+--- a/misc/ssfilter.h
++++ b/misc/ssfilter.h
+@@ -9,6 +9,8 @@
+ #define SSF_S_LE  8
+ #define SSF_S_AUTO  9
+ 
++#include <stdbool.h>
++
+ struct ssfilter
+ {
+ 	int type;
+@@ -17,5 +19,5 @@ struct ssfilter
+ };
+ 
+ int ssfilter_parse(struct ssfilter **f, int argc, char **argv, FILE *fp);
+-void *parse_hostcond(char*);
++void *parse_hostcond(char *addr, bool is_port);
+ 
+diff --git a/misc/ssfilter.y b/misc/ssfilter.y
+index 2e9d962..a258d04 100644
+--- a/misc/ssfilter.y
++++ b/misc/ssfilter.y
+@@ -25,6 +25,7 @@ static char		**yy_argv;
+ static int		yy_argc;
+ static FILE		*yy_fp;
+ static ssfilter_t	*yy_ret;
++static int tok_type = -1;
+ 
+ static int yylex(void);
+ 
+@@ -220,14 +221,22 @@ int yylex(void)
+ 		return '(';
+ 	if (strcmp(curtok, ")") == 0)
+ 		return ')';
+-	if (strcmp(curtok, "dst") == 0)
++	if (strcmp(curtok, "dst") == 0) {
++		tok_type = DCOND;
+ 		return DCOND;
+-	if (strcmp(curtok, "src") == 0)
++	}
++	if (strcmp(curtok, "src") == 0) {
++                tok_type = SCOND;
+ 		return SCOND;
+-	if (strcmp(curtok, "dport") == 0)
++        }
++	if (strcmp(curtok, "dport") == 0) {
++		tok_type = DPORT;
+ 		return DPORT;
+-	if (strcmp(curtok, "sport") == 0)
++	}
++	if (strcmp(curtok, "sport") == 0) {
++		tok_type = SPORT;
+ 		return SPORT;
++	}
+ 	if (strcmp(curtok, ">=") == 0 ||
+ 	    strcmp(curtok, "ge") == 0 ||
+ 	    strcmp(curtok, "geq") == 0)
+@@ -250,9 +259,11 @@ int yylex(void)
+ 	if (strcmp(curtok, "<") == 0 ||
+ 	    strcmp(curtok, "lt") == 0)
+ 		return '<';
+-	if (strcmp(curtok, "autobound") == 0)
++	if (strcmp(curtok, "autobound") == 0) {
++		tok_type = AUTOBOUND;
+ 		return AUTOBOUND;
+-	yylval = (void*)parse_hostcond(curtok);
++	}
++	yylval = (void*)parse_hostcond(curtok, tok_type == SPORT || tok_type == DPORT);
+ 	if (yylval == NULL) {
+ 		fprintf(stderr, "Cannot parse dst/src address.\n");
+ 		exit(1);
+-- 
+2.3.5
+
diff --git a/SOURCES/iproute2-3.10.0-tc-fix-for-qdiscs-without-options.patch b/SOURCES/iproute2-3.10.0-tc-fix-for-qdiscs-without-options.patch
new file mode 100644
index 0000000..87ff98b
--- /dev/null
+++ b/SOURCES/iproute2-3.10.0-tc-fix-for-qdiscs-without-options.patch
@@ -0,0 +1,65 @@
+From f2794eafcfaa6dacb1bdcf5cfc11bf9d173cad28 Mon Sep 17 00:00:00 2001
+From: Stephen Hemminger <stephen@networkplumber.org>
+Date: Mon, 26 Aug 2013 08:41:19 -0700
+Subject: [PATCH] tc: fix for qdiscs without options
+
+This is a combination of 2 commits which fix tc for adding a qdisc which does
+not support options, like e.g. pfifo_fast. A simple test-case is:
+
+tc qdisc replace dev eth0 root pfifo_fast
+
+Without this patch applied, the above command fails with the following message:
+
+qdisc 'pfifo_fast' does not support option parsing
+
+commit e9e78b0db0e023035e346ba67de838be851eb665
+Author: Stephen Hemminger <stephen@networkplumber.org>
+Date:   Mon Aug 26 08:41:19 2013 -0700
+
+    tc: allow qdisc without options
+
+    Pfifo_fast needs no options. So don't force it to have parsing code.
+
+commit 0a502b21e30be835dcad8d9c6023a41da8709eb1
+Author: Stephen Hemminger <stephen@networkplumber.org>
+Date:   Sun Oct 27 12:26:47 2013 -0700
+
+    Fix handling of qdis without options
+
+    Some qdisc like htb want the parse_qopt to be called even if no options
+    present. Fixes regression caused by:
+
+    e9e78b0db0e023035e346ba67de838be851eb665 is the first bad commit
+    commit e9e78b0db0e023035e346ba67de838be851eb665
+    Author: Stephen Hemminger <stephen@networkplumber.org>
+    Date:   Mon Aug 26 08:41:19 2013 -0700
+
+        tc: allow qdisc without options
+---
+ tc/tc_qdisc.c | 7 ++++---
+ 1 file changed, 4 insertions(+), 3 deletions(-)
+
+diff --git a/tc/tc_qdisc.c b/tc/tc_qdisc.c
+index f3bf5b5..e304858 100644
+--- a/tc/tc_qdisc.c
++++ b/tc/tc_qdisc.c
+@@ -138,12 +138,13 @@ static int tc_qdisc_modify(int cmd, unsigned flags, int argc, char **argv)
+ 		addattr_l(&req.n, sizeof(req), TCA_RATE, &est, sizeof(est));
+ 
+ 	if (q) {
+-		if (!q->parse_qopt) {
++		if (q->parse_qopt) {
++			if (q->parse_qopt(q, argc, argv, &req.n))
++				return 1;
++		} else if (argc) {
+ 			fprintf(stderr, "qdisc '%s' does not support option parsing\n", k);
+ 			return -1;
+ 		}
+-		if (q->parse_qopt(q, argc, argv, &req.n))
+-			return 1;
+ 	} else {
+ 		if (argc) {
+ 			if (matches(*argv, "help") == 0)
+-- 
+1.8.3.1
+
diff --git a/SOURCES/iproute2-3.10.0-tc.patch b/SOURCES/iproute2-3.10.0-tc.patch
new file mode 100644
index 0000000..61cab01
--- /dev/null
+++ b/SOURCES/iproute2-3.10.0-tc.patch
@@ -0,0 +1,168 @@
+commit 53e34d82748442625618582eb88512fc4ee49c2e
+Author: Pavel Šimerda <psimerda@redhat.com>
+Date:   Thu May 28 12:17:39 2015 +0200
+
+    backport selected tc features and documentation
+
+diff --git a/man/man8/tc.8 b/man/man8/tc.8
+index e0acfeb..cc839d9 100644
+--- a/man/man8/tc.8
++++ b/man/man8/tc.8
+@@ -2,7 +2,9 @@
+ .SH NAME
+ tc \- show / manipulate traffic control settings
+ .SH SYNOPSIS
+-.B tc qdisc [ add | change | replace | link | delete ] dev
++.B tc
++.RI "[ " OPTIONS " ]"
++.B qdisc [ add | change | replace | link | delete ] dev
+ DEV
+ .B
+ [ parent
+@@ -13,7 +15,9 @@ qdisc-id ] qdisc
+ [ qdisc specific parameters ]
+ .P
+ 
+-.B tc class [ add | change | replace | delete ] dev
++.B tc
++.RI "[ " OPTIONS " ]"
++.B class [ add | change | replace | delete ] dev
+ DEV
+ .B parent
+ qdisc-id
+@@ -22,7 +26,9 @@ class-id ] qdisc
+ [ qdisc specific parameters ]
+ .P
+ 
+-.B tc filter [ add | change | replace | delete ] dev
++.B tc
++.RI "[ " OPTIONS " ]"
++.B filter [ add | change | replace | delete ] dev
+ DEV
+ .B [ parent
+ qdisc-id
+@@ -35,21 +41,28 @@ priority filtertype
+ flow-id
+ 
+ .B tc
++.RI "[ " OPTIONS " ]"
+ .RI "[ " FORMAT " ]"
+ .B qdisc show [ dev
+ DEV
+ .B ]
+ .P
+ .B tc
++.RI "[ " OPTIONS " ]"
+ .RI "[ " FORMAT " ]"
+ .B class show dev
+ DEV
+ .P
+-.B tc filter show dev
++.B tc
++.RI "[ " OPTIONS " ]"
++.B filter show dev
+ DEV
+ 
+ .P
+-.B tc [ -force ] -b\fR[\fIatch\fR] \fB[ filename ]
++.ti 8
++.IR OPTIONS " := {"
++\fB[ -force ] [ -OK ] -b\fR[\fIatch\fR] \fB[ filename ] \fR|
++\fB[ \fB-n\fR[\fIetns\fR] name \fB] \fR}
+ 
+ .ti 8
+ .IR FORMAT " := {"
+@@ -407,6 +420,44 @@ link
+ Only available for qdiscs and performs a replace where the node
+ must exist already.
+ 
++.SH OPTIONS
++
++.TP
++.BR "\-b", " \-b filename", " \-batch", " \-batch filename"
++read commands from provided file or standard input and invoke them.
++First failure will cause termination of tc.
++
++.TP
++.BR "\-force"
++don't terminate tc on errors in batch mode.
++If there were any errors during execution of the commands, the application return code will be non zero.
++
++.TP
++.BR "\-OK"
++in batch mode, print
++.B OK
++and a new line on standard output after each successfully interpreted command.
++
++.TP
++.BR "\-n" , " \-net" , " \-netns " <NETNS>
++switches
++.B tc
++to the specified network namespace
++.IR NETNS .
++Actually it just simplifies executing of:
++
++.B ip netns exec
++.IR NETNS
++.B tc
++.RI "[ " OPTIONS " ] " OBJECT " { " COMMAND " | "
++.BR help " }"
++
++to
++
++.B tc
++.RI "-n[etns] " NETNS " [ " OPTIONS " ] " OBJECT " { " COMMAND " | "
++.BR help " }"
++
+ .SH FORMAT
+ The show command has additional formatting options:
+ 
+diff --git a/tc/Makefile b/tc/Makefile
+index 0277760..af6a277 100644
+--- a/tc/Makefile
++++ b/tc/Makefile
+@@ -3,6 +3,11 @@ TCOBJ= tc.o tc_qdisc.o tc_class.o tc_filter.o tc_util.o \
+        m_ematch.o emp_ematch.yacc.o emp_ematch.lex.o
+ 
+ include ../Config
++
++ifeq ($(IP_CONFIG_SETNS),y)
++	CFLAGS += -DHAVE_SETNS
++endif
++
+ SHARED_LIBS ?= y
+ 
+ TCMODULES :=
+diff --git a/tc/tc.c b/tc/tc.c
+index b43bb47..4aaec21 100644
+--- a/tc/tc.c
++++ b/tc/tc.c
+@@ -29,6 +29,7 @@
+ #include "utils.h"
+ #include "tc_util.h"
+ #include "tc_common.h"
++#include "namespace.h"
+ 
+ int show_stats = 0;
+ int show_details = 0;
+@@ -186,7 +187,8 @@ static void usage(void)
+ 	fprintf(stderr, "Usage: tc [ OPTIONS ] OBJECT { COMMAND | help }\n"
+ 			"       tc [-force] [-OK] -batch filename\n"
+ 	                "where  OBJECT := { qdisc | class | filter | action | monitor }\n"
+-	                "       OPTIONS := { -s[tatistics] | -d[etails] | -r[aw] | -p[retty] | -b[atch] [filename] }\n");
++	                "       OPTIONS := { -s[tatistics] | -d[etails] | -r[aw] | -p[retty] | -b[atch] [filename] | "
++			"-n[etns] name }\n");
+ }
+ 
+ static int do_cmd(int argc, char **argv)
+@@ -299,6 +301,10 @@ int main(int argc, char **argv)
+ 			if (argc <= 1)
+ 				usage();
+ 			batch_file = argv[1];
++		} else if (matches(argv[1], "-netns") == 0) {
++			NEXT_ARG();
++			if (netns_switch(argv[1]))
++				return -1;
+ 		} else {
+ 			fprintf(stderr, "Option \"%s\" is unknown, try \"tc -help\".\n", argv[1]);
+ 			return -1;
diff --git a/SOURCES/iproute2-3.10.0-vxlan-add-dstport-option.patch b/SOURCES/iproute2-3.10.0-vxlan-add-dstport-option.patch
deleted file mode 100644
index 194b271..0000000
--- a/SOURCES/iproute2-3.10.0-vxlan-add-dstport-option.patch
+++ /dev/null
@@ -1,87 +0,0 @@
-diff --git a/ip/iplink_vxlan.c b/ip/iplink_vxlan.c
-index 1025326..3450135 100644
---- a/ip/iplink_vxlan.c
-+++ b/ip/iplink_vxlan.c
-@@ -25,8 +25,8 @@ static void explain(void)
- {
- 	fprintf(stderr, "Usage: ... vxlan id VNI [ group ADDR ] [ local ADDR ]\n");
- 	fprintf(stderr, "                 [ ttl TTL ] [ tos TOS ] [ dev PHYS_DEV ]\n");
--	fprintf(stderr, "                 [ port MIN MAX ] [ [no]learning ]\n");
--	fprintf(stderr, "                 [ [no]proxy ] [ [no]rsc ]\n");
-+	fprintf(stderr, "                 [ dstport PORT ] [ srcport MIN MAX ]\n");
-+	fprintf(stderr, "                 [ [no]learning ] [ [no]proxy ] [ [no]rsc ]\n");
- 	fprintf(stderr, "                 [ [no]l2miss ] [ [no]l3miss ]\n");
- 	fprintf(stderr, "\n");
- 	fprintf(stderr, "Where: VNI := 0-16777215\n");
-@@ -53,6 +53,8 @@ static int vxlan_parse_opt(struct link_util *lu, int argc, char **argv,
- 	__u8 noage = 0;
- 	__u32 age = 0;
- 	__u32 maxaddr = 0;
-+	__u16 dstport = 0;
-+	int dst_port_set = 0;
- 	struct ifla_vxlan_port_range range = { 0, 0 };
- 
- 	while (argc > 0) {
-@@ -115,7 +117,8 @@ static int vxlan_parse_opt(struct link_util *lu, int argc, char **argv,
- 				maxaddr = 0;
- 			else if (get_u32(&maxaddr, *argv, 0))
- 				invarg("max addresses", *argv);
--		} else if (!matches(*argv, "port")) {
-+		} else if (!matches(*argv, "port") ||
-+			   !matches(*argv, "srcport")) {
- 			__u16 minport, maxport;
- 			NEXT_ARG();
- 			if (get_u16(&minport, *argv, 0))
-@@ -125,6 +128,11 @@ static int vxlan_parse_opt(struct link_util *lu, int argc, char **argv,
- 				invarg("max port", *argv);
- 			range.low = htons(minport);
- 			range.high = htons(maxport);
-+		} else if (!matches(*argv, "dstport")){
-+			NEXT_ARG();
-+			if (get_u16(&dstport, *argv, 0))
-+				invarg("dst port", *argv);
-+			dst_port_set = 1;
- 		} else if (!matches(*argv, "nolearning")) {
- 			learning = 0;
- 		} else if (!matches(*argv, "learning")) {
-@@ -160,6 +168,15 @@ static int vxlan_parse_opt(struct link_util *lu, int argc, char **argv,
- 		fprintf(stderr, "vxlan: missing virtual network identifier\n");
- 		return -1;
- 	}
-+
-+	if (!dst_port_set) {
-+		fprintf(stderr, "vxlan: destination port not specified\n"
-+			"Will use Linux kernel default (non-standard value)\n");
-+		fprintf(stderr,
-+			"Use 'dstport 4789' to get the IANA assigned value\n"
-+			"Use 'dstport 0' to get default and quiet this message\n");
-+	}
-+
- 	addattr32(n, 1024, IFLA_VXLAN_ID, vni);
- 	if (gaddr)
- 		addattr_l(n, 1024, IFLA_VXLAN_GROUP, &gaddr, 4);
-@@ -184,6 +201,9 @@ static int vxlan_parse_opt(struct link_util *lu, int argc, char **argv,
- 		addattr_l(n, 1024, IFLA_VXLAN_PORT_RANGE,
- 			  &range, sizeof(range));
- 
-+	if (dstport)
-+		addattr16(n, 1024, IFLA_VXLAN_PORT, htons(dstport));
-+
- 	return 0;
- }
- 
-@@ -233,9 +253,13 @@ static void vxlan_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
- 	if (tb[IFLA_VXLAN_PORT_RANGE]) {
- 		const struct ifla_vxlan_port_range *r
- 			= RTA_DATA(tb[IFLA_VXLAN_PORT_RANGE]);
--		fprintf(f, "port %u %u ", ntohs(r->low), ntohs(r->high));
-+		fprintf(f, "srcport %u %u ", ntohs(r->low), ntohs(r->high));
- 	}
- 
-+	if (tb[IFLA_VXLAN_PORT])
-+		fprintf(f, "dstport %u ",
-+			ntohs(rta_getattr_u16(tb[IFLA_VXLAN_PORT])));
-+
- 	if (tb[IFLA_VXLAN_LEARNING] &&
- 	    !rta_getattr_u8(tb[IFLA_VXLAN_LEARNING]))
- 		fputs("nolearning ", f);
diff --git a/SOURCES/iproute2-3.10.0-xfrm.patch b/SOURCES/iproute2-3.10.0-xfrm.patch
new file mode 100644
index 0000000..3d75f2e
--- /dev/null
+++ b/SOURCES/iproute2-3.10.0-xfrm.patch
@@ -0,0 +1,326 @@
+commit f3de468299d13204f47dd8e431750fcba33fcd29
+Author: Christophe Gouault <christophe.gouault@6wind.com>
+Date:   Thu Apr 9 17:39:32 2015 +0200
+
+    xfrm: add command for configuring SPD hash table
+    
+    add a new command to configure the SPD hash table:
+       ip xfrm policy set [ hthresh4 LBITS RBITS ] [ hthresh6 LBITS RBITS ]
+    
+    and code to display the SPD hash configuration:
+      ip -s -s xfrm policy count
+    
+    hthresh4: defines minimum local and remote IPv4 prefix lengths of
+    selectors to hash a policy. If prefix lengths are greater or equal
+    to the thresholds, then the policy is hashed, otherwise it falls back
+    in the policy_inexact chained list.
+    
+    hthresh6: defines minimum local and remote IPv6 prefix lengths of
+    selectors to hash a policy, otherwise it falls back
+    in the policy_inexact chained list.
+    
+    Example:
+    
+    % ip -s -s xfrm policy count
+             SPD IN  0 OUT 0 FWD 0 (Sock: IN 0 OUT 0 FWD 0)
+             SPD buckets: count 7 Max 1048576
+             SPD IPv4 thresholds: local 32 remote 32
+             SPD IPv6 thresholds: local 128 remote 128
+    
+    % ip xfrm pol set hthresh4 24 16 hthresh6 64 56
+    
+    % ip -s -s xfrm policy count
+             SPD IN  0 OUT 0 FWD 0 (Sock: IN 0 OUT 0 FWD 0)
+             SPD buckets: count 7 Max 1048576
+             SPD IPv4 thresholds: local 24 remote 16
+             SPD IPv6 thresholds: local 64 remote 56
+    
+    Signed-off-by: Christophe Gouault <christophe.gouault@6wind.com>
+
+diff --git a/ip/xfrm_policy.c b/ip/xfrm_policy.c
+index 36e33c9..9ac4a89 100644
+--- a/ip/xfrm_policy.c
++++ b/ip/xfrm_policy.c
+@@ -64,7 +64,8 @@ static void usage(void)
+ 	fprintf(stderr, "        [ index INDEX ] [ ptype PTYPE ] [ action ACTION ] [ priority PRIORITY ]\n");
+ 	fprintf(stderr, "        [ flag FLAG-LIST ]\n");
+ 	fprintf(stderr, "Usage: ip xfrm policy flush [ ptype PTYPE ]\n");
+-	fprintf(stderr, "Usage: ip xfrm count\n");
++	fprintf(stderr, "Usage: ip xfrm policy count\n");
++	fprintf(stderr, "Usage: ip xfrm policy set [ hthresh4 LBITS RBITS ] [ hthresh6 LBITS RBITS ]\n");
+ 	fprintf(stderr, "SELECTOR := [ src ADDR[/PLEN] ] [ dst ADDR[/PLEN] ] [ dev DEV ] [ UPSPEC ]\n");
+ 	fprintf(stderr, "UPSPEC := proto { { ");
+ 	fprintf(stderr, "%s | ", strxf_proto(IPPROTO_TCP));
+@@ -935,7 +936,7 @@ static int print_spdinfo( struct nlmsghdr *n, void *arg)
+ 			fprintf(fp,")");
+ 		}
+ 
+-		fprintf(fp,"\n");
++		fprintf(fp, "%s", _SL_);
+ 	}
+ 	if (show_stats > 1) {
+ 		struct xfrmu_spdhinfo *sh;
+@@ -949,13 +950,109 @@ static int print_spdinfo( struct nlmsghdr *n, void *arg)
+ 			fprintf(fp,"\t SPD buckets:");
+ 			fprintf(fp," count %d", sh->spdhcnt);
+ 			fprintf(fp," Max %d", sh->spdhmcnt);
++			fprintf(fp, "%s", _SL_);
++		}
++		if (tb[XFRMA_SPD_IPV4_HTHRESH]) {
++			struct xfrmu_spdhthresh *th;
++			if (RTA_PAYLOAD(tb[XFRMA_SPD_IPV4_HTHRESH]) < sizeof(*th)) {
++				fprintf(stderr, "SPDinfo: Wrong len %d\n", len);
++				return -1;
++			}
++			th = RTA_DATA(tb[XFRMA_SPD_IPV4_HTHRESH]);
++			fprintf(fp,"\t SPD IPv4 thresholds:");
++			fprintf(fp," local %d", th->lbits);
++			fprintf(fp," remote %d", th->rbits);
++			fprintf(fp, "%s", _SL_);
++
++		}
++		if (tb[XFRMA_SPD_IPV6_HTHRESH]) {
++			struct xfrmu_spdhthresh *th;
++			if (RTA_PAYLOAD(tb[XFRMA_SPD_IPV6_HTHRESH]) < sizeof(*th)) {
++				fprintf(stderr, "SPDinfo: Wrong len %d\n", len);
++				return -1;
++			}
++			th = RTA_DATA(tb[XFRMA_SPD_IPV6_HTHRESH]);
++			fprintf(fp,"\t SPD IPv6 thresholds:");
++			fprintf(fp," local %d", th->lbits);
++			fprintf(fp," remote %d", th->rbits);
++			fprintf(fp, "%s", _SL_);
+ 		}
+ 	}
+-	fprintf(fp,"\n");
++
++	if (oneline)
++		fprintf(fp, "\n");
+ 
+         return 0;
+ }
+ 
++static int xfrm_spd_setinfo(int argc, char **argv)
++{
++	struct rtnl_handle rth;
++	struct {
++		struct nlmsghdr			n;
++		__u32				flags;
++		char				buf[RTA_BUF_SIZE];
++	} req;
++
++	char *thr4 = NULL;
++	char *thr6 = NULL;
++
++	memset(&req, 0, sizeof(req));
++
++	req.n.nlmsg_len = NLMSG_LENGTH(sizeof(__u32));
++	req.n.nlmsg_flags = NLM_F_REQUEST;
++	req.n.nlmsg_type = XFRM_MSG_NEWSPDINFO;
++	req.flags = 0XFFFFFFFF;
++
++	while (argc > 0) {
++		if (strcmp(*argv, "hthresh4") == 0) {
++			struct xfrmu_spdhthresh thr;
++
++			if (thr4)
++				duparg("hthresh4", *argv);
++			thr4 = *argv;
++			NEXT_ARG();
++			if (get_u8(&thr.lbits, *argv, 0) || thr.lbits > 32)
++				invarg("hthresh4 LBITS value is invalid", *argv);
++			NEXT_ARG();
++			if (get_u8(&thr.rbits, *argv, 0) || thr.rbits > 32)
++				invarg("hthresh4 RBITS value is invalid", *argv);
++
++			addattr_l(&req.n, sizeof(req), XFRMA_SPD_IPV4_HTHRESH,
++				  (void *)&thr, sizeof(thr));
++		} else if (strcmp(*argv, "hthresh6") == 0) {
++			struct xfrmu_spdhthresh thr;
++
++			if (thr6)
++				duparg("hthresh6", *argv);
++			thr6 = *argv;
++			NEXT_ARG();
++			if (get_u8(&thr.lbits, *argv, 0) || thr.lbits > 128)
++				invarg("hthresh6 LBITS value is invalid", *argv);
++			NEXT_ARG();
++			if (get_u8(&thr.rbits, *argv, 0) || thr.rbits > 128)
++				invarg("hthresh6 RBITS value is invalid", *argv);
++
++			addattr_l(&req.n, sizeof(req), XFRMA_SPD_IPV6_HTHRESH,
++				  (void *)&thr, sizeof(thr));
++		} else {
++			invarg("unknown", *argv);
++		}
++
++		argc--; argv++;
++	}
++
++	if (rtnl_open_byproto(&rth, 0, NETLINK_XFRM) < 0)
++		exit(1);
++
++	if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0)
++		exit(2);
++
++	rtnl_close(&rth);
++
++	return 0;
++}
++
+ static int xfrm_spd_getinfo(int argc, char **argv)
+ {
+ 	struct rtnl_handle rth;
+@@ -1059,6 +1156,8 @@ int do_xfrm_policy(int argc, char **argv)
+ 		return xfrm_policy_flush(argc-1, argv+1);
+ 	if (matches(*argv, "count") == 0)
+ 		return xfrm_spd_getinfo(argc, argv);
++	if (matches(*argv, "set") == 0)
++		return xfrm_spd_setinfo(argc-1, argv+1);
+ 	if (matches(*argv, "help") == 0)
+ 		usage();
+ 	fprintf(stderr, "Command \"%s\" is unknown, try \"ip xfrm policy help\".\n", *argv);
+commit 0b1562a4459c59d79ecabcf919e3db423a2c321d
+Author: Christophe Gouault <christophe.gouault@6wind.com>
+Date:   Thu Apr 9 17:39:33 2015 +0200
+
+    xfrm: revise man page and document ip xfrm policy set
+    
+    - document ip xfrm policy set
+    - update ip xfrm monitor documentation
+    - in DESCRIPTION section, reorganize grouping of commands
+    
+    Signed-off-by: Christophe Gouault <christophe.gouault@6wind.com>
+
+diff --git a/man/man8/ip-xfrm.8 b/man/man8/ip-xfrm.8
+index 2d31b4d..e305c0b 100644
+--- a/man/man8/ip-xfrm.8
++++ b/man/man8/ip-xfrm.8
+@@ -252,6 +252,13 @@ ip-xfrm \- transform configuration
+ .B "ip xfrm policy count"
+ 
+ .ti -8
++.B "ip xfrm policy set"
++.RB "[ " hthresh4
++.IR LBITS " " RBITS " ]"
++.RB "[ " hthresh6
++.IR LBITS " " RBITS " ]"
++
++.ti -8
+ .IR SELECTOR " :="
+ .RB "[ " src
+ .IR ADDR "[/" PLEN "] ]"
+@@ -355,6 +362,13 @@ ip-xfrm \- transform configuration
+ .BR "ip xfrm monitor" " [ " all " |"
+ .IR LISTofXFRM-OBJECTS " ]"
+ 
++.ti -8
++.IR LISTofXFRM-OBJECTS " := [ " LISTofXFRM-OBJECTS " ] " XFRM-OBJECT
++
++.ti -8
++.IR XFRM-OBJECT " := "
++.BR acquire " | " expire " | " SA " | " policy " | " aevent " | " report
++
+ .in -8
+ .ad b
+ 
+@@ -380,7 +394,6 @@ ip xfrm state deleteall	delete all existing state in xfrm
+ ip xfrm state list	print out the list of existing state in xfrm
+ ip xfrm state flush	flush all state in xfrm
+ ip xfrm state count	count all existing state in xfrm
+-ip xfrm monitor 	state monitoring for xfrm objects
+ .TE
+ 
+ .TP
+@@ -502,7 +515,9 @@ encapsulates packets with protocol
+ .BR espinudp " or " espinudp-nonike ","
+ .RI "using source port " SPORT ", destination port "  DPORT
+ .RI ", and original address " OADDR "."
++
+ .sp
++.PP
+ .TS
+ l l.
+ ip xfrm policy add	add a new policy
+@@ -512,7 +527,6 @@ ip xfrm policy get	get an existing policy
+ ip xfrm policy deleteall	delete all existing xfrm policies
+ ip xfrm policy list	print out the list of xfrm policies
+ ip xfrm policy flush	flush policies
+-ip xfrm policy count	count existing policies
+ .TE
+ 
+ .TP
+@@ -607,7 +621,50 @@ and inbound trigger
+ can be
+ .BR required " (default) or " use "."
+ 
++.sp
++.PP
++.TS
++l l.
++ip xfrm policy count	count existing policies
++.TE
++
++.PP
++Use one or more -s options to display more details, including policy hash table
++information.
++
++.sp
++.PP
++.TS
++l l.
++ip xfrm policy set	configure the policy hash table
++.TE
++
++.PP
++Security policies whose address prefix lengths are greater than or equal
++policy hash table thresholds are hashed. Others are stored in the
++policy_inexact chained list.
++
++.TP
++.I LBITS
++specifies the minimum local address prefix length of policies that are
++stored in the Security Policy Database hash table.
++
++.TP
++.I RBITS
++specifies the minimum remote address prefix length of policies that are
++stored in the Security Policy Database hash table.
++
++.sp
++.PP
++.TS
++l l.
++ip xfrm monitor 	state monitoring for xfrm objects
++.TE
++
++.PP
+ The xfrm objects to monitor can be optionally specified.
+ 
+ .SH AUTHOR
+ Manpage revised by David Ward <david.ward@ll.mit.edu>
++.br
++Manpage revised by Christophe Gouault <christophe.gouault@6wind.com>
+commit 5bf9f5c5a0f2d8a0fdb06c60242ff805177a4d73
+Author: Vadim Kochan <vadim4j@gmail.com>
+Date:   Sat Feb 14 19:45:04 2015 +0200
+
+    ip xfrm: Allow to specify "all" option for monitor
+    
+    Just to be aligned with the usage output.
+    
+    Signed-off-by: Vadim Kochan <vadim4j@gmail.com>
+
+diff --git a/ip/xfrm_monitor.c b/ip/xfrm_monitor.c
+index 79453e4..8aa6f49 100644
+--- a/ip/xfrm_monitor.c
++++ b/ip/xfrm_monitor.c
+@@ -374,7 +374,7 @@ int do_xfrm_monitor(int argc, char **argv)
+ 			groups = 0;
+ 		} else if (matches(*argv, "help") == 0) {
+ 			usage();
+-		} else {
++		} else if (strcmp(*argv, "all")) {
+ 			fprintf(stderr, "Argument \"%s\" is unknown, try \"ip xfrm monitor help\".\n", *argv);
+ 			exit(-1);
+ 		}
diff --git a/SOURCES/iproute2-3.11.0-iproute2-bridge-Close-file-with-bridge-monitor-file.patch b/SOURCES/iproute2-3.11.0-iproute2-bridge-Close-file-with-bridge-monitor-file.patch
deleted file mode 100644
index 8d381a4..0000000
--- a/SOURCES/iproute2-3.11.0-iproute2-bridge-Close-file-with-bridge-monitor-file.patch
+++ /dev/null
@@ -1,41 +0,0 @@
-From 101847446e6a5e3ca370e65ebc462584934fce0e Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Petr=20P=C3=ADsa=C5=99?= <ppisar@redhat.com>
-Date: Wed, 25 Sep 2013 09:45:45 +0200
-Subject: [PATCH] iproute2: bridge: Close file with bridge monitor file
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-The `bridge monitor file FILENAME' reads dumped netlink messages from
-a file. But it forgot to close the file after using it. This patch
-fixes it.
-
-Signed-off-by: Petr Písař <ppisar@redhat.com>
----
- bridge/monitor.c | 5 ++++-
- 1 file changed, 4 insertions(+), 1 deletion(-)
-
-diff --git a/bridge/monitor.c b/bridge/monitor.c
-index e96fcaf..76e7d47 100644
---- a/bridge/monitor.c
-+++ b/bridge/monitor.c
-@@ -132,12 +132,15 @@ int do_monitor(int argc, char **argv)
- 
- 	if (file) {
- 		FILE *fp;
-+		int err;
- 		fp = fopen(file, "r");
- 		if (fp == NULL) {
- 			perror("Cannot fopen");
- 			exit(-1);
- 		}
--		return rtnl_from_file(fp, accept_msg, stdout);
-+		err = rtnl_from_file(fp, accept_msg, stdout);
-+		fclose(fp);
-+		return err;
- 	}
- 
- 	if (rtnl_open(&rth, groups) < 0)
--- 
-1.8.3.1
-
diff --git a/SOURCES/iproute2-3.11.0-iproute2-bridge-document-mdb.patch b/SOURCES/iproute2-3.11.0-iproute2-bridge-document-mdb.patch
deleted file mode 100644
index 0c827f5..0000000
--- a/SOURCES/iproute2-3.11.0-iproute2-bridge-document-mdb.patch
+++ /dev/null
@@ -1,153 +0,0 @@
-From 54e9c3a34d4ba8a0890f3bf21d708342329461b5 Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Petr=20P=C3=ADsa=C5=99?= <ppisar@redhat.com>
-Date: Thu, 19 Sep 2013 10:41:26 +0200
-Subject: [PATCH] iproute2: bridge: document mdb
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-This augments bridge(8) manual page with `bridge mdb' and `bridge
-monitor mdb' commands which have been added recently.
-
-Signed-off-by: Petr Písař <ppisar@redhat.com>
----
- man/man8/bridge.8 | 88 +++++++++++++++++++++++++++++++++++++++++++++++++++++--
- 1 file changed, 85 insertions(+), 3 deletions(-)
-
-diff --git a/man/man8/bridge.8 b/man/man8/bridge.8
-index 66678b5..9a34804 100644
---- a/man/man8/bridge.8
-+++ b/man/man8/bridge.8
-@@ -13,7 +13,7 @@ bridge \- show / manipulate bridge addresses and devices
- 
- .ti -8
- .IR OBJECT " := { "
--.BR link " | " fdb " | " vlan " | " monitor " }"
-+.BR link " | " fdb " | " mdb " | " vlan " | " monitor " }"
- .sp
- 
- .ti -8
-@@ -65,6 +65,21 @@ bridge \- show / manipulate bridge addresses and devices
- .IR DEV " ]"
- 
- .ti -8
-+.BR "bridge mdb" " { " add " | " del " } "
-+.B  dev
-+.IR DEV
-+.B port
-+.IR PORT
-+.B grp
-+.IR GROUP " [ "
-+.BR permanent " | " temp " ]"
-+
-+.ti -8
-+.BR "bridge mdb show " [ "
-+.B  dev
-+.IR DEV " ]"
-+
-+.ti -8
- .BR "bridge vlan" " { " add " | " del " } "
- .B  dev
- .IR DEV
-@@ -79,7 +94,7 @@ bridge \- show / manipulate bridge addresses and devices
- .IR DEV " ]"
- 
- .ti -8
--.BR "bridge monitor" " [ " all " | " neigh " | " link " ]"
-+.BR "bridge monitor" " [ " all " | " neigh " | " link " | " mdb " ]"
- 
- .SH OPTIONS
- 
-@@ -110,6 +125,10 @@ As a rule, the information is statistics or some time values.
- - Forwarding Database entry.
- 
- .TP
-+.B mdb
-+- Multicast group database entry.
-+
-+.TP
- .B vlan
- - VLAN filter list.
- 
-@@ -326,6 +345,69 @@ With the
- option, the command becomes verbose.  It prints out the last updated
- and last used time for each entry.
- 
-+.SH bridge mdb - multicast group database management
-+
-+.B mdb
-+objects contain known IP multicast group addresses on a link.
-+
-+.P
-+The corresponding commands display mdb entries, add new entries,
-+and delete old ones.
-+
-+.SS bridge mdb add - add a new multicast group database entry
-+
-+This command creates a new mdb entry.
-+
-+.TP
-+.BI dev " DEV"
-+the interface where this group address is associated.
-+
-+.TP
-+.BI port " PORT"
-+the port whose link is known to have members of this multicast group.
-+
-+.TP
-+.BI grp " GROUP"
-+the IP multicast group address whose members reside on the link connected to
-+the port.
-+
-+.B permanent
-+- the mdb entry is permanent
-+.sp
-+
-+.B temp
-+- the mdb entry is temporary (default)
-+.sp
-+
-+.in -8
-+.SS bridge mdb delete - delete a multicast group database entry
-+This command removes an existing mdb entry.
-+
-+.PP
-+The arguments are the same as with
-+.BR "bridge mdb add" .
-+
-+.SS bridge mdb show - list multicast group database entries
-+
-+This command displays the current multicast group membership table. The table
-+is populated by IGMP and MLD snooping in the bridge driver automatically. It
-+can be altered by
-+.B bridge mdb add
-+and
-+.B bridge mdb del
-+commands manually too.
-+
-+.TP
-+.BI dev " DEV"
-+the interface only whose entries should be listed. Default is to list all
-+bridge interfaces.
-+
-+.PP
-+With the
-+.B -details
-+option, the command becomes verbose.  It prints out the ports known to have
-+a connected router.
-+
- .SH bridge vlan - VLAN filter list
- 
- .B vlan
-@@ -395,7 +477,7 @@ command is the first in the command line and then the object list follows:
- .I OBJECT-LIST
- is the list of object types that we want to monitor.
- It may contain
--.BR link ",  and " fdb "."
-+.BR link ",  " fdb ", and " mdb "."
- If no
- .B file
- argument is given,
--- 
-1.8.3.1
-
diff --git a/SOURCES/iproute2-3.11.0-tc-ok.patch b/SOURCES/iproute2-3.11.0-tc-ok.patch
index fb8a13c..f717497 100644
--- a/SOURCES/iproute2-3.11.0-tc-ok.patch
+++ b/SOURCES/iproute2-3.11.0-tc-ok.patch
@@ -20,32 +20,6 @@ Signed-off-by: Petr Písař <ppisar@redhat.com>
  tc/tc.c       | 8 +++++++-
  2 files changed, 14 insertions(+), 2 deletions(-)
 
-diff --git a/man/man8/tc.8 b/man/man8/tc.8
-index e0acfeb..583eae2 100644
---- a/man/man8/tc.8
-+++ b/man/man8/tc.8
-@@ -49,7 +49,7 @@ DEV
- DEV
- 
- .P
--.B tc [ -force ] -b\fR[\fIatch\fR] \fB[ filename ]
-+.B tc [ -force ] [ -OK ] -b\fR[\fIatch\fR] \fB[ filename ]
- 
- .ti 8
- .IR FORMAT " := {"
-@@ -440,6 +440,12 @@ First failure will cause termination of tc.
- don't terminate tc on errors in batch mode.
- If there were any errors during execution of the commands, the application return code will be non zero.
- 
-+.TP
-+.BR "\-OK"
-+in batch mode, print
-+.B OK
-+and a new line on standard output after each successfully interpreted command.
-+
- .SH HISTORY
- .B tc
- was written by Alexey N. Kuznetsov and added in Linux 2.2.
 diff --git a/tc/tc.c b/tc/tc.c
 index 9b50e74..b43bb47 100644
 --- a/tc/tc.c
diff --git a/SOURCES/iproute2-3.16.0-addrgenmode.patch b/SOURCES/iproute2-3.16.0-addrgenmode.patch
deleted file mode 100644
index 02f6fec..0000000
--- a/SOURCES/iproute2-3.16.0-addrgenmode.patch
+++ /dev/null
@@ -1,97 +0,0 @@
-diff --git a/include/linux/if_link.h b/include/linux/if_link.h
-index fadef0f..39cb62c 100644
---- a/include/linux/if_link.h
-+++ b/include/linux/if_link.h
-@@ -202,11 +202,17 @@ enum {
- 	IFLA_INET6_CACHEINFO,	/* time values and max reasm size */
- 	IFLA_INET6_ICMP6STATS,	/* statistics (icmpv6)		*/
- 	IFLA_INET6_TOKEN,	/* device token			*/
-+	IFLA_INET6_ADDR_GEN_MODE, /* implicit address generator mode */
- 	__IFLA_INET6_MAX
- };
- 
- #define IFLA_INET6_MAX	(__IFLA_INET6_MAX - 1)
- 
-+enum in6_addr_gen_mode {
-+	IN6_ADDR_GEN_MODE_EUI64,
-+	IN6_ADDR_GEN_MODE_NONE,
-+};
-+
- enum {
- 	BRIDGE_MODE_UNSPEC,
- 	BRIDGE_MODE_HAIRPIN,
-diff --git a/ip/iplink.c b/ip/iplink.c
-index 0d020ef..ecb05d6 100644
---- a/ip/iplink.c
-+++ b/ip/iplink.c
-@@ -81,6 +81,7 @@ void iplink_usage(void)
- 	fprintf(stderr, "				   [ state { auto | enable | disable} ] ]\n");
- 	fprintf(stderr, "			  [ master DEVICE ]\n");
- 	fprintf(stderr, "			  [ nomaster ]\n");
-+	fprintf(stderr, "			  [ addrgenmode { eui64 | none } ]\n");
- 	fprintf(stderr, "       ip link show [ DEVICE | group GROUP ] [up]\n");
- 
- 	if (iplink_have_newlink()) {
-@@ -161,6 +162,15 @@ static int get_link_mode(const char *mode)
- 	return -1;
- }
- 
-+static int get_addr_gen_mode(const char *mode)
-+{
-+	if (strcasecmp(mode, "eui64") == 0)
-+		return IN6_ADDR_GEN_MODE_EUI64;
-+	if (strcasecmp(mode, "none") == 0)
-+		return IN6_ADDR_GEN_MODE_NONE;
-+	return -1;
-+}
-+
- #if IPLINK_IOCTL_COMPAT
- static int have_rtnl_newlink = -1;
- 
-@@ -557,6 +567,18 @@ int iplink_parse(int argc, char **argv, struct iplink_req *req,
- 				invarg("Invalid \"numrxqueues\" value\n", *argv);
- 			addattr_l(&req->n, sizeof(*req), IFLA_NUM_RX_QUEUES,
- 				  &numrxqueues, 4);
-+		} else if (matches(*argv, "addrgenmode") == 0) {
-+			struct rtattr *afs, *afs6;
-+			int mode;
-+			NEXT_ARG();
-+			mode = get_addr_gen_mode(*argv);
-+			if (mode < 0)
-+				invarg("Invalid address generation mode\n", *argv);
-+			afs = addattr_nest(&req->n, sizeof(*req), IFLA_AF_SPEC);
-+			afs6 = addattr_nest(&req->n, sizeof(*req), AF_INET6);
-+			addattr8(&req->n, sizeof(*req), IFLA_INET6_ADDR_GEN_MODE, mode);
-+			addattr_nest_end(&req->n, afs6);
-+			addattr_nest_end(&req->n, afs);
- 		} else {
- 			if (strcmp(*argv, "dev") == 0) {
- 				NEXT_ARG();
-diff -uNrp iproute2-3.10.0.orig/man/man8/ip-link.8.in iproute2-3.10.0/man/man8/ip-link.8.in
---- iproute2-3.10.0.orig/man/man8/ip-link.8.in	2014-10-24 12:59:52.388574153 +0200
-+++ iproute2-3.10.0/man/man8/ip-link.8.in	2014-10-24 12:57:58.650081739 +0200
-@@ -120,9 +120,11 @@ ip-link \- network device configuration
- ] |
- .br
- .B master
--.IR DEVICE
-+.IR DEVICE " |"
- .br
--.B nomaster
-+.B nomaster " |"
-+.br
-+.B addrgenmode { eui64 | none }
- .BR " }"
- 
- 
-@@ -512,6 +514,10 @@ set master device of the device (enslave
- .BI nomaster
- unset master device of the device (release device).
- 
-+.TP
-+.BR "addrgenmode eui64 " or " addrgenmode none"
-+set IPv6 address generation mode
-+
- .PP
- .B Warning:
- If multiple parameter changes are requested,
diff --git a/SOURCES/iproute2-3.16.0-bpf.patch b/SOURCES/iproute2-3.16.0-bpf.patch
index c4c7df9..28ae5b5 100644
--- a/SOURCES/iproute2-3.16.0-bpf.patch
+++ b/SOURCES/iproute2-3.16.0-bpf.patch
@@ -329,82 +329,3 @@ Date:   Wed Oct 30 16:42:03 2013 -0700
     
     Lastest from net-next
 
-diff --git a/include/linux/can/netlink.h b/include/linux/can/netlink.h
-index 14966dd..df944ed 100644
---- a/include/linux/can/netlink.h
-+++ b/include/linux/can/netlink.h
-@@ -5,6 +5,14 @@
-  *
-  * Copyright (c) 2009 Wolfgang Grandegger <wg@grandegger.com>
-  *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the version 2 of the GNU General Public License
-+ * as published by the Free Software Foundation
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-  */
- 
- #ifndef CAN_NETLINK_H
-diff --git a/include/linux/if_link.h b/include/linux/if_link.h
-index ee4f2ba..a485920 100644
---- a/include/linux/if_link.h
-+++ b/include/linux/if_link.h
-@@ -323,6 +323,17 @@ struct ifla_vxlan_port_range {
- 	__be16	high;
- };
- 
-+/* Bonding section */
-+
-+enum {
-+	IFLA_BOND_UNSPEC,
-+	IFLA_BOND_MODE,
-+	IFLA_BOND_ACTIVE_SLAVE,
-+	__IFLA_BOND_MAX,
-+};
-+
-+#define IFLA_BOND_MAX	(__IFLA_BOND_MAX - 1)
-+
- /* SR-IOV virtual function management section */
- 
- enum {
-diff --git a/include/linux/pkt_cls.h b/include/linux/pkt_cls.h
-index 082eafa..25731df 100644
---- a/include/linux/pkt_cls.h
-+++ b/include/linux/pkt_cls.h
-@@ -388,6 +388,20 @@ enum {
- 
- #define TCA_CGROUP_MAX (__TCA_CGROUP_MAX - 1)
- 
-+/* BPF classifier */
-+
-+enum {
-+	TCA_BPF_UNSPEC,
-+	TCA_BPF_ACT,
-+	TCA_BPF_POLICE,
-+	TCA_BPF_CLASSID,
-+	TCA_BPF_OPS_LEN,
-+	TCA_BPF_OPS,
-+	__TCA_BPF_MAX,
-+};
-+
-+#define TCA_BPF_MAX (__TCA_BPF_MAX - 1)
-+
- /* Extended Matches */
- 
- struct tcf_ematch_tree_hdr {
-diff --git a/include/linux/pkt_sched.h b/include/linux/pkt_sched.h
-index 9b82913..f2624b5 100644
---- a/include/linux/pkt_sched.h
-+++ b/include/linux/pkt_sched.h
-@@ -357,6 +357,8 @@ enum {
- 	TCA_HTB_CTAB,
- 	TCA_HTB_RTAB,
- 	TCA_HTB_DIRECT_QLEN,
-+	TCA_HTB_RATE64,
-+	TCA_HTB_CEIL64,
- 	__TCA_HTB_MAX,
- };
- 
diff --git a/SOURCES/iproute2-3.16.0-quickack.patch b/SOURCES/iproute2-3.16.0-quickack.patch
index 8d780b0..8f47261 100644
--- a/SOURCES/iproute2-3.16.0-quickack.patch
+++ b/SOURCES/iproute2-3.16.0-quickack.patch
@@ -12,19 +12,6 @@ Date:   Sat Jun 15 09:39:19 2013 +0800
     Cc: Thomas Graf <tgraf@suug.ch>
     Signed-off-by: Cong Wang <amwang@redhat.com>
 
-diff --git a/include/linux/rtnetlink.h b/include/linux/rtnetlink.h
-index 93370bd..248fdd3 100644
---- a/include/linux/rtnetlink.h
-+++ b/include/linux/rtnetlink.h
-@@ -386,6 +386,8 @@ enum {
- #define RTAX_RTO_MIN RTAX_RTO_MIN
- 	RTAX_INITRWND,
- #define RTAX_INITRWND RTAX_INITRWND
-+	RTAX_QUICKACK,
-+#define RTAX_QUICKACK RTAX_QUICKACK
- 	__RTAX_MAX
- };
- 
 diff --git a/ip/iproute.c b/ip/iproute.c
 index adef774..46710b2 100644
 --- a/ip/iproute.c
diff --git a/SOURCES/iproute2-4.0.0-netns.patch b/SOURCES/iproute2-4.0.0-netns.patch
new file mode 100644
index 0000000..c374dc4
--- /dev/null
+++ b/SOURCES/iproute2-4.0.0-netns.patch
@@ -0,0 +1,423 @@
+commit a721ebaafd6852e86b636e2595e36f635c2b3cae
+Author: Nicolas Dichtel <nicolas.dichtel@6wind.com>
+Date:   Wed Apr 15 14:23:22 2015 +0200
+
+    netns: allow to dump and monitor nsid
+    
+    Two commands are added:
+     - ip netns list-id
+     - ip monitor nsid
+    
+    A cache is also added to remember the association between the iproute2 netns
+    name (from /var/run/netns/) and the nsid.
+    To avoid interfering with the rth socket, a new rtnl socket (rtnsh) is used to
+    get nsid (we may send rtnl request during listing on rth).
+    
+    Example:
+    $ ip netns list-id
+    nsid 0 (iproute2 netns name: foo)
+    $ ip monitor nsid
+    Deleted nsid 0 (iproute2 netns name: foo)
+    nsid 16 (iproute2 netns name: bar)
+    
+    Signed-off-by: Nicolas Dichtel <nicolas.dichtel@6wind.com>
+
+diff --git a/include/ll_map.h b/include/ll_map.h
+index f1dda39..a9d9cb3 100644
+--- a/include/ll_map.h
++++ b/include/ll_map.h
+@@ -10,5 +10,6 @@ extern const char *ll_index_to_name(unsigned idx);
+ extern const char *ll_idx_n2a(unsigned idx, char *buf);
+ extern int ll_index_to_type(unsigned idx);
+ extern unsigned ll_index_to_flags(unsigned idx);
++extern unsigned namehash(const char *str);
+ 
+ #endif /* __LL_MAP_H__ */
+diff --git a/ip/ip_common.h b/ip/ip_common.h
+index f9b4734..85529f0 100644
+--- a/ip/ip_common.h
++++ b/ip/ip_common.h
+@@ -30,6 +30,9 @@ extern int print_rule(const struct sockaddr_nl *who,
+ 		      struct nlmsghdr *n, void *arg);
+ extern int print_netconf(const struct sockaddr_nl *who,
+ 			 struct nlmsghdr *n, void *arg);
++extern void netns_map_init(void);
++extern int print_nsid(const struct sockaddr_nl *who,
++		      struct nlmsghdr *n, void *arg);
+ extern int do_ipaddr(int argc, char **argv);
+ extern int do_ipaddrlabel(int argc, char **argv);
+ extern int do_iproute(int argc, char **argv);
+diff --git a/ip/ipmonitor.c b/ip/ipmonitor.c
+index 86c473e..148cf1e 100644
+--- a/ip/ipmonitor.c
++++ b/ip/ipmonitor.c
+@@ -31,7 +31,7 @@ static void usage(void)
+ {
+ 	fprintf(stderr, "Usage: ip monitor [ all | LISTofOBJECTS ] [ FILE ]\n");
+ 	fprintf(stderr, "LISTofOBJECTS := link | address | route | mroute | prefix |\n");
+-	fprintf(stderr, "                 neigh | netconf\n");
++	fprintf(stderr, "                 neigh | netconf | nsid\n");
+ 	fprintf(stderr, "FILE := file FILENAME\n");
+ 	exit(-1);
+ }
+@@ -127,6 +127,12 @@ static int accept_msg(const struct sockaddr_nl *who,
+ 	    n->nlmsg_type == RTM_NEWTFILTER ||
+ 	    n->nlmsg_type == RTM_DELTFILTER)
+ 		return 0;
++	if (n->nlmsg_type == RTM_NEWNSID || n->nlmsg_type == RTM_DELNSID) {
++		if (prefix_banner)
++			fprintf(fp, "[NSID]");
++		print_nsid(who, n, arg);
++		return 0;
++	}
+ 	if (n->nlmsg_type != NLMSG_ERROR && n->nlmsg_type != NLMSG_NOOP &&
+ 	    n->nlmsg_type != NLMSG_DONE) {
+ 		fprintf(fp, "Unknown message: %08x %08x %08x\n",
+@@ -146,6 +152,9 @@ int do_ipmonitor(int argc, char **argv)
+ 	int lprefix=0;
+ 	int lneigh=0;
+ 	int lnetconf=0;
++	int lnsid=0;
++
++	groups |= nl_mgrp(RTNLGRP_NSID);
+ 
+ 	rtnl_close(&rth);
+ 	ipaddr_reset_filter(1);
+@@ -178,6 +187,9 @@ int do_ipmonitor(int argc, char **argv)
+ 		} else if (matches(*argv, "netconf") == 0) {
+ 			lnetconf = 1;
+ 			groups = 0;
++		} else if (matches(*argv, "nsid") == 0) {
++			lnsid = 1;
++			groups = 0;
+ 		} else if (strcmp(*argv, "all") == 0) {
+ 			groups = ~RTMGRP_TC;
+ 			prefix_banner=1;
+@@ -223,6 +235,9 @@ int do_ipmonitor(int argc, char **argv)
+ 		if (!preferred_family || preferred_family == AF_INET6)
+ 			groups |= nl_mgrp(RTNLGRP_IPV6_NETCONF);
+ 	}
++	if (lnsid) {
++		groups |= nl_mgrp(RTNLGRP_NSID);
++	}
+ 	if (file) {
+ 		FILE *fp;
+ 		fp = fopen(file, "r");
+@@ -236,6 +251,7 @@ int do_ipmonitor(int argc, char **argv)
+ 	if (rtnl_open(&rth, groups) < 0)
+ 		exit(1);
+ 	ll_init_map(&rth);
++	netns_map_init();
+ 
+ 	if (rtnl_listen(&rth, accept_msg, stdout) < 0)
+ 		exit(2);
+diff --git a/ip/ipnetns.c b/ip/ipnetns.c
+index 24df167..438d59b 100644
+--- a/ip/ipnetns.c
++++ b/ip/ipnetns.c
+@@ -14,10 +14,12 @@
+ #include <errno.h>
+ #include <unistd.h>
+ #include <ctype.h>
++#include <linux/limits.h>
+ 
+ #include <linux/net_namespace.h>
+ 
+ #include "utils.h"
++#include "hlist.h"
+ #include "ip_common.h"
+ #include "namespace.h"
+ 
+@@ -31,9 +33,13 @@ static int usage(void)
+ 	fprintf(stderr, "       ip netns pids NAME\n");
+ 	fprintf(stderr, "       ip [-all] netns exec [NAME] cmd ...\n");
+ 	fprintf(stderr, "       ip netns monitor\n");
++	fprintf(stderr, "       ip netns list-id\n");
+ 	exit(-1);
+ }
+ 
++/* This socket is used to get nsid */
++static struct rtnl_handle rtnsh = { .fd = -1 };
++
+ static int have_rtnl_getnsid = -1;
+ 
+ static int ipnetns_accept_msg(const struct sockaddr_nl *who,
+@@ -106,7 +112,7 @@ static int get_netnsid_from_name(const char *name)
+ 		return fd;
+ 
+ 	addattr32(&req.n, 1024, NETNSA_FD, fd);
+-	if (rtnl_talk(&rth, &req.n, 0, 0, &answer.n) < 0) {
++	if (rtnl_talk(&rtnsh, &req.n, 0, 0, &answer.n) < 0) {
+ 		close(fd);
+ 		return -2;
+ 	}
+@@ -129,6 +135,196 @@ static int get_netnsid_from_name(const char *name)
+ 	return -1;
+ }
+ 
++struct nsid_cache {
++	struct hlist_node	nsid_hash;
++	struct hlist_node	name_hash;
++	int			nsid;
++	char			name[NAME_MAX];
++};
++
++#define NSIDMAP_SIZE		128
++#define NSID_HASH_NSID(nsid)	(nsid & (NSIDMAP_SIZE - 1))
++#define NSID_HASH_NAME(name)	(namehash(name) & (NSIDMAP_SIZE - 1))
++
++static struct hlist_head	nsid_head[NSIDMAP_SIZE];
++static struct hlist_head	name_head[NSIDMAP_SIZE];
++
++static struct nsid_cache *netns_map_get_by_nsid(int nsid)
++{
++	uint32_t h = NSID_HASH_NSID(nsid);
++	struct hlist_node *n;
++
++	hlist_for_each(n, &nsid_head[h]) {
++		struct nsid_cache *c = container_of(n, struct nsid_cache,
++						    nsid_hash);
++		if (c->nsid == nsid)
++			return c;
++	}
++
++	return NULL;
++}
++
++static int netns_map_add(int nsid, char *name)
++{
++	struct nsid_cache *c;
++	uint32_t h;
++
++	if (netns_map_get_by_nsid(nsid) != NULL)
++		return -EEXIST;
++
++	c = malloc(sizeof(*c));
++	if (c == NULL) {
++		perror("malloc");
++		return -ENOMEM;
++	}
++	c->nsid = nsid;
++	strcpy(c->name, name);
++
++	h = NSID_HASH_NSID(nsid);
++	hlist_add_head(&c->nsid_hash, &nsid_head[h]);
++
++	h = NSID_HASH_NAME(name);
++	hlist_add_head(&c->name_hash, &name_head[h]);
++
++	return 0;
++}
++
++static void netns_map_del(struct nsid_cache *c)
++{
++	hlist_del(&c->name_hash);
++	hlist_del(&c->nsid_hash);
++	free(c);
++}
++
++void netns_map_init(void)
++{
++	static int initialized;
++	struct dirent *entry;
++	DIR *dir;
++	int nsid;
++
++	if (initialized || !ipnetns_have_nsid())
++		return;
++
++	if (rtnl_open(&rtnsh, 0) < 0) {
++		fprintf(stderr, "Cannot open rtnetlink\n");
++		exit(1);
++	}
++
++	dir = opendir(NETNS_RUN_DIR);
++	if (!dir)
++		return;
++
++	while ((entry = readdir(dir)) != NULL) {
++		if (strcmp(entry->d_name, ".") == 0)
++			continue;
++		if (strcmp(entry->d_name, "..") == 0)
++			continue;
++		nsid = get_netnsid_from_name(entry->d_name);
++
++		if (nsid >= 0)
++			netns_map_add(nsid, entry->d_name);
++	}
++	closedir(dir);
++	initialized = 1;
++}
++
++static int netns_get_name(int nsid, char *name)
++{
++	struct dirent *entry;
++	DIR *dir;
++	int id;
++
++	dir = opendir(NETNS_RUN_DIR);
++	if (!dir)
++		return -ENOENT;
++
++	while ((entry = readdir(dir)) != NULL) {
++		if (strcmp(entry->d_name, ".") == 0)
++			continue;
++		if (strcmp(entry->d_name, "..") == 0)
++			continue;
++		id = get_netnsid_from_name(entry->d_name);
++
++		if (nsid == id) {
++			strcpy(name, entry->d_name);
++			closedir(dir);
++			return 0;
++		}
++	}
++	closedir(dir);
++	return -ENOENT;
++}
++
++int print_nsid(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
++{
++	struct rtgenmsg *rthdr = NLMSG_DATA(n);
++	struct rtattr *tb[NETNSA_MAX+1];
++	int len = n->nlmsg_len;
++	FILE *fp = (FILE *)arg;
++	struct nsid_cache *c;
++	char name[NAME_MAX];
++	int nsid;
++
++	if (n->nlmsg_type != RTM_NEWNSID && n->nlmsg_type != RTM_DELNSID)
++		return 0;
++
++	len -= NLMSG_SPACE(sizeof(*rthdr));
++	if (len < 0) {
++		fprintf(stderr, "BUG: wrong nlmsg len %d in %s\n", len,
++			__func__);
++		return -1;
++	}
++
++	parse_rtattr(tb, NETNSA_MAX, NETNS_RTA(rthdr), len);
++	if (tb[NETNSA_NSID] == NULL) {
++		fprintf(stderr, "BUG: NETNSA_NSID is missing %s\n", __func__);
++		return -1;
++	}
++
++	if (n->nlmsg_type == RTM_DELNSID)
++		fprintf(fp, "Deleted ");
++
++	nsid = rta_getattr_u32(tb[NETNSA_NSID]);
++	fprintf(fp, "nsid %u ", nsid);
++
++	c = netns_map_get_by_nsid(nsid);
++	if (c != NULL) {
++		fprintf(fp, "(iproute2 netns name: %s)", c->name);
++		netns_map_del(c);
++	}
++
++	/* During 'ip monitor nsid', no chance to have new nsid in cache. */
++	if (c == NULL && n->nlmsg_type == RTM_NEWNSID)
++		if (netns_get_name(nsid, name) == 0) {
++			fprintf(fp, "(iproute2 netns name: %s)", name);
++			netns_map_add(nsid, name);
++		}
++
++	fprintf(fp, "\n");
++	fflush(fp);
++	return 0;
++}
++
++static int netns_list_id(int argc, char **argv)
++{
++	if (!ipnetns_have_nsid()) {
++		fprintf(stderr,
++			"RTM_GETNSID is not supported by the kernel.\n");
++		return -ENOTSUP;
++	}
++
++	if (rtnl_wilddump_request(&rth, AF_UNSPEC, RTM_GETNSID) < 0) {
++		perror("Cannot send dump request");
++		exit(1);
++	}
++	if (rtnl_dump_filter(&rth, print_nsid, stdout) < 0) {
++		fprintf(stderr, "Dump terminated\n");
++		exit(1);
++	}
++	return 0;
++}
++
+ static int netns_list(int argc, char **argv)
+ {
+ 	struct dirent *entry;
+@@ -577,6 +773,8 @@ static int netns_monitor(int argc, char **argv)
+ 
+ int do_netns(int argc, char **argv)
+ {
++	netns_map_init();
++
+ 	if (argc < 1)
+ 		return netns_list(0, NULL);
+ 
+@@ -584,6 +782,9 @@ int do_netns(int argc, char **argv)
+ 	    (matches(*argv, "lst") == 0))
+ 		return netns_list(argc-1, argv+1);
+ 
++	if ((matches(*argv, "list-id") == 0))
++		return netns_list_id(argc-1, argv+1);
++
+ 	if (matches(*argv, "help") == 0)
+ 		return usage();
+ 
+diff --git a/lib/ll_map.c b/lib/ll_map.c
+index fd7db55..a57a150 100644
+--- a/lib/ll_map.c
++++ b/lib/ll_map.c
+@@ -52,7 +52,7 @@ static struct ll_cache *ll_get_by_index(unsigned index)
+ 	return NULL;
+ }
+ 
+-static unsigned namehash(const char *str)
++unsigned namehash(const char *str)
+ {
+ 	unsigned hash = 5381;
+ 
+diff --git a/man/man8/ip-monitor.8 b/man/man8/ip-monitor.8
+index b6e8d1d..a710b34 100644
+--- a/man/man8/ip-monitor.8
++++ b/man/man8/ip-monitor.8
+@@ -32,7 +32,7 @@ command is the first in the command line and then the object list follows:
+ is the list of object types that we want to monitor.
+ It may contain
+ .BR link ", " address ", " route ", " mroute ", " prefix ", "
+-.BR neigh " and " netconf "."
++.BR neigh ", " netconf " and " nsid "."
+ If no
+ .B file
+ argument is given,
+diff --git a/man/man8/ip-netns.8 b/man/man8/ip-netns.8
+index 80a4ad1..c9b0fbc 100644
+--- a/man/man8/ip-netns.8
++++ b/man/man8/ip-netns.8
+@@ -42,6 +42,9 @@ ip-netns \- process network namespace management
+ .ti -8
+ .BR "ip netns monitor"
+ 
++.ti -8
++.BR "ip netns list-id"
++
+ .SH DESCRIPTION
+ A network namespace is logically another copy of the network stack,
+ with its own routes, firewall rules, and network devices.
+@@ -178,6 +181,13 @@ executing.
+ This command watches network namespace name addition and deletion events
+ and prints a line for each event it sees.
+ 
++.TP
++.B ip netns list-id - list network namespace ids (nsid)
++.sp
++Network namespace ids are used to identify a peer network namespace. This
++command displays nsid of the current network namespace and provides the
++corresponding iproute2 netns name (from /var/run/netns) if any.
++
+ .SH EXAMPLES
+ .PP
+ ip netns list
diff --git a/SOURCES/man-pages.patch b/SOURCES/man-pages.patch
index 08b626d..be91cf3 100644
--- a/SOURCES/man-pages.patch
+++ b/SOURCES/man-pages.patch
@@ -171,19 +171,3 @@ index 0000000..042dd3e
 +ifstat was written by Alexey Kuznetsov <kuznet@ms2.inr.ac.ru>.
 +.PP
 +This manual page was written by Petr Sabata <contyk@redhat.com>.
-diff --git a/man/man8/ss.8 b/man/man8/ss.8
-index e55dd0c..70ed85c 100644
---- a/man/man8/ss.8
-+++ b/man/man8/ss.8
-@@ -116,7 +116,7 @@ Find all local processes connected to X server.
- List all the tcp sockets in state FIN-WAIT-1 for our apache to network 193.233.7/24 and look at their timers.
- .SH SEE ALSO
- .BR ip (8),
--.BR /usr/share/doc/iproute-doc/ss.html " (package iproute�doc)"
-+.BR /usr/share/doc/iproute-doc-_VERSION_/ss.ps " (package iproute-doc)"
- .SH AUTHOR
- .I ss 
- was written by Alexey Kuznetosv, <kuznet@ms2.inr.ac.ru>.
--- 
-1.8.3.1
-
diff --git a/SPECS/iproute.spec b/SPECS/iproute.spec
index f4ab6c5..fdfafb9 100644
--- a/SPECS/iproute.spec
+++ b/SPECS/iproute.spec
@@ -2,7 +2,7 @@
 Summary:            Advanced IP routing and network device configuration tools
 Name:               iproute
 Version:            3.10.0
-Release:            21%{?dist}
+Release:            54%{?dist}
 Group:              Applications/System
 URL:                http://kernel.org/pub/linux/utils/net/%{name}2/
 Source0:            http://kernel.org/pub/linux/utils/net/%{name}2/%{name}2-%{version}.tar.gz
@@ -20,45 +20,114 @@ Patch8:             iproute2-3.8.0-unused-result.patch
 Patch9:             iproute2-3.10.0-xfrm-state-overflow.patch
 # rhbz#977844
 Patch10:            iproute2-3.11.0-tc-ok.patch
-# rhbz#1009860
-Patch11:            iproute2-3.11.0-iproute2-bridge-document-mdb.patch
-# rhbz#1011818, in upstream after 3.11.0
-Patch12:            iproute2-3.11.0-iproute2-bridge-Close-file-with-bridge-monitor-file.patch
 # rhbz#1024426
 Patch13:            iproute2-3.10.0-lnstat-interval.patch
-# rhbz#1017228
-Patch14:            iproute2-3.10.0-ipadress-fix-display-of-IPv6-peer-address.patch
-# rhbz#1024697
-Patch15:            iproute2-3.10.0-bridge-fdb-replace.patch
-# rhbz#979326
-Patch16:            iproute2-3.10.0-document-vlan.patch
 # rhbz#1032501
 Patch17:            iproute2-3.10.0-rtt.patch
-# rhbz#1024697
-Patch18:            iproute2-3.10.0-bridge-fdb-additional-man-changes.patch
-# rhbz#1040454
-Patch19:            iproute2-3.10.0-rtnl_send.patch
-# rhbz#1039855
-Patch20:            iproute2-3.10.0-vxlan-add-dstport-option.patch
-# rhbz#1067437
-Patch21:            iproute2-3.10.0-Add-destination-port-support-for-VXLAN.patch
-Patch22:            iproute2-3.10.0-Add-IPv6-support-to-VXLAN.patch
-# rhbz#1061593
-Patch23:            iproute2-3.10.0-Add-VF-link-state-control.patch
-# rhbz#1119180
-Patch24:            iproute2-3.16.0-addrgenmode.patch
 # rhbz#1034049
 Patch25:            iproute2-3.16.0-addrlabel.patch
 # rhbz#1091010
 Patch26:            iproute2-3.16.0-quickack.patch
 # rhbz#1044535
 Patch27:            iproute2-3.16.0-bpf.patch
+# Backport linux headers
+#
+#  * git diff v3.10.0..v4.0.0-26-g94f6653 include/linux
+#  * minor adaptation ip/xfrm_monitor.c
+#
+# Note: This is useful to avoid having to patch individual kernel header files.
+Patch28:          iproute2-3.10.0-linux.patch
+# Backport selected library functions
+Patch29:          iproute2-3.10.0-lib.patch
+# Backport 'ss' command from 4.0.0
+#
+# https://bugzilla.redhat.com/show_bug.cgi?id=1215006
+Patch30:          iproute2-3.10.0-ss.patch
+# Fix "ip -s xfrm state" segfault
+#
+# https://bugzilla.redhat.com/show_bug.cgi?id=1139173
+Patch31:            iproute2-3.10.0-1139173.patch
+# Option to operate on different namespace
+#
+# https://bugzilla.redhat.com/show_bug.cgi?id=1131928
+Patch32:            iproute2-3.10.0-tc.patch
+# Backport selected bridge features and documentation
+#
+# https://bugzilla.redhat.com/show_bug.cgi?id=1131928
+# https://bugzilla.redhat.com//show_bug.cgi?id=1009860
+# https://bugzilla.redhat.com//show_bug.cgi?id=1011818
+# https://bugzilla.redhat.com//show_bug.cgi?id=1024697
+# https://bugzilla.redhat.com//show_bug.cgi?id=1024697
+Patch33:            iproute2-3.10.0-bridge.patch
+# https://bugzilla.redhat.com/show_bug.cgi?id=1212026
+Patch35:            iproute2-3.10.0-xfrm.patch
+# https://bugzilla.redhat.com/show_bug.cgi?id=1198489
+Patch37:            iproute2-3.10.0-route.patch
+# https://bugzilla.redhat.com/show_bug.cgi?id=1219280
+Patch38:            0025-Consolidated-tunnel-support-fixes-for-ip6-gre-and-ip.patch
+# Backport selected ip-link and ip-address features
+#
+# https://bugzilla.redhat.com/show_bug.cgi?id=1040454
+# https://bugzilla.redhat.com/show_bug.cgi?id=1017228
+# https://bugzilla.redhat.com/show_bug.cgi?id=1039855
+# https://bugzilla.redhat.com/show_bug.cgi?id=1061593
+# https://bugzilla.redhat.com/show_bug.cgi?id=1067437
+# https://bugzilla.redhat.com/show_bug.cgi?id=1119180
+# https://bugzilla.redhat.com/show_bug.cgi?id=1198456
+# https://bugzilla.redhat.com/show_bug.cgi?id=1203646
+# https://bugzilla.redhat.com/show_bug.cgi?id=1218568
+#
+# Note: It proved very impractical to keep the patches
+# separate when importing new upstream features to
+# rhel-7.2 and therefore we are using a large patch
+# instead.
+Patch39:            iproute2-3.10.0-address.patch
+# Backport selected ip-netns features
+#
+# https://bugzilla.redhat.com/show_bug.cgi?id=1213869
+Patch40:            iproute2-3.10.0-netns.patch
+# Backport post-4.0.0 netns patch
+Patch41:            iproute2-4.0.0-netns.patch
+# https://bugzilla.redhat.com/show_bug.cgi?id=1169874
+Patch42:            iproute2-3.10.0-ip-rule.patch
+# https://bugzilla.redhat.com/show_bug.cgi?id=1247315
+Patch43:            iproute2-3.10.0-backport-additional-INET_DIAG-flags-in-inet_diag.h.patch
+Patch44:            iproute2-3.10.0-ss-print-value-of-IPV6_V6ONLY-socket-option-if-set.patch
+# https://bugzilla.redhat.com/show_bug.cgi?id=1241486
+Patch45:            iproute2-3.10.0-pkt_sched-fq-Fair-Queue-packet-scheduler.patch
+Patch46:            iproute2-3.10.0-fq-allow-options-of-fair-queue-set-to-0U.patch
+# https://bugzilla.redhat.com/show_bug.cgi?id=1244851
+Patch47:            iproute2-3.10.0-fix-ip-tunnel-command-for-vti-tunnels-with-io-key-gi.patch
+# https://bugzilla.redhat.com/show_bug.cgi?id=1155116
+Patch48:            iproute2-3.10.0-man-ip-Add-missing-details-option.patch
+# https://bugzilla.redhat.com/show_bug.cgi?id=1251451
+Patch49:            iproute2-3.10.0-Fix-changing-tunnel-remote-and-local-address-to-any.patch
+# https://bugzilla.redhat.com/show_bug.cgi?id=1213869
+Patch50:            iproute2-3.10.0-ip-xfrm-monitor-allows-to-monitor-in-several-netns.patch
+# https://bugzilla.redhat.com/show_bug.cgi?id=1215006
+Patch51:            iproute2-3.10.0-misc-ss-don-t-imply-a-when-A-was-specified.patch
+# https://bugzilla.redhat.com/show_bug.cgi?id=1251070
+Patch52:            iproute2-3.10.0-Fix-multiple-programming-errors.patch
+# https://bugzilla.redhat.com/show_bug.cgi?id=1198456
+Patch53:            iproute2-3.10.0-ip-link-fix-minor-typo-in-manpage.patch
+# https://bugzilla.redhat.com/show_bug.cgi?id=1210402
+# https://bugzilla.redhat.com/show_bug.cgi?id=1213869
+Patch54:            iproute2-3.10.0-ip-link-fix-and-extend-documentation.patch
+# https://bugzilla.redhat.com/show_bug.cgi?id=1254095
+Patch55:            iproute2-3.10.0-bridge-Add-master-device-name-to-bridge-fdb-show.patch
+# https://bugzilla.redhat.com/show_bug.cgi?id=1255316
+Patch56:            iproute2-3.10.0-tc-fix-for-qdiscs-without-options.patch
+# https://bugzilla.redhat.com/show_bug.cgi?id=1212026
+Patch57:            iproute2-3.10.0-Revert-Changes-for-BZ-1212026.patch
+# https://bugzilla.redhat.com/show_bug.cgi?id=1241486
+Patch58:            iproute-3.10.0-man-tc.8-mention-Fair-Queue-scheduler.patch
+
 License:            GPLv2+ and Public Domain
 BuildRequires:      bison
 BuildRequires:      flex
 BuildRequires:      iptables-devel >= 1.4.5
 BuildRequires:      libdb-devel
-BuildRequires:      libnl-devel
+BuildRequires:      libselinux-devel
 BuildRequires:      linuxdoc-tools
 BuildRequires:      pkgconfig
 BuildRequires:      psutils
@@ -109,23 +178,41 @@ sed -i "s/_VERSION_/%{version}/" man/man8/ss.8
 %patch8 -p1 -b .unused-result
 %patch9 -p1 -b .xfrm-state
 %patch10 -p1 -b .ok
-%patch11 -p1 -b .bridge_mdb_doc
-%patch12 -p1 -b .bridge_monitor_close
 %patch13 -p1 -b .lnstat-interval
-%patch14 -p1 -b .ipadress-fix-display-of-IPv6-peer-address
-%patch15 -p1 -b .bridge-fdb-replace
-%patch16 -p1 -b .document-vlan
 %patch17 -p1 -b .rtt
-%patch18 -p1 -b .fdb-man
-%patch19 -p1
-%patch20 -p1
-%patch21 -p1
-%patch22 -p1
-%patch23 -p1
-%patch24 -p1
 %patch25 -p1
 %patch26 -p1
 %patch27 -p1
+%patch28 -p1
+%patch29 -p1
+%patch30 -p1
+%patch31 -p1
+%patch32 -p1
+%patch33 -p1
+%patch35 -p1
+%patch37 -p1
+%patch38 -p1
+%patch39 -p1
+%patch40 -p1
+%patch41 -p1
+%patch42 -p1
+%patch43 -p1
+%patch44 -p1
+%patch45 -p1
+%patch46 -p1
+%patch47 -p1
+%patch48 -p1
+%patch49 -p1
+%patch50 -p1
+%patch51 -p1
+%patch52 -p1
+%patch53 -p1
+%patch54 -p1
+%patch55 -p1
+%patch56 -p1
+%patch57 -p1
+%patch58 -p1
+
 sed -i 's/^LIBDIR=/LIBDIR?=/' Makefile
 sed -i 's/iproute-doc/%{name}-%{version}/' man/man8/lnstat.8
 
@@ -226,6 +313,126 @@ done
 %{_includedir}/libnetlink.h
 
 %changelog
+* Thu Sep 17 2015 Phil Sutter - 3.10.0-54
+- Related: #1241486 - backport: tc: fq scheduler - add missing documentation
+
+* Thu Sep 03 2015 Phil Sutter - 3.10.0-53
+- Related: #1212026 - [6wind 7.2 Feat]: backport: ipxfrm: unable to configure
+  SPD hash table - reverted this backport due to unmet dependencies
+
+* Mon Aug 24 2015 Phil Sutter - 3.10.0-52
+- Resolves: #1254095 - bridge: Add master device name to bridge fdb show
+- Resolves: #1255316 - tc does not allow to attach pfifo_fast qdisc
+- Related: #1251070 - Fix multiple programming errors in iproute package
+
+* Sun Aug 16 2015 Phil Sutter - 3.10.0-51
+- Resolves: bz#1251451 - can't change the remote/local address of tunnel
+  interface to "any" in ipip mode
+- Related: #1213869 - [6wind 7.2 Feat]: backport: iproute2: various netns
+  features
+- Related: #1215006 - [RFE] backport current version of the ss command
+- Resolves: #1251070 - Fix multiple programming errors in iproute package
+- Related: #1198456 - backport: dynamic precision, human readable, and IEC
+  output to ip stats
+- Related: #1210402 - [6wind 7.2 Feat]: backport: vxlan: unable to configure
+  UDP checksums
+- Related: #1213869 - [6wind 7.2 Feat]: backport: iproute2: various netns
+  features
+
+* Fri Aug 07 2015 Phil Sutter - 3.10.0-50
+- Resolves: #1244851 - vti tunnel does not work
+- Resolves: #1155116 - iproute2: implement "-d" option for "ip mon"
+
+* Thu Aug 06 2015 Phil Sutter - 3.10.0-49
+- Resolves: bz#1241486 - backport: tc: fq scheduler
+- Related: #1215006 - backport current version of the ss command
+
+* Wed Aug 05 2015 Phil Sutter - 3.10.0-48
+- Related: #1215006 - backport current version of the ss command
+- Resolves: #1247315 - Fix limitation in iproute/ss regarding dual-stack sockets
+
+* Mon Aug 03 2015 Phil Sutter - 3.10.0-47
+- Related: #1215006 - backport current version of the ss command
+- Related: #1219280 - backport: iproute2: vti6 support
+
+* Wed Jul 08 2015 Pavel Šimerda <psimerda@redhat.com> - 3.10.0-46
+- Related: #1198456 - add missing parts
+
+* Wed Jul 08 2015 Pavel Šimerda <psimerda@redhat.com> - 3.10.0-45
+- Related: #1213869 - add support for 'ip -all netns'
+
+* Wed Jul 08 2015 Pavel Šimerda <psimerda@redhat.com> - 3.10.0-44
+- Related: #1176180 - put back addrgenmode docs
+
+* Wed Jul 08 2015 Pavel Šimerda <psimerda@redhat.com> - 3.10.0-43
+- Related: #1131928 - make netns docs consistent
+
+* Wed Jul 08 2015 Pavel Šimerda <psimerda@redhat.com> - 3.10.0-42
+- Resolves: #1169901 - ip rule help output contains action reject, but this
+  action does not work
+
+* Tue Jul 07 2015 Pavel Šimerda <psimerda@redhat.com> - 3.10.0-41
+- Resolves: #1169874 - ip rule command allows to remove rule with priority 0
+
+* Tue Jul 07 2015 Pavel Šimerda <psimerda@redhat.com> - 3.10.0-40
+- Resolves: #1042802 - make 'ip -d monitor' consistent with 'ip -d link'
+
+* Thu Jun 04 2015 Pavel Šimerda <psimerda@redhat.com> - 3.10.0-39
+- Resolves: #1228166 - remove redundant libnl-devel build dependency
+
+* Tue Jun 02 2015 Pavel Šimerda <psimerda@redhat.com> - 3.10.0-38
+- Resolves: #1131473 - backport: implement -s option for ip a
+
+* Tue Jun 02 2015 Pavel Šimerda <psimerda@redhat.com> - 3.10.0-37
+- Resolves: #1213869 - backport: iproute2: unable to manage nsid
+
+* Fri May 29 2015 Pavel Šimerda <psimerda@redhat.com> - 3.10.0-36
+- Resolves: #1224970 - backport: ipv6: support noprefixroute and mngtmpaddr
+
+* Thu May 28 2015 Pavel Šimerda <psimerda@redhat.com> - 3.10.0-35
+- Related: #1198456 - refactor patchset thoroughly
+
+* Mon May 25 2015 Pavel Šimerda <psimerda@redhat.com> - 3.10.0-34
+- Resolves: #1176684 - backport: ip xfrm monitor all does not work
+
+* Mon May 25 2015 Pavel Šimerda <psimerda@redhat.com> - 3.10.0-33
+- Resolves: #1219280 - backport: iproute2: vti6 support
+
+* Wed May 20 2015 Pavel Šimerda <psimerda@redhat.com> - 3.10.0-32
+- Resolves: #1198489 - backport: "ip route del" without arguments should print
+  help
+
+* Thu May 14 2015 Pavel Šimerda <psimerda@redhat.com> - 3.10.0-31
+- Resolves: #1218568 - backport: iproute2: query_rss command is missing
+
+* Thu May 14 2015 Pavel Šimerda <psimerda@redhat.com> - 3.10.0-30
+- Resolves: #1212026 - backport: ipxfrm: unable to configure SPD hash table
+
+* Wed May 13 2015 Pavel Šimerda <psimerda@redhat.com> - 3.10.0-29
+- Resolves: #1210402 - backport: vxlan: unable to configure UDP checksums
+
+* Wed May 13 2015 Pavel Šimerda <psimerda@redhat.com> - 3.10.0-28
+- Resolves: #1131928 - backport: introduce option to ip to operate on a
+  different namespace
+
+* Wed May 13 2015 Pavel Šimerda <psimerda@redhat.com> - 3.10.0-27
+- Resolves: #1198456 - make sure the patch is applied
+
+* Tue Apr 28 2015 Pavel Šimerda <psimerda@redhat.com> - 3.10.0-26
+- Resolves: #1198456 - backport changes in link statistics
+
+* Tue Apr 28 2015 Pavel Šimerda <psimerda@redhat.com>
+- Resolves: #1139173 - ip -s xfrm state crashes with segfault
+
+* Tue Apr 28 2015 Pavel Šimerda <psimerda@redhat.com> - 3.10.0-24
+- Resolves: #1215006 - backport current version of the ss command
+
+* Fri Apr 17 2015 Pavel Šimerda <psimerda@redhat.com> - 3.10.0-23
+- Resolves: #1203646 - backport VXLAN-GBP
+
+* Thu Apr 16 2015 Pavel Šimerda <psimerda@redhat.com> - 3.10.0-22
+- Resolves: #1176180 - ip -d link show: print addrgenmode
+
 * Fri Oct 24 2014 Pavel Šimerda <psimerda@redhat.com> - 3.10.0-21
 - Related: #1119180 - improve addrgen documentation