diff --git a/package/network/utils/iproute2/patches/950-add-cake-to-tc.patch b/package/network/utils/iproute2/patches/950-add-cake-to-tc.patch index 5edb71ddc9..216d7c7ef3 100644 --- a/package/network/utils/iproute2/patches/950-add-cake-to-tc.patch +++ b/package/network/utils/iproute2/patches/950-add-cake-to-tc.patch @@ -1,6 +1,8 @@ +diff --git a/include/uapi/linux/pkt_sched.h b/include/uapi/linux/pkt_sched.h +index 37b5096a..66da5df9 100644 --- a/include/uapi/linux/pkt_sched.h +++ b/include/uapi/linux/pkt_sched.h -@@ -934,4 +934,62 @@ enum { +@@ -934,4 +934,75 @@ enum { #define TCA_CBS_MAX (__TCA_CBS_MAX - 1) @@ -17,7 +19,7 @@ + TCA_CAKE_AUTORATE, + TCA_CAKE_MEMORY, + TCA_CAKE_NAT, -+ TCA_CAKE_ETHERNET, ++ TCA_CAKE_RAW, // was _ETHERNET + TCA_CAKE_WASH, + TCA_CAKE_MPU, + TCA_CAKE_INGRESS, @@ -33,53 +35,757 @@ +}; + +#define TC_CAKE_MAX_TINS (8) ++struct tc_cake_tin_stats { ++ ++ __u32 threshold_rate; ++ __u32 target_us; ++ struct tc_cake_traffic_stats sent; ++ struct tc_cake_traffic_stats dropped; ++ struct tc_cake_traffic_stats ecn_marked; ++ struct tc_cake_traffic_stats backlog; ++ __u32 interval_us; ++ __u32 way_indirect_hits; ++ __u32 way_misses; ++ __u32 way_collisions; ++ __u32 peak_delay_us; /* ~= bulk flow delay */ ++ __u32 avge_delay_us; ++ __u32 base_delay_us; /* ~= sparse flows delay */ ++ __u16 sparse_flows; ++ __u16 bulk_flows; ++ __u16 unresponse_flows; ++ __u16 spare; ++ __u32 max_skblen; ++ struct tc_cake_traffic_stats ack_drops; ++}; ++ +struct tc_cake_xstats { -+ __u16 version; /* == 5, increments when struct extended */ -+ __u8 max_tins; /* == TC_CAKE_MAX_TINS */ -+ __u8 tin_cnt; /* <= TC_CAKE_MAX_TINS */ -+ -+ __u32 threshold_rate [TC_CAKE_MAX_TINS]; -+ __u32 target_us [TC_CAKE_MAX_TINS]; -+ struct tc_cake_traffic_stats sent [TC_CAKE_MAX_TINS]; -+ struct tc_cake_traffic_stats dropped [TC_CAKE_MAX_TINS]; -+ struct tc_cake_traffic_stats ecn_marked[TC_CAKE_MAX_TINS]; -+ struct tc_cake_traffic_stats backlog [TC_CAKE_MAX_TINS]; -+ __u32 interval_us [TC_CAKE_MAX_TINS]; -+ __u32 way_indirect_hits[TC_CAKE_MAX_TINS]; -+ __u32 way_misses [TC_CAKE_MAX_TINS]; -+ __u32 way_collisions [TC_CAKE_MAX_TINS]; -+ __u32 peak_delay_us [TC_CAKE_MAX_TINS]; /* ~= bulk flow delay */ -+ __u32 avge_delay_us [TC_CAKE_MAX_TINS]; -+ __u32 base_delay_us [TC_CAKE_MAX_TINS]; /* ~= sparse flows delay */ -+ __u16 sparse_flows [TC_CAKE_MAX_TINS]; -+ __u16 bulk_flows [TC_CAKE_MAX_TINS]; -+ __u16 unresponse_flows [TC_CAKE_MAX_TINS]; /* v4 - was u32 last_len */ -+ __u16 spare [TC_CAKE_MAX_TINS]; /* v4 - split last_len */ -+ __u32 max_skblen [TC_CAKE_MAX_TINS]; -+ __u32 capacity_estimate; /* version 2 */ -+ __u32 memory_limit; /* version 3 */ -+ __u32 memory_used; /* version 3 */ -+ struct tc_cake_traffic_stats ack_drops [TC_CAKE_MAX_TINS]; /* v5 */ ++ __u16 version; ++ __u16 tin_stats_size; /* == sizeof(struct tc_cake_tin_stats) */ ++ __u32 capacity_estimate; ++ __u32 memory_limit; ++ __u32 memory_used; ++ __u8 tin_cnt; ++ __u8 avg_trnoff; ++ __u16 max_trnlen; ++ __u16 max_adjlen; ++ __u16 min_trnlen; ++ __u16 min_adjlen; ++ ++ __u16 spare1; ++ __u32 spare2; ++ ++ struct tc_cake_tin_stats tin_stats[0]; /* keep last */ +}; + #endif +diff --git a/man/man8/tc-cake.8 b/man/man8/tc-cake.8 +new file mode 100644 +index 00000000..ff77db8f +--- /dev/null ++++ b/man/man8/tc-cake.8 +@@ -0,0 +1,678 @@ ++.TH CAKE 8 "23 November 2017" "iproute2" "Linux" ++.SH NAME ++CAKE \- COMMON Applications Kept Enhanced (CAKE) ++.SH SYNOPSIS ++.B tc qdisc ... cake ++.br ++[ ++.BR bandwidth ++RATE | ++.BR unlimited* ++| ++.BR autorate_ingress ++] ++.br ++[ ++.BR rtt ++TIME | ++.BR datacentre ++| ++.BR lan ++| ++.BR metro ++| ++.BR regional ++| ++.BR internet* ++| ++.BR oceanic ++| ++.BR satellite ++| ++.BR interplanetary ++] ++.br ++[ ++.BR besteffort ++| ++.BR diffserv8 ++| ++.BR diffserv4 ++| ++.BR diffserv-llt ++| ++.BR diffserv3* ++] ++.br ++[ ++.BR flowblind ++| ++.BR srchost ++| ++.BR dsthost ++| ++.BR hosts ++| ++.BR flows ++| ++.BR dual-srchost ++| ++.BR dual-dsthost ++| ++.BR triple-isolate* ++] ++.br ++[ ++.BR nat ++| ++.BR nonat* ++] ++.br ++[ ++.BR wash ++| ++.BR nowash* ++] ++.br ++[ ++.BR ack-filter ++| ++.BR ack-filter-aggressive ++| ++.BR no-ack-filter* ++] ++.br ++[ ++.BR memlimit ++LIMIT ] ++.br ++[ ++.BR ptm ++| ++.BR atm ++| ++.BR noatm* ++] ++.br ++[ ++.BR overhead ++N | ++.BR conservative ++| ++.BR raw* ++] ++.br ++[ ++.BR mpu ++N ] ++.br ++[ ++.BR ingress ++| ++.BR egress* ++] ++.br ++(* marks defaults) ++ ++ ++.SH DESCRIPTION ++CAKE (Common Applications Kept Enhanced) is a shaping-capable queue discipline ++which uses both AQM and FQ. It combines COBALT, which is an AQM algorithm ++combining Codel and BLUE, a shaper which operates in deficit mode, and a variant ++of DRR++ for flow isolation. 8-way set-associative hashing is used to virtually ++eliminate hash collisions. Priority queuing is available through a simplified ++diffserv implementation. Overhead compensation for various encapsulation ++schemes is tightly integrated. ++ ++All settings are optional; the default settings are chosen to be sensible in ++most common deployments. Most people will only need to set the ++.B bandwidth ++parameter to get useful results, but reading the ++.B Overhead Compensation ++and ++.B Round Trip Time ++sections is strongly encouraged. ++ ++.SH SHAPER PARAMETERS ++CAKE uses a deficit-mode shaper, which does not exhibit the initial burst ++typical of token-bucket shapers. It will automatically burst precisely as much ++as required to maintain the configured throughput. As such, it is very ++straightforward to configure. ++.PP ++.B unlimited ++(default) ++.br ++ No limit on the bandwidth. ++.PP ++.B bandwidth ++RATE ++.br ++ Set the shaper bandwidth. See ++.BR tc(8) ++or examples below for details of the RATE value. ++.PP ++.B autorate_ingress ++.br ++ Automatic capacity estimation based on traffic arriving at this qdisc. ++This is most likely to be useful with cellular links, which tend to change ++quality randomly. A ++.B bandwidth ++parameter can be used in conjunction to specify an initial estimate. The shaper ++will periodically be set to a bandwidth slightly below the estimated rate. This ++estimator cannot estimate the bandwidth of links downstream of itself. ++ ++.SH OVERHEAD COMPENSATION PARAMETERS ++The size of each packet on the wire may differ from that seen by Linux. The ++following parameters allow CAKE to compensate for this difference by internally ++considering each packet to be bigger than Linux informs it. To assist users who ++are not expert network engineers, keywords have been provided to represent a ++number of common link technologies. ++ ++.SS Manual Overhead Specification ++.B overhead ++BYTES ++.br ++ Adds BYTES to the size of each packet. BYTES may be negative; values ++between -64 and 256 (inclusive) are accepted. ++.PP ++.B mpu ++BYTES ++.br ++ Rounds each packet (including overhead) up to a minimum length ++BYTES. BYTES may not be negative; values between 0 and 256 (inclusive) ++are accepted. ++.PP ++.B atm ++.br ++ Compensates for ATM cell framing, which is normally found on ADSL links. ++This is performed after the ++.B overhead ++parameter above. ATM uses fixed 53-byte cells, each of which can carry 48 bytes ++payload. ++.PP ++.B ptm ++.br ++ Compensates for PTM encoding, which is normally found on VDSL2 links and ++uses a 64b/65b encoding scheme. It is even more efficient to simply ++derate the specified shaper bandwidth by a factor of 64/65 or 0.984. See ++ITU G.992.3 Annex N and IEEE 802.3 Section 61.3 for details. ++.PP ++.B noatm ++.br ++ Disables ATM and PTM compensation. ++ ++.SS Failsafe Overhead Keywords ++These two keywords are provided for quick-and-dirty setup. Use them if you ++can't be bothered to read the rest of this section. ++.PP ++.B raw ++(default) ++.br ++ Turns off all overhead compensation in CAKE. The packet size reported ++by Linux will be used directly. ++.PP ++ Other overhead keywords may be added after "raw". The effect of this is ++to make the overhead compensation operate relative to the reported packet size, ++not the underlying IP packet size. ++.PP ++.B conservative ++.br ++ Compensates for more overhead than is likely to occur on any ++widely-deployed link technology. ++.br ++ Equivalent to ++.B overhead 48 atm. ++ ++.SS ADSL Overhead Keywords ++Most ADSL modems have a way to check which framing scheme is in use. Often this ++is also specified in the settings document provided by the ISP. The keywords in ++this section are intended to correspond with these sources of information. All ++of them implicitly set the ++.B atm ++flag. ++.PP ++.B pppoa-vcmux ++.br ++ Equivalent to ++.B overhead 10 atm ++.PP ++.B pppoa-llc ++.br ++ Equivalent to ++.B overhead 14 atm ++.PP ++.B pppoe-vcmux ++.br ++ Equivalent to ++.B overhead 32 atm ++.PP ++.B pppoe-llcsnap ++.br ++ Equivalent to ++.B overhead 40 atm ++.PP ++.B bridged-vcmux ++.br ++ Equivalent to ++.B overhead 24 atm ++.PP ++.B bridged-llcsnap ++.br ++ Equivalent to ++.B overhead 32 atm ++.PP ++.B ipoa-vcmux ++.br ++ Equivalent to ++.B overhead 8 atm ++.PP ++.B ipoa-llcsnap ++.br ++ Equivalent to ++.B overhead 16 atm ++.PP ++See also the Ethernet Correction Factors section below. ++ ++.SS VDSL2 Overhead Keywords ++ATM was dropped from VDSL2 in favour of PTM, which is a much more ++straightforward framing scheme. Some ISPs retained PPPoE for compatibility with ++their existing back-end systems. ++.PP ++.B pppoe-ptm ++.br ++ Equivalent to ++.B overhead 30 ptm ++ ++.br ++ PPPoE: 2B PPP + 6B PPPoE + ++.br ++ ETHERNET: 6B dest MAC + 6B src MAC + 2B ethertype + 4B Frame Check Sequence + ++.br ++ PTM: 1B Start of Frame (S) + 1B End of Frame (Ck) + 2B TC-CRC (PTM-FCS) ++.br ++.PP ++.B bridged-ptm ++.br ++ Equivalent to ++.B overhead 22 ptm ++.br ++ ETHERNET: 6B dest MAC + 6B src MAC + 2B ethertype + 4B Frame Check Sequence + ++.br ++ PTM: 1B Start of Frame (S) + 1B End of Frame (Ck) + 2B TC-CRC (PTM-FCS) ++.br ++.PP ++See also the Ethernet Correction Factors section below. ++ ++.SS DOCSIS Cable Overhead Keyword ++DOCSIS is the universal standard for providing Internet service over cable-TV ++infrastructure. ++ ++In this case, the actual on-wire overhead is less important than the packet size ++the head-end equipment uses for shaping and metering. This is specified to be ++an Ethernet frame including the CRC (aka FCS). ++.PP ++.B docsis ++.br ++ Equivalent to ++.B overhead 18 mpu 64 noatm ++ ++.SS Ethernet Overhead Keywords ++.PP ++.B ethernet ++.br ++ Accounts for Ethernet's preamble, inter-frame gap, and Frame Check ++Sequence. Use this keyword when the bottleneck being shaped for is an ++actual Ethernet cable. ++.br ++ Equivalent to ++.B overhead 38 mpu 84 noatm ++.PP ++.B ether-vlan ++.br ++ Adds 4 bytes to the overhead compensation, accounting for an IEEE 802.1Q ++VLAN header appended to the Ethernet frame header. NB: Some ISPs use one or ++even two of these within PPPoE; this keyword may be repeated as necessary to ++express this. ++ ++.SH ROUND TRIP TIME PARAMETERS ++Active Queue Management (AQM) consists of embedding congestion signals in the ++packet flow, which receivers use to instruct senders to slow down when the queue ++is persistently occupied. CAKE uses ECN signalling when available, and packet ++drops otherwise, according to a combination of the Codel and BLUE AQM algorithms ++called COBALT. ++ ++Very short latencies require a very rapid AQM response to adequately control ++latency. However, such a rapid response tends to impair throughput when the ++actual RTT is relatively long. CAKE allows specifying the RTT it assumes for ++tuning various parameters. Actual RTTs within an order of magnitude of this ++will generally work well for both throughput and latency management. ++ ++At the 'lan' setting and below, the time constants are similar in magnitude to ++the jitter in the Linux kernel itself, so congestion might be signalled ++prematurely. The flows will then become sparse and total throughput reduced, ++leaving little or no back-pressure for the fairness logic to work against. Use ++the "metro" setting for local lans unless you have a custom kernel. ++.PP ++.B rtt ++TIME ++.br ++ Manually specify an RTT. ++.PP ++.B datacentre ++.br ++ For extremely high-performance 10GigE+ networks only. Equivalent to ++.B rtt 100us. ++.PP ++.B lan ++.br ++ For pure Ethernet (not Wi-Fi) networks, at home or in the office. Don't ++use this when shaping for an Internet access link. Equivalent to ++.B rtt 1ms. ++.PP ++.B metro ++.br ++ For traffic mostly within a single city. Equivalent to ++.B rtt 10ms. ++.PP ++.B regional ++.br ++ For traffic mostly within a European-sized country. Equivalent to ++.B rtt 30ms. ++.PP ++.B internet ++(default) ++.br ++ This is suitable for most Internet traffic. Equivalent to ++.B rtt 100ms. ++.PP ++.B oceanic ++.br ++ For Internet traffic with generally above-average latency, such as that ++suffered by Australasian residents. Equivalent to ++.B rtt 300ms. ++.PP ++.B satellite ++.br ++ For traffic via geostationary satellites. Equivalent to ++.B rtt 1000ms. ++.PP ++.B interplanetary ++.br ++ So named because Jupiter is about 1 light-hour from Earth. Use this to ++(almost) completely disable AQM actions. Equivalent to ++.B rtt 1000s. ++ ++.SH FLOW ISOLATION PARAMETERS ++With flow isolation enabled, CAKE places packets from different flows into ++different queues, each of which carries its own AQM state. Packets from each ++queue are then delivered fairly, according to a DRR++ algorithm which minimises ++latency for "sparse" flows. CAKE uses a set-associative hashing algorithm to ++minimise flow collisions. ++ ++These keywords specify whether fairness based on source address, destination ++address, individual flows, or any combination of those is desired. ++.PP ++.B flowblind ++.br ++ Disables flow isolation; all traffic passes through a single queue for ++each tin. ++.PP ++.B srchost ++.br ++ Flows are defined only by source address. Could be useful on the egress ++path of an ISP backhaul. ++.PP ++.B dsthost ++.br ++ Flows are defined only by destination address. Could be useful on the ++ingress path of an ISP backhaul. ++.PP ++.B hosts ++.br ++ Flows are defined by source-destination host pairs. This is host ++isolation, rather than flow isolation. ++.PP ++.B flows ++.br ++ Flows are defined by the entire 5-tuple of source address, destination ++address, transport protocol, source port and destination port. This is the type ++of flow isolation performed by SFQ and fq_codel. ++.PP ++.B dual-srchost ++.br ++ Flows are defined by the 5-tuple, and fairness is applied first over ++source addresses, then over individual flows. Good for use on egress traffic ++from a LAN to the internet, where it'll prevent any one LAN host from ++monopolising the uplink, regardless of the number of flows they use. ++.PP ++.B dual-dsthost ++.br ++ Flows are defined by the 5-tuple, and fairness is applied first over ++destination addresses, then over individual flows. Good for use on ingress ++traffic to a LAN from the internet, where it'll prevent any one LAN host from ++monopolising the downlink, regardless of the number of flows they use. ++.PP ++.B triple-isolate ++(default) ++.br ++ Flows are defined by the 5-tuple, and fairness is applied over source ++*and* destination addresses intelligently (ie. not merely by host-pairs), and ++also over individual flows. Use this if you're not certain whether to use ++dual-srchost or dual-dsthost; it'll do both jobs at once, preventing any one ++host on *either* side of the link from monopolising it with a large number of ++flows. ++.PP ++.B nat ++.br ++ Instructs Cake to perform a NAT lookup before applying flow-isolation ++rules, to determine the true addresses and port numbers of the packet, to ++improve fairness between hosts "inside" the NAT. This has no practical effect ++in "flowblind" or "flows" modes, or if NAT is performed on a different host. ++.PP ++.B nonat ++(default) ++.br ++ Cake will not perform a NAT lookup. Flow isolation will be performed ++using the addresses and port numbers directly visible to the interface Cake is ++attached to. ++ ++.SH PRIORITY QUEUE PARAMETERS ++CAKE can divide traffic into "tins" based on the Diffserv field. Each tin has ++its own independent set of flow-isolation queues, and is serviced based on a WRR ++algorithm. To avoid perverse Diffserv marking incentives, tin weights have a ++"priority sharing" value when bandwidth used by that tin is below a threshold, ++and a lower "bandwidth sharing" value when above. Bandwidth is compared against ++the threshold using the same algorithm as the deficit-mode shaper. ++ ++Detailed customisation of tin parameters is not provided. The following presets ++perform all necessary tuning, relative to the current shaper bandwidth and RTT ++settings. ++.PP ++.B besteffort ++.br ++ Disables priority queuing by placing all traffic in one tin. ++.PP ++.B precedence ++.br ++ Enables legacy interpretation of TOS "Precedence" field. Use of this ++preset on the modern Internet is firmly discouraged. ++.PP ++.B diffserv-llt ++.br ++ Provides a "Latency-Loss Tradeoff" implementation with five tins: ++.br ++ Low Loss (TOS1, TOS2), 100% threshold, increased Codel target. ++.br ++ Best Effort (general), 100% threshold, normal Codel target & interval. ++.br ++ Low Latency (TOS4, TOS5, VA, EF), 100% threshold, reduced Codel interval. ++.br ++ Bulk (CS1), 6.25% threshold, normal Codel target & interval. ++.br ++ Net Control (CS6, CS7), 6.25% threshold, increased Codel target & interval. ++.PP ++.B diffserv4 ++.br ++ Provides a general-purpose Diffserv implementation with four tins: ++.br ++ Bulk (CS1), 6.25% threshold, generally low priority. ++.br ++ Best Effort (general), 100% threshold. ++.br ++ Video (AF4x, AF3x, CS3, AF2x, CS2, TOS4, TOS1), 50% threshold. ++.br ++ Voice (CS7, CS6, EF, VA, CS5, CS4), 25% threshold. ++.PP ++.B diffserv3 ++(default) ++.br ++ Provides a simple, general-purpose Diffserv implementation with three tins: ++.br ++ Bulk (CS1), 6.25% threshold, generally low priority. ++.br ++ Best Effort (general), 100% threshold. ++.br ++ Voice (CS7, CS6, EF, VA, TOS4), 25% threshold, reduced Codel interval. ++ ++.SH OTHER PARAMETERS ++.B memlimit ++LIMIT ++.br ++ Limit the memory consumed by Cake to LIMIT bytes. Note that this does ++not translate directly to queue size (so do not size this based on bandwidth ++delay product considerations, but rather on worst case acceptable memory ++consumption), as there is some overhead in the data structures containing the ++packets, especially for small packets. ++ ++ By default, the limit is calculated based on the bandwidth and RTT ++settings. ++ ++.PP ++.B wash ++ ++.br ++ Traffic entering your diffserv domain is frequently mis-marked in ++transit from the perspective of your network, and traffic exiting yours may be ++mis-marked from the perspective of the transiting provider. ++ ++Apply the wash option to clear all extra diffserv (but not ECN bits), after ++priority queuing has taken place. ++ ++If you are shaping inbound, and cannot trust the diffserv markings (as is the ++case for Comcast Cable, among others), it is best to use a single queue ++"besteffort" mode with wash. ++ ++.SH EXAMPLES ++# tc qdisc delete root dev eth0 ++.br ++# tc qdisc add root dev eth0 cake bandwidth 9500Kbit pppoe-ptm ether-vlan ++.br ++# tc -s qdisc show dev eth0 ++.br ++qdisc cake 8007: root refcnt 6 bandwidth 9500Kbit diffserv3 triple-isolate rtt 100.0ms ptm overhead 34 via-ethernet total_overhead 34 hard_header_len 14 ++ Sent 0 bytes 0 pkt (dropped 0, overlimits 0 requeues 0) ++ backlog 0b 0p requeues 0 ++ memory used: 0b of 4Mb ++ capacity estimate: 9500Kbit ++.br ++ Bulk Best Effort Voice ++.br ++ thresh 593744bit 9500Kbit 2375Kbit ++.br ++ target 30.6ms 5.0ms 7.6ms ++.br ++ interval 125.6ms 100.0ms 102.6ms ++.br ++ pk_delay 0us 0us 0us ++.br ++ av_delay 0us 0us 0us ++.br ++ sp_delay 0us 0us 0us ++.br ++ pkts 0 0 0 ++.br ++ bytes 0 0 0 ++.br ++ way_inds 0 0 0 ++.br ++ way_miss 0 0 0 ++.br ++ way_cols 0 0 0 ++.br ++ drops 0 0 0 ++.br ++ marks 0 0 0 ++.br ++ ack_drop 0 0 0 ++.br ++ sp_flows 0 0 0 ++.br ++ bk_flows 0 0 0 ++.br ++ un_flows 0 0 0 ++.br ++ max_len 0 0 0 ++.br ++ ++After some use: ++.br ++# tc -s qdisc show dev eth0 ++ ++qdisc cake 8007: root refcnt 6 bandwidth 9500Kbit diffserv3 triple-isolate rtt 100.0ms ptm overhead 34 via-ethernet total_overhead 34 hard_header_len 14 ++ Sent 110769306 bytes 313857 pkt (dropped 18, overlimits 741791 requeues 0) ++ backlog 0b 0p requeues 0 ++ memory used: 110488b of 4Mb ++ capacity estimate: 9500Kbit ++.br ++ Bulk Best Effort Voice ++.br ++ thresh 593744bit 9500Kbit 2375Kbit ++.br ++ target 30.6ms 5.0ms 7.6ms ++.br ++ interval 125.6ms 100.0ms 102.6ms ++.br ++ pk_delay 16.0ms 545us 15us ++.br ++ av_delay 2.4ms 161us 3us ++.br ++ sp_delay 59us 1us 1us ++.br ++ pkts 32866 195815 85194 ++.br ++ bytes 8132614 69517496 33122156 ++.br ++ way_inds 0 29208 0 ++.br ++ way_miss 7 173 17 ++.br ++ way_cols 0 0 0 ++.br ++ drops 10 7 1 ++.br ++ marks 217 692 300 ++.br ++ ack_drop 0 0 0 ++.br ++ sp_flows 0 0 0 ++.br ++ bk_flows 0 0 1 ++.br ++ un_flows 0 0 0 ++.br ++ max_len 3028 3012 3028 ++.br ++ ++.SH SEE ALSO ++.BR tc (8), ++.BR tc-codel (8), ++.BR tc-fq_codel (8), ++.BR tc-red (8) ++ ++.SH AUTHORS ++Cake's principal author is Jonathan Morton, with contributions from ++Tony Ambardar, Kevin Darbyshire-Bryant, Toke Høiland-Jørgensen, ++Sebastian Moeller, Ryan Mounce, Dean Scarff, Nils Andreas Svee, and Dave Täht. ++ ++This manual page was written by Loganaden Velvindron. Please report corrections ++to the Linux Networking mailing list . +diff --git a/tc/Makefile b/tc/Makefile +index 3716dd6a..69f50a6b 100644 --- a/tc/Makefile +++ b/tc/Makefile -@@ -66,6 +66,7 @@ TCMODULES += q_codel.o +@@ -64,6 +64,7 @@ TCMODULES += em_meta.o + TCMODULES += q_mqprio.o + TCMODULES += q_codel.o TCMODULES += q_fq_codel.o ++TCMODULES += q_cake.o TCMODULES += q_fq.o TCMODULES += q_pie.o -+TCMODULES += q_cake.o TCMODULES += q_hhf.o - TCMODULES += q_clsact.o - TCMODULES += e_bpf.o +diff --git a/tc/q_cake.c b/tc/q_cake.c +new file mode 100644 +index 00000000..44cadb63 --- /dev/null +++ b/tc/q_cake.c -@@ -0,0 +1,771 @@ +@@ -0,0 +1,770 @@ ++/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */ +/* + * Common Applications Kept Enhanced -- CAKE + * -+ * Copyright (C) 2014-2015 Jonathan Morton ++ * Copyright (C) 2014-2018 Jonathan Morton ++ * Copyright (C) 2017-2018 Toke Høiland-Jørgensen + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions @@ -138,8 +844,8 @@ +" [ flowblind | srchost | dsthost | hosts | flows |\n" +" dual-srchost | dual-dsthost | triple-isolate* ]\n" +" [ nat | nonat* ]\n" -+" [ wash | nowash * ]\n" -+" [ ack-filter | ack-filter-aggressive | no-ack-filter * ]\n" ++" [ wash | nowash* ]\n" ++" [ ack-filter | ack-filter-aggressive | no-ack-filter* ]\n" +" [ memlimit LIMIT ]\n" +" [ ptm | atm | noatm* ] [ overhead N | conservative | raw* ]\n" +" [ mpu N ] [ ingress | egress* ]\n" @@ -147,7 +853,7 @@ +} + +static int cake_parse_opt(struct qdisc_util *qu, int argc, char **argv, -+ struct nlmsghdr *n) ++ struct nlmsghdr *n, const char *dev) +{ + int unlimited = 0; + unsigned bandwidth = 0; @@ -215,8 +921,8 @@ + interval = 1000000; + target = 50000; + } else if (strcmp(*argv, "interplanetary") == 0) { -+ interval = 3600000000U; -+ target = 5000; ++ interval = 1000000000; ++ target = 50000000; + + } else if (strcmp(*argv, "besteffort") == 0) { + diffserv = 1; @@ -351,23 +1057,6 @@ + * active. + */ + -+ } else if (strcmp(*argv, "total_overhead") == 0) { -+ /* -+ * This is the overhead cake accounts for; added here so -+ * that cake's "tc -s qdisc" output can be directly -+ * pasted into the tc command to instantate a new cake.. -+ */ -+ NEXT_ARG(); -+ -+ } else if (strcmp(*argv, "hard_header_len") == 0) { -+ /* -+ * This is the overhead the kernel automatically -+ * accounted for; added here so that cake's "tc -s -+ * qdisc" output can be directly pasted into the tc -+ * command to instantiate a new cake.. -+ */ -+ NEXT_ARG(); -+ + } else if (strcmp(*argv, "ethernet") == 0) { + /* ethernet pre-amble & interframe gap & FCS + * you may need to add vlan tag */ @@ -454,7 +1143,7 @@ + addattr_l(n, 1024, TCA_CAKE_OVERHEAD, &overhead, sizeof(overhead)); + if (overhead_override) { + unsigned zero = 0; -+ addattr_l(n, 1024, TCA_CAKE_ETHERNET, &zero, sizeof(zero)); ++ addattr_l(n, 1024, TCA_CAKE_RAW, &zero, sizeof(zero)); + } + if (mpu > 0) + addattr_l(n, 1024, TCA_CAKE_MPU, &mpu, sizeof(mpu)); @@ -489,7 +1178,7 @@ + unsigned interval = 0; + unsigned memlimit = 0; + int overhead = 0; -+ int ethernet = 0; ++ int raw = 0; + int mpu = 0; + int atm = 0; + int nat = 0; @@ -508,43 +1197,44 @@ + if (tb[TCA_CAKE_BASE_RATE] && + RTA_PAYLOAD(tb[TCA_CAKE_BASE_RATE]) >= sizeof(__u32)) { + bandwidth = rta_getattr_u32(tb[TCA_CAKE_BASE_RATE]); -+ if(bandwidth) -+ fprintf(f, "bandwidth %s ", sprint_rate(bandwidth, b1)); -+ else -+ fprintf(f, "unlimited "); ++ if(bandwidth) { ++ print_uint(PRINT_JSON, "bandwidth", NULL, bandwidth); ++ print_string(PRINT_FP, NULL, "bandwidth %s ", sprint_rate(bandwidth, b1)); ++ } else ++ print_string(PRINT_ANY, "bandwidth", "bandwidth %s ", "unlimited"); + } + if (tb[TCA_CAKE_AUTORATE] && + RTA_PAYLOAD(tb[TCA_CAKE_AUTORATE]) >= sizeof(__u32)) { + autorate = rta_getattr_u32(tb[TCA_CAKE_AUTORATE]); + if(autorate == 1) -+ fprintf(f, "autorate_ingress "); ++ print_string(PRINT_ANY, "autorate", "autorate_%s ", "ingress"); + else if(autorate) -+ fprintf(f, "(?autorate?) "); ++ print_string(PRINT_ANY, "autorate", "(?autorate?) ", "unknown"); + } + if (tb[TCA_CAKE_DIFFSERV_MODE] && + RTA_PAYLOAD(tb[TCA_CAKE_DIFFSERV_MODE]) >= sizeof(__u32)) { + diffserv = rta_getattr_u32(tb[TCA_CAKE_DIFFSERV_MODE]); + switch(diffserv) { + case 1: -+ fprintf(f, "besteffort "); ++ print_string(PRINT_ANY, "diffserv", "%s ", "besteffort"); + break; + case 2: -+ fprintf(f, "precedence "); ++ print_string(PRINT_ANY, "diffserv", "%s ", "precedence"); + break; + case 3: -+ fprintf(f, "diffserv8 "); ++ print_string(PRINT_ANY, "diffserv", "%s ", "diffserv8"); + break; + case 4: -+ fprintf(f, "diffserv4 "); ++ print_string(PRINT_ANY, "diffserv", "%s ", "diffserv4"); + break; + case 5: -+ fprintf(f, "diffserv-llt "); ++ print_string(PRINT_ANY, "diffserv", "%s ", "diffserv-llt"); + break; + case 6: -+ fprintf(f, "diffserv3 "); ++ print_string(PRINT_ANY, "diffserv", "%s ", "diffserv3"); + break; + default: -+ fprintf(f, "(?diffserv?) "); ++ print_string(PRINT_ANY, "diffserv", "(?diffserv?) ", "unknown"); + break; + }; + } @@ -555,36 +1245,37 @@ + flowmode &= ~64; + switch(flowmode) { + case 0: -+ fprintf(f, "flowblind "); ++ print_string(PRINT_ANY, "flowmode", "%s ", "flowblind"); + break; + case 1: -+ fprintf(f, "srchost "); ++ print_string(PRINT_ANY, "flowmode", "%s ", "srchost"); + break; + case 2: -+ fprintf(f, "dsthost "); ++ print_string(PRINT_ANY, "flowmode", "%s ", "dsthost"); + break; + case 3: -+ fprintf(f, "hosts "); ++ print_string(PRINT_ANY, "flowmode", "%s ", "hosts"); + break; + case 4: -+ fprintf(f, "flows "); ++ print_string(PRINT_ANY, "flowmode", "%s ", "flows"); + break; + case 5: -+ fprintf(f, "dual-srchost "); ++ print_string(PRINT_ANY, "flowmode", "%s ", "dual-srchost"); + break; + case 6: -+ fprintf(f, "dual-dsthost "); ++ print_string(PRINT_ANY, "flowmode", "%s ", "dual-dsthost"); + break; + case 7: -+ fprintf(f, "triple-isolate "); ++ print_string(PRINT_ANY, "flowmode", "%s ", "triple-isolate"); + break; + default: -+ fprintf(f, "(?flowmode?) "); ++ print_string(PRINT_ANY, "flowmode", "(?flowmode?) ", "unknown"); + break; + }; + + if(nat) -+ fprintf(f, "nat "); ++ print_string(PRINT_FP, NULL, "nat ", NULL); ++ print_bool(PRINT_JSON, "nat", NULL, nat); + } + if (tb[TCA_CAKE_WASH] && + RTA_PAYLOAD(tb[TCA_CAKE_WASH]) >= sizeof(__u32)) { @@ -610,9 +1301,8 @@ + RTA_PAYLOAD(tb[TCA_CAKE_ACK_FILTER]) >= sizeof(__u32)) { + ack_filter = rta_getattr_u32(tb[TCA_CAKE_ACK_FILTER]); + } -+ if (tb[TCA_CAKE_ETHERNET] && -+ RTA_PAYLOAD(tb[TCA_CAKE_ETHERNET]) >= sizeof(__u32)) { -+ ethernet = rta_getattr_u32(tb[TCA_CAKE_ETHERNET]); ++ if (tb[TCA_CAKE_RAW]) { ++ raw = 1; + } + if (tb[TCA_CAKE_RTT] && + RTA_PAYLOAD(tb[TCA_CAKE_RTT]) >= sizeof(__u32)) { @@ -620,224 +1310,237 @@ + } + + if (wash) -+ fprintf(f,"wash "); ++ print_string(PRINT_FP, NULL, "wash ", NULL); ++ print_bool(PRINT_JSON, "wash", NULL, wash); + + if (ingress) -+ fprintf(f,"ingress "); ++ print_string(PRINT_FP, NULL, "ingress ", NULL); ++ print_bool(PRINT_JSON, "ingress", NULL, ingress); + + if (ack_filter == 0x0600) -+ fprintf(f,"ack-filter-aggressive "); ++ print_string(PRINT_ANY, "ack-filter", "ack-filter-%s ", "aggressive"); + else if (ack_filter) -+ fprintf(f,"ack-filter "); ++ print_string(PRINT_ANY, "ack-filter", "ack-filter ", "enabled"); ++ else ++ print_string(PRINT_JSON, "ack-filter", NULL, "disabled"); + + if (interval) -+ fprintf(f, "rtt %s ", sprint_time(interval, b2)); -+ -+ if (!atm && overhead == ethernet) { -+ fprintf(f, "raw "); -+ } else { -+ if (atm == 1) -+ fprintf(f, "atm "); -+ else if (atm == 2) -+ fprintf(f, "ptm "); -+ else -+ fprintf(f, "noatm "); -+ -+ fprintf(f, "overhead %d ", overhead); -+ -+ /* This is actually the *amount* of automatic compensation, but -+ * we only report its presence as a boolean for now. -+ */ -+ if (ethernet) -+ fprintf(f, "via-ethernet "); -+ } ++ print_string(PRINT_FP, NULL, "rtt %s ", sprint_time(interval, b2)); ++ print_uint(PRINT_JSON, "rtt", NULL, interval); + -+ /* unconditionally report the overhead and hard_header_len overhead the -+ * kernel added automatically -+ */ -+ fprintf(f, "total_overhead %d ", overhead); -+ fprintf(f, "hard_header_len %d ", ethernet); ++ if (raw) ++ print_string(PRINT_FP, NULL, "raw ", NULL); ++ print_bool(PRINT_JSON, "raw", NULL, raw); + -+ if (mpu) { -+ fprintf(f, "mpu %d ", mpu); -+ } ++ if (atm == 1) ++ print_string(PRINT_ANY, "atm", "%s ", "atm"); ++ else if (atm == 2) ++ print_string(PRINT_ANY, "atm", "%s ", "ptm"); ++ else if (!raw) ++ print_string(PRINT_ANY, "atm", "%s ", "noatm"); + -+ if (memlimit) -+ fprintf(f, "memlimit %s", sprint_size(memlimit, b1)); ++ print_uint(PRINT_ANY, "overhead", "overhead %d ", overhead); ++ ++ if (mpu) ++ print_uint(PRINT_ANY, "mpu", "mpu %d ", mpu); ++ ++ if (memlimit) { ++ print_uint(PRINT_JSON, "memlimit", NULL, memlimit); ++ print_string(PRINT_FP, NULL, "memlimit %s", sprint_size(memlimit, b1)); ++ } + + return 0; +} + ++#define FOR_EACH_TIN(xstats, tst, i) \ ++ for(tst = xstats->tin_stats, i = 0; \ ++ i < xstats->tin_cnt; \ ++ i++, tst = ((void *) xstats->tin_stats) + xstats->tin_stats_size * i) ++ ++static void cake_print_json_tin(struct tc_cake_tin_stats *tst) ++{ ++ open_json_object(NULL); ++ print_uint(PRINT_JSON, "threshold_rate", NULL, tst->threshold_rate); ++ print_uint(PRINT_JSON, "target", NULL, tst->target_us); ++ print_uint(PRINT_JSON, "interval", NULL, tst->interval_us); ++ print_uint(PRINT_JSON, "peak_delay", NULL, tst->peak_delay_us); ++ print_uint(PRINT_JSON, "average_delay", NULL, tst->avge_delay_us); ++ print_uint(PRINT_JSON, "base_delay", NULL, tst->base_delay_us); ++ print_uint(PRINT_JSON, "sent_packets", NULL, tst->sent.packets); ++ print_uint(PRINT_JSON, "sent_bytes", NULL, tst->sent.bytes); ++ print_uint(PRINT_JSON, "way_indirect_hits", NULL, tst->way_indirect_hits); ++ print_uint(PRINT_JSON, "way_misses", NULL, tst->way_misses); ++ print_uint(PRINT_JSON, "way_collisions", NULL, tst->way_collisions); ++ print_uint(PRINT_JSON, "drops", NULL, tst->dropped.packets); ++ print_uint(PRINT_JSON, "ecn_mark", NULL, tst->ecn_marked.packets); ++ print_uint(PRINT_JSON, "ack_drops", NULL, tst->ack_drops.packets); ++ print_uint(PRINT_JSON, "sparse_flows", NULL, tst->sparse_flows); ++ print_uint(PRINT_JSON, "bulk_flows", NULL, tst->bulk_flows); ++ print_uint(PRINT_JSON, "unresponsive_flows", NULL, tst->unresponse_flows); ++ print_uint(PRINT_JSON, "max_pkt_len", NULL, tst->max_skblen); ++ close_json_object(); ++} ++ +static int cake_print_xstats(struct qdisc_util *qu, FILE *f, + struct rtattr *xstats) +{ -+ /* fq_codel stats format borrowed */ -+ struct tc_fq_codel_xstats *st; + struct tc_cake_xstats *stnc; ++ struct tc_cake_tin_stats *tst; + SPRINT_BUF(b1); -+ SPRINT_BUF(b2); ++ int i; + + if (xstats == NULL) + return 0; + -+ if (RTA_PAYLOAD(xstats) < sizeof(st->type)) ++ if (RTA_PAYLOAD(xstats) < sizeof(*stnc)) + return -1; + -+ st = RTA_DATA(xstats); + stnc = RTA_DATA(xstats); + -+ if (st->type == TCA_FQ_CODEL_XSTATS_QDISC && RTA_PAYLOAD(xstats) >= sizeof(*st)) { -+ fprintf(f, " maxpacket %u drop_overlimit %u new_flow_count %u ecn_mark %u", -+ st->qdisc_stats.maxpacket, -+ st->qdisc_stats.drop_overlimit, -+ st->qdisc_stats.new_flow_count, -+ st->qdisc_stats.ecn_mark); -+ fprintf(f, "\n new_flows_len %u old_flows_len %u", -+ st->qdisc_stats.new_flows_len, -+ st->qdisc_stats.old_flows_len); -+ } else if (st->type == TCA_FQ_CODEL_XSTATS_CLASS && RTA_PAYLOAD(xstats) >= sizeof(*st)) { -+ fprintf(f, " deficit %d count %u lastcount %u ldelay %s", -+ st->class_stats.deficit, -+ st->class_stats.count, -+ st->class_stats.lastcount, -+ sprint_time(st->class_stats.ldelay, b1)); -+ if (st->class_stats.dropping) { -+ fprintf(f, " dropping"); -+ if (st->class_stats.drop_next < 0) -+ fprintf(f, " drop_next -%s", -+ sprint_time(-st->class_stats.drop_next, b1)); -+ else -+ fprintf(f, " drop_next %s", -+ sprint_time(st->class_stats.drop_next, b1)); -+ } -+ } else if (stnc->version >= 1 && stnc->version < 0xFF -+ && stnc->max_tins == TC_CAKE_MAX_TINS -+ && RTA_PAYLOAD(xstats) >= offsetof(struct tc_cake_xstats, capacity_estimate)) -+ { -+ int i; -+ -+ if(stnc->version >= 3) -+ fprintf(f, " memory used: %s of %s\n", sprint_size(stnc->memory_used, b1), sprint_size(stnc->memory_limit, b2)); -+ -+ if(stnc->version >= 2) -+ fprintf(f, " capacity estimate: %s\n", sprint_rate(stnc->capacity_estimate, b1)); -+ -+ switch(stnc->tin_cnt) { -+ case 3: -+ fprintf(f, " Bulk Best Effort Voice\n"); -+ break; -+ -+ case 4: -+ fprintf(f, " Bulk Best Effort Video Voice\n"); -+ break; -+ -+ case 5: -+ fprintf(f, " Low Loss Best Effort Low Delay Bulk Net Control\n"); -+ break; -+ -+ default: -+ fprintf(f, " "); -+ for(i=0; i < stnc->tin_cnt; i++) -+ fprintf(f, " Tin %u", i); -+ fprintf(f, "\n"); -+ }; -+ -+ fprintf(f, " thresh "); -+ for(i=0; i < stnc->tin_cnt; i++) -+ fprintf(f, " %12s", sprint_rate(stnc->threshold_rate[i], b1)); -+ fprintf(f, "\n"); -+ -+ fprintf(f, " target "); -+ for(i=0; i < stnc->tin_cnt; i++) -+ fprintf(f, " %12s", sprint_time(stnc->target_us[i], b1)); -+ fprintf(f, "\n"); -+ -+ fprintf(f, " interval"); -+ for(i=0; i < stnc->tin_cnt; i++) -+ fprintf(f, " %12s", sprint_time(stnc->interval_us[i], b1)); -+ fprintf(f, "\n"); -+ -+ fprintf(f, " pk_delay"); -+ for(i=0; i < stnc->tin_cnt; i++) -+ fprintf(f, " %12s", sprint_time(stnc->peak_delay_us[i], b1)); -+ fprintf(f, "\n"); -+ -+ fprintf(f, " av_delay"); -+ for(i=0; i < stnc->tin_cnt; i++) -+ fprintf(f, " %12s", sprint_time(stnc->avge_delay_us[i], b1)); -+ fprintf(f, "\n"); -+ -+ fprintf(f, " sp_delay"); -+ for(i=0; i < stnc->tin_cnt; i++) -+ fprintf(f, " %12s", sprint_time(stnc->base_delay_us[i], b1)); -+ fprintf(f, "\n"); -+ -+ fprintf(f, " pkts "); -+ for(i=0; i < stnc->tin_cnt; i++) -+ fprintf(f, " %12u", stnc->sent[i].packets); -+ fprintf(f, "\n"); -+ -+ fprintf(f, " bytes "); -+ for(i=0; i < stnc->tin_cnt; i++) -+ fprintf(f, " %12llu", stnc->sent[i].bytes); -+ fprintf(f, "\n"); -+ -+ fprintf(f, " way_inds"); -+ for(i=0; i < stnc->tin_cnt; i++) -+ fprintf(f, " %12u", stnc->way_indirect_hits[i]); -+ fprintf(f, "\n"); -+ -+ fprintf(f, " way_miss"); -+ for(i=0; i < stnc->tin_cnt; i++) -+ fprintf(f, " %12u", stnc->way_misses[i]); -+ fprintf(f, "\n"); ++ if (stnc->version < 0x101 || ++ RTA_PAYLOAD(xstats) < (sizeof(struct tc_cake_xstats) + ++ stnc->tin_stats_size * stnc->tin_cnt)) ++ return -1; + -+ fprintf(f, " way_cols"); -+ for(i=0; i < stnc->tin_cnt; i++) -+ fprintf(f, " %12u", stnc->way_collisions[i]); -+ fprintf(f, "\n"); ++ print_uint(PRINT_JSON, "memory_used", NULL, stnc->memory_used); ++ print_uint(PRINT_JSON, "memory_limit", NULL, stnc->memory_limit); ++ print_uint(PRINT_JSON, "capacity_estimate", NULL, stnc->capacity_estimate); ++ ++ print_string(PRINT_FP, NULL, " memory used: %s", ++ sprint_size(stnc->memory_used, b1)); ++ print_string(PRINT_FP, NULL, " of %s\n", ++ sprint_size(stnc->memory_limit, b1)); ++ print_string(PRINT_FP, NULL, " capacity estimate: %s\n", ++ sprint_rate(stnc->capacity_estimate, b1)); ++ ++ print_uint(PRINT_ANY, "min_transport_size", " min/max transport layer size: %10u", ++ stnc->min_trnlen); ++ print_uint(PRINT_ANY, "max_transport_size", " /%8u\n", stnc->max_trnlen); ++ print_uint(PRINT_ANY, "min_adj_size", " min/max overhead-adjusted size: %8u", ++ stnc->min_adjlen); ++ print_uint(PRINT_ANY, "max_adj_size", " /%8u\n", stnc->max_adjlen); ++ print_uint(PRINT_ANY, "avg_hdr_offset", " average transport hdr offset: %10u\n\n", ++ stnc->avg_trnoff); ++ ++ if (is_json_context()) { ++ open_json_array(PRINT_JSON, "tins"); ++ FOR_EACH_TIN(stnc, tst, i) ++ cake_print_json_tin(tst); ++ close_json_array(PRINT_JSON, NULL); ++ return 0; ++ } + -+ fprintf(f, " drops "); -+ for(i=0; i < stnc->tin_cnt; i++) -+ fprintf(f, " %12u", stnc->dropped[i].packets); -+ fprintf(f, "\n"); + -+ fprintf(f, " marks "); -+ for(i=0; i < stnc->tin_cnt; i++) -+ fprintf(f, " %12u", stnc->ecn_marked[i].packets); -+ fprintf(f, "\n"); ++ switch(stnc->tin_cnt) { ++ case 3: ++ fprintf(f, " Bulk Best Effort Voice\n"); ++ break; + -+ if(stnc->version >= 5) { -+ fprintf(f, " ack_drop"); -+ for(i=0; i < stnc->tin_cnt; i++) -+ fprintf(f, " %12u", stnc->ack_drops[i].packets); -+ fprintf(f, "\n"); -+ } ++ case 4: ++ fprintf(f, " Bulk Best Effort Video Voice\n"); ++ break; + -+ fprintf(f, " sp_flows"); -+ for(i=0; i < stnc->tin_cnt; i++) -+ fprintf(f, " %12u", stnc->sparse_flows[i]); -+ fprintf(f, "\n"); ++ case 5: ++ fprintf(f, " Low Loss Best Effort Low Delay Bulk Net Control\n"); ++ break; + -+ fprintf(f, " bk_flows"); ++ default: ++ fprintf(f, " "); + for(i=0; i < stnc->tin_cnt; i++) -+ fprintf(f, " %12u", stnc->bulk_flows[i]); ++ fprintf(f, " Tin %u", i); + fprintf(f, "\n"); ++ }; ++ ++ fprintf(f, " thresh "); ++ FOR_EACH_TIN(stnc, tst, i) ++ fprintf(f, " %12s", sprint_rate(tst->threshold_rate, b1)); ++ fprintf(f, "\n"); ++ ++ fprintf(f, " target "); ++ FOR_EACH_TIN(stnc, tst, i) ++ fprintf(f, " %12s", sprint_time(tst->target_us, b1)); ++ fprintf(f, "\n"); ++ ++ fprintf(f, " interval"); ++ FOR_EACH_TIN(stnc, tst, i) ++ fprintf(f, " %12s", sprint_time(tst->interval_us, b1)); ++ fprintf(f, "\n"); ++ ++ fprintf(f, " pk_delay"); ++ FOR_EACH_TIN(stnc, tst, i) ++ fprintf(f, " %12s", sprint_time(tst->peak_delay_us, b1)); ++ fprintf(f, "\n"); ++ ++ fprintf(f, " av_delay"); ++ FOR_EACH_TIN(stnc, tst, i) ++ fprintf(f, " %12s", sprint_time(tst->avge_delay_us, b1)); ++ fprintf(f, "\n"); ++ ++ fprintf(f, " sp_delay"); ++ FOR_EACH_TIN(stnc, tst, i) ++ fprintf(f, " %12s", sprint_time(tst->base_delay_us, b1)); ++ fprintf(f, "\n"); ++ ++ fprintf(f, " pkts "); ++ FOR_EACH_TIN(stnc, tst, i) ++ fprintf(f, " %12u", tst->sent.packets); ++ fprintf(f, "\n"); ++ ++ fprintf(f, " bytes "); ++ FOR_EACH_TIN(stnc, tst, i) ++ fprintf(f, " %12llu", tst->sent.bytes); ++ fprintf(f, "\n"); ++ ++ fprintf(f, " way_inds"); ++ FOR_EACH_TIN(stnc, tst, i) ++ fprintf(f, " %12u", tst->way_indirect_hits); ++ fprintf(f, "\n"); ++ ++ fprintf(f, " way_miss"); ++ FOR_EACH_TIN(stnc, tst, i) ++ fprintf(f, " %12u", tst->way_misses); ++ fprintf(f, "\n"); ++ ++ fprintf(f, " way_cols"); ++ FOR_EACH_TIN(stnc, tst, i) ++ fprintf(f, " %12u", tst->way_collisions); ++ fprintf(f, "\n"); ++ ++ fprintf(f, " drops "); ++ FOR_EACH_TIN(stnc, tst, i) ++ fprintf(f, " %12u", tst->dropped.packets); ++ fprintf(f, "\n"); ++ ++ fprintf(f, " marks "); ++ FOR_EACH_TIN(stnc, tst, i) ++ fprintf(f, " %12u", tst->ecn_marked.packets); ++ fprintf(f, "\n"); ++ ++ fprintf(f, " ack_drop"); ++ FOR_EACH_TIN(stnc, tst, i) ++ fprintf(f, " %12u", tst->ack_drops.packets); ++ fprintf(f, "\n"); ++ ++ fprintf(f, " sp_flows"); ++ FOR_EACH_TIN(stnc, tst, i) ++ fprintf(f, " %12u", tst->sparse_flows); ++ fprintf(f, "\n"); ++ ++ fprintf(f, " bk_flows"); ++ FOR_EACH_TIN(stnc, tst, i) ++ fprintf(f, " %12u", tst->bulk_flows); ++ fprintf(f, "\n"); ++ ++ fprintf(f, " un_flows"); ++ FOR_EACH_TIN(stnc, tst, i) ++ fprintf(f, " %12u", tst->unresponse_flows); ++ fprintf(f, "\n"); ++ ++ fprintf(f, " max_len "); ++ FOR_EACH_TIN(stnc, tst, i) ++ fprintf(f, " %12u", tst->max_skblen); ++ fprintf(f, "\n"); + -+ if(stnc->version >= 4) { -+ fprintf(f, " un_flows"); -+ for(i=0; i < stnc->tin_cnt; i++) -+ fprintf(f, " %12u", stnc->unresponse_flows[i]); -+ fprintf(f, "\n"); -+ } -+ -+ fprintf(f, " max_len "); -+ for(i=0; i < stnc->tin_cnt; i++) -+ fprintf(f, " %12u", stnc->max_skblen[i]); -+ fprintf(f, "\n"); -+ } else { -+ return -1; -+ } + return 0; +} +