4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version
7 * 2 of the License, or (at your option) any later version.
9 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
17 #include <sys/socket.h>
18 #include <netinet/in.h>
19 #include <arpa/inet.h>
25 static void explain(void)
28 "Usage: ... tbf limit BYTES burst BYTES[/BYTES] rate KBPS [ mtu BYTES[/BYTES] ]\n"
29 " [ peakrate KBPS ] [ latency TIME ] "
30 "[ overhead BYTES ] [ linklayer TYPE ]\n");
33 static void explain1(const char *arg
, const char *val
)
35 fprintf(stderr
, "tbf: illegal value for \"%s\": \"%s\"\n", arg
, val
);
39 static int tbf_parse_opt(struct qdisc_util
*qu
, int argc
, char **argv
,
40 struct nlmsghdr
*n
, const char *dev
)
43 struct tc_tbf_qopt opt
= {};
46 unsigned buffer
= 0, mtu
= 0, mpu
= 0, latency
= 0;
47 int Rcell_log
= -1, Pcell_log
= -1;
48 unsigned short overhead
= 0;
49 unsigned int linklayer
= LINKLAYER_ETHERNET
; /* Assume ethernet */
51 __u64 rate64
= 0, prate64
= 0;
54 if (matches(*argv
, "limit") == 0) {
57 fprintf(stderr
, "tbf: duplicate \"limit\" specification\n");
61 fprintf(stderr
, "tbf: specifying both \"latency\" and \"limit\" is not allowed\n");
64 if (get_size(&opt
.limit
, *argv
)) {
65 explain1("limit", *argv
);
69 } else if (matches(*argv
, "latency") == 0) {
72 fprintf(stderr
, "tbf: duplicate \"latency\" specification\n");
76 fprintf(stderr
, "tbf: specifying both \"limit\" and \"/latency\" is not allowed\n");
79 if (get_time(&latency
, *argv
)) {
80 explain1("latency", *argv
);
84 } else if (matches(*argv
, "burst") == 0 ||
85 strcmp(*argv
, "buffer") == 0 ||
86 strcmp(*argv
, "maxburst") == 0) {
87 const char *parm_name
= *argv
;
91 fprintf(stderr
, "tbf: duplicate \"buffer/burst/maxburst\" specification\n");
94 if (get_size_and_cell(&buffer
, &Rcell_log
, *argv
) < 0) {
95 explain1(parm_name
, *argv
);
99 } else if (strcmp(*argv
, "mtu") == 0 ||
100 strcmp(*argv
, "minburst") == 0) {
101 const char *parm_name
= *argv
;
105 fprintf(stderr
, "tbf: duplicate \"mtu/minburst\" specification\n");
108 if (get_size_and_cell(&mtu
, &Pcell_log
, *argv
) < 0) {
109 explain1(parm_name
, *argv
);
113 } else if (strcmp(*argv
, "mpu") == 0) {
116 fprintf(stderr
, "tbf: duplicate \"mpu\" specification\n");
119 if (get_size(&mpu
, *argv
)) {
120 explain1("mpu", *argv
);
124 } else if (strcmp(*argv
, "rate") == 0) {
127 fprintf(stderr
, "tbf: duplicate \"rate\" specification\n");
130 if (strchr(*argv
, '%')) {
131 if (get_percent_rate64(&rate64
, *argv
, dev
)) {
132 explain1("rate", *argv
);
135 } else if (get_rate64(&rate64
, *argv
)) {
136 explain1("rate", *argv
);
140 } else if (matches(*argv
, "peakrate") == 0) {
143 fprintf(stderr
, "tbf: duplicate \"peakrate\" specification\n");
146 if (strchr(*argv
, '%')) {
147 if (get_percent_rate64(&prate64
, *argv
, dev
)) {
148 explain1("peakrate", *argv
);
151 } else if (get_rate64(&prate64
, *argv
)) {
152 explain1("peakrate", *argv
);
156 } else if (matches(*argv
, "overhead") == 0) {
159 fprintf(stderr
, "tbf: duplicate \"overhead\" specification\n");
162 if (get_u16(&overhead
, *argv
, 10)) {
163 explain1("overhead", *argv
); return -1;
165 } else if (matches(*argv
, "linklayer") == 0) {
167 if (get_linklayer(&linklayer
, *argv
)) {
168 explain1("linklayer", *argv
); return -1;
170 } else if (strcmp(*argv
, "help") == 0) {
174 fprintf(stderr
, "tbf: unknown parameter \"%s\"\n", *argv
);
183 /* Be nice to the user: try to emit all error messages in
184 * one go rather than reveal one more problem when a
185 * previous one has been fixed.
188 fprintf(stderr
, "tbf: the \"rate\" parameter is mandatory.\n");
192 fprintf(stderr
, "tbf: the \"burst\" parameter is mandatory.\n");
197 fprintf(stderr
, "tbf: when \"peakrate\" is specified, \"mtu\" must also be specified.\n");
202 if (opt
.limit
== 0 && latency
== 0) {
203 fprintf(stderr
, "tbf: either \"limit\" or \"latency\" is required.\n");
212 opt
.rate
.rate
= (rate64
>= (1ULL << 32)) ? ~0U : rate64
;
213 opt
.peakrate
.rate
= (prate64
>= (1ULL << 32)) ? ~0U : prate64
;
215 if (opt
.limit
== 0) {
216 double lim
= rate64
*(double)latency
/TIME_UNITS_PER_SEC
+ buffer
;
219 double lim2
= prate64
*(double)latency
/TIME_UNITS_PER_SEC
+ mtu
;
228 opt
.rate
.overhead
= overhead
;
229 if (tc_calc_rtable(&opt
.rate
, rtab
, Rcell_log
, mtu
, linklayer
) < 0) {
230 fprintf(stderr
, "tbf: failed to calculate rate table.\n");
233 opt
.buffer
= tc_calc_xmittime(opt
.rate
.rate
, buffer
);
235 if (opt
.peakrate
.rate
) {
236 opt
.peakrate
.mpu
= mpu
;
237 opt
.peakrate
.overhead
= overhead
;
238 if (tc_calc_rtable(&opt
.peakrate
, ptab
, Pcell_log
, mtu
, linklayer
) < 0) {
239 fprintf(stderr
, "tbf: failed to calculate peak rate table.\n");
242 opt
.mtu
= tc_calc_xmittime(opt
.peakrate
.rate
, mtu
);
245 tail
= addattr_nest(n
, 1024, TCA_OPTIONS
);
246 addattr_l(n
, 2024, TCA_TBF_PARMS
, &opt
, sizeof(opt
));
247 addattr_l(n
, 2124, TCA_TBF_BURST
, &buffer
, sizeof(buffer
));
248 if (rate64
>= (1ULL << 32))
249 addattr_l(n
, 2124, TCA_TBF_RATE64
, &rate64
, sizeof(rate64
));
250 addattr_l(n
, 3024, TCA_TBF_RTAB
, rtab
, 1024);
251 if (opt
.peakrate
.rate
) {
252 if (prate64
>= (1ULL << 32))
253 addattr_l(n
, 3124, TCA_TBF_PRATE64
, &prate64
, sizeof(prate64
));
254 addattr_l(n
, 3224, TCA_TBF_PBURST
, &mtu
, sizeof(mtu
));
255 addattr_l(n
, 4096, TCA_TBF_PTAB
, ptab
, 1024);
257 addattr_nest_end(n
, tail
);
261 static int tbf_print_opt(struct qdisc_util
*qu
, FILE *f
, struct rtattr
*opt
)
263 struct rtattr
*tb
[TCA_TBF_MAX
+1];
264 struct tc_tbf_qopt
*qopt
;
265 unsigned int linklayer
;
267 double latency
, lat2
;
268 __u64 rate64
= 0, prate64
= 0;
277 parse_rtattr_nested(tb
, TCA_TBF_MAX
, opt
);
279 if (tb
[TCA_TBF_PARMS
] == NULL
)
282 qopt
= RTA_DATA(tb
[TCA_TBF_PARMS
]);
283 if (RTA_PAYLOAD(tb
[TCA_TBF_PARMS
]) < sizeof(*qopt
))
285 rate64
= qopt
->rate
.rate
;
286 if (tb
[TCA_TBF_RATE64
] &&
287 RTA_PAYLOAD(tb
[TCA_TBF_RATE64
]) >= sizeof(rate64
))
288 rate64
= rta_getattr_u64(tb
[TCA_TBF_RATE64
]);
289 tc_print_rate(PRINT_ANY
, "rate", "rate %s ", rate64
);
290 buffer
= tc_calc_xmitsize(rate64
, qopt
->buffer
);
292 sprintf(b1
, "%s/%u", sprint_size(buffer
, b2
),
293 1 << qopt
->rate
.cell_log
);
294 print_string(PRINT_ANY
, "burst", "burst %s ", b1
);
295 print_size(PRINT_ANY
, "mpu", "mpu %s ", qopt
->rate
.mpu
);
297 print_size(PRINT_ANY
, "burst", "burst %s ", buffer
);
300 print_hex(PRINT_ANY
, "burst_raw", "[%08x] ", qopt
->buffer
);
301 prate64
= qopt
->peakrate
.rate
;
302 if (tb
[TCA_TBF_PRATE64
] &&
303 RTA_PAYLOAD(tb
[TCA_TBF_PRATE64
]) >= sizeof(prate64
))
304 prate64
= rta_getattr_u64(tb
[TCA_TBF_PRATE64
]);
306 tc_print_rate(PRINT_FP
, "peakrate", "peakrate %s ", prate64
);
307 if (qopt
->mtu
|| qopt
->peakrate
.mpu
) {
308 mtu
= tc_calc_xmitsize(prate64
, qopt
->mtu
);
310 sprintf(b1
, "%s/%u", sprint_size(mtu
, b2
),
311 1 << qopt
->peakrate
.cell_log
);
312 print_string(PRINT_ANY
, "mtu", "mtu %s ", b1
);
313 print_size(PRINT_ANY
, "mpu", "mpu %s ",
316 print_size(PRINT_ANY
, "minburst",
317 "minburst %s ", mtu
);
320 print_hex(PRINT_ANY
, "mtu_raw", "[%08x] ",
325 latency
= TIME_UNITS_PER_SEC
* (qopt
->limit
/ (double)rate64
) -
326 tc_core_tick2time(qopt
->buffer
);
328 lat2
= TIME_UNITS_PER_SEC
* (qopt
->limit
/ (double)prate64
) -
329 tc_core_tick2time(qopt
->mtu
);
334 if (latency
>= 0.0) {
335 print_u64(PRINT_JSON
, "lat", NULL
, latency
);
336 print_string(PRINT_FP
, NULL
, "lat %s ",
337 sprint_time(latency
, b1
));
339 if (show_raw
|| latency
< 0.0)
340 print_size(PRINT_ANY
, "limit", "limit %s ", qopt
->limit
);
341 if (qopt
->rate
.overhead
)
342 print_int(PRINT_ANY
, "overhead", "overhead %d ",
343 qopt
->rate
.overhead
);
344 linklayer
= (qopt
->rate
.linklayer
& TC_LINKLAYER_MASK
);
345 if (linklayer
> TC_LINKLAYER_ETHERNET
|| show_details
)
346 print_string(PRINT_ANY
, "linklayer", "linklayer %s ",
347 sprint_linklayer(linklayer
, b3
));
352 struct qdisc_util tbf_qdisc_util
= {
354 .parse_qopt
= tbf_parse_opt
,
355 .print_qopt
= tbf_print_opt
,