950-add-cake-to-tc.patch 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850
  1. --- a/include/linux/pkt_sched.h
  2. +++ b/include/linux/pkt_sched.h
  3. @@ -850,4 +850,63 @@ struct tc_pie_xstats {
  4. __u32 maxq; /* maximum queue size */
  5. __u32 ecn_mark; /* packets marked with ecn*/
  6. };
  7. +
  8. +/* CAKE */
  9. +enum {
  10. + TCA_CAKE_UNSPEC,
  11. + TCA_CAKE_BASE_RATE,
  12. + TCA_CAKE_DIFFSERV_MODE,
  13. + TCA_CAKE_ATM,
  14. + TCA_CAKE_FLOW_MODE,
  15. + TCA_CAKE_OVERHEAD,
  16. + TCA_CAKE_RTT,
  17. + TCA_CAKE_TARGET,
  18. + TCA_CAKE_AUTORATE,
  19. + TCA_CAKE_MEMORY,
  20. + TCA_CAKE_NAT,
  21. + TCA_CAKE_ETHERNET,
  22. + TCA_CAKE_WASH,
  23. + TCA_CAKE_MPU,
  24. + TCA_CAKE_INGRESS,
  25. + TCA_CAKE_ACK_FILTER,
  26. + __TCA_CAKE_MAX
  27. +};
  28. +#define TCA_CAKE_MAX (__TCA_CAKE_MAX - 1)
  29. +
  30. +struct tc_cake_traffic_stats {
  31. + __u32 packets;
  32. + __u32 link_ms;
  33. + __u64 bytes;
  34. +};
  35. +
  36. +#define TC_CAKE_MAX_TINS (8)
  37. +struct tc_cake_xstats {
  38. + __u16 version; /* == 5, increments when struct extended */
  39. + __u8 max_tins; /* == TC_CAKE_MAX_TINS */
  40. + __u8 tin_cnt; /* <= TC_CAKE_MAX_TINS */
  41. +
  42. + __u32 threshold_rate [TC_CAKE_MAX_TINS];
  43. + __u32 target_us [TC_CAKE_MAX_TINS];
  44. + struct tc_cake_traffic_stats sent [TC_CAKE_MAX_TINS];
  45. + struct tc_cake_traffic_stats dropped [TC_CAKE_MAX_TINS];
  46. + struct tc_cake_traffic_stats ecn_marked[TC_CAKE_MAX_TINS];
  47. + struct tc_cake_traffic_stats backlog [TC_CAKE_MAX_TINS];
  48. + __u32 interval_us [TC_CAKE_MAX_TINS];
  49. + __u32 way_indirect_hits[TC_CAKE_MAX_TINS];
  50. + __u32 way_misses [TC_CAKE_MAX_TINS];
  51. + __u32 way_collisions [TC_CAKE_MAX_TINS];
  52. + __u32 peak_delay_us [TC_CAKE_MAX_TINS]; /* ~= bulk flow delay */
  53. + __u32 avge_delay_us [TC_CAKE_MAX_TINS];
  54. + __u32 base_delay_us [TC_CAKE_MAX_TINS]; /* ~= sparse flows delay */
  55. + __u16 sparse_flows [TC_CAKE_MAX_TINS];
  56. + __u16 bulk_flows [TC_CAKE_MAX_TINS];
  57. + __u16 unresponse_flows [TC_CAKE_MAX_TINS]; /* v4 - was u32 last_len */
  58. + __u16 spare [TC_CAKE_MAX_TINS]; /* v4 - split last_len */
  59. + __u32 max_skblen [TC_CAKE_MAX_TINS];
  60. + __u32 capacity_estimate; /* version 2 */
  61. + __u32 memory_limit; /* version 3 */
  62. + __u32 memory_used; /* version 3 */
  63. + struct tc_cake_traffic_stats ack_drops [TC_CAKE_MAX_TINS]; /* v5 */
  64. +};
  65. +
  66. #endif
  67. --- a/tc/Makefile
  68. +++ b/tc/Makefile
  69. @@ -63,6 +63,7 @@ TCMODULES += q_codel.o
  70. TCMODULES += q_fq_codel.o
  71. TCMODULES += q_fq.o
  72. TCMODULES += q_pie.o
  73. +TCMODULES += q_cake.o
  74. TCMODULES += q_hhf.o
  75. TCMODULES += e_bpf.o
  76. --- /dev/null
  77. +++ b/tc/q_cake.c
  78. @@ -0,0 +1,771 @@
  79. +/*
  80. + * Common Applications Kept Enhanced -- CAKE
  81. + *
  82. + * Copyright (C) 2014-2015 Jonathan Morton <chromatix99@gmail.com>
  83. + *
  84. + * Redistribution and use in source and binary forms, with or without
  85. + * modification, are permitted provided that the following conditions
  86. + * are met:
  87. + * 1. Redistributions of source code must retain the above copyright
  88. + * notice, this list of conditions, and the following disclaimer,
  89. + * without modification.
  90. + * 2. Redistributions in binary form must reproduce the above copyright
  91. + * notice, this list of conditions and the following disclaimer in the
  92. + * documentation and/or other materials provided with the distribution.
  93. + * 3. The names of the authors may not be used to endorse or promote products
  94. + * derived from this software without specific prior written permission.
  95. + *
  96. + * Alternatively, provided that this notice is retained in full, this
  97. + * software may be distributed under the terms of the GNU General
  98. + * Public License ("GPL") version 2, in which case the provisions of the
  99. + * GPL apply INSTEAD OF those given above.
  100. + *
  101. + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  102. + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  103. + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  104. + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  105. + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  106. + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  107. + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  108. + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  109. + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  110. + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  111. + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
  112. + * DAMAGE.
  113. + *
  114. + */
  115. +
  116. +#include <stddef.h>
  117. +#include <stdio.h>
  118. +#include <stdlib.h>
  119. +#include <unistd.h>
  120. +#include <syslog.h>
  121. +#include <fcntl.h>
  122. +#include <sys/socket.h>
  123. +#include <netinet/in.h>
  124. +#include <arpa/inet.h>
  125. +#include <string.h>
  126. +
  127. +#include "utils.h"
  128. +#include "tc_util.h"
  129. +
  130. +static void explain(void)
  131. +{
  132. + fprintf(stderr,
  133. +"Usage: ... cake [ bandwidth RATE | unlimited* | autorate_ingress ]\n"
  134. +" [ rtt TIME | datacentre | lan | metro | regional |\n"
  135. +" internet* | oceanic | satellite | interplanetary ]\n"
  136. +" [ besteffort | diffserv8 | diffserv4 | diffserv-llt |\n"
  137. +" diffserv3* ]\n"
  138. +" [ flowblind | srchost | dsthost | hosts | flows |\n"
  139. +" dual-srchost | dual-dsthost | triple-isolate* ]\n"
  140. +" [ nat | nonat* ]\n"
  141. +" [ wash | nowash * ]\n"
  142. +" [ ack-filter | ack-filter-aggressive | no-ack-filter * ]\n"
  143. +" [ memlimit LIMIT ]\n"
  144. +" [ ptm | atm | noatm* ] [ overhead N | conservative | raw* ]\n"
  145. +" [ mpu N ] [ ingress | egress* ]\n"
  146. +" (* marks defaults)\n");
  147. +}
  148. +
  149. +static int cake_parse_opt(struct qdisc_util *qu, int argc, char **argv,
  150. + struct nlmsghdr *n)
  151. +{
  152. + int unlimited = 0;
  153. + unsigned bandwidth = 0;
  154. + unsigned interval = 0;
  155. + unsigned target = 0;
  156. + unsigned diffserv = 0;
  157. + unsigned memlimit = 0;
  158. + int overhead = 0;
  159. + bool overhead_set = false;
  160. + bool overhead_override = false;
  161. + int mpu = 0;
  162. + int flowmode = -1;
  163. + int nat = -1;
  164. + int atm = -1;
  165. + int autorate = -1;
  166. + int wash = -1;
  167. + int ingress = -1;
  168. + int ack_filter = -1;
  169. + struct rtattr *tail;
  170. +
  171. + while (argc > 0) {
  172. + if (strcmp(*argv, "bandwidth") == 0) {
  173. + NEXT_ARG();
  174. + if (get_rate(&bandwidth, *argv)) {
  175. + fprintf(stderr, "Illegal \"bandwidth\"\n");
  176. + return -1;
  177. + }
  178. + unlimited = 0;
  179. + autorate = 0;
  180. + } else if (strcmp(*argv, "unlimited") == 0) {
  181. + bandwidth = 0;
  182. + unlimited = 1;
  183. + autorate = 0;
  184. + } else if (strcmp(*argv, "autorate_ingress") == 0) {
  185. + autorate = 1;
  186. +
  187. + } else if (strcmp(*argv, "rtt") == 0) {
  188. + NEXT_ARG();
  189. + if (get_time(&interval, *argv)) {
  190. + fprintf(stderr, "Illegal \"rtt\"\n");
  191. + return -1;
  192. + }
  193. + target = interval / 20;
  194. + if(!target)
  195. + target = 1;
  196. + } else if (strcmp(*argv, "datacentre") == 0) {
  197. + interval = 100;
  198. + target = 5;
  199. + } else if (strcmp(*argv, "lan") == 0) {
  200. + interval = 1000;
  201. + target = 50;
  202. + } else if (strcmp(*argv, "metro") == 0) {
  203. + interval = 10000;
  204. + target = 500;
  205. + } else if (strcmp(*argv, "regional") == 0) {
  206. + interval = 30000;
  207. + target = 1500;
  208. + } else if (strcmp(*argv, "internet") == 0) {
  209. + interval = 100000;
  210. + target = 5000;
  211. + } else if (strcmp(*argv, "oceanic") == 0) {
  212. + interval = 300000;
  213. + target = 15000;
  214. + } else if (strcmp(*argv, "satellite") == 0) {
  215. + interval = 1000000;
  216. + target = 50000;
  217. + } else if (strcmp(*argv, "interplanetary") == 0) {
  218. + interval = 3600000000U;
  219. + target = 5000;
  220. +
  221. + } else if (strcmp(*argv, "besteffort") == 0) {
  222. + diffserv = 1;
  223. + } else if (strcmp(*argv, "precedence") == 0) {
  224. + diffserv = 2;
  225. + } else if (strcmp(*argv, "diffserv8") == 0) {
  226. + diffserv = 3;
  227. + } else if (strcmp(*argv, "diffserv4") == 0) {
  228. + diffserv = 4;
  229. + } else if (strcmp(*argv, "diffserv") == 0) {
  230. + diffserv = 4;
  231. + } else if (strcmp(*argv, "diffserv-llt") == 0) {
  232. + diffserv = 5;
  233. + } else if (strcmp(*argv, "diffserv3") == 0) {
  234. + diffserv = 6;
  235. +
  236. + } else if (strcmp(*argv, "nowash") == 0) {
  237. + wash = 0;
  238. + } else if (strcmp(*argv, "wash") == 0) {
  239. + wash = 1;
  240. +
  241. + } else if (strcmp(*argv, "flowblind") == 0) {
  242. + flowmode = 0;
  243. + } else if (strcmp(*argv, "srchost") == 0) {
  244. + flowmode = 1;
  245. + } else if (strcmp(*argv, "dsthost") == 0) {
  246. + flowmode = 2;
  247. + } else if (strcmp(*argv, "hosts") == 0) {
  248. + flowmode = 3;
  249. + } else if (strcmp(*argv, "flows") == 0) {
  250. + flowmode = 4;
  251. + } else if (strcmp(*argv, "dual-srchost") == 0) {
  252. + flowmode = 5;
  253. + } else if (strcmp(*argv, "dual-dsthost") == 0) {
  254. + flowmode = 6;
  255. + } else if (strcmp(*argv, "triple-isolate") == 0) {
  256. + flowmode = 7;
  257. +
  258. + } else if (strcmp(*argv, "nat") == 0) {
  259. + nat = 1;
  260. + } else if (strcmp(*argv, "nonat") == 0) {
  261. + nat = 0;
  262. +
  263. + } else if (strcmp(*argv, "ptm") == 0) {
  264. + atm = 2;
  265. + } else if (strcmp(*argv, "atm") == 0) {
  266. + atm = 1;
  267. + } else if (strcmp(*argv, "noatm") == 0) {
  268. + atm = 0;
  269. +
  270. + } else if (strcmp(*argv, "raw") == 0) {
  271. + atm = 0;
  272. + overhead = 0;
  273. + overhead_set = true;
  274. + overhead_override = true;
  275. + } else if (strcmp(*argv, "conservative") == 0) {
  276. + /*
  277. + * Deliberately over-estimate overhead:
  278. + * one whole ATM cell plus ATM framing.
  279. + * A safe choice if the actual overhead is unknown.
  280. + */
  281. + atm = 1;
  282. + overhead = 48;
  283. + overhead_set = true;
  284. +
  285. + /* Various ADSL framing schemes, all over ATM cells */
  286. + } else if (strcmp(*argv, "ipoa-vcmux") == 0) {
  287. + atm = 1;
  288. + overhead += 8;
  289. + overhead_set = true;
  290. + } else if (strcmp(*argv, "ipoa-llcsnap") == 0) {
  291. + atm = 1;
  292. + overhead += 16;
  293. + overhead_set = true;
  294. + } else if (strcmp(*argv, "bridged-vcmux") == 0) {
  295. + atm = 1;
  296. + overhead += 24;
  297. + overhead_set = true;
  298. + } else if (strcmp(*argv, "bridged-llcsnap") == 0) {
  299. + atm = 1;
  300. + overhead += 32;
  301. + overhead_set = true;
  302. + } else if (strcmp(*argv, "pppoa-vcmux") == 0) {
  303. + atm = 1;
  304. + overhead += 10;
  305. + overhead_set = true;
  306. + } else if (strcmp(*argv, "pppoa-llc") == 0) {
  307. + atm = 1;
  308. + overhead += 14;
  309. + overhead_set = true;
  310. + } else if (strcmp(*argv, "pppoe-vcmux") == 0) {
  311. + atm = 1;
  312. + overhead += 32;
  313. + overhead_set = true;
  314. + } else if (strcmp(*argv, "pppoe-llcsnap") == 0) {
  315. + atm = 1;
  316. + overhead += 40;
  317. + overhead_set = true;
  318. +
  319. + /* Typical VDSL2 framing schemes, both over PTM */
  320. + /* PTM has 64b/65b coding which absorbs some bandwidth */
  321. + } else if (strcmp(*argv, "pppoe-ptm") == 0) {
  322. + /* 2B PPP + 6B PPPoE + 6B dest MAC + 6B src MAC
  323. + * + 2B ethertype + 4B Frame Check Sequence
  324. + * + 1B Start of Frame (S) + 1B End of Frame (Ck)
  325. + * + 2B TC-CRC (PTM-FCS) = 30B
  326. + */
  327. + atm = 2;
  328. + overhead += 30;
  329. + overhead_set = true;
  330. + } else if (strcmp(*argv, "bridged-ptm") == 0) {
  331. + /* 6B dest MAC + 6B src MAC + 2B ethertype
  332. + * + 4B Frame Check Sequence
  333. + * + 1B Start of Frame (S) + 1B End of Frame (Ck)
  334. + * + 2B TC-CRC (PTM-FCS) = 22B
  335. + */
  336. + atm = 2;
  337. + overhead += 22;
  338. + overhead_set = true;
  339. +
  340. + } else if (strcmp(*argv, "via-ethernet") == 0) {
  341. + /*
  342. + * We used to use this flag to manually compensate for
  343. + * Linux including the Ethernet header on Ethernet-type
  344. + * interfaces, but not on IP-type interfaces.
  345. + *
  346. + * It is no longer needed, because Cake now adjusts for
  347. + * that automatically, and is thus ignored.
  348. + *
  349. + * It would be deleted entirely, but it appears in the
  350. + * stats output when the automatic compensation is
  351. + * active.
  352. + */
  353. +
  354. + } else if (strcmp(*argv, "total_overhead") == 0) {
  355. + /*
  356. + * This is the overhead cake accounts for; added here so
  357. + * that cake's "tc -s qdisc" output can be directly
  358. + * pasted into the tc command to instantate a new cake..
  359. + */
  360. + NEXT_ARG();
  361. +
  362. + } else if (strcmp(*argv, "hard_header_len") == 0) {
  363. + /*
  364. + * This is the overhead the kernel automatically
  365. + * accounted for; added here so that cake's "tc -s
  366. + * qdisc" output can be directly pasted into the tc
  367. + * command to instantiate a new cake..
  368. + */
  369. + NEXT_ARG();
  370. +
  371. + } else if (strcmp(*argv, "ethernet") == 0) {
  372. + /* ethernet pre-amble & interframe gap & FCS
  373. + * you may need to add vlan tag */
  374. + overhead += 38;
  375. + overhead_set = true;
  376. + mpu = 84;
  377. +
  378. + /* Additional Ethernet-related overhead used by some ISPs */
  379. + } else if (strcmp(*argv, "ether-vlan") == 0) {
  380. + /* 802.1q VLAN tag - may be repeated */
  381. + overhead += 4;
  382. + overhead_set = true;
  383. +
  384. + /*
  385. + * DOCSIS cable shapers account for Ethernet frame with FCS,
  386. + * but not interframe gap or preamble.
  387. + */
  388. + } else if (strcmp(*argv, "docsis") == 0) {
  389. + atm = 0;
  390. + overhead += 18;
  391. + overhead_set = true;
  392. + mpu = 64;
  393. +
  394. + } else if (strcmp(*argv, "overhead") == 0) {
  395. + char* p = NULL;
  396. + NEXT_ARG();
  397. + overhead = strtol(*argv, &p, 10);
  398. + if(!p || *p || !*argv || overhead < -64 || overhead > 256) {
  399. + fprintf(stderr, "Illegal \"overhead\", valid range is -64 to 256\\n");
  400. + return -1;
  401. + }
  402. + overhead_set = true;
  403. +
  404. + } else if (strcmp(*argv, "mpu") == 0) {
  405. + char* p = NULL;
  406. + NEXT_ARG();
  407. + mpu = strtol(*argv, &p, 10);
  408. + if(!p || *p || !*argv || mpu < 0 || mpu > 256) {
  409. + fprintf(stderr, "Illegal \"mpu\", valid range is 0 to 256\\n");
  410. + return -1;
  411. + }
  412. +
  413. + } else if (strcmp(*argv, "ingress") == 0) {
  414. + ingress = 1;
  415. + } else if (strcmp(*argv, "egress") == 0) {
  416. + ingress = 0;
  417. +
  418. + } else if (strcmp(*argv, "no-ack-filter") == 0) {
  419. + ack_filter = 0;
  420. + } else if (strcmp(*argv, "ack-filter") == 0) {
  421. + ack_filter = 0x0200;
  422. + } else if (strcmp(*argv, "ack-filter-aggressive") == 0) {
  423. + ack_filter = 0x0600;
  424. +
  425. + } else if (strcmp(*argv, "memlimit") == 0) {
  426. + NEXT_ARG();
  427. + if(get_size(&memlimit, *argv)) {
  428. + fprintf(stderr, "Illegal value for \"memlimit\": \"%s\"\n", *argv);
  429. + return -1;
  430. + }
  431. +
  432. + } else if (strcmp(*argv, "help") == 0) {
  433. + explain();
  434. + return -1;
  435. + } else {
  436. + fprintf(stderr, "What is \"%s\"?\n", *argv);
  437. + explain();
  438. + return -1;
  439. + }
  440. + argc--; argv++;
  441. + }
  442. +
  443. + tail = NLMSG_TAIL(n);
  444. + addattr_l(n, 1024, TCA_OPTIONS, NULL, 0);
  445. + if (bandwidth || unlimited)
  446. + addattr_l(n, 1024, TCA_CAKE_BASE_RATE, &bandwidth, sizeof(bandwidth));
  447. + if (diffserv)
  448. + addattr_l(n, 1024, TCA_CAKE_DIFFSERV_MODE, &diffserv, sizeof(diffserv));
  449. + if (atm != -1)
  450. + addattr_l(n, 1024, TCA_CAKE_ATM, &atm, sizeof(atm));
  451. + if (flowmode != -1)
  452. + addattr_l(n, 1024, TCA_CAKE_FLOW_MODE, &flowmode, sizeof(flowmode));
  453. + if (overhead_set)
  454. + addattr_l(n, 1024, TCA_CAKE_OVERHEAD, &overhead, sizeof(overhead));
  455. + if (overhead_override) {
  456. + unsigned zero = 0;
  457. + addattr_l(n, 1024, TCA_CAKE_ETHERNET, &zero, sizeof(zero));
  458. + }
  459. + if (mpu > 0)
  460. + addattr_l(n, 1024, TCA_CAKE_MPU, &mpu, sizeof(mpu));
  461. + if (interval)
  462. + addattr_l(n, 1024, TCA_CAKE_RTT, &interval, sizeof(interval));
  463. + if (target)
  464. + addattr_l(n, 1024, TCA_CAKE_TARGET, &target, sizeof(target));
  465. + if (autorate != -1)
  466. + addattr_l(n, 1024, TCA_CAKE_AUTORATE, &autorate, sizeof(autorate));
  467. + if (memlimit)
  468. + addattr_l(n, 1024, TCA_CAKE_MEMORY, &memlimit, sizeof(memlimit));
  469. + if (nat != -1)
  470. + addattr_l(n, 1024, TCA_CAKE_NAT, &nat, sizeof(nat));
  471. + if (wash != -1)
  472. + addattr_l(n, 1024, TCA_CAKE_WASH, &wash, sizeof(wash));
  473. + if (ingress != -1)
  474. + addattr_l(n, 1024, TCA_CAKE_INGRESS, &ingress, sizeof(ingress));
  475. + if (ack_filter != -1)
  476. + addattr_l(n, 1024, TCA_CAKE_ACK_FILTER, &ack_filter, sizeof(ack_filter));
  477. +
  478. + tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail;
  479. + return 0;
  480. +}
  481. +
  482. +
  483. +static int cake_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
  484. +{
  485. + struct rtattr *tb[TCA_CAKE_MAX + 1];
  486. + unsigned bandwidth = 0;
  487. + unsigned diffserv = 0;
  488. + unsigned flowmode = 0;
  489. + unsigned interval = 0;
  490. + unsigned memlimit = 0;
  491. + int overhead = 0;
  492. + int ethernet = 0;
  493. + int mpu = 0;
  494. + int atm = 0;
  495. + int nat = 0;
  496. + int autorate = 0;
  497. + int wash = 0;
  498. + int ingress = 0;
  499. + int ack_filter = 0;
  500. + SPRINT_BUF(b1);
  501. + SPRINT_BUF(b2);
  502. +
  503. + if (opt == NULL)
  504. + return 0;
  505. +
  506. + parse_rtattr_nested(tb, TCA_CAKE_MAX, opt);
  507. +
  508. + if (tb[TCA_CAKE_BASE_RATE] &&
  509. + RTA_PAYLOAD(tb[TCA_CAKE_BASE_RATE]) >= sizeof(__u32)) {
  510. + bandwidth = rta_getattr_u32(tb[TCA_CAKE_BASE_RATE]);
  511. + if(bandwidth)
  512. + fprintf(f, "bandwidth %s ", sprint_rate(bandwidth, b1));
  513. + else
  514. + fprintf(f, "unlimited ");
  515. + }
  516. + if (tb[TCA_CAKE_AUTORATE] &&
  517. + RTA_PAYLOAD(tb[TCA_CAKE_AUTORATE]) >= sizeof(__u32)) {
  518. + autorate = rta_getattr_u32(tb[TCA_CAKE_AUTORATE]);
  519. + if(autorate == 1)
  520. + fprintf(f, "autorate_ingress ");
  521. + else if(autorate)
  522. + fprintf(f, "(?autorate?) ");
  523. + }
  524. + if (tb[TCA_CAKE_DIFFSERV_MODE] &&
  525. + RTA_PAYLOAD(tb[TCA_CAKE_DIFFSERV_MODE]) >= sizeof(__u32)) {
  526. + diffserv = rta_getattr_u32(tb[TCA_CAKE_DIFFSERV_MODE]);
  527. + switch(diffserv) {
  528. + case 1:
  529. + fprintf(f, "besteffort ");
  530. + break;
  531. + case 2:
  532. + fprintf(f, "precedence ");
  533. + break;
  534. + case 3:
  535. + fprintf(f, "diffserv8 ");
  536. + break;
  537. + case 4:
  538. + fprintf(f, "diffserv4 ");
  539. + break;
  540. + case 5:
  541. + fprintf(f, "diffserv-llt ");
  542. + break;
  543. + case 6:
  544. + fprintf(f, "diffserv3 ");
  545. + break;
  546. + default:
  547. + fprintf(f, "(?diffserv?) ");
  548. + break;
  549. + };
  550. + }
  551. + if (tb[TCA_CAKE_FLOW_MODE] &&
  552. + RTA_PAYLOAD(tb[TCA_CAKE_FLOW_MODE]) >= sizeof(__u32)) {
  553. + flowmode = rta_getattr_u32(tb[TCA_CAKE_FLOW_MODE]);
  554. + nat = !!(flowmode & 64);
  555. + flowmode &= ~64;
  556. + switch(flowmode) {
  557. + case 0:
  558. + fprintf(f, "flowblind ");
  559. + break;
  560. + case 1:
  561. + fprintf(f, "srchost ");
  562. + break;
  563. + case 2:
  564. + fprintf(f, "dsthost ");
  565. + break;
  566. + case 3:
  567. + fprintf(f, "hosts ");
  568. + break;
  569. + case 4:
  570. + fprintf(f, "flows ");
  571. + break;
  572. + case 5:
  573. + fprintf(f, "dual-srchost ");
  574. + break;
  575. + case 6:
  576. + fprintf(f, "dual-dsthost ");
  577. + break;
  578. + case 7:
  579. + fprintf(f, "triple-isolate ");
  580. + break;
  581. + default:
  582. + fprintf(f, "(?flowmode?) ");
  583. + break;
  584. + };
  585. +
  586. + if(nat)
  587. + fprintf(f, "nat ");
  588. + }
  589. + if (tb[TCA_CAKE_WASH] &&
  590. + RTA_PAYLOAD(tb[TCA_CAKE_WASH]) >= sizeof(__u32)) {
  591. + wash = rta_getattr_u32(tb[TCA_CAKE_WASH]);
  592. + }
  593. + if (tb[TCA_CAKE_ATM] &&
  594. + RTA_PAYLOAD(tb[TCA_CAKE_ATM]) >= sizeof(__u32)) {
  595. + atm = rta_getattr_u32(tb[TCA_CAKE_ATM]);
  596. + }
  597. + if (tb[TCA_CAKE_OVERHEAD] &&
  598. + RTA_PAYLOAD(tb[TCA_CAKE_OVERHEAD]) >= sizeof(__u32)) {
  599. + overhead = rta_getattr_u32(tb[TCA_CAKE_OVERHEAD]);
  600. + }
  601. + if (tb[TCA_CAKE_MPU] &&
  602. + RTA_PAYLOAD(tb[TCA_CAKE_MPU]) >= sizeof(__u32)) {
  603. + mpu = rta_getattr_u32(tb[TCA_CAKE_MPU]);
  604. + }
  605. + if (tb[TCA_CAKE_INGRESS] &&
  606. + RTA_PAYLOAD(tb[TCA_CAKE_INGRESS]) >= sizeof(__u32)) {
  607. + ingress = rta_getattr_u32(tb[TCA_CAKE_INGRESS]);
  608. + }
  609. + if (tb[TCA_CAKE_ACK_FILTER] &&
  610. + RTA_PAYLOAD(tb[TCA_CAKE_ACK_FILTER]) >= sizeof(__u32)) {
  611. + ack_filter = rta_getattr_u32(tb[TCA_CAKE_ACK_FILTER]);
  612. + }
  613. + if (tb[TCA_CAKE_ETHERNET] &&
  614. + RTA_PAYLOAD(tb[TCA_CAKE_ETHERNET]) >= sizeof(__u32)) {
  615. + ethernet = rta_getattr_u32(tb[TCA_CAKE_ETHERNET]);
  616. + }
  617. + if (tb[TCA_CAKE_RTT] &&
  618. + RTA_PAYLOAD(tb[TCA_CAKE_RTT]) >= sizeof(__u32)) {
  619. + interval = rta_getattr_u32(tb[TCA_CAKE_RTT]);
  620. + }
  621. +
  622. + if (wash)
  623. + fprintf(f,"wash ");
  624. +
  625. + if (ingress)
  626. + fprintf(f,"ingress ");
  627. +
  628. + if (ack_filter == 0x0600)
  629. + fprintf(f,"ack-filter-aggressive ");
  630. + else if (ack_filter)
  631. + fprintf(f,"ack-filter ");
  632. +
  633. + if (interval)
  634. + fprintf(f, "rtt %s ", sprint_time(interval, b2));
  635. +
  636. + if (!atm && overhead == ethernet) {
  637. + fprintf(f, "raw ");
  638. + } else {
  639. + if (atm == 1)
  640. + fprintf(f, "atm ");
  641. + else if (atm == 2)
  642. + fprintf(f, "ptm ");
  643. + else
  644. + fprintf(f, "noatm ");
  645. +
  646. + fprintf(f, "overhead %d ", overhead);
  647. +
  648. + /* This is actually the *amount* of automatic compensation, but
  649. + * we only report its presence as a boolean for now.
  650. + */
  651. + if (ethernet)
  652. + fprintf(f, "via-ethernet ");
  653. + }
  654. +
  655. + /* unconditionally report the overhead and hard_header_len overhead the
  656. + * kernel added automatically
  657. + */
  658. + fprintf(f, "total_overhead %d ", overhead);
  659. + fprintf(f, "hard_header_len %d ", ethernet);
  660. +
  661. + if (mpu) {
  662. + fprintf(f, "mpu %d ", mpu);
  663. + }
  664. +
  665. + if (memlimit)
  666. + fprintf(f, "memlimit %s", sprint_size(memlimit, b1));
  667. +
  668. + return 0;
  669. +}
  670. +
  671. +static int cake_print_xstats(struct qdisc_util *qu, FILE *f,
  672. + struct rtattr *xstats)
  673. +{
  674. + /* fq_codel stats format borrowed */
  675. + struct tc_fq_codel_xstats *st;
  676. + struct tc_cake_xstats *stnc;
  677. + SPRINT_BUF(b1);
  678. + SPRINT_BUF(b2);
  679. +
  680. + if (xstats == NULL)
  681. + return 0;
  682. +
  683. + if (RTA_PAYLOAD(xstats) < sizeof(st->type))
  684. + return -1;
  685. +
  686. + st = RTA_DATA(xstats);
  687. + stnc = RTA_DATA(xstats);
  688. +
  689. + if (st->type == TCA_FQ_CODEL_XSTATS_QDISC && RTA_PAYLOAD(xstats) >= sizeof(*st)) {
  690. + fprintf(f, " maxpacket %u drop_overlimit %u new_flow_count %u ecn_mark %u",
  691. + st->qdisc_stats.maxpacket,
  692. + st->qdisc_stats.drop_overlimit,
  693. + st->qdisc_stats.new_flow_count,
  694. + st->qdisc_stats.ecn_mark);
  695. + fprintf(f, "\n new_flows_len %u old_flows_len %u",
  696. + st->qdisc_stats.new_flows_len,
  697. + st->qdisc_stats.old_flows_len);
  698. + } else if (st->type == TCA_FQ_CODEL_XSTATS_CLASS && RTA_PAYLOAD(xstats) >= sizeof(*st)) {
  699. + fprintf(f, " deficit %d count %u lastcount %u ldelay %s",
  700. + st->class_stats.deficit,
  701. + st->class_stats.count,
  702. + st->class_stats.lastcount,
  703. + sprint_time(st->class_stats.ldelay, b1));
  704. + if (st->class_stats.dropping) {
  705. + fprintf(f, " dropping");
  706. + if (st->class_stats.drop_next < 0)
  707. + fprintf(f, " drop_next -%s",
  708. + sprint_time(-st->class_stats.drop_next, b1));
  709. + else
  710. + fprintf(f, " drop_next %s",
  711. + sprint_time(st->class_stats.drop_next, b1));
  712. + }
  713. + } else if (stnc->version >= 1 && stnc->version < 0xFF
  714. + && stnc->max_tins == TC_CAKE_MAX_TINS
  715. + && RTA_PAYLOAD(xstats) >= offsetof(struct tc_cake_xstats, capacity_estimate))
  716. + {
  717. + int i;
  718. +
  719. + if(stnc->version >= 3)
  720. + fprintf(f, " memory used: %s of %s\n", sprint_size(stnc->memory_used, b1), sprint_size(stnc->memory_limit, b2));
  721. +
  722. + if(stnc->version >= 2)
  723. + fprintf(f, " capacity estimate: %s\n", sprint_rate(stnc->capacity_estimate, b1));
  724. +
  725. + switch(stnc->tin_cnt) {
  726. + case 3:
  727. + fprintf(f, " Bulk Best Effort Voice\n");
  728. + break;
  729. +
  730. + case 4:
  731. + fprintf(f, " Bulk Best Effort Video Voice\n");
  732. + break;
  733. +
  734. + case 5:
  735. + fprintf(f, " Low Loss Best Effort Low Delay Bulk Net Control\n");
  736. + break;
  737. +
  738. + default:
  739. + fprintf(f, " ");
  740. + for(i=0; i < stnc->tin_cnt; i++)
  741. + fprintf(f, " Tin %u", i);
  742. + fprintf(f, "\n");
  743. + };
  744. +
  745. + fprintf(f, " thresh ");
  746. + for(i=0; i < stnc->tin_cnt; i++)
  747. + fprintf(f, " %12s", sprint_rate(stnc->threshold_rate[i], b1));
  748. + fprintf(f, "\n");
  749. +
  750. + fprintf(f, " target ");
  751. + for(i=0; i < stnc->tin_cnt; i++)
  752. + fprintf(f, " %12s", sprint_time(stnc->target_us[i], b1));
  753. + fprintf(f, "\n");
  754. +
  755. + fprintf(f, " interval");
  756. + for(i=0; i < stnc->tin_cnt; i++)
  757. + fprintf(f, " %12s", sprint_time(stnc->interval_us[i], b1));
  758. + fprintf(f, "\n");
  759. +
  760. + fprintf(f, " pk_delay");
  761. + for(i=0; i < stnc->tin_cnt; i++)
  762. + fprintf(f, " %12s", sprint_time(stnc->peak_delay_us[i], b1));
  763. + fprintf(f, "\n");
  764. +
  765. + fprintf(f, " av_delay");
  766. + for(i=0; i < stnc->tin_cnt; i++)
  767. + fprintf(f, " %12s", sprint_time(stnc->avge_delay_us[i], b1));
  768. + fprintf(f, "\n");
  769. +
  770. + fprintf(f, " sp_delay");
  771. + for(i=0; i < stnc->tin_cnt; i++)
  772. + fprintf(f, " %12s", sprint_time(stnc->base_delay_us[i], b1));
  773. + fprintf(f, "\n");
  774. +
  775. + fprintf(f, " pkts ");
  776. + for(i=0; i < stnc->tin_cnt; i++)
  777. + fprintf(f, " %12u", stnc->sent[i].packets);
  778. + fprintf(f, "\n");
  779. +
  780. + fprintf(f, " bytes ");
  781. + for(i=0; i < stnc->tin_cnt; i++)
  782. + fprintf(f, " %12llu", stnc->sent[i].bytes);
  783. + fprintf(f, "\n");
  784. +
  785. + fprintf(f, " way_inds");
  786. + for(i=0; i < stnc->tin_cnt; i++)
  787. + fprintf(f, " %12u", stnc->way_indirect_hits[i]);
  788. + fprintf(f, "\n");
  789. +
  790. + fprintf(f, " way_miss");
  791. + for(i=0; i < stnc->tin_cnt; i++)
  792. + fprintf(f, " %12u", stnc->way_misses[i]);
  793. + fprintf(f, "\n");
  794. +
  795. + fprintf(f, " way_cols");
  796. + for(i=0; i < stnc->tin_cnt; i++)
  797. + fprintf(f, " %12u", stnc->way_collisions[i]);
  798. + fprintf(f, "\n");
  799. +
  800. + fprintf(f, " drops ");
  801. + for(i=0; i < stnc->tin_cnt; i++)
  802. + fprintf(f, " %12u", stnc->dropped[i].packets);
  803. + fprintf(f, "\n");
  804. +
  805. + fprintf(f, " marks ");
  806. + for(i=0; i < stnc->tin_cnt; i++)
  807. + fprintf(f, " %12u", stnc->ecn_marked[i].packets);
  808. + fprintf(f, "\n");
  809. +
  810. + if(stnc->version >= 5) {
  811. + fprintf(f, " ack_drop");
  812. + for(i=0; i < stnc->tin_cnt; i++)
  813. + fprintf(f, " %12u", stnc->ack_drops[i].packets);
  814. + fprintf(f, "\n");
  815. + }
  816. +
  817. + fprintf(f, " sp_flows");
  818. + for(i=0; i < stnc->tin_cnt; i++)
  819. + fprintf(f, " %12u", stnc->sparse_flows[i]);
  820. + fprintf(f, "\n");
  821. +
  822. + fprintf(f, " bk_flows");
  823. + for(i=0; i < stnc->tin_cnt; i++)
  824. + fprintf(f, " %12u", stnc->bulk_flows[i]);
  825. + fprintf(f, "\n");
  826. +
  827. + if(stnc->version >= 4) {
  828. + fprintf(f, " un_flows");
  829. + for(i=0; i < stnc->tin_cnt; i++)
  830. + fprintf(f, " %12u", stnc->unresponse_flows[i]);
  831. + fprintf(f, "\n");
  832. + }
  833. +
  834. + fprintf(f, " max_len ");
  835. + for(i=0; i < stnc->tin_cnt; i++)
  836. + fprintf(f, " %12u", stnc->max_skblen[i]);
  837. + fprintf(f, "\n");
  838. + } else {
  839. + return -1;
  840. + }
  841. + return 0;
  842. +}
  843. +
  844. +struct qdisc_util cake_qdisc_util = {
  845. + .id = "cake",
  846. + .parse_qopt = cake_parse_opt,
  847. + .print_qopt = cake_print_opt,
  848. + .print_xstats = cake_print_xstats,
  849. +};