Fix build break in 64bit architectures
[platform/upstream/iproute2.git] / tc / q_cake.c
1 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
2
3 /*
4  * Common Applications Kept Enhanced  --  CAKE
5  *
6  *  Copyright (C) 2014-2018 Jonathan Morton <chromatix99@gmail.com>
7  *  Copyright (C) 2017-2018 Toke Høiland-Jørgensen <toke@toke.dk>
8  */
9
10 #include <stddef.h>
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <unistd.h>
14 #include <syslog.h>
15 #include <fcntl.h>
16 #include <sys/socket.h>
17 #include <netinet/in.h>
18 #include <arpa/inet.h>
19 #include <string.h>
20 #include <inttypes.h>
21
22 #include "utils.h"
23 #include "tc_util.h"
24
25 struct cake_preset {
26         char *name;
27         unsigned int target;
28         unsigned int interval;
29 };
30
31 static struct cake_preset presets[] = {
32         {"datacentre",          5,              100},
33         {"lan",                 50,             1000},
34         {"metro",               500,            10000},
35         {"regional",            1500,           30000},
36         {"internet",            5000,           100000},
37         {"oceanic",             15000,          300000},
38         {"satellite",           50000,          1000000},
39         {"interplanetary",      50000000,       1000000000},
40 };
41
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",
48 };
49
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",
59 };
60
61 static struct cake_preset *find_preset(char *argv)
62 {
63         int i;
64
65         for (i = 0; i < ARRAY_SIZE(presets); i++)
66                 if (!strcmp(argv, presets[i].name))
67                         return &presets[i];
68         return NULL;
69 }
70
71 static void explain(void)
72 {
73         fprintf(stderr,
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"
80                 "                [ nat | nonat* ]\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                 "                [ fwmark MASK ]\n"
86                 "                [ ptm | atm | noatm* ] [ overhead N | conservative | raw* ]\n"
87                 "                [ mpu N ] [ ingress | egress* ]\n"
88                 "                (* marks defaults)\n");
89 }
90
91 static int cake_parse_opt(struct qdisc_util *qu, int argc, char **argv,
92                           struct nlmsghdr *n, const char *dev)
93 {
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;
101         __u64 bandwidth = 0;
102         int ack_filter = -1;
103         struct rtattr *tail;
104         int split_gso = -1;
105         int unlimited = 0;
106         int flowmode = -1;
107         int autorate = -1;
108         int ingress = -1;
109         int overhead = 0;
110         int fwmark = -1;
111         int wash = -1;
112         int nat = -1;
113         int atm = -1;
114         int mpu = 0;
115
116         while (argc > 0) {
117                 if (strcmp(*argv, "bandwidth") == 0) {
118                         NEXT_ARG();
119                         if (get_rate64(&bandwidth, *argv)) {
120                                 fprintf(stderr, "Illegal \"bandwidth\"\n");
121                                 return -1;
122                         }
123                         unlimited = 0;
124                         autorate = 0;
125                 } else if (strcmp(*argv, "unlimited") == 0) {
126                         bandwidth = 0;
127                         unlimited = 1;
128                         autorate = 0;
129                 } else if (strcmp(*argv, "autorate-ingress") == 0) {
130                         autorate = 1;
131                 } else if (strcmp(*argv, "rtt") == 0) {
132                         NEXT_ARG();
133                         if (get_time(&interval, *argv)) {
134                                 fprintf(stderr, "Illegal \"rtt\"\n");
135                                 return -1;
136                         }
137                         target = interval / 20;
138                         if (!target)
139                                 target = 1;
140                 } else if ((preset = find_preset(*argv))) {
141                         if (preset_set)
142                                 duparg(*argv, preset_set->name);
143                         preset_set = preset;
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) {
159                         wash = 0;
160                 } else if (strcmp(*argv, "wash") == 0) {
161                         wash = 1;
162                 } else if (strcmp(*argv, "split-gso") == 0) {
163                         split_gso = 1;
164                 } else if (strcmp(*argv, "no-split-gso") == 0) {
165                         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) {
183                         nat = 1;
184                 } else if (strcmp(*argv, "nonat") == 0) {
185                         nat = 0;
186                 } else if (strcmp(*argv, "ptm") == 0) {
187                         atm = CAKE_ATM_PTM;
188                 } else if (strcmp(*argv, "atm") == 0) {
189                         atm = CAKE_ATM_ATM;
190                 } else if (strcmp(*argv, "noatm") == 0) {
191                         atm = CAKE_ATM_NONE;
192                 } else if (strcmp(*argv, "raw") == 0) {
193                         atm = CAKE_ATM_NONE;
194                         overhead = 0;
195                         overhead_set = true;
196                         overhead_override = true;
197                 } else if (strcmp(*argv, "conservative") == 0) {
198                         /*
199                          * Deliberately over-estimate overhead:
200                          * one whole ATM cell plus ATM framing.
201                          * A safe choice if the actual overhead is unknown.
202                          */
203                         atm = CAKE_ATM_ATM;
204                         overhead = 48;
205                         overhead_set = true;
206
207                 /* Various ADSL framing schemes, all over ATM cells */
208                 } else if (strcmp(*argv, "ipoa-vcmux") == 0) {
209                         atm = CAKE_ATM_ATM;
210                         overhead += 8;
211                         overhead_set = true;
212                 } else if (strcmp(*argv, "ipoa-llcsnap") == 0) {
213                         atm = CAKE_ATM_ATM;
214                         overhead += 16;
215                         overhead_set = true;
216                 } else if (strcmp(*argv, "bridged-vcmux") == 0) {
217                         atm = CAKE_ATM_ATM;
218                         overhead += 24;
219                         overhead_set = true;
220                 } else if (strcmp(*argv, "bridged-llcsnap") == 0) {
221                         atm = CAKE_ATM_ATM;
222                         overhead += 32;
223                         overhead_set = true;
224                 } else if (strcmp(*argv, "pppoa-vcmux") == 0) {
225                         atm = CAKE_ATM_ATM;
226                         overhead += 10;
227                         overhead_set = true;
228                 } else if (strcmp(*argv, "pppoa-llc") == 0) {
229                         atm = CAKE_ATM_ATM;
230                         overhead += 14;
231                         overhead_set = true;
232                 } else if (strcmp(*argv, "pppoe-vcmux") == 0) {
233                         atm = CAKE_ATM_ATM;
234                         overhead += 32;
235                         overhead_set = true;
236                 } else if (strcmp(*argv, "pppoe-llcsnap") == 0) {
237                         atm = CAKE_ATM_ATM;
238                         overhead += 40;
239                         overhead_set = true;
240
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
248                          */
249                         atm = CAKE_ATM_PTM;
250                         overhead += 30;
251                         overhead_set = true;
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
257                          */
258                         atm = CAKE_ATM_PTM;
259                         overhead += 22;
260                         overhead_set = true;
261                 } else if (strcmp(*argv, "via-ethernet") == 0) {
262                         /*
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.
266                          *
267                          * It is no longer needed, because Cake now adjusts for
268                          * that automatically, and is thus ignored.
269                          *
270                          * It would be deleted entirely, but it appears in the
271                          * stats output when the automatic compensation is
272                          * active.
273                          */
274                 } else if (strcmp(*argv, "ethernet") == 0) {
275                         /* ethernet pre-amble & interframe gap & FCS
276                          * you may need to add vlan tag
277                          */
278                         overhead += 38;
279                         overhead_set = true;
280                         mpu = 84;
281
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 */
285                         overhead += 4;
286                         overhead_set = true;
287
288                 /*
289                  * DOCSIS cable shapers account for Ethernet frame with FCS,
290                  * but not interframe gap or preamble.
291                  */
292                 } else if (strcmp(*argv, "docsis") == 0) {
293                         atm = CAKE_ATM_NONE;
294                         overhead += 18;
295                         overhead_set = true;
296                         mpu = 64;
297                 } else if (strcmp(*argv, "overhead") == 0) {
298                         char *p = NULL;
299
300                         NEXT_ARG();
301                         overhead = strtol(*argv, &p, 10);
302                         if (!p || *p || !*argv ||
303                             overhead < -64 || overhead > 256) {
304                                 fprintf(stderr,
305                                         "Illegal \"overhead\", valid range is -64 to 256\\n");
306                                 return -1;
307                         }
308                         overhead_set = true;
309
310                 } else if (strcmp(*argv, "mpu") == 0) {
311                         char *p = NULL;
312
313                         NEXT_ARG();
314                         mpu = strtol(*argv, &p, 10);
315                         if (!p || *p || !*argv || mpu < 0 || mpu > 256) {
316                                 fprintf(stderr,
317                                         "Illegal \"mpu\", valid range is 0 to 256\\n");
318                                 return -1;
319                         }
320                 } else if (strcmp(*argv, "ingress") == 0) {
321                         ingress = 1;
322                 } else if (strcmp(*argv, "egress") == 0) {
323                         ingress = 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) {
331                         NEXT_ARG();
332                         if (get_size(&memlimit, *argv)) {
333                                 fprintf(stderr,
334                                         "Illegal value for \"memlimit\": \"%s\"\n", *argv);
335                                 return -1;
336                         }
337                 } else if (strcmp(*argv, "fwmark") == 0) {
338                         unsigned int fwm;
339
340                         NEXT_ARG();
341                         if (get_u32(&fwm, *argv, 0)) {
342                                 fprintf(stderr,
343                                         "Illegal value for \"fwmark\": \"%s\"\n", *argv);
344                                 return -1;
345                         }
346                         fwmark = fwm;
347                 } else if (strcmp(*argv, "help") == 0) {
348                         explain();
349                         return -1;
350                 } else {
351                         fprintf(stderr, "What is \"%s\"?\n", *argv);
352                         explain();
353                         return -1;
354                 }
355                 argc--; argv++;
356         }
357
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,
362                           sizeof(bandwidth));
363         if (diffserv)
364                 addattr_l(n, 1024, TCA_CAKE_DIFFSERV_MODE, &diffserv,
365                           sizeof(diffserv));
366         if (atm != -1)
367                 addattr_l(n, 1024, TCA_CAKE_ATM, &atm, sizeof(atm));
368         if (flowmode != -1)
369                 addattr_l(n, 1024, TCA_CAKE_FLOW_MODE, &flowmode,
370                           sizeof(flowmode));
371         if (overhead_set)
372                 addattr_l(n, 1024, TCA_CAKE_OVERHEAD, &overhead,
373                           sizeof(overhead));
374         if (overhead_override) {
375                 unsigned int zero = 0;
376
377                 addattr_l(n, 1024, TCA_CAKE_RAW, &zero, sizeof(zero));
378         }
379         if (mpu > 0)
380                 addattr_l(n, 1024, TCA_CAKE_MPU, &mpu, sizeof(mpu));
381         if (interval)
382                 addattr_l(n, 1024, TCA_CAKE_RTT, &interval, sizeof(interval));
383         if (target)
384                 addattr_l(n, 1024, TCA_CAKE_TARGET, &target, sizeof(target));
385         if (autorate != -1)
386                 addattr_l(n, 1024, TCA_CAKE_AUTORATE, &autorate,
387                           sizeof(autorate));
388         if (memlimit)
389                 addattr_l(n, 1024, TCA_CAKE_MEMORY, &memlimit,
390                           sizeof(memlimit));
391         if (fwmark != -1)
392                 addattr_l(n, 1024, TCA_CAKE_FWMARK, &fwmark,
393                           sizeof(fwmark));
394         if (nat != -1)
395                 addattr_l(n, 1024, TCA_CAKE_NAT, &nat, sizeof(nat));
396         if (wash != -1)
397                 addattr_l(n, 1024, TCA_CAKE_WASH, &wash, sizeof(wash));
398         if (split_gso != -1)
399                 addattr_l(n, 1024, TCA_CAKE_SPLIT_GSO, &split_gso,
400                           sizeof(split_gso));
401         if (ingress != -1)
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,
405                           sizeof(ack_filter));
406
407         tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail;
408         return 0;
409 }
410
411 static void cake_print_mode(unsigned int value, unsigned int max,
412                             const char *key, const char **table)
413 {
414         if (value < max && table[value]) {
415                 print_string(PRINT_ANY, key, "%s ", table[value]);
416         } else {
417                 print_string(PRINT_JSON, key, NULL, "unknown");
418                 print_string(PRINT_FP, NULL, "(?%s?)", key);
419         }
420 }
421
422 static int cake_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
423 {
424         struct rtattr *tb[TCA_CAKE_MAX + 1];
425         unsigned int interval = 0;
426         unsigned int memlimit = 0;
427         unsigned int fwmark = 0;
428         __u64 bandwidth = 0;
429         int ack_filter = 0;
430         int split_gso = 0;
431         int overhead = 0;
432         int autorate = 0;
433         int ingress = 0;
434         int wash = 0;
435         int raw = 0;
436         int mpu = 0;
437         int atm = 0;
438         int nat = 0;
439
440         SPRINT_BUF(b1);
441         SPRINT_BUF(b2);
442
443         if (opt == NULL)
444                 return 0;
445
446         parse_rtattr_nested(tb, TCA_CAKE_MAX, opt);
447
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]);
451                 if (bandwidth) {
452                         print_uint(PRINT_JSON, "bandwidth", NULL, bandwidth);
453                         print_string(PRINT_FP, NULL, "bandwidth %s ",
454                                      sprint_rate(bandwidth, b1));
455                 } else
456                         print_string(PRINT_ANY, "bandwidth", "bandwidth %s ",
457                                      "unlimited");
458         }
459         if (tb[TCA_CAKE_AUTORATE] &&
460                 RTA_PAYLOAD(tb[TCA_CAKE_AUTORATE]) >= sizeof(__u32)) {
461                 autorate = rta_getattr_u32(tb[TCA_CAKE_AUTORATE]);
462                 if (autorate == 1)
463                         print_string(PRINT_ANY, "autorate", "%s ",
464                                      "autorate-ingress");
465                 else if (autorate)
466                         print_string(PRINT_ANY, "autorate", "(?autorate?) ",
467                                      "unknown");
468         }
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);
473         }
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);
478         }
479
480         if (tb[TCA_CAKE_NAT] &&
481             RTA_PAYLOAD(tb[TCA_CAKE_NAT]) >= sizeof(__u32)) {
482                 nat = rta_getattr_u32(tb[TCA_CAKE_NAT]);
483         }
484
485         if (nat)
486                 print_string(PRINT_FP, NULL, "nat ", NULL);
487         else
488                 print_string(PRINT_FP, NULL, "nonat ", NULL);
489         print_bool(PRINT_JSON, "nat", NULL, nat);
490
491         if (tb[TCA_CAKE_WASH] &&
492             RTA_PAYLOAD(tb[TCA_CAKE_WASH]) >= sizeof(__u32)) {
493                 wash = rta_getattr_u32(tb[TCA_CAKE_WASH]);
494         }
495         if (tb[TCA_CAKE_ATM] &&
496             RTA_PAYLOAD(tb[TCA_CAKE_ATM]) >= sizeof(__u32)) {
497                 atm = rta_getattr_u32(tb[TCA_CAKE_ATM]);
498         }
499         if (tb[TCA_CAKE_OVERHEAD] &&
500             RTA_PAYLOAD(tb[TCA_CAKE_OVERHEAD]) >= sizeof(__s32)) {
501                 overhead = *(__s32 *) RTA_DATA(tb[TCA_CAKE_OVERHEAD]);
502         }
503         if (tb[TCA_CAKE_MPU] &&
504             RTA_PAYLOAD(tb[TCA_CAKE_MPU]) >= sizeof(__u32)) {
505                 mpu = rta_getattr_u32(tb[TCA_CAKE_MPU]);
506         }
507         if (tb[TCA_CAKE_INGRESS] &&
508             RTA_PAYLOAD(tb[TCA_CAKE_INGRESS]) >= sizeof(__u32)) {
509                 ingress = rta_getattr_u32(tb[TCA_CAKE_INGRESS]);
510         }
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]);
514         }
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]);
518         }
519         if (tb[TCA_CAKE_RAW]) {
520                 raw = 1;
521         }
522         if (tb[TCA_CAKE_RTT] &&
523             RTA_PAYLOAD(tb[TCA_CAKE_RTT]) >= sizeof(__u32)) {
524                 interval = rta_getattr_u32(tb[TCA_CAKE_RTT]);
525         }
526         if (tb[TCA_CAKE_FWMARK] &&
527             RTA_PAYLOAD(tb[TCA_CAKE_FWMARK]) >= sizeof(__u32)) {
528                 fwmark = rta_getattr_u32(tb[TCA_CAKE_FWMARK]);
529         }
530
531         if (wash)
532                 print_string(PRINT_FP, NULL, "wash ", NULL);
533         else
534                 print_string(PRINT_FP, NULL, "nowash ", NULL);
535         print_bool(PRINT_JSON, "wash", NULL, wash);
536
537         if (ingress)
538                 print_string(PRINT_FP, NULL, "ingress ", NULL);
539         print_bool(PRINT_JSON, "ingress", NULL, ingress);
540
541         if (ack_filter == CAKE_ACK_AGGRESSIVE)
542                 print_string(PRINT_ANY, "ack-filter", "ack-filter-%s ",
543                              "aggressive");
544         else if (ack_filter == CAKE_ACK_FILTER)
545                 print_string(PRINT_ANY, "ack-filter", "ack-filter ", "enabled");
546         else
547                 print_string(PRINT_ANY, "ack-filter", "no-ack-filter ", "disabled");
548
549         if (split_gso)
550                 print_string(PRINT_FP, NULL, "split-gso ", NULL);
551         else
552                 print_string(PRINT_FP, NULL, "no-split-gso ", NULL);
553         print_bool(PRINT_JSON, "split_gso", NULL, split_gso);
554
555         if (interval)
556                 print_string(PRINT_FP, NULL, "rtt %s ",
557                              sprint_time(interval, b2));
558         print_uint(PRINT_JSON, "rtt", NULL, interval);
559
560         if (raw)
561                 print_string(PRINT_FP, NULL, "raw ", NULL);
562         print_bool(PRINT_JSON, "raw", NULL, raw);
563
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");
568         else if (!raw)
569                 print_string(PRINT_ANY, "atm", "%s ", "noatm");
570
571         print_int(PRINT_ANY, "overhead", "overhead %d ", overhead);
572
573         if (mpu)
574                 print_uint(PRINT_ANY, "mpu", "mpu %u ", mpu);
575
576         if (memlimit) {
577                 print_uint(PRINT_JSON, "memlimit", NULL, memlimit);
578                 print_string(PRINT_FP, NULL, "memlimit %s",
579                              sprint_size(memlimit, b1));
580         }
581
582         if (fwmark)
583                 print_uint(PRINT_FP, NULL, "fwmark 0x%x ", fwmark);
584         print_0xhex(PRINT_JSON, "fwmark", NULL, fwmark);
585
586         return 0;
587 }
588
589 static void cake_print_json_tin(struct rtattr **tstat)
590 {
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]))
595
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);
617         close_json_object();
618
619 #undef PRINT_TSTAT_JSON
620 }
621
622 static int cake_print_xstats(struct qdisc_util *qu, FILE *f,
623                              struct rtattr *xstats)
624 {
625         struct rtattr *st[TCA_CAKE_STATS_MAX + 1];
626         SPRINT_BUF(b1);
627         int i;
628
629         if (xstats == NULL)
630                 return 0;
631
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])
635
636         parse_rtattr_nested(st, TCA_CAKE_STATS_MAX, xstats);
637
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));
642
643                 print_string(PRINT_FP, NULL, " of %s\n",
644                         sprint_size(GET_STAT_U32(MEMORY_LIMIT), b1));
645
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));
650         }
651
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));
657         }
658
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));
666         }
667
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));
675         }
676
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));
681
682         /* class stats */
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));
689
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);
694
695                         if (drop_next < 0) {
696                                 print_string(PRINT_FP, NULL, " drop_next -%s",
697                                         sprint_time(drop_next, b1));
698                         } else {
699                                 print_uint(PRINT_JSON, "drop_next", NULL,
700                                         drop_next);
701                                 print_string(PRINT_FP, NULL, " drop_next %s",
702                                         sprint_time(drop_next, b1));
703                         }
704                 }
705         }
706
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);
712
713                         if (blue_timer < 0) {
714                                 print_string(PRINT_FP, NULL, " blue_timer -%s",
715                                         sprint_time(blue_timer, b1));
716                         } else {
717                                 print_uint(PRINT_JSON, "blue_timer", NULL,
718                                         blue_timer);
719                                 print_string(PRINT_FP, NULL, " blue_timer %s",
720                                         sprint_time(blue_timer, b1));
721                         }
722                 }
723         }
724
725 #undef GET_STAT_U32
726 #undef GET_STAT_S32
727 #undef GET_STAT_U64
728
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];
732                 int num_tins = 0;
733
734                 parse_rtattr_nested(tins, TC_CAKE_MAX_TINS,
735                                     st[TCA_CAKE_STATS_TIN_STATS]);
736
737                 for (i = 1; i <= TC_CAKE_MAX_TINS && tins[i]; i++) {
738                         parse_rtattr_nested(tstat[i-1], TCA_CAKE_TIN_STATS_MAX,
739                                             tins[i]);
740                         num_tins++;
741                 }
742
743                 if (!num_tins)
744                         return 0;
745
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);
751
752                         return 0;
753                 }
754
755
756                 switch (num_tins) {
757                 case 3:
758                         fprintf(f, "                   Bulk  Best Effort        Voice\n");
759                         break;
760
761                 case 4:
762                         fprintf(f, "                   Bulk  Best Effort        Video        Voice\n");
763                         break;
764
765                 default:
766                         fprintf(f, "          ");
767                         for (i = 0; i < num_tins; i++)
768                                 fprintf(f, "        Tin %u", i);
769                         fprintf(f, "\n");
770                 };
771
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)) {               \
775                                 fprintf(f, name);               \
776                                 for (i = 0; i < num_tins; i++)  \
777                                         fprintf(f, " %12" fmts, val);   \
778                                 fprintf(f, "\n");                       \
779                         }                                               \
780                 } while (0)
781
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))
785
786 #define PRINT_TSTAT_U32(name, attr)     PRINT_TSTAT(                    \
787                         name, attr, "u", rta_getattr_u32(GET_TSTAT(i, attr)))
788
789 #define PRINT_TSTAT_U64(name, attr)     PRINT_TSTAT(                    \
790                         name, attr, "llu", rta_getattr_u64(GET_TSTAT(i, attr)))
791
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);
799
800                 PRINT_TSTAT_U32("  pkts    ", SENT_PACKETS);
801                 PRINT_TSTAT_U64("  bytes   ", SENT_BYTES64);
802
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);
814
815 #undef GET_STAT
816 #undef PRINT_TSTAT
817 #undef SPRINT_TSTAT
818 #undef PRINT_TSTAT_U32
819 #undef PRINT_TSTAT_U64
820         }
821         return 0;
822 }
823
824 struct qdisc_util cake_qdisc_util = {
825         .id             = "cake",
826         .parse_qopt     = cake_parse_opt,
827         .print_qopt     = cake_print_opt,
828         .print_xstats   = cake_print_xstats,
829 };