vde_l3:
[vde.git] / vde-2 / vde_l3 / tbf.c
blob9e86cd4d3208212c2c121ff6f23bbf0039b539c6
1 /*
2 * tc token bucket module
3 * Usage: tc set <dev> tbf rate <speed>[K|M] limit <packets>
4 * Alternate usage: tc set <dev> tbf rate <speed>[K|M] latency <ms>
8 * */
9 #include "vde_buff.h"
10 #include <stdio.h>
11 #include <sys/time.h>
12 #include <time.h>
14 struct timeval add_t(struct timeval x, struct timeval y)
16 struct timeval ret = {
17 .tv_sec = x.tv_sec + y.tv_sec + ((x.tv_usec + y.tv_usec) / 1000000),
18 .tv_usec = (x.tv_usec + y.tv_usec) % 1000000
20 return ret;
22 #define before(x,y) x.tv_sec < y.tv_sec || (x.tv_sec == y.tv_sec && x.tv_usec < y.tv_usec)
24 #define tbf_tcpriv(x) (struct tc_tbf*)(tcpriv(x))
26 /** Private per-interface structure
29 struct tc_tbf
31 uint32_t qlen; // Bytes.
32 uint32_t limit; // Bytes.
33 uint32_t latency; // ms
34 uint32_t rate; // bits/s
35 uint32_t dropped; //packets
36 uint32_t mtu;
37 uint32_t bytes_out;
38 struct timeval delta;
39 struct timeval last_out;
44 * Enqueue function. Try to add the packet 'vdb' to the output queue
45 * of the interface 'vif'
47 * return value: 1 = packet was enqueued, 0 = packet was rejected
49 int tbf_enqueue(struct vde_buff *vdb, struct vde_iface *vif)
51 struct tc_tbf *tbf = tbf_tcpriv(vif);
52 if (tbf->qlen < tbf->limit){
53 tbf->qlen+=vdb->len;
54 ufifo_enqueue(vdb,vif);
55 if(vdb->len > tbf->mtu){
56 tbf->mtu = vdb->len;
57 tbf->delta.tv_usec = (1000000*tbf->mtu) / tbf->rate;
58 if (tbf->latency){
59 tbf->limit = (tbf->rate/tbf->mtu) * tbf->latency;
62 return 1;
63 }else{
64 /* Queue Full: dropping. */
65 free(vdb);
66 tbf->dropped++;
67 return 0;
71 /* Dequeue function. Interface is ready to send the packet.
74 int tbf_dequeue(struct vde_iface *vif)
76 struct tc_tbf *tbf = tbf_tcpriv(vif);
77 struct timeval now;
78 struct timeval when;
79 gettimeofday(&now,NULL);
80 when = add_t (tbf->last_out, tbf->delta);
82 if (before(now, when))
83 return 0;
85 tbf->bytes_out = vif->q_out->len;
86 ufifo_dequeue(vif);
87 tbf->qlen -= tbf->bytes_out;
88 while (tbf->bytes_out >= tbf->mtu){
89 memcpy(&tbf->last_out,&now,sizeof(struct timeval));
90 tbf->bytes_out -= tbf->mtu;
92 return 1;
98 /* Function to initialize the queue on the given interface.
100 int tbf_init(struct vde_iface *vif, char *args)
102 struct tc_tbf *tbf=(struct tc_tbf *)malloc(sizeof(struct tc_tbf));
103 int arglen = strlen(args) - 1;
104 uint32_t latency=0;
105 char *rate;
106 if ((arglen < 5) || strncmp(args,"rate",4))
107 goto fail;
108 args=index(args,' ');
109 if(args) *(args++)=(char)0;
110 rate=args;
111 if(!args || sscanf(args, "%lu",&(tbf->rate)) < 1)
112 goto fail;
113 args=index(args,' ');
114 if(args) *(args++)=(char)0;
115 if(index(rate,'K')) tbf->rate *=1000;
116 else if(index(rate,'M')) tbf->rate *=1000000;
117 if(tbf->rate < 5000)
118 goto fail;
119 tbf->rate = (tbf->rate >> 3); // from bits/s --> to Bytes/s
121 if(strncmp(args,"latency",7)==0){
122 args=index(args,' ');
123 if(args) *(args++)=(char)0;
124 if(!args || sscanf(args, "%lu",&latency) < 1)
125 goto fail;
126 } else if (strncmp(args,"limit",5)==0){
127 args=index(args,' ');
128 if(args) *(args++)=(char)0;
129 if(!args || sscanf(args, "%lu",&(tbf->limit)) < 1)
130 goto fail;
134 } else goto fail;
136 tbf->mtu=1000;
138 if(latency){
139 tbf->limit = (tbf->rate/tbf->mtu) * latency;
143 tbf->latency = latency;
144 gettimeofday(&tbf->last_out,NULL);
145 tbf->qlen = 0;
146 tbf->dropped = 0;
147 tbf->bytes_out = 0;
148 tbf->delta.tv_sec = 0;
149 tbf->delta.tv_usec = (1000000*tbf->mtu) / tbf->rate;
150 vif->policy_name="tbf";
151 memcpy(vif->tc_priv, tbf, sizeof(struct tc_tbf));
152 return 1;
154 fail:
155 return 0;
159 char *tbf_tc_stats(struct vde_iface *vif)
161 struct tc_tbf *tbf = tbf_tcpriv(vif);
162 char *statistics=(char*)malloc(256);
163 snprintf(statistics,255,"Shaping at Rate = %lu Bytes/s, bucket limit: %lu bytes. Overlimits: %lu packets. MTU=%lu", tbf->rate, tbf->limit, tbf->dropped, tbf->mtu);
164 return statistics;
170 * Module symbol to load into module list.
173 struct routing_policy module_routing_policy=
175 .name="tbf",
176 .help="Packet Fifo queue\nUsage: tc set <dev> tbf rate <speed>[K|M] ( limit <bytes> | latency <ms> )\n",
177 .policy_init = tbf_init,
178 .enqueue = tbf_enqueue,
179 .dequeue = tbf_dequeue,
180 .tc_stats = tbf_tc_stats
183 static void
184 __attribute__ ((constructor))
185 init (void)
187 fprintf(stderr,"Loading library: tbf.so\n");
191 static void
192 __attribute__ ((destructor))
193 fini (void)