diff options
Diffstat (limited to 'package/network/utils/iproute2')
-rw-r--r-- | package/network/utils/iproute2/Makefile | 2 | ||||
-rw-r--r-- | package/network/utils/iproute2/patches/950-add-cake-to-tc.patch | 869 |
2 files changed, 425 insertions, 446 deletions
diff --git a/package/network/utils/iproute2/Makefile b/package/network/utils/iproute2/Makefile index f5a9db321d..88a4851748 100644 --- a/package/network/utils/iproute2/Makefile +++ b/package/network/utils/iproute2/Makefile @@ -9,7 +9,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=iproute2 PKG_VERSION:=4.16.0 -PKG_RELEASE:=2 +PKG_RELEASE:=3 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz PKG_SOURCE_URL:=@KERNEL/linux/utils/net/iproute2 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 c8f70da132..3c2cdaaac3 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,6 @@ --- a/include/uapi/linux/pkt_sched.h +++ b/include/uapi/linux/pkt_sched.h -@@ -934,4 +934,75 @@ enum { +@@ -934,4 +934,110 @@ enum { #define TCA_CBS_MAX (__TCA_CBS_MAX - 1) @@ -22,66 +22,101 @@ + TCA_CAKE_MPU, + TCA_CAKE_INGRESS, + TCA_CAKE_ACK_FILTER, ++ TCA_CAKE_SPLIT_GSO, + __TCA_CAKE_MAX +}; +#define TCA_CAKE_MAX (__TCA_CAKE_MAX - 1) + -+struct tc_cake_traffic_stats { -+ __u32 packets; -+ __u32 link_ms; -+ __u64 bytes; ++enum { ++ __TCA_CAKE_STATS_INVALID, ++ TCA_CAKE_STATS_CAPACITY_ESTIMATE, ++ TCA_CAKE_STATS_MEMORY_LIMIT, ++ TCA_CAKE_STATS_MEMORY_USED, ++ TCA_CAKE_STATS_AVG_NETOFF, ++ TCA_CAKE_STATS_MIN_NETLEN, ++ TCA_CAKE_STATS_MAX_NETLEN, ++ TCA_CAKE_STATS_MIN_ADJLEN, ++ TCA_CAKE_STATS_MAX_ADJLEN, ++ TCA_CAKE_STATS_TIN_STATS, ++ __TCA_CAKE_STATS_MAX +}; ++#define TCA_CAKE_STATS_MAX (__TCA_CAKE_STATS_MAX - 1) + ++enum { ++ __TCA_CAKE_TIN_STATS_INVALID, ++ TCA_CAKE_TIN_STATS_PAD, ++ TCA_CAKE_TIN_STATS_SENT_PACKETS, ++ TCA_CAKE_TIN_STATS_SENT_BYTES64, ++ TCA_CAKE_TIN_STATS_DROPPED_PACKETS, ++ TCA_CAKE_TIN_STATS_DROPPED_BYTES64, ++ TCA_CAKE_TIN_STATS_ACKS_DROPPED_PACKETS, ++ TCA_CAKE_TIN_STATS_ACKS_DROPPED_BYTES64, ++ TCA_CAKE_TIN_STATS_ECN_MARKED_PACKETS, ++ TCA_CAKE_TIN_STATS_ECN_MARKED_BYTES64, ++ TCA_CAKE_TIN_STATS_BACKLOG_PACKETS, ++ TCA_CAKE_TIN_STATS_BACKLOG_BYTES64, ++ TCA_CAKE_TIN_STATS_THRESHOLD_RATE, ++ TCA_CAKE_TIN_STATS_TARGET_US, ++ TCA_CAKE_TIN_STATS_INTERVAL_US, ++ TCA_CAKE_TIN_STATS_WAY_INDIRECT_HITS, ++ TCA_CAKE_TIN_STATS_WAY_MISSES, ++ TCA_CAKE_TIN_STATS_WAY_COLLISIONS, ++ TCA_CAKE_TIN_STATS_PEAK_DELAY_US, ++ TCA_CAKE_TIN_STATS_AVG_DELAY_US, ++ TCA_CAKE_TIN_STATS_BASE_DELAY_US, ++ TCA_CAKE_TIN_STATS_SPARSE_FLOWS, ++ TCA_CAKE_TIN_STATS_BULK_FLOWS, ++ TCA_CAKE_TIN_STATS_UNRESPONSIVE_FLOWS, ++ TCA_CAKE_TIN_STATS_MAX_SKBLEN, ++ TCA_CAKE_TIN_STATS_FLOW_QUANTUM, ++ __TCA_CAKE_TIN_STATS_MAX ++}; ++#define TCA_CAKE_TIN_STATS_MAX (__TCA_CAKE_TIN_STATS_MAX - 1) +#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; ++ ++enum { ++ CAKE_FLOW_NONE = 0, ++ CAKE_FLOW_SRC_IP, ++ CAKE_FLOW_DST_IP, ++ CAKE_FLOW_HOSTS, /* = CAKE_FLOW_SRC_IP | CAKE_FLOW_DST_IP */ ++ CAKE_FLOW_FLOWS, ++ CAKE_FLOW_DUAL_SRC, /* = CAKE_FLOW_SRC_IP | CAKE_FLOW_FLOWS */ ++ CAKE_FLOW_DUAL_DST, /* = CAKE_FLOW_DST_IP | CAKE_FLOW_FLOWS */ ++ CAKE_FLOW_TRIPLE, /* = CAKE_FLOW_HOSTS | CAKE_FLOW_FLOWS */ ++ CAKE_FLOW_MAX, +}; + -+struct tc_cake_xstats { -+ __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 */ ++enum { ++ CAKE_DIFFSERV_DIFFSERV3 = 0, ++ CAKE_DIFFSERV_DIFFSERV4, ++ CAKE_DIFFSERV_DIFFSERV8, ++ CAKE_DIFFSERV_BESTEFFORT, ++ CAKE_DIFFSERV_PRECEDENCE, ++ CAKE_DIFFSERV_MAX ++}; ++ ++enum { ++ CAKE_ACK_NONE = 0, ++ CAKE_ACK_FILTER, ++ CAKE_ACK_AGGRESSIVE, ++ CAKE_ACK_MAX +}; + ++enum { ++ CAKE_ATM_NONE = 0, ++ CAKE_ATM_ATM, ++ CAKE_ATM_PTM, ++ CAKE_ATM_MAX ++}; ++ ++ #endif --- /dev/null +++ b/man/man8/tc-cake.8 -@@ -0,0 +1,678 @@ +@@ -0,0 +1,632 @@ +.TH CAKE 8 "23 November 2017" "iproute2" "Linux" +.SH NAME -+CAKE \- COMMON Applications Kept Enhanced (CAKE) ++CAKE \- Common Applications Kept Enhanced (CAKE) +.SH SYNOPSIS +.B tc qdisc ... cake +.br @@ -120,8 +155,6 @@ +| +.BR diffserv4 +| -+.BR diffserv-llt -+| +.BR diffserv3* +] +.br @@ -578,20 +611,6 @@ + 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: @@ -646,103 +665,73 @@ +.SH EXAMPLES +# tc qdisc delete root dev eth0 +.br -+# tc qdisc add root dev eth0 cake bandwidth 9500Kbit pppoe-ptm ether-vlan ++# tc qdisc add root dev eth0 cake bandwidth 100Mbit ethernet +.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) ++qdisc cake 1: dev eth0 root refcnt 2 bandwidth 100Mbit diffserv3 triple-isolate rtt 100.0ms noatm overhead 38 mpu 84 ++ 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 ++ memory used: 0b of 5000000b ++ capacity estimate: 100Mbit ++ min/max network layer size: 65535 / 0 ++ min/max overhead-adjusted size: 65535 / 0 ++ average network hdr offset: 0 ++ ++ Bulk Best Effort Voice ++ thresh 6250Kbit 100Mbit 25Mbit ++ target 5.0ms 5.0ms 5.0ms ++ interval 100.0ms 100.0ms 100.0ms ++ pk_delay 0us 0us 0us ++ av_delay 0us 0us 0us ++ sp_delay 0us 0us 0us ++ pkts 0 0 0 ++ bytes 0 0 0 ++ way_inds 0 0 0 ++ way_miss 0 0 0 ++ way_cols 0 0 0 ++ drops 0 0 0 ++ marks 0 0 0 ++ ack_drop 0 0 0 ++ sp_flows 0 0 0 ++ bk_flows 0 0 0 ++ un_flows 0 0 0 ++ max_len 0 0 0 ++ quantum 300 1514 762 + +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 ++qdisc cake 1: root refcnt 2 bandwidth 100Mbit diffserv3 triple-isolate rtt 100.0ms noatm overhead 38 mpu 84 ++ Sent 44709231 bytes 31931 pkt (dropped 45, overlimits 93782 requeues 0) ++ backlog 33308b 22p requeues 0 ++ memory used: 292352b of 5000000b ++ capacity estimate: 100Mbit ++ min/max network layer size: 28 / 1500 ++ min/max overhead-adjusted size: 84 / 1538 ++ average network hdr offset: 14 ++ ++ Bulk Best Effort Voice ++ thresh 6250Kbit 100Mbit 25Mbit ++ target 5.0ms 5.0ms 5.0ms ++ interval 100.0ms 100.0ms 100.0ms ++ pk_delay 8.7ms 6.9ms 5.0ms ++ av_delay 4.9ms 5.3ms 3.8ms ++ sp_delay 727us 1.4ms 511us ++ pkts 2590 21271 8137 ++ bytes 3081804 30302659 11426206 ++ way_inds 0 46 0 ++ way_miss 3 17 4 ++ way_cols 0 0 0 ++ drops 20 15 10 ++ marks 0 0 0 ++ ack_drop 0 0 0 ++ sp_flows 2 4 1 ++ bk_flows 1 2 1 ++ un_flows 0 0 0 ++ max_len 1514 1514 1514 ++ quantum 300 1514 762 + +.SH SEE ALSO +.BR tc (8), @@ -769,44 +758,13 @@ TCMODULES += q_hhf.o --- /dev/null +++ b/tc/q_cake.c -@@ -0,0 +1,770 @@ +@@ -0,0 +1,749 @@ +/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */ +/* + * Common Applications Kept Enhanced -- CAKE + * + * Copyright (C) 2014-2018 Jonathan Morton <chromatix99@gmail.com> + * Copyright (C) 2017-2018 Toke Høiland-Jørgensen <toke@toke.dk> -+ * -+ * 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 <stddef.h> @@ -823,14 +781,41 @@ +#include "utils.h" +#include "tc_util.h" + ++struct cake_preset { ++ char *name; ++ unsigned int target; ++ unsigned int interval; ++}; ++ ++static struct cake_preset presets[] = { ++ {"datacentre", 5, 100}, ++ {"lan", 50, 1000}, ++ {"metro", 500, 10000}, ++ {"regional", 1500, 30000}, ++ {"internet", 5000, 100000}, ++ {"oceanic", 15000, 300000}, ++ {"satellite", 50000, 1000000}, ++ {"interplanetary", 50000000, 1000000000}, ++}; ++ ++ ++static struct cake_preset *find_preset(char *argv) ++{ ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE(presets); i++) ++ if (!strcmp(argv, presets[i].name)) ++ return &presets[i]; ++ return NULL; ++} ++ +static void explain(void) +{ + fprintf(stderr, +"Usage: ... cake [ bandwidth RATE | unlimited* | autorate_ingress ]\n" +" [ rtt TIME | datacentre | lan | metro | regional |\n" +" internet* | oceanic | satellite | interplanetary ]\n" -+" [ besteffort | diffserv8 | diffserv4 | diffserv-llt |\n" -+" diffserv3* ]\n" ++" [ besteffort | diffserv8 | diffserv4 | diffserv3* ]\n" +" [ flowblind | srchost | dsthost | hosts | flows |\n" +" dual-srchost | dual-dsthost | triple-isolate* ]\n" +" [ nat | nonat* ]\n" @@ -863,6 +848,7 @@ + int ingress = -1; + int ack_filter = -1; + struct rtattr *tail; ++ struct cake_preset *preset, *preset_set = NULL; + + while (argc > 0) { + if (strcmp(*argv, "bandwidth") == 0) { @@ -889,45 +875,25 @@ + target = interval / 20; + if(!target) + target = 1; -+ } else if (strcmp(*argv, "datacentre") == 0) { -+ interval = 100; -+ target = 5; -+ } else if (strcmp(*argv, "lan") == 0) { -+ interval = 1000; -+ target = 50; -+ } else if (strcmp(*argv, "metro") == 0) { -+ interval = 10000; -+ target = 500; -+ } else if (strcmp(*argv, "regional") == 0) { -+ interval = 30000; -+ target = 1500; -+ } else if (strcmp(*argv, "internet") == 0) { -+ interval = 100000; -+ target = 5000; -+ } else if (strcmp(*argv, "oceanic") == 0) { -+ interval = 300000; -+ target = 15000; -+ } else if (strcmp(*argv, "satellite") == 0) { -+ interval = 1000000; -+ target = 50000; -+ } else if (strcmp(*argv, "interplanetary") == 0) { -+ interval = 1000000000; -+ target = 50000000; ++ } else if ((preset = find_preset(*argv))) { ++ if (preset_set) ++ duparg(*argv, preset_set->name); ++ preset_set = preset; ++ target = preset->target; ++ interval = preset->interval; + + } else if (strcmp(*argv, "besteffort") == 0) { -+ diffserv = 1; ++ diffserv = CAKE_DIFFSERV_BESTEFFORT; + } else if (strcmp(*argv, "precedence") == 0) { -+ diffserv = 2; ++ diffserv = CAKE_DIFFSERV_PRECEDENCE; + } else if (strcmp(*argv, "diffserv8") == 0) { -+ diffserv = 3; ++ diffserv = CAKE_DIFFSERV_DIFFSERV8; + } else if (strcmp(*argv, "diffserv4") == 0) { -+ diffserv = 4; ++ diffserv = CAKE_DIFFSERV_DIFFSERV4; + } else if (strcmp(*argv, "diffserv") == 0) { -+ diffserv = 4; -+ } else if (strcmp(*argv, "diffserv-llt") == 0) { -+ diffserv = 5; ++ diffserv = CAKE_DIFFSERV_DIFFSERV4; + } else if (strcmp(*argv, "diffserv3") == 0) { -+ diffserv = 6; ++ diffserv = CAKE_DIFFSERV_DIFFSERV3; + + } else if (strcmp(*argv, "nowash") == 0) { + wash = 0; @@ -935,21 +901,21 @@ + wash = 1; + + } else if (strcmp(*argv, "flowblind") == 0) { -+ flowmode = 0; ++ flowmode = CAKE_FLOW_NONE; + } else if (strcmp(*argv, "srchost") == 0) { -+ flowmode = 1; ++ flowmode = CAKE_FLOW_SRC_IP; + } else if (strcmp(*argv, "dsthost") == 0) { -+ flowmode = 2; ++ flowmode = CAKE_FLOW_DST_IP; + } else if (strcmp(*argv, "hosts") == 0) { -+ flowmode = 3; ++ flowmode = CAKE_FLOW_HOSTS; + } else if (strcmp(*argv, "flows") == 0) { -+ flowmode = 4; ++ flowmode = CAKE_FLOW_FLOWS; + } else if (strcmp(*argv, "dual-srchost") == 0) { -+ flowmode = 5; ++ flowmode = CAKE_FLOW_DUAL_SRC; + } else if (strcmp(*argv, "dual-dsthost") == 0) { -+ flowmode = 6; ++ flowmode = CAKE_FLOW_DUAL_DST; + } else if (strcmp(*argv, "triple-isolate") == 0) { -+ flowmode = 7; ++ flowmode = CAKE_FLOW_TRIPLE; + + } else if (strcmp(*argv, "nat") == 0) { + nat = 1; @@ -957,14 +923,14 @@ + nat = 0; + + } else if (strcmp(*argv, "ptm") == 0) { -+ atm = 2; ++ atm = CAKE_ATM_PTM; + } else if (strcmp(*argv, "atm") == 0) { -+ atm = 1; ++ atm = CAKE_ATM_ATM; + } else if (strcmp(*argv, "noatm") == 0) { -+ atm = 0; ++ atm = CAKE_ATM_NONE; + + } else if (strcmp(*argv, "raw") == 0) { -+ atm = 0; ++ atm = CAKE_ATM_NONE; + overhead = 0; + overhead_set = true; + overhead_override = true; @@ -974,41 +940,41 @@ + * one whole ATM cell plus ATM framing. + * A safe choice if the actual overhead is unknown. + */ -+ atm = 1; ++ atm = CAKE_ATM_ATM; + overhead = 48; + overhead_set = true; + + /* Various ADSL framing schemes, all over ATM cells */ + } else if (strcmp(*argv, "ipoa-vcmux") == 0) { -+ atm = 1; ++ atm = CAKE_ATM_ATM; + overhead += 8; + overhead_set = true; + } else if (strcmp(*argv, "ipoa-llcsnap") == 0) { -+ atm = 1; ++ atm = CAKE_ATM_ATM; + overhead += 16; + overhead_set = true; + } else if (strcmp(*argv, "bridged-vcmux") == 0) { -+ atm = 1; ++ atm = CAKE_ATM_ATM; + overhead += 24; + overhead_set = true; + } else if (strcmp(*argv, "bridged-llcsnap") == 0) { -+ atm = 1; ++ atm = CAKE_ATM_ATM; + overhead += 32; + overhead_set = true; + } else if (strcmp(*argv, "pppoa-vcmux") == 0) { -+ atm = 1; ++ atm = CAKE_ATM_ATM; + overhead += 10; + overhead_set = true; + } else if (strcmp(*argv, "pppoa-llc") == 0) { -+ atm = 1; ++ atm = CAKE_ATM_ATM; + overhead += 14; + overhead_set = true; + } else if (strcmp(*argv, "pppoe-vcmux") == 0) { -+ atm = 1; ++ atm = CAKE_ATM_ATM; + overhead += 32; + overhead_set = true; + } else if (strcmp(*argv, "pppoe-llcsnap") == 0) { -+ atm = 1; ++ atm = CAKE_ATM_ATM; + overhead += 40; + overhead_set = true; + @@ -1020,7 +986,7 @@ + * + 1B Start of Frame (S) + 1B End of Frame (Ck) + * + 2B TC-CRC (PTM-FCS) = 30B + */ -+ atm = 2; ++ atm = CAKE_ATM_PTM; + overhead += 30; + overhead_set = true; + } else if (strcmp(*argv, "bridged-ptm") == 0) { @@ -1029,7 +995,7 @@ + * + 1B Start of Frame (S) + 1B End of Frame (Ck) + * + 2B TC-CRC (PTM-FCS) = 22B + */ -+ atm = 2; ++ atm = CAKE_ATM_PTM; + overhead += 22; + overhead_set = true; + @@ -1065,7 +1031,7 @@ + * but not interframe gap or preamble. + */ + } else if (strcmp(*argv, "docsis") == 0) { -+ atm = 0; ++ atm = CAKE_ATM_NONE; + overhead += 18; + overhead_set = true; + mpu = 64; @@ -1095,11 +1061,11 @@ + ingress = 0; + + } else if (strcmp(*argv, "no-ack-filter") == 0) { -+ ack_filter = 0; ++ ack_filter = CAKE_ACK_NONE; + } else if (strcmp(*argv, "ack-filter") == 0) { -+ ack_filter = 0x0200; ++ ack_filter = CAKE_ACK_FILTER; + } else if (strcmp(*argv, "ack-filter-aggressive") == 0) { -+ ack_filter = 0x0600; ++ ack_filter = CAKE_ACK_AGGRESSIVE; + + } else if (strcmp(*argv, "memlimit") == 0) { + NEXT_ARG(); @@ -1176,6 +1142,7 @@ + int wash = 0; + int ingress = 0; + int ack_filter = 0; ++ int split_gso = 0; + SPRINT_BUF(b1); + SPRINT_BUF(b2); + @@ -1205,23 +1172,20 @@ + RTA_PAYLOAD(tb[TCA_CAKE_DIFFSERV_MODE]) >= sizeof(__u32)) { + diffserv = rta_getattr_u32(tb[TCA_CAKE_DIFFSERV_MODE]); + switch(diffserv) { -+ case 1: -+ print_string(PRINT_ANY, "diffserv", "%s ", "besteffort"); ++ case CAKE_DIFFSERV_DIFFSERV3: ++ print_string(PRINT_ANY, "diffserv", "%s ", "diffserv3"); + break; -+ case 2: -+ print_string(PRINT_ANY, "diffserv", "%s ", "precedence"); ++ case CAKE_DIFFSERV_DIFFSERV4: ++ print_string(PRINT_ANY, "diffserv", "%s ", "diffserv4"); + break; -+ case 3: ++ case CAKE_DIFFSERV_DIFFSERV8: + print_string(PRINT_ANY, "diffserv", "%s ", "diffserv8"); + break; -+ case 4: -+ print_string(PRINT_ANY, "diffserv", "%s ", "diffserv4"); -+ break; -+ case 5: -+ print_string(PRINT_ANY, "diffserv", "%s ", "diffserv-llt"); ++ case CAKE_DIFFSERV_BESTEFFORT: ++ print_string(PRINT_ANY, "diffserv", "%s ", "besteffort"); + break; -+ case 6: -+ print_string(PRINT_ANY, "diffserv", "%s ", "diffserv3"); ++ case CAKE_DIFFSERV_PRECEDENCE: ++ print_string(PRINT_ANY, "diffserv", "%s ", "precedence"); + break; + default: + print_string(PRINT_ANY, "diffserv", "(?diffserv?) ", "unknown"); @@ -1231,31 +1195,29 @@ + if (tb[TCA_CAKE_FLOW_MODE] && + RTA_PAYLOAD(tb[TCA_CAKE_FLOW_MODE]) >= sizeof(__u32)) { + flowmode = rta_getattr_u32(tb[TCA_CAKE_FLOW_MODE]); -+ nat = !!(flowmode & 64); -+ flowmode &= ~64; + switch(flowmode) { -+ case 0: ++ case CAKE_FLOW_NONE: + print_string(PRINT_ANY, "flowmode", "%s ", "flowblind"); + break; -+ case 1: ++ case CAKE_FLOW_SRC_IP: + print_string(PRINT_ANY, "flowmode", "%s ", "srchost"); + break; -+ case 2: ++ case CAKE_FLOW_DST_IP: + print_string(PRINT_ANY, "flowmode", "%s ", "dsthost"); + break; -+ case 3: ++ case CAKE_FLOW_HOSTS: + print_string(PRINT_ANY, "flowmode", "%s ", "hosts"); + break; -+ case 4: ++ case CAKE_FLOW_FLOWS: + print_string(PRINT_ANY, "flowmode", "%s ", "flows"); + break; -+ case 5: ++ case CAKE_FLOW_DUAL_SRC: + print_string(PRINT_ANY, "flowmode", "%s ", "dual-srchost"); + break; -+ case 6: ++ case CAKE_FLOW_DUAL_DST: + print_string(PRINT_ANY, "flowmode", "%s ", "dual-dsthost"); + break; -+ case 7: ++ case CAKE_FLOW_TRIPLE: + print_string(PRINT_ANY, "flowmode", "%s ", "triple-isolate"); + break; + default: @@ -1263,10 +1225,17 @@ + break; + }; + -+ if(nat) -+ print_string(PRINT_FP, NULL, "nat ", NULL); -+ print_bool(PRINT_JSON, "nat", NULL, nat); + } ++ ++ if (tb[TCA_CAKE_NAT] && ++ RTA_PAYLOAD(tb[TCA_CAKE_NAT]) >= sizeof(__u32)) { ++ nat = rta_getattr_u32(tb[TCA_CAKE_NAT]); ++ } ++ ++ if(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)) { + wash = rta_getattr_u32(tb[TCA_CAKE_WASH]); @@ -1276,8 +1245,8 @@ + atm = rta_getattr_u32(tb[TCA_CAKE_ATM]); + } + if (tb[TCA_CAKE_OVERHEAD] && -+ RTA_PAYLOAD(tb[TCA_CAKE_OVERHEAD]) >= sizeof(__u32)) { -+ overhead = rta_getattr_u32(tb[TCA_CAKE_OVERHEAD]); ++ RTA_PAYLOAD(tb[TCA_CAKE_OVERHEAD]) >= sizeof(__s32)) { ++ overhead = *(__s32 *) RTA_DATA(tb[TCA_CAKE_OVERHEAD]); + } + if (tb[TCA_CAKE_MPU] && + RTA_PAYLOAD(tb[TCA_CAKE_MPU]) >= sizeof(__u32)) { @@ -1291,6 +1260,10 @@ + RTA_PAYLOAD(tb[TCA_CAKE_ACK_FILTER]) >= sizeof(__u32)) { + ack_filter = rta_getattr_u32(tb[TCA_CAKE_ACK_FILTER]); + } ++ if (tb[TCA_CAKE_SPLIT_GSO] && ++ RTA_PAYLOAD(tb[TCA_CAKE_SPLIT_GSO]) >= sizeof(__u32)) { ++ split_gso = rta_getattr_u32(tb[TCA_CAKE_SPLIT_GSO]); ++ } + if (tb[TCA_CAKE_RAW]) { + raw = 1; + } @@ -1307,13 +1280,17 @@ + print_string(PRINT_FP, NULL, "ingress ", NULL); + print_bool(PRINT_JSON, "ingress", NULL, ingress); + -+ if (ack_filter == 0x0600) ++ if (ack_filter == CAKE_ACK_AGGRESSIVE) + print_string(PRINT_ANY, "ack-filter", "ack-filter-%s ", "aggressive"); -+ else if (ack_filter) ++ else if (ack_filter == CAKE_ACK_FILTER) + print_string(PRINT_ANY, "ack-filter", "ack-filter ", "enabled"); + else + print_string(PRINT_JSON, "ack-filter", NULL, "disabled"); + ++ if (split_gso) ++ print_string(PRINT_FP, NULL, "split-gso ", NULL); ++ print_bool(PRINT_JSON, "split_gso", NULL, split_gso); ++ + if (interval) + print_string(PRINT_FP, NULL, "rtt %s ", sprint_time(interval, b2)); + print_uint(PRINT_JSON, "rtt", NULL, interval); @@ -1322,9 +1299,9 @@ + print_string(PRINT_FP, NULL, "raw ", NULL); + print_bool(PRINT_JSON, "raw", NULL, raw); + -+ if (atm == 1) ++ if (atm == CAKE_ATM_ATM) + print_string(PRINT_ANY, "atm", "%s ", "atm"); -+ else if (atm == 2) ++ else if (atm == CAKE_ATM_PTM) + print_string(PRINT_ANY, "atm", "%s ", "ptm"); + else if (!raw) + print_string(PRINT_ANY, "atm", "%s ", "noatm"); @@ -1332,7 +1309,7 @@ + print_uint(PRINT_ANY, "overhead", "overhead %d ", overhead); + + if (mpu) -+ print_uint(PRINT_ANY, "mpu", "mpu %d ", mpu); ++ print_uint(PRINT_ANY, "mpu", "mpu %u ", mpu); + + if (memlimit) { + print_uint(PRINT_JSON, "memlimit", NULL, memlimit); @@ -1342,195 +1319,186 @@ + 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) ++static void cake_print_json_tin(struct rtattr **tstat) +{ ++#define PRINT_TSTAT_JSON(type, name, attr) if (tstat[TCA_CAKE_TIN_STATS_ ## attr]) \ ++ print_uint(PRINT_JSON, name, NULL, \ ++ rta_getattr_ ## type((struct rtattr *)tstat[TCA_CAKE_TIN_STATS_ ## attr])) ++ + 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); ++ PRINT_TSTAT_JSON(u32, "threshold_rate", THRESHOLD_RATE); ++ PRINT_TSTAT_JSON(u32, "target_us", TARGET_US); ++ PRINT_TSTAT_JSON(u32, "interval_us", INTERVAL_US); ++ PRINT_TSTAT_JSON(u32, "peak_delay_us", PEAK_DELAY_US); ++ PRINT_TSTAT_JSON(u32, "avg_delay_us", AVG_DELAY_US); ++ PRINT_TSTAT_JSON(u32, "base_delay_us", BASE_DELAY_US); ++ PRINT_TSTAT_JSON(u32, "sent_packets", SENT_PACKETS); ++ PRINT_TSTAT_JSON(u64, "sent_bytes", SENT_BYTES64); ++ PRINT_TSTAT_JSON(u32, "way_indirect_hits", WAY_INDIRECT_HITS); ++ PRINT_TSTAT_JSON(u32, "way_misses", WAY_MISSES); ++ PRINT_TSTAT_JSON(u32, "way_collisions", WAY_COLLISIONS); ++ PRINT_TSTAT_JSON(u32, "drops", DROPPED_PACKETS); ++ PRINT_TSTAT_JSON(u32, "ecn_mark", ECN_MARKED_PACKETS); ++ PRINT_TSTAT_JSON(u32, "ack_drops", ACKS_DROPPED_PACKETS); ++ PRINT_TSTAT_JSON(u32, "sparse_flows", SPARSE_FLOWS); ++ PRINT_TSTAT_JSON(u32, "bulk_flows", BULK_FLOWS); ++ PRINT_TSTAT_JSON(u32, "unresponsive_flows", UNRESPONSIVE_FLOWS); ++ PRINT_TSTAT_JSON(u32, "max_pkt_len", MAX_SKBLEN); ++ PRINT_TSTAT_JSON(u32, "flow_quantum", FLOW_QUANTUM); + close_json_object(); ++ ++#undef PRINT_TSTAT_JSON +} + +static int cake_print_xstats(struct qdisc_util *qu, FILE *f, + struct rtattr *xstats) +{ -+ struct tc_cake_xstats *stnc; -+ struct tc_cake_tin_stats *tst; + SPRINT_BUF(b1); ++ struct rtattr *st[TCA_CAKE_STATS_MAX + 1]; + int i; + + if (xstats == NULL) + return 0; + -+ if (RTA_PAYLOAD(xstats) < sizeof(*stnc)) -+ return -1; -+ -+ stnc = RTA_DATA(xstats); -+ -+ if (stnc->version < 0x101 || -+ RTA_PAYLOAD(xstats) < (sizeof(struct tc_cake_xstats) + -+ stnc->tin_stats_size * stnc->tin_cnt)) -+ return -1; -+ -+ 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; ++#define GET_STAT_U32(attr) rta_getattr_u32(st[TCA_CAKE_STATS_ ## attr]) ++ ++ parse_rtattr_nested(st, TCA_CAKE_STATS_MAX, xstats); ++ ++ if (st[TCA_CAKE_STATS_MEMORY_USED] && ++ st[TCA_CAKE_STATS_MEMORY_LIMIT]) { ++ print_string(PRINT_FP, NULL, " memory used: %s", ++ sprint_size(GET_STAT_U32(MEMORY_USED), b1)); ++ ++ print_string(PRINT_FP, NULL, " of %s\n", ++ sprint_size(GET_STAT_U32(MEMORY_LIMIT), b1)); ++ ++ print_uint(PRINT_JSON, "memory_used", NULL, ++ GET_STAT_U32(MEMORY_USED)); ++ print_uint(PRINT_JSON, "memory_limit", NULL, ++ GET_STAT_U32(MEMORY_LIMIT)); ++ } ++ ++ if (st[TCA_CAKE_STATS_CAPACITY_ESTIMATE]) { ++ print_string(PRINT_FP, NULL, " capacity estimate: %s\n", ++ sprint_rate(GET_STAT_U32(CAPACITY_ESTIMATE), b1)); ++ print_uint(PRINT_JSON, "capacity_estimate", NULL, ++ GET_STAT_U32(CAPACITY_ESTIMATE)); + } + ++ if (st[TCA_CAKE_STATS_MIN_NETLEN] && ++ st[TCA_CAKE_STATS_MAX_NETLEN]) { ++ print_uint(PRINT_ANY, "min_network_size", ++ " min/max network layer size: %8u", ++ GET_STAT_U32(MIN_NETLEN)); ++ print_uint(PRINT_ANY, "max_network_size", ++ " /%8u\n", GET_STAT_U32(MAX_NETLEN)); ++ } ++ ++ if (st[TCA_CAKE_STATS_MIN_ADJLEN] && ++ st[TCA_CAKE_STATS_MAX_ADJLEN]) { ++ print_uint(PRINT_ANY, "min_adj_size", ++ " min/max overhead-adjusted size: %8u", ++ GET_STAT_U32(MIN_ADJLEN)); ++ print_uint(PRINT_ANY, "max_adj_size", ++ " /%8u\n", GET_STAT_U32(MAX_ADJLEN)); ++ } ++ ++ if (st[TCA_CAKE_STATS_AVG_NETOFF]) ++ print_uint(PRINT_ANY, "avg_hdr_offset", ++ " average network hdr offset: %8u\n\n", ++ GET_STAT_U32(AVG_NETOFF)); ++ ++#undef GET_STAT_U32 ++ ++ if (st[TCA_CAKE_STATS_TIN_STATS]) { ++ struct rtattr *tins[TC_CAKE_MAX_TINS + 1]; ++ struct rtattr *tstat[TC_CAKE_MAX_TINS][TCA_CAKE_TIN_STATS_MAX + 1]; ++ int num_tins = 0; ++ ++ parse_rtattr_nested(tins, TC_CAKE_MAX_TINS, st[TCA_CAKE_STATS_TIN_STATS]); ++ ++ for (i = 1; i <= TC_CAKE_MAX_TINS && tins[i]; i++) { ++ parse_rtattr_nested(tstat[i-1], TCA_CAKE_TIN_STATS_MAX, tins[i]); ++ num_tins++; ++ } ++ ++ if (!num_tins) ++ return 0; ++ ++ if (is_json_context()) { ++ open_json_array(PRINT_JSON, "tins"); ++ for (i = 0; i < num_tins; i++) ++ cake_print_json_tin(tstat[i]); ++ close_json_array(PRINT_JSON, NULL); ++ ++ return 0; ++ } ++ ++ ++ switch(num_tins) { ++ case 3: ++ fprintf(f, " Bulk Best Effort Voice\n"); ++ break; ++ ++ case 4: ++ fprintf(f, " Bulk Best Effort Video Voice\n"); ++ break; + -+ 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_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"); ++ default: ++ fprintf(f, " "); ++ for(i=0; i < num_tins; i++) ++ fprintf(f, " Tin %u", i); ++ fprintf(f, "\n"); ++ }; + ++#define GET_TSTAT(i, attr) (tstat[i][TCA_CAKE_TIN_STATS_ ## attr]) ++#define PRINT_TSTAT(name, attr, fmts, val) do { \ ++ if (GET_TSTAT(0, attr)) { \ ++ fprintf(f, name); \ ++ for (i = 0; i < num_tins; i++) \ ++ fprintf(f, " %12" fmts, val); \ ++ fprintf(f, "\n"); \ ++ } \ ++ } while (0) ++ ++#define SPRINT_TSTAT(pfunc, name, attr) PRINT_TSTAT( \ ++ name, attr, "s", sprint_ ## pfunc( \ ++ rta_getattr_u32(GET_TSTAT(i, attr)), b1)) ++ ++#define PRINT_TSTAT_U32(name, attr) PRINT_TSTAT( \ ++ name, attr, "u", rta_getattr_u32(GET_TSTAT(i, attr))) ++ ++#define PRINT_TSTAT_U64(name, attr) PRINT_TSTAT( \ ++ name, attr, "llu", rta_getattr_u64(GET_TSTAT(i, attr))) ++ ++ SPRINT_TSTAT(rate, " thresh ", THRESHOLD_RATE); ++ SPRINT_TSTAT(time, " target ", TARGET_US); ++ SPRINT_TSTAT(time, " interval", INTERVAL_US); ++ SPRINT_TSTAT(time, " pk_delay", PEAK_DELAY_US); ++ SPRINT_TSTAT(time, " av_delay", AVG_DELAY_US); ++ SPRINT_TSTAT(time, " sp_delay", BASE_DELAY_US); ++ ++ PRINT_TSTAT_U32(" pkts ", SENT_PACKETS); ++ PRINT_TSTAT_U64(" bytes ", SENT_BYTES64); ++ ++ PRINT_TSTAT_U32(" way_inds", WAY_INDIRECT_HITS); ++ PRINT_TSTAT_U32(" way_miss", WAY_MISSES); ++ PRINT_TSTAT_U32(" way_cols", WAY_COLLISIONS); ++ PRINT_TSTAT_U32(" drops ", DROPPED_PACKETS); ++ PRINT_TSTAT_U32(" marks ", ECN_MARKED_PACKETS); ++ PRINT_TSTAT_U32(" ack_drop", ACKS_DROPPED_PACKETS); ++ PRINT_TSTAT_U32(" sp_flows", SPARSE_FLOWS); ++ PRINT_TSTAT_U32(" bk_flows", BULK_FLOWS); ++ PRINT_TSTAT_U32(" un_flows", UNRESPONSIVE_FLOWS); ++ PRINT_TSTAT_U32(" max_len ", MAX_SKBLEN); ++ PRINT_TSTAT_U32(" quantum ", FLOW_QUANTUM); ++ ++#undef GET_STAT ++#undef PRINT_TSTAT ++#undef SPRINT_TSTAT ++#undef PRINT_TSTAT_U32 ++#undef PRINT_TSTAT_U64 ++ } + return 0; +} + @@ -1540,3 +1508,14 @@ + .print_qopt = cake_print_opt, + .print_xstats = cake_print_xstats, +}; +--- a/tc/q_ingress.c ++++ b/tc/q_ingress.c +@@ -40,7 +40,7 @@ static int ingress_parse_opt(struct qdis + static int ingress_print_opt(struct qdisc_util *qu, FILE *f, + struct rtattr *opt) + { +- fprintf(f, "---------------- "); ++ print_string(PRINT_FP, NULL, "---------------- ", NULL); + return 0; + } + |