diff -Nru iproute2-3.10.0/bridge/fdb.c iproute2-3.12.0/bridge/fdb.c --- iproute2-3.10.0/bridge/fdb.c 2013-07-16 17:06:36.000000000 +0000 +++ iproute2-3.12.0/bridge/fdb.c 2013-11-23 01:10:33.000000000 +0000 @@ -30,7 +30,7 @@ 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 @@ 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 -Nru iproute2-3.10.0/bridge/monitor.c iproute2-3.12.0/bridge/monitor.c --- iproute2-3.10.0/bridge/monitor.c 2013-07-16 17:06:36.000000000 +0000 +++ iproute2-3.12.0/bridge/monitor.c 2013-11-23 01:10:33.000000000 +0000 @@ -132,12 +132,15 @@ 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 -Nru iproute2-3.10.0/debian/changelog iproute2-3.12.0/debian/changelog --- iproute2-3.10.0/debian/changelog 2014-03-27 10:38:04.000000000 +0000 +++ iproute2-3.12.0/debian/changelog 2014-02-26 13:38:16.000000000 +0000 @@ -1,17 +1,30 @@ -iproute2 (3.10.0-1ubuntu1ppa1) precise; urgency=low +iproute2 (3.12.0-2~ctools0) precise; urgency=medium - * Backport from Ubuntu saucy to precise. + * New update for the Ubuntu Cloud Archive. - -- Simon Pasquier Thu, 27 Mar 2014 10:52:46 +0100 + -- Scott Moser Wed, 26 Feb 2014 08:38:16 -0500 -iproute2 (3.10.0-1ubuntu1) saucy; urgency=low +iproute2 (3.12.0-2) unstable; urgency=medium - * Merge from Debian unstable. Remaining changes: - - Disable Werror for now (based on a similar change done in Fedora), - this prevents a build failure caused by ss.c not checking the return - values of several fgets and fscanf. + * Add build-dependency on texlive-fonts-recommended (Closes: #738397) - -- Stéphane Graber Mon, 19 Aug 2013 16:25:11 +0200 + -- Andreas Henriksson Wed, 12 Feb 2014 22:18:40 +0100 + +iproute2 (3.12.0-1) unstable; urgency=low + + * Improve removal comment in transitional packages descriptions + (Closes: #708823) + * Imported Upstream version 3.12.0 (aka snapshot 20131122) + - ss now avoids negative numbers in malloc, partially fixes #511720 + - gretap now listed in help output and manpage (Closes: #582675) + + -- Andreas Henriksson Tue, 26 Nov 2013 00:43:35 +0100 + +iproute2 (3.11.0-1) unstable; urgency=low + + * Imported Upstream version 3.11.0 (aka snapshot 20130903) + + -- Andreas Henriksson Wed, 04 Sep 2013 21:21:03 +0200 iproute2 (3.10.0-1) unstable; urgency=low @@ -23,14 +36,6 @@ -- Andreas Henriksson Wed, 24 Jul 2013 12:23:53 +0200 -iproute2 (3.9.0-5ubuntu1) saucy; urgency=low - - * Disable Werror for now (based on a similar change done in Fedora), - this prevents a build failure caused by ss.c not checking the return - values of several fgets and fscanf. - - -- Stéphane Graber Tue, 09 Jul 2013 18:17:59 -0400 - iproute2 (3.9.0-5) unstable; urgency=low * Cherry-pick patch from upstream to fix build on x32. @@ -1073,3 +1078,6 @@ -- Tom Lees Mon, 30 Dec 1996 11:12:23 +0000 +Local variables: +mode: debian-changelog +End: diff -Nru iproute2-3.10.0/debian/control iproute2-3.12.0/debian/control --- iproute2-3.10.0/debian/control 2014-03-27 09:45:35.000000000 +0000 +++ iproute2-3.12.0/debian/control 2014-02-12 21:17:16.000000000 +0000 @@ -1,8 +1,7 @@ Source: iproute2 Section: net Priority: optional -Maintainer: Ubuntu Developers -XSBC-Original-Maintainer: Debian iproute2 Maintainers +Maintainer: Debian iproute2 Maintainers Uploaders: Andreas Henriksson , Alexander Wirt Homepage: http://www.linux-foundation.org/en/Net:Iproute2 Vcs-Browser: http://git.debian.org/?p=collab-maint/pkg-iproute.git @@ -10,6 +9,7 @@ Standards-Version: 3.9.4 Build-Depends: texlive-latex-base, texlive-latex-recommended, + texlive-fonts-recommended, iptables-dev, libatm1-dev, libdb-dev, @@ -57,7 +57,8 @@ Section: oldlibs Description: transitional dummy package for iproute2 This is a transitional dummy package to get upgrading systems to install - the iproute2 package. It can safely be removed. + the iproute2 package. It can safely be removed once no other package + depends on it. Package: iproute-doc Depends: iproute2-doc, ${misc:Depends} @@ -65,4 +66,5 @@ Section: oldlibs Description: transitional dummy package for iproute2-doc This is a transitional dummy package to get upgrading systems to install - the iproute2-doc package. It can safely be removed. + the iproute2-doc package. It can safely be removed once no other package + depends on it. diff -Nru iproute2-3.10.0/debian/patches/0006-fix-warn_unused_result.patch iproute2-3.12.0/debian/patches/0006-fix-warn_unused_result.patch --- iproute2-3.10.0/debian/patches/0006-fix-warn_unused_result.patch 2014-03-27 09:45:35.000000000 +0000 +++ iproute2-3.12.0/debian/patches/0006-fix-warn_unused_result.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,17 +0,0 @@ -Change taken from Fedora, Werror currently causes a build failure -because of several cases of unchecked return value for fscanf fgets in -ss.c - -Index: iproute2/Makefile -=================================================================== ---- iproute2.orig/Makefile 2013-07-09 18:08:14.811170000 -0400 -+++ iproute2/Makefile 2013-07-09 18:08:49.333718363 -0400 -@@ -30,7 +30,7 @@ - HOSTCC = gcc - DEFINES += -D_GNU_SOURCE - CCOPTS = -O2 --WFLAGS := -Wall -Wstrict-prototypes -Werror -Wmissing-prototypes -+WFLAGS := -Wall -Wstrict-prototypes -Wmissing-prototypes - WFLAGS += -Wmissing-declarations -Wold-style-definition - - CFLAGS = $(WFLAGS) $(CCOPTS) -I../include $(DEFINES) diff -Nru iproute2-3.10.0/debian/patches/series iproute2-3.12.0/debian/patches/series --- iproute2-3.10.0/debian/patches/series 2014-03-27 09:45:35.000000000 +0000 +++ iproute2-3.12.0/debian/patches/series 2014-02-12 21:09:06.000000000 +0000 @@ -1,3 +1,2 @@ 0001-Add-moo-feature.patch 0002-txtdocs.patch -0006-fix-warn_unused_result.patch diff -Nru iproute2-3.10.0/doc/ip-cref.tex iproute2-3.12.0/doc/ip-cref.tex --- iproute2-3.10.0/doc/ip-cref.tex 2013-07-16 17:06:36.000000000 +0000 +++ iproute2-3.12.0/doc/ip-cref.tex 2013-11-23 01:10:33.000000000 +0000 @@ -2542,13 +2542,15 @@ the \verb|monitor| command is the first in the command line and then the object list follows: \begin{verbatim} - ip monitor [ file FILE ] [ all | OBJECT-LIST ] + ip monitor [ file FILE ] [ all | OBJECT-LIST ] [ label ] \end{verbatim} -\verb|OBJECT-LIST| is the list of object types that we want to monitor. -It may contain \verb|link|, \verb|address| and \verb|route|. -If no \verb|file| argument is given, \verb|ip| opens RTNETLINK, -listens on it and dumps state changes in the format described -in previous sections. +\verb|OBJECT-LIST| is the list of object types that we want to +monitor. It may contain \verb|link|, \verb|address| and \verb|route|. +Specifying \verb|label| indicates that output lines should be labelled +with the type of object being printed --- this happens by default if +\verb|all| is specified. If no \verb|file| argument is given, +\verb|ip| opens RTNETLINK, listens on it and dumps state changes in +the format described in previous sections. If a file name is given, it does not listen on RTNETLINK, but opens the file containing RTNETLINK messages saved in binary format diff -Nru iproute2-3.10.0/include/linux/fib_rules.h iproute2-3.12.0/include/linux/fib_rules.h --- iproute2-3.10.0/include/linux/fib_rules.h 2013-07-16 17:06:36.000000000 +0000 +++ iproute2-3.12.0/include/linux/fib_rules.h 2013-11-23 01:10:33.000000000 +0000 @@ -44,8 +44,8 @@ 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 -Nru iproute2-3.10.0/include/linux/gen_stats.h iproute2-3.12.0/include/linux/gen_stats.h --- iproute2-3.10.0/include/linux/gen_stats.h 2013-07-16 17:06:36.000000000 +0000 +++ iproute2-3.12.0/include/linux/gen_stats.h 2013-11-23 01:10:33.000000000 +0000 @@ -9,6 +9,7 @@ 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_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 -Nru iproute2-3.10.0/include/linux/if_arp.h iproute2-3.12.0/include/linux/if_arp.h --- iproute2-3.10.0/include/linux/if_arp.h 2013-07-16 17:06:36.000000000 +0000 +++ iproute2-3.12.0/include/linux/if_arp.h 2013-11-23 01:10:33.000000000 +0000 @@ -93,6 +93,7 @@ #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_VOID 0xFFFF /* Void type, nothing is known */ #define ARPHRD_NONE 0xFFFE /* zero header length */ diff -Nru iproute2-3.10.0/include/linux/if_bridge.h iproute2-3.12.0/include/linux/if_bridge.h --- iproute2-3.10.0/include/linux/if_bridge.h 2013-07-16 17:06:36.000000000 +0000 +++ iproute2-3.12.0/include/linux/if_bridge.h 2013-11-23 01:10:33.000000000 +0000 @@ -14,6 +14,7 @@ #define _LINUX_IF_BRIDGE_H #include +#include #define SYSFS_BRIDGE_ATTR "bridge" #define SYSFS_BRIDGE_FDB "brforward" @@ -88,7 +89,7 @@ }; struct __fdb_entry { - __u8 mac_addr[6]; + __u8 mac_addr[ETH_ALEN]; __u8 port_no; __u8 is_local; __u32 ageing_timer_value; diff -Nru iproute2-3.10.0/include/linux/if_link.h iproute2-3.12.0/include/linux/if_link.h --- iproute2-3.10.0/include/linux/if_link.h 2013-07-16 17:06:36.000000000 +0000 +++ iproute2-3.12.0/include/linux/if_link.h 2013-11-23 01:10:33.000000000 +0000 @@ -143,6 +143,7 @@ IFLA_NUM_TX_QUEUES, IFLA_NUM_RX_QUEUES, IFLA_CARRIER, + IFLA_PHYS_PORT_ID, __IFLA_MAX }; @@ -219,6 +220,8 @@ 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_MAX }; #define IFLA_BRPORT_MAX (__IFLA_BRPORT_MAX - 1) @@ -309,6 +312,8 @@ 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) @@ -334,6 +339,7 @@ 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, }; @@ -360,6 +366,18 @@ __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 -Nru iproute2-3.10.0/include/linux/if_tun.h iproute2-3.12.0/include/linux/if_tun.h --- iproute2-3.10.0/include/linux/if_tun.h 2013-07-16 17:06:36.000000000 +0000 +++ iproute2-3.12.0/include/linux/if_tun.h 2013-11-23 01:10:33.000000000 +0000 @@ -56,6 +56,8 @@ #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) /* TUNSETIFF ifr flags */ #define IFF_TUN 0x0001 @@ -68,6 +70,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 -Nru iproute2-3.10.0/include/linux/pkt_sched.h iproute2-3.12.0/include/linux/pkt_sched.h --- iproute2-3.10.0/include/linux/pkt_sched.h 2013-07-16 17:06:36.000000000 +0000 +++ iproute2-3.12.0/include/linux/pkt_sched.h 2013-11-23 01:10:33.000000000 +0000 @@ -73,9 +73,17 @@ #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; @@ -736,4 +744,45 @@ }; }; +/* 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,/* for sockets with unspecified sk_rate, + * use the following rate + */ + + TCA_FQ_FLOW_MAX_RATE, /* per flow max rate */ + + TCA_FQ_BUCKETS_LOG, /* log2(number of buckets) */ + __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; +}; #endif diff -Nru iproute2-3.10.0/include/linux/rtnetlink.h iproute2-3.12.0/include/linux/rtnetlink.h --- iproute2-3.10.0/include/linux/rtnetlink.h 2013-07-16 17:06:36.000000000 +0000 +++ iproute2-3.12.0/include/linux/rtnetlink.h 2013-11-23 01:10:33.000000000 +0000 @@ -386,6 +386,8 @@ #define RTAX_RTO_MIN RTAX_RTO_MIN RTAX_INITRWND, #define RTAX_INITRWND RTAX_INITRWND + RTAX_QUICKACK, +#define RTAX_QUICKACK RTAX_QUICKACK __RTAX_MAX }; diff -Nru iproute2-3.10.0/include/linux/tc_act/tc_defact.h iproute2-3.12.0/include/linux/tc_act/tc_defact.h --- iproute2-3.10.0/include/linux/tc_act/tc_defact.h 1970-01-01 00:00:00.000000000 +0000 +++ iproute2-3.12.0/include/linux/tc_act/tc_defact.h 2013-11-23 01:10:33.000000000 +0000 @@ -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 -Nru iproute2-3.10.0/include/linux/tcp.h iproute2-3.12.0/include/linux/tcp.h --- iproute2-3.10.0/include/linux/tcp.h 2013-07-16 17:06:36.000000000 +0000 +++ iproute2-3.12.0/include/linux/tcp.h 2013-11-23 01:10:33.000000000 +0000 @@ -111,6 +111,7 @@ #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; diff -Nru iproute2-3.10.0/include/rt_names.h iproute2-3.12.0/include/rt_names.h --- iproute2-3.10.0/include/rt_names.h 2013-07-16 17:06:36.000000000 +0000 +++ iproute2-3.12.0/include/rt_names.h 2013-11-23 01:10:33.000000000 +0000 @@ -8,6 +8,7 @@ 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); diff -Nru iproute2-3.10.0/include/SNAPSHOT.h iproute2-3.12.0/include/SNAPSHOT.h --- iproute2-3.10.0/include/SNAPSHOT.h 2013-07-16 17:06:36.000000000 +0000 +++ iproute2-3.12.0/include/SNAPSHOT.h 2013-11-23 01:10:33.000000000 +0000 @@ -1 +1 @@ -static const char SNAPSHOT[] = "130716"; +static const char SNAPSHOT[] = "131122"; diff -Nru iproute2-3.10.0/include/utils.h iproute2-3.12.0/include/utils.h --- iproute2-3.10.0/include/utils.h 2013-07-16 17:06:36.000000000 +0000 +++ iproute2-3.12.0/include/utils.h 2013-11-23 01:10:33.000000000 +0000 @@ -151,6 +151,7 @@ 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 -Nru iproute2-3.10.0/ip/ip6tunnel.c iproute2-3.12.0/ip/ip6tunnel.c --- iproute2-3.10.0/ip/ip6tunnel.c 2013-07-16 17:06:36.000000000 +0000 +++ iproute2-3.12.0/ip/ip6tunnel.c 2013-11-23 01:10:33.000000000 +0000 @@ -48,11 +48,12 @@ 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 | 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 @@ 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 @@ 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.\n", _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]; @@ -124,6 +146,9 @@ 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; @@ -202,6 +227,60 @@ 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 +291,7 @@ 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 +309,7 @@ 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 +323,8 @@ * @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 +342,7 @@ (!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 +366,7 @@ 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 +391,12 @@ 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 +427,7 @@ 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 +450,44 @@ static int do_add(int cmd, int argc, char **argv) { - struct ip6_tnl_parm p; + struct ip6_tnl_parm2 p; 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); + switch (p.proto) { + case IPPROTO_IPIP: + case IPPROTO_IPV6: + return tnl_add_ioctl(cmd, "ip6tnl0", p.name, &p); + case IPPROTO_GRE: + return tnl_add_ioctl(cmd, "ip6gre0", p.name, &p); + default: + fprintf(stderr, "cannot determine tunnel mode (ip6ip6, ipip6 or gre)\n"); + } + return -1; } static int do_del(int argc, char **argv) { - struct ip6_tnl_parm p; + struct ip6_tnl_parm2 p; 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); + switch (p.proto) { + case IPPROTO_IPIP: + case IPPROTO_IPV6: + return tnl_del_ioctl("ip6tnl0", p.name, &p); + case IPPROTO_GRE: + return tnl_del_ioctl("ip6gre0", p.name, &p); + default: + return tnl_del_ioctl(p.name, p.name, &p); + } + return -1; } int do_ip6tunnel(int argc, char **argv) diff -Nru iproute2-3.10.0/ip/ipaddress.c iproute2-3.12.0/ip/ipaddress.c --- iproute2-3.10.0/ip/ipaddress.c 2013-07-16 17:06:36.000000000 +0000 +++ iproute2-3.12.0/ip/ipaddress.c 2013-11-23 01:10:33.000000000 +0000 @@ -229,6 +229,7 @@ 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 @@ 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 @@ 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) { @@ -395,7 +418,7 @@ if (tb[IFLA_GROUP]) { int group = *(int*)RTA_DATA(tb[IFLA_GROUP]); - if (group != filter.group) + if (filter.group != -1 && group != filter.group) return -1; } @@ -435,6 +458,12 @@ if (do_link && tb[IFLA_LINKMODE]) print_linkmode(fp, tb[IFLA_LINKMODE]); + if (tb[IFLA_GROUP]) { + SPRINT_BUF(b1); + int group = *(int*)RTA_DATA(tb[IFLA_GROUP]); + fprintf(fp, "group %s ", rtnl_group_n2a(group, b1, sizeof(b1))); + } + if (filter.showqueue) print_queuelen(fp, tb); @@ -607,17 +636,18 @@ fprintf(fp, " family %d ", ifa->ifa_family); if (rta_tb[IFA_LOCAL]) { - fprintf(fp, "%s", rt_addr_n2a(ifa->ifa_family, + fprintf(fp, "%s", format_host(ifa->ifa_family, RTA_PAYLOAD(rta_tb[IFA_LOCAL]), RTA_DATA(rta_tb[IFA_LOCAL]), 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 ", - rt_addr_n2a(ifa->ifa_family, + format_host(ifa->ifa_family, RTA_PAYLOAD(rta_tb[IFA_ADDRESS]), RTA_DATA(rta_tb[IFA_ADDRESS]), abuf, sizeof(abuf)), @@ -627,14 +657,14 @@ if (rta_tb[IFA_BROADCAST]) { fprintf(fp, "brd %s ", - rt_addr_n2a(ifa->ifa_family, + format_host(ifa->ifa_family, RTA_PAYLOAD(rta_tb[IFA_BROADCAST]), RTA_DATA(rta_tb[IFA_BROADCAST]), abuf, sizeof(abuf))); } if (rta_tb[IFA_ANYCAST]) { fprintf(fp, "any %s ", - rt_addr_n2a(ifa->ifa_family, + format_host(ifa->ifa_family, RTA_PAYLOAD(rta_tb[IFA_ANYCAST]), RTA_DATA(rta_tb[IFA_ANYCAST]), abuf, sizeof(abuf))); @@ -1026,7 +1056,7 @@ if (filter.family == AF_UNSPEC) filter.family = preferred_family; - filter.group = INIT_NETDEV_GROUP; + filter.group = -1; if (action == IPADD_FLUSH) { if (argc <= 0) { diff -Nru iproute2-3.10.0/ip/ipaddrlabel.c iproute2-3.12.0/ip/ipaddrlabel.c --- iproute2-3.10.0/ip/ipaddrlabel.c 2013-07-16 17:06:36.000000000 +0000 +++ iproute2-3.12.0/ip/ipaddrlabel.c 2013-11-23 01:10:33.000000000 +0000 @@ -86,10 +86,10 @@ if (ifal->ifal_index) fprintf(fp, "dev %s ", ll_index_to_name(ifal->ifal_index)); - if (tb[IFAL_LABEL] && RTA_PAYLOAD(tb[IFAL_LABEL]) == sizeof(int32_t)) { - int32_t label; + if (tb[IFAL_LABEL] && RTA_PAYLOAD(tb[IFAL_LABEL]) == sizeof(uint32_t)) { + uint32_t label; memcpy(&label, RTA_DATA(tb[IFAL_LABEL]), sizeof(label)); - fprintf(fp, "label %d ", label); + fprintf(fp, "label %u ", label); } fprintf(fp, "\n"); diff -Nru iproute2-3.10.0/ip/iplink.c iproute2-3.12.0/ip/iplink.c --- iproute2-3.10.0/ip/iplink.c 2013-07-16 17:06:36.000000000 +0000 +++ iproute2-3.12.0/ip/iplink.c 2013-11-23 01:10:33.000000000 +0000 @@ -77,14 +77,16 @@ 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"); 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, "TYPE := { vlan | veth | vcan | dummy | ifb | macvlan | macvtap |\n"); + fprintf(stderr, " can | bridge | ipoib | ip6tnl | ipip | sit | vxlan |\n"); + fprintf(stderr, " gre | gretap | ip6gre | ip6gretap | vti }\n"); } exit(-1); } @@ -242,7 +244,7 @@ } 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(); @@ -255,6 +257,19 @@ 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(); @@ -272,7 +287,6 @@ return 0; } - int iplink_parse(int argc, char **argv, struct iplink_req *req, char **name, char **type, char **link, char **dev, int *group) { @@ -797,7 +811,6 @@ return 0; } - static int do_set(int argc, char **argv) { char *dev = NULL; diff -Nru iproute2-3.10.0/ip/iplink_macvlan.c iproute2-3.12.0/ip/iplink_macvlan.c --- iproute2-3.10.0/ip/iplink_macvlan.c 2013-07-16 17:06:36.000000000 +0000 +++ iproute2-3.12.0/ip/iplink_macvlan.c 2013-11-23 01:10:33.000000000 +0000 @@ -79,7 +79,7 @@ RTA_PAYLOAD(tb[IFLA_MACVLAN_MODE]) < sizeof(__u32)) return; - mode = rta_getattr_u32(tb[IFLA_VLAN_ID]); + mode = rta_getattr_u32(tb[IFLA_MACVLAN_MODE]); fprintf(f, " mode %s ", mode == MACVLAN_MODE_PRIVATE ? "private" : mode == MACVLAN_MODE_VEPA ? "vepa" diff -Nru iproute2-3.10.0/ip/iplink_vxlan.c iproute2-3.12.0/ip/iplink_vxlan.c --- iproute2-3.10.0/ip/iplink_vxlan.c 2013-07-16 17:06:36.000000000 +0000 +++ iproute2-3.12.0/ip/iplink_vxlan.c 2013-11-23 01:10:33.000000000 +0000 @@ -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, " [ port MIN MAX ] [ [no]learning ]\n"); fprintf(stderr, " [ [no]proxy ] [ [no]rsc ]\n"); @@ -42,6 +42,10 @@ 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; @@ -65,15 +69,30 @@ 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(); @@ -160,11 +179,27 @@ fprintf(stderr, "vxlan: missing virtual network identifier\n"); return -1; } + 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); @@ -208,9 +243,25 @@ 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 +269,12 @@ 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 -Nru iproute2-3.10.0/ip/ipmonitor.c iproute2-3.12.0/ip/ipmonitor.c --- iproute2-3.10.0/ip/ipmonitor.c 2013-07-16 17:06:36.000000000 +0000 +++ iproute2-3.12.0/ip/ipmonitor.c 2013-11-23 01:10:33.000000000 +0000 @@ -29,14 +29,13 @@ static void usage(void) { - fprintf(stderr, "Usage: ip monitor [ all | LISTofOBJECTS ] [ FILE ]\n"); + fprintf(stderr, "Usage: ip monitor [ all | LISTofOBJECTS ] [ FILE ] [ label ]\n"); fprintf(stderr, "LISTofOBJECTS := link | address | route | mroute | prefix |\n"); fprintf(stderr, " neigh | netconf\n"); fprintf(stderr, "FILE := file FILENAME\n"); exit(-1); } - static int accept_msg(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) { @@ -88,6 +87,13 @@ } if (n->nlmsg_type == RTM_NEWNEIGH || n->nlmsg_type == RTM_DELNEIGH || n->nlmsg_type == RTM_GETNEIGH) { + if (preferred_family) { + struct ndmsg *r = NLMSG_DATA(n); + + if (r->ndm_family != preferred_family) + return 0; + } + if (prefix_banner) fprintf(fp, "[NEIGH]"); print_neigh(who, n, arg); @@ -157,6 +163,8 @@ if (matches(*argv, "file") == 0) { NEXT_ARG(); file = *argv; + } else if (matches(*argv, "label") == 0) { + prefix_banner = 1; } else if (matches(*argv, "link") == 0) { llink=1; groups = 0; diff -Nru iproute2-3.10.0/ip/ipnetns.c iproute2-3.12.0/ip/ipnetns.c --- iproute2-3.10.0/ip/ipnetns.c 2013-07-16 17:06:36.000000000 +0000 +++ iproute2-3.12.0/ip/ipnetns.c 2013-11-23 01:10:33.000000000 +0000 @@ -167,7 +167,7 @@ fprintf(stderr, "unshare failed: %s\n", strerror(errno)); return -1; } - /* Don't let any mounts propogate back to the parent */ + /* 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)); @@ -205,11 +205,15 @@ exit(1); } - /* If child failed, propogate status */ - if (WIFEXITED(status)) - exit(WEXITSTATUS(status)); + if (WIFEXITED(status)) { + /* 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. + */ + return -WEXITSTATUS(status); + } - return 0; + exit(1); } } @@ -405,7 +409,7 @@ /* Create the base netns directory if it doesn't exist */ mkdir(NETNS_RUN_DIR, S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH); - /* 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 diff -Nru iproute2-3.10.0/ip/ipntable.c iproute2-3.12.0/ip/ipntable.c --- iproute2-3.10.0/ip/ipntable.c 2013-07-16 17:06:36.000000000 +0000 +++ iproute2-3.12.0/ip/ipntable.c 2013-11-23 01:10:33.000000000 +0000 @@ -305,7 +305,7 @@ if (!namep) missarg("NAME"); if (!threshsp && !gc_intp && !parms_change) { - fprintf(stderr, "Not enough information: changable attributes required.\n"); + fprintf(stderr, "Not enough information: changeable attributes required.\n"); exit(-1); } diff -Nru iproute2-3.10.0/ip/iproute.c iproute2-3.12.0/ip/iproute.c --- iproute2-3.10.0/ip/iproute.c 2013-07-16 17:06:36.000000000 +0000 +++ iproute2-3.12.0/ip/iproute.c 2013-11-23 01:10:33.000000000 +0000 @@ -52,6 +52,7 @@ [RTAX_FEATURES] = "features", [RTAX_RTO_MIN] = "rto_min", [RTAX_INITRWND] = "initrwnd", + [RTAX_QUICKACK] = "quickack", }; static void usage(void) __attribute__((noreturn)); @@ -62,7 +63,7 @@ fprintf(stderr, " ip route restore\n"); fprintf(stderr, " ip route showdump\n"); fprintf(stderr, " ip route get ADDRESS [ from ADDRESS iif STRING ]\n"); - fprintf(stderr, " [ oif STRING ] [ tos TOS ]\n"); + fprintf(stderr, " [ oif STRING ] [ tos TOS ]\n"); fprintf(stderr, " [ mark NUMBER ]\n"); fprintf(stderr, " ip route { add | del | change | append | replace } ROUTE\n"); fprintf(stderr, "SELECTOR := [ root PREFIX ] [ match PREFIX ] [ exact PREFIX ]\n"); @@ -75,10 +76,11 @@ fprintf(stderr, "INFO_SPEC := NH OPTIONS FLAGS [ nexthop NH ]...\n"); fprintf(stderr, "NH := [ via ADDRESS ] [ dev STRING ] [ weight NUMBER ] NHFLAGS\n"); fprintf(stderr, "OPTIONS := FLAGS [ mtu NUMBER ] [ advmss NUMBER ]\n"); - fprintf(stderr, " [ rtt TIME ] [ rttvar TIME ] [reordering NUMBER ]\n"); + fprintf(stderr, " [ rtt TIME ] [ rttvar TIME ] [ reordering NUMBER ]\n"); fprintf(stderr, " [ window NUMBER] [ cwnd NUMBER ] [ initcwnd NUMBER ]\n"); fprintf(stderr, " [ ssthresh NUMBER ] [ realms REALM ] [ src ADDRESS ]\n"); fprintf(stderr, " [ rto_min TIME ] [ hoplimit NUMBER ] [ initrwnd NUMBER ]\n"); + fprintf(stderr, " [ quickack BOOL ]\n"); fprintf(stderr, "TYPE := [ unicast | local | broadcast | multicast | throw |\n"); fprintf(stderr, " unreachable | prohibit | blackhole | nat ]\n"); fprintf(stderr, "TABLE_ID := [ local | main | default | all | NUMBER ]\n"); @@ -86,6 +88,7 @@ fprintf(stderr, "NHFLAGS := [ onlink | pervasive ]\n"); fprintf(stderr, "RTPROTO := [ kernel | boot | static | NUMBER ]\n"); fprintf(stderr, "TIME := NUMBER[s|ms]\n"); + fprintf(stderr, "BOOL := [1|0]\n"); exit(-1); } @@ -885,6 +888,14 @@ if (get_unsigned(&win, *argv, 0)) invarg("\"initrwnd\" value is invalid\n", *argv); rta_addattr32(mxrta, sizeof(mxbuf), RTAX_INITRWND, win); + } else if (matches(*argv, "quickack") == 0) { + unsigned quickack; + NEXT_ARG(); + if (get_unsigned(&quickack, *argv, 0)) + invarg("\"quickack\" value is invalid\n", *argv); + if (quickack != 1 && quickack != 0) + invarg("\"quickack\" value should be 0 or 1\n", *argv); + rta_addattr32(mxrta, sizeof(mxbuf), RTAX_QUICKACK, quickack); } else if (matches(*argv, "rttvar") == 0) { unsigned win; NEXT_ARG(); diff -Nru iproute2-3.10.0/ip/iprule.c iproute2-3.12.0/ip/iprule.c --- iproute2-3.10.0/ip/iprule.c 2013-07-16 17:06:36.000000000 +0000 +++ iproute2-3.12.0/ip/iprule.c 2013-11-23 01:10:33.000000000 +0000 @@ -39,6 +39,9 @@ fprintf(stderr, " [ prohibit | reject | unreachable ]\n"); fprintf(stderr, " [ realms [SRCREALM/]DSTREALM ]\n"); fprintf(stderr, " [ goto NUMBER ]\n"); + fprintf(stderr, " SUPPRESSOR\n"); + fprintf(stderr, "SUPPRESSOR := [ suppress_prefixlength NUMBER ]\n"); + fprintf(stderr, " [ suppress_ifgroup DEVGROUP ]\n"); fprintf(stderr, "TABLE_ID := [ local | main | default | NUMBER ]\n"); exit(-1); } @@ -153,9 +156,24 @@ } table = rtm_get_table(r, tb); - if (table) + if (table) { fprintf(fp, "lookup %s ", rtnl_rttable_n2a(table, b1, sizeof(b1))); + if (tb[FRA_SUPPRESS_PREFIXLEN]) { + int pl = rta_getattr_u32(tb[FRA_SUPPRESS_PREFIXLEN]); + if (pl != -1) { + fprintf(fp, "suppress_prefixlength %d ", pl); + } + } + if (tb[FRA_SUPPRESS_IFGROUP]) { + int group = rta_getattr_u32(tb[FRA_SUPPRESS_IFGROUP]); + if (group != -1) { + SPRINT_BUF(b1); + fprintf(fp, "suppress_ifgroup %s ", rtnl_group_n2a(group, b1, sizeof(b1))); + } + } + } + if (tb[FRA_FLOW]) { __u32 to = rta_getattr_u32(tb[FRA_FLOW]); __u32 from = to>>16; @@ -310,6 +328,20 @@ addattr32(&req.n, sizeof(req), FRA_TABLE, tid); } table_ok = 1; + } else if (matches(*argv, "suppress_prefixlength") == 0 || + strcmp(*argv, "sup_pl") == 0) { + int pl; + NEXT_ARG(); + if (get_s32(&pl, *argv, 0) || pl < 0) + invarg("suppress_prefixlength value is invalid\n", *argv); + addattr32(&req.n, sizeof(req), FRA_SUPPRESS_PREFIXLEN, pl); + } else if (matches(*argv, "suppress_ifgroup") == 0 || + strcmp(*argv, "sup_group") == 0) { + NEXT_ARG(); + int group; + if (rtnl_group_a2n(&group, *argv)) + invarg("Invalid \"suppress_ifgroup\" value\n", *argv); + addattr32(&req.n, sizeof(req), FRA_SUPPRESS_IFGROUP, group); } else if (strcmp(*argv, "dev") == 0 || strcmp(*argv, "iif") == 0) { NEXT_ARG(); diff -Nru iproute2-3.10.0/ip/iptunnel.c iproute2-3.12.0/ip/iptunnel.c --- iproute2-3.10.0/ip/iptunnel.c 2013-07-16 17:06:36.000000000 +0000 +++ iproute2-3.12.0/ip/iptunnel.c 2013-11-23 01:10:33.000000000 +0000 @@ -280,7 +280,7 @@ 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; } diff -Nru iproute2-3.10.0/ip/ipxfrm.c iproute2-3.12.0/ip/ipxfrm.c --- iproute2-3.10.0/ip/ipxfrm.c 2013-07-16 17:06:36.000000000 +0000 +++ iproute2-3.12.0/ip/ipxfrm.c 2013-11-23 01:10:33.000000000 +0000 @@ -856,7 +856,7 @@ 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 -Nru iproute2-3.10.0/ip/link_gre6.c iproute2-3.12.0/ip/link_gre6.c --- iproute2-3.10.0/ip/link_gre6.c 1970-01-01 00:00:00.000000000 +0000 +++ iproute2-3.12.0/ip/link_gre6.c 2013-11-23 01:10:33.000000000 +0000 @@ -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 -Nru iproute2-3.10.0/ip/link_iptnl.c iproute2-3.12.0/ip/link_iptnl.c --- iproute2-3.10.0/ip/link_iptnl.c 2013-07-16 17:06:36.000000000 +0000 +++ iproute2-3.12.0/ip/link_iptnl.c 2013-11-23 01:10:33.000000000 +0000 @@ -30,8 +30,10 @@ fprintf(stderr, " type { ipip | sit } [ remote ADDR ] [ local ADDR ]\n"); fprintf(stderr, " [ ttl TTL ] [ tos TOS ] [ [no]pmtudisc ] [ dev PHYS_DEV ]\n"); fprintf(stderr, " [ 6rd-prefix ADDR ] [ 6rd-relay_prefix ADDR ] [ 6rd-reset ]\n"); - if (sit) + if (sit) { + fprintf(stderr, " [ mode { ip6ip | ipip | any } ]\n"); fprintf(stderr, " [ isatap ]\n"); + } fprintf(stderr, "\n"); fprintf(stderr, "Where: NAME := STRING\n"); fprintf(stderr, " ADDR := { IP_ADDRESS | any }\n"); @@ -60,6 +62,7 @@ __u8 tos = 0; __u8 pmtudisc = 1; __u16 iflags = 0; + __u8 proto = 0; struct in6_addr ip6rdprefix; __u16 ip6rdprefixlen = 0; __u32 ip6rdrelayprefix = 0; @@ -123,6 +126,9 @@ if (iptuninfo[IFLA_IPTUN_LINK]) link = rta_getattr_u32(iptuninfo[IFLA_IPTUN_LINK]); + if (iptuninfo[IFLA_IPTUN_PROTO]) + proto = rta_getattr_u8(iptuninfo[IFLA_IPTUN_PROTO]); + if (iptuninfo[IFLA_IPTUN_6RD_PREFIX]) memcpy(&ip6rdprefix, RTA_DATA(iptuninfo[IFLA_IPTUN_6RD_PREFIX]), @@ -185,6 +191,21 @@ } else if (strcmp(lu->id, "sit") == 0 && strcmp(*argv, "isatap") == 0) { iflags |= SIT_ISATAP; + } else if (strcmp(lu->id, "sit") == 0 && + strcmp(*argv, "mode") == 0) { + NEXT_ARG(); + if (strcmp(*argv, "ipv6/ipv4") == 0 || + strcmp(*argv, "ip6ip") == 0) + proto = IPPROTO_IPV6; + else if (strcmp(*argv, "ipv4/ipv4") == 0 || + strcmp(*argv, "ipip") == 0 || + strcmp(*argv, "ip4ip4") == 0) + proto = IPPROTO_IPIP; + else if (strcmp(*argv, "any/ipv4") == 0 || + strcmp(*argv, "any") == 0) + proto = 0; + else + invarg("Cannot guess tunnel mode.", *argv); } else if (strcmp(*argv, "6rd-prefix") == 0) { inet_prefix prefix; NEXT_ARG(); @@ -212,7 +233,7 @@ } if (ttl && pmtudisc == 0) { - fprintf(stderr, "ttl != 0 and noptmudisc are incompatible\n"); + fprintf(stderr, "ttl != 0 and nopmtudisc are incompatible\n"); exit(-1); } @@ -224,6 +245,7 @@ addattr8(n, 1024, IFLA_IPTUN_PMTUDISC, pmtudisc); if (strcmp(lu->id, "sit") == 0) { addattr16(n, 1024, IFLA_IPTUN_FLAGS, iflags); + addattr8(n, 1024, IFLA_IPTUN_PROTO, proto); if (ip6rdprefixlen) { addattr_l(n, 1024, IFLA_IPTUN_6RD_PREFIX, &ip6rdprefix, sizeof(ip6rdprefix)); diff -Nru iproute2-3.10.0/ip/link_veth.c iproute2-3.12.0/ip/link_veth.c --- iproute2-3.10.0/ip/link_veth.c 2013-07-16 17:06:36.000000000 +0000 +++ iproute2-3.12.0/ip/link_veth.c 2013-11-23 01:10:33.000000000 +0000 @@ -19,9 +19,8 @@ static void usage(void) { - printf("Usage: ip link type veth " - "[peer ]\nTo get type " - "'ip link add help'\n"); + printf("Usage: ip link type veth [peer ]\n" + "To get type 'ip link add help'\n"); } static int veth_parse_opt(struct link_util *lu, int argc, char **argv, diff -Nru iproute2-3.10.0/ip/Makefile iproute2-3.12.0/ip/Makefile --- iproute2-3.10.0/ip/Makefile 2013-07-16 17:06:36.000000000 +0000 +++ iproute2-3.12.0/ip/Makefile 2013-11-23 01:10:33.000000000 +0000 @@ -5,7 +5,7 @@ iplink_vlan.o link_veth.o link_gre.o iplink_can.o \ iplink_macvlan.o iplink_macvtap.o ipl2tp.o link_vti.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 @@ ip: $(IPOBJ) $(LIBNETLINK) - rtmon: $(RTMONOBJ) install: all diff -Nru iproute2-3.10.0/ip/xfrm_policy.c iproute2-3.12.0/ip/xfrm_policy.c --- iproute2-3.10.0/ip/xfrm_policy.c 2013-07-16 17:06:36.000000000 +0000 +++ iproute2-3.12.0/ip/xfrm_policy.c 2013-11-23 01:10:33.000000000 +0000 @@ -373,7 +373,7 @@ (void *)tmpls_buf, tmpls_len); } - if (mark.m & mark.v) { + if (mark.m) { int r = addattr_l(&req.n, sizeof(req.buf), XFRMA_MARK, (void *)&mark, sizeof(mark)); if (r < 0) { diff -Nru iproute2-3.10.0/ip/xfrm_state.c iproute2-3.12.0/ip/xfrm_state.c --- iproute2-3.10.0/ip/xfrm_state.c 2013-07-16 17:06:36.000000000 +0000 +++ iproute2-3.12.0/ip/xfrm_state.c 2013-11-23 01:10:33.000000000 +0000 @@ -162,7 +162,7 @@ if (len > max) invarg("ALGO-KEYMAT value makes buffer overflow\n", key); - strncpy(buf, key, len); + memcpy(buf, key, len); } } @@ -528,7 +528,7 @@ exit(1); } - if (mark.m & mark.v) { + if (mark.m) { int r = addattr_l(&req.n, sizeof(req.buf), XFRMA_MARK, (void *)&mark, sizeof(mark)); if (r < 0) { diff -Nru iproute2-3.10.0/lib/ll_types.c iproute2-3.12.0/lib/ll_types.c --- iproute2-3.10.0/lib/ll_types.c 2013-07-16 17:06:36.000000000 +0000 +++ iproute2-3.12.0/lib/ll_types.c 2013-11-23 01:10:33.000000000 +0000 @@ -103,6 +103,7 @@ __PF(PHONET, phonet) __PF(PHONET_PIPE, phonet_pipe) __PF(CAIF, caif) +__PF(IP6GRE, gre6) __PF(NONE, none) __PF(VOID,void) diff -Nru iproute2-3.10.0/lib/rt_names.c iproute2-3.12.0/lib/rt_names.c --- iproute2-3.10.0/lib/rt_names.c 2013-07-16 17:06:36.000000000 +0000 +++ iproute2-3.12.0/lib/rt_names.c 2013-11-23 01:10:33.000000000 +0000 @@ -500,3 +500,22 @@ *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; +} diff -Nru iproute2-3.10.0/lib/utils.c iproute2-3.12.0/lib/utils.c --- iproute2-3.10.0/lib/utils.c 2013-07-16 17:06:36.000000000 +0000 +++ iproute2-3.12.0/lib/utils.c 2013-11-23 01:10:33.000000000 +0000 @@ -868,3 +868,11 @@ 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); +} diff -Nru iproute2-3.10.0/Makefile iproute2-3.12.0/Makefile --- iproute2-3.10.0/Makefile 2013-07-16 17:06:36.000000000 +0000 +++ iproute2-3.12.0/Makefile 2013-11-23 01:10:33.000000000 +0000 @@ -30,7 +30,7 @@ HOSTCC = gcc DEFINES += -D_GNU_SOURCE CCOPTS = -O2 -WFLAGS := -Wall -Wstrict-prototypes -Werror -Wmissing-prototypes +WFLAGS := -Wall -Wstrict-prototypes -Wmissing-prototypes WFLAGS += -Wmissing-declarations -Wold-style-definition CFLAGS = $(WFLAGS) $(CCOPTS) -I../include $(DEFINES) diff -Nru iproute2-3.10.0/man/man8/bridge.8 iproute2-3.12.0/man/man8/bridge.8 --- iproute2-3.10.0/man/man8/bridge.8 2013-07-16 17:06:36.000000000 +0000 +++ iproute2-3.12.0/man/man8/bridge.8 2013-11-23 01:10:33.000000000 +0000 @@ -13,7 +13,7 @@ .ti -8 .IR OBJECT " := { " -.BR link " | " fdb " | " vlan " | " monitor " }" +.BR link " | " fdb " | " mdb " | " vlan " | " monitor " }" .sp .ti -8 @@ -65,6 +65,21 @@ .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 @@ .IR DEV " ]" .ti -8 -.BR "bridge monitor" " [ " all " | " neigh " | " link " ]" +.BR "bridge monitor" " [ " all " | " neigh " | " link " | " mdb " ]" .SH OPTIONS @@ -110,6 +125,10 @@ - Forwarding Database entry. .TP +.B mdb +- Multicast group database entry. + +.TP .B vlan - VLAN filter list. @@ -326,6 +345,69 @@ 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 @@ .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 -Nru iproute2-3.10.0/man/man8/ip-link.8.in iproute2-3.12.0/man/man8/ip-link.8.in --- iproute2-3.10.0/man/man8/ip-link.8.in 2013-07-16 17:06:36.000000000 +0000 +++ iproute2-3.12.0/man/man8/ip-link.8.in 2013-11-23 01:10:33.000000000 +0000 @@ -62,7 +62,11 @@ .BR vxlan " |" .BR ip6tnl " |" .BR ipip " |" -.BR sit " ]" +.BR sit " |" +.BR gre " |" +.BR gretap " |" +.BR ip6gre " |" +.BR ip6gretap " ]" .ti -8 .BI "ip link delete " DEVICE @@ -186,6 +190,18 @@ .sp .BR sit - Virtual tunnel interface IPv6 over IPv4 +.sp +.BR gre +- Virtual tunnel interface GRE over IPv4 +.sp +.BR gretap +- Virtual L2 tuunel interface GRE over IPv4 +.sp +.BR ip6gre +- Virtual tuunel interface GRE over IPv6 +.sp +.BR ip6gretap +- Virtual L2 tuunel interface GRE over IPv6 .in -8 .TP @@ -206,8 +222,8 @@ .BI type " vxlan " id " ID .R " [ " .BI dev " PHYS_DEV " -.R " ] [ " -.BI group " IPADDR " +.RB " ] [ { " group " | " remote " } " +.I IPADDR .R " ] [ " .BI local " IPADDR " .R " ] [ " @@ -240,6 +256,17 @@ .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" @@ -281,6 +308,112 @@ .in -8 +.TP +IP6GRE/IP6GRETAP Type Support +For a link of type +.I IP6GRE/IP6GRETAP +the following additional arguments are supported: + +.BI "ip link add " DEVICE +.BI type " { ip6gre | ip6gretap } " remote " ADDR " local " ADDR +.R " [ " +.I "[i|o]seq]" +.R " ] [ " +.I "[i|o]key" KEY +.R " ] [ " +.I " [i|o]csum " +.R " ] [ " +.BI hoplimit " TTL " +.R " ] [ " +.BI encaplimit " ELIM " +.R " ] [ " +.BI tclass " TCLASS " +.R " ] [ " +.BI flowlabel " FLOWLABEL " +.R " ] [ " +.BI "dscp inherit" +.R " ] [ " +.BI dev " PHYS_DEV " +.R " ]" + +.in +8 +.sp +.BI remote " ADDR " +- specifies the remote IPv6 address of the tunnel. + +.sp +.BI local " ADDR " +- specifies the fixed local IPv6 address for tunneled packets. +It must be and address on another interface on this host. + +.sp +.BI [i|o]seq +- serialize packets. +The +.B oseq +flag enables sequencing of outgoing packets. +The +.B iseq +flag requires that all input packets are serialized. + +.sp +.BI [i|o]key " KEY" +- use keyed GRE with key +.IR KEY ". "KEY +is either a number or an IPv4 address-like dotted quad. +The +.B key +parameter specifies the same key to use in both directions. +The +.BR ikey " and " okey +parameters specify different keys for input and output. + +.sp +.BI [i|o]csum +- generate/require checksums for tunneled packets. +The +.B ocsum +flag calculates checksums for outgoing packets. +The +.B icsum +flag requires that all input packets have the correct +checksum. The +.B csum +flag is equivalent to the combination +.BR "icsum ocsum" . + +.sp +.BI hoplimit " TTL" +- specifies Hop Limit value to use in outgoing packets. + +.sp +.BI encaplimit " ELIM" +- specifies a fixed encapsulation limit. Default is 4. + +.sp +.BI flowlabel " FLOWLABEL" +- specifies a fixed flowlabel. + +.sp +.BI tclass " TCLASS" +- specifies the traffic class field on +tunneled packets, which can be specified as either a two-digit +hex value (e.g. c0) or a predefined string (e.g. internet). +The value +.B inherit +causes the field to be copied from the original IP header. The +values +.BI "inherit/" STRING +or +.BI "inherit/" 00 ".." ff +will set the field to +.I STRING +or +.IR 00 ".." ff +when tunneling non-IP packets. The default value is 00. + +.in -8 + .SS ip link delete - delete virtual link .I DEVICE specifies the virtual device to act operate on. diff -Nru iproute2-3.10.0/man/man8/ip-route.8.in iproute2-3.12.0/man/man8/ip-route.8.in --- iproute2-3.10.0/man/man8/ip-route.8.in 2013-07-16 17:06:36.000000000 +0000 +++ iproute2-3.12.0/man/man8/ip-route.8.in 2013-11-23 01:10:33.000000000 +0000 @@ -97,6 +97,8 @@ .IR TIME " ] [ " .B rttvar .IR TIME " ] [ " +.B reordering +.IR NUMBER " ] [ " .B window .IR NUMBER " ] [ " .B cwnd @@ -110,7 +112,9 @@ .B initcwnd .IR NUMBER " ] [ " .B initrwnd -.IR NUMBER " ]" +.IR NUMBER " ] [ " +.B quickack +.IR BOOL " ]" .ti -8 .IR TYPE " := [ " @@ -407,6 +411,10 @@ The default value is zero, meaning to use Slow Start value. .TP +.BI quickack " BOOL " "(3.11+ only)" +Enable or disable quick ack for connections to this destination. + +.TP .BI advmss " NUMBER " "(2.3.15+ only)" the MSS ('Maximal Segment Size') to advertise to these destinations when establishing TCP connections. If it is not given, diff -Nru iproute2-3.10.0/man/man8/ip-rule.8 iproute2-3.12.0/man/man8/ip-rule.8 --- iproute2-3.10.0/man/man8/ip-rule.8 2013-07-16 17:06:36.000000000 +0000 +++ iproute2-3.12.0/man/man8/ip-rule.8 2013-11-23 01:10:33.000000000 +0000 @@ -43,6 +43,14 @@ .IR ADDRESS " ] [ " .BR prohibit " | " reject " | " unreachable " ] [ " realms .RI "[" SRCREALM "/]" DSTREALM " ]" +.I SUPPRESSOR + +.ti -8 +.IR SUPPRESSOR " := [ " +.B suppress_prefixlength +.IR NUMBER " ] [ " +.B suppress_ifgroup +.IR GROUP " ]" .ti -8 .IR TABLE_ID " := [ " @@ -217,6 +225,15 @@ It is also possible to use lookup instead of table. .TP +.BI suppress_prefixlength " NUMBER" +reject routing decisions that have a prefix length of NUMBER or less. + +.TP +.BI suppress_ifgroup " GROUP" +reject routing decisions that use a device belonging to the interface +group GROUP. + +.TP .BI realms " FROM/TO" Realms to select if the rule matched and the routing table lookup succeeded. Realm diff -Nru iproute2-3.10.0/man/man8/ip-tunnel.8 iproute2-3.12.0/man/man8/ip-tunnel.8 --- iproute2-3.10.0/man/man8/ip-tunnel.8 2013-07-16 17:06:36.000000000 +0000 +++ iproute2-3.12.0/man/man8/ip-tunnel.8 2013-11-23 01:10:33.000000000 +0000 @@ -50,7 +50,7 @@ .ti -8 .IR MODE " := " -.RB " { " ipip " | " gre " | " sit " | " isatap " | " ip6ip6 " | " ipip6 " | " any " }" +.RB " { " ipip " | " gre " | " sit " | " isatap " | " ip6ip6 " | " ipip6 " | " ip6gre " | " any " }" .ti -8 .IR ADDR " := { " IP_ADDRESS " |" @@ -110,7 +110,7 @@ .BR ipip ", " sit ", " isatap " and " gre "." .br Modes for IPv6 encapsulation available: -.BR ip6ip6 ", " ipip6 " and " any "." +.BR ip6ip6 ", " ipip6 ", " ip6gre ", and " any "." .TP .BI remote " ADDRESS" diff -Nru iproute2-3.10.0/man/man8/lnstat.8 iproute2-3.12.0/man/man8/lnstat.8 --- iproute2-3.10.0/man/man8/lnstat.8 2013-07-16 17:06:36.000000000 +0000 +++ iproute2-3.12.0/man/man8/lnstat.8 2013-11-23 01:10:33.000000000 +0000 @@ -33,6 +33,9 @@ .B \-i, \-\-interval Set interval to 'intv' seconds. .TP +.B \-j, \-\-json +Display results in JSON format +.TP .B \-k, \-\-keys k,k,k,... Display only keys specified. .TP diff -Nru iproute2-3.10.0/man/man8/rtacct.8 iproute2-3.12.0/man/man8/rtacct.8 --- iproute2-3.10.0/man/man8/rtacct.8 2013-07-16 17:06:36.000000000 +0000 +++ iproute2-3.12.0/man/man8/rtacct.8 2013-11-23 01:10:33.000000000 +0000 @@ -15,33 +15,35 @@ are simple tools to monitor kernel snmp counters and network interface statistics. .SH OPTIONS -.TP --h -? +.B \-h, \-\-help Print help .TP --v -V +.B \-V, \-\-version Print version .TP --z +.B \-z, \-\-zero Dump zero counters too. By default they are not shown. .TP --r +.B \-r, \-\-reset Reset history. .TP --n +.B \-n, \-\-nooutput Do not display anything, only update history. .TP --a +.B \-a, \-\-ignore Dump absolute values of counters. The default is to calculate increments since the previous use. .TP --s +.B \-s, \-\-noupdate Do not update history, so that the next time you will see counters including values accumulated to the moment of this measurement too. +.B \-j, \-\-json +Display results in JSON format. .TP --d +.B \-d, \-\-interval Run in daemon mode collecting statistics. is interval between measurements in seconds. .TP --t + Time interval to average rates. Default value is 60 seconds. +.TP .SH SEE ALSO lnstat(8) diff -Nru iproute2-3.10.0/misc/ifstat.c iproute2-3.12.0/misc/ifstat.c --- iproute2-3.10.0/misc/ifstat.c 2013-07-16 17:06:36.000000000 +0000 +++ iproute2-3.12.0/misc/ifstat.c 2013-11-23 01:10:33.000000000 +0000 @@ -38,6 +38,7 @@ int reset_history = 0; int ignore_history = 0; int no_output = 0; +int json_output = 0; int no_update = 0; int scan_interval = 0; int time_constant = 0; @@ -61,6 +62,32 @@ __u32 ival[MAXS]; }; +static const char *stats[MAXS] = { + "rx_packets", + "tx_packets", + "rx_bytes", + "tx_bytes", + "rx_errors", + "tx_errors", + "rx_dropped", + "tx_dropped", + "multicast", + "collisions", + "rx_length_errors", + "rx_over_errors", + "rx_crc_errors", + "rx_frame_errors", + "rx_fifo_errors", + "rx_missed_errors", + "tx_aborted_errors", + "tx_carrier_errors", + "tx_fifo_errors", + "tx_heartbeat_errors", + "tx_window_errors", + "rx_compressed", + "tx_compressed" +}; + struct ifstat_ent *kern_db; struct ifstat_ent *hist_db; @@ -212,8 +239,13 @@ static void dump_raw_db(FILE *fp, int to_hist) { struct ifstat_ent *n, *h; + const char *eol = "\n"; + h = hist_db; - fprintf(fp, "#%s\n", info_source); + if (json_output) + fprintf(fp, "{ \"%s\":{", info_source); + else + fprintf(fp, "#%s\n", info_source); for (n=kern_db; n; n=n->next) { int i; @@ -232,10 +264,22 @@ } } } - fprintf(fp, "%d %s ", n->ifindex, n->name); - for (i=0; iname); + eol = ",\n"; + for (i=0; iifindex, n->name); + for (i=0; i giga) fprintf(fp, "%7lluM ", vals[i]/mega); else if (vals[i] > mega) @@ -265,7 +310,7 @@ fprintf(fp, "%-6u ", (unsigned)rates[i]); } -static void format_pair(FILE *fp, unsigned long long *vals, int i, int k) +static void format_pair(FILE *fp, const unsigned long long *vals, int i, int k) { char temp[64]; if (vals[i] > giga) @@ -328,10 +373,27 @@ } } -static void print_one_if(FILE *fp, struct ifstat_ent *n, - unsigned long long *vals) +static void print_one_json(FILE *fp, const struct ifstat_ent *n, + const unsigned long long *vals) +{ + int i, m; + const char *sep = " "; + + m = show_errors ? 20 : 10; + fprintf(fp, " \"%s\":{", n->name); + for (i=0; i < m && stats[i]; i++) { + fprintf(fp, "%s\"%s\":%llu", + sep, stats[i], vals[i]); + sep = ", "; + } + fprintf(fp, " }"); +} + +static void print_one_if(FILE *fp, const struct ifstat_ent *n, + const unsigned long long *vals) { int i; + fprintf(fp, "%-15s ", n->name); for (i=0; i<4; i++) format_rate(fp, vals, n->rate, i); @@ -375,27 +437,42 @@ } } - static void dump_kern_db(FILE *fp) { struct ifstat_ent *n; + const char *eol = "\n"; - print_head(fp); + if (json_output) + fprintf(fp, "{ \"%s\": {", info_source); + else + print_head(fp); for (n=kern_db; n; n=n->next) { if (!match(n->name)) continue; - print_one_if(fp, n, n->val); + + if (json_output) { + fprintf(fp, "%s", eol); + eol = ",\n"; + print_one_json(fp, n, n->val); + } else + print_one_if(fp, n, n->val); } + if (json_output) + fprintf(fp, "\n} }\n"); } static void dump_incr_db(FILE *fp) { struct ifstat_ent *n, *h; - h = hist_db; + const char *eol = "\n"; - print_head(fp); + h = hist_db; + if (json_output) + fprintf(fp, "{ \"%s\":{", info_source); + else + print_head(fp); for (n=kern_db; n; n=n->next) { int i; @@ -414,8 +491,16 @@ } if (!match(n->name)) continue; - print_one_if(fp, n, vals); + + if (json_output) { + fprintf(fp, "%s", eol); + eol = ",\n"; + print_one_json(fp, n, n->val); + } else + print_one_if(fp, n, vals); } + if (json_output) + fprintf(fp, "\n} }\n"); } @@ -559,9 +644,10 @@ " -a, --ignore ignore history\n" " -d, --scan=SECS sample every statistics every SECS\n" " -e, --errors show errors\n" +" -j, --json format output in JSON\n" " -n, --nooutput do history only\n" " -r, --reset reset history\n" -" -s, --noupdate don;t update history\n" +" -s, --noupdate don\'t update history\n" " -t, --interval=SECS report average over the last SECS\n" " -V, --version output version information\n" " -z, --zeros show entries with zero activity\n"); @@ -575,6 +661,7 @@ { "scan", 1, 0, 'd'}, { "errors", 0, 0, 'e' }, { "nooutput", 0, 0, 'n' }, + { "json", 0, 0, 'j' }, { "reset", 0, 0, 'r' }, { "noupdate", 0, 0, 's' }, { "interval", 1, 0, 't' }, @@ -591,7 +678,7 @@ int ch; int fd; - while ((ch = getopt_long(argc, argv, "hvVzrnasd:t:eK", + while ((ch = getopt_long(argc, argv, "hjvVzrnasd:t:e", longopts, NULL)) != EOF) { switch(ch) { case 'z': @@ -612,6 +699,9 @@ case 'e': show_errors = 1; break; + case 'j': + json_output = 1; + break; case 'd': scan_interval = atoi(optarg) * 1000; if (scan_interval <= 0) { @@ -759,11 +849,14 @@ else dump_incr_db(stdout); } + if (!no_update) { ftruncate(fileno(hist_fp), 0); rewind(hist_fp); + + json_output = 0; dump_raw_db(hist_fp, 1); - fflush(hist_fp); + fclose(hist_fp); } exit(0); } diff -Nru iproute2-3.10.0/misc/lnstat.c iproute2-3.12.0/misc/lnstat.c --- iproute2-3.10.0/misc/lnstat.c 2013-07-16 17:06:36.000000000 +0000 +++ iproute2-3.12.0/misc/lnstat.c 2013-11-23 01:10:33.000000000 +0000 @@ -41,7 +41,8 @@ static struct option opts[] = { { "version", 0, NULL, 'V' }, { "count", 1, NULL, 'c' }, - { "dump", 1, NULL, 'd' }, + { "dump", 0, NULL, 'd' }, + { "json", 0, NULL, 'j' }, { "file", 1, NULL, 'f' }, { "help", 0, NULL, 'h' }, { "interval", 1, NULL, 'i' }, @@ -63,6 +64,8 @@ "Print number of intervals\n"); fprintf(stderr, "\t-d --dump\t\t" "Dump list of available files/keys\n"); + fprintf(stderr, "\t-j --json\t\t" + "Display in JSON format\n"); fprintf(stderr, "\t-f --file \tStatistics file to use\n"); fprintf(stderr, "\t-h --help\t\tThis help message\n"); fprintf(stderr, "\t-i --interval \t" @@ -94,7 +97,7 @@ int i; for (i = 0; i < fp->num; i++) { - struct lnstat_field *lf = fp->params[i].lf; + const struct lnstat_field *lf = fp->params[i].lf; char formatbuf[255]; snprintf(formatbuf, sizeof(formatbuf)-1, "%%%ulu|", @@ -104,6 +107,30 @@ fputc('\n', of); } +static void print_json(FILE *of, const struct lnstat_file *lnstat_files, + const struct field_params *fp) +{ + int i; + const char *sep; + const char *base = NULL; + + fputs("{\n", of); + for (i = 0; i < fp->num; i++) { + const struct lnstat_field *lf = fp->params[i].lf; + + if (!base || lf->file->basename != base) { + if (base) fputs("},\n", of); + base = lf->file->basename; + sep = "\n\t"; + fprintf(of, " \"%s\":{", base); + } + fprintf(of, "%s\"%s\":%lu", sep, + lf->name, lf->result); + sep = ",\n\t"; + } + fputs("}\n}\n", of); +} + /* find lnstat_field according to user specification */ static int map_field_params(struct lnstat_file *lnstat_files, struct field_params *fps, int interval) @@ -218,15 +245,16 @@ { struct lnstat_file *lnstat_files; const char *basename; - int c; + int i, c; int interval = DEFAULT_INTERVAL; int hdr = 2; enum { MODE_DUMP, + MODE_JSON, MODE_NORMAL, } mode = MODE_NORMAL; - unsigned long count = 1; + struct table_hdr *header; static struct field_params fp; int num_req_files = 0; char *req_files[LNSTAT_MAX_FILES]; @@ -248,70 +276,73 @@ num_req_files = 1; } - while ((c = getopt_long(argc, argv,"Vc:df:h?i:k:s:w:", + while ((c = getopt_long(argc, argv,"Vc:djf:h?i:k:s:w:", opts, NULL)) != -1) { - int i, len = 0; + int len = 0; char *tmp, *tok; switch (c) { - case 'c': - count = strtoul(optarg, NULL, 0); - break; - case 'd': - mode = MODE_DUMP; - break; - case 'f': - req_files[num_req_files++] = strdup(optarg); + case 'c': + count = strtoul(optarg, NULL, 0); + break; + case 'd': + mode = MODE_DUMP; + break; + case 'j': + mode = MODE_JSON; + break; + case 'f': + req_files[num_req_files++] = strdup(optarg); + break; + case '?': + case 'h': + usage(argv[0], 0); + break; + case 'i': + sscanf(optarg, "%u", &interval); + break; + case 'k': + tmp = strdup(optarg); + if (!tmp) break; - case '?': - case 'h': - usage(argv[0], 0); - break; - case 'i': - sscanf(optarg, "%u", &interval); - break; - case 'k': - tmp = strdup(optarg); - if (!tmp) + for (tok = strtok(tmp, ","); + tok; + tok = strtok(NULL, ",")) { + if (fp.num >= MAX_FIELDS) { + fprintf(stderr, + "WARN: too many keys" + " requested: (%d max)\n", + MAX_FIELDS); break; - for (tok = strtok(tmp, ","); - tok; - tok = strtok(NULL, ",")) { - if (fp.num >= MAX_FIELDS) { - fprintf(stderr, - "WARN: too many keys" - " requested: (%d max)\n", - MAX_FIELDS); - break; - } - fp.params[fp.num++].name = tok; } + fp.params[fp.num++].name = tok; + } + break; + case 's': + sscanf(optarg, "%u", &hdr); + break; + case 'w': + tmp = strdup(optarg); + if (!tmp) break; - case 's': - sscanf(optarg, "%u", &hdr); - break; - case 'w': - tmp = strdup(optarg); - if (!tmp) - break; - i = 0; - for (tok = strtok(tmp, ","); - tok; - tok = strtok(NULL, ",")) { - len = strtoul(tok, NULL, 0); - if (len > FIELD_WIDTH_MAX) - len = FIELD_WIDTH_MAX; + i = 0; + for (tok = strtok(tmp, ","); + tok; + tok = strtok(NULL, ",")) { + len = strtoul(tok, NULL, 0); + if (len > FIELD_WIDTH_MAX) + len = FIELD_WIDTH_MAX; + fp.params[i].print.width = len; + i++; + } + if (i == 1) { + for (i = 0; i < MAX_FIELDS; i++) fp.params[i].print.width = len; - i++; - } - if (i == 1) { - for (i = 0; i < MAX_FIELDS; i++) - fp.params[i].print.width = len; - } - break; - default: - usage(argv[0], 1); - break; + } + break; + default: + usage(argv[0], 1); + break; } } @@ -319,13 +350,12 @@ (const char **) req_files); switch (mode) { - int i; - struct table_hdr *header; case MODE_DUMP: lnstat_dump(stderr, lnstat_files); break; - case MODE_NORMAL: + case MODE_NORMAL: + case MODE_JSON: if (!map_field_params(lnstat_files, &fp, interval)) exit(1); @@ -334,16 +364,23 @@ exit(1); if (interval < 1 ) - interval=1; + interval = 1; for (i = 0; i < count; i++) { - if ((hdr > 1 && (! (i % 20))) || (hdr == 1 && i == 0)) - print_hdr(stdout, header); lnstat_update(lnstat_files); - print_line(stdout, lnstat_files, &fp); + if (mode == MODE_JSON) + print_json(stdout, lnstat_files, &fp); + else { + if ((hdr > 1 && + (! (i % 20))) || (hdr == 1 && i == 0)) + print_hdr(stdout, header); + print_line(stdout, lnstat_files, &fp); + } fflush(stdout); - sleep(interval); + if (i < count - 1) + sleep(interval); } + break; } return 1; diff -Nru iproute2-3.10.0/misc/nstat.c iproute2-3.12.0/misc/nstat.c --- iproute2-3.10.0/misc/nstat.c 2013-07-16 17:06:36.000000000 +0000 +++ iproute2-3.12.0/misc/nstat.c 2013-11-23 01:10:33.000000000 +0000 @@ -26,6 +26,7 @@ #include #include #include +#include #include @@ -33,6 +34,7 @@ int reset_history = 0; int ignore_history = 0; int no_output = 0; +int json_output = 0; int no_update = 0; int scan_interval = 0; int time_constant = 0; @@ -255,11 +257,18 @@ } } + static void dump_kern_db(FILE *fp, int to_hist) { struct nstat_ent *n, *h; + const char *eol = "\n"; + h = hist_db; - fprintf(fp, "#%s\n", info_source); + if (json_output) + fprintf(fp, "{ \"%s\":{", info_source); + else + fprintf(fp, "#%s\n", info_source); + for (n=kern_db; n; n=n->next) { unsigned long long val = n->val; if (!dump_zeros && !val && !n->rate) @@ -276,15 +285,29 @@ } } } - fprintf(fp, "%-32s%-16llu%6.1f\n", n->id, val, n->rate); + + if (json_output) { + fprintf(fp, "%s \"%s\":%llu", + eol, n->id, val); + eol = ",\n"; + } else + fprintf(fp, "%-32s%-16llu%6.1f\n", n->id, val, n->rate); } + if (json_output) + fprintf(fp, "\n} }\n"); } static void dump_incr_db(FILE *fp) { struct nstat_ent *n, *h; + const char *eol = "\n"; + h = hist_db; - fprintf(fp, "#%s\n", info_source); + if (json_output) + fprintf(fp, "{ \"%s\":{", info_source); + else + fprintf(fp, "#%s\n", info_source); + for (n=kern_db; n; n=n->next) { int ovfl = 0; unsigned long long val = n->val; @@ -304,9 +327,17 @@ continue; if (!match(n->id)) continue; - fprintf(fp, "%-32s%-16llu%6.1f%s\n", n->id, val, - n->rate, ovfl?" (overflow)":""); + + if (json_output) { + fprintf(fp, "%s \"%s\":%llu", + eol, n->id, val); + eol = ",\n"; + } else + fprintf(fp, "%-32s%-16llu%6.1f%s\n", n->id, val, + n->rate, ovfl?" (overflow)":""); } + if (json_output) + fprintf(fp, "\n} }\n"); } static int children; @@ -437,11 +468,33 @@ static void usage(void) { fprintf(stderr, -"Usage: nstat [ -h?vVzrnasd:t: ] [ PATTERN [ PATTERN ] ]\n" - ); +"Usage: nstat [OPTION] [ PATTERN [ PATTERN ] ]\n" +" -h, --help this message\n" +" -a, --ignore ignore history\n" +" -d, --scan=SECS sample every statistics every SECS\n" +" -j, --json format output in JSON\n" +" -n, --nooutput do history only\n" +" -r, --reset reset history\n" +" -s, --noupdate don\'t update history\n" +" -t, --interval=SECS report average over the last SECS\n" +" -V, --version output version information\n" +" -z, --zeros show entries with zero activity\n"); exit(-1); } +static const struct option longopts[] = { + { "help", 0, 0, 'h' }, + { "ignore", 0, 0, 'a' }, + { "scan", 1, 0, 'd'}, + { "nooutput", 0, 0, 'n' }, + { "json", 0, 0, 'j' }, + { "reset", 0, 0, 'r' }, + { "noupdate", 0, 0, 's' }, + { "interval", 1, 0, 't' }, + { "version", 0, 0, 'V' }, + { "zeros", 0, 0, 'z' }, + { 0 } +}; int main(int argc, char *argv[]) { @@ -451,7 +504,8 @@ int ch; int fd; - while ((ch = getopt(argc, argv, "h?vVzrnasd:t:")) != EOF) { + while ((ch = getopt_long(argc, argv, "h?vVzrnasd:t:j", + longopts, NULL)) != EOF) { switch(ch) { case 'z': dump_zeros = 1; @@ -478,6 +532,9 @@ exit(-1); } break; + case 'j': + json_output = 1; + break; case 'v': case 'V': printf("nstat utility, iproute2-ss%s\n", SNAPSHOT); @@ -614,8 +671,10 @@ if (!no_update) { ftruncate(fileno(hist_fp), 0); rewind(hist_fp); + + json_output = 0; dump_kern_db(hist_fp, 1); - fflush(hist_fp); + fclose(hist_fp); } exit(0); } diff -Nru iproute2-3.10.0/misc/ss.c iproute2-3.12.0/misc/ss.c --- iproute2-3.10.0/misc/ss.c 2013-07-16 17:06:36.000000000 +0000 +++ iproute2-3.12.0/misc/ss.c 2013-11-23 01:10:33.000000000 +0000 @@ -894,7 +894,8 @@ 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 +908,8 @@ } 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 +922,8 @@ } 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); diff -Nru iproute2-3.10.0/tc/Makefile iproute2-3.12.0/tc/Makefile --- iproute2-3.10.0/tc/Makefile 2013-07-16 17:06:36.000000000 +0000 +++ iproute2-3.12.0/tc/Makefile 2013-11-23 01:10:33.000000000 +0000 @@ -38,6 +38,7 @@ TCMODULES += m_pedit.o TCMODULES += m_skbedit.o TCMODULES += m_csum.o +TCMODULES += m_simple.o TCMODULES += p_ip.o TCMODULES += p_icmp.o TCMODULES += p_tcp.o @@ -50,6 +51,7 @@ 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 -Nru iproute2-3.10.0/tc/m_ipt.c iproute2-3.12.0/tc/m_ipt.c --- iproute2-3.10.0/tc/m_ipt.c 2013-07-16 17:06:36.000000000 +0000 +++ iproute2-3.12.0/tc/m_ipt.c 2013-11-23 01:10:33.000000000 +0000 @@ -415,7 +415,7 @@ } if (argc <= 2) { - fprintf(stderr,"bad arguements to ipt %d vs %d \n", argc, rargc); + fprintf(stderr,"bad arguments to ipt %d vs %d \n", argc, rargc); return -1; } diff -Nru iproute2-3.10.0/tc/m_mirred.c iproute2-3.12.0/tc/m_mirred.c --- iproute2-3.10.0/tc/m_mirred.c 2013-07-16 17:06:36.000000000 +0000 +++ iproute2-3.12.0/tc/m_mirred.c 2013-11-23 01:10:33.000000000 +0000 @@ -105,7 +105,7 @@ } else if (!mirror && matches(*argv, "mirror") == 0) { mirror=1; if (redir) { - fprintf(stderr, "Cant have both mirror and redir\n"); + fprintf(stderr, "Can't have both mirror and redir\n"); return -1; } p.eaction = TCA_EGRESS_MIRROR; @@ -114,7 +114,7 @@ } else if (!redir && matches(*argv, "redirect") == 0) { redir=1; if (mirror) { - fprintf(stderr, "Cant have both mirror and redir\n"); + fprintf(stderr, "Can't have both mirror and redir\n"); return -1; } p.eaction = TCA_EGRESS_REDIR; @@ -215,14 +215,14 @@ char **argv = *argv_p; if (argc < 0) { - fprintf(stderr,"mirred bad arguement count %d\n", argc); + fprintf(stderr,"mirred bad argument count %d\n", argc); return -1; } if (matches(*argv, "mirred") == 0) { NEXT_ARG(); } else { - fprintf(stderr,"mirred bad arguement %s\n", *argv); + fprintf(stderr,"mirred bad argument %s\n", *argv); return -1; } diff -Nru iproute2-3.10.0/tc/m_nat.c iproute2-3.12.0/tc/m_nat.c --- iproute2-3.10.0/tc/m_nat.c 2013-07-16 17:06:36.000000000 +0000 +++ iproute2-3.12.0/tc/m_nat.c 2013-11-23 01:10:33.000000000 +0000 @@ -146,7 +146,7 @@ if (matches(*argv, "index") == 0) { NEXT_ARG(); if (get_u32(&sel.index, *argv, 10)) { - fprintf(stderr, "Pedit: Illegal \"index\"\n"); + fprintf(stderr, "Nat: Illegal \"index\"\n"); return -1; } argc--; diff -Nru iproute2-3.10.0/tc/m_police.c iproute2-3.12.0/tc/m_police.c --- iproute2-3.10.0/tc/m_police.c 2013-07-16 17:06:36.000000000 +0000 +++ iproute2-3.12.0/tc/m_police.c 2013-11-23 01:10:33.000000000 +0000 @@ -322,9 +322,11 @@ print_police(struct action_util *a, FILE *f, struct rtattr *arg) { SPRINT_BUF(b1); + SPRINT_BUF(b2); struct tc_police *p; struct rtattr *tb[TCA_POLICE_MAX+1]; unsigned buffer; + unsigned int linklayer; if (arg == NULL) return 0; @@ -360,6 +362,9 @@ } else fprintf(f, " "); fprintf(f, "overhead %ub ", p->rate.overhead); + linklayer = (p->rate.linklayer & TC_LINKLAYER_MASK); + if (linklayer > TC_LINKLAYER_ETHERNET || show_details) + fprintf(f, "linklayer %s ", sprint_linklayer(linklayer, b2)); fprintf(f, "\nref %d bind %d\n",p->refcnt, p->bindcnt); return 0; diff -Nru iproute2-3.10.0/tc/m_simple.c iproute2-3.12.0/tc/m_simple.c --- iproute2-3.10.0/tc/m_simple.c 1970-01-01 00:00:00.000000000 +0000 +++ iproute2-3.12.0/tc/m_simple.c 2013-11-23 01:10:33.000000000 +0000 @@ -0,0 +1,202 @@ +/* + * m_simple.c simple action + * + * This program is free software; you can distribute 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: J Hadi Salim + * + * Pedagogical example. Adds a string that will be printed everytime + * the simple instance is hit. + * Use this as a skeleton action and keep modifying it to meet your needs. + * Look at linux/tc_act/tc_defact.h for the different components ids and + * definitions used in this actions + * + * example use, yell "Incoming ICMP!" every time you see an incoming ICMP on + * eth0. Steps are: + * 1) Add an ingress qdisc point to eth0 + * 2) Start a chain on ingress of eth0 that first matches ICMP then invokes + * the simple action to shout. + * 3) display stats and show that no packet has been seen by the action + * 4) Send one ping packet to google (expect to receive a response back) + * 5) grep the logs to see the logged message + * 6) display stats again and observe increment by 1 + * + hadi@noma1:$ tc qdisc add dev eth0 ingress + hadi@noma1:$tc filter add dev eth0 parent ffff: protocol ip prio 5 \ + u32 match ip protocol 1 0xff flowid 1:1 action simple "Incoming ICMP" + + hadi@noma1:$ sudo tc -s filter ls dev eth0 parent ffff: + filter protocol ip pref 5 u32 + filter protocol ip pref 5 u32 fh 800: ht divisor 1 + filter protocol ip pref 5 u32 fh 800::800 order 2048 key ht 800 bkt 0 flowid 1:1 + match 00010000/00ff0000 at 8 + action order 1: Simple + index 4 ref 1 bind 1 installed 29 sec used 29 sec + Action statistics: + Sent 0 bytes 0 pkt (dropped 0, overlimits 0 requeues 0) + backlog 0b 0p requeues 0 + + + hadi@noma1$ ping -c 1 www.google.ca + PING www.google.ca (74.125.225.120) 56(84) bytes of data. + 64 bytes from ord08s08-in-f24.1e100.net (74.125.225.120): icmp_req=1 ttl=53 time=31.3 ms + + --- www.google.ca ping statistics --- + 1 packets transmitted, 1 received, 0% packet loss, time 0ms + rtt min/avg/max/mdev = 31.316/31.316/31.316/0.000 ms + + hadi@noma1$ dmesg | grep simple + [135354.473951] simple: Incoming ICMP_1 + + hadi@noma1$ sudo tc/tc -s filter ls dev eth0 parent ffff: + filter protocol ip pref 5 u32 + filter protocol ip pref 5 u32 fh 800: ht divisor 1 + filter protocol ip pref 5 u32 fh 800::800 order 2048 key ht 800 bkt 0 flowid 1:1 + match 00010000/00ff0000 at 8 + action order 1: Simple + index 4 ref 1 bind 1 installed 206 sec used 67 sec + Action statistics: + Sent 84 bytes 1 pkt (dropped 0, overlimits 0 requeues 0) + backlog 0b 0p requeues 0 +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "utils.h" +#include "tc_util.h" +#include + +#ifndef SIMP_MAX_DATA +#define SIMP_MAX_DATA 32 +#endif +static void explain(void) +{ + fprintf(stderr, "Usage: ... simple STRING\n" + "STRING being an arbitrary string\n" + "example: \"simple blah\"\n"); +} + +static void usage(void) +{ + explain(); + exit(-1); +} + +static int +parse_simple(struct action_util *a, int *argc_p, char ***argv_p, int tca_id, + struct nlmsghdr *n) +{ + struct tc_defact sel = {}; + int argc = *argc_p; + char **argv = *argv_p; + int ok = 0; + struct rtattr *tail; + char *simpdata = NULL; + + + while (argc > 0) { + if (matches(*argv, "simple") == 0) { + NEXT_ARG(); + simpdata = *argv; + ok = 1; + argc--; + argv++; + break; + } else if (matches(*argv, "help") == 0) { + usage(); + } else { + break; + } + + } + + if (!ok) { + explain(); + return -1; + } + + if (argc) { + if (matches(*argv, "index") == 0) { + NEXT_ARG(); + if (get_u32(&sel.index, *argv, 10)) { + fprintf(stderr, "simple: Illegal \"index\"\n"); + return -1; + } + argc--; + argv++; + } + } + + if (strlen(simpdata) > (SIMP_MAX_DATA - 1)) { + fprintf(stderr, "simple: Illegal string len %ld <%s> \n", + strlen(simpdata), simpdata); + return -1; + } + + sel.action = TC_ACT_PIPE; + + tail = NLMSG_TAIL(n); + addattr_l(n, MAX_MSG, tca_id, NULL, 0); + addattr_l(n, MAX_MSG, TCA_DEF_PARMS, &sel, sizeof(sel)); + addattr_l(n, MAX_MSG, TCA_DEF_DATA, simpdata, SIMP_MAX_DATA); + tail->rta_len = (char *)NLMSG_TAIL(n) - (char *)tail; + + *argc_p = argc; + *argv_p = argv; + return 0; +} + +static int print_simple(struct action_util *au, FILE * f, struct rtattr *arg) +{ + struct tc_defact *sel; + struct rtattr *tb[TCA_DEF_MAX + 1]; + char *simpdata; + + if (arg == NULL) + return -1; + + parse_rtattr_nested(tb, TCA_DEF_MAX, arg); + + if (tb[TCA_DEF_PARMS] == NULL) { + fprintf(f, "[NULL simple parameters]"); + return -1; + } + sel = RTA_DATA(tb[TCA_DEF_PARMS]); + + if (tb[TCA_DEF_DATA] == NULL) { + fprintf(f, "[missing simple string]"); + return -1; + } + + simpdata = RTA_DATA(tb[TCA_DEF_DATA]); + + fprintf(f, "Simple <%s>\n", simpdata); + fprintf(f, "\t index %d ref %d bind %d", sel->index, + sel->refcnt, sel->bindcnt); + + if (show_stats) { + if (tb[TCA_DEF_TM]) { + struct tcf_t *tm = RTA_DATA(tb[TCA_DEF_TM]); + print_tm(f, tm); + fprintf(f, "\n"); + } + } + + return 0; +} + +struct action_util simple_action_util = { + .id = "simple", + .parse_aopt = parse_simple, + .print_aopt = print_simple, +}; diff -Nru iproute2-3.10.0/tc/m_xt.c iproute2-3.12.0/tc/m_xt.c --- iproute2-3.10.0/tc/m_xt.c 2013-07-16 17:06:36.000000000 +0000 +++ iproute2-3.12.0/tc/m_xt.c 2013-11-23 01:10:33.000000000 +0000 @@ -147,7 +147,7 @@ } if (argc <= 2) { - fprintf(stderr,"bad arguements to ipt %d vs %d \n", argc, rargc); + fprintf(stderr,"bad arguments to ipt %d vs %d \n", argc, rargc); return -1; } diff -Nru iproute2-3.10.0/tc/m_xt_old.c iproute2-3.12.0/tc/m_xt_old.c --- iproute2-3.10.0/tc/m_xt_old.c 2013-07-16 17:06:36.000000000 +0000 +++ iproute2-3.12.0/tc/m_xt_old.c 2013-11-23 01:10:33.000000000 +0000 @@ -232,7 +232,7 @@ } if (argc <= 2) { - fprintf(stderr,"bad arguements to ipt %d vs %d \n", argc, rargc); + fprintf(stderr,"bad arguments to ipt %d vs %d \n", argc, rargc); return -1; } diff -Nru iproute2-3.10.0/tc/q_cbq.c iproute2-3.12.0/tc/q_cbq.c --- iproute2-3.10.0/tc/q_cbq.c 2013-07-16 17:06:36.000000000 +0000 +++ iproute2-3.12.0/tc/q_cbq.c 2013-11-23 01:10:33.000000000 +0000 @@ -442,7 +442,9 @@ struct tc_cbq_wrropt *wrr = NULL; struct tc_cbq_fopt *fopt = NULL; struct tc_cbq_ovl *ovl = NULL; + unsigned int linklayer; SPRINT_BUF(b1); + SPRINT_BUF(b2); if (opt == NULL) return 0; @@ -486,6 +488,9 @@ char buf[64]; print_rate(buf, sizeof(buf), r->rate); fprintf(f, "rate %s ", buf); + linklayer = (r->linklayer & TC_LINKLAYER_MASK); + if (linklayer > TC_LINKLAYER_ETHERNET || show_details) + fprintf(f, "linklayer %s ", sprint_linklayer(linklayer, b2)); if (show_details) { fprintf(f, "cell %ub ", 1<cell_log); if (r->mpu) diff -Nru iproute2-3.10.0/tc/q_fq.c iproute2-3.12.0/tc/q_fq.c --- iproute2-3.10.0/tc/q_fq.c 1970-01-01 00:00:00.000000000 +0000 +++ iproute2-3.12.0/tc/q_fq.c 2013-11-23 01:10:33.000000000 +0000 @@ -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, +}; diff -Nru iproute2-3.10.0/tc/q_htb.c iproute2-3.12.0/tc/q_htb.c --- iproute2-3.10.0/tc/q_htb.c 2013-07-16 17:06:36.000000000 +0000 +++ iproute2-3.12.0/tc/q_htb.c 2013-11-23 01:10:33.000000000 +0000 @@ -31,9 +31,11 @@ static void explain(void) { fprintf(stderr, "Usage: ... qdisc add ... htb [default N] [r2q N]\n" + " [direct_qlen P]\n" " default minor id of class to which unclassified packets are sent {0}\n" " r2q DRR quantums are computed as rate in Bps/r2q {10}\n" " debug string of 16 numbers each 0-3 {0}\n\n" + " direct_qlen Limit of the direct queue {in packets}\n" "... class add ... htb rate R1 [burst B1] [mpu B] [overhead O]\n" " [prio P] [slot S] [pslot PS]\n" " [ceil R2] [cburst B2] [mtu MTU] [quantum Q]\n" @@ -108,6 +110,7 @@ unsigned mtu; unsigned short mpu = 0; unsigned short overhead = 0; + unsigned int direct_qlen = ~0U; unsigned int linklayer = LINKLAYER_ETHERNET; /* Assume ethernet */ struct rtattr *tail; @@ -125,6 +128,11 @@ if (get_u32(&mtu, *argv, 10)) { explain1("mtu"); return -1; } + } else if (matches(*argv, "direct_qlen") == 0) { + NEXT_ARG(); + if (get_u32(&direct_qlen, *argv, 10)) { + explain1("direct_qlen"); return -1; + } } else if (matches(*argv, "mpu") == 0) { NEXT_ARG(); if (get_u16(&mpu, *argv, 10)) { @@ -230,6 +238,9 @@ opt.cbuffer = tc_calc_xmittime(opt.ceil.rate, cbuffer); tail = NLMSG_TAIL(n); + if (direct_qlen != ~0U) + addattr_l(n, 1024, TCA_HTB_DIRECT_QLEN, + &direct_qlen, sizeof(direct_qlen)); addattr_l(n, 1024, TCA_OPTIONS, NULL, 0); addattr_l(n, 2024, TCA_HTB_PARMS, &opt, sizeof(opt)); addattr_l(n, 3024, TCA_HTB_RTAB, rtab, 1024); @@ -240,18 +251,20 @@ static int htb_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) { - struct rtattr *tb[TCA_HTB_RTAB+1]; + struct rtattr *tb[TCA_HTB_MAX + 1]; struct tc_htb_opt *hopt; struct tc_htb_glob *gopt; double buffer,cbuffer; + unsigned int linklayer; SPRINT_BUF(b1); SPRINT_BUF(b2); SPRINT_BUF(b3); + SPRINT_BUF(b4); if (opt == NULL) return 0; - parse_rtattr_nested(tb, TCA_HTB_RTAB, opt); + parse_rtattr_nested(tb, TCA_HTB_MAX, opt); if (tb[TCA_HTB_PARMS]) { hopt = RTA_DATA(tb[TCA_HTB_PARMS]); @@ -268,6 +281,9 @@ buffer = tc_calc_xmitsize(hopt->rate.rate, hopt->buffer); fprintf(f, "ceil %s ", sprint_rate(hopt->ceil.rate, b1)); cbuffer = tc_calc_xmitsize(hopt->ceil.rate, hopt->cbuffer); + linklayer = (hopt->rate.linklayer & TC_LINKLAYER_MASK); + if (linklayer > TC_LINKLAYER_ETHERNET || show_details) + fprintf(f, "linklayer %s ", sprint_linklayer(linklayer, b4)); if (show_details) { fprintf(f, "burst %s/%u mpu %s overhead %s ", sprint_size(buffer, b1), @@ -297,6 +313,12 @@ if (show_details) fprintf(f," ver %d.%d",gopt->version >> 16,gopt->version & 0xffff); } + if (tb[TCA_HTB_DIRECT_QLEN] && + RTA_PAYLOAD(tb[TCA_HTB_DIRECT_QLEN]) >= sizeof(__u32)) { + __u32 direct_qlen = rta_getattr_u32(tb[TCA_HTB_DIRECT_QLEN]); + + fprintf(f, " direct_qlen %u", direct_qlen); + } return 0; } @@ -321,16 +343,6 @@ .parse_qopt = htb_parse_opt, .print_qopt = htb_print_opt, .print_xstats = htb_print_xstats, - .parse_copt = htb_parse_class_opt, - .print_copt = htb_print_opt, -}; - -/* for testing of old one */ -struct qdisc_util htb2_qdisc_util = { - .id = "htb2", - .parse_qopt = htb_parse_opt, - .print_qopt = htb_print_opt, - .print_xstats = htb_print_xstats, .parse_copt = htb_parse_class_opt, .print_copt = htb_print_opt, }; diff -Nru iproute2-3.10.0/tc/q_tbf.c iproute2-3.12.0/tc/q_tbf.c --- iproute2-3.10.0/tc/q_tbf.c 2013-07-16 17:06:36.000000000 +0000 +++ iproute2-3.12.0/tc/q_tbf.c 2013-11-23 01:10:33.000000000 +0000 @@ -239,10 +239,12 @@ { struct rtattr *tb[TCA_TBF_PTAB+1]; struct tc_tbf_qopt *qopt; + unsigned int linklayer; double buffer, mtu; double latency; SPRINT_BUF(b1); SPRINT_BUF(b2); + SPRINT_BUF(b3); if (opt == NULL) return 0; @@ -294,6 +296,9 @@ if (qopt->rate.overhead) { fprintf(f, "overhead %d", qopt->rate.overhead); } + linklayer = (qopt->rate.linklayer & TC_LINKLAYER_MASK); + if (linklayer > TC_LINKLAYER_ETHERNET || show_details) + fprintf(f, "linklayer %s ", sprint_linklayer(linklayer, b3)); return 0; } diff -Nru iproute2-3.10.0/tc/tc_class.c iproute2-3.12.0/tc/tc_class.c --- iproute2-3.10.0/tc/tc_class.c 2013-07-16 17:06:36.000000000 +0000 +++ iproute2-3.12.0/tc/tc_class.c 2013-11-23 01:10:33.000000000 +0000 @@ -241,6 +241,9 @@ t.tcm_family = AF_UNSPEC; memset(d, 0, sizeof(d)); + filter_qdisc = 0; + filter_classid = 0; + while (argc > 0) { if (strcmp(*argv, "dev") == 0) { NEXT_ARG(); diff -Nru iproute2-3.10.0/tc/tc_core.c iproute2-3.12.0/tc/tc_core.c --- iproute2-3.10.0/tc/tc_core.c 2013-07-16 17:06:36.000000000 +0000 +++ iproute2-3.12.0/tc/tc_core.c 2013-11-23 01:10:33.000000000 +0000 @@ -102,6 +102,21 @@ } } +/* Notice, the rate table calculated here, have gotten replaced in the + * kernel and is no-longer used for lookups. + * + * This happened in kernel release v3.8 caused by kernel + * - commit 56b765b79 ("htb: improved accuracy at high rates"). + * This change unfortunately caused breakage of tc overhead and + * linklayer parameters. + * + * Kernel overhead handling got fixed in kernel v3.10 by + * - commit 01cb71d2d47 (net_sched: restore "overhead xxx" handling) + * + * Kernel linklayer handling got fixed in kernel v3.11 by + * - commit 8a8e3d84b17 (net_sched: restore "linklayer atm" handling) + */ + /* rtab[pkt_len>>cell_log] = pkt_xmit_time */ @@ -131,6 +146,7 @@ r->cell_align=-1; // Due to the sz calc r->cell_log=cell_log; + r->linklayer = (linklayer & TC_LINKLAYER_MASK); return cell_log; } diff -Nru iproute2-3.10.0/tc/tc_qdisc.c iproute2-3.12.0/tc/tc_qdisc.c --- iproute2-3.10.0/tc/tc_qdisc.c 2013-07-16 17:06:36.000000000 +0000 +++ iproute2-3.12.0/tc/tc_qdisc.c 2013-11-23 01:10:33.000000000 +0000 @@ -138,12 +138,13 @@ 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) diff -Nru iproute2-3.10.0/tc/tc_util.c iproute2-3.12.0/tc/tc_util.c --- iproute2-3.10.0/tc/tc_util.c 2013-07-16 17:06:36.000000000 +0000 +++ iproute2-3.12.0/tc/tc_util.c 2013-11-23 01:10:33.000000000 +0000 @@ -171,20 +171,24 @@ return 0; } -void print_rate(char *buf, int len, __u32 rate) +void print_rate(char *buf, int len, __u64 rate) { double tmp = (double)rate*8; extern int use_iec; if (use_iec) { - if (tmp >= 1000.0*1024.0*1024.0) + if (tmp >= 1000.0*1024.0*1024.0*1024.0) + snprintf(buf, len, "%.0fGibit", tmp/(1024.0*1024.0*1024.0)); + else if (tmp >= 1000.0*1024.0*1024.0) snprintf(buf, len, "%.0fMibit", tmp/(1024.0*1024.0)); else if (tmp >= 1000.0*1024) snprintf(buf, len, "%.0fKibit", tmp/1024); else snprintf(buf, len, "%.0fbit", tmp); } else { - if (tmp >= 1000.0*1000000.0) + if (tmp >= 1000.0*1000000000.0) + snprintf(buf, len, "%.0fGbit", tmp/1000000000.0); + else if (tmp >= 1000.0*1000000.0) snprintf(buf, len, "%.0fMbit", tmp/1000000.0); else if (tmp >= 1000.0 * 1000.0) snprintf(buf, len, "%.0fKbit", tmp/1000.0); @@ -193,7 +197,7 @@ } } -char * sprint_rate(__u32 rate, char *buf) +char * sprint_rate(__u64 rate, char *buf) { print_rate(buf, SPRINT_BSIZE-1, rate); return buf; @@ -460,9 +464,19 @@ q.drops, q.overlimits, q.requeues); } - if (tbs[TCA_STATS_RATE_EST]) { + if (tbs[TCA_STATS_RATE_EST64]) { + struct gnet_stats_rate_est64 re = {0}; + + memcpy(&re, RTA_DATA(tbs[TCA_STATS_RATE_EST64]), + MIN(RTA_PAYLOAD(tbs[TCA_STATS_RATE_EST64]), + sizeof(re))); + fprintf(fp, "\n%srate %s %llupps ", + prefix, sprint_rate(re.bps, b1), re.pps); + } else if (tbs[TCA_STATS_RATE_EST]) { struct gnet_stats_rate_est re = {0}; - memcpy(&re, RTA_DATA(tbs[TCA_STATS_RATE_EST]), MIN(RTA_PAYLOAD(tbs[TCA_STATS_RATE_EST]), sizeof(re))); + + memcpy(&re, RTA_DATA(tbs[TCA_STATS_RATE_EST]), + MIN(RTA_PAYLOAD(tbs[TCA_STATS_RATE_EST]), sizeof(re))); fprintf(fp, "\n%srate %s %upps ", prefix, sprint_rate(re.bps, b1), re.pps); } diff -Nru iproute2-3.10.0/tc/tc_util.h iproute2-3.12.0/tc/tc_util.h --- iproute2-3.10.0/tc/tc_util.h 2013-07-16 17:06:36.000000000 +0000 +++ iproute2-3.12.0/tc/tc_util.h 2013-11-23 01:10:33.000000000 +0000 @@ -63,12 +63,12 @@ extern int get_time(unsigned *time, const char *str); extern int get_linklayer(unsigned *val, const char *arg); -extern void print_rate(char *buf, int len, __u32 rate); +extern void print_rate(char *buf, int len, __u64 rate); extern void print_size(char *buf, int len, __u32 size); extern void print_qdisc_handle(char *buf, int len, __u32 h); extern void print_time(char *buf, int len, __u32 time); extern void print_linklayer(char *buf, int len, unsigned linklayer); -extern char * sprint_rate(__u32 rate, char *buf); +extern char * sprint_rate(__u64 rate, char *buf); extern char * sprint_size(__u32 size, char *buf); extern char * sprint_qdisc_handle(__u32 h, char *buf); extern char * sprint_tc_classid(__u32 h, char *buf);