From a4b897d5620d3260fc653901749adc111b36ef1d Mon Sep 17 00:00:00 2001 From: CentOS Sources Date: Nov 19 2015 16:09:10 +0000 Subject: import iproute-3.10.0-54.el7 --- 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 +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 ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#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 ++ * Saurabh Mohan Modified link_gre.c for VTI ++ * Steffen Klassert Modified link_vti.c for IPv6 ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#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 +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 +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 + +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?= -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 ---- - 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?= -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 ---- - 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 +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 +Acked-by: Nicolas Dichtel +(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 +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 +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 + +commit e0dce0e5dc363b7e307984706c130f6ee769259b +Author: Phil Sutter +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 + +commit 532ca40a52d4103816f2e50690a02e9dd6c1abe5 +Author: Phil Sutter +Date: Thu Aug 6 14:24:33 2015 +0200 + + misc/ss: simplify buffer realloc, fix checking realloc failure + + Signed-off-by: Phil Sutter + +commit b95d28c380c945ac760b128403dc82279cb9cc39 +Author: Phil Sutter +Date: Thu Aug 6 14:24:34 2015 +0200 + + misc/ss: add missing fclose() calls + + Signed-off-by: Phil Sutter + +commit 5950ba914e12b9c942e45e2dda6b1732a3efa058 +Author: Phil Sutter +Date: Thu Aug 6 14:24:35 2015 +0200 + + lib/namespace: don't leak fd in error case + + Signed-off-by: Phil Sutter + +commit a02371fb3831c8d3d9d53209f2389b250a1fb804 +Author: Phil Sutter +Date: Thu Aug 6 14:24:36 2015 +0200 + + misc/ss: fix memory leak in user_ent_hash_build() + + Signed-off-by: Phil Sutter + +commit 9e5ba07f491037f51472915477575d3e3fe0adcb +Author: Phil Sutter +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 + +commit b765eda924363caec99b760d8cff815ecf4a8de6 +Author: Nicolas Dichtel +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 +--- + 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 + #include ++#include + #include + #include + +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 +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 + .br +-Manpage revised by Christophe Gouault +-.br + Manpage revised by Nicolas Dichtel +-- +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 +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 + #include + #include ++#include + + #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 +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 " ++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 +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 +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 +Signed-off-by: Roopa Prabhu +--- + 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 +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 " ++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?= -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 ---- - 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 +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 +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 +Signed-off-by: Yang Yingliang +--- + 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 + #include + #include ++#include + + #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?= +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 +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 +--- + 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 +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 +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 +Date: Wed May 20 16:19:57 2015 +0200 + + man: update ip monitor page + + Add label option. + + Signed-off-by: Nicolas Dichtel + +commit 0628cddd9d5c0cb9ed0e0aba136e50de93487150 +Author: Nicolas Dichtel +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 + +commit 3b0006f8183e09eda5f2f11667f2b9d36fcd8c16 +Author: Nicolas Dichtel +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 + +commit 449b824ad19679f66164e1e97513f36eee0d004e +Author: Nicolas Dichtel +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 + +commit b6ec53e3008aaf2acc3db146e24bc9a365e4b6c2 +Author: Nicolas Dichtel +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 + +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: 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 ++.br ++Manpage revised by Nicolas Dichtel +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 + .br + Manpage revised by Christophe Gouault ++.br ++Manpage revised by Nicolas Dichtel +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 +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 ++#include ++#include ++#include ++ ++#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 + #include + #include ++#include + + #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 ++#include ++ ++#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 ++#include ++ ++/* 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 + #include +@@ -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 + * ++ * 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 + +@@ -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 +- ++#include + + /* + * 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 + +-/* 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//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 ++#include ++#include + + #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 ++ * ++ * Sources: ++ * IPv6 Program Interfaces for BSD Systems ++ * ++ * ++ * Advanced Sockets API for IPv6 ++ * ++ * ++ * 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 ++#include ++ ++/* ++ * 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 ++ * 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 ++#include ++ ++/* 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 ++ * ++ * 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 ++ * ++ * 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 ++ ++#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 ++#include ++ ++#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 ++ ++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 + + #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 ++ * ++ * 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 ++ ++#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 + #include + + /* 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 + #include + #include ++#include + #include ++ + #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 +Date: Mon, 27 Oct 2014 17:22:58 +0200 +Subject: [PATCH] man ip: Add missing '-details' option + +Signed-off-by: Vadim Kochan +--- + 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 " + 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 +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 +--- + 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 +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 + #include + ++#include ++ + #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 " ++.BR "\-n" , " \-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 +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 +--- + 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 ++ * ++ * 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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#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 +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 + +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 +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 +--- + 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?= +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 @@ +
+ + 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 = ¤t_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(¤t_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(¤t_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(¤t_filter, AF_INET); + break; + case '6': +- preferred_family = AF_INET6; ++ filter_af_set(¤t_filter, AF_INET6); + break; + case '0': +- preferred_family = AF_PACKET; ++ filter_af_set(¤t_filter, AF_PACKET); + break; + case 'f': + if (strcmp(optarg, "inet") == 0) +- preferred_family = AF_INET; ++ filter_af_set(¤t_filter, AF_INET); + else if (strcmp(optarg, "inet6") == 0) +- preferred_family = AF_INET6; ++ filter_af_set(¤t_filter, AF_INET6); + else if (strcmp(optarg, "link") == 0) +- preferred_family = AF_PACKET; ++ filter_af_set(¤t_filter, AF_PACKET); + else if (strcmp(optarg, "unix") == 0) +- preferred_family = AF_UNIX; ++ filter_af_set(¤t_filter, AF_UNIX); + else if (strcmp(optarg, "netlink") == 0) +- preferred_family = AF_NETLINK; ++ filter_af_set(¤t_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(¤t_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(¤t_filter.f, argc, argv, filter_fp)) +- usage(); + break; + } + argc--; argv++; + } + ++ if (do_default) { ++ state_filter = state_filter ? state_filter : SS_CONN; ++ filter_default_dbs(¤t_filter); ++ filter_merge(¤t_filter, ¤t_filter, state_filter); ++ } else { ++ filter_merge(¤t_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(¤t_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(¤t_filter, IPPROTO_TCP); + if (current_filter.dbs & (1<<DCCP_DB)) + tcp_show(¤t_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