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
);
471 print_bool(PRINT_JSON
, "nat", NULL
, nat
);
473 if (tb
[TCA_CAKE_WASH
] &&
474 RTA_PAYLOAD(tb
[TCA_CAKE_WASH
]) >= sizeof(__u32
)) {
475 wash
= rta_getattr_u32(tb
[TCA_CAKE_WASH
]);
477 if (tb
[TCA_CAKE_ATM
] &&
478 RTA_PAYLOAD(tb
[TCA_CAKE_ATM
]) >= sizeof(__u32
)) {
479 atm
= rta_getattr_u32(tb
[TCA_CAKE_ATM
]);
481 if (tb
[TCA_CAKE_OVERHEAD
] &&
482 RTA_PAYLOAD(tb
[TCA_CAKE_OVERHEAD
]) >= sizeof(__s32
)) {
483 overhead
= *(__s32
*) RTA_DATA(tb
[TCA_CAKE_OVERHEAD
]);
485 if (tb
[TCA_CAKE_MPU
] &&
486 RTA_PAYLOAD(tb
[TCA_CAKE_MPU
]) >= sizeof(__u32
)) {
487 mpu
= rta_getattr_u32(tb
[TCA_CAKE_MPU
]);
489 if (tb
[TCA_CAKE_INGRESS
] &&
490 RTA_PAYLOAD(tb
[TCA_CAKE_INGRESS
]) >= sizeof(__u32
)) {
491 ingress
= rta_getattr_u32(tb
[TCA_CAKE_INGRESS
]);
493 if (tb
[TCA_CAKE_ACK_FILTER
] &&
494 RTA_PAYLOAD(tb
[TCA_CAKE_ACK_FILTER
]) >= sizeof(__u32
)) {
495 ack_filter
= rta_getattr_u32(tb
[TCA_CAKE_ACK_FILTER
]);
497 if (tb
[TCA_CAKE_SPLIT_GSO
] &&
498 RTA_PAYLOAD(tb
[TCA_CAKE_SPLIT_GSO
]) >= sizeof(__u32
)) {
499 split_gso
= rta_getattr_u32(tb
[TCA_CAKE_SPLIT_GSO
]);
501 if (tb
[TCA_CAKE_RAW
]) {
504 if (tb
[TCA_CAKE_RTT
] &&
505 RTA_PAYLOAD(tb
[TCA_CAKE_RTT
]) >= sizeof(__u32
)) {
506 interval
= rta_getattr_u32(tb
[TCA_CAKE_RTT
]);
510 print_string(PRINT_FP
, NULL
, "wash ", NULL
);
511 print_bool(PRINT_JSON
, "wash", NULL
, wash
);
514 print_string(PRINT_FP
, NULL
, "ingress ", NULL
);
515 print_bool(PRINT_JSON
, "ingress", NULL
, ingress
);
517 if (ack_filter
== CAKE_ACK_AGGRESSIVE
)
518 print_string(PRINT_ANY
, "ack-filter", "ack-filter-%s ",
520 else if (ack_filter
== CAKE_ACK_FILTER
)
521 print_string(PRINT_ANY
, "ack-filter", "ack-filter ", "enabled");
523 print_string(PRINT_JSON
, "ack-filter", NULL
, "disabled");
526 print_string(PRINT_FP
, NULL
, "split-gso ", NULL
);
527 print_bool(PRINT_JSON
, "split_gso", NULL
, split_gso
);
530 print_string(PRINT_FP
, NULL
, "rtt %s ",
531 sprint_time(interval
, b2
));
532 print_uint(PRINT_JSON
, "rtt", NULL
, interval
);
535 print_string(PRINT_FP
, NULL
, "raw ", NULL
);
536 print_bool(PRINT_JSON
, "raw", NULL
, raw
);
538 if (atm
== CAKE_ATM_ATM
)
539 print_string(PRINT_ANY
, "atm", "%s ", "atm");
540 else if (atm
== CAKE_ATM_PTM
)
541 print_string(PRINT_ANY
, "atm", "%s ", "ptm");
543 print_string(PRINT_ANY
, "atm", "%s ", "noatm");
545 print_int(PRINT_ANY
, "overhead", "overhead %d ", overhead
);
548 print_uint(PRINT_ANY
, "mpu", "mpu %u ", mpu
);
551 print_uint(PRINT_JSON
, "memlimit", NULL
, memlimit
);
552 print_string(PRINT_FP
, NULL
, "memlimit %s",
553 sprint_size(memlimit
, b1
));
559 static void cake_print_json_tin(struct rtattr
**tstat
)
561 #define PRINT_TSTAT_JSON(type, name, attr) if (tstat[TCA_CAKE_TIN_STATS_ ## attr]) \
562 print_u64(PRINT_JSON, name, NULL, \
563 rta_getattr_ ## type((struct rtattr *) \
564 tstat[TCA_CAKE_TIN_STATS_ ## attr]))
566 open_json_object(NULL
);
567 PRINT_TSTAT_JSON(u64
, "threshold_rate", THRESHOLD_RATE64
);
568 PRINT_TSTAT_JSON(u64
, "sent_bytes", SENT_BYTES64
);
569 PRINT_TSTAT_JSON(u32
, "backlog_bytes", BACKLOG_BYTES
);
570 PRINT_TSTAT_JSON(u32
, "target_us", TARGET_US
);
571 PRINT_TSTAT_JSON(u32
, "interval_us", INTERVAL_US
);
572 PRINT_TSTAT_JSON(u32
, "peak_delay_us", PEAK_DELAY_US
);
573 PRINT_TSTAT_JSON(u32
, "avg_delay_us", AVG_DELAY_US
);
574 PRINT_TSTAT_JSON(u32
, "base_delay_us", BASE_DELAY_US
);
575 PRINT_TSTAT_JSON(u32
, "sent_packets", SENT_PACKETS
);
576 PRINT_TSTAT_JSON(u32
, "way_indirect_hits", WAY_INDIRECT_HITS
);
577 PRINT_TSTAT_JSON(u32
, "way_misses", WAY_MISSES
);
578 PRINT_TSTAT_JSON(u32
, "way_collisions", WAY_COLLISIONS
);
579 PRINT_TSTAT_JSON(u32
, "drops", DROPPED_PACKETS
);
580 PRINT_TSTAT_JSON(u32
, "ecn_mark", ECN_MARKED_PACKETS
);
581 PRINT_TSTAT_JSON(u32
, "ack_drops", ACKS_DROPPED_PACKETS
);
582 PRINT_TSTAT_JSON(u32
, "sparse_flows", SPARSE_FLOWS
);
583 PRINT_TSTAT_JSON(u32
, "bulk_flows", BULK_FLOWS
);
584 PRINT_TSTAT_JSON(u32
, "unresponsive_flows", UNRESPONSIVE_FLOWS
);
585 PRINT_TSTAT_JSON(u32
, "max_pkt_len", MAX_SKBLEN
);
586 PRINT_TSTAT_JSON(u32
, "flow_quantum", FLOW_QUANTUM
);
589 #undef PRINT_TSTAT_JSON
592 static int cake_print_xstats(struct qdisc_util
*qu
, FILE *f
,
593 struct rtattr
*xstats
)
595 struct rtattr
*st
[TCA_CAKE_STATS_MAX
+ 1];
602 #define GET_STAT_U32(attr) rta_getattr_u32(st[TCA_CAKE_STATS_ ## attr])
603 #define GET_STAT_S32(attr) (*(__s32 *)RTA_DATA(st[TCA_CAKE_STATS_ ## attr]))
604 #define GET_STAT_U64(attr) rta_getattr_u64(st[TCA_CAKE_STATS_ ## attr])
606 parse_rtattr_nested(st
, TCA_CAKE_STATS_MAX
, xstats
);
608 if (st
[TCA_CAKE_STATS_MEMORY_USED
] &&
609 st
[TCA_CAKE_STATS_MEMORY_LIMIT
]) {
610 print_string(PRINT_FP
, NULL
, " memory used: %s",
611 sprint_size(GET_STAT_U32(MEMORY_USED
), b1
));
613 print_string(PRINT_FP
, NULL
, " of %s\n",
614 sprint_size(GET_STAT_U32(MEMORY_LIMIT
), b1
));
616 print_uint(PRINT_JSON
, "memory_used", NULL
,
617 GET_STAT_U32(MEMORY_USED
));
618 print_uint(PRINT_JSON
, "memory_limit", NULL
,
619 GET_STAT_U32(MEMORY_LIMIT
));
622 if (st
[TCA_CAKE_STATS_CAPACITY_ESTIMATE64
]) {
623 print_string(PRINT_FP
, NULL
, " capacity estimate: %s\n",
624 sprint_rate(GET_STAT_U64(CAPACITY_ESTIMATE64
), b1
));
625 print_uint(PRINT_JSON
, "capacity_estimate", NULL
,
626 GET_STAT_U64(CAPACITY_ESTIMATE64
));
629 if (st
[TCA_CAKE_STATS_MIN_NETLEN
] &&
630 st
[TCA_CAKE_STATS_MAX_NETLEN
]) {
631 print_uint(PRINT_ANY
, "min_network_size",
632 " min/max network layer size: %12u",
633 GET_STAT_U32(MIN_NETLEN
));
634 print_uint(PRINT_ANY
, "max_network_size",
635 " /%8u\n", GET_STAT_U32(MAX_NETLEN
));
638 if (st
[TCA_CAKE_STATS_MIN_ADJLEN
] &&
639 st
[TCA_CAKE_STATS_MAX_ADJLEN
]) {
640 print_uint(PRINT_ANY
, "min_adj_size",
641 " min/max overhead-adjusted size: %8u",
642 GET_STAT_U32(MIN_ADJLEN
));
643 print_uint(PRINT_ANY
, "max_adj_size",
644 " /%8u\n", GET_STAT_U32(MAX_ADJLEN
));
647 if (st
[TCA_CAKE_STATS_AVG_NETOFF
])
648 print_uint(PRINT_ANY
, "avg_hdr_offset",
649 " average network hdr offset: %12u\n\n",
650 GET_STAT_U32(AVG_NETOFF
));
653 if (st
[TCA_CAKE_STATS_DEFICIT
])
654 print_int(PRINT_ANY
, "deficit", " deficit %u",
655 GET_STAT_S32(DEFICIT
));
656 if (st
[TCA_CAKE_STATS_COBALT_COUNT
])
657 print_uint(PRINT_ANY
, "count", " count %u",
658 GET_STAT_U32(COBALT_COUNT
));
660 if (st
[TCA_CAKE_STATS_DROPPING
] && GET_STAT_U32(DROPPING
)) {
661 print_bool(PRINT_ANY
, "dropping", " dropping", true);
662 if (st
[TCA_CAKE_STATS_DROP_NEXT_US
]) {
663 int drop_next
= GET_STAT_S32(DROP_NEXT_US
);
666 print_string(PRINT_FP
, NULL
, " drop_next -%s",
667 sprint_time(drop_next
, b1
));
669 print_uint(PRINT_JSON
, "drop_next", NULL
,
671 print_string(PRINT_FP
, NULL
, " drop_next %s",
672 sprint_time(drop_next
, b1
));
677 if (st
[TCA_CAKE_STATS_P_DROP
]) {
678 print_uint(PRINT_ANY
, "blue_prob", " blue_prob %u",
679 GET_STAT_U32(P_DROP
));
680 if (st
[TCA_CAKE_STATS_BLUE_TIMER_US
]) {
681 int blue_timer
= GET_STAT_S32(BLUE_TIMER_US
);
683 if (blue_timer
< 0) {
684 print_string(PRINT_FP
, NULL
, " blue_timer -%s",
685 sprint_time(blue_timer
, b1
));
687 print_uint(PRINT_JSON
, "blue_timer", NULL
,
689 print_string(PRINT_FP
, NULL
, " blue_timer %s",
690 sprint_time(blue_timer
, b1
));
699 if (st
[TCA_CAKE_STATS_TIN_STATS
]) {
700 struct rtattr
*tstat
[TC_CAKE_MAX_TINS
][TCA_CAKE_TIN_STATS_MAX
+ 1];
701 struct rtattr
*tins
[TC_CAKE_MAX_TINS
+ 1];
704 parse_rtattr_nested(tins
, TC_CAKE_MAX_TINS
,
705 st
[TCA_CAKE_STATS_TIN_STATS
]);
707 for (i
= 1; i
<= TC_CAKE_MAX_TINS
&& tins
[i
]; i
++) {
708 parse_rtattr_nested(tstat
[i
-1], TCA_CAKE_TIN_STATS_MAX
,
716 if (is_json_context()) {
717 open_json_array(PRINT_JSON
, "tins");
718 for (i
= 0; i
< num_tins
; i
++)
719 cake_print_json_tin(tstat
[i
]);
720 close_json_array(PRINT_JSON
, NULL
);
728 fprintf(f
, " Bulk Best Effort Voice\n");
732 fprintf(f
, " Bulk Best Effort Video Voice\n");
737 for (i
= 0; i
< num_tins
; i
++)
738 fprintf(f
, " Tin %u", i
);
742 #define GET_TSTAT(i, attr) (tstat[i][TCA_CAKE_TIN_STATS_ ## attr])
743 #define PRINT_TSTAT(name, attr, fmts, val) do { \
744 if (GET_TSTAT(0, attr)) { \
746 for (i = 0; i < num_tins; i++) \
747 fprintf(f, " %12" fmts, val); \
752 #define SPRINT_TSTAT(pfunc, type, name, attr) PRINT_TSTAT( \
753 name, attr, "s", sprint_ ## pfunc( \
754 rta_getattr_ ## type(GET_TSTAT(i, attr)), b1))
756 #define PRINT_TSTAT_U32(name, attr) PRINT_TSTAT( \
757 name, attr, "u", rta_getattr_u32(GET_TSTAT(i, attr)))
759 #define PRINT_TSTAT_U64(name, attr) PRINT_TSTAT( \
760 name, attr, "llu", rta_getattr_u64(GET_TSTAT(i, attr)))
762 SPRINT_TSTAT(rate
, u64
, " thresh ", THRESHOLD_RATE64
);
763 SPRINT_TSTAT(time
, u32
, " target ", TARGET_US
);
764 SPRINT_TSTAT(time
, u32
, " interval", INTERVAL_US
);
765 SPRINT_TSTAT(time
, u32
, " pk_delay", PEAK_DELAY_US
);
766 SPRINT_TSTAT(time
, u32
, " av_delay", AVG_DELAY_US
);
767 SPRINT_TSTAT(time
, u32
, " sp_delay", BASE_DELAY_US
);
768 SPRINT_TSTAT(size
, u32
, " backlog ", BACKLOG_BYTES
);
770 PRINT_TSTAT_U32(" pkts ", SENT_PACKETS
);
771 PRINT_TSTAT_U64(" bytes ", SENT_BYTES64
);
773 PRINT_TSTAT_U32(" way_inds", WAY_INDIRECT_HITS
);
774 PRINT_TSTAT_U32(" way_miss", WAY_MISSES
);
775 PRINT_TSTAT_U32(" way_cols", WAY_COLLISIONS
);
776 PRINT_TSTAT_U32(" drops ", DROPPED_PACKETS
);
777 PRINT_TSTAT_U32(" marks ", ECN_MARKED_PACKETS
);
778 PRINT_TSTAT_U32(" ack_drop", ACKS_DROPPED_PACKETS
);
779 PRINT_TSTAT_U32(" sp_flows", SPARSE_FLOWS
);
780 PRINT_TSTAT_U32(" bk_flows", BULK_FLOWS
);
781 PRINT_TSTAT_U32(" un_flows", UNRESPONSIVE_FLOWS
);
782 PRINT_TSTAT_U32(" max_len ", MAX_SKBLEN
);
783 PRINT_TSTAT_U32(" quantum ", FLOW_QUANTUM
);
788 #undef PRINT_TSTAT_U32
789 #undef PRINT_TSTAT_U64
794 struct qdisc_util cake_qdisc_util
= {
796 .parse_qopt
= cake_parse_opt
,
797 .print_qopt
= cake_print_opt
,
798 .print_xstats
= cake_print_xstats
,