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>
18 #include <sys/socket.h>
19 #include <netinet/in.h>
20 #include <arpa/inet.h>
26 static void explain(void)
28 fprintf(stderr
, "Usage: ... tbf limit BYTES burst BYTES[/BYTES] rate KBPS [ mtu BYTES[/BYTES] ]\n");
29 fprintf(stderr
, " [ peakrate KBPS ] [ latency TIME ] ");
30 fprintf(stderr
, "[ 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
, struct nlmsghdr
*n
)
42 struct tc_tbf_qopt opt
;
45 unsigned buffer
=0, mtu
=0, mpu
=0, latency
=0;
46 int Rcell_log
=-1, Pcell_log
= -1;
47 unsigned short overhead
=0;
48 unsigned int linklayer
= LINKLAYER_ETHERNET
; /* Assume ethernet */
51 memset(&opt
, 0, sizeof(opt
));
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
;
90 fprintf(stderr
, "tbf: duplicate \"buffer/burst/maxburst\" specification\n");
93 if (get_size_and_cell(&buffer
, &Rcell_log
, *argv
) < 0) {
94 explain1(parm_name
, *argv
);
98 } else if (strcmp(*argv
, "mtu") == 0 ||
99 strcmp(*argv
, "minburst") == 0) {
100 const char *parm_name
= *argv
;
103 fprintf(stderr
, "tbf: duplicate \"mtu/minburst\" specification\n");
106 if (get_size_and_cell(&mtu
, &Pcell_log
, *argv
) < 0) {
107 explain1(parm_name
, *argv
);
111 } else if (strcmp(*argv
, "mpu") == 0) {
114 fprintf(stderr
, "tbf: duplicate \"mpu\" specification\n");
117 if (get_size(&mpu
, *argv
)) {
118 explain1("mpu", *argv
);
122 } else if (strcmp(*argv
, "rate") == 0) {
125 fprintf(stderr
, "tbf: duplicate \"rate\" specification\n");
128 if (get_rate(&opt
.rate
.rate
, *argv
)) {
129 explain1("rate", *argv
);
133 } else if (matches(*argv
, "peakrate") == 0) {
135 if (opt
.peakrate
.rate
) {
136 fprintf(stderr
, "tbf: duplicate \"peakrate\" specification\n");
139 if (get_rate(&opt
.peakrate
.rate
, *argv
)) {
140 explain1("peakrate", *argv
);
144 } else if (matches(*argv
, "overhead") == 0) {
147 fprintf(stderr
, "tbf: duplicate \"overhead\" specification\n");
150 if (get_u16(&overhead
, *argv
, 10)) {
151 explain1("overhead", *argv
); return -1;
153 } else if (matches(*argv
, "linklayer") == 0) {
155 if (get_linklayer(&linklayer
, *argv
)) {
156 explain1("linklayer", *argv
); return -1;
158 } else if (strcmp(*argv
, "help") == 0) {
162 fprintf(stderr
, "tbf: unknown parameter \"%s\"\n", *argv
);
171 /* Be nice to the user: try to emit all error messages in
172 * one go rather than reveal one more problem when a
173 * previous one has been fixed.
175 if (opt
.rate
.rate
== 0) {
176 fprintf(stderr
, "tbf: the \"rate\" parameter is mandatory.\n");
180 fprintf(stderr
, "tbf: the \"burst\" parameter is mandatory.\n");
183 if (opt
.peakrate
.rate
) {
185 fprintf(stderr
, "tbf: when \"peakrate\" is specified, \"mtu\" must also be specified.\n");
190 if (opt
.limit
== 0 && latency
== 0) {
191 fprintf(stderr
, "tbf: either \"limit\" or \"latency\" is required.\n");
200 if (opt
.limit
== 0) {
201 double lim
= opt
.rate
.rate
*(double)latency
/TIME_UNITS_PER_SEC
+ buffer
;
202 if (opt
.peakrate
.rate
) {
203 double lim2
= opt
.peakrate
.rate
*(double)latency
/TIME_UNITS_PER_SEC
+ mtu
;
211 opt
.rate
.overhead
= overhead
;
212 if (tc_calc_rtable(&opt
.rate
, rtab
, Rcell_log
, mtu
, linklayer
) < 0) {
213 fprintf(stderr
, "tbf: failed to calculate rate table.\n");
216 opt
.buffer
= tc_calc_xmittime(opt
.rate
.rate
, buffer
);
218 if (opt
.peakrate
.rate
) {
219 opt
.peakrate
.mpu
= mpu
;
220 opt
.peakrate
.overhead
= overhead
;
221 if (tc_calc_rtable(&opt
.peakrate
, ptab
, Pcell_log
, mtu
, linklayer
) < 0) {
222 fprintf(stderr
, "tbf: failed to calculate peak rate table.\n");
225 opt
.mtu
= tc_calc_xmittime(opt
.peakrate
.rate
, mtu
);
228 tail
= NLMSG_TAIL(n
);
229 addattr_l(n
, 1024, TCA_OPTIONS
, NULL
, 0);
230 addattr_l(n
, 2024, TCA_TBF_PARMS
, &opt
, sizeof(opt
));
231 addattr_l(n
, 3024, TCA_TBF_RTAB
, rtab
, 1024);
232 if (opt
.peakrate
.rate
)
233 addattr_l(n
, 4096, TCA_TBF_PTAB
, ptab
, 1024);
234 tail
->rta_len
= (void *) NLMSG_TAIL(n
) - (void *) tail
;
238 static int tbf_print_opt(struct qdisc_util
*qu
, FILE *f
, struct rtattr
*opt
)
240 struct rtattr
*tb
[TCA_TBF_PTAB
+1];
241 struct tc_tbf_qopt
*qopt
;
242 unsigned int linklayer
;
252 parse_rtattr_nested(tb
, TCA_TBF_PTAB
, opt
);
254 if (tb
[TCA_TBF_PARMS
] == NULL
)
257 qopt
= RTA_DATA(tb
[TCA_TBF_PARMS
]);
258 if (RTA_PAYLOAD(tb
[TCA_TBF_PARMS
]) < sizeof(*qopt
))
260 fprintf(f
, "rate %s ", sprint_rate(qopt
->rate
.rate
, b1
));
261 buffer
= tc_calc_xmitsize(qopt
->rate
.rate
, qopt
->buffer
);
263 fprintf(f
, "burst %s/%u mpu %s ", sprint_size(buffer
, b1
),
264 1<<qopt
->rate
.cell_log
, sprint_size(qopt
->rate
.mpu
, b2
));
266 fprintf(f
, "burst %s ", sprint_size(buffer
, b1
));
269 fprintf(f
, "[%08x] ", qopt
->buffer
);
270 if (qopt
->peakrate
.rate
) {
271 fprintf(f
, "peakrate %s ", sprint_rate(qopt
->peakrate
.rate
, b1
));
272 if (qopt
->mtu
|| qopt
->peakrate
.mpu
) {
273 mtu
= tc_calc_xmitsize(qopt
->peakrate
.rate
, qopt
->mtu
);
275 fprintf(f
, "mtu %s/%u mpu %s ", sprint_size(mtu
, b1
),
276 1<<qopt
->peakrate
.cell_log
, sprint_size(qopt
->peakrate
.mpu
, b2
));
278 fprintf(f
, "minburst %s ", sprint_size(mtu
, b1
));
281 fprintf(f
, "[%08x] ", qopt
->mtu
);
286 fprintf(f
, "limit %s ", sprint_size(qopt
->limit
, b1
));
288 latency
= TIME_UNITS_PER_SEC
*(qopt
->limit
/(double)qopt
->rate
.rate
) - tc_core_tick2time(qopt
->buffer
);
289 if (qopt
->peakrate
.rate
) {
290 double lat2
= TIME_UNITS_PER_SEC
*(qopt
->limit
/(double)qopt
->peakrate
.rate
) - tc_core_tick2time(qopt
->mtu
);
294 fprintf(f
, "lat %s ", sprint_time(latency
, b1
));
296 if (qopt
->rate
.overhead
) {
297 fprintf(f
, "overhead %d", qopt
->rate
.overhead
);
299 linklayer
= (qopt
->rate
.linklayer
& TC_LINKLAYER_MASK
);
300 if (linklayer
> TC_LINKLAYER_ETHERNET
|| show_details
)
301 fprintf(f
, "linklayer %s ", sprint_linklayer(linklayer
, b3
));
306 struct qdisc_util tbf_qdisc_util
= {
308 .parse_qopt
= tbf_parse_opt
,
309 .print_qopt
= tbf_print_opt
,