]> rtime.felk.cvut.cz Git - lisovros/iproute2_canprio.git/blob - tc/q_tbf.c
v3.3.0
[lisovros/iproute2_canprio.git] / tc / q_tbf.c
1 /*
2  * q_tbf.c              TBF.
3  *
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.
8  *
9  * Authors:     Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
10  *
11  */
12
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <unistd.h>
16 #include <syslog.h>
17 #include <fcntl.h>
18 #include <sys/socket.h>
19 #include <netinet/in.h>
20 #include <arpa/inet.h>
21 #include <string.h>
22
23 #include "utils.h"
24 #include "tc_util.h"
25
26 static void explain(void)
27 {
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");
31 }
32
33 static void explain1(char *arg)
34 {
35         fprintf(stderr, "Illegal \"%s\"\n", arg);
36 }
37
38
39 static int tbf_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n)
40 {
41         int ok=0;
42         struct tc_tbf_qopt opt;
43         __u32 rtab[256];
44         __u32 ptab[256];
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 */
49         struct rtattr *tail;
50
51         memset(&opt, 0, sizeof(opt));
52
53         while (argc > 0) {
54                 if (matches(*argv, "limit") == 0) {
55                         NEXT_ARG();
56                         if (opt.limit || latency) {
57                                 fprintf(stderr, "Double \"limit/latency\" spec\n");
58                                 return -1;
59                         }
60                         if (get_size(&opt.limit, *argv)) {
61                                 explain1("limit");
62                                 return -1;
63                         }
64                         ok++;
65                 } else if (matches(*argv, "latency") == 0) {
66                         NEXT_ARG();
67                         if (opt.limit || latency) {
68                                 fprintf(stderr, "Double \"limit/latency\" spec\n");
69                                 return -1;
70                         }
71                         if (get_time(&latency, *argv)) {
72                                 explain1("latency");
73                                 return -1;
74                         }
75                         ok++;
76                 } else if (matches(*argv, "burst") == 0 ||
77                         strcmp(*argv, "buffer") == 0 ||
78                         strcmp(*argv, "maxburst") == 0) {
79                         NEXT_ARG();
80                         if (buffer) {
81                                 fprintf(stderr, "Double \"buffer/burst\" spec\n");
82                                 return -1;
83                         }
84                         if (get_size_and_cell(&buffer, &Rcell_log, *argv) < 0) {
85                                 explain1("buffer");
86                                 return -1;
87                         }
88                         ok++;
89                 } else if (strcmp(*argv, "mtu") == 0 ||
90                            strcmp(*argv, "minburst") == 0) {
91                         NEXT_ARG();
92                         if (mtu) {
93                                 fprintf(stderr, "Double \"mtu/minburst\" spec\n");
94                                 return -1;
95                         }
96                         if (get_size_and_cell(&mtu, &Pcell_log, *argv) < 0) {
97                                 explain1("mtu");
98                                 return -1;
99                         }
100                         ok++;
101                 } else if (strcmp(*argv, "mpu") == 0) {
102                         NEXT_ARG();
103                         if (mpu) {
104                                 fprintf(stderr, "Double \"mpu\" spec\n");
105                                 return -1;
106                         }
107                         if (get_size(&mpu, *argv)) {
108                                 explain1("mpu");
109                                 return -1;
110                         }
111                         ok++;
112                 } else if (strcmp(*argv, "rate") == 0) {
113                         NEXT_ARG();
114                         if (opt.rate.rate) {
115                                 fprintf(stderr, "Double \"rate\" spec\n");
116                                 return -1;
117                         }
118                         if (get_rate(&opt.rate.rate, *argv)) {
119                                 explain1("rate");
120                                 return -1;
121                         }
122                         ok++;
123                 } else if (matches(*argv, "peakrate") == 0) {
124                         NEXT_ARG();
125                         if (opt.peakrate.rate) {
126                                 fprintf(stderr, "Double \"peakrate\" spec\n");
127                                 return -1;
128                         }
129                         if (get_rate(&opt.peakrate.rate, *argv)) {
130                                 explain1("peakrate");
131                                 return -1;
132                         }
133                         ok++;
134                 } else if (matches(*argv, "overhead") == 0) {
135                         NEXT_ARG();
136                         if (overhead) {
137                                 fprintf(stderr, "Double \"overhead\" spec\n");
138                                 return -1;
139                         }
140                         if (get_u16(&overhead, *argv, 10)) {
141                                 explain1("overhead"); return -1;
142                         }
143                 } else if (matches(*argv, "linklayer") == 0) {
144                         NEXT_ARG();
145                         if (get_linklayer(&linklayer, *argv)) {
146                                 explain1("linklayer"); return -1;
147                         }
148                 } else if (strcmp(*argv, "help") == 0) {
149                         explain();
150                         return -1;
151                 } else {
152                         fprintf(stderr, "What is \"%s\"?\n", *argv);
153                         explain();
154                         return -1;
155                 }
156                 argc--; argv++;
157         }
158
159         if (!ok) {
160                 explain();
161                 return -1;
162         }
163
164         if (opt.rate.rate == 0 || !buffer) {
165                 fprintf(stderr, "Both \"rate\" and \"burst\" are required.\n");
166                 return -1;
167         }
168         if (opt.peakrate.rate) {
169                 if (!mtu) {
170                         fprintf(stderr, "\"mtu\" is required, if \"peakrate\" is requested.\n");
171                         return -1;
172                 }
173         }
174
175         if (opt.limit == 0 && latency == 0) {
176                 fprintf(stderr, "Either \"limit\" or \"latency\" are required.\n");
177                 return -1;
178         }
179
180         if (opt.limit == 0) {
181                 double lim = opt.rate.rate*(double)latency/TIME_UNITS_PER_SEC + buffer;
182                 if (opt.peakrate.rate) {
183                         double lim2 = opt.peakrate.rate*(double)latency/TIME_UNITS_PER_SEC + mtu;
184                         if (lim2 < lim)
185                                 lim = lim2;
186                 }
187                 opt.limit = lim;
188         }
189
190         opt.rate.mpu      = mpu;
191         opt.rate.overhead = overhead;
192         if (tc_calc_rtable(&opt.rate, rtab, Rcell_log, mtu, linklayer) < 0) {
193                 fprintf(stderr, "TBF: failed to calculate rate table.\n");
194                 return -1;
195         }
196         opt.buffer = tc_calc_xmittime(opt.rate.rate, buffer);
197
198         if (opt.peakrate.rate) {
199                 opt.peakrate.mpu      = mpu;
200                 opt.peakrate.overhead = overhead;
201                 if (tc_calc_rtable(&opt.peakrate, ptab, Pcell_log, mtu, linklayer) < 0) {
202                         fprintf(stderr, "TBF: failed to calculate peak rate table.\n");
203                         return -1;
204                 }
205                 opt.mtu = tc_calc_xmittime(opt.peakrate.rate, mtu);
206         }
207
208         tail = NLMSG_TAIL(n);
209         addattr_l(n, 1024, TCA_OPTIONS, NULL, 0);
210         addattr_l(n, 2024, TCA_TBF_PARMS, &opt, sizeof(opt));
211         addattr_l(n, 3024, TCA_TBF_RTAB, rtab, 1024);
212         if (opt.peakrate.rate)
213                 addattr_l(n, 4096, TCA_TBF_PTAB, ptab, 1024);
214         tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail;
215         return 0;
216 }
217
218 static int tbf_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
219 {
220         struct rtattr *tb[TCA_TBF_PTAB+1];
221         struct tc_tbf_qopt *qopt;
222         double buffer, mtu;
223         double latency;
224         SPRINT_BUF(b1);
225         SPRINT_BUF(b2);
226
227         if (opt == NULL)
228                 return 0;
229
230         parse_rtattr_nested(tb, TCA_TBF_PTAB, opt);
231
232         if (tb[TCA_TBF_PARMS] == NULL)
233                 return -1;
234
235         qopt = RTA_DATA(tb[TCA_TBF_PARMS]);
236         if (RTA_PAYLOAD(tb[TCA_TBF_PARMS])  < sizeof(*qopt))
237                 return -1;
238         fprintf(f, "rate %s ", sprint_rate(qopt->rate.rate, b1));
239         buffer = tc_calc_xmitsize(qopt->rate.rate, qopt->buffer);
240         if (show_details) {
241                 fprintf(f, "burst %s/%u mpu %s ", sprint_size(buffer, b1),
242                         1<<qopt->rate.cell_log, sprint_size(qopt->rate.mpu, b2));
243         } else {
244                 fprintf(f, "burst %s ", sprint_size(buffer, b1));
245         }
246         if (show_raw)
247                 fprintf(f, "[%08x] ", qopt->buffer);
248         if (qopt->peakrate.rate) {
249                 fprintf(f, "peakrate %s ", sprint_rate(qopt->peakrate.rate, b1));
250                 if (qopt->mtu || qopt->peakrate.mpu) {
251                         mtu = tc_calc_xmitsize(qopt->peakrate.rate, qopt->mtu);
252                         if (show_details) {
253                                 fprintf(f, "mtu %s/%u mpu %s ", sprint_size(mtu, b1),
254                                         1<<qopt->peakrate.cell_log, sprint_size(qopt->peakrate.mpu, b2));
255                         } else {
256                                 fprintf(f, "minburst %s ", sprint_size(mtu, b1));
257                         }
258                         if (show_raw)
259                                 fprintf(f, "[%08x] ", qopt->mtu);
260                 }
261         }
262
263         if (show_raw)
264                 fprintf(f, "limit %s ", sprint_size(qopt->limit, b1));
265
266         latency = TIME_UNITS_PER_SEC*(qopt->limit/(double)qopt->rate.rate) - tc_core_tick2time(qopt->buffer);
267         if (qopt->peakrate.rate) {
268                 double lat2 = TIME_UNITS_PER_SEC*(qopt->limit/(double)qopt->peakrate.rate) - tc_core_tick2time(qopt->mtu);
269                 if (lat2 > latency)
270                         latency = lat2;
271         }
272         fprintf(f, "lat %s ", sprint_time(latency, b1));
273
274         if (qopt->rate.overhead) {
275                 fprintf(f, "overhead %d", qopt->rate.overhead);
276         }
277
278         return 0;
279 }
280
281 struct qdisc_util tbf_qdisc_util = {
282         .id             = "tbf",
283         .parse_qopt     = tbf_parse_opt,
284         .print_qopt     = tbf_print_opt,
285 };
286