]>
Commit | Line | Data |
---|---|---|
1e16bc40 BZ |
1 | diff -urN iproute-2.6.20-070313-orig/tc/Makefile iproute-2.6.20-070313/tc/Makefile |
2 | --- iproute-2.6.20-070313-orig/tc/Makefile 2007-03-13 22:50:56.000000000 +0100 | |
3 | +++ iproute-2.6.20-070313/tc/Makefile 2007-04-15 20:52:33.000000000 +0200 | |
4 | @@ -11,6 +11,7 @@ | |
ca1c0e2c | 5 | TCMODULES += q_tbf.o |
6 | TCMODULES += q_cbq.o | |
58f49aa5 | 7 | TCMODULES += q_netem.o |
ca1c0e2c | 8 | +TCMODULES += q_wrr.o |
8e226f4f AM |
9 | TCMODULES += q_choke.o |
10 | TCMODULES += q_sfb.o | |
ca1c0e2c | 11 | TCMODULES += f_rsvp.o |
12 | TCMODULES += f_u32.o | |
1e16bc40 BZ |
13 | diff -urN iproute-2.6.20-070313-orig/include/linux/pkt_sched.h iproute-2.6.20-070313/include/linux/pkt_sched.h |
14 | --- iproute-2.6.20-070313-orig/include/linux/pkt_sched.h 2007-03-13 22:50:56.000000000 +0100 | |
15 | +++ iproute-2.6.20-070313/include/linux/pkt_sched.h 2007-04-15 20:52:33.000000000 +0200 | |
16 | @@ -466,4 +498,116 @@ | |
1e16bc40 | 17 | #define NETEM_DIST_SCALE 8192 |
cf9419df | 18 | #define NETEM_DIST_MAX 16384 |
1e16bc40 | 19 | |
8db47f55 JB |
20 | +/* WRR section */ |
21 | + | |
22 | +/* Other includes */ | |
23 | +#include <linux/if_ether.h> | |
24 | + | |
25 | +// A sub weight and of a class | |
26 | +// All numbers are represented as parts of (2^64-1). | |
27 | +struct tc_wrr_class_weight { | |
1e16bc40 BZ |
28 | + __u64 val; // Current value (0 is not valid) |
29 | + __u64 decr; // Value pr bytes (2^64-1 is not valid) | |
30 | + __u64 incr; // Value pr seconds (2^64-1 is not valid) | |
31 | + __u64 min; // Minimal value (0 is not valid) | |
32 | + __u64 max; // Minimal value (0 is not valid) | |
33 | + | |
34 | +// The time where the above information was correct: | |
35 | + time_t tim; | |
8db47f55 JB |
36 | +}; |
37 | + | |
1e16bc40 | 38 | +// Packet send when modifying a class: |
8db47f55 | 39 | +struct tc_wrr_class_modf { |
1e16bc40 BZ |
40 | + // Not-valid values are ignored. |
41 | + struct tc_wrr_class_weight weight1; | |
42 | + struct tc_wrr_class_weight weight2; | |
8db47f55 JB |
43 | +}; |
44 | + | |
45 | +// Packet returned when quering a class: | |
46 | +struct tc_wrr_class_stats { | |
1e16bc40 | 47 | + char used; // If this is false the information below is invalid |
8db47f55 | 48 | + |
1e16bc40 | 49 | + struct tc_wrr_class_modf class_modf; |
8db47f55 | 50 | + |
1e16bc40 BZ |
51 | + unsigned char addr[ETH_ALEN]; |
52 | + char usemac; // True if addr is a MAC address, else it is an IP address | |
53 | + // (this value is only for convience, it is always the same | |
54 | + // value as in the qdisc) | |
55 | + int heappos; // Current heap position or 0 if not in heap | |
56 | + __u64 penal_ls; // Penalty value in heap (ls) | |
57 | + __u64 penal_ms; // Penalty value in heap (ms) | |
8db47f55 JB |
58 | +}; |
59 | + | |
60 | +// Qdisc-wide penalty information (boolean values - 2 not valid) | |
61 | +struct tc_wrr_qdisc_weight { | |
1e16bc40 BZ |
62 | + char weight_mode; // 0=No automatic change to weight |
63 | + // 1=Decrease normally | |
64 | + // 2=Also multiply with number of machines | |
65 | + // 3=Instead multiply with priority divided | |
66 | + // with priority of the other. | |
67 | + // -1=no change | |
8db47f55 JB |
68 | +}; |
69 | + | |
70 | +// Packet send when modifing a qdisc: | |
71 | +struct tc_wrr_qdisc_modf { | |
1e16bc40 BZ |
72 | + // Not-valid values are ignored: |
73 | + struct tc_wrr_qdisc_weight weight1; | |
74 | + struct tc_wrr_qdisc_weight weight2; | |
8db47f55 JB |
75 | +}; |
76 | + | |
77 | +// Packet send when creating a qdisc: | |
78 | +struct tc_wrr_qdisc_crt { | |
1e16bc40 BZ |
79 | + struct tc_wrr_qdisc_modf qdisc_modf; |
80 | + | |
81 | + char srcaddr; // 1=lookup source, 0=lookup destination | |
82 | + char usemac; // 1=Classify on MAC addresses, 0=classify on IP | |
83 | + char usemasq; // 1=Classify based on masqgrading - only valid | |
84 | + // if usemac is zero | |
85 | + int bands_max; // Maximal number of bands (i.e.: classes) | |
86 | + int proxy_maxconn;// If differnt from 0 then we support proxy remapping | |
87 | + // of packets. And this is the number of maximal | |
88 | + // concurrent proxy connections. | |
8db47f55 JB |
89 | +}; |
90 | + | |
91 | +// Packet returned when quering a qdisc: | |
92 | +struct tc_wrr_qdisc_stats { | |
1e16bc40 BZ |
93 | + struct tc_wrr_qdisc_crt qdisc_crt; |
94 | + int proxy_curconn; | |
95 | + int nodes_in_heap; // Current number of bands wanting to send something | |
96 | + int bands_cur; // Current number of bands used (i.e.: MAC/IP addresses seen) | |
97 | + int bands_reused; // Number of times this band has been reused. | |
98 | + int packets_requed; // Number of times packets have been requeued. | |
99 | + __u64 priosum; // Sum of priorities in heap where 1 is 2^32 | |
8db47f55 JB |
100 | +}; |
101 | + | |
102 | +struct tc_wrr_qdisc_modf_std { | |
1e16bc40 BZ |
103 | + // This indicates which of the tc_wrr_qdisc_modf structers this is: |
104 | + char proxy; // 0=This struct | |
8db47f55 | 105 | + |
1e16bc40 BZ |
106 | + // Should we also change a class? |
107 | + char change_class; | |
8db47f55 | 108 | + |
1e16bc40 BZ |
109 | + // Only valid if change_class is false |
110 | + struct tc_wrr_qdisc_modf qdisc_modf; | |
111 | + | |
112 | + // Only valid if change_class is true: | |
113 | + unsigned char addr[ETH_ALEN]; // Class to change (non-used bytes should be 0) | |
114 | + struct tc_wrr_class_modf class_modf; // The change | |
8db47f55 JB |
115 | +}; |
116 | + | |
117 | +// Used for proxyrempping: | |
118 | +struct tc_wrr_qdisc_modf_proxy { | |
1e16bc40 BZ |
119 | + // This indicates which of the tc_wrr_qdisc_modf structers this is: |
120 | + char proxy; // 1=This struct | |
121 | + | |
122 | + // This is 1 if the proxyremap information should be reset | |
123 | + char reset; | |
124 | + | |
125 | + // changec is the number of elements in changes. | |
126 | + int changec; | |
127 | + | |
128 | + // This is an array of type ProxyRemapBlock: | |
129 | + long changes[0]; | |
8db47f55 | 130 | +}; |
1e16bc40 | 131 | + |
cf9419df | 132 | /* DRR */ |
1e16bc40 BZ |
133 | |
134 | diff -urN iproute-2.6.20-070313-orig/tc/q_wrr.c iproute-2.6.20-070313/tc/q_wrr.c | |
135 | --- iproute-2.6.20-070313-orig/tc/q_wrr.c 1970-01-01 01:00:00.000000000 +0100 | |
136 | +++ iproute-2.6.20-070313/tc/q_wrr.c 2007-04-15 20:52:33.000000000 +0200 | |
137 | @@ -0,0 +1,322 @@ | |
138 | +#include <stdio.h> | |
139 | +#include <stdlib.h> | |
140 | +#include <unistd.h> | |
141 | +#include <syslog.h> | |
142 | +#include <fcntl.h> | |
143 | +#include <sys/socket.h> | |
144 | +#include <netinet/in.h> | |
145 | +#include <arpa/inet.h> | |
146 | +#include <string.h> | |
147 | +#include <math.h> | |
148 | + | |
149 | +#include "utils.h" | |
150 | +#include "tc_util.h" | |
151 | + | |
152 | +#define usage() return(-1) | |
8db47f55 | 153 | + |
ca1c0e2c | 154 | +// Returns -1 on error |
155 | +static int wrr_parse_qdisc_weight(int argc, char** argv, | |
156 | + struct tc_wrr_qdisc_modf* opt) { | |
157 | + int i; | |
158 | + | |
159 | + opt->weight1.weight_mode=-1; | |
160 | + opt->weight2.weight_mode=-1; | |
161 | + | |
162 | + for(i=0; i<argc; i++) { | |
163 | + if(!memcmp(argv[i],"wmode1=",7)) { | |
164 | + opt->weight1.weight_mode=atoi(argv[i]+7); | |
165 | + } else if(!memcmp(argv[i],"wmode2=",7)) { | |
166 | + opt->weight2.weight_mode=atoi(argv[i]+7); | |
167 | + } else { | |
168 | + printf("Usage: ... [wmode1=0|1|2|3] [wmode2=0|1|2|3]\n"); | |
169 | + return -1; | |
170 | + } | |
171 | + } | |
172 | + return 0; | |
173 | +} | |
174 | + | |
175 | +static int wrr_parse_class_modf(int argc, char** argv, | |
176 | + struct tc_wrr_class_modf* modf) { | |
177 | + int i; | |
178 | + | |
179 | + if(argc<1) { | |
180 | + fprintf(stderr, "Usage: ... [weight1=val] [decr1=val] [incr1=val] [min1=val] [max1=val] [val2=val] ...\n"); | |
181 | + fprintf(stderr, " The values can be floating point like 0.42 or divisions like 42/100\n"); | |
182 | + return -1; | |
183 | + } | |
184 | + | |
185 | + // Set meaningless values: | |
186 | + modf->weight1.val=0; | |
187 | + modf->weight1.decr=(__u64)-1; | |
188 | + modf->weight1.incr=(__u64)-1; | |
189 | + modf->weight1.min=0; | |
190 | + modf->weight1.max=0; | |
191 | + modf->weight2.val=0; | |
192 | + modf->weight2.decr=(__u64)-1; | |
193 | + modf->weight2.incr=(__u64)-1; | |
194 | + modf->weight2.min=0; | |
195 | + modf->weight2.max=0; | |
196 | + | |
197 | + // And read values: | |
198 | + for(i=0; i<argc; i++) { | |
199 | + char arg[80]; | |
200 | + char* name,*value1=0,*value2=0; | |
201 | + long double f_val1,f_val2=1,value; | |
202 | + if(strlen(argv[i])>=sizeof(arg)) { | |
203 | + fprintf(stderr,"Argument too long: %s\n",argv[i]); | |
204 | + return -1; | |
205 | + } | |
206 | + strcpy(arg,argv[i]); | |
207 | + | |
208 | + name=strtok(arg,"="); | |
209 | + if(name) value1=strtok(0,"/"); | |
210 | + if(value1) value2=strtok(0,""); | |
211 | + | |
212 | + if(!value1) { | |
213 | + fprintf(stderr,"No = found in argument: %s\n",argv[i]); | |
214 | + return -1; | |
215 | + } | |
216 | + | |
217 | + f_val1=atof(value1); | |
218 | + if(value2) f_val2=atof(value2); | |
219 | + | |
220 | + if(f_val2==0) { | |
221 | + fprintf(stderr,"Division by 0\n"); | |
222 | + return -1; | |
223 | + } | |
224 | + | |
225 | + value=f_val1/f_val2; | |
226 | + if(value>1) value=1; | |
227 | + if(value<0) value=0; | |
228 | + value*=((__u64)-1); | |
229 | + | |
230 | + // And find the value set | |
231 | + if(!strcmp(name,"weight1")) modf->weight1.val=value; | |
232 | + else if(!strcmp(name,"decr1")) modf->weight1.decr=value; | |
233 | + else if(!strcmp(name,"incr1")) modf->weight1.incr=value; | |
234 | + else if(!strcmp(name,"min1")) modf->weight1.min=value; | |
235 | + else if(!strcmp(name,"max1")) modf->weight1.max=value; | |
236 | + else if(!strcmp(name,"weight2")) modf->weight2.val=value; | |
237 | + else if(!strcmp(name,"decr2")) modf->weight2.decr=value; | |
238 | + else if(!strcmp(name,"incr2")) modf->weight2.incr=value; | |
239 | + else if(!strcmp(name,"min2")) modf->weight2.min=value; | |
240 | + else if(!strcmp(name,"max2")) modf->weight2.max=value; | |
241 | + else { | |
242 | + fprintf(stderr,"illegal value: %s\n",name); | |
243 | + return -1; | |
244 | + } | |
245 | + } | |
246 | + | |
247 | + return 0; | |
248 | +} | |
249 | + | |
250 | +static int wrr_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n) | |
251 | +{ | |
252 | + if(n->nlmsg_flags & NLM_F_CREATE) { | |
253 | + // This is a create request: | |
254 | + struct tc_wrr_qdisc_crt opt; | |
255 | + | |
256 | + int sour,dest,ip,mac,masq; | |
257 | + | |
258 | + if(argc<4) { | |
259 | + fprintf(stderr, "Usage: ... wrr sour|dest ip|masq|mac maxclasses proxymaxcon [penalty-setup]\n"); | |
260 | + return -1; | |
261 | + } | |
262 | + | |
263 | + // Read sour/dest: | |
264 | + memset(&opt,0,sizeof(opt)); | |
265 | + sour=!strcmp(argv[0],"sour"); | |
266 | + dest=!strcmp(argv[0],"dest"); | |
267 | + | |
268 | + if(!sour && !dest) { | |
269 | + fprintf(stderr,"sour or dest must be specified\n"); | |
270 | + return -1; | |
271 | + } | |
272 | + | |
273 | + // Read ip/mac | |
274 | + ip=!strcmp(argv[1],"ip"); | |
275 | + mac=!strcmp(argv[1],"mac"); | |
276 | + masq=!strcmp(argv[1],"masq"); | |
277 | + | |
278 | + if(!ip && !mac && !masq) { | |
279 | + fprintf(stderr,"ip, masq or mac must be specified\n"); | |
280 | + return -1; | |
281 | + } | |
282 | + | |
283 | + opt.srcaddr=sour; | |
284 | + opt.usemac=mac; | |
285 | + opt.usemasq=masq; | |
286 | + opt.bands_max=atoi(argv[2]); | |
287 | + | |
288 | + opt.proxy_maxconn=atoi(argv[3]); | |
289 | + | |
290 | + // Read weights: | |
291 | + if(wrr_parse_qdisc_weight(argc-4,argv+4,&opt.qdisc_modf)<0) return -1; | |
292 | + if(opt.qdisc_modf.weight1.weight_mode==-1) opt.qdisc_modf.weight1.weight_mode=0; | |
293 | + if(opt.qdisc_modf.weight2.weight_mode==-1) opt.qdisc_modf.weight2.weight_mode=0; | |
294 | + | |
295 | + addattr_l(n, 1024, TCA_OPTIONS, &opt, sizeof(opt)); | |
296 | + } else { | |
297 | + struct tc_wrr_qdisc_modf_std opt; | |
298 | + char qdisc,class; | |
299 | + | |
300 | + // This is a modify request: | |
301 | + if(argc<1) { | |
302 | + fprintf(stderr,"... qdisc ... or ... class ...\n"); | |
303 | + return -1; | |
304 | + } | |
305 | + | |
306 | + qdisc=!strcmp(argv[0],"qdisc"); | |
307 | + class=!strcmp(argv[0],"class"); | |
308 | + | |
309 | + if(!qdisc && !class) { | |
310 | + fprintf(stderr,"qdisc or class must be specified\n"); | |
311 | + return -1; | |
312 | + } | |
313 | + | |
314 | + argc--; | |
315 | + argv++; | |
316 | + | |
317 | + opt.proxy=0; | |
318 | + | |
319 | + if(qdisc) { | |
320 | + opt.change_class=0; | |
321 | + if(wrr_parse_qdisc_weight(argc, argv, &opt.qdisc_modf)<0) return -1; | |
322 | + } else { | |
323 | + int a0,a1,a2,a3,a4=0,a5=0; | |
324 | + | |
325 | + opt.change_class=1; | |
326 | + | |
327 | + if(argc<1) { | |
328 | + fprintf(stderr,"... <mac>|<ip>|<masq> ...\n"); | |
329 | + return -1; | |
330 | + } | |
331 | + memset(opt.addr,0,sizeof(opt.addr)); | |
332 | + | |
333 | + if((sscanf(argv[0],"%i.%i.%i.%i",&a0,&a1,&a2,&a3)!=4) && | |
334 | + (sscanf(argv[0],"%x:%x:%x:%x:%x:%x",&a0,&a1,&a2,&a3,&a4,&a5)!=6)) { | |
335 | + fprintf(stderr,"Wrong format of mac or ip address\n"); | |
336 | + return -1; | |
337 | + } | |
338 | + | |
339 | + opt.addr[0]=a0; opt.addr[1]=a1; opt.addr[2]=a2; | |
340 | + opt.addr[3]=a3; opt.addr[4]=a4; opt.addr[5]=a5; | |
341 | + | |
342 | + if(wrr_parse_class_modf(argc-1, argv+1, &opt.class_modf)<0) return -1; | |
343 | + } | |
344 | + | |
345 | + addattr_l(n, 1024, TCA_OPTIONS, &opt, sizeof(opt)); | |
346 | + } | |
347 | + return 0; | |
348 | +} | |
349 | + | |
350 | +static int wrr_parse_copt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n) { | |
351 | + struct tc_wrr_class_modf opt; | |
352 | + | |
353 | + memset(&opt,0,sizeof(opt)); | |
354 | + if(wrr_parse_class_modf(argc,argv,&opt)<0) return -1; | |
355 | + | |
356 | + addattr_l(n, 1024, TCA_OPTIONS, &opt, sizeof(opt)); | |
357 | + return 0; | |
358 | +} | |
359 | + | |
360 | +static int wrr_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) | |
361 | +{ | |
362 | + struct tc_wrr_qdisc_stats *qopt; | |
363 | + | |
364 | + if (opt == NULL) | |
365 | + return 0; | |
366 | + | |
367 | + if (RTA_PAYLOAD(opt) < sizeof(*qopt)) | |
368 | + return -1; | |
369 | + qopt = RTA_DATA(opt); | |
370 | + | |
371 | + fprintf(f,"\n (%s/%s) (maxclasses %i) (usedclasses %i) (reused classes %i)\n", | |
372 | + qopt->qdisc_crt.srcaddr ? "sour" : "dest", | |
373 | + qopt->qdisc_crt.usemac ? "mac" : (qopt->qdisc_crt.usemasq ? "masq" : "ip"), | |
374 | + qopt->qdisc_crt.bands_max, | |
375 | + qopt->bands_cur, | |
376 | + qopt->bands_reused | |
377 | + ); | |
378 | + | |
379 | + if(qopt->qdisc_crt.proxy_maxconn) { | |
380 | + fprintf(f," (proxy maxcon %i) (proxy curcon %i)\n", | |
381 | + qopt->qdisc_crt.proxy_maxconn,qopt->proxy_curconn); | |
382 | + } | |
383 | + | |
384 | + fprintf(f," (waiting classes %i) (packets requeued %i) (priosum: %Lg)\n", | |
385 | + qopt->nodes_in_heap, | |
386 | + qopt->packets_requed, | |
387 | + qopt->priosum/((long double)((__u32)-1)) | |
388 | + ); | |
389 | + | |
390 | + fprintf(f," (wmode1 %i) (wmode2 %i) \n", | |
391 | + qopt->qdisc_crt.qdisc_modf.weight1.weight_mode, | |
392 | + qopt->qdisc_crt.qdisc_modf.weight2.weight_mode); | |
393 | + | |
394 | + return 0; | |
395 | +} | |
396 | + | |
397 | +static int wrr_print_copt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) { | |
398 | + struct tc_wrr_class_stats *copt; | |
399 | + long double d=(__u64)-1; | |
400 | + | |
401 | + if (opt == NULL) return 0; | |
402 | + | |
403 | + if (RTA_PAYLOAD(opt) < sizeof(*copt)) | |
404 | + return -1; | |
405 | + copt = RTA_DATA(opt); | |
406 | + | |
407 | + if(!copt->used) { | |
408 | + fprintf(f,"(unused)"); | |
409 | + return 0; | |
410 | + } | |
411 | + | |
412 | + if(copt->usemac) { | |
413 | + fprintf(f,"\n (address: %.2X:%.2X:%.2X:%.2X:%.2X:%.2X)\n", | |
414 | + copt->addr[0],copt->addr[1],copt->addr[2], | |
415 | + copt->addr[3],copt->addr[4],copt->addr[5]); | |
416 | + } else { | |
417 | + fprintf(f,"\n (address: %i.%i.%i.%i)\n",copt->addr[0],copt->addr[1],copt->addr[2],copt->addr[3]); | |
418 | + } | |
419 | + | |
420 | + fprintf(f," (total weight: %Lg) (current position: %i) (counters: %u %u : %u %u)\n", | |
421 | + (copt->class_modf.weight1.val/d)*(copt->class_modf.weight2.val/d), | |
422 | + copt->heappos, | |
423 | + (unsigned)(copt->penal_ms>>32), | |
424 | + (unsigned)(copt->penal_ms & 0xffffffffU), | |
425 | + (unsigned)(copt->penal_ls>>32), | |
426 | + (unsigned)(copt->penal_ls & 0xffffffffU) | |
427 | + ); | |
428 | + | |
429 | + fprintf(f," Pars 1: (weight %Lg) (decr: %Lg) (incr: %Lg) (min: %Lg) (max: %Lg)\n", | |
430 | + copt->class_modf.weight1.val/d, | |
431 | + copt->class_modf.weight1.decr/d, | |
432 | + copt->class_modf.weight1.incr/d, | |
433 | + copt->class_modf.weight1.min/d, | |
434 | + copt->class_modf.weight1.max/d); | |
435 | + | |
436 | + fprintf(f," Pars 2: (weight %Lg) (decr: %Lg) (incr: %Lg) (min: %Lg) (max: %Lg)", | |
437 | + copt->class_modf.weight2.val/d, | |
438 | + copt->class_modf.weight2.decr/d, | |
439 | + copt->class_modf.weight2.incr/d, | |
440 | + copt->class_modf.weight2.min/d, | |
441 | + copt->class_modf.weight2.max/d); | |
442 | + | |
443 | + return 0; | |
444 | +} | |
445 | + | |
446 | +static int wrr_print_xstats(struct qdisc_util *qu, FILE *f, struct rtattr *xstats) | |
447 | +{ | |
448 | + return 0; | |
449 | +} | |
450 | + | |
451 | + | |
080dc5df | 452 | +struct qdisc_util wrr_qdisc_util = { |
1e16bc40 BZ |
453 | + .id = "wrr", |
454 | + .parse_qopt = wrr_parse_opt, | |
455 | + .print_qopt = wrr_print_opt, | |
456 | + .print_xstats = wrr_print_xstats, | |
457 | + .parse_copt = wrr_parse_copt, | |
458 | + .print_copt = wrr_print_copt | |
ca1c0e2c | 459 | +}; |