1 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
4 * Common Applications Kept Enhanced -- CAKE
6 * Copyright (C) 2014-2018 Jonathan Morton <chromatix99@gmail.com>
7 * Copyright (C) 2017-2018 Toke Høiland-Jørgensen <toke@toke.dk>
16 #include <sys/socket.h>
17 #include <netinet/in.h>
18 #include <arpa/inet.h>
28 unsigned int interval
;
31 static struct cake_preset presets
[] = {
32 {"datacentre", 5, 100},
34 {"metro", 500, 10000},
35 {"regional", 1500, 30000},
36 {"internet", 5000, 100000},
37 {"oceanic", 15000, 300000},
38 {"satellite", 50000, 1000000},
39 {"interplanetary", 50000000, 1000000000},
42 static const char * diffserv_names
[CAKE_DIFFSERV_MAX
] = {
43 [CAKE_DIFFSERV_DIFFSERV3
] = "diffserv3",
44 [CAKE_DIFFSERV_DIFFSERV4
] = "diffserv4",
45 [CAKE_DIFFSERV_DIFFSERV8
] = "diffserv8",
46 [CAKE_DIFFSERV_BESTEFFORT
] = "besteffort",
47 [CAKE_DIFFSERV_PRECEDENCE
] = "precedence",
50 static const char * flowmode_names
[CAKE_FLOW_MAX
] = {
51 [CAKE_FLOW_NONE
] = "flowblind",
52 [CAKE_FLOW_SRC_IP
] = "srchost",
53 [CAKE_FLOW_DST_IP
] = "dsthost",
54 [CAKE_FLOW_HOSTS
] = "hosts",
55 [CAKE_FLOW_FLOWS
] = "flows",
56 [CAKE_FLOW_DUAL_SRC
] = "dual-srchost",
57 [CAKE_FLOW_DUAL_DST
] = "dual-dsthost",
58 [CAKE_FLOW_TRIPLE
] = "triple-isolate",
61 static struct cake_preset
*find_preset(char *argv
)
65 for (i
= 0; i
< ARRAY_SIZE(presets
); i
++)
66 if (!strcmp(argv
, presets
[i
].name
))
71 static void explain(void)
74 "Usage: ... cake [ bandwidth RATE | unlimited* | autorate-ingress ]\n"
75 " [ rtt TIME | datacentre | lan | metro | regional |\n"
76 " internet* | oceanic | satellite | interplanetary ]\n"
77 " [ besteffort | diffserv8 | diffserv4 | diffserv3* ]\n"
78 " [ flowblind | srchost | dsthost | hosts | flows |\n"
79 " dual-srchost | dual-dsthost | triple-isolate* ]\n"
81 " [ wash | nowash* ]\n"
82 " [ split-gso* | no-split-gso ]\n"
83 " [ ack-filter | ack-filter-aggressive | no-ack-filter* ]\n"
84 " [ memlimit LIMIT ]\n"
85 " [ ptm | atm | noatm* ] [ overhead N | conservative | raw* ]\n"
86 " [ mpu N ] [ ingress | egress* ]\n"
87 " (* marks defaults)\n");
90 static int cake_parse_opt(struct qdisc_util
*qu
, int argc
, char **argv
,
91 struct nlmsghdr
*n
, const char *dev
)
93 struct cake_preset
*preset
, *preset_set
= NULL
;
94 bool overhead_override
= false;
95 bool overhead_set
= false;
96 unsigned int interval
= 0;
97 unsigned int diffserv
= 0;
98 unsigned int memlimit
= 0;
99 unsigned int target
= 0;
115 if (strcmp(*argv
, "bandwidth") == 0) {
117 if (get_rate64(&bandwidth
, *argv
)) {
118 fprintf(stderr
, "Illegal \"bandwidth\"\n");
123 } else if (strcmp(*argv
, "unlimited") == 0) {
127 } else if (strcmp(*argv
, "autorate-ingress") == 0) {
129 } else if (strcmp(*argv
, "rtt") == 0) {
131 if (get_time(&interval
, *argv
)) {
132 fprintf(stderr
, "Illegal \"rtt\"\n");
135 target
= interval
/ 20;
138 } else if ((preset
= find_preset(*argv
))) {
140 duparg(*argv
, preset_set
->name
);
142 target
= preset
->target
;
143 interval
= preset
->interval
;
144 } else if (strcmp(*argv
, "besteffort") == 0) {
145 diffserv
= CAKE_DIFFSERV_BESTEFFORT
;
146 } else if (strcmp(*argv
, "precedence") == 0) {
147 diffserv
= CAKE_DIFFSERV_PRECEDENCE
;
148 } else if (strcmp(*argv
, "diffserv8") == 0) {
149 diffserv
= CAKE_DIFFSERV_DIFFSERV8
;
150 } else if (strcmp(*argv
, "diffserv4") == 0) {
151 diffserv
= CAKE_DIFFSERV_DIFFSERV4
;
152 } else if (strcmp(*argv
, "diffserv") == 0) {
153 diffserv
= CAKE_DIFFSERV_DIFFSERV4
;
154 } else if (strcmp(*argv
, "diffserv3") == 0) {
155 diffserv
= CAKE_DIFFSERV_DIFFSERV3
;
156 } else if (strcmp(*argv
, "nowash") == 0) {
158 } else if (strcmp(*argv
, "wash") == 0) {
160 } else if (strcmp(*argv
, "split-gso") == 0) {
162 } else if (strcmp(*argv
, "no-split-gso") == 0) {
164 } else if (strcmp(*argv
, "flowblind") == 0) {
165 flowmode
= CAKE_FLOW_NONE
;
166 } else if (strcmp(*argv
, "srchost") == 0) {
167 flowmode
= CAKE_FLOW_SRC_IP
;
168 } else if (strcmp(*argv
, "dsthost") == 0) {
169 flowmode
= CAKE_FLOW_DST_IP
;
170 } else if (strcmp(*argv
, "hosts") == 0) {
171 flowmode
= CAKE_FLOW_HOSTS
;
172 } else if (strcmp(*argv
, "flows") == 0) {
173 flowmode
= CAKE_FLOW_FLOWS
;
174 } else if (strcmp(*argv
, "dual-srchost") == 0) {
175 flowmode
= CAKE_FLOW_DUAL_SRC
;
176 } else if (strcmp(*argv
, "dual-dsthost") == 0) {
177 flowmode
= CAKE_FLOW_DUAL_DST
;
178 } else if (strcmp(*argv
, "triple-isolate") == 0) {
179 flowmode
= CAKE_FLOW_TRIPLE
;
180 } else if (strcmp(*argv
, "nat") == 0) {
182 } else if (strcmp(*argv
, "nonat") == 0) {
184 } else if (strcmp(*argv
, "ptm") == 0) {
186 } else if (strcmp(*argv
, "atm") == 0) {
188 } else if (strcmp(*argv
, "noatm") == 0) {
190 } else if (strcmp(*argv
, "raw") == 0) {
194 overhead_override
= true;
195 } else if (strcmp(*argv
, "conservative") == 0) {
197 * Deliberately over-estimate overhead:
198 * one whole ATM cell plus ATM framing.
199 * A safe choice if the actual overhead is unknown.
205 /* Various ADSL framing schemes, all over ATM cells */
206 } else if (strcmp(*argv
, "ipoa-vcmux") == 0) {
210 } else if (strcmp(*argv
, "ipoa-llcsnap") == 0) {
214 } else if (strcmp(*argv
, "bridged-vcmux") == 0) {
218 } else if (strcmp(*argv
, "bridged-llcsnap") == 0) {
222 } else if (strcmp(*argv
, "pppoa-vcmux") == 0) {
226 } else if (strcmp(*argv
, "pppoa-llc") == 0) {
230 } else if (strcmp(*argv
, "pppoe-vcmux") == 0) {
234 } else if (strcmp(*argv
, "pppoe-llcsnap") == 0) {
239 /* Typical VDSL2 framing schemes, both over PTM */
240 /* PTM has 64b/65b coding which absorbs some bandwidth */
241 } else if (strcmp(*argv
, "pppoe-ptm") == 0) {
242 /* 2B PPP + 6B PPPoE + 6B dest MAC + 6B src MAC
243 * + 2B ethertype + 4B Frame Check Sequence
244 * + 1B Start of Frame (S) + 1B End of Frame (Ck)
245 * + 2B TC-CRC (PTM-FCS) = 30B
250 } else if (strcmp(*argv
, "bridged-ptm") == 0) {
251 /* 6B dest MAC + 6B src MAC + 2B ethertype
252 * + 4B Frame Check Sequence
253 * + 1B Start of Frame (S) + 1B End of Frame (Ck)
254 * + 2B TC-CRC (PTM-FCS) = 22B
259 } else if (strcmp(*argv
, "via-ethernet") == 0) {
261 * We used to use this flag to manually compensate for
262 * Linux including the Ethernet header on Ethernet-type
263 * interfaces, but not on IP-type interfaces.
265 * It is no longer needed, because Cake now adjusts for
266 * that automatically, and is thus ignored.
268 * It would be deleted entirely, but it appears in the
269 * stats output when the automatic compensation is
272 } else if (strcmp(*argv
, "ethernet") == 0) {
273 /* ethernet pre-amble & interframe gap & FCS
274 * you may need to add vlan tag
280 /* Additional Ethernet-related overhead used by some ISPs */
281 } else if (strcmp(*argv
, "ether-vlan") == 0) {
282 /* 802.1q VLAN tag - may be repeated */
287 * DOCSIS cable shapers account for Ethernet frame with FCS,
288 * but not interframe gap or preamble.
290 } else if (strcmp(*argv
, "docsis") == 0) {
295 } else if (strcmp(*argv
, "overhead") == 0) {
299 overhead
= strtol(*argv
, &p
, 10);
300 if (!p
|| *p
|| !*argv
||
301 overhead
< -64 || overhead
> 256) {
303 "Illegal \"overhead\", valid range is -64 to 256\\n");
308 } else if (strcmp(*argv
, "mpu") == 0) {
312 mpu
= strtol(*argv
, &p
, 10);
313 if (!p
|| *p
|| !*argv
|| mpu
< 0 || mpu
> 256) {
315 "Illegal \"mpu\", valid range is 0 to 256\\n");
318 } else if (strcmp(*argv
, "ingress") == 0) {
320 } else if (strcmp(*argv
, "egress") == 0) {
322 } else if (strcmp(*argv
, "no-ack-filter") == 0) {
323 ack_filter
= CAKE_ACK_NONE
;
324 } else if (strcmp(*argv
, "ack-filter") == 0) {
325 ack_filter
= CAKE_ACK_FILTER
;
326 } else if (strcmp(*argv
, "ack-filter-aggressive") == 0) {
327 ack_filter
= CAKE_ACK_AGGRESSIVE
;
328 } else if (strcmp(*argv
, "memlimit") == 0) {
330 if (get_size(&memlimit
, *argv
)) {
332 "Illegal value for \"memlimit\": \"%s\"\n", *argv
);
335 } else if (strcmp(*argv
, "help") == 0) {
339 fprintf(stderr
, "What is \"%s\"?\n", *argv
);
346 tail
= NLMSG_TAIL(n
);
347 addattr_l(n
, 1024, TCA_OPTIONS
, NULL
, 0);
348 if (bandwidth
|| unlimited
)
349 addattr_l(n
, 1024, TCA_CAKE_BASE_RATE64
, &bandwidth
,
352 addattr_l(n
, 1024, TCA_CAKE_DIFFSERV_MODE
, &diffserv
,
355 addattr_l(n
, 1024, TCA_CAKE_ATM
, &atm
, sizeof(atm
));
357 addattr_l(n
, 1024, TCA_CAKE_FLOW_MODE
, &flowmode
,
360 addattr_l(n
, 1024, TCA_CAKE_OVERHEAD
, &overhead
,
362 if (overhead_override
) {
363 unsigned int zero
= 0;
365 addattr_l(n
, 1024, TCA_CAKE_RAW
, &zero
, sizeof(zero
));
368 addattr_l(n
, 1024, TCA_CAKE_MPU
, &mpu
, sizeof(mpu
));
370 addattr_l(n
, 1024, TCA_CAKE_RTT
, &interval
, sizeof(interval
));
372 addattr_l(n
, 1024, TCA_CAKE_TARGET
, &target
, sizeof(target
));
374 addattr_l(n
, 1024, TCA_CAKE_AUTORATE
, &autorate
,
377 addattr_l(n
, 1024, TCA_CAKE_MEMORY
, &memlimit
,
380 addattr_l(n
, 1024, TCA_CAKE_NAT
, &nat
, sizeof(nat
));
382 addattr_l(n
, 1024, TCA_CAKE_WASH
, &wash
, sizeof(wash
));
384 addattr_l(n
, 1024, TCA_CAKE_SPLIT_GSO
, &split_gso
,
387 addattr_l(n
, 1024, TCA_CAKE_INGRESS
, &ingress
, sizeof(ingress
));
388 if (ack_filter
!= -1)
389 addattr_l(n
, 1024, TCA_CAKE_ACK_FILTER
, &ack_filter
,
392 tail
->rta_len
= (void *) NLMSG_TAIL(n
) - (void *) tail
;
396 static void cake_print_mode(unsigned int value
, unsigned int max
,
397 const char *key
, const char **table
)
399 if (value
< max
&& table
[value
]) {
400 print_string(PRINT_ANY
, key
, "%s ", table
[value
]);
402 print_string(PRINT_JSON
, key
, NULL
, "unknown");
403 print_string(PRINT_FP
, NULL
, "(?%s?)", key
);
407 static int cake_print_opt(struct qdisc_util
*qu
, FILE *f
, struct rtattr
*opt
)
409 struct rtattr
*tb
[TCA_CAKE_MAX
+ 1];
410 unsigned int interval
= 0;
411 unsigned int memlimit
= 0;
430 parse_rtattr_nested(tb
, TCA_CAKE_MAX
, opt
);
432 if (tb
[TCA_CAKE_BASE_RATE64
] &&
433 RTA_PAYLOAD(tb
[TCA_CAKE_BASE_RATE64
]) >= sizeof(bandwidth
)) {
434 bandwidth
= rta_getattr_u64(tb
[TCA_CAKE_BASE_RATE64
]);
436 print_uint(PRINT_JSON
, "bandwidth", NULL
, bandwidth
);
437 print_string(PRINT_FP
, NULL
, "bandwidth %s ",
438 sprint_rate(bandwidth
, b1
));
440 print_string(PRINT_ANY
, "bandwidth", "bandwidth %s ",
443 if (tb
[TCA_CAKE_AUTORATE
] &&
444 RTA_PAYLOAD(tb
[TCA_CAKE_AUTORATE
]) >= sizeof(__u32
)) {
445 autorate
= rta_getattr_u32(tb
[TCA_CAKE_AUTORATE
]);
447 print_string(PRINT_ANY
, "autorate", "%s ",
450 print_string(PRINT_ANY
, "autorate", "(?autorate?) ",
453 if (tb
[TCA_CAKE_DIFFSERV_MODE
] &&
454 RTA_PAYLOAD(tb
[TCA_CAKE_DIFFSERV_MODE
]) >= sizeof(__u32
)) {
455 cake_print_mode(rta_getattr_u32(tb
[TCA_CAKE_DIFFSERV_MODE
]),
456 CAKE_DIFFSERV_MAX
, "diffserv", diffserv_names
);
458 if (tb
[TCA_CAKE_FLOW_MODE
] &&
459 RTA_PAYLOAD(tb
[TCA_CAKE_FLOW_MODE
]) >= sizeof(__u32
)) {
460 cake_print_mode(rta_getattr_u32(tb
[TCA_CAKE_FLOW_MODE
]),
461 CAKE_FLOW_MAX
, "flowmode", flowmode_names
);
464 if (tb
[TCA_CAKE_NAT
] &&
465 RTA_PAYLOAD(tb
[TCA_CAKE_NAT
]) >= sizeof(__u32
)) {
466 nat
= rta_getattr_u32(tb
[TCA_CAKE_NAT
]);
470 print_string(PRINT_FP
, NULL
, "nat ", NULL
);
472 print_string(PRINT_FP
, NULL
, "nonat ", NULL
);
473 print_bool(PRINT_JSON
, "nat", NULL
, nat
);
475 if (tb
[TCA_CAKE_WASH
] &&
476 RTA_PAYLOAD(tb
[TCA_CAKE_WASH
]) >= sizeof(__u32
)) {
477 wash
= rta_getattr_u32(tb
[TCA_CAKE_WASH
]);
479 if (tb
[TCA_CAKE_ATM
] &&
480 RTA_PAYLOAD(tb
[TCA_CAKE_ATM
]) >= sizeof(__u32
)) {
481 atm
= rta_getattr_u32(tb
[TCA_CAKE_ATM
]);
483 if (tb
[TCA_CAKE_OVERHEAD
] &&
484 RTA_PAYLOAD(tb
[TCA_CAKE_OVERHEAD
]) >= sizeof(__s32
)) {
485 overhead
= *(__s32
*) RTA_DATA(tb
[TCA_CAKE_OVERHEAD
]);
487 if (tb
[TCA_CAKE_MPU
] &&
488 RTA_PAYLOAD(tb
[TCA_CAKE_MPU
]) >= sizeof(__u32
)) {
489 mpu
= rta_getattr_u32(tb
[TCA_CAKE_MPU
]);
491 if (tb
[TCA_CAKE_INGRESS
] &&
492 RTA_PAYLOAD(tb
[TCA_CAKE_INGRESS
]) >= sizeof(__u32
)) {
493 ingress
= rta_getattr_u32(tb
[TCA_CAKE_INGRESS
]);
495 if (tb
[TCA_CAKE_ACK_FILTER
] &&
496 RTA_PAYLOAD(tb
[TCA_CAKE_ACK_FILTER
]) >= sizeof(__u32
)) {
497 ack_filter
= rta_getattr_u32(tb
[TCA_CAKE_ACK_FILTER
]);
499 if (tb
[TCA_CAKE_SPLIT_GSO
] &&
500 RTA_PAYLOAD(tb
[TCA_CAKE_SPLIT_GSO
]) >= sizeof(__u32
)) {
501 split_gso
= rta_getattr_u32(tb
[TCA_CAKE_SPLIT_GSO
]);
503 if (tb
[TCA_CAKE_RAW
]) {
506 if (tb
[TCA_CAKE_RTT
] &&
507 RTA_PAYLOAD(tb
[TCA_CAKE_RTT
]) >= sizeof(__u32
)) {
508 interval
= rta_getattr_u32(tb
[TCA_CAKE_RTT
]);
512 print_string(PRINT_FP
, NULL
, "wash ", NULL
);
514 print_string(PRINT_FP
, NULL
, "nowash ", NULL
);
515 print_bool(PRINT_JSON
, "wash", NULL
, wash
);
518 print_string(PRINT_FP
, NULL
, "ingress ", NULL
);
519 print_bool(PRINT_JSON
, "ingress", NULL
, ingress
);
521 if (ack_filter
== CAKE_ACK_AGGRESSIVE
)
522 print_string(PRINT_ANY
, "ack-filter", "ack-filter-%s ",
524 else if (ack_filter
== CAKE_ACK_FILTER
)
525 print_string(PRINT_ANY
, "ack-filter", "ack-filter ", "enabled");
527 print_string(PRINT_ANY
, "ack-filter", "no-ack-filter ", "disabled");
530 print_string(PRINT_FP
, NULL
, "split-gso ", NULL
);
532 print_string(PRINT_FP
, NULL
, "no-split-gso ", NULL
);
533 print_bool(PRINT_JSON
, "split_gso", NULL
, split_gso
);
536 print_string(PRINT_FP
, NULL
, "rtt %s ",
537 sprint_time(interval
, b2
));
538 print_uint(PRINT_JSON
, "rtt", NULL
, interval
);
541 print_string(PRINT_FP
, NULL
, "raw ", NULL
);
542 print_bool(PRINT_JSON
, "raw", NULL
, raw
);
544 if (atm
== CAKE_ATM_ATM
)
545 print_string(PRINT_ANY
, "atm", "%s ", "atm");
546 else if (atm
== CAKE_ATM_PTM
)
547 print_string(PRINT_ANY
, "atm", "%s ", "ptm");
549 print_string(PRINT_ANY
, "atm", "%s ", "noatm");
551 print_int(PRINT_ANY
, "overhead", "overhead %d ", overhead
);
554 print_uint(PRINT_ANY
, "mpu", "mpu %u ", mpu
);
557 print_uint(PRINT_JSON
, "memlimit", NULL
, memlimit
);
558 print_string(PRINT_FP
, NULL
, "memlimit %s",
559 sprint_size(memlimit
, b1
));
565 static void cake_print_json_tin(struct rtattr
**tstat
)
567 #define PRINT_TSTAT_JSON(type, name, attr) if (tstat[TCA_CAKE_TIN_STATS_ ## attr]) \
568 print_u64(PRINT_JSON, name, NULL, \
569 rta_getattr_ ## type((struct rtattr *) \
570 tstat[TCA_CAKE_TIN_STATS_ ## attr]))
572 open_json_object(NULL
);
573 PRINT_TSTAT_JSON(u64
, "threshold_rate", THRESHOLD_RATE64
);
574 PRINT_TSTAT_JSON(u64
, "sent_bytes", SENT_BYTES64
);
575 PRINT_TSTAT_JSON(u32
, "backlog_bytes", BACKLOG_BYTES
);
576 PRINT_TSTAT_JSON(u32
, "target_us", TARGET_US
);
577 PRINT_TSTAT_JSON(u32
, "interval_us", INTERVAL_US
);
578 PRINT_TSTAT_JSON(u32
, "peak_delay_us", PEAK_DELAY_US
);
579 PRINT_TSTAT_JSON(u32
, "avg_delay_us", AVG_DELAY_US
);
580 PRINT_TSTAT_JSON(u32
, "base_delay_us", BASE_DELAY_US
);
581 PRINT_TSTAT_JSON(u32
, "sent_packets", SENT_PACKETS
);
582 PRINT_TSTAT_JSON(u32
, "way_indirect_hits", WAY_INDIRECT_HITS
);
583 PRINT_TSTAT_JSON(u32
, "way_misses", WAY_MISSES
);
584 PRINT_TSTAT_JSON(u32
, "way_collisions", WAY_COLLISIONS
);
585 PRINT_TSTAT_JSON(u32
, "drops", DROPPED_PACKETS
);
586 PRINT_TSTAT_JSON(u32
, "ecn_mark", ECN_MARKED_PACKETS
);
587 PRINT_TSTAT_JSON(u32
, "ack_drops", ACKS_DROPPED_PACKETS
);
588 PRINT_TSTAT_JSON(u32
, "sparse_flows", SPARSE_FLOWS
);
589 PRINT_TSTAT_JSON(u32
, "bulk_flows", BULK_FLOWS
);
590 PRINT_TSTAT_JSON(u32
, "unresponsive_flows", UNRESPONSIVE_FLOWS
);
591 PRINT_TSTAT_JSON(u32
, "max_pkt_len", MAX_SKBLEN
);
592 PRINT_TSTAT_JSON(u32
, "flow_quantum", FLOW_QUANTUM
);
595 #undef PRINT_TSTAT_JSON
598 static int cake_print_xstats(struct qdisc_util
*qu
, FILE *f
,
599 struct rtattr
*xstats
)
601 struct rtattr
*st
[TCA_CAKE_STATS_MAX
+ 1];
608 #define GET_STAT_U32(attr) rta_getattr_u32(st[TCA_CAKE_STATS_ ## attr])
609 #define GET_STAT_S32(attr) (*(__s32 *)RTA_DATA(st[TCA_CAKE_STATS_ ## attr]))
610 #define GET_STAT_U64(attr) rta_getattr_u64(st[TCA_CAKE_STATS_ ## attr])
612 parse_rtattr_nested(st
, TCA_CAKE_STATS_MAX
, xstats
);
614 if (st
[TCA_CAKE_STATS_MEMORY_USED
] &&
615 st
[TCA_CAKE_STATS_MEMORY_LIMIT
]) {
616 print_string(PRINT_FP
, NULL
, " memory used: %s",
617 sprint_size(GET_STAT_U32(MEMORY_USED
), b1
));
619 print_string(PRINT_FP
, NULL
, " of %s\n",
620 sprint_size(GET_STAT_U32(MEMORY_LIMIT
), b1
));
622 print_uint(PRINT_JSON
, "memory_used", NULL
,
623 GET_STAT_U32(MEMORY_USED
));
624 print_uint(PRINT_JSON
, "memory_limit", NULL
,
625 GET_STAT_U32(MEMORY_LIMIT
));
628 if (st
[TCA_CAKE_STATS_CAPACITY_ESTIMATE64
]) {
629 print_string(PRINT_FP
, NULL
, " capacity estimate: %s\n",
630 sprint_rate(GET_STAT_U64(CAPACITY_ESTIMATE64
), b1
));
631 print_uint(PRINT_JSON
, "capacity_estimate", NULL
,
632 GET_STAT_U64(CAPACITY_ESTIMATE64
));
635 if (st
[TCA_CAKE_STATS_MIN_NETLEN
] &&
636 st
[TCA_CAKE_STATS_MAX_NETLEN
]) {
637 print_uint(PRINT_ANY
, "min_network_size",
638 " min/max network layer size: %12u",
639 GET_STAT_U32(MIN_NETLEN
));
640 print_uint(PRINT_ANY
, "max_network_size",
641 " /%8u\n", GET_STAT_U32(MAX_NETLEN
));
644 if (st
[TCA_CAKE_STATS_MIN_ADJLEN
] &&
645 st
[TCA_CAKE_STATS_MAX_ADJLEN
]) {
646 print_uint(PRINT_ANY
, "min_adj_size",
647 " min/max overhead-adjusted size: %8u",
648 GET_STAT_U32(MIN_ADJLEN
));
649 print_uint(PRINT_ANY
, "max_adj_size",
650 " /%8u\n", GET_STAT_U32(MAX_ADJLEN
));
653 if (st
[TCA_CAKE_STATS_AVG_NETOFF
])
654 print_uint(PRINT_ANY
, "avg_hdr_offset",
655 " average network hdr offset: %12u\n\n",
656 GET_STAT_U32(AVG_NETOFF
));
659 if (st
[TCA_CAKE_STATS_DEFICIT
])
660 print_int(PRINT_ANY
, "deficit", " deficit %u",
661 GET_STAT_S32(DEFICIT
));
662 if (st
[TCA_CAKE_STATS_COBALT_COUNT
])
663 print_uint(PRINT_ANY
, "count", " count %u",
664 GET_STAT_U32(COBALT_COUNT
));
666 if (st
[TCA_CAKE_STATS_DROPPING
] && GET_STAT_U32(DROPPING
)) {
667 print_bool(PRINT_ANY
, "dropping", " dropping", true);
668 if (st
[TCA_CAKE_STATS_DROP_NEXT_US
]) {
669 int drop_next
= GET_STAT_S32(DROP_NEXT_US
);
672 print_string(PRINT_FP
, NULL
, " drop_next -%s",
673 sprint_time(drop_next
, b1
));
675 print_uint(PRINT_JSON
, "drop_next", NULL
,
677 print_string(PRINT_FP
, NULL
, " drop_next %s",
678 sprint_time(drop_next
, b1
));
683 if (st
[TCA_CAKE_STATS_P_DROP
]) {
684 print_uint(PRINT_ANY
, "blue_prob", " blue_prob %u",
685 GET_STAT_U32(P_DROP
));
686 if (st
[TCA_CAKE_STATS_BLUE_TIMER_US
]) {
687 int blue_timer
= GET_STAT_S32(BLUE_TIMER_US
);
689 if (blue_timer
< 0) {
690 print_string(PRINT_FP
, NULL
, " blue_timer -%s",
691 sprint_time(blue_timer
, b1
));
693 print_uint(PRINT_JSON
, "blue_timer", NULL
,
695 print_string(PRINT_FP
, NULL
, " blue_timer %s",
696 sprint_time(blue_timer
, b1
));
705 if (st
[TCA_CAKE_STATS_TIN_STATS
]) {
706 struct rtattr
*tstat
[TC_CAKE_MAX_TINS
][TCA_CAKE_TIN_STATS_MAX
+ 1];
707 struct rtattr
*tins
[TC_CAKE_MAX_TINS
+ 1];
710 parse_rtattr_nested(tins
, TC_CAKE_MAX_TINS
,
711 st
[TCA_CAKE_STATS_TIN_STATS
]);
713 for (i
= 1; i
<= TC_CAKE_MAX_TINS
&& tins
[i
]; i
++) {
714 parse_rtattr_nested(tstat
[i
-1], TCA_CAKE_TIN_STATS_MAX
,
722 if (is_json_context()) {
723 open_json_array(PRINT_JSON
, "tins");
724 for (i
= 0; i
< num_tins
; i
++)
725 cake_print_json_tin(tstat
[i
]);
726 close_json_array(PRINT_JSON
, NULL
);
734 fprintf(f
, " Bulk Best Effort Voice\n");
738 fprintf(f
, " Bulk Best Effort Video Voice\n");
743 for (i
= 0; i
< num_tins
; i
++)
744 fprintf(f
, " Tin %u", i
);
748 #define GET_TSTAT(i, attr) (tstat[i][TCA_CAKE_TIN_STATS_ ## attr])
749 #define PRINT_TSTAT(name, attr, fmts, val) do { \
750 if (GET_TSTAT(0, attr)) { \
752 for (i = 0; i < num_tins; i++) \
753 fprintf(f, " %12" fmts, val); \
758 #define SPRINT_TSTAT(pfunc, type, name, attr) PRINT_TSTAT( \
759 name, attr, "s", sprint_ ## pfunc( \
760 rta_getattr_ ## type(GET_TSTAT(i, attr)), b1))
762 #define PRINT_TSTAT_U32(name, attr) PRINT_TSTAT( \
763 name, attr, "u", rta_getattr_u32(GET_TSTAT(i, attr)))
765 #define PRINT_TSTAT_U64(name, attr) PRINT_TSTAT( \
766 name, attr, "llu", rta_getattr_u64(GET_TSTAT(i, attr)))
768 SPRINT_TSTAT(rate
, u64
, " thresh ", THRESHOLD_RATE64
);
769 SPRINT_TSTAT(time
, u32
, " target ", TARGET_US
);
770 SPRINT_TSTAT(time
, u32
, " interval", INTERVAL_US
);
771 SPRINT_TSTAT(time
, u32
, " pk_delay", PEAK_DELAY_US
);
772 SPRINT_TSTAT(time
, u32
, " av_delay", AVG_DELAY_US
);
773 SPRINT_TSTAT(time
, u32
, " sp_delay", BASE_DELAY_US
);
774 SPRINT_TSTAT(size
, u32
, " backlog ", BACKLOG_BYTES
);
776 PRINT_TSTAT_U32(" pkts ", SENT_PACKETS
);
777 PRINT_TSTAT_U64(" bytes ", SENT_BYTES64
);
779 PRINT_TSTAT_U32(" way_inds", WAY_INDIRECT_HITS
);
780 PRINT_TSTAT_U32(" way_miss", WAY_MISSES
);
781 PRINT_TSTAT_U32(" way_cols", WAY_COLLISIONS
);
782 PRINT_TSTAT_U32(" drops ", DROPPED_PACKETS
);
783 PRINT_TSTAT_U32(" marks ", ECN_MARKED_PACKETS
);
784 PRINT_TSTAT_U32(" ack_drop", ACKS_DROPPED_PACKETS
);
785 PRINT_TSTAT_U32(" sp_flows", SPARSE_FLOWS
);
786 PRINT_TSTAT_U32(" bk_flows", BULK_FLOWS
);
787 PRINT_TSTAT_U32(" un_flows", UNRESPONSIVE_FLOWS
);
788 PRINT_TSTAT_U32(" max_len ", MAX_SKBLEN
);
789 PRINT_TSTAT_U32(" quantum ", FLOW_QUANTUM
);
794 #undef PRINT_TSTAT_U32
795 #undef PRINT_TSTAT_U64
800 struct qdisc_util cake_qdisc_util
= {
802 .parse_qopt
= cake_parse_opt
,
803 .print_qopt
= cake_print_opt
,
804 .print_xstats
= cake_print_xstats
,