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"
86 " [ ptm | atm | noatm* ] [ overhead N | conservative | raw* ]\n"
87 " [ mpu N ] [ ingress | egress* ]\n"
88 " (* marks defaults)\n");
91 static int cake_parse_opt(struct qdisc_util
*qu
, int argc
, char **argv
,
92 struct nlmsghdr
*n
, const char *dev
)
94 struct cake_preset
*preset
, *preset_set
= NULL
;
95 bool overhead_override
= false;
96 bool overhead_set
= false;
97 unsigned int interval
= 0;
98 unsigned int diffserv
= 0;
99 unsigned int memlimit
= 0;
100 unsigned int fwmark
= 0;
101 unsigned int target
= 0;
117 if (strcmp(*argv
, "bandwidth") == 0) {
119 if (get_rate64(&bandwidth
, *argv
)) {
120 fprintf(stderr
, "Illegal \"bandwidth\"\n");
125 } else if (strcmp(*argv
, "unlimited") == 0) {
129 } else if (strcmp(*argv
, "autorate-ingress") == 0) {
131 } else if (strcmp(*argv
, "rtt") == 0) {
133 if (get_time(&interval
, *argv
)) {
134 fprintf(stderr
, "Illegal \"rtt\"\n");
137 target
= interval
/ 20;
140 } else if ((preset
= find_preset(*argv
))) {
142 duparg(*argv
, preset_set
->name
);
144 target
= preset
->target
;
145 interval
= preset
->interval
;
146 } else if (strcmp(*argv
, "besteffort") == 0) {
147 diffserv
= CAKE_DIFFSERV_BESTEFFORT
;
148 } else if (strcmp(*argv
, "precedence") == 0) {
149 diffserv
= CAKE_DIFFSERV_PRECEDENCE
;
150 } else if (strcmp(*argv
, "diffserv8") == 0) {
151 diffserv
= CAKE_DIFFSERV_DIFFSERV8
;
152 } else if (strcmp(*argv
, "diffserv4") == 0) {
153 diffserv
= CAKE_DIFFSERV_DIFFSERV4
;
154 } else if (strcmp(*argv
, "diffserv") == 0) {
155 diffserv
= CAKE_DIFFSERV_DIFFSERV4
;
156 } else if (strcmp(*argv
, "diffserv3") == 0) {
157 diffserv
= CAKE_DIFFSERV_DIFFSERV3
;
158 } else if (strcmp(*argv
, "nowash") == 0) {
160 } else if (strcmp(*argv
, "wash") == 0) {
162 } else if (strcmp(*argv
, "split-gso") == 0) {
164 } else if (strcmp(*argv
, "no-split-gso") == 0) {
166 } else if (strcmp(*argv
, "flowblind") == 0) {
167 flowmode
= CAKE_FLOW_NONE
;
168 } else if (strcmp(*argv
, "srchost") == 0) {
169 flowmode
= CAKE_FLOW_SRC_IP
;
170 } else if (strcmp(*argv
, "dsthost") == 0) {
171 flowmode
= CAKE_FLOW_DST_IP
;
172 } else if (strcmp(*argv
, "hosts") == 0) {
173 flowmode
= CAKE_FLOW_HOSTS
;
174 } else if (strcmp(*argv
, "flows") == 0) {
175 flowmode
= CAKE_FLOW_FLOWS
;
176 } else if (strcmp(*argv
, "dual-srchost") == 0) {
177 flowmode
= CAKE_FLOW_DUAL_SRC
;
178 } else if (strcmp(*argv
, "dual-dsthost") == 0) {
179 flowmode
= CAKE_FLOW_DUAL_DST
;
180 } else if (strcmp(*argv
, "triple-isolate") == 0) {
181 flowmode
= CAKE_FLOW_TRIPLE
;
182 } else if (strcmp(*argv
, "nat") == 0) {
184 } else if (strcmp(*argv
, "nonat") == 0) {
186 } else if (strcmp(*argv
, "ptm") == 0) {
188 } else if (strcmp(*argv
, "atm") == 0) {
190 } else if (strcmp(*argv
, "noatm") == 0) {
192 } else if (strcmp(*argv
, "raw") == 0) {
196 overhead_override
= true;
197 } else if (strcmp(*argv
, "conservative") == 0) {
199 * Deliberately over-estimate overhead:
200 * one whole ATM cell plus ATM framing.
201 * A safe choice if the actual overhead is unknown.
207 /* Various ADSL framing schemes, all over ATM cells */
208 } else if (strcmp(*argv
, "ipoa-vcmux") == 0) {
212 } else if (strcmp(*argv
, "ipoa-llcsnap") == 0) {
216 } else if (strcmp(*argv
, "bridged-vcmux") == 0) {
220 } else if (strcmp(*argv
, "bridged-llcsnap") == 0) {
224 } else if (strcmp(*argv
, "pppoa-vcmux") == 0) {
228 } else if (strcmp(*argv
, "pppoa-llc") == 0) {
232 } else if (strcmp(*argv
, "pppoe-vcmux") == 0) {
236 } else if (strcmp(*argv
, "pppoe-llcsnap") == 0) {
241 /* Typical VDSL2 framing schemes, both over PTM */
242 /* PTM has 64b/65b coding which absorbs some bandwidth */
243 } else if (strcmp(*argv
, "pppoe-ptm") == 0) {
244 /* 2B PPP + 6B PPPoE + 6B dest MAC + 6B src MAC
245 * + 2B ethertype + 4B Frame Check Sequence
246 * + 1B Start of Frame (S) + 1B End of Frame (Ck)
247 * + 2B TC-CRC (PTM-FCS) = 30B
252 } else if (strcmp(*argv
, "bridged-ptm") == 0) {
253 /* 6B dest MAC + 6B src MAC + 2B ethertype
254 * + 4B Frame Check Sequence
255 * + 1B Start of Frame (S) + 1B End of Frame (Ck)
256 * + 2B TC-CRC (PTM-FCS) = 22B
261 } else if (strcmp(*argv
, "via-ethernet") == 0) {
263 * We used to use this flag to manually compensate for
264 * Linux including the Ethernet header on Ethernet-type
265 * interfaces, but not on IP-type interfaces.
267 * It is no longer needed, because Cake now adjusts for
268 * that automatically, and is thus ignored.
270 * It would be deleted entirely, but it appears in the
271 * stats output when the automatic compensation is
274 } else if (strcmp(*argv
, "ethernet") == 0) {
275 /* ethernet pre-amble & interframe gap & FCS
276 * you may need to add vlan tag
282 /* Additional Ethernet-related overhead used by some ISPs */
283 } else if (strcmp(*argv
, "ether-vlan") == 0) {
284 /* 802.1q VLAN tag - may be repeated */
289 * DOCSIS cable shapers account for Ethernet frame with FCS,
290 * but not interframe gap or preamble.
292 } else if (strcmp(*argv
, "docsis") == 0) {
297 } else if (strcmp(*argv
, "overhead") == 0) {
301 overhead
= strtol(*argv
, &p
, 10);
302 if (!p
|| *p
|| !*argv
||
303 overhead
< -64 || overhead
> 256) {
305 "Illegal \"overhead\", valid range is -64 to 256\\n");
310 } else if (strcmp(*argv
, "mpu") == 0) {
314 mpu
= strtol(*argv
, &p
, 10);
315 if (!p
|| *p
|| !*argv
|| mpu
< 0 || mpu
> 256) {
317 "Illegal \"mpu\", valid range is 0 to 256\\n");
320 } else if (strcmp(*argv
, "ingress") == 0) {
322 } else if (strcmp(*argv
, "egress") == 0) {
324 } else if (strcmp(*argv
, "no-ack-filter") == 0) {
325 ack_filter
= CAKE_ACK_NONE
;
326 } else if (strcmp(*argv
, "ack-filter") == 0) {
327 ack_filter
= CAKE_ACK_FILTER
;
328 } else if (strcmp(*argv
, "ack-filter-aggressive") == 0) {
329 ack_filter
= CAKE_ACK_AGGRESSIVE
;
330 } else if (strcmp(*argv
, "memlimit") == 0) {
332 if (get_size(&memlimit
, *argv
)) {
334 "Illegal value for \"memlimit\": \"%s\"\n", *argv
);
337 } else if (strcmp(*argv
, "fwmark") == 0) {
339 if (get_u32(&fwmark
, *argv
, 0)) {
341 "Illegal value for \"fwmark\": \"%s\"\n", *argv
);
344 } else if (strcmp(*argv
, "help") == 0) {
348 fprintf(stderr
, "What is \"%s\"?\n", *argv
);
355 tail
= NLMSG_TAIL(n
);
356 addattr_l(n
, 1024, TCA_OPTIONS
, NULL
, 0);
357 if (bandwidth
|| unlimited
)
358 addattr_l(n
, 1024, TCA_CAKE_BASE_RATE64
, &bandwidth
,
361 addattr_l(n
, 1024, TCA_CAKE_DIFFSERV_MODE
, &diffserv
,
364 addattr_l(n
, 1024, TCA_CAKE_ATM
, &atm
, sizeof(atm
));
366 addattr_l(n
, 1024, TCA_CAKE_FLOW_MODE
, &flowmode
,
369 addattr_l(n
, 1024, TCA_CAKE_OVERHEAD
, &overhead
,
371 if (overhead_override
) {
372 unsigned int zero
= 0;
374 addattr_l(n
, 1024, TCA_CAKE_RAW
, &zero
, sizeof(zero
));
377 addattr_l(n
, 1024, TCA_CAKE_MPU
, &mpu
, sizeof(mpu
));
379 addattr_l(n
, 1024, TCA_CAKE_RTT
, &interval
, sizeof(interval
));
381 addattr_l(n
, 1024, TCA_CAKE_TARGET
, &target
, sizeof(target
));
383 addattr_l(n
, 1024, TCA_CAKE_AUTORATE
, &autorate
,
386 addattr_l(n
, 1024, TCA_CAKE_MEMORY
, &memlimit
,
389 addattr_l(n
, 1024, TCA_CAKE_FWMARK
, &fwmark
,
392 addattr_l(n
, 1024, TCA_CAKE_NAT
, &nat
, sizeof(nat
));
394 addattr_l(n
, 1024, TCA_CAKE_WASH
, &wash
, sizeof(wash
));
396 addattr_l(n
, 1024, TCA_CAKE_SPLIT_GSO
, &split_gso
,
399 addattr_l(n
, 1024, TCA_CAKE_INGRESS
, &ingress
, sizeof(ingress
));
400 if (ack_filter
!= -1)
401 addattr_l(n
, 1024, TCA_CAKE_ACK_FILTER
, &ack_filter
,
404 tail
->rta_len
= (void *) NLMSG_TAIL(n
) - (void *) tail
;
408 static void cake_print_mode(unsigned int value
, unsigned int max
,
409 const char *key
, const char **table
)
411 if (value
< max
&& table
[value
]) {
412 print_string(PRINT_ANY
, key
, "%s ", table
[value
]);
414 print_string(PRINT_JSON
, key
, NULL
, "unknown");
415 print_string(PRINT_FP
, NULL
, "(?%s?)", key
);
419 static int cake_print_opt(struct qdisc_util
*qu
, FILE *f
, struct rtattr
*opt
)
421 struct rtattr
*tb
[TCA_CAKE_MAX
+ 1];
422 unsigned int interval
= 0;
423 unsigned int memlimit
= 0;
424 unsigned int fwmark
= 0;
442 parse_rtattr_nested(tb
, TCA_CAKE_MAX
, opt
);
444 if (tb
[TCA_CAKE_BASE_RATE64
] &&
445 RTA_PAYLOAD(tb
[TCA_CAKE_BASE_RATE64
]) >= sizeof(bandwidth
)) {
446 bandwidth
= rta_getattr_u64(tb
[TCA_CAKE_BASE_RATE64
]);
448 tc_print_rate(PRINT_ANY
, "bandwidth", "bandwidth %s ",
451 print_string(PRINT_ANY
, "bandwidth", "bandwidth %s ",
454 if (tb
[TCA_CAKE_AUTORATE
] &&
455 RTA_PAYLOAD(tb
[TCA_CAKE_AUTORATE
]) >= sizeof(__u32
)) {
456 autorate
= rta_getattr_u32(tb
[TCA_CAKE_AUTORATE
]);
458 print_string(PRINT_ANY
, "autorate", "%s ",
461 print_string(PRINT_ANY
, "autorate", "(?autorate?) ",
464 if (tb
[TCA_CAKE_DIFFSERV_MODE
] &&
465 RTA_PAYLOAD(tb
[TCA_CAKE_DIFFSERV_MODE
]) >= sizeof(__u32
)) {
466 cake_print_mode(rta_getattr_u32(tb
[TCA_CAKE_DIFFSERV_MODE
]),
467 CAKE_DIFFSERV_MAX
, "diffserv", diffserv_names
);
469 if (tb
[TCA_CAKE_FLOW_MODE
] &&
470 RTA_PAYLOAD(tb
[TCA_CAKE_FLOW_MODE
]) >= sizeof(__u32
)) {
471 cake_print_mode(rta_getattr_u32(tb
[TCA_CAKE_FLOW_MODE
]),
472 CAKE_FLOW_MAX
, "flowmode", flowmode_names
);
475 if (tb
[TCA_CAKE_NAT
] &&
476 RTA_PAYLOAD(tb
[TCA_CAKE_NAT
]) >= sizeof(__u32
)) {
477 nat
= rta_getattr_u32(tb
[TCA_CAKE_NAT
]);
481 print_string(PRINT_FP
, NULL
, "nat ", NULL
);
483 print_string(PRINT_FP
, NULL
, "nonat ", NULL
);
484 print_bool(PRINT_JSON
, "nat", NULL
, nat
);
486 if (tb
[TCA_CAKE_WASH
] &&
487 RTA_PAYLOAD(tb
[TCA_CAKE_WASH
]) >= sizeof(__u32
)) {
488 wash
= rta_getattr_u32(tb
[TCA_CAKE_WASH
]);
490 if (tb
[TCA_CAKE_ATM
] &&
491 RTA_PAYLOAD(tb
[TCA_CAKE_ATM
]) >= sizeof(__u32
)) {
492 atm
= rta_getattr_u32(tb
[TCA_CAKE_ATM
]);
494 if (tb
[TCA_CAKE_OVERHEAD
] &&
495 RTA_PAYLOAD(tb
[TCA_CAKE_OVERHEAD
]) >= sizeof(__s32
)) {
496 overhead
= *(__s32
*) RTA_DATA(tb
[TCA_CAKE_OVERHEAD
]);
498 if (tb
[TCA_CAKE_MPU
] &&
499 RTA_PAYLOAD(tb
[TCA_CAKE_MPU
]) >= sizeof(__u32
)) {
500 mpu
= rta_getattr_u32(tb
[TCA_CAKE_MPU
]);
502 if (tb
[TCA_CAKE_INGRESS
] &&
503 RTA_PAYLOAD(tb
[TCA_CAKE_INGRESS
]) >= sizeof(__u32
)) {
504 ingress
= rta_getattr_u32(tb
[TCA_CAKE_INGRESS
]);
506 if (tb
[TCA_CAKE_ACK_FILTER
] &&
507 RTA_PAYLOAD(tb
[TCA_CAKE_ACK_FILTER
]) >= sizeof(__u32
)) {
508 ack_filter
= rta_getattr_u32(tb
[TCA_CAKE_ACK_FILTER
]);
510 if (tb
[TCA_CAKE_SPLIT_GSO
] &&
511 RTA_PAYLOAD(tb
[TCA_CAKE_SPLIT_GSO
]) >= sizeof(__u32
)) {
512 split_gso
= rta_getattr_u32(tb
[TCA_CAKE_SPLIT_GSO
]);
514 if (tb
[TCA_CAKE_RAW
]) {
517 if (tb
[TCA_CAKE_RTT
] &&
518 RTA_PAYLOAD(tb
[TCA_CAKE_RTT
]) >= sizeof(__u32
)) {
519 interval
= rta_getattr_u32(tb
[TCA_CAKE_RTT
]);
521 if (tb
[TCA_CAKE_MEMORY
] &&
522 RTA_PAYLOAD(tb
[TCA_CAKE_MEMORY
]) >= sizeof(__u32
)) {
523 memlimit
= rta_getattr_u32(tb
[TCA_CAKE_MEMORY
]);
525 if (tb
[TCA_CAKE_FWMARK
] &&
526 RTA_PAYLOAD(tb
[TCA_CAKE_FWMARK
]) >= sizeof(__u32
)) {
527 fwmark
= rta_getattr_u32(tb
[TCA_CAKE_FWMARK
]);
531 print_string(PRINT_FP
, NULL
, "wash ", NULL
);
533 print_string(PRINT_FP
, NULL
, "nowash ", NULL
);
534 print_bool(PRINT_JSON
, "wash", NULL
, wash
);
537 print_string(PRINT_FP
, NULL
, "ingress ", NULL
);
538 print_bool(PRINT_JSON
, "ingress", NULL
, ingress
);
540 if (ack_filter
== CAKE_ACK_AGGRESSIVE
)
541 print_string(PRINT_ANY
, "ack-filter", "ack-filter-%s ",
543 else if (ack_filter
== CAKE_ACK_FILTER
)
544 print_string(PRINT_ANY
, "ack-filter", "ack-filter ", "enabled");
546 print_string(PRINT_ANY
, "ack-filter", "no-ack-filter ", "disabled");
549 print_string(PRINT_FP
, NULL
, "split-gso ", NULL
);
551 print_string(PRINT_FP
, NULL
, "no-split-gso ", NULL
);
552 print_bool(PRINT_JSON
, "split_gso", NULL
, split_gso
);
555 print_string(PRINT_FP
, NULL
, "rtt %s ",
556 sprint_time(interval
, b2
));
557 print_uint(PRINT_JSON
, "rtt", NULL
, interval
);
560 print_string(PRINT_FP
, NULL
, "raw ", NULL
);
561 print_bool(PRINT_JSON
, "raw", NULL
, raw
);
563 if (atm
== CAKE_ATM_ATM
)
564 print_string(PRINT_ANY
, "atm", "%s ", "atm");
565 else if (atm
== CAKE_ATM_PTM
)
566 print_string(PRINT_ANY
, "atm", "%s ", "ptm");
568 print_string(PRINT_ANY
, "atm", "%s ", "noatm");
570 print_int(PRINT_ANY
, "overhead", "overhead %d ", overhead
);
573 print_uint(PRINT_ANY
, "mpu", "mpu %u ", mpu
);
576 print_size(PRINT_ANY
, "memlimit", "memlimit %s ", memlimit
);
579 print_uint(PRINT_FP
, NULL
, "fwmark 0x%x ", fwmark
);
580 print_0xhex(PRINT_JSON
, "fwmark", NULL
, fwmark
);
585 static void cake_print_json_tin(struct rtattr
**tstat
)
587 #define PRINT_TSTAT_JSON(type, name, attr) if (tstat[TCA_CAKE_TIN_STATS_ ## attr]) \
588 print_u64(PRINT_JSON, name, NULL, \
589 rta_getattr_ ## type((struct rtattr *) \
590 tstat[TCA_CAKE_TIN_STATS_ ## attr]))
592 open_json_object(NULL
);
593 PRINT_TSTAT_JSON(u64
, "threshold_rate", THRESHOLD_RATE64
);
594 PRINT_TSTAT_JSON(u64
, "sent_bytes", SENT_BYTES64
);
595 PRINT_TSTAT_JSON(u32
, "backlog_bytes", BACKLOG_BYTES
);
596 PRINT_TSTAT_JSON(u32
, "target_us", TARGET_US
);
597 PRINT_TSTAT_JSON(u32
, "interval_us", INTERVAL_US
);
598 PRINT_TSTAT_JSON(u32
, "peak_delay_us", PEAK_DELAY_US
);
599 PRINT_TSTAT_JSON(u32
, "avg_delay_us", AVG_DELAY_US
);
600 PRINT_TSTAT_JSON(u32
, "base_delay_us", BASE_DELAY_US
);
601 PRINT_TSTAT_JSON(u32
, "sent_packets", SENT_PACKETS
);
602 PRINT_TSTAT_JSON(u32
, "way_indirect_hits", WAY_INDIRECT_HITS
);
603 PRINT_TSTAT_JSON(u32
, "way_misses", WAY_MISSES
);
604 PRINT_TSTAT_JSON(u32
, "way_collisions", WAY_COLLISIONS
);
605 PRINT_TSTAT_JSON(u32
, "drops", DROPPED_PACKETS
);
606 PRINT_TSTAT_JSON(u32
, "ecn_mark", ECN_MARKED_PACKETS
);
607 PRINT_TSTAT_JSON(u32
, "ack_drops", ACKS_DROPPED_PACKETS
);
608 PRINT_TSTAT_JSON(u32
, "sparse_flows", SPARSE_FLOWS
);
609 PRINT_TSTAT_JSON(u32
, "bulk_flows", BULK_FLOWS
);
610 PRINT_TSTAT_JSON(u32
, "unresponsive_flows", UNRESPONSIVE_FLOWS
);
611 PRINT_TSTAT_JSON(u32
, "max_pkt_len", MAX_SKBLEN
);
612 PRINT_TSTAT_JSON(u32
, "flow_quantum", FLOW_QUANTUM
);
615 #undef PRINT_TSTAT_JSON
618 static int cake_print_xstats(struct qdisc_util
*qu
, FILE *f
,
619 struct rtattr
*xstats
)
621 struct rtattr
*st
[TCA_CAKE_STATS_MAX
+ 1];
628 #define GET_STAT_U32(attr) rta_getattr_u32(st[TCA_CAKE_STATS_ ## attr])
629 #define GET_STAT_S32(attr) (*(__s32 *)RTA_DATA(st[TCA_CAKE_STATS_ ## attr]))
630 #define GET_STAT_U64(attr) rta_getattr_u64(st[TCA_CAKE_STATS_ ## attr])
632 parse_rtattr_nested(st
, TCA_CAKE_STATS_MAX
, xstats
);
634 if (st
[TCA_CAKE_STATS_MEMORY_USED
] &&
635 st
[TCA_CAKE_STATS_MEMORY_LIMIT
]) {
636 print_size(PRINT_FP
, NULL
, " memory used: %s",
637 GET_STAT_U32(MEMORY_USED
));
639 print_size(PRINT_FP
, NULL
, " of %s\n",
640 GET_STAT_U32(MEMORY_LIMIT
));
642 print_uint(PRINT_JSON
, "memory_used", NULL
,
643 GET_STAT_U32(MEMORY_USED
));
644 print_uint(PRINT_JSON
, "memory_limit", NULL
,
645 GET_STAT_U32(MEMORY_LIMIT
));
648 if (st
[TCA_CAKE_STATS_CAPACITY_ESTIMATE64
])
649 tc_print_rate(PRINT_ANY
, "capacity_estimate",
650 " capacity estimate: %s\n",
651 GET_STAT_U64(CAPACITY_ESTIMATE64
));
653 if (st
[TCA_CAKE_STATS_MIN_NETLEN
] &&
654 st
[TCA_CAKE_STATS_MAX_NETLEN
]) {
655 print_uint(PRINT_ANY
, "min_network_size",
656 " min/max network layer size: %12u",
657 GET_STAT_U32(MIN_NETLEN
));
658 print_uint(PRINT_ANY
, "max_network_size",
659 " /%8u\n", GET_STAT_U32(MAX_NETLEN
));
662 if (st
[TCA_CAKE_STATS_MIN_ADJLEN
] &&
663 st
[TCA_CAKE_STATS_MAX_ADJLEN
]) {
664 print_uint(PRINT_ANY
, "min_adj_size",
665 " min/max overhead-adjusted size: %8u",
666 GET_STAT_U32(MIN_ADJLEN
));
667 print_uint(PRINT_ANY
, "max_adj_size",
668 " /%8u\n", GET_STAT_U32(MAX_ADJLEN
));
671 if (st
[TCA_CAKE_STATS_AVG_NETOFF
])
672 print_uint(PRINT_ANY
, "avg_hdr_offset",
673 " average network hdr offset: %12u\n\n",
674 GET_STAT_U32(AVG_NETOFF
));
677 if (st
[TCA_CAKE_STATS_DEFICIT
])
678 print_int(PRINT_ANY
, "deficit", " deficit %u",
679 GET_STAT_S32(DEFICIT
));
680 if (st
[TCA_CAKE_STATS_COBALT_COUNT
])
681 print_uint(PRINT_ANY
, "count", " count %u",
682 GET_STAT_U32(COBALT_COUNT
));
684 if (st
[TCA_CAKE_STATS_DROPPING
] && GET_STAT_U32(DROPPING
)) {
685 print_bool(PRINT_ANY
, "dropping", " dropping", true);
686 if (st
[TCA_CAKE_STATS_DROP_NEXT_US
]) {
687 int drop_next
= GET_STAT_S32(DROP_NEXT_US
);
690 print_string(PRINT_FP
, NULL
, " drop_next -%s",
691 sprint_time(drop_next
, b1
));
693 print_uint(PRINT_JSON
, "drop_next", NULL
,
695 print_string(PRINT_FP
, NULL
, " drop_next %s",
696 sprint_time(drop_next
, b1
));
701 if (st
[TCA_CAKE_STATS_P_DROP
]) {
702 print_uint(PRINT_ANY
, "blue_prob", " blue_prob %u",
703 GET_STAT_U32(P_DROP
));
704 if (st
[TCA_CAKE_STATS_BLUE_TIMER_US
]) {
705 int blue_timer
= GET_STAT_S32(BLUE_TIMER_US
);
707 if (blue_timer
< 0) {
708 print_string(PRINT_FP
, NULL
, " blue_timer -%s",
709 sprint_time(blue_timer
, b1
));
711 print_uint(PRINT_JSON
, "blue_timer", NULL
,
713 print_string(PRINT_FP
, NULL
, " blue_timer %s",
714 sprint_time(blue_timer
, b1
));
723 if (st
[TCA_CAKE_STATS_TIN_STATS
]) {
724 struct rtattr
*tstat
[TC_CAKE_MAX_TINS
][TCA_CAKE_TIN_STATS_MAX
+ 1];
725 struct rtattr
*tins
[TC_CAKE_MAX_TINS
+ 1];
728 parse_rtattr_nested(tins
, TC_CAKE_MAX_TINS
,
729 st
[TCA_CAKE_STATS_TIN_STATS
]);
731 for (i
= 1; i
<= TC_CAKE_MAX_TINS
&& tins
[i
]; i
++) {
732 parse_rtattr_nested(tstat
[i
-1], TCA_CAKE_TIN_STATS_MAX
,
740 if (is_json_context()) {
741 open_json_array(PRINT_JSON
, "tins");
742 for (i
= 0; i
< num_tins
; i
++)
743 cake_print_json_tin(tstat
[i
]);
744 close_json_array(PRINT_JSON
, NULL
);
752 fprintf(f
, " Bulk Best Effort Voice\n");
756 fprintf(f
, " Bulk Best Effort Video Voice\n");
761 for (i
= 0; i
< num_tins
; i
++)
762 fprintf(f
, " Tin %u", i
);
763 fprintf(f
, "%s", _SL_
);
766 #define GET_TSTAT(i, attr) (tstat[i][TCA_CAKE_TIN_STATS_ ## attr])
767 #define PRINT_TSTAT(name, attr, fmts, val) do { \
768 if (GET_TSTAT(0, attr)) { \
770 for (i = 0; i < num_tins; i++) \
771 fprintf(f, " %12" fmts, val); \
772 fprintf(f, "%s", _SL_); \
776 #define SPRINT_TSTAT(pfunc, type, name, attr) PRINT_TSTAT( \
777 name, attr, "s", sprint_ ## pfunc( \
778 rta_getattr_ ## type(GET_TSTAT(i, attr)), b1))
780 #define PRINT_TSTAT_U32(name, attr) PRINT_TSTAT( \
781 name, attr, "u", rta_getattr_u32(GET_TSTAT(i, attr)))
783 #define PRINT_TSTAT_U64(name, attr) PRINT_TSTAT( \
784 name, attr, "llu", rta_getattr_u64(GET_TSTAT(i, attr)))
786 if (GET_TSTAT(0, THRESHOLD_RATE64
)) {
787 fprintf(f
, " thresh ");
788 for (i
= 0; i
< num_tins
; i
++)
789 tc_print_rate(PRINT_FP
, NULL
, " %12s",
790 rta_getattr_u64(GET_TSTAT(i
, THRESHOLD_RATE64
)));
791 fprintf(f
, "%s", _SL_
);
794 SPRINT_TSTAT(time
, u32
, " target ", TARGET_US
);
795 SPRINT_TSTAT(time
, u32
, " interval", INTERVAL_US
);
796 SPRINT_TSTAT(time
, u32
, " pk_delay", PEAK_DELAY_US
);
797 SPRINT_TSTAT(time
, u32
, " av_delay", AVG_DELAY_US
);
798 SPRINT_TSTAT(time
, u32
, " sp_delay", BASE_DELAY_US
);
799 SPRINT_TSTAT(size
, u32
, " backlog ", BACKLOG_BYTES
);
801 PRINT_TSTAT_U32(" pkts ", SENT_PACKETS
);
802 PRINT_TSTAT_U64(" bytes ", SENT_BYTES64
);
804 PRINT_TSTAT_U32(" way_inds", WAY_INDIRECT_HITS
);
805 PRINT_TSTAT_U32(" way_miss", WAY_MISSES
);
806 PRINT_TSTAT_U32(" way_cols", WAY_COLLISIONS
);
807 PRINT_TSTAT_U32(" drops ", DROPPED_PACKETS
);
808 PRINT_TSTAT_U32(" marks ", ECN_MARKED_PACKETS
);
809 PRINT_TSTAT_U32(" ack_drop", ACKS_DROPPED_PACKETS
);
810 PRINT_TSTAT_U32(" sp_flows", SPARSE_FLOWS
);
811 PRINT_TSTAT_U32(" bk_flows", BULK_FLOWS
);
812 PRINT_TSTAT_U32(" un_flows", UNRESPONSIVE_FLOWS
);
813 PRINT_TSTAT_U32(" max_len ", MAX_SKBLEN
);
814 PRINT_TSTAT_U32(" quantum ", FLOW_QUANTUM
);
819 #undef PRINT_TSTAT_U32
820 #undef PRINT_TSTAT_U64
825 struct qdisc_util cake_qdisc_util
= {
827 .parse_qopt
= cake_parse_opt
,
828 .print_qopt
= cake_print_opt
,
829 .print_xstats
= cake_print_xstats
,