1 --- linux-2.6.4/include/linux/pkt_sched.h.orig 2004-04-02 23:46:35.869438752 +0200
2 +++ linux-2.6.4/include/linux/pkt_sched.h 2004-04-02 23:59:09.936803088 +0200
5 #define TCA_ATM_MAX TCA_ATM_STATE
10 +#include <linux/if_ether.h>
12 +// A sub weight and of a class
13 +// All numbers are represented as parts of (2^64-1).
14 +struct tc_wrr_class_weight {
15 + __u64 val; // Current value (0 is not valid)
16 + __u64 decr; // Value pr bytes (2^64-1 is not valid)
17 + __u64 incr; // Value pr seconds (2^64-1 is not valid)
18 + __u64 min; // Minimal value (0 is not valid)
19 + __u64 max; // Minimal value (0 is not valid)
21 + // The time where the above information was correct:
25 +// Pakcet send when modifying a class:
26 +struct tc_wrr_class_modf {
27 + // Not-valid values are ignored.
28 + struct tc_wrr_class_weight weight1;
29 + struct tc_wrr_class_weight weight2;
32 +// Packet returned when quering a class:
33 +struct tc_wrr_class_stats {
34 + char used; // If this is false the information below is invalid
36 + struct tc_wrr_class_modf class_modf;
38 + unsigned char addr[ETH_ALEN];
39 + char usemac; // True if addr is a MAC address, else it is an IP address
40 + // (this value is only for convience, it is always the same
41 + // value as in the qdisc)
42 + int heappos; // Current heap position or 0 if not in heap
43 + __u64 penal_ls; // Penalty value in heap (ls)
44 + __u64 penal_ms; // Penalty value in heap (ms)
47 +// Qdisc-wide penalty information (boolean values - 2 not valid)
48 +struct tc_wrr_qdisc_weight {
49 + char weight_mode; // 0=No automatic change to weight
50 + // 1=Decrease normally
51 + // 2=Also multiply with number of machines
52 + // 3=Instead multiply with priority divided
53 + // with priority of the other.
57 +// Packet send when modifing a qdisc:
58 +struct tc_wrr_qdisc_modf {
59 + // Not-valid values are ignored:
60 + struct tc_wrr_qdisc_weight weight1;
61 + struct tc_wrr_qdisc_weight weight2;
64 +// Packet send when creating a qdisc:
65 +struct tc_wrr_qdisc_crt {
66 + struct tc_wrr_qdisc_modf qdisc_modf;
68 + char srcaddr; // 1=lookup source, 0=lookup destination
69 + char usemac; // 1=Classify on MAC addresses, 0=classify on IP
70 + char usemasq; // 1=Classify based on masqgrading - only valid
71 + // if usemac is zero
72 + int bands_max; // Maximal number of bands (i.e.: classes)
73 + int proxy_maxconn; // If differnt from 0 then we support proxy remapping
74 + // of packets. And this is the number of maximal
75 + // concurrent proxy connections.
78 +// Packet returned when quering a qdisc:
79 +struct tc_wrr_qdisc_stats {
80 + struct tc_wrr_qdisc_crt qdisc_crt;
82 + int nodes_in_heap; // Current number of bands wanting to send something
83 + int bands_cur; // Current number of bands used (i.e.: MAC/IP addresses seen)
84 + int bands_reused; // Number of times this band has been reused.
85 + int packets_requed; // Number of times packets have been requeued.
86 + __u64 priosum; // Sum of priorities in heap where 1 is 2^32
89 +struct tc_wrr_qdisc_modf_std {
90 + // This indicates which of the tc_wrr_qdisc_modf structers this is:
91 + char proxy; // 0=This struct
93 + // Should we also change a class?
96 + // Only valid if change_class is false
97 + struct tc_wrr_qdisc_modf qdisc_modf;
99 + // Only valid if change_class is true:
100 + unsigned char addr[ETH_ALEN]; // Class to change (non-used bytes should be 0)
101 + struct tc_wrr_class_modf class_modf; // The change
104 +// Used for proxyrempping:
105 +struct tc_wrr_qdisc_modf_proxy {
106 + // This indicates which of the tc_wrr_qdisc_modf structers this is:
107 + char proxy; // 1=This struct
109 + // This is 1 if the proxyremap information should be reset
112 + // changec is the number of elements in changes.
115 + // This is an array of type ProxyRemapBlock:
122 diff -uNr linux-2.6.4/net/sched.orig/Kconfig linux-2.6.4/net/sched/Kconfig
123 --- linux-2.6.4/net/sched.orig/Kconfig 2004-04-02 23:46:35.000000000 +0200
124 +++ linux-2.6.4/net/sched/Kconfig 2004-04-03 00:06:53.438340144 +0200
126 To compile this code as a module, choose M here: the
127 module will be called sch_htb.
130 + tristate "WRR packet scheduler"
131 + depends on NET_SCHED
134 tristate "HFSC packet scheduler"
136 diff -uNr linux-2.6.4/net/sched.orig/Makefile linux-2.6.4/net/sched/Makefile
137 --- linux-2.6.4/net/sched.orig/Makefile 2004-04-02 23:46:35.000000000 +0200
138 +++ linux-2.6.4/net/sched/Makefile 2004-04-03 00:05:52.359625520 +0200
140 obj-$(CONFIG_NET_CLS_POLICE) += police.o
141 obj-$(CONFIG_NET_SCH_CBQ) += sch_cbq.o
142 obj-$(CONFIG_NET_SCH_HTB) += sch_htb.o
143 +obj-$(CONFIG_NET_SCH_WRR) += sch_wrr.o
144 obj-$(CONFIG_NET_SCH_CSZ) += sch_csz.o
145 obj-$(CONFIG_NET_SCH_HPFQ) += sch_hpfq.o
146 obj-$(CONFIG_NET_SCH_HFSC) += sch_hfsc.o
147 diff -uNr linux-2.6.4/net/sched.orig/proxydict.c linux-2.6.4/net/sched/proxydict.c
148 --- linux-2.6.4/net/sched.orig/proxydict.c 1970-01-01 01:00:00.000000000 +0100
149 +++ linux-2.6.4/net/sched/proxydict.c 2004-04-03 00:02:21.565671072 +0200
153 +#include <netinet/in.h>
156 +#include "proxyremap.h"
157 +#include "proxydict.h"
160 +/*--------------------------------------------------------------------------
165 +#define hash_fnc(m,server,port,proto) \
166 + (((proto)*7+(server)*13+(port)*5)%m->hash_size)
168 +// Size of hash table given maximal number of connections:
169 +#define hash_size_max_con(max_con) (2*(max_con))
171 +// The memory area we maintain:
180 + // int hash_table[hash_size];
181 + // int next[max_con];
182 + // ProxyRemapBlock info[max_con];
184 + // The idea is the following:
185 + // Given a connection we map it by hash_fnc into hash_table. This gives an
186 + // index in next which contains a -1 terminated linked list of connections
187 + // mapping to that hash value.
189 + // The entries in next not allocated is also in linked list where
190 + // the first free index is free_first.
193 +#define Memory(m) ((memory*)m)
194 +#define Hash_table(m) ((int*)(((char*)m)+sizeof(memory)))
195 +#define Next(m) ((int*)(((char*)m)+sizeof(memory)+ \
196 + sizeof(int)*((memory*)m)->hash_size))
197 +#define Info(m) ((ProxyRemapBlock*)(((char*)m)+ \
199 + sizeof(int)*((memory*)m)->hash_size+\
200 + sizeof(int)*((memory*)m)->max_con \
203 +int proxyGetMemSize(int max_con) {
204 + return sizeof(memory)+
205 + sizeof(int)*hash_size_max_con(max_con)+
206 + sizeof(int)*max_con+
207 + sizeof(ProxyRemapBlock)*max_con;
210 +void proxyInitMem(void* data, int max_con) {
212 + memory* m=Memory(data);
213 + m->max_con=max_con;
215 + m->hash_size=hash_size_max_con(max_con);
219 + int* hash_table=Hash_table(data);
220 + int* next=Next(data);
223 + // Init the hash table:
224 + for(i=0; i<m->hash_size; i++) hash_table[i]=-1;
226 + // Init the free-list
227 + for(i=0; i<m->max_con; i++) next[i]=i+1;
232 +int proxyGetCurConn(void* data) {
233 + return Memory(data)->cur_con;
236 +int proxyGetMaxConn(void* data) {
237 + return Memory(data)->max_con;
240 +ProxyRemapBlock* proxyLookup(void* data, unsigned ipaddr, unsigned short port, char proto) {
241 + memory* m=Memory(data);
242 + int* hash_table=Hash_table(m);
244 + ProxyRemapBlock* info=Info(m);
247 + for(i=hash_table[hash_fnc(m,ipaddr,port,proto)]; i!=-1; i=next[i]) {
248 + if(info[i].proto==proto &&
249 + info[i].sport==port &&
250 + info[i].saddr==ipaddr) return &info[i];
256 +int proxyConsumeBlock(void* data, ProxyRemapBlock* blk) {
257 + memory* m=Memory(data);
258 + int* hash_table=Hash_table(m);
260 + ProxyRemapBlock* info=Info(m);
261 + int hash=hash_fnc(m,blk->saddr,blk->sport,blk->proto);
265 + if(m->cur_con == m->max_con) return -1;
267 + // Insert the block at a free entry:
268 + info[m->free_first]=*blk;
271 + foo=next[m->free_first];
273 + // And insert it in the hash tabel:
274 + next[m->free_first]=hash_table[hash];
275 + hash_table[hash]=m->free_first;
281 + for(toupdate=&hash_table[hash];
283 + toupdate=&next[*toupdate]) {
284 + if(info[*toupdate].proto==blk->proto &&
285 + info[*toupdate].sport==blk->sport &&
286 + info[*toupdate].saddr==blk->saddr) break;
288 + if(*toupdate==-1) return -1;
292 + // Delete it from the hashing list:
293 + *toupdate=next[*toupdate];
295 + // And put it on the free list:
296 + next[foo]=m->free_first;
304 diff -uNr linux-2.6.4/net/sched.orig/proxydict.h linux-2.6.4/net/sched/proxydict.h
305 --- linux-2.6.4/net/sched.orig/proxydict.h 1970-01-01 01:00:00.000000000 +0100
306 +++ linux-2.6.4/net/sched/proxydict.h 2004-04-03 00:02:21.567670768 +0200
312 +/*--------------------------------------------------------------------------
313 +This is common code for for handling the tabels containing information about
314 +which proxyserver connections are associated with which machines..
317 +// Returns the number of bytes that should be available in the area
318 +// maintained by this module given the maximal number of concurrent
320 +int proxyGetMemSize(int max_connections);
322 +// Initializes a memory area to use. There must be as many bytes
323 +// available as returned by getMemSize.
324 +void proxyInitMem(void* data, int max_connections);
327 +int proxyGetCurConn(void* data); // Returns current number of connections
328 +int proxyMaxCurConn(void* data); // Returns maximal number of connections
330 +// This is called to open and close conenctions. Returns -1 if
331 +// a protocol error occores (i.e.: If it is discovered)
332 +int proxyConsumeBlock(void* data, ProxyRemapBlock*);
334 +// Returns the RemapBlock associated with this connection or 0:
335 +ProxyRemapBlock* proxyLookup(void* data, unsigned ipaddr, unsigned short port, char proto);
340 diff -uNr linux-2.6.4/net/sched.orig/proxyremap.h linux-2.6.4/net/sched/proxyremap.h
341 --- linux-2.6.4/net/sched.orig/proxyremap.h 1970-01-01 01:00:00.000000000 +0100
342 +++ linux-2.6.4/net/sched/proxyremap.h 2004-04-03 00:02:21.568670616 +0200
344 +#ifndef PROXYREMAP_H
345 +#define PROXYREMAP_H
347 +// This describes the information that is written in proxyremap.log and which
348 +// are used in the communication between proxyremapserver and proxyremapclient.
349 +// Everything is in network order.
351 +// First this header is send:
352 +#define PROXY_WELCOME_LINE "ProxyRemap 1.02. This is a binary protocol.\r\n"
354 +// Then this block is send every time a connection is opened or closed.
355 +// Note how it is alligned to use small space usage - arrays of this
356 +// structure are saved in many places.
358 + // Server endpoint of connection:
360 + unsigned short sport;
362 + // IP protocol for this connection (typically udp or tcp):
363 + unsigned char proto;
365 + // Is the connection opened or closed?
366 + unsigned char open;
368 + // Client the packets should be accounted to:
370 + unsigned char macaddr[6]; // Might be 0.
372 + // An informal two-charecter code from the proxyserver. Used for debugging.
377 diff -uNr linux-2.6.4/net/sched.orig/sch_wrr.c linux-2.6.4/net/sched/sch_wrr.c
378 --- linux-2.6.4/net/sched.orig/sch_wrr.c 1970-01-01 01:00:00.000000000 +0100
379 +++ linux-2.6.4/net/sched/sch_wrr.c 2004-04-03 00:02:21.574669704 +0200
381 +/*-----------------------------------------------------------------------------
382 +Weighted Round Robin scheduler.
384 +Written by Christian Worm Mortensen, cworm@it-c.dk.
388 +This module implements a weighted round robin queue with build-in classifier.
389 +The classifier currently map each MAC or IP address (configurable either MAC
390 +or IP and either source or destination) to different classes. Each such class
391 +is called a band. Whan using MAC addresses only bridged packets can be
392 +classified other packets go to a default MAC address.
394 +Each band has a weight value, where 0<weight<=1. The bandwidth each band
395 +get is proportional to the weight as can be deduced from the next section.
400 +Each band has a penalty value. Bands having something to sent are kept in
401 +a heap according to this value. The band with the lowest penalty value
402 +is in the root of the heap. The penalty value is a 128 bit number. Initially
403 +no bands are in the heap.
405 +Two global 64 bit values counter_low_penal and couter_high_penal are initialized
406 +to 0 and to 2^63 respectively.
409 + The packet is inserted in the queue for the band it belongs to. If the band
410 + is not in the heap it is inserted into it. In this case, the upper 64 bits
411 + of its penalty value is set to the same as for the root-band of the heap.
412 + If the heap is empty 0 is used. The lower 64 bit is set to couter_low_penal
413 + and couter_low_penal is incremented by 1.
416 + If the heap is empty we have nothing to send.
418 + If the root band has a non-empty queue a packet is dequeued from that.
419 + The upper 64 bit of the penalty value of the band is incremented by the
420 + packet size divided with the weight of the band. The lower 64 bit is set to
421 + couter_high_penal and couter_high_penal is incremented by 1.
423 + If the root element for some reason has an empty queue it is removed from
424 + the heap and we try to dequeue again.
426 +The effect of the heap and the upper 64 bit of the penalty values is to
427 +implement a weighted round robin queue. The effect of counter_low_penal,
428 +counter_high_penal and the lower 64 bit of the penalty value is primarily to
429 +stabilize the queue and to give better quality of service to machines only
430 +sending a packet now and then. For example machines which have a single
431 +interactive connection such as telnet or simple text chatting.
436 +The weight value can be changed dynamically by the queue itself. The weight
437 +value and how it is changed is described by the two members weight1 and
438 +weight2 which has type tc_wrr_class_weight and which are in each class. And
439 +by the two integer value members of the qdisc called penalfact1 and penalfact2.
440 +The structure is defined as:
442 + struct tc_wrr_class_weight {
443 + // All are represented as parts of (2^64-1).
444 + __u64 val; // Current value (0 is not valid)
445 + __u64 decr; // Value pr bytes (2^64-1 is not valid)
446 + __u64 incr; // Value pr seconds (2^64-1 is not valid)
447 + __u64 min; // Minimal value (0 is not valid)
448 + __u64 max; // Minimal value (0 is not valid)
450 + // The time where the above information was correct:
454 +The weight value used by the dequeue operations is calculated as
455 +weight1.val*weight2.val. weight1 and weight2 and handled independently and in the
456 +same way as will be described now.
458 +Every second, the val parameter is incremented by incr.
460 +Every time a packet is transmitted the value is increment by decr times
461 +the packet size. Depending on the value of the weight_mode parameter it
462 +is also mulitplied with other numbers. This makes it possible to give
463 +penalty to machines transferring much data.
465 +-----------------------------------------------------------------------------*/
467 +#include <linux/config.h>
468 +#include <linux/module.h>
469 +#include <asm/uaccess.h>
470 +#include <asm/system.h>
471 +#include <asm/bitops.h>
472 +#include <linux/types.h>
473 +#include <linux/kernel.h>
474 +#include <linux/vmalloc.h>
475 +#include <linux/sched.h>
476 +#include <linux/string.h>
477 +#include <linux/mm.h>
478 +#include <linux/socket.h>
479 +#include <linux/sockios.h>
480 +#include <linux/in.h>
481 +#include <linux/errno.h>
482 +#include <linux/interrupt.h>
483 +#include <linux/if_ether.h>
484 +#include <linux/inet.h>
485 +#include <linux/netdevice.h>
486 +#include <linux/etherdevice.h>
487 +#include <linux/notifier.h>
489 +#include <net/route.h>
490 +#include <linux/skbuff.h>
491 +#include <net/sock.h>
492 +#include <net/pkt_sched.h>
494 +#include <linux/if_arp.h>
495 +#include <linux/version.h>
497 +// There seems to be problems when calling functions from userspace when
498 +// using vmalloc and vfree.
499 +//#define my_malloc(size) vmalloc(size)
500 +//#define my_free(ptr) vfree(ptr)
501 +#define my_malloc(size) kmalloc(size,GFP_KERNEL)
502 +#define my_free(ptr) kfree(ptr)
504 +// Kernel depend stuff:
505 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
510 + #define LOCK_START start_bh_atomic();
511 + #define LOCK_END end_bh_atomic();
512 + #define ENQUEUE_SUCCESS 1
513 + #define ENQUEUE_FAIL 0
514 + #ifdef CONFIG_IP_MASQUERADE
515 + #include <net/ip_masq.h>
516 + #define MASQ_SUPPORT
519 + #define LOCK_START sch_tree_lock(sch);
520 + #define LOCK_END sch_tree_unlock(sch);
521 + #define ENQUEUE_SUCCESS 0
522 + #define ENQUEUE_FAIL NET_XMIT_DROP
523 + #ifdef CONFIG_NETFILTER
524 + #include <linux/netfilter_ipv4/ip_conntrack.h>
525 + #define MASQ_SUPPORT
529 +#include "proxydict.c"
531 +// The penalty (priority) type:
532 +typedef u64 penalty_base_t;
533 +#define penalty_base_t_max ((penalty_base_t)-1)
534 +typedef struct penalty_t {
538 +#define penalty_leq(a,b) (a.ms<b.ms || (a.ms==b.ms && a.ls<=b.ls))
539 +#define penalty_le(a,b) (a.ms<b.ms || (a.ms==b.ms && a.ls<b.ls))
540 +static penalty_t penalty_max={penalty_base_t_max,penalty_base_t_max};
542 +//-----------------------------------------------------------------------------
546 +struct heap_element;
548 +// Initializes an empty heap:
549 +// he: A pointer to an unintialized heap structure identifying the heap
550 +// size: Maximal number of elements the heap can contain
551 +// poll: An array of size "size" used by the heap.
552 +static void heap_init(struct heap* he,int size, struct heap_element* poll);
554 +// Each element in the heap is identified by a user-assigned id which
555 +// should be a non negative integer less than the size argument
556 +// given to heap_init.
557 +static void heap_insert(struct heap*, int id, penalty_t);
558 +static void heap_remove(struct heap*, int id);
559 +static void heap_set_penalty(struct heap*, int id, penalty_t);
561 +// Retreviewing information:
562 +static char heap_empty(struct heap*); // Heap empty?
563 +static char heap_contains(struct heap*, int id); // Does heap contain
565 +static int heap_root(struct heap*); // Returns the id of the root
566 +static penalty_t heap_get_penalty(struct heap*, int id); // Returns penaly
569 +//--------------------
570 +// Heap implementation
572 +struct heap_element {
574 + int id; // The user-assigned id of this element
575 + int id2idx; // Maps from user-assigned ids to indices in root_1
579 + struct heap_element* root_1;
583 +// Heap implementation:
584 +static void heap_init(struct heap* h, int size, struct heap_element* poll) {
590 + for(i=0; i<size; i++) poll[i].id2idx=0;
593 +static char heap_empty(struct heap* h) {
594 + return h->elements==0;
597 +static char heap_contains(struct heap* h, int id) {
598 + return h->root_1[id+1].id2idx!=0;
601 +static int heap_root(struct heap* h) {
602 + return h->root_1[1].id;
605 +static penalty_t heap_get_penalty(struct heap* h, int id) {
606 + return h->root_1[ h->root_1[id+1].id2idx ].penalty;
609 +static void heap_penalty_changed_internal(struct heap* h,int idx);
611 +static void heap_set_penalty(struct heap* h, int id, penalty_t p) {
612 + int idx=h->root_1[id+1].id2idx;
613 + h->root_1[idx].penalty=p;
614 + heap_penalty_changed_internal(h,idx);
617 +static void heap_insert(struct heap* h, int id, penalty_t p) {
618 + // Insert at the end of the heap:
620 + h->root_1[h->elements].id=id;
621 + h->root_1[h->elements].penalty=p;
622 + h->root_1[id+1].id2idx=h->elements;
624 + // And put it in the right position:
625 + heap_penalty_changed_internal(h,h->elements);
628 +static void heap_remove(struct heap* h, int id) {
629 + int idx=h->root_1[id+1].id2idx;
631 + h->root_1[id+1].id2idx=0;
633 + if(h->elements==idx) { h->elements--; return; }
635 + mvid=h->root_1[h->elements].id;
636 + h->root_1[idx].id=mvid;
637 + h->root_1[idx].penalty=h->root_1[h->elements].penalty;
638 + h->root_1[mvid+1].id2idx=idx;
641 + heap_penalty_changed_internal(h,idx);
644 +static void heap_swap(struct heap* h, int idx0, int idx1) {
650 + tmp_p=h->root_1[idx0].penalty;
651 + tmp_id=h->root_1[idx0].id;
652 + h->root_1[idx0].penalty=h->root_1[idx1].penalty;
653 + h->root_1[idx0].id=h->root_1[idx1].id;
654 + h->root_1[idx1].penalty=tmp_p;
655 + h->root_1[idx1].id=tmp_id;
657 + // Update reverse pointers:
658 + id0=h->root_1[idx0].id;
659 + id1=h->root_1[idx1].id;
660 + h->root_1[id0+1].id2idx=idx0;
661 + h->root_1[id1+1].id2idx=idx1;
664 +static void heap_penalty_changed_internal(struct heap* h,int cur) {
665 + if(cur==1 || penalty_leq(h->root_1[cur>>1].penalty,h->root_1[cur].penalty)) {
666 + // We are in heap order upwards - so we should move the element down
670 + penalty_t pen_c=h->root_1[cur].penalty;
671 + penalty_t pen_0=nxt0<=h->elements ? h->root_1[nxt0].penalty : penalty_max;
672 + penalty_t pen_1=nxt1<=h->elements ? h->root_1[nxt1].penalty : penalty_max;
674 + if(penalty_le(pen_0,pen_c) && penalty_leq(pen_0,pen_1)) {
675 + // Swap with child 0:
676 + heap_swap(h,cur,nxt0);
678 + } else if(penalty_le(pen_1,pen_c)) {
679 + // Swap with child 1:
680 + heap_swap(h,cur,nxt1);
683 + // Heap in heap order:
688 + // We are not in heap order upwards (and thus we must be it downwards).
690 + while(cur!=1) { // While not root
692 + if(penalty_leq(h->root_1[nxt].penalty,h->root_1[cur].penalty)) return;
693 + heap_swap(h,cur,nxt);
699 +//-----------------------------------------------------------------------------
700 +// Classification based on MAC or IP adresses. Note that of historical reason
701 +// these are prefixed with mac_ since originally only MAC bases classification
704 +// This code should be in a separate filter module - but it isn't.
710 +// Initialices/destroys the structure we maintain.
711 +// Returns -1 on error
712 +static int mac_init(struct mac_head*, int max_macs, char srcaddr,
713 + char usemac, char usemasq, void* proxyremap);
714 +static void mac_done(struct mac_head*);
715 +static void mac_reset(struct mac_head*);
717 +// Classify a packet. Returns a number n where 0<=n<max_macs. Or -1 if
718 +// the packet should be dropped.
719 +static int mac_classify(struct mac_head*, struct sk_buff *skb);
725 + unsigned char addr[ETH_ALEN]; // Address of this band (last two are 0 on IP)
726 + unsigned long lastused; // Last time a packet was encountered
727 + int class; // Classid of this band (0<=classid<max_macs)
730 +static int mac_compare(const void* a, const void* b) {
731 + return memcmp(a,b,ETH_ALEN);
735 + int mac_max; // Maximal number of MAC addresses/classes allowed
736 + int mac_cur; // Current number of MAC addresses/classes
737 + int mac_reused; // Number of times we have reused a class with a new
740 + char srcaddr; // True if we classify on the source address of packets,
741 + // else we use destination address.
742 + char usemac; // If true we use mac, else we use IP
743 + char usemasq; // If true we try to demasqgrade
744 + struct mac_addr* macs; // Allocated mac_max elements, used max_cur
745 + char* cls2mac; // Mapping from classnumbers to addresses -
746 + // there is 6 bytes in each entry
748 + void* proxyremap; // Information on proxy remapping of data or 0
751 +// This is as the standard C library function with the same name:
752 +static const void* bsearch(const void* key, const void* base, int nmemb,
754 + int (*compare)(const void*, const void*)) {
759 + if(nmemb<=0) return 0;
762 + m_ptr=((const char*)base)+m_idx*size;
764 + i=compare(key,m_ptr);
765 + if(i<0) // key is less
766 + return bsearch(key,base,m_idx,size,compare);
768 + return bsearch(key,((const char*)m_ptr)+size,nmemb-m_idx-1,size,compare);
773 +static int mac_init(struct mac_head* h, int max_macs, char srcaddr,
774 + char usemac, char usemasq,void* proxyremap) {
778 + h->srcaddr=srcaddr;
780 + h->usemasq=usemasq;
781 + h->mac_max=max_macs;
782 + h->proxyremap=proxyremap;
784 + h->macs=(struct mac_addr*)
785 + my_malloc( sizeof(struct mac_addr)*max_macs);
786 + h->cls2mac=(char*)my_malloc( 6*max_macs);
787 + if(!h->macs || !h->cls2mac) {
788 + if(h->macs) my_free(h->macs);
789 + if(h->cls2mac) my_free(h->cls2mac);
795 +static void mac_done(struct mac_head* h) {
797 + my_free(h->cls2mac);
800 +static void mac_reset(struct mac_head* h) {
806 +static int lookup_mac(struct mac_head* h, unsigned char* addr) {
810 + // First try to find the address in the table:
811 + struct mac_addr* m=(struct mac_addr*)
812 + bsearch(addr,h->macs,h->mac_cur,sizeof(struct mac_addr),mac_compare);
815 + m->lastused=h->incr_time++;
819 + // Okay - the MAC adress was not in table
820 + if(h->mac_cur==h->mac_max) {
821 + // And the table is full - delete the oldest entry:
823 + // Find the oldest entry:
826 + for(i=1; i<h->mac_cur; i++)
827 + if(h->macs[i].lastused < h->macs[lowidx].lastused) lowidx=i;
829 + class=h->macs[lowidx].class;
832 + memmove(&h->macs[lowidx],&h->macs[lowidx+1],
833 + (h->mac_cur-lowidx-1)*sizeof(struct mac_addr));
840 + // The table is now not full - find the position we should put the address in:
841 + for(i=0; i<h->mac_cur; i++) if(mac_compare(addr,&h->macs[i])<0) break;
843 + // We should insert at position i:
844 + memmove(&h->macs[i+1],&h->macs[i],(h->mac_cur-i)*sizeof(struct mac_addr));
846 + memcpy(m->addr,addr,ETH_ALEN);
847 + m->lastused=h->incr_time++;
851 + // Finally update the cls2mac variabel:
852 + memcpy(h->cls2mac+ETH_ALEN*class,addr,ETH_ALEN);
857 +int valid_ip_checksum(struct iphdr* ip, int size) {
858 + __u16 header_len=ip->ihl<<2;
860 + __u16* ipu=(u16*)ip;
863 + // We require 4 bytes in the packet since we access the port numbers:
864 + if((size<header_len) || size<sizeof(struct iphdr)+4) return 0;
866 + for(a=0; a<(header_len>>1); a++, ipu++) {
867 + if(a!=5) { // If not the checksum field
874 + return ip->check==(__u16)~c;
877 +static int mac_classify(struct mac_head* head, struct sk_buff *skb)
879 + // We set this to the address we map to. In case we map to an IP
880 + // address the last two entries are set to 0.
881 + unsigned char addr[ETH_ALEN];
884 + // This is the size of the network part of the packet, I think:
885 + int size=((char*)skb->data+skb->len)-((char*)skb->nh.iph);
887 + // Set a default value for the address:
888 + memset(addr,0,ETH_ALEN);
890 + // Accept IP-ARP traffic with big-enough packets:
891 + if(ntohs(skb->protocol)==ETH_P_ARP &&
892 + ntohs(skb->nh.arph->ar_pro)==ETH_P_IP) {
893 + // Map all ARP trafic to a default adress to make sure
895 + } else if ((ntohs(skb->protocol)==ETH_P_IP) &&
896 + valid_ip_checksum(skb->nh.iph,size)) {
897 + // Accept IP packets which have correct checksum.
899 + // This is the IP header:
900 + struct iphdr* iph=skb->nh.iph;
902 + // And this is the port numbers:
903 + const __u16 *portp = (__u16 *)&(((char *)iph)[iph->ihl*4]);
904 + __u16 sport=portp[0];
905 + __u16 dport=portp[1];
907 + // We will set this to the IP address of the packet that should be
912 + ProxyRemapBlock* prm;
921 + // Update ipaddr if packet is masqgraded:
922 + if(head->usemasq) {
924 + struct ip_masq* src;
927 + // ip_masq_in_get must be called for packets comming from the outside
928 + // to the firewall. We have a a packet which is comming from the
929 + // firewall to the outside - so we switch the parameters:
930 + if((src=ip_masq_in_get(
933 + iph->saddr,sport))) {
934 + // Use masqgraded address:
937 + // It seems like we must put it back:
941 + // Thanks to Rusty Russell for help with the following code:
942 + enum ip_conntrack_info ctinfo;
943 + struct ip_conntrack *ct;
944 + ct = ip_conntrack_get(skb, &ctinfo);
947 + ipaddr=ct->tuplehash[CTINFO2DIR(ctinfo)].tuple.src.ip;
949 + ipaddr=ct->tuplehash[CTINFO2DIR(ctinfo)].tuple.dst.ip;
955 + // Set prm based on ipaddr:
957 + if(head->proxyremap) {
958 + if(head->srcaddr) {
959 + prm=proxyLookup(head->proxyremap,ipaddr,sport,skb->nh.iph->protocol);
961 + prm=proxyLookup(head->proxyremap,ipaddr,dport,skb->nh.iph->protocol);
965 + // And finally set addr to the address:
966 + memset(addr,0,ETH_ALEN);
968 + // This package should be remapped:
970 + memcpy(addr,prm->macaddr,ETH_ALEN);
972 + memcpy(addr,&prm->caddr,sizeof(unsigned));
975 + // This packet should not be remapped:
977 + // We should find MAC address of packet.
978 + // Unfortunatly, this is not always available.
979 + // On bridged packets it always is, however..
981 + if(skb->pkt_bridged) {
982 + if(head->srcaddr) {
983 + memcpy(addr,skb->mac.ethernet->h_source,ETH_ALEN);
985 + memcpy(addr,skb->mac.ethernet->h_dest,ETH_ALEN);
990 + memcpy(addr,&ipaddr,4);
994 + // All other traffic is dropped - this ensures that packets
995 + // we consider probably have valid addresses so we don't
996 + // get to many strange addresses into our table. And that we
997 + // don't use bandwidth on strange packets..
1001 + return lookup_mac(head,addr);
1004 +//-----------------------------------------------------------------------------
1005 +// The qdisc itself
1007 +// Pr-class information.
1008 +struct wrrc_sched_data {
1009 + struct Qdisc* que; // The queue for this class
1010 + struct tc_wrr_class_modf class_modf; // Information about the class.
1012 + // For classes in the heap this is the priority value priosum
1013 + // was updated with for this class:
1017 +// Pr-qdisc information:
1018 +struct wrr_sched_data
1020 + // A heap containing all the bands that will send something
1022 + struct heap_element* poll; // bandc elements
1024 + // The sum of the prioities of the elements in the heap where
1025 + // a priority of 1 is saved as 2^32
1028 + // A class for each band
1029 + struct wrrc_sched_data* bands; // bandc elements
1031 + // Information maintained by the proxydict module of 0 if we
1032 + // have no proxy remapping
1035 + // Always incrementning counters, we always have that any value of
1036 + // counter_low_penal < any value of counter_high_penal.
1037 + penalty_base_t counter_low_penal;
1038 + penalty_base_t counter_high_penal;
1040 + // Penalty updating:
1041 + struct tc_wrr_qdisc_modf qdisc_modf;
1044 + int packets_requed;
1047 + struct mac_head filter;
1048 + int bandc; // Number of bands
1051 +// Priority handling.
1052 +// weight is in interval [0..2^32]
1053 +// priosum has whole numbers in the upper and fragments in the lower 32 bits.
1054 +static void weight_transmit(struct tc_wrr_class_weight* p,
1055 + struct tc_wrr_qdisc_weight q,
1056 + unsigned heapsize,
1057 + u64 priosum, u64 weight,
1060 + unsigned long now=jiffies/HZ;
1062 + // Penalty for transmitting:
1067 + switch(q.weight_mode) {
1068 + case 1: change=p->decr*size; break;
1069 + case 2: change=p->decr*size*heapsize; break;
1070 + case 3: // Note: 64 bit division is not always available..
1071 + divisor=(u32)(weight>>16);
1072 + if(divisor<=0) divisor=1;
1073 + change=p->decr*size*(((u32)(priosum>>16))/divisor); break;
1077 + if(p->val>old || p->val<p->min) p->val=p->min;
1079 + // Credit for time went:
1080 + change=(now-p->tim)*p->incr;
1084 + if(p->val<old || p->val>p->max) p->val=p->max;
1087 +static void weight_setdefault(struct tc_wrr_class_weight* p) {
1093 + p->tim=jiffies/HZ;
1096 +static void weight_setvalue(struct tc_wrr_class_weight* dst,
1097 + struct tc_wrr_class_weight* src) {
1099 + dst->val=src->val;
1100 + dst->tim=jiffies/HZ;
1102 + if(src->min!=0) dst->min=src->min;
1103 + if(src->max!=0) dst->max=src->max;
1104 + if(src->decr!=((u64)-1)) dst->decr=src->decr;
1105 + if(src->incr!=((u64)-1)) dst->incr=src->incr;
1106 + if(dst->val<dst->min) dst->val=dst->min;
1107 + if(dst->val>dst->max) dst->val=dst->max;
1110 +static void wrr_destroy(struct Qdisc *sch)
1112 + struct wrr_sched_data *q=(struct wrr_sched_data *)sch->data;
1115 + // Destroy our filter:
1116 + mac_done(&q->filter);
1118 + // Destroy all our childre ques:
1119 + for(i=0; i<q->bandc; i++)
1120 + qdisc_destroy(q->bands[i].que);
1122 + // And free memory:
1123 + my_free(q->bands);
1125 + if(q->proxydict) my_free(q->proxydict);
1127 + MOD_DEC_USE_COUNT;
1130 +static int wrr_init(struct Qdisc *sch, struct rtattr *opt)
1132 + struct wrr_sched_data *q = (struct wrr_sched_data *)sch->data;
1135 + struct tc_wrr_qdisc_crt *qopt;
1138 + if (!opt) return -EINVAL; // Options must be specified
1139 + if (opt->rta_len < RTA_LENGTH(sizeof(*qopt))) return -EINVAL;
1140 + qopt = RTA_DATA(opt);
1142 + if(qopt->bands_max>8192 || qopt->bands_max<2) {
1143 + // More than 8192 queues or less than 2? That cannot be true - it must be
1148 + if(qopt->proxy_maxconn<0 || qopt->proxy_maxconn>20000) {
1149 + // More than this number of maximal concurrent connections is unrealistic
1153 +#ifndef MASQ_SUPPORT
1154 + if(qopt->usemasq) {
1160 + if(qopt->usemac) { // Not supported - please fix this!
1165 + q->bandc=qopt->bands_max;
1166 + q->qdisc_modf=qopt->qdisc_modf;
1168 + // Create structures:
1169 + q->poll=(struct heap_element*)
1170 + my_malloc( sizeof(struct heap_element)*q->bandc);
1171 + q->bands=(struct wrrc_sched_data*)
1172 + my_malloc( sizeof(struct wrrc_sched_data)*q->bandc);
1174 + if(qopt->proxy_maxconn>0) {
1175 + q->proxydict=my_malloc(proxyGetMemSize(qopt->proxy_maxconn));
1180 + // Init mac module:
1181 + maciniterr=mac_init(&q->filter,qopt->bands_max,qopt->srcaddr,
1182 + qopt->usemac,qopt->usemasq,q->proxydict);
1184 + // See if we got the memory we wanted:
1185 + if(!q->poll || !q->bands ||
1186 + (qopt->proxy_maxconn>0 && !q->proxydict) || maciniterr<0) {
1187 + if(q->poll) my_free(q->poll);
1188 + if(q->bands) my_free(q->bands);
1189 + if(q->proxydict) my_free(q->proxydict);
1190 + if(maciniterr>=0) mac_done(&q->filter);
1194 + // Initialize proxy:
1195 + if(q->proxydict) {
1196 + proxyInitMem(q->proxydict,qopt->proxy_maxconn);
1199 + // Initialize values:
1200 + q->counter_low_penal=0;
1201 + q->counter_high_penal=penalty_base_t_max>>1;
1202 + q->packets_requed=0;
1204 + // Initialize empty heap:
1205 + heap_init(&q->h,q->bandc,q->poll);
1208 + // Initialize each band:
1210 + for (i=0; i<q->bandc; i++) {
1211 + weight_setdefault(&q->bands[i].class_modf.weight1);
1212 + weight_setdefault(&q->bands[i].class_modf.weight2);
1214 + struct Qdisc *child=qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops);
1216 + q->bands[i].que = child;
1218 + // Queue couldn't be created :-(
1222 + if(crterr) q->bands[i].que = &noop_qdisc;
1225 + MOD_INC_USE_COUNT;
1236 +static void wrr_reset(struct Qdisc* sch)
1238 + struct wrr_sched_data *q = (struct wrr_sched_data *)sch->data;
1241 + // Reset own values:
1242 + q->counter_low_penal=0;
1243 + q->counter_high_penal=penalty_base_t_max>>1;
1244 + q->packets_requed=0;
1247 + mac_reset(&q->filter);
1249 + // Reinitialize heap:
1250 + heap_init(&q->h,q->bandc,q->poll);
1253 + // Reset all bands:
1254 + for (i=0; i<q->bandc; i++) {
1255 + weight_setdefault(&q->bands[i].class_modf.weight1);
1256 + weight_setdefault(&q->bands[i].class_modf.weight2);
1257 + qdisc_reset(q->bands[i].que);
1260 + // Reset proxy remapping information:
1262 + proxyInitMem(q->proxydict,proxyGetMaxConn(q->proxydict));
1265 +static int wrr_enqueue(struct sk_buff *skb, struct Qdisc* sch)
1267 + struct wrr_sched_data *q = (struct wrr_sched_data *)sch->data;
1268 + int retvalue=ENQUEUE_FAIL;
1270 + // The packet is in skb.
1271 + int band=mac_classify(&q->filter,skb);
1274 + // Enque packet for this band:
1275 + struct Qdisc* qdisc = q->bands[band].que;
1277 + if ((retvalue=qdisc->enqueue(skb, qdisc)) == ENQUEUE_SUCCESS) {
1279 + sch->stats.bytes += skb->len;
1280 + sch->stats.packets++;
1283 + // Insert band into heap if not already there:
1284 + if(!heap_contains(&q->h,band)) {
1286 + if(!heap_empty(&q->h))
1287 + p.ms=heap_get_penalty(&q->h,heap_root(&q->h)).ms;
1290 + p.ls=q->counter_low_penal++;
1291 + heap_insert(&q->h,band,p);
1292 + q->bands[band].priosum_val=
1293 + ((q->bands[band].class_modf.weight1.val>>48)+1)*
1294 + ((q->bands[band].class_modf.weight2.val>>48)+1);
1295 + q->priosum+=q->bands[band].priosum_val;
1299 + // If we decide not to enque it seems like we also need to free the packet:
1303 + if(retvalue!=ENQUEUE_SUCCESS) {
1304 + // Packet not enqued:
1305 + sch->stats.drops++;
1311 +static struct sk_buff *wrr_dequeue(struct Qdisc* sch)
1313 + struct wrr_sched_data *q = (struct wrr_sched_data *)sch->data;
1314 + struct sk_buff* skb;
1316 + u64 weight,priosum;
1317 + struct wrrc_sched_data* b;
1319 + // Return if heap is empty:
1320 + if(heap_empty(&q->h)) return 0;
1322 + // Find root element:
1323 + band=heap_root(&q->h);
1325 + // Find priority of this element in interval [1;2^32]
1326 + b=&q->bands[band];
1327 + weight=((b->class_modf.weight1.val>>48)+1)*
1328 + ((b->class_modf.weight2.val>>48)+1); //weight is in interval [1;2^32]
1329 + priosum=q->priosum;
1330 + q->priosum-=q->bands[band].priosum_val;
1332 + // Deque the packet from the root:
1333 + skb=q->bands[band].que->dequeue(q->bands[band].que);
1336 + // There was a packet in this que.
1340 + // Find length of packet adjusted with priority:
1341 + adjlen=(u32)(weight>>(32-16));
1342 + if(adjlen==0) adjlen=1;
1343 + adjlen=(skb->len<<16)/adjlen;
1345 + // Update penalty information for this class:
1346 + weight_transmit(&b->class_modf.weight1,q->qdisc_modf.weight1,q->h.elements,priosum,weight,skb->len);
1347 + weight_transmit(&b->class_modf.weight2,q->qdisc_modf.weight2,q->h.elements,priosum,weight,skb->len);
1348 + q->bands[band].priosum_val=((b->class_modf.weight1.val>>48)+1)*
1349 + ((b->class_modf.weight2.val>>48)+1);
1350 + q->priosum+=q->bands[band].priosum_val;
1352 + // And update the class in the heap
1353 + p=heap_get_penalty(&q->h,band);
1355 + p.ls=q->counter_high_penal++;
1356 + heap_set_penalty(&q->h,band,p);
1363 + // No packet - so machine should be removed from heap:
1364 + heap_remove(&q->h,band);
1367 + return wrr_dequeue(sch);
1370 +static int wrr_requeue(struct sk_buff *skb, struct Qdisc* sch)
1372 + struct wrr_sched_data *q = (struct wrr_sched_data *)sch->data;
1373 + struct Qdisc* qdisc;
1376 + // Find band we took it from:
1377 + int band=mac_classify(&q->filter,skb);
1379 + // Who should now free the pakcet?
1380 + printk(KERN_DEBUG "sch_wrr: Oops - packet requed could never have been queued.\n");
1381 + sch->stats.drops++;
1382 + return ENQUEUE_FAIL;
1385 + q->packets_requed++;
1387 + // Try to requeue it on that machine:
1388 + qdisc=q->bands[band].que;
1390 + if((ret=qdisc->ops->requeue(skb,qdisc))==ENQUEUE_SUCCESS) {
1394 + // We should restore priority information - but we don't
1396 + // p=heap_get_penalty(&q->h,band);
1398 + // heap_set_penalty(&q->h,band,p);
1400 + return ENQUEUE_SUCCESS;
1402 + sch->stats.drops++;
1407 +static unsigned wrr_drop(struct Qdisc* sch)
1409 + struct wrr_sched_data *q = (struct wrr_sched_data *)sch->data;
1411 + // Ugly... Drop button up in heap:
1414 + for(i=q->h.elements; i>=1; i--) {
1415 + int band=q->h.root_1[i].id;
1416 + if(q->bands[band].que->ops->drop(q->bands[band].que)) {
1426 +static int wrr_dump(struct Qdisc *sch, struct sk_buff *skb)
1428 + struct wrr_sched_data *q = (struct wrr_sched_data *)sch->data;
1429 + unsigned char *b = skb->tail;
1430 + struct tc_wrr_qdisc_stats opt;
1432 + opt.qdisc_crt.qdisc_modf=q->qdisc_modf;
1433 + opt.qdisc_crt.srcaddr=q->filter.srcaddr;
1434 + opt.qdisc_crt.usemac=q->filter.usemac;
1435 + opt.qdisc_crt.usemasq=q->filter.usemasq;
1436 + opt.qdisc_crt.bands_max=q->filter.mac_max;
1437 + opt.nodes_in_heap=q->h.elements;
1438 + opt.bands_cur=q->filter.mac_cur;
1439 + opt.bands_reused=q->filter.mac_reused;
1440 + opt.packets_requed=q->packets_requed;
1441 + opt.priosum=q->priosum;
1443 + if(q->proxydict) {
1444 + opt.qdisc_crt.proxy_maxconn=proxyGetMaxConn(q->proxydict);
1445 + opt.proxy_curconn=proxyGetCurConn(q->proxydict);
1447 + opt.qdisc_crt.proxy_maxconn=0;
1448 + opt.proxy_curconn=0;
1451 + RTA_PUT(skb, TCA_OPTIONS, sizeof(opt), &opt);
1454 +rtattr_failure: // seems like RTA_PUT jump to this label..
1455 + skb_trim(skb, b - skb->data);
1459 +static int wrr_tune_std(struct Qdisc *sch, struct rtattr *opt)
1461 + struct wrr_sched_data *q = (struct wrr_sched_data *)sch->data;
1462 + struct tc_wrr_qdisc_modf_std *qopt = RTA_DATA(opt);
1464 + if(opt->rta_len < RTA_LENGTH(sizeof(*qopt))) return -EINVAL;
1468 + if(qopt->change_class) {
1469 + int idx=lookup_mac(&q->filter,qopt->addr);
1471 + (&q->bands[idx].class_modf.weight1,&qopt->class_modf.weight1);
1473 + (&q->bands[idx].class_modf.weight2,&qopt->class_modf.weight2);
1475 + if(qopt->qdisc_modf.weight1.weight_mode!=-1)
1476 + q->qdisc_modf.weight1.weight_mode=qopt->qdisc_modf.weight1.weight_mode;
1477 + if(qopt->qdisc_modf.weight2.weight_mode!=-1)
1478 + q->qdisc_modf.weight2.weight_mode=qopt->qdisc_modf.weight2.weight_mode;
1486 +static int wrr_tune_proxy(struct Qdisc *sch, struct rtattr *opt)
1488 + struct wrr_sched_data *q = (struct wrr_sched_data *)sch->data;
1489 + struct tc_wrr_qdisc_modf_proxy *qopt = RTA_DATA(opt);
1492 + // Return if we are not configured with proxy support:
1493 + if(!q->proxydict) return -ENOSYS;
1495 + // Return if not enough data given:
1496 + if(opt->rta_len<RTA_LENGTH(sizeof(*qopt)) ||
1498 + RTA_LENGTH(sizeof(*qopt)+sizeof(ProxyRemapBlock)*qopt->changec))
1504 + proxyInitMem(q->proxydict,proxyGetMaxConn(q->proxydict));
1507 + // Do all the changes:
1508 + for(i=0; i<qopt->changec; i++) {
1509 + proxyConsumeBlock(q->proxydict,&((ProxyRemapBlock*)&qopt->changes)[i]);
1517 +static int wrr_tune(struct Qdisc *sch, struct rtattr *opt) {
1518 + if(((struct tc_wrr_qdisc_modf_std*)RTA_DATA(opt))->proxy) {
1519 + return wrr_tune_proxy(sch,opt);
1521 + return wrr_tune_std(sch,opt);
1525 +//-----------------------------------------------------------------------------
1527 +// External and internal IDs are equal. They are the band number plus 1.
1529 +// Replace a class with another:
1530 +static int wrr_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new,
1531 + struct Qdisc **old)
1533 + struct wrr_sched_data *q = (struct wrr_sched_data *)sch->data;
1534 + if(arg>q->bandc || arg==0) return -EINVAL;
1538 + new = &noop_qdisc;
1541 + *old = xchg(&q->bands[arg].que, new);
1544 + *old = q->bands[arg].que;
1545 + q->bands[arg].que = new;
1546 + qdisc_reset(*old);
1553 +// Returns the qdisc for a class:
1554 +static struct Qdisc * wrr_leaf(struct Qdisc *sch, unsigned long arg)
1556 + struct wrr_sched_data *q = (struct wrr_sched_data *)sch->data;
1557 + if(arg>q->bandc || arg==0) return NULL;
1559 + return q->bands[arg].que;
1562 +static unsigned long wrr_get(struct Qdisc *sch, u32 classid)
1564 + struct wrr_sched_data *q = (struct wrr_sched_data *)sch->data;
1565 + unsigned long band = TC_H_MIN(classid);
1566 + if(band>q->bandc || band==0) return 0;
1570 +static void wrr_put(struct Qdisc *q, unsigned long cl)
1575 +static int wrr_delete(struct Qdisc *sch, unsigned long cl)
1577 + struct wrr_sched_data *q = (struct wrr_sched_data *)sch->data;
1578 + if(cl==0 || cl>q->bandc) return -ENOENT;
1583 +static int wrr_dump_class(struct Qdisc *sch, unsigned long cl,
1584 + struct sk_buff *skb, struct tcmsg *tcm)
1586 + struct wrr_sched_data *q = (struct wrr_sched_data *)sch->data;
1587 + unsigned char *b = skb->tail;
1588 + struct tc_wrr_class_stats opt;
1590 + // Handle of this class:
1591 + tcm->tcm_handle = sch->handle|cl;
1593 + if(cl==0 || cl>q->bandc)
1594 + goto rtattr_failure;
1597 + if(cl>=q->filter.mac_cur) {
1598 + // Band is unused:
1599 + memset(&opt,0,sizeof(opt));
1603 + opt.class_modf.weight1=q->bands[cl].class_modf.weight1;
1604 + opt.class_modf.weight2=q->bands[cl].class_modf.weight2;
1605 + weight_transmit(&opt.class_modf.weight1,q->qdisc_modf.weight1,0,0,0,0);
1606 + weight_transmit(&opt.class_modf.weight2,q->qdisc_modf.weight2,0,0,0,0);
1607 + memcpy(opt.addr,q->filter.cls2mac+cl*ETH_ALEN,ETH_ALEN);
1608 + opt.usemac=q->filter.usemac;
1609 + opt.heappos=q->h.root_1[cl+1].id2idx;
1610 + if(opt.heappos!=0) { // Is in heap
1611 + opt.penal_ls=heap_get_penalty(&q->h,cl).ls;
1612 + opt.penal_ms=heap_get_penalty(&q->h,cl).ms;
1619 + // Put quing information:
1620 + RTA_PUT(skb, TCA_OPTIONS, sizeof(opt), &opt);
1624 + skb_trim(skb, b - skb->data);
1628 +static int wrr_change(struct Qdisc *sch, u32 handle, u32 parent,
1629 + struct rtattr **tca, unsigned long *arg)
1631 + unsigned long cl = *arg;
1632 + struct wrr_sched_data *q = (struct wrr_sched_data *)sch->data;
1633 + struct rtattr *opt = tca[TCA_OPTIONS-1];
1634 + struct tc_wrr_class_modf *copt = RTA_DATA(opt);
1636 + if(cl==0 || cl>q->bandc) return -EINVAL;
1639 + if (opt->rta_len < RTA_LENGTH(sizeof(*copt))) return -EINVAL;
1643 + weight_setvalue(&q->bands[cl].class_modf.weight1,&copt->weight1);
1644 + weight_setvalue(&q->bands[cl].class_modf.weight2,&copt->weight2);
1651 +static void wrr_walk(struct Qdisc *sch, struct qdisc_walker *arg)
1653 + struct wrr_sched_data *q = (struct wrr_sched_data *)sch->data;
1656 + if (arg->stop) return;
1658 + for (prio = 1; prio <= q->bandc; prio++) {
1659 + if (arg->count < arg->skip) {
1663 + if (arg->fn(sch, prio, arg) < 0) {
1671 +static struct tcf_proto ** wrr_find_tcf(struct Qdisc *sch, unsigned long cl)
1676 +static unsigned long wrr_bind(struct Qdisc *sch,
1677 + unsigned long parent, u32 classid)
1679 + return wrr_get(sch, classid);
1682 +//-----------------------------------------------------------------------------
1685 +static struct Qdisc_class_ops wrr_class_ops =
1700 +#if !defined(KERNEL22) || defined(CONFIG_RTNETLINK)
1705 +struct Qdisc_ops wrr_qdisc_ops =
1710 + sizeof(struct wrr_sched_data),
1722 +#if !defined(KERNEL22) || defined(CONFIG_RTNETLINK)
1729 +int init_module(void)
1731 + return register_qdisc(&wrr_qdisc_ops);
1734 +void cleanup_module(void)
1736 + unregister_qdisc(&wrr_qdisc_ops);
1740 + MODULE_LICENSE("GPL");