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 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) {
341 if (get_u32(&fwm
, *argv
, 0)) {
343 "Illegal value for \"fwmark\": \"%s\"\n", *argv
);
347 } else if (strcmp(*argv
, "help") == 0) {
351 fprintf(stderr
, "What is \"%s\"?\n", *argv
);
358 tail
= NLMSG_TAIL(n
);
359 addattr_l(n
, 1024, TCA_OPTIONS
, NULL
, 0);
360 if (bandwidth
|| unlimited
)
361 addattr_l(n
, 1024, TCA_CAKE_BASE_RATE64
, &bandwidth
,
364 addattr_l(n
, 1024, TCA_CAKE_DIFFSERV_MODE
, &diffserv
,
367 addattr_l(n
, 1024, TCA_CAKE_ATM
, &atm
, sizeof(atm
));
369 addattr_l(n
, 1024, TCA_CAKE_FLOW_MODE
, &flowmode
,
372 addattr_l(n
, 1024, TCA_CAKE_OVERHEAD
, &overhead
,
374 if (overhead_override
) {
375 unsigned int zero
= 0;
377 addattr_l(n
, 1024, TCA_CAKE_RAW
, &zero
, sizeof(zero
));
380 addattr_l(n
, 1024, TCA_CAKE_MPU
, &mpu
, sizeof(mpu
));
382 addattr_l(n
, 1024, TCA_CAKE_RTT
, &interval
, sizeof(interval
));
384 addattr_l(n
, 1024, TCA_CAKE_TARGET
, &target
, sizeof(target
));
386 addattr_l(n
, 1024, TCA_CAKE_AUTORATE
, &autorate
,
389 addattr_l(n
, 1024, TCA_CAKE_MEMORY
, &memlimit
,
392 addattr_l(n
, 1024, TCA_CAKE_FWMARK
, &fwmark
,
395 addattr_l(n
, 1024, TCA_CAKE_NAT
, &nat
, sizeof(nat
));
397 addattr_l(n
, 1024, TCA_CAKE_WASH
, &wash
, sizeof(wash
));
399 addattr_l(n
, 1024, TCA_CAKE_SPLIT_GSO
, &split_gso
,
402 addattr_l(n
, 1024, TCA_CAKE_INGRESS
, &ingress
, sizeof(ingress
));
403 if (ack_filter
!= -1)
404 addattr_l(n
, 1024, TCA_CAKE_ACK_FILTER
, &ack_filter
,
407 tail
->rta_len
= (void *) NLMSG_TAIL(n
) - (void *) tail
;
411 static void cake_print_mode(unsigned int value
, unsigned int max
,
412 const char *key
, const char **table
)
414 if (value
< max
&& table
[value
]) {
415 print_string(PRINT_ANY
, key
, "%s ", table
[value
]);
417 print_string(PRINT_JSON
, key
, NULL
, "unknown");
418 print_string(PRINT_FP
, NULL
, "(?%s?)", key
);
422 static int cake_print_opt(struct qdisc_util
*qu
, FILE *f
, struct rtattr
*opt
)
424 struct rtattr
*tb
[TCA_CAKE_MAX
+ 1];
425 unsigned int interval
= 0;
426 unsigned int memlimit
= 0;
427 unsigned int fwmark
= 0;
446 parse_rtattr_nested(tb
, TCA_CAKE_MAX
, opt
);
448 if (tb
[TCA_CAKE_BASE_RATE64
] &&
449 RTA_PAYLOAD(tb
[TCA_CAKE_BASE_RATE64
]) >= sizeof(bandwidth
)) {
450 bandwidth
= rta_getattr_u64(tb
[TCA_CAKE_BASE_RATE64
]);
452 print_uint(PRINT_JSON
, "bandwidth", NULL
, bandwidth
);
453 print_string(PRINT_FP
, NULL
, "bandwidth %s ",
454 sprint_rate(bandwidth
, b1
));
456 print_string(PRINT_ANY
, "bandwidth", "bandwidth %s ",
459 if (tb
[TCA_CAKE_AUTORATE
] &&
460 RTA_PAYLOAD(tb
[TCA_CAKE_AUTORATE
]) >= sizeof(__u32
)) {
461 autorate
= rta_getattr_u32(tb
[TCA_CAKE_AUTORATE
]);
463 print_string(PRINT_ANY
, "autorate", "%s ",
466 print_string(PRINT_ANY
, "autorate", "(?autorate?) ",
469 if (tb
[TCA_CAKE_DIFFSERV_MODE
] &&
470 RTA_PAYLOAD(tb
[TCA_CAKE_DIFFSERV_MODE
]) >= sizeof(__u32
)) {
471 cake_print_mode(rta_getattr_u32(tb
[TCA_CAKE_DIFFSERV_MODE
]),
472 CAKE_DIFFSERV_MAX
, "diffserv", diffserv_names
);
474 if (tb
[TCA_CAKE_FLOW_MODE
] &&
475 RTA_PAYLOAD(tb
[TCA_CAKE_FLOW_MODE
]) >= sizeof(__u32
)) {
476 cake_print_mode(rta_getattr_u32(tb
[TCA_CAKE_FLOW_MODE
]),
477 CAKE_FLOW_MAX
, "flowmode", flowmode_names
);
480 if (tb
[TCA_CAKE_NAT
] &&
481 RTA_PAYLOAD(tb
[TCA_CAKE_NAT
]) >= sizeof(__u32
)) {
482 nat
= rta_getattr_u32(tb
[TCA_CAKE_NAT
]);
486 print_string(PRINT_FP
, NULL
, "nat ", NULL
);
488 print_string(PRINT_FP
, NULL
, "nonat ", NULL
);
489 print_bool(PRINT_JSON
, "nat", NULL
, nat
);
491 if (tb
[TCA_CAKE_WASH
] &&
492 RTA_PAYLOAD(tb
[TCA_CAKE_WASH
]) >= sizeof(__u32
)) {
493 wash
= rta_getattr_u32(tb
[TCA_CAKE_WASH
]);
495 if (tb
[TCA_CAKE_ATM
] &&
496 RTA_PAYLOAD(tb
[TCA_CAKE_ATM
]) >= sizeof(__u32
)) {
497 atm
= rta_getattr_u32(tb
[TCA_CAKE_ATM
]);
499 if (tb
[TCA_CAKE_OVERHEAD
] &&
500 RTA_PAYLOAD(tb
[TCA_CAKE_OVERHEAD
]) >= sizeof(__s32
)) {
501 overhead
= *(__s32
*) RTA_DATA(tb
[TCA_CAKE_OVERHEAD
]);
503 if (tb
[TCA_CAKE_MPU
] &&
504 RTA_PAYLOAD(tb
[TCA_CAKE_MPU
]) >= sizeof(__u32
)) {
505 mpu
= rta_getattr_u32(tb
[TCA_CAKE_MPU
]);
507 if (tb
[TCA_CAKE_INGRESS
] &&
508 RTA_PAYLOAD(tb
[TCA_CAKE_INGRESS
]) >= sizeof(__u32
)) {
509 ingress
= rta_getattr_u32(tb
[TCA_CAKE_INGRESS
]);
511 if (tb
[TCA_CAKE_ACK_FILTER
] &&
512 RTA_PAYLOAD(tb
[TCA_CAKE_ACK_FILTER
]) >= sizeof(__u32
)) {
513 ack_filter
= rta_getattr_u32(tb
[TCA_CAKE_ACK_FILTER
]);
515 if (tb
[TCA_CAKE_SPLIT_GSO
] &&
516 RTA_PAYLOAD(tb
[TCA_CAKE_SPLIT_GSO
]) >= sizeof(__u32
)) {
517 split_gso
= rta_getattr_u32(tb
[TCA_CAKE_SPLIT_GSO
]);
519 if (tb
[TCA_CAKE_RAW
]) {
522 if (tb
[TCA_CAKE_RTT
] &&
523 RTA_PAYLOAD(tb
[TCA_CAKE_RTT
]) >= sizeof(__u32
)) {
524 interval
= rta_getattr_u32(tb
[TCA_CAKE_RTT
]);
526 if (tb
[TCA_CAKE_FWMARK
] &&
527 RTA_PAYLOAD(tb
[TCA_CAKE_FWMARK
]) >= sizeof(__u32
)) {
528 fwmark
= rta_getattr_u32(tb
[TCA_CAKE_FWMARK
]);
532 print_string(PRINT_FP
, NULL
, "wash ", NULL
);
534 print_string(PRINT_FP
, NULL
, "nowash ", NULL
);
535 print_bool(PRINT_JSON
, "wash", NULL
, wash
);
538 print_string(PRINT_FP
, NULL
, "ingress ", NULL
);
539 print_bool(PRINT_JSON
, "ingress", NULL
, ingress
);
541 if (ack_filter
== CAKE_ACK_AGGRESSIVE
)
542 print_string(PRINT_ANY
, "ack-filter", "ack-filter-%s ",
544 else if (ack_filter
== CAKE_ACK_FILTER
)
545 print_string(PRINT_ANY
, "ack-filter", "ack-filter ", "enabled");
547 print_string(PRINT_ANY
, "ack-filter", "no-ack-filter ", "disabled");
550 print_string(PRINT_FP
, NULL
, "split-gso ", NULL
);
552 print_string(PRINT_FP
, NULL
, "no-split-gso ", NULL
);
553 print_bool(PRINT_JSON
, "split_gso", NULL
, split_gso
);
556 print_string(PRINT_FP
, NULL
, "rtt %s ",
557 sprint_time(interval
, b2
));
558 print_uint(PRINT_JSON
, "rtt", NULL
, interval
);
561 print_string(PRINT_FP
, NULL
, "raw ", NULL
);
562 print_bool(PRINT_JSON
, "raw", NULL
, raw
);
564 if (atm
== CAKE_ATM_ATM
)
565 print_string(PRINT_ANY
, "atm", "%s ", "atm");
566 else if (atm
== CAKE_ATM_PTM
)
567 print_string(PRINT_ANY
, "atm", "%s ", "ptm");
569 print_string(PRINT_ANY
, "atm", "%s ", "noatm");
571 print_int(PRINT_ANY
, "overhead", "overhead %d ", overhead
);
574 print_uint(PRINT_ANY
, "mpu", "mpu %u ", mpu
);
577 print_uint(PRINT_JSON
, "memlimit", NULL
, memlimit
);
578 print_string(PRINT_FP
, NULL
, "memlimit %s",
579 sprint_size(memlimit
, b1
));
583 print_uint(PRINT_FP
, NULL
, "fwmark 0x%x ", fwmark
);
584 print_0xhex(PRINT_JSON
, "fwmark", NULL
, fwmark
);
589 static void cake_print_json_tin(struct rtattr
**tstat
)
591 #define PRINT_TSTAT_JSON(type, name, attr) if (tstat[TCA_CAKE_TIN_STATS_ ## attr]) \
592 print_u64(PRINT_JSON, name, NULL, \
593 rta_getattr_ ## type((struct rtattr *) \
594 tstat[TCA_CAKE_TIN_STATS_ ## attr]))
596 open_json_object(NULL
);
597 PRINT_TSTAT_JSON(u64
, "threshold_rate", THRESHOLD_RATE64
);
598 PRINT_TSTAT_JSON(u64
, "sent_bytes", SENT_BYTES64
);
599 PRINT_TSTAT_JSON(u32
, "backlog_bytes", BACKLOG_BYTES
);
600 PRINT_TSTAT_JSON(u32
, "target_us", TARGET_US
);
601 PRINT_TSTAT_JSON(u32
, "interval_us", INTERVAL_US
);
602 PRINT_TSTAT_JSON(u32
, "peak_delay_us", PEAK_DELAY_US
);
603 PRINT_TSTAT_JSON(u32
, "avg_delay_us", AVG_DELAY_US
);
604 PRINT_TSTAT_JSON(u32
, "base_delay_us", BASE_DELAY_US
);
605 PRINT_TSTAT_JSON(u32
, "sent_packets", SENT_PACKETS
);
606 PRINT_TSTAT_JSON(u32
, "way_indirect_hits", WAY_INDIRECT_HITS
);
607 PRINT_TSTAT_JSON(u32
, "way_misses", WAY_MISSES
);
608 PRINT_TSTAT_JSON(u32
, "way_collisions", WAY_COLLISIONS
);
609 PRINT_TSTAT_JSON(u32
, "drops", DROPPED_PACKETS
);
610 PRINT_TSTAT_JSON(u32
, "ecn_mark", ECN_MARKED_PACKETS
);
611 PRINT_TSTAT_JSON(u32
, "ack_drops", ACKS_DROPPED_PACKETS
);
612 PRINT_TSTAT_JSON(u32
, "sparse_flows", SPARSE_FLOWS
);
613 PRINT_TSTAT_JSON(u32
, "bulk_flows", BULK_FLOWS
);
614 PRINT_TSTAT_JSON(u32
, "unresponsive_flows", UNRESPONSIVE_FLOWS
);
615 PRINT_TSTAT_JSON(u32
, "max_pkt_len", MAX_SKBLEN
);
616 PRINT_TSTAT_JSON(u32
, "flow_quantum", FLOW_QUANTUM
);
619 #undef PRINT_TSTAT_JSON
622 static int cake_print_xstats(struct qdisc_util
*qu
, FILE *f
,
623 struct rtattr
*xstats
)
625 struct rtattr
*st
[TCA_CAKE_STATS_MAX
+ 1];
632 #define GET_STAT_U32(attr) rta_getattr_u32(st[TCA_CAKE_STATS_ ## attr])
633 #define GET_STAT_S32(attr) (*(__s32 *)RTA_DATA(st[TCA_CAKE_STATS_ ## attr]))
634 #define GET_STAT_U64(attr) rta_getattr_u64(st[TCA_CAKE_STATS_ ## attr])
636 parse_rtattr_nested(st
, TCA_CAKE_STATS_MAX
, xstats
);
638 if (st
[TCA_CAKE_STATS_MEMORY_USED
] &&
639 st
[TCA_CAKE_STATS_MEMORY_LIMIT
]) {
640 print_string(PRINT_FP
, NULL
, " memory used: %s",
641 sprint_size(GET_STAT_U32(MEMORY_USED
), b1
));
643 print_string(PRINT_FP
, NULL
, " of %s\n",
644 sprint_size(GET_STAT_U32(MEMORY_LIMIT
), b1
));
646 print_uint(PRINT_JSON
, "memory_used", NULL
,
647 GET_STAT_U32(MEMORY_USED
));
648 print_uint(PRINT_JSON
, "memory_limit", NULL
,
649 GET_STAT_U32(MEMORY_LIMIT
));
652 if (st
[TCA_CAKE_STATS_CAPACITY_ESTIMATE64
]) {
653 print_string(PRINT_FP
, NULL
, " capacity estimate: %s\n",
654 sprint_rate(GET_STAT_U64(CAPACITY_ESTIMATE64
), b1
));
655 print_uint(PRINT_JSON
, "capacity_estimate", NULL
,
656 GET_STAT_U64(CAPACITY_ESTIMATE64
));
659 if (st
[TCA_CAKE_STATS_MIN_NETLEN
] &&
660 st
[TCA_CAKE_STATS_MAX_NETLEN
]) {
661 print_uint(PRINT_ANY
, "min_network_size",
662 " min/max network layer size: %12u",
663 GET_STAT_U32(MIN_NETLEN
));
664 print_uint(PRINT_ANY
, "max_network_size",
665 " /%8u\n", GET_STAT_U32(MAX_NETLEN
));
668 if (st
[TCA_CAKE_STATS_MIN_ADJLEN
] &&
669 st
[TCA_CAKE_STATS_MAX_ADJLEN
]) {
670 print_uint(PRINT_ANY
, "min_adj_size",
671 " min/max overhead-adjusted size: %8u",
672 GET_STAT_U32(MIN_ADJLEN
));
673 print_uint(PRINT_ANY
, "max_adj_size",
674 " /%8u\n", GET_STAT_U32(MAX_ADJLEN
));
677 if (st
[TCA_CAKE_STATS_AVG_NETOFF
])
678 print_uint(PRINT_ANY
, "avg_hdr_offset",
679 " average network hdr offset: %12u\n\n",
680 GET_STAT_U32(AVG_NETOFF
));
683 if (st
[TCA_CAKE_STATS_DEFICIT
])
684 print_int(PRINT_ANY
, "deficit", " deficit %u",
685 GET_STAT_S32(DEFICIT
));
686 if (st
[TCA_CAKE_STATS_COBALT_COUNT
])
687 print_uint(PRINT_ANY
, "count", " count %u",
688 GET_STAT_U32(COBALT_COUNT
));
690 if (st
[TCA_CAKE_STATS_DROPPING
] && GET_STAT_U32(DROPPING
)) {
691 print_bool(PRINT_ANY
, "dropping", " dropping", true);
692 if (st
[TCA_CAKE_STATS_DROP_NEXT_US
]) {
693 int drop_next
= GET_STAT_S32(DROP_NEXT_US
);
696 print_string(PRINT_FP
, NULL
, " drop_next -%s",
697 sprint_time(drop_next
, b1
));
699 print_uint(PRINT_JSON
, "drop_next", NULL
,
701 print_string(PRINT_FP
, NULL
, " drop_next %s",
702 sprint_time(drop_next
, b1
));
707 if (st
[TCA_CAKE_STATS_P_DROP
]) {
708 print_uint(PRINT_ANY
, "blue_prob", " blue_prob %u",
709 GET_STAT_U32(P_DROP
));
710 if (st
[TCA_CAKE_STATS_BLUE_TIMER_US
]) {
711 int blue_timer
= GET_STAT_S32(BLUE_TIMER_US
);
713 if (blue_timer
< 0) {
714 print_string(PRINT_FP
, NULL
, " blue_timer -%s",
715 sprint_time(blue_timer
, b1
));
717 print_uint(PRINT_JSON
, "blue_timer", NULL
,
719 print_string(PRINT_FP
, NULL
, " blue_timer %s",
720 sprint_time(blue_timer
, b1
));
729 if (st
[TCA_CAKE_STATS_TIN_STATS
]) {
730 struct rtattr
*tstat
[TC_CAKE_MAX_TINS
][TCA_CAKE_TIN_STATS_MAX
+ 1];
731 struct rtattr
*tins
[TC_CAKE_MAX_TINS
+ 1];
734 parse_rtattr_nested(tins
, TC_CAKE_MAX_TINS
,
735 st
[TCA_CAKE_STATS_TIN_STATS
]);
737 for (i
= 1; i
<= TC_CAKE_MAX_TINS
&& tins
[i
]; i
++) {
738 parse_rtattr_nested(tstat
[i
-1], TCA_CAKE_TIN_STATS_MAX
,
746 if (is_json_context()) {
747 open_json_array(PRINT_JSON
, "tins");
748 for (i
= 0; i
< num_tins
; i
++)
749 cake_print_json_tin(tstat
[i
]);
750 close_json_array(PRINT_JSON
, NULL
);
758 fprintf(f
, " Bulk Best Effort Voice\n");
762 fprintf(f
, " Bulk Best Effort Video Voice\n");
767 for (i
= 0; i
< num_tins
; i
++)
768 fprintf(f
, " Tin %u", i
);
772 #define GET_TSTAT(i, attr) (tstat[i][TCA_CAKE_TIN_STATS_ ## attr])
773 #define PRINT_TSTAT(name, attr, fmts, val) do { \
774 if (GET_TSTAT(0, attr)) { \
776 for (i = 0; i < num_tins; i++) \
777 fprintf(f, " %12" fmts, val); \
782 #define SPRINT_TSTAT(pfunc, type, name, attr) PRINT_TSTAT( \
783 name, attr, "s", sprint_ ## pfunc( \
784 rta_getattr_ ## type(GET_TSTAT(i, attr)), b1))
786 #define PRINT_TSTAT_U32(name, attr) PRINT_TSTAT( \
787 name, attr, "u", rta_getattr_u32(GET_TSTAT(i, attr)))
789 #define PRINT_TSTAT_U64(name, attr) PRINT_TSTAT( \
790 name, attr, "llu", rta_getattr_u64(GET_TSTAT(i, attr)))
792 SPRINT_TSTAT(rate
, u64
, " thresh ", THRESHOLD_RATE64
);
793 SPRINT_TSTAT(time
, u32
, " target ", TARGET_US
);
794 SPRINT_TSTAT(time
, u32
, " interval", INTERVAL_US
);
795 SPRINT_TSTAT(time
, u32
, " pk_delay", PEAK_DELAY_US
);
796 SPRINT_TSTAT(time
, u32
, " av_delay", AVG_DELAY_US
);
797 SPRINT_TSTAT(time
, u32
, " sp_delay", BASE_DELAY_US
);
798 SPRINT_TSTAT(size
, u32
, " backlog ", BACKLOG_BYTES
);
800 PRINT_TSTAT_U32(" pkts ", SENT_PACKETS
);
801 PRINT_TSTAT_U64(" bytes ", SENT_BYTES64
);
803 PRINT_TSTAT_U32(" way_inds", WAY_INDIRECT_HITS
);
804 PRINT_TSTAT_U32(" way_miss", WAY_MISSES
);
805 PRINT_TSTAT_U32(" way_cols", WAY_COLLISIONS
);
806 PRINT_TSTAT_U32(" drops ", DROPPED_PACKETS
);
807 PRINT_TSTAT_U32(" marks ", ECN_MARKED_PACKETS
);
808 PRINT_TSTAT_U32(" ack_drop", ACKS_DROPPED_PACKETS
);
809 PRINT_TSTAT_U32(" sp_flows", SPARSE_FLOWS
);
810 PRINT_TSTAT_U32(" bk_flows", BULK_FLOWS
);
811 PRINT_TSTAT_U32(" un_flows", UNRESPONSIVE_FLOWS
);
812 PRINT_TSTAT_U32(" max_len ", MAX_SKBLEN
);
813 PRINT_TSTAT_U32(" quantum ", FLOW_QUANTUM
);
818 #undef PRINT_TSTAT_U32
819 #undef PRINT_TSTAT_U64
824 struct qdisc_util cake_qdisc_util
= {
826 .parse_qopt
= cake_parse_opt
,
827 .print_qopt
= cake_print_opt
,
828 .print_xstats
= cake_print_xstats
,