]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/netinet/ip_dummynet.c
This commit was generated by cvs2svn to compensate for changes in r147013,
[FreeBSD/FreeBSD.git] / sys / netinet / ip_dummynet.c
1 /*-
2  * Copyright (c) 1998-2002 Luigi Rizzo, Universita` di Pisa
3  * Portions Copyright (c) 2000 Akamba Corp.
4  * All rights reserved
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  *
27  * $FreeBSD$
28  */
29
30 #define DUMMYNET_DEBUG
31
32 #if !defined(KLD_MODULE)
33 #include "opt_inet6.h"
34 #endif
35
36 /*
37  * This module implements IP dummynet, a bandwidth limiter/delay emulator
38  * used in conjunction with the ipfw package.
39  * Description of the data structures used is in ip_dummynet.h
40  * Here you mainly find the following blocks of code:
41  *  + variable declarations;
42  *  + heap management functions;
43  *  + scheduler and dummynet functions;
44  *  + configuration and initialization.
45  *
46  * NOTA BENE: critical sections are protected by the "dummynet lock".
47  *
48  * Most important Changes:
49  *
50  * 011004: KLDable
51  * 010124: Fixed WF2Q behaviour
52  * 010122: Fixed spl protection.
53  * 000601: WF2Q support
54  * 000106: large rewrite, use heaps to handle very many pipes.
55  * 980513:      initial release
56  *
57  * include files marked with XXX are probably not needed
58  */
59
60 #include <sys/param.h>
61 #include <sys/systm.h>
62 #include <sys/malloc.h>
63 #include <sys/mbuf.h>
64 #include <sys/kernel.h>
65 #include <sys/module.h>
66 #include <sys/proc.h>
67 #include <sys/socket.h>
68 #include <sys/socketvar.h>
69 #include <sys/time.h>
70 #include <sys/sysctl.h>
71 #include <net/if.h>
72 #include <net/route.h>
73 #include <netinet/in.h>
74 #include <netinet/in_systm.h>
75 #include <netinet/in_var.h>
76 #include <netinet/ip.h>
77 #include <netinet/ip_fw.h>
78 #include <netinet/ip_dummynet.h>
79 #include <netinet/ip_var.h>
80
81 #include <netinet/if_ether.h> /* for struct arpcom */
82 #include <net/bridge.h>
83
84 #include <netinet/ip6.h>       /* for ip6_input, ip6_output prototypes */
85 #include <netinet6/ip6_var.h>
86
87 /*
88  * We keep a private variable for the simulation time, but we could
89  * probably use an existing one ("softticks" in sys/kern/kern_timeout.c)
90  */
91 static dn_key curr_time = 0 ; /* current simulation time */
92
93 static int dn_hash_size = 64 ;  /* default hash size */
94
95 /* statistics on number of queue searches and search steps */
96 static int searches, search_steps ;
97 static int pipe_expire = 1 ;   /* expire queue if empty */
98 static int dn_max_ratio = 16 ; /* max queues/buckets ratio */
99
100 static int red_lookup_depth = 256;      /* RED - default lookup table depth */
101 static int red_avg_pkt_size = 512;      /* RED - default medium packet size */
102 static int red_max_pkt_size = 1500;     /* RED - default max packet size */
103
104 /*
105  * Three heaps contain queues and pipes that the scheduler handles:
106  *
107  * ready_heap contains all dn_flow_queue related to fixed-rate pipes.
108  *
109  * wfq_ready_heap contains the pipes associated with WF2Q flows
110  *
111  * extract_heap contains pipes associated with delay lines.
112  *
113  */
114
115 MALLOC_DEFINE(M_DUMMYNET, "dummynet", "dummynet heap");
116
117 static struct dn_heap ready_heap, extract_heap, wfq_ready_heap ;
118
119 static int heap_init(struct dn_heap *h, int size) ;
120 static int heap_insert (struct dn_heap *h, dn_key key1, void *p);
121 static void heap_extract(struct dn_heap *h, void *obj);
122
123 static void transmit_event(struct dn_pipe *pipe);
124 static void ready_event(struct dn_flow_queue *q);
125
126 static struct dn_pipe *all_pipes = NULL ;       /* list of all pipes */
127 static struct dn_flow_set *all_flow_sets = NULL ;/* list of all flow_sets */
128
129 static struct callout dn_timeout;
130
131 #ifdef SYSCTL_NODE
132 SYSCTL_NODE(_net_inet_ip, OID_AUTO, dummynet,
133                 CTLFLAG_RW, 0, "Dummynet");
134 SYSCTL_INT(_net_inet_ip_dummynet, OID_AUTO, hash_size,
135             CTLFLAG_RW, &dn_hash_size, 0, "Default hash table size");
136 SYSCTL_INT(_net_inet_ip_dummynet, OID_AUTO, curr_time,
137             CTLFLAG_RD, &curr_time, 0, "Current tick");
138 SYSCTL_INT(_net_inet_ip_dummynet, OID_AUTO, ready_heap,
139             CTLFLAG_RD, &ready_heap.size, 0, "Size of ready heap");
140 SYSCTL_INT(_net_inet_ip_dummynet, OID_AUTO, extract_heap,
141             CTLFLAG_RD, &extract_heap.size, 0, "Size of extract heap");
142 SYSCTL_INT(_net_inet_ip_dummynet, OID_AUTO, searches,
143             CTLFLAG_RD, &searches, 0, "Number of queue searches");
144 SYSCTL_INT(_net_inet_ip_dummynet, OID_AUTO, search_steps,
145             CTLFLAG_RD, &search_steps, 0, "Number of queue search steps");
146 SYSCTL_INT(_net_inet_ip_dummynet, OID_AUTO, expire,
147             CTLFLAG_RW, &pipe_expire, 0, "Expire queue if empty");
148 SYSCTL_INT(_net_inet_ip_dummynet, OID_AUTO, max_chain_len,
149             CTLFLAG_RW, &dn_max_ratio, 0,
150         "Max ratio between dynamic queues and buckets");
151 SYSCTL_INT(_net_inet_ip_dummynet, OID_AUTO, red_lookup_depth,
152         CTLFLAG_RD, &red_lookup_depth, 0, "Depth of RED lookup table");
153 SYSCTL_INT(_net_inet_ip_dummynet, OID_AUTO, red_avg_pkt_size,
154         CTLFLAG_RD, &red_avg_pkt_size, 0, "RED Medium packet size");
155 SYSCTL_INT(_net_inet_ip_dummynet, OID_AUTO, red_max_pkt_size,
156         CTLFLAG_RD, &red_max_pkt_size, 0, "RED Max packet size");
157 #endif
158
159 #ifdef DUMMYNET_DEBUG
160 int     dummynet_debug = 0;
161 #ifdef SYSCTL_NODE
162 SYSCTL_INT(_net_inet_ip_dummynet, OID_AUTO, debug, CTLFLAG_RW, &dummynet_debug,
163             0, "control debugging printfs");
164 #endif
165 #define DPRINTF(X)      if (dummynet_debug) printf X
166 #else
167 #define DPRINTF(X)
168 #endif
169
170 static struct mtx dummynet_mtx;
171 /*
172  * NB: Recursion is needed to deal with re-entry via ICMP.  That is,
173  *     a packet may be dispatched via ip_input from dummynet_io and
174  *     re-enter through ip_output.  Yech.
175  */
176 #define DUMMYNET_LOCK_INIT() \
177         mtx_init(&dummynet_mtx, "dummynet", NULL, MTX_DEF | MTX_RECURSE)
178 #define DUMMYNET_LOCK_DESTROY() mtx_destroy(&dummynet_mtx)
179 #define DUMMYNET_LOCK()         mtx_lock(&dummynet_mtx)
180 #define DUMMYNET_UNLOCK()       mtx_unlock(&dummynet_mtx)
181 #define DUMMYNET_LOCK_ASSERT()  do {                            \
182         mtx_assert(&dummynet_mtx, MA_OWNED);                    \
183         NET_ASSERT_GIANT();                                     \
184 } while (0)
185
186 static int config_pipe(struct dn_pipe *p);
187 static int ip_dn_ctl(struct sockopt *sopt);
188
189 static void dummynet(void *);
190 static void dummynet_flush(void);
191 void dummynet_drain(void);
192 static ip_dn_io_t dummynet_io;
193 static void dn_rule_delete(void *);
194
195 int if_tx_rdy(struct ifnet *ifp);
196
197 /*
198  * Heap management functions.
199  *
200  * In the heap, first node is element 0. Children of i are 2i+1 and 2i+2.
201  * Some macros help finding parent/children so we can optimize them.
202  *
203  * heap_init() is called to expand the heap when needed.
204  * Increment size in blocks of 16 entries.
205  * XXX failure to allocate a new element is a pretty bad failure
206  * as we basically stall a whole queue forever!!
207  * Returns 1 on error, 0 on success
208  */
209 #define HEAP_FATHER(x) ( ( (x) - 1 ) / 2 )
210 #define HEAP_LEFT(x) ( 2*(x) + 1 )
211 #define HEAP_IS_LEFT(x) ( (x) & 1 )
212 #define HEAP_RIGHT(x) ( 2*(x) + 2 )
213 #define HEAP_SWAP(a, b, buffer) { buffer = a ; a = b ; b = buffer ; }
214 #define HEAP_INCREMENT  15
215
216 static int
217 heap_init(struct dn_heap *h, int new_size)
218 {
219     struct dn_heap_entry *p;
220
221     if (h->size >= new_size ) {
222         printf("dummynet: %s, Bogus call, have %d want %d\n", __func__,
223                 h->size, new_size);
224         return 0 ;
225     }
226     new_size = (new_size + HEAP_INCREMENT ) & ~HEAP_INCREMENT ;
227     p = malloc(new_size * sizeof(*p), M_DUMMYNET, M_NOWAIT);
228     if (p == NULL) {
229         printf("dummynet: %s, resize %d failed\n", __func__, new_size );
230         return 1 ; /* error */
231     }
232     if (h->size > 0) {
233         bcopy(h->p, p, h->size * sizeof(*p) );
234         free(h->p, M_DUMMYNET);
235     }
236     h->p = p ;
237     h->size = new_size ;
238     return 0 ;
239 }
240
241 /*
242  * Insert element in heap. Normally, p != NULL, we insert p in
243  * a new position and bubble up. If p == NULL, then the element is
244  * already in place, and key is the position where to start the
245  * bubble-up.
246  * Returns 1 on failure (cannot allocate new heap entry)
247  *
248  * If offset > 0 the position (index, int) of the element in the heap is
249  * also stored in the element itself at the given offset in bytes.
250  */
251 #define SET_OFFSET(heap, node) \
252     if (heap->offset > 0) \
253             *((int *)((char *)(heap->p[node].object) + heap->offset)) = node ;
254 /*
255  * RESET_OFFSET is used for sanity checks. It sets offset to an invalid value.
256  */
257 #define RESET_OFFSET(heap, node) \
258     if (heap->offset > 0) \
259             *((int *)((char *)(heap->p[node].object) + heap->offset)) = -1 ;
260 static int
261 heap_insert(struct dn_heap *h, dn_key key1, void *p)
262 {
263     int son = h->elements ;
264
265     if (p == NULL)      /* data already there, set starting point */
266         son = key1 ;
267     else {              /* insert new element at the end, possibly resize */
268         son = h->elements ;
269         if (son == h->size) /* need resize... */
270             if (heap_init(h, h->elements+1) )
271                 return 1 ; /* failure... */
272         h->p[son].object = p ;
273         h->p[son].key = key1 ;
274         h->elements++ ;
275     }
276     while (son > 0) {                           /* bubble up */
277         int father = HEAP_FATHER(son) ;
278         struct dn_heap_entry tmp  ;
279
280         if (DN_KEY_LT( h->p[father].key, h->p[son].key ) )
281             break ; /* found right position */
282         /* son smaller than father, swap and repeat */
283         HEAP_SWAP(h->p[son], h->p[father], tmp) ;
284         SET_OFFSET(h, son);
285         son = father ;
286     }
287     SET_OFFSET(h, son);
288     return 0 ;
289 }
290
291 /*
292  * remove top element from heap, or obj if obj != NULL
293  */
294 static void
295 heap_extract(struct dn_heap *h, void *obj)
296 {
297     int child, father, max = h->elements - 1 ;
298
299     if (max < 0) {
300         printf("dummynet: warning, extract from empty heap 0x%p\n", h);
301         return ;
302     }
303     father = 0 ; /* default: move up smallest child */
304     if (obj != NULL) { /* extract specific element, index is at offset */
305         if (h->offset <= 0)
306             panic("dummynet: heap_extract from middle not supported on this heap!!!\n");
307         father = *((int *)((char *)obj + h->offset)) ;
308         if (father < 0 || father >= h->elements) {
309             printf("dummynet: heap_extract, father %d out of bound 0..%d\n",
310                 father, h->elements);
311             panic("dummynet: heap_extract");
312         }
313     }
314     RESET_OFFSET(h, father);
315     child = HEAP_LEFT(father) ;         /* left child */
316     while (child <= max) {              /* valid entry */
317         if (child != max && DN_KEY_LT(h->p[child+1].key, h->p[child].key) )
318             child = child+1 ;           /* take right child, otherwise left */
319         h->p[father] = h->p[child] ;
320         SET_OFFSET(h, father);
321         father = child ;
322         child = HEAP_LEFT(child) ;   /* left child for next loop */
323     }
324     h->elements-- ;
325     if (father != max) {
326         /*
327          * Fill hole with last entry and bubble up, reusing the insert code
328          */
329         h->p[father] = h->p[max] ;
330         heap_insert(h, father, NULL); /* this one cannot fail */
331     }
332 }
333
334 #if 0
335 /*
336  * change object position and update references
337  * XXX this one is never used!
338  */
339 static void
340 heap_move(struct dn_heap *h, dn_key new_key, void *object)
341 {
342     int temp;
343     int i ;
344     int max = h->elements-1 ;
345     struct dn_heap_entry buf ;
346
347     if (h->offset <= 0)
348         panic("cannot move items on this heap");
349
350     i = *((int *)((char *)object + h->offset));
351     if (DN_KEY_LT(new_key, h->p[i].key) ) { /* must move up */
352         h->p[i].key = new_key ;
353         for (; i>0 && DN_KEY_LT(new_key, h->p[(temp = HEAP_FATHER(i))].key) ;
354                  i = temp ) { /* bubble up */
355             HEAP_SWAP(h->p[i], h->p[temp], buf) ;
356             SET_OFFSET(h, i);
357         }
358     } else {            /* must move down */
359         h->p[i].key = new_key ;
360         while ( (temp = HEAP_LEFT(i)) <= max ) { /* found left child */
361             if ((temp != max) && DN_KEY_GT(h->p[temp].key, h->p[temp+1].key))
362                 temp++ ; /* select child with min key */
363             if (DN_KEY_GT(new_key, h->p[temp].key)) { /* go down */
364                 HEAP_SWAP(h->p[i], h->p[temp], buf) ;
365                 SET_OFFSET(h, i);
366             } else
367                 break ;
368             i = temp ;
369         }
370     }
371     SET_OFFSET(h, i);
372 }
373 #endif /* heap_move, unused */
374
375 /*
376  * heapify() will reorganize data inside an array to maintain the
377  * heap property. It is needed when we delete a bunch of entries.
378  */
379 static void
380 heapify(struct dn_heap *h)
381 {
382     int i ;
383
384     for (i = 0 ; i < h->elements ; i++ )
385         heap_insert(h, i , NULL) ;
386 }
387
388 /*
389  * cleanup the heap and free data structure
390  */
391 static void
392 heap_free(struct dn_heap *h)
393 {
394     if (h->size >0 )
395         free(h->p, M_DUMMYNET);
396     bzero(h, sizeof(*h) );
397 }
398
399 /*
400  * --- end of heap management functions ---
401  */
402
403 /*
404  * Return the mbuf tag holding the dummynet state.  As an optimization
405  * this is assumed to be the first tag on the list.  If this turns out
406  * wrong we'll need to search the list.
407  */
408 static struct dn_pkt_tag *
409 dn_tag_get(struct mbuf *m)
410 {
411     struct m_tag *mtag = m_tag_first(m);
412     KASSERT(mtag != NULL &&
413             mtag->m_tag_cookie == MTAG_ABI_COMPAT &&
414             mtag->m_tag_id == PACKET_TAG_DUMMYNET,
415             ("packet on dummynet queue w/o dummynet tag!"));
416     return (struct dn_pkt_tag *)(mtag+1);
417 }
418
419 /*
420  * Scheduler functions:
421  *
422  * transmit_event() is called when the delay-line needs to enter
423  * the scheduler, either because of existing pkts getting ready,
424  * or new packets entering the queue. The event handled is the delivery
425  * time of the packet.
426  *
427  * ready_event() does something similar with fixed-rate queues, and the
428  * event handled is the finish time of the head pkt.
429  *
430  * wfq_ready_event() does something similar with WF2Q queues, and the
431  * event handled is the start time of the head pkt.
432  *
433  * In all cases, we make sure that the data structures are consistent
434  * before passing pkts out, because this might trigger recursive
435  * invocations of the procedures.
436  */
437 static void
438 transmit_event(struct dn_pipe *pipe)
439 {
440     struct mbuf *m ;
441     struct dn_pkt_tag *pkt ;
442     struct ip *ip;
443
444     DUMMYNET_LOCK_ASSERT();
445
446     while ( (m = pipe->head) ) {
447         pkt = dn_tag_get(m);
448         if ( !DN_KEY_LEQ(pkt->output_time, curr_time) )
449             break;
450         /*
451          * first unlink, then call procedures, since ip_input() can invoke
452          * ip_output() and viceversa, thus causing nested calls
453          */
454         pipe->head = m->m_nextpkt ;
455         m->m_nextpkt = NULL;
456
457         /* XXX: drop the lock for now to avoid LOR's */
458         DUMMYNET_UNLOCK();
459         switch (pkt->dn_dir) {
460         case DN_TO_IP_OUT:
461             (void)ip_output(m, NULL, NULL, pkt->flags, NULL, NULL);
462             break ;
463
464         case DN_TO_IP_IN :
465             ip = mtod(m, struct ip *);
466             ip->ip_len = htons(ip->ip_len);
467             ip->ip_off = htons(ip->ip_off);
468             ip_input(m) ;
469             break ;
470
471 #ifdef INET6
472         case DN_TO_IP6_IN:
473             ip6_input(m) ;
474             break ;
475
476         case DN_TO_IP6_OUT:
477             (void)ip6_output(m, NULL, NULL, pkt->flags, NULL, NULL, NULL);
478             break ;
479 #endif
480
481         case DN_TO_BDG_FWD :
482             /*
483              * The bridge requires/assumes the Ethernet header is
484              * contiguous in the first mbuf header.  Insure this is true.
485              */
486             if (BDG_LOADED) {
487                 if (m->m_len < ETHER_HDR_LEN &&
488                     (m = m_pullup(m, ETHER_HDR_LEN)) == NULL) {
489                     printf("dummynet/bridge: pullup fail, dropping pkt\n");
490                     break;
491                 }
492                 m = bdg_forward_ptr(m, pkt->ifp);
493             } else {
494                 /* somebody unloaded the bridge module. Drop pkt */
495                 /* XXX rate limit */
496                 printf("dummynet: dropping bridged packet trapped in pipe\n");
497             }
498             if (m)
499                 m_freem(m);
500             break;
501
502         case DN_TO_ETH_DEMUX:
503             /*
504              * The Ethernet code assumes the Ethernet header is
505              * contiguous in the first mbuf header.  Insure this is true.
506              */
507             if (m->m_len < ETHER_HDR_LEN &&
508                 (m = m_pullup(m, ETHER_HDR_LEN)) == NULL) {
509                 printf("dummynet/ether: pullup fail, dropping pkt\n");
510                 break;
511             }
512             ether_demux(m->m_pkthdr.rcvif, m); /* which consumes the mbuf */
513             break ;
514
515         case DN_TO_ETH_OUT:
516             ether_output_frame(pkt->ifp, m);
517             break;
518
519         default:
520             printf("dummynet: bad switch %d!\n", pkt->dn_dir);
521             m_freem(m);
522             break ;
523         }
524         DUMMYNET_LOCK();
525     }
526     /* if there are leftover packets, put into the heap for next event */
527     if ( (m = pipe->head) ) {
528         pkt = dn_tag_get(m) ;
529         /* XXX should check errors on heap_insert, by draining the
530          * whole pipe p and hoping in the future we are more successful
531          */
532         heap_insert(&extract_heap, pkt->output_time, pipe ) ;
533     }
534 }
535
536 /*
537  * the following macro computes how many ticks we have to wait
538  * before being able to transmit a packet. The credit is taken from
539  * either a pipe (WF2Q) or a flow_queue (per-flow queueing)
540  */
541 #define SET_TICKS(_m, q, p)     \
542     ((_m)->m_pkthdr.len*8*hz - (q)->numbytes + p->bandwidth - 1 ) / \
543             p->bandwidth ;
544
545 /*
546  * extract pkt from queue, compute output time (could be now)
547  * and put into delay line (p_queue)
548  */
549 static void
550 move_pkt(struct mbuf *pkt, struct dn_flow_queue *q,
551         struct dn_pipe *p, int len)
552 {
553     struct dn_pkt_tag *dt = dn_tag_get(pkt);
554
555     q->head = pkt->m_nextpkt ;
556     q->len-- ;
557     q->len_bytes -= len ;
558
559     dt->output_time = curr_time + p->delay ;
560
561     if (p->head == NULL)
562         p->head = pkt;
563     else
564         p->tail->m_nextpkt = pkt;
565     p->tail = pkt;
566     p->tail->m_nextpkt = NULL;
567 }
568
569 /*
570  * ready_event() is invoked every time the queue must enter the
571  * scheduler, either because the first packet arrives, or because
572  * a previously scheduled event fired.
573  * On invokation, drain as many pkts as possible (could be 0) and then
574  * if there are leftover packets reinsert the pkt in the scheduler.
575  */
576 static void
577 ready_event(struct dn_flow_queue *q)
578 {
579     struct mbuf *pkt;
580     struct dn_pipe *p = q->fs->pipe ;
581     int p_was_empty ;
582
583     DUMMYNET_LOCK_ASSERT();
584
585     if (p == NULL) {
586         printf("dummynet: ready_event- pipe is gone\n");
587         return ;
588     }
589     p_was_empty = (p->head == NULL) ;
590
591     /*
592      * schedule fixed-rate queues linked to this pipe:
593      * Account for the bw accumulated since last scheduling, then
594      * drain as many pkts as allowed by q->numbytes and move to
595      * the delay line (in p) computing output time.
596      * bandwidth==0 (no limit) means we can drain the whole queue,
597      * setting len_scaled = 0 does the job.
598      */
599     q->numbytes += ( curr_time - q->sched_time ) * p->bandwidth;
600     while ( (pkt = q->head) != NULL ) {
601         int len = pkt->m_pkthdr.len;
602         int len_scaled = p->bandwidth ? len*8*hz : 0 ;
603         if (len_scaled > q->numbytes )
604             break ;
605         q->numbytes -= len_scaled ;
606         move_pkt(pkt, q, p, len);
607     }
608     /*
609      * If we have more packets queued, schedule next ready event
610      * (can only occur when bandwidth != 0, otherwise we would have
611      * flushed the whole queue in the previous loop).
612      * To this purpose we record the current time and compute how many
613      * ticks to go for the finish time of the packet.
614      */
615     if ( (pkt = q->head) != NULL ) { /* this implies bandwidth != 0 */
616         dn_key t = SET_TICKS(pkt, q, p); /* ticks i have to wait */
617         q->sched_time = curr_time ;
618         heap_insert(&ready_heap, curr_time + t, (void *)q );
619         /* XXX should check errors on heap_insert, and drain the whole
620          * queue on error hoping next time we are luckier.
621          */
622     } else {    /* RED needs to know when the queue becomes empty */
623         q->q_time = curr_time;
624         q->numbytes = 0;
625     }
626     /*
627      * If the delay line was empty call transmit_event(p) now.
628      * Otherwise, the scheduler will take care of it.
629      */
630     if (p_was_empty)
631         transmit_event(p);
632 }
633
634 /*
635  * Called when we can transmit packets on WF2Q queues. Take pkts out of
636  * the queues at their start time, and enqueue into the delay line.
637  * Packets are drained until p->numbytes < 0. As long as
638  * len_scaled >= p->numbytes, the packet goes into the delay line
639  * with a deadline p->delay. For the last packet, if p->numbytes<0,
640  * there is an additional delay.
641  */
642 static void
643 ready_event_wfq(struct dn_pipe *p)
644 {
645     int p_was_empty = (p->head == NULL) ;
646     struct dn_heap *sch = &(p->scheduler_heap);
647     struct dn_heap *neh = &(p->not_eligible_heap) ;
648
649     DUMMYNET_LOCK_ASSERT();
650
651     if (p->if_name[0] == 0) /* tx clock is simulated */
652         p->numbytes += ( curr_time - p->sched_time ) * p->bandwidth;
653     else { /* tx clock is for real, the ifq must be empty or this is a NOP */
654         if (p->ifp && p->ifp->if_snd.ifq_head != NULL)
655             return ;
656         else {
657             DPRINTF(("dummynet: pipe %d ready from %s --\n",
658                 p->pipe_nr, p->if_name));
659         }
660     }
661
662     /*
663      * While we have backlogged traffic AND credit, we need to do
664      * something on the queue.
665      */
666     while ( p->numbytes >=0 && (sch->elements>0 || neh->elements >0) ) {
667         if (sch->elements > 0) { /* have some eligible pkts to send out */
668             struct dn_flow_queue *q = sch->p[0].object ;
669             struct mbuf *pkt = q->head;
670             struct dn_flow_set *fs = q->fs;
671             u_int64_t len = pkt->m_pkthdr.len;
672             int len_scaled = p->bandwidth ? len*8*hz : 0 ;
673
674             heap_extract(sch, NULL); /* remove queue from heap */
675             p->numbytes -= len_scaled ;
676             move_pkt(pkt, q, p, len);
677
678             p->V += (len<<MY_M) / p->sum ; /* update V */
679             q->S = q->F ; /* update start time */
680             if (q->len == 0) { /* Flow not backlogged any more */
681                 fs->backlogged-- ;
682                 heap_insert(&(p->idle_heap), q->F, q);
683             } else { /* still backlogged */
684                 /*
685                  * update F and position in backlogged queue, then
686                  * put flow in not_eligible_heap (we will fix this later).
687                  */
688                 len = (q->head)->m_pkthdr.len;
689                 q->F += (len<<MY_M)/(u_int64_t) fs->weight ;
690                 if (DN_KEY_LEQ(q->S, p->V))
691                     heap_insert(neh, q->S, q);
692                 else
693                     heap_insert(sch, q->F, q);
694             }
695         }
696         /*
697          * now compute V = max(V, min(S_i)). Remember that all elements in sch
698          * have by definition S_i <= V so if sch is not empty, V is surely
699          * the max and we must not update it. Conversely, if sch is empty
700          * we only need to look at neh.
701          */
702         if (sch->elements == 0 && neh->elements > 0)
703             p->V = MAX64 ( p->V, neh->p[0].key );
704         /* move from neh to sch any packets that have become eligible */
705         while (neh->elements > 0 && DN_KEY_LEQ(neh->p[0].key, p->V) ) {
706             struct dn_flow_queue *q = neh->p[0].object ;
707             heap_extract(neh, NULL);
708             heap_insert(sch, q->F, q);
709         }
710
711         if (p->if_name[0] != '\0') {/* tx clock is from a real thing */
712             p->numbytes = -1 ; /* mark not ready for I/O */
713             break ;
714         }
715     }
716     if (sch->elements == 0 && neh->elements == 0 && p->numbytes >= 0
717             && p->idle_heap.elements > 0) {
718         /*
719          * no traffic and no events scheduled. We can get rid of idle-heap.
720          */
721         int i ;
722
723         for (i = 0 ; i < p->idle_heap.elements ; i++) {
724             struct dn_flow_queue *q = p->idle_heap.p[i].object ;
725
726             q->F = 0 ;
727             q->S = q->F + 1 ;
728         }
729         p->sum = 0 ;
730         p->V = 0 ;
731         p->idle_heap.elements = 0 ;
732     }
733     /*
734      * If we are getting clocks from dummynet (not a real interface) and
735      * If we are under credit, schedule the next ready event.
736      * Also fix the delivery time of the last packet.
737      */
738     if (p->if_name[0]==0 && p->numbytes < 0) { /* this implies bandwidth >0 */
739         dn_key t=0 ; /* number of ticks i have to wait */
740
741         if (p->bandwidth > 0)
742             t = ( p->bandwidth -1 - p->numbytes) / p->bandwidth ;
743         dn_tag_get(p->tail)->output_time += t ;
744         p->sched_time = curr_time ;
745         heap_insert(&wfq_ready_heap, curr_time + t, (void *)p);
746         /* XXX should check errors on heap_insert, and drain the whole
747          * queue on error hoping next time we are luckier.
748          */
749     }
750     /*
751      * If the delay line was empty call transmit_event(p) now.
752      * Otherwise, the scheduler will take care of it.
753      */
754     if (p_was_empty)
755         transmit_event(p);
756 }
757
758 /*
759  * This is called once per tick, or HZ times per second. It is used to
760  * increment the current tick counter and schedule expired events.
761  */
762 static void
763 dummynet(void * __unused unused)
764 {
765     void *p ; /* generic parameter to handler */
766     struct dn_heap *h ;
767     struct dn_heap *heaps[3];
768     int i;
769     struct dn_pipe *pe ;
770
771     heaps[0] = &ready_heap ;            /* fixed-rate queues */
772     heaps[1] = &wfq_ready_heap ;        /* wfq queues */
773     heaps[2] = &extract_heap ;          /* delay line */
774
775     DUMMYNET_LOCK();
776     curr_time++ ;
777     for (i=0; i < 3 ; i++) {
778         h = heaps[i];
779         while (h->elements > 0 && DN_KEY_LEQ(h->p[0].key, curr_time) ) {
780             if (h->p[0].key > curr_time)
781                 printf("dummynet: warning, heap %d is %d ticks late\n",
782                     i, (int)(curr_time - h->p[0].key));
783             p = h->p[0].object ; /* store a copy before heap_extract */
784             heap_extract(h, NULL); /* need to extract before processing */
785             if (i == 0)
786                 ready_event(p) ;
787             else if (i == 1) {
788                 struct dn_pipe *pipe = p;
789                 if (pipe->if_name[0] != '\0')
790                     printf("dummynet: bad ready_event_wfq for pipe %s\n",
791                         pipe->if_name);
792                 else
793                     ready_event_wfq(p) ;
794             } else
795                 transmit_event(p);
796         }
797     }
798     /* sweep pipes trying to expire idle flow_queues */
799     for (pe = all_pipes; pe ; pe = pe->next )
800         if (pe->idle_heap.elements > 0 &&
801                 DN_KEY_LT(pe->idle_heap.p[0].key, pe->V) ) {
802             struct dn_flow_queue *q = pe->idle_heap.p[0].object ;
803
804             heap_extract(&(pe->idle_heap), NULL);
805             q->S = q->F + 1 ; /* mark timestamp as invalid */
806             pe->sum -= q->fs->weight ;
807         }
808     DUMMYNET_UNLOCK();
809
810     callout_reset(&dn_timeout, 1, dummynet, NULL);
811 }
812
813 /*
814  * called by an interface when tx_rdy occurs.
815  */
816 int
817 if_tx_rdy(struct ifnet *ifp)
818 {
819     struct dn_pipe *p;
820
821     DUMMYNET_LOCK();
822     for (p = all_pipes; p ; p = p->next )
823         if (p->ifp == ifp)
824             break ;
825     if (p == NULL) {
826         for (p = all_pipes; p ; p = p->next )
827             if (!strcmp(p->if_name, ifp->if_xname) ) {
828                 p->ifp = ifp ;
829                 DPRINTF(("dummynet: ++ tx rdy from %s (now found)\n",
830                         ifp->if_xname));
831                 break ;
832             }
833     }
834     if (p != NULL) {
835         DPRINTF(("dummynet: ++ tx rdy from %s - qlen %d\n", ifp->if_xname,
836                 ifp->if_snd.ifq_len));
837         p->numbytes = 0 ; /* mark ready for I/O */
838         ready_event_wfq(p);
839     }
840     DUMMYNET_UNLOCK();
841
842     return 0;
843 }
844
845 /*
846  * Unconditionally expire empty queues in case of shortage.
847  * Returns the number of queues freed.
848  */
849 static int
850 expire_queues(struct dn_flow_set *fs)
851 {
852     struct dn_flow_queue *q, *prev ;
853     int i, initial_elements = fs->rq_elements ;
854
855     if (fs->last_expired == time_second)
856         return 0 ;
857     fs->last_expired = time_second ;
858     for (i = 0 ; i <= fs->rq_size ; i++) /* last one is overflow */
859         for (prev=NULL, q = fs->rq[i] ; q != NULL ; )
860             if (q->head != NULL || q->S != q->F+1) {
861                 prev = q ;
862                 q = q->next ;
863             } else { /* entry is idle, expire it */
864                 struct dn_flow_queue *old_q = q ;
865
866                 if (prev != NULL)
867                     prev->next = q = q->next ;
868                 else
869                     fs->rq[i] = q = q->next ;
870                 fs->rq_elements-- ;
871                 free(old_q, M_DUMMYNET);
872             }
873     return initial_elements - fs->rq_elements ;
874 }
875
876 /*
877  * If room, create a new queue and put at head of slot i;
878  * otherwise, create or use the default queue.
879  */
880 static struct dn_flow_queue *
881 create_queue(struct dn_flow_set *fs, int i)
882 {
883     struct dn_flow_queue *q ;
884
885     if (fs->rq_elements > fs->rq_size * dn_max_ratio &&
886             expire_queues(fs) == 0) {
887         /*
888          * No way to get room, use or create overflow queue.
889          */
890         i = fs->rq_size ;
891         if ( fs->rq[i] != NULL )
892             return fs->rq[i] ;
893     }
894     q = malloc(sizeof(*q), M_DUMMYNET, M_NOWAIT | M_ZERO);
895     if (q == NULL) {
896         printf("dummynet: sorry, cannot allocate queue for new flow\n");
897         return NULL ;
898     }
899     q->fs = fs ;
900     q->hash_slot = i ;
901     q->next = fs->rq[i] ;
902     q->S = q->F + 1;   /* hack - mark timestamp as invalid */
903     fs->rq[i] = q ;
904     fs->rq_elements++ ;
905     return q ;
906 }
907
908 /*
909  * Given a flow_set and a pkt in last_pkt, find a matching queue
910  * after appropriate masking. The queue is moved to front
911  * so that further searches take less time.
912  */
913 static struct dn_flow_queue *
914 find_queue(struct dn_flow_set *fs, struct ipfw_flow_id *id)
915 {
916     int i = 0 ; /* we need i and q for new allocations */
917     struct dn_flow_queue *q, *prev;
918     int is_v6 = IS_IP6_FLOW_ID(id);
919
920     if ( !(fs->flags_fs & DN_HAVE_FLOW_MASK) )
921         q = fs->rq[0] ;
922     else {
923         /* first, do the masking, then hash */
924         id->dst_port &= fs->flow_mask.dst_port ;
925         id->src_port &= fs->flow_mask.src_port ;
926         id->proto &= fs->flow_mask.proto ;
927         id->flags = 0 ; /* we don't care about this one */
928         if (is_v6) {
929             APPLY_MASK(&id->dst_ip6, &fs->flow_mask.dst_ip6);
930             APPLY_MASK(&id->src_ip6, &fs->flow_mask.src_ip6);
931             id->flow_id6 &= fs->flow_mask.flow_id6;
932
933             i = ((id->dst_ip6.__u6_addr.__u6_addr32[0]) & 0xffff)^
934                 ((id->dst_ip6.__u6_addr.__u6_addr32[1]) & 0xffff)^
935                 ((id->dst_ip6.__u6_addr.__u6_addr32[2]) & 0xffff)^
936                 ((id->dst_ip6.__u6_addr.__u6_addr32[3]) & 0xffff)^
937
938                 ((id->dst_ip6.__u6_addr.__u6_addr32[0] >> 15) & 0xffff)^
939                 ((id->dst_ip6.__u6_addr.__u6_addr32[1] >> 15) & 0xffff)^
940                 ((id->dst_ip6.__u6_addr.__u6_addr32[2] >> 15) & 0xffff)^
941                 ((id->dst_ip6.__u6_addr.__u6_addr32[3] >> 15) & 0xffff)^
942
943                 ((id->src_ip6.__u6_addr.__u6_addr32[0] << 1) & 0xfffff)^
944                 ((id->src_ip6.__u6_addr.__u6_addr32[1] << 1) & 0xfffff)^
945                 ((id->src_ip6.__u6_addr.__u6_addr32[2] << 1) & 0xfffff)^
946                 ((id->src_ip6.__u6_addr.__u6_addr32[3] << 1) & 0xfffff)^
947
948                 ((id->src_ip6.__u6_addr.__u6_addr32[0] << 16) & 0xffff)^
949                 ((id->src_ip6.__u6_addr.__u6_addr32[1] << 16) & 0xffff)^
950                 ((id->src_ip6.__u6_addr.__u6_addr32[2] << 16) & 0xffff)^
951                 ((id->src_ip6.__u6_addr.__u6_addr32[3] << 16) & 0xffff)^
952
953                 (id->dst_port << 1) ^ (id->src_port) ^
954                 (id->proto ) ^
955                 (id->flow_id6);
956         } else {
957             id->dst_ip &= fs->flow_mask.dst_ip ;
958             id->src_ip &= fs->flow_mask.src_ip ;
959
960             i = ( (id->dst_ip) & 0xffff ) ^
961                 ( (id->dst_ip >> 15) & 0xffff ) ^
962                 ( (id->src_ip << 1) & 0xffff ) ^
963                 ( (id->src_ip >> 16 ) & 0xffff ) ^
964                 (id->dst_port << 1) ^ (id->src_port) ^
965                 (id->proto );
966         }
967         i = i % fs->rq_size ;
968         /* finally, scan the current list for a match */
969         searches++ ;
970         for (prev=NULL, q = fs->rq[i] ; q ; ) {
971             search_steps++;
972             if (is_v6 &&
973                     IN6_ARE_ADDR_EQUAL(&id->dst_ip6,&q->id.dst_ip6) &&  
974                     IN6_ARE_ADDR_EQUAL(&id->src_ip6,&q->id.src_ip6) &&  
975                     id->dst_port == q->id.dst_port &&
976                     id->src_port == q->id.src_port &&
977                     id->proto == q->id.proto &&
978                     id->flags == q->id.flags &&
979                     id->flow_id6 == q->id.flow_id6)
980                 break ; /* found */
981
982             if (!is_v6 && id->dst_ip == q->id.dst_ip &&
983                     id->src_ip == q->id.src_ip &&
984                     id->dst_port == q->id.dst_port &&
985                     id->src_port == q->id.src_port &&
986                     id->proto == q->id.proto &&
987                     id->flags == q->id.flags)
988                 break ; /* found */
989
990             /* No match. Check if we can expire the entry */
991             if (pipe_expire && q->head == NULL && q->S == q->F+1 ) {
992                 /* entry is idle and not in any heap, expire it */
993                 struct dn_flow_queue *old_q = q ;
994
995                 if (prev != NULL)
996                     prev->next = q = q->next ;
997                 else
998                     fs->rq[i] = q = q->next ;
999                 fs->rq_elements-- ;
1000                 free(old_q, M_DUMMYNET);
1001                 continue ;
1002             }
1003             prev = q ;
1004             q = q->next ;
1005         }
1006         if (q && prev != NULL) { /* found and not in front */
1007             prev->next = q->next ;
1008             q->next = fs->rq[i] ;
1009             fs->rq[i] = q ;
1010         }
1011     }
1012     if (q == NULL) { /* no match, need to allocate a new entry */
1013         q = create_queue(fs, i);
1014         if (q != NULL)
1015         q->id = *id ;
1016     }
1017     return q ;
1018 }
1019
1020 static int
1021 red_drops(struct dn_flow_set *fs, struct dn_flow_queue *q, int len)
1022 {
1023     /*
1024      * RED algorithm
1025      *
1026      * RED calculates the average queue size (avg) using a low-pass filter
1027      * with an exponential weighted (w_q) moving average:
1028      *  avg  <-  (1-w_q) * avg + w_q * q_size
1029      * where q_size is the queue length (measured in bytes or * packets).
1030      *
1031      * If q_size == 0, we compute the idle time for the link, and set
1032      *  avg = (1 - w_q)^(idle/s)
1033      * where s is the time needed for transmitting a medium-sized packet.
1034      *
1035      * Now, if avg < min_th the packet is enqueued.
1036      * If avg > max_th the packet is dropped. Otherwise, the packet is
1037      * dropped with probability P function of avg.
1038      *
1039      */
1040
1041     int64_t p_b = 0;
1042     /* queue in bytes or packets ? */
1043     u_int q_size = (fs->flags_fs & DN_QSIZE_IS_BYTES) ? q->len_bytes : q->len;
1044
1045     DPRINTF(("\ndummynet: %d q: %2u ", (int) curr_time, q_size));
1046
1047     /* average queue size estimation */
1048     if (q_size != 0) {
1049         /*
1050          * queue is not empty, avg <- avg + (q_size - avg) * w_q
1051          */
1052         int diff = SCALE(q_size) - q->avg;
1053         int64_t v = SCALE_MUL((int64_t) diff, (int64_t) fs->w_q);
1054
1055         q->avg += (int) v;
1056     } else {
1057         /*
1058          * queue is empty, find for how long the queue has been
1059          * empty and use a lookup table for computing
1060          * (1 - * w_q)^(idle_time/s) where s is the time to send a
1061          * (small) packet.
1062          * XXX check wraps...
1063          */
1064         if (q->avg) {
1065             u_int t = (curr_time - q->q_time) / fs->lookup_step;
1066
1067             q->avg = (t < fs->lookup_depth) ?
1068                     SCALE_MUL(q->avg, fs->w_q_lookup[t]) : 0;
1069         }
1070     }
1071     DPRINTF(("dummynet: avg: %u ", SCALE_VAL(q->avg)));
1072
1073     /* should i drop ? */
1074
1075     if (q->avg < fs->min_th) {
1076         q->count = -1;
1077         return 0; /* accept packet ; */
1078     }
1079     if (q->avg >= fs->max_th) { /* average queue >=  max threshold */
1080         if (fs->flags_fs & DN_IS_GENTLE_RED) {
1081             /*
1082              * According to Gentle-RED, if avg is greater than max_th the
1083              * packet is dropped with a probability
1084              *  p_b = c_3 * avg - c_4
1085              * where c_3 = (1 - max_p) / max_th, and c_4 = 1 - 2 * max_p
1086              */
1087             p_b = SCALE_MUL((int64_t) fs->c_3, (int64_t) q->avg) - fs->c_4;
1088         } else {
1089             q->count = -1;
1090             DPRINTF(("dummynet: - drop"));
1091             return 1 ;
1092         }
1093     } else if (q->avg > fs->min_th) {
1094         /*
1095          * we compute p_b using the linear dropping function p_b = c_1 *
1096          * avg - c_2, where c_1 = max_p / (max_th - min_th), and c_2 =
1097          * max_p * min_th / (max_th - min_th)
1098          */
1099         p_b = SCALE_MUL((int64_t) fs->c_1, (int64_t) q->avg) - fs->c_2;
1100     }
1101     if (fs->flags_fs & DN_QSIZE_IS_BYTES)
1102         p_b = (p_b * len) / fs->max_pkt_size;
1103     if (++q->count == 0)
1104         q->random = random() & 0xffff;
1105     else {
1106         /*
1107          * q->count counts packets arrived since last drop, so a greater
1108          * value of q->count means a greater packet drop probability.
1109          */
1110         if (SCALE_MUL(p_b, SCALE((int64_t) q->count)) > q->random) {
1111             q->count = 0;
1112             DPRINTF(("dummynet: - red drop"));
1113             /* after a drop we calculate a new random value */
1114             q->random = random() & 0xffff;
1115             return 1;    /* drop */
1116         }
1117     }
1118     /* end of RED algorithm */
1119     return 0 ; /* accept */
1120 }
1121
1122 static __inline
1123 struct dn_flow_set *
1124 locate_flowset(int pipe_nr, struct ip_fw *rule)
1125 {
1126     struct dn_flow_set *fs;
1127     ipfw_insn *cmd = ACTION_PTR(rule);
1128
1129     if (cmd->opcode == O_LOG)
1130         cmd += F_LEN(cmd);
1131 #ifdef __i386__
1132     fs = ((ipfw_insn_pipe *)cmd)->pipe_ptr;
1133 #else
1134     bcopy(& ((ipfw_insn_pipe *)cmd)->pipe_ptr, &fs, sizeof(fs));
1135 #endif
1136
1137     if (fs != NULL)
1138         return fs;
1139
1140     if (cmd->opcode == O_QUEUE)
1141         for (fs=all_flow_sets; fs && fs->fs_nr != pipe_nr; fs=fs->next)
1142             ;
1143     else {
1144         struct dn_pipe *p1;
1145         for (p1 = all_pipes; p1 && p1->pipe_nr != pipe_nr; p1 = p1->next)
1146             ;
1147         if (p1 != NULL)
1148             fs = &(p1->fs) ;
1149     }
1150     /* record for the future */
1151 #ifdef __i386__
1152     ((ipfw_insn_pipe *)cmd)->pipe_ptr = fs;
1153 #else
1154     bcopy(&fs, & ((ipfw_insn_pipe *)cmd)->pipe_ptr, sizeof(fs));
1155 #endif
1156     return fs ;
1157 }
1158
1159 /*
1160  * dummynet hook for packets. Below 'pipe' is a pipe or a queue
1161  * depending on whether WF2Q or fixed bw is used.
1162  *
1163  * pipe_nr      pipe or queue the packet is destined for.
1164  * dir          where shall we send the packet after dummynet.
1165  * m            the mbuf with the packet
1166  * ifp          the 'ifp' parameter from the caller.
1167  *              NULL in ip_input, destination interface in ip_output,
1168  *              real_dst in bdg_forward
1169  * rule         matching rule, in case of multiple passes
1170  * flags        flags from the caller, only used in ip_output
1171  *
1172  */
1173 static int
1174 dummynet_io(struct mbuf *m, int dir, struct ip_fw_args *fwa)
1175 {
1176     struct dn_pkt_tag *pkt;
1177     struct m_tag *mtag;
1178     struct dn_flow_set *fs;
1179     struct dn_pipe *pipe ;
1180     u_int64_t len = m->m_pkthdr.len ;
1181     struct dn_flow_queue *q = NULL ;
1182     int is_pipe;
1183     ipfw_insn *cmd = ACTION_PTR(fwa->rule);
1184
1185     KASSERT(m->m_nextpkt == NULL,
1186         ("dummynet_io: mbuf queue passed to dummynet"));
1187
1188     if (cmd->opcode == O_LOG)
1189         cmd += F_LEN(cmd);
1190     is_pipe = (cmd->opcode == O_PIPE);
1191
1192     DUMMYNET_LOCK();
1193     /*
1194      * This is a dummynet rule, so we expect an O_PIPE or O_QUEUE rule.
1195      */
1196     fs = locate_flowset(fwa->cookie, fwa->rule);
1197     if (fs == NULL)
1198         goto dropit ;   /* this queue/pipe does not exist! */
1199     pipe = fs->pipe ;
1200     if (pipe == NULL) { /* must be a queue, try find a matching pipe */
1201         for (pipe = all_pipes; pipe && pipe->pipe_nr != fs->parent_nr;
1202                  pipe = pipe->next)
1203             ;
1204         if (pipe != NULL)
1205             fs->pipe = pipe ;
1206         else {
1207             printf("dummynet: no pipe %d for queue %d, drop pkt\n",
1208                 fs->parent_nr, fs->fs_nr);
1209             goto dropit ;
1210         }
1211     }
1212     q = find_queue(fs, &(fwa->f_id));
1213     if ( q == NULL )
1214         goto dropit ;           /* cannot allocate queue                */
1215     /*
1216      * update statistics, then check reasons to drop pkt
1217      */
1218     q->tot_bytes += len ;
1219     q->tot_pkts++ ;
1220     if ( fs->plr && random() < fs->plr )
1221         goto dropit ;           /* random pkt drop                      */
1222     if ( fs->flags_fs & DN_QSIZE_IS_BYTES) {
1223         if (q->len_bytes > fs->qsize)
1224             goto dropit ;       /* queue size overflow                  */
1225     } else {
1226         if (q->len >= fs->qsize)
1227             goto dropit ;       /* queue count overflow                 */
1228     }
1229     if ( fs->flags_fs & DN_IS_RED && red_drops(fs, q, len) )
1230         goto dropit ;
1231
1232     /* XXX expensive to zero, see if we can remove it*/
1233     mtag = m_tag_get(PACKET_TAG_DUMMYNET,
1234                 sizeof(struct dn_pkt_tag), M_NOWAIT|M_ZERO);
1235     if ( mtag == NULL )
1236         goto dropit ;           /* cannot allocate packet header        */
1237     m_tag_prepend(m, mtag);     /* attach to mbuf chain */
1238
1239     pkt = (struct dn_pkt_tag *)(mtag+1);
1240     /* ok, i can handle the pkt now... */
1241     /* build and enqueue packet + parameters */
1242     pkt->rule = fwa->rule ;
1243     pkt->dn_dir = dir ;
1244
1245     pkt->ifp = fwa->oif;
1246     if (dir == DN_TO_IP_OUT || dir == DN_TO_IP6_OUT)
1247         pkt->flags = fwa->flags;
1248
1249     if (q->head == NULL)
1250         q->head = m;
1251     else
1252         q->tail->m_nextpkt = m;
1253     q->tail = m;
1254     q->len++;
1255     q->len_bytes += len ;
1256
1257     if ( q->head != m )         /* flow was not idle, we are done */
1258         goto done;
1259     /*
1260      * If we reach this point the flow was previously idle, so we need
1261      * to schedule it. This involves different actions for fixed-rate or
1262      * WF2Q queues.
1263      */
1264     if (is_pipe) {
1265         /*
1266          * Fixed-rate queue: just insert into the ready_heap.
1267          */
1268         dn_key t = 0 ;
1269         if (pipe->bandwidth)
1270             t = SET_TICKS(m, q, pipe);
1271         q->sched_time = curr_time ;
1272         if (t == 0)     /* must process it now */
1273             ready_event( q );
1274         else
1275             heap_insert(&ready_heap, curr_time + t , q );
1276     } else {
1277         /*
1278          * WF2Q. First, compute start time S: if the flow was idle (S=F+1)
1279          * set S to the virtual time V for the controlling pipe, and update
1280          * the sum of weights for the pipe; otherwise, remove flow from
1281          * idle_heap and set S to max(F,V).
1282          * Second, compute finish time F = S + len/weight.
1283          * Third, if pipe was idle, update V=max(S, V).
1284          * Fourth, count one more backlogged flow.
1285          */
1286         if (DN_KEY_GT(q->S, q->F)) { /* means timestamps are invalid */
1287             q->S = pipe->V ;
1288             pipe->sum += fs->weight ; /* add weight of new queue */
1289         } else {
1290             heap_extract(&(pipe->idle_heap), q);
1291             q->S = MAX64(q->F, pipe->V ) ;
1292         }
1293         q->F = q->S + ( len<<MY_M )/(u_int64_t) fs->weight;
1294
1295         if (pipe->not_eligible_heap.elements == 0 &&
1296                 pipe->scheduler_heap.elements == 0)
1297             pipe->V = MAX64 ( q->S, pipe->V );
1298         fs->backlogged++ ;
1299         /*
1300          * Look at eligibility. A flow is not eligibile if S>V (when
1301          * this happens, it means that there is some other flow already
1302          * scheduled for the same pipe, so the scheduler_heap cannot be
1303          * empty). If the flow is not eligible we just store it in the
1304          * not_eligible_heap. Otherwise, we store in the scheduler_heap
1305          * and possibly invoke ready_event_wfq() right now if there is
1306          * leftover credit.
1307          * Note that for all flows in scheduler_heap (SCH), S_i <= V,
1308          * and for all flows in not_eligible_heap (NEH), S_i > V .
1309          * So when we need to compute max( V, min(S_i) ) forall i in SCH+NEH,
1310          * we only need to look into NEH.
1311          */
1312         if (DN_KEY_GT(q->S, pipe->V) ) { /* not eligible */
1313             if (pipe->scheduler_heap.elements == 0)
1314                 printf("dummynet: ++ ouch! not eligible but empty scheduler!\n");
1315             heap_insert(&(pipe->not_eligible_heap), q->S, q);
1316         } else {
1317             heap_insert(&(pipe->scheduler_heap), q->F, q);
1318             if (pipe->numbytes >= 0) { /* pipe is idle */
1319                 if (pipe->scheduler_heap.elements != 1)
1320                     printf("dummynet: OUCH! pipe should have been idle!\n");
1321                 DPRINTF(("dummynet: waking up pipe %d at %d\n",
1322                         pipe->pipe_nr, (int)(q->F >> MY_M)));
1323                 pipe->sched_time = curr_time ;
1324                 ready_event_wfq(pipe);
1325             }
1326         }
1327     }
1328 done:
1329     DUMMYNET_UNLOCK();
1330     return 0;
1331
1332 dropit:
1333     if (q)
1334         q->drops++ ;
1335     DUMMYNET_UNLOCK();
1336     m_freem(m);
1337     return ( (fs && (fs->flags_fs & DN_NOERROR)) ? 0 : ENOBUFS);
1338 }
1339
1340 /*
1341  * Below, the rt_unref is only needed when (pkt->dn_dir == DN_TO_IP_OUT)
1342  * Doing this would probably save us the initial bzero of dn_pkt
1343  */
1344 #define DN_FREE_PKT(_m) do {                            \
1345         m_freem(_m);                                    \
1346 } while (0)
1347
1348 /*
1349  * Dispose all packets and flow_queues on a flow_set.
1350  * If all=1, also remove red lookup table and other storage,
1351  * including the descriptor itself.
1352  * For the one in dn_pipe MUST also cleanup ready_heap...
1353  */
1354 static void
1355 purge_flow_set(struct dn_flow_set *fs, int all)
1356 {
1357     struct dn_flow_queue *q, *qn ;
1358     int i ;
1359
1360     DUMMYNET_LOCK_ASSERT();
1361
1362     for (i = 0 ; i <= fs->rq_size ; i++ ) {
1363         for (q = fs->rq[i] ; q ; q = qn ) {
1364             struct mbuf *m, *mnext;
1365
1366             mnext = q->head;
1367             while ((m = mnext) != NULL) {
1368                 mnext = m->m_nextpkt;
1369                 DN_FREE_PKT(m);
1370             }
1371             qn = q->next ;
1372             free(q, M_DUMMYNET);
1373         }
1374         fs->rq[i] = NULL ;
1375     }
1376     fs->rq_elements = 0 ;
1377     if (all) {
1378         /* RED - free lookup table */
1379         if (fs->w_q_lookup)
1380             free(fs->w_q_lookup, M_DUMMYNET);
1381         if (fs->rq)
1382             free(fs->rq, M_DUMMYNET);
1383         /* if this fs is not part of a pipe, free it */
1384         if (fs->pipe && fs != &(fs->pipe->fs) )
1385             free(fs, M_DUMMYNET);
1386     }
1387 }
1388
1389 /*
1390  * Dispose all packets queued on a pipe (not a flow_set).
1391  * Also free all resources associated to a pipe, which is about
1392  * to be deleted.
1393  */
1394 static void
1395 purge_pipe(struct dn_pipe *pipe)
1396 {
1397     struct mbuf *m, *mnext;
1398
1399     purge_flow_set( &(pipe->fs), 1 );
1400
1401     mnext = pipe->head;
1402     while ((m = mnext) != NULL) {
1403         mnext = m->m_nextpkt;
1404         DN_FREE_PKT(m);
1405     }
1406
1407     heap_free( &(pipe->scheduler_heap) );
1408     heap_free( &(pipe->not_eligible_heap) );
1409     heap_free( &(pipe->idle_heap) );
1410 }
1411
1412 /*
1413  * Delete all pipes and heaps returning memory. Must also
1414  * remove references from all ipfw rules to all pipes.
1415  */
1416 static void
1417 dummynet_flush(void)
1418 {
1419     struct dn_pipe *curr_p, *p ;
1420     struct dn_flow_set *fs, *curr_fs;
1421
1422     DUMMYNET_LOCK();
1423     /* remove all references to pipes ...*/
1424     flush_pipe_ptrs(NULL);
1425     /* prevent future matches... */
1426     p = all_pipes ;
1427     all_pipes = NULL ;
1428     fs = all_flow_sets ;
1429     all_flow_sets = NULL ;
1430     /* and free heaps so we don't have unwanted events */
1431     heap_free(&ready_heap);
1432     heap_free(&wfq_ready_heap);
1433     heap_free(&extract_heap);
1434
1435     /*
1436      * Now purge all queued pkts and delete all pipes
1437      */
1438     /* scan and purge all flow_sets. */
1439     for ( ; fs ; ) {
1440         curr_fs = fs ;
1441         fs = fs->next ;
1442         purge_flow_set(curr_fs, 1);
1443     }
1444     for ( ; p ; ) {
1445         purge_pipe(p);
1446         curr_p = p ;
1447         p = p->next ;
1448         free(curr_p, M_DUMMYNET);
1449     }
1450     DUMMYNET_UNLOCK();
1451 }
1452
1453
1454 extern struct ip_fw *ip_fw_default_rule ;
1455 static void
1456 dn_rule_delete_fs(struct dn_flow_set *fs, void *r)
1457 {
1458     int i ;
1459     struct dn_flow_queue *q ;
1460     struct mbuf *m ;
1461
1462     for (i = 0 ; i <= fs->rq_size ; i++) /* last one is ovflow */
1463         for (q = fs->rq[i] ; q ; q = q->next )
1464             for (m = q->head ; m ; m = m->m_nextpkt ) {
1465                 struct dn_pkt_tag *pkt = dn_tag_get(m) ;
1466                 if (pkt->rule == r)
1467                     pkt->rule = ip_fw_default_rule ;
1468             }
1469 }
1470 /*
1471  * when a firewall rule is deleted, scan all queues and remove the flow-id
1472  * from packets matching this rule.
1473  */
1474 void
1475 dn_rule_delete(void *r)
1476 {
1477     struct dn_pipe *p ;
1478     struct dn_flow_set *fs ;
1479     struct dn_pkt_tag *pkt ;
1480     struct mbuf *m ;
1481
1482     DUMMYNET_LOCK();
1483     /*
1484      * If the rule references a queue (dn_flow_set), then scan
1485      * the flow set, otherwise scan pipes. Should do either, but doing
1486      * both does not harm.
1487      */
1488     for ( fs = all_flow_sets ; fs ; fs = fs->next )
1489         dn_rule_delete_fs(fs, r);
1490     for ( p = all_pipes ; p ; p = p->next ) {
1491         fs = &(p->fs) ;
1492         dn_rule_delete_fs(fs, r);
1493         for (m = p->head ; m ; m = m->m_nextpkt ) {
1494             pkt = dn_tag_get(m) ;
1495             if (pkt->rule == r)
1496                 pkt->rule = ip_fw_default_rule ;
1497         }
1498     }
1499     DUMMYNET_UNLOCK();
1500 }
1501
1502 /*
1503  * setup RED parameters
1504  */
1505 static int
1506 config_red(struct dn_flow_set *p, struct dn_flow_set * x)
1507 {
1508     int i;
1509
1510     x->w_q = p->w_q;
1511     x->min_th = SCALE(p->min_th);
1512     x->max_th = SCALE(p->max_th);
1513     x->max_p = p->max_p;
1514
1515     x->c_1 = p->max_p / (p->max_th - p->min_th);
1516     x->c_2 = SCALE_MUL(x->c_1, SCALE(p->min_th));
1517     if (x->flags_fs & DN_IS_GENTLE_RED) {
1518         x->c_3 = (SCALE(1) - p->max_p) / p->max_th;
1519         x->c_4 = (SCALE(1) - 2 * p->max_p);
1520     }
1521
1522     /* if the lookup table already exist, free and create it again */
1523     if (x->w_q_lookup) {
1524         free(x->w_q_lookup, M_DUMMYNET);
1525         x->w_q_lookup = NULL ;
1526     }
1527     if (red_lookup_depth == 0) {
1528         printf("\ndummynet: net.inet.ip.dummynet.red_lookup_depth must be > 0\n");
1529         free(x, M_DUMMYNET);
1530         return EINVAL;
1531     }
1532     x->lookup_depth = red_lookup_depth;
1533     x->w_q_lookup = (u_int *) malloc(x->lookup_depth * sizeof(int),
1534             M_DUMMYNET, M_NOWAIT);
1535     if (x->w_q_lookup == NULL) {
1536         printf("dummynet: sorry, cannot allocate red lookup table\n");
1537         free(x, M_DUMMYNET);
1538         return ENOSPC;
1539     }
1540
1541     /* fill the lookup table with (1 - w_q)^x */
1542     x->lookup_step = p->lookup_step ;
1543     x->lookup_weight = p->lookup_weight ;
1544     x->w_q_lookup[0] = SCALE(1) - x->w_q;
1545     for (i = 1; i < x->lookup_depth; i++)
1546         x->w_q_lookup[i] = SCALE_MUL(x->w_q_lookup[i - 1], x->lookup_weight);
1547     if (red_avg_pkt_size < 1)
1548         red_avg_pkt_size = 512 ;
1549     x->avg_pkt_size = red_avg_pkt_size ;
1550     if (red_max_pkt_size < 1)
1551         red_max_pkt_size = 1500 ;
1552     x->max_pkt_size = red_max_pkt_size ;
1553     return 0 ;
1554 }
1555
1556 static int
1557 alloc_hash(struct dn_flow_set *x, struct dn_flow_set *pfs)
1558 {
1559     if (x->flags_fs & DN_HAVE_FLOW_MASK) {     /* allocate some slots */
1560         int l = pfs->rq_size;
1561
1562         if (l == 0)
1563             l = dn_hash_size;
1564         if (l < 4)
1565             l = 4;
1566         else if (l > DN_MAX_HASH_SIZE)
1567             l = DN_MAX_HASH_SIZE;
1568         x->rq_size = l;
1569     } else                  /* one is enough for null mask */
1570         x->rq_size = 1;
1571     x->rq = malloc((1 + x->rq_size) * sizeof(struct dn_flow_queue *),
1572             M_DUMMYNET, M_NOWAIT | M_ZERO);
1573     if (x->rq == NULL) {
1574         printf("dummynet: sorry, cannot allocate queue\n");
1575         return ENOSPC;
1576     }
1577     x->rq_elements = 0;
1578     return 0 ;
1579 }
1580
1581 static void
1582 set_fs_parms(struct dn_flow_set *x, struct dn_flow_set *src)
1583 {
1584     x->flags_fs = src->flags_fs;
1585     x->qsize = src->qsize;
1586     x->plr = src->plr;
1587     x->flow_mask = src->flow_mask;
1588     if (x->flags_fs & DN_QSIZE_IS_BYTES) {
1589         if (x->qsize > 1024*1024)
1590             x->qsize = 1024*1024 ;
1591     } else {
1592         if (x->qsize == 0)
1593             x->qsize = 50 ;
1594         if (x->qsize > 100)
1595             x->qsize = 50 ;
1596     }
1597     /* configuring RED */
1598     if ( x->flags_fs & DN_IS_RED )
1599         config_red(src, x) ;    /* XXX should check errors */
1600 }
1601
1602 /*
1603  * setup pipe or queue parameters.
1604  */
1605
1606 static int
1607 config_pipe(struct dn_pipe *p)
1608 {
1609     int i, r;
1610     struct dn_flow_set *pfs = &(p->fs);
1611     struct dn_flow_queue *q;
1612
1613     /*
1614      * The config program passes parameters as follows:
1615      * bw = bits/second (0 means no limits),
1616      * delay = ms, must be translated into ticks.
1617      * qsize = slots/bytes
1618      */
1619     p->delay = ( p->delay * hz ) / 1000 ;
1620     /* We need either a pipe number or a flow_set number */
1621     if (p->pipe_nr == 0 && pfs->fs_nr == 0)
1622         return EINVAL ;
1623     if (p->pipe_nr != 0 && pfs->fs_nr != 0)
1624         return EINVAL ;
1625     if (p->pipe_nr != 0) { /* this is a pipe */
1626         struct dn_pipe *x, *a, *b;
1627
1628         DUMMYNET_LOCK();
1629         /* locate pipe */
1630         for (a = NULL , b = all_pipes ; b && b->pipe_nr < p->pipe_nr ;
1631                  a = b , b = b->next) ;
1632
1633         if (b == NULL || b->pipe_nr != p->pipe_nr) { /* new pipe */
1634             x = malloc(sizeof(struct dn_pipe), M_DUMMYNET, M_NOWAIT | M_ZERO);
1635             if (x == NULL) {
1636                 DUMMYNET_UNLOCK();
1637                 printf("dummynet: no memory for new pipe\n");
1638                 return ENOSPC;
1639             }
1640             x->pipe_nr = p->pipe_nr;
1641             x->fs.pipe = x ;
1642             /* idle_heap is the only one from which we extract from the middle.
1643              */
1644             x->idle_heap.size = x->idle_heap.elements = 0 ;
1645             x->idle_heap.offset=OFFSET_OF(struct dn_flow_queue, heap_pos);
1646         } else {
1647             x = b;
1648             /* Flush accumulated credit for all queues */
1649             for (i = 0; i <= x->fs.rq_size; i++)
1650                 for (q = x->fs.rq[i]; q; q = q->next)
1651                     q->numbytes = 0;
1652         }
1653
1654         x->bandwidth = p->bandwidth ;
1655         x->numbytes = 0; /* just in case... */
1656         bcopy(p->if_name, x->if_name, sizeof(p->if_name) );
1657         x->ifp = NULL ; /* reset interface ptr */
1658         x->delay = p->delay ;
1659         set_fs_parms(&(x->fs), pfs);
1660
1661
1662         if ( x->fs.rq == NULL ) { /* a new pipe */
1663             r = alloc_hash(&(x->fs), pfs) ;
1664             if (r) {
1665                 DUMMYNET_UNLOCK();
1666                 free(x, M_DUMMYNET);
1667                 return r ;
1668             }
1669             x->next = b ;
1670             if (a == NULL)
1671                 all_pipes = x ;
1672             else
1673                 a->next = x ;
1674         }
1675         DUMMYNET_UNLOCK();
1676     } else { /* config queue */
1677         struct dn_flow_set *x, *a, *b ;
1678
1679         DUMMYNET_LOCK();
1680         /* locate flow_set */
1681         for (a=NULL, b=all_flow_sets ; b && b->fs_nr < pfs->fs_nr ;
1682                  a = b , b = b->next) ;
1683
1684         if (b == NULL || b->fs_nr != pfs->fs_nr) { /* new  */
1685             if (pfs->parent_nr == 0) {  /* need link to a pipe */
1686                 DUMMYNET_UNLOCK();
1687                 return EINVAL ;
1688             }
1689             x = malloc(sizeof(struct dn_flow_set), M_DUMMYNET, M_NOWAIT|M_ZERO);
1690             if (x == NULL) {
1691                 DUMMYNET_UNLOCK();
1692                 printf("dummynet: no memory for new flow_set\n");
1693                 return ENOSPC;
1694             }
1695             x->fs_nr = pfs->fs_nr;
1696             x->parent_nr = pfs->parent_nr;
1697             x->weight = pfs->weight ;
1698             if (x->weight == 0)
1699                 x->weight = 1 ;
1700             else if (x->weight > 100)
1701                 x->weight = 100 ;
1702         } else {
1703             /* Change parent pipe not allowed; must delete and recreate */
1704             if (pfs->parent_nr != 0 && b->parent_nr != pfs->parent_nr) {
1705                 DUMMYNET_UNLOCK();
1706                 return EINVAL ;
1707             }
1708             x = b;
1709         }
1710         set_fs_parms(x, pfs);
1711
1712         if ( x->rq == NULL ) { /* a new flow_set */
1713             r = alloc_hash(x, pfs) ;
1714             if (r) {
1715                 DUMMYNET_UNLOCK();
1716                 free(x, M_DUMMYNET);
1717                 return r ;
1718             }
1719             x->next = b;
1720             if (a == NULL)
1721                 all_flow_sets = x;
1722             else
1723                 a->next = x;
1724         }
1725         DUMMYNET_UNLOCK();
1726     }
1727     return 0 ;
1728 }
1729
1730 /*
1731  * Helper function to remove from a heap queues which are linked to
1732  * a flow_set about to be deleted.
1733  */
1734 static void
1735 fs_remove_from_heap(struct dn_heap *h, struct dn_flow_set *fs)
1736 {
1737     int i = 0, found = 0 ;
1738     for (; i < h->elements ;)
1739         if ( ((struct dn_flow_queue *)h->p[i].object)->fs == fs) {
1740             h->elements-- ;
1741             h->p[i] = h->p[h->elements] ;
1742             found++ ;
1743         } else
1744             i++ ;
1745     if (found)
1746         heapify(h);
1747 }
1748
1749 /*
1750  * helper function to remove a pipe from a heap (can be there at most once)
1751  */
1752 static void
1753 pipe_remove_from_heap(struct dn_heap *h, struct dn_pipe *p)
1754 {
1755     if (h->elements > 0) {
1756         int i = 0 ;
1757         for (i=0; i < h->elements ; i++ ) {
1758             if (h->p[i].object == p) { /* found it */
1759                 h->elements-- ;
1760                 h->p[i] = h->p[h->elements] ;
1761                 heapify(h);
1762                 break ;
1763             }
1764         }
1765     }
1766 }
1767
1768 /*
1769  * drain all queues. Called in case of severe mbuf shortage.
1770  */
1771 void
1772 dummynet_drain()
1773 {
1774     struct dn_flow_set *fs;
1775     struct dn_pipe *p;
1776     struct mbuf *m, *mnext;
1777
1778     DUMMYNET_LOCK_ASSERT();
1779
1780     heap_free(&ready_heap);
1781     heap_free(&wfq_ready_heap);
1782     heap_free(&extract_heap);
1783     /* remove all references to this pipe from flow_sets */
1784     for (fs = all_flow_sets; fs; fs= fs->next )
1785         purge_flow_set(fs, 0);
1786
1787     for (p = all_pipes; p; p= p->next ) {
1788         purge_flow_set(&(p->fs), 0);
1789
1790         mnext = p->head;
1791         while ((m = mnext) != NULL) {
1792             mnext = m->m_nextpkt;
1793             DN_FREE_PKT(m);
1794         }
1795         p->head = p->tail = NULL ;
1796     }
1797 }
1798
1799 /*
1800  * Fully delete a pipe or a queue, cleaning up associated info.
1801  */
1802 static int
1803 delete_pipe(struct dn_pipe *p)
1804 {
1805     if (p->pipe_nr == 0 && p->fs.fs_nr == 0)
1806         return EINVAL ;
1807     if (p->pipe_nr != 0 && p->fs.fs_nr != 0)
1808         return EINVAL ;
1809     if (p->pipe_nr != 0) { /* this is an old-style pipe */
1810         struct dn_pipe *a, *b;
1811         struct dn_flow_set *fs;
1812
1813         DUMMYNET_LOCK();
1814         /* locate pipe */
1815         for (a = NULL , b = all_pipes ; b && b->pipe_nr < p->pipe_nr ;
1816                  a = b , b = b->next) ;
1817         if (b == NULL || (b->pipe_nr != p->pipe_nr) ) {
1818             DUMMYNET_UNLOCK();
1819             return EINVAL ; /* not found */
1820         }
1821
1822         /* unlink from list of pipes */
1823         if (a == NULL)
1824             all_pipes = b->next ;
1825         else
1826             a->next = b->next ;
1827         /* remove references to this pipe from the ip_fw rules. */
1828         flush_pipe_ptrs(&(b->fs));
1829
1830         /* remove all references to this pipe from flow_sets */
1831         for (fs = all_flow_sets; fs; fs= fs->next )
1832             if (fs->pipe == b) {
1833                 printf("dummynet: ++ ref to pipe %d from fs %d\n",
1834                         p->pipe_nr, fs->fs_nr);
1835                 fs->pipe = NULL ;
1836                 purge_flow_set(fs, 0);
1837             }
1838         fs_remove_from_heap(&ready_heap, &(b->fs));
1839         purge_pipe(b);  /* remove all data associated to this pipe */
1840         /* remove reference to here from extract_heap and wfq_ready_heap */
1841         pipe_remove_from_heap(&extract_heap, b);
1842         pipe_remove_from_heap(&wfq_ready_heap, b);
1843         DUMMYNET_UNLOCK();
1844
1845         free(b, M_DUMMYNET);
1846     } else { /* this is a WF2Q queue (dn_flow_set) */
1847         struct dn_flow_set *a, *b;
1848
1849         DUMMYNET_LOCK();
1850         /* locate set */
1851         for (a = NULL, b = all_flow_sets ; b && b->fs_nr < p->fs.fs_nr ;
1852                  a = b , b = b->next) ;
1853         if (b == NULL || (b->fs_nr != p->fs.fs_nr) ) {
1854             DUMMYNET_UNLOCK();
1855             return EINVAL ; /* not found */
1856         }
1857
1858         if (a == NULL)
1859             all_flow_sets = b->next ;
1860         else
1861             a->next = b->next ;
1862         /* remove references to this flow_set from the ip_fw rules. */
1863         flush_pipe_ptrs(b);
1864
1865         if (b->pipe != NULL) {
1866             /* Update total weight on parent pipe and cleanup parent heaps */
1867             b->pipe->sum -= b->weight * b->backlogged ;
1868             fs_remove_from_heap(&(b->pipe->not_eligible_heap), b);
1869             fs_remove_from_heap(&(b->pipe->scheduler_heap), b);
1870 #if 1   /* XXX should i remove from idle_heap as well ? */
1871             fs_remove_from_heap(&(b->pipe->idle_heap), b);
1872 #endif
1873         }
1874         purge_flow_set(b, 1);
1875         DUMMYNET_UNLOCK();
1876     }
1877     return 0 ;
1878 }
1879
1880 /*
1881  * helper function used to copy data from kernel in DUMMYNET_GET
1882  */
1883 static char *
1884 dn_copy_set(struct dn_flow_set *set, char *bp)
1885 {
1886     int i, copied = 0 ;
1887     struct dn_flow_queue *q, *qp = (struct dn_flow_queue *)bp;
1888
1889     DUMMYNET_LOCK_ASSERT();
1890
1891     for (i = 0 ; i <= set->rq_size ; i++)
1892         for (q = set->rq[i] ; q ; q = q->next, qp++ ) {
1893             if (q->hash_slot != i)
1894                 printf("dummynet: ++ at %d: wrong slot (have %d, "
1895                     "should be %d)\n", copied, q->hash_slot, i);
1896             if (q->fs != set)
1897                 printf("dummynet: ++ at %d: wrong fs ptr (have %p, should be %p)\n",
1898                         i, q->fs, set);
1899             copied++ ;
1900             bcopy(q, qp, sizeof( *q ) );
1901             /* cleanup pointers */
1902             qp->next = NULL ;
1903             qp->head = qp->tail = NULL ;
1904             qp->fs = NULL ;
1905         }
1906     if (copied != set->rq_elements)
1907         printf("dummynet: ++ wrong count, have %d should be %d\n",
1908             copied, set->rq_elements);
1909     return (char *)qp ;
1910 }
1911
1912 static size_t
1913 dn_calc_size(void)
1914 {
1915     struct dn_flow_set *set ;
1916     struct dn_pipe *p ;
1917     size_t size ;
1918
1919     DUMMYNET_LOCK_ASSERT();
1920     /*
1921      * compute size of data structures: list of pipes and flow_sets.
1922      */
1923     for (p = all_pipes, size = 0 ; p ; p = p->next )
1924         size += sizeof( *p ) +
1925             p->fs.rq_elements * sizeof(struct dn_flow_queue);
1926     for (set = all_flow_sets ; set ; set = set->next )
1927         size += sizeof ( *set ) +
1928             set->rq_elements * sizeof(struct dn_flow_queue);
1929     return size ;
1930 }
1931
1932 static int
1933 dummynet_get(struct sockopt *sopt)
1934 {
1935     char *buf, *bp ; /* bp is the "copy-pointer" */
1936     size_t size ;
1937     struct dn_flow_set *set ;
1938     struct dn_pipe *p ;
1939     int error=0, i ;
1940
1941     /* XXX lock held too long */
1942     DUMMYNET_LOCK();
1943     /*
1944      * XXX: Ugly, but we need to allocate memory with M_WAITOK flag and we
1945      *      cannot use this flag while holding a mutex.
1946      */
1947     for (i = 0; i < 10; i++) {
1948         size = dn_calc_size();
1949         DUMMYNET_UNLOCK();
1950         buf = malloc(size, M_TEMP, M_WAITOK);
1951         DUMMYNET_LOCK();
1952         if (size == dn_calc_size())
1953                 break;
1954         free(buf, M_TEMP);
1955         buf = NULL;
1956     }
1957     if (buf == NULL) {
1958         DUMMYNET_UNLOCK();
1959         return ENOBUFS ;
1960     }
1961     for (p = all_pipes, bp = buf ; p ; p = p->next ) {
1962         struct dn_pipe *pipe_bp = (struct dn_pipe *)bp ;
1963
1964         /*
1965          * copy pipe descriptor into *bp, convert delay back to ms,
1966          * then copy the flow_set descriptor(s) one at a time.
1967          * After each flow_set, copy the queue descriptor it owns.
1968          */
1969         bcopy(p, bp, sizeof( *p ) );
1970         pipe_bp->delay = (pipe_bp->delay * 1000) / hz ;
1971         /*
1972          * XXX the following is a hack based on ->next being the
1973          * first field in dn_pipe and dn_flow_set. The correct
1974          * solution would be to move the dn_flow_set to the beginning
1975          * of struct dn_pipe.
1976          */
1977         pipe_bp->next = (struct dn_pipe *)DN_IS_PIPE ;
1978         /* clean pointers */
1979         pipe_bp->head = pipe_bp->tail = NULL ;
1980         pipe_bp->fs.next = NULL ;
1981         pipe_bp->fs.pipe = NULL ;
1982         pipe_bp->fs.rq = NULL ;
1983
1984         bp += sizeof( *p ) ;
1985         bp = dn_copy_set( &(p->fs), bp );
1986     }
1987     for (set = all_flow_sets ; set ; set = set->next ) {
1988         struct dn_flow_set *fs_bp = (struct dn_flow_set *)bp ;
1989         bcopy(set, bp, sizeof( *set ) );
1990         /* XXX same hack as above */
1991         fs_bp->next = (struct dn_flow_set *)DN_IS_QUEUE ;
1992         fs_bp->pipe = NULL ;
1993         fs_bp->rq = NULL ;
1994         bp += sizeof( *set ) ;
1995         bp = dn_copy_set( set, bp );
1996     }
1997     DUMMYNET_UNLOCK();
1998
1999     error = sooptcopyout(sopt, buf, size);
2000     free(buf, M_TEMP);
2001     return error ;
2002 }
2003
2004 /*
2005  * Handler for the various dummynet socket options (get, flush, config, del)
2006  */
2007 static int
2008 ip_dn_ctl(struct sockopt *sopt)
2009 {
2010     int error = 0 ;
2011     struct dn_pipe *p, tmp_pipe;
2012
2013     /* Disallow sets in really-really secure mode. */
2014     if (sopt->sopt_dir == SOPT_SET) {
2015 #if __FreeBSD_version >= 500034
2016         error =  securelevel_ge(sopt->sopt_td->td_ucred, 3);
2017         if (error)
2018             return (error);
2019 #else
2020         if (securelevel >= 3)
2021             return (EPERM);
2022 #endif
2023     }
2024
2025     switch (sopt->sopt_name) {
2026     default :
2027         printf("dummynet: -- unknown option %d", sopt->sopt_name);
2028         return EINVAL ;
2029
2030     case IP_DUMMYNET_GET :
2031         error = dummynet_get(sopt);
2032         break ;
2033
2034     case IP_DUMMYNET_FLUSH :
2035         dummynet_flush() ;
2036         break ;
2037
2038     case IP_DUMMYNET_CONFIGURE :
2039         p = &tmp_pipe ;
2040         error = sooptcopyin(sopt, p, sizeof *p, sizeof *p);
2041         if (error)
2042             break ;
2043         error = config_pipe(p);
2044         break ;
2045
2046     case IP_DUMMYNET_DEL :      /* remove a pipe or queue */
2047         p = &tmp_pipe ;
2048         error = sooptcopyin(sopt, p, sizeof *p, sizeof *p);
2049         if (error)
2050             break ;
2051
2052         error = delete_pipe(p);
2053         break ;
2054     }
2055     return error ;
2056 }
2057
2058 static void
2059 ip_dn_init(void)
2060 {
2061     if (bootverbose)
2062             printf("DUMMYNET with IPv6 initialized (040826)\n");
2063
2064     DUMMYNET_LOCK_INIT();
2065
2066     all_pipes = NULL ;
2067     all_flow_sets = NULL ;
2068     ready_heap.size = ready_heap.elements = 0 ;
2069     ready_heap.offset = 0 ;
2070
2071     wfq_ready_heap.size = wfq_ready_heap.elements = 0 ;
2072     wfq_ready_heap.offset = 0 ;
2073
2074     extract_heap.size = extract_heap.elements = 0 ;
2075     extract_heap.offset = 0 ;
2076
2077     ip_dn_ctl_ptr = ip_dn_ctl;
2078     ip_dn_io_ptr = dummynet_io;
2079     ip_dn_ruledel_ptr = dn_rule_delete;
2080
2081     callout_init(&dn_timeout, NET_CALLOUT_MPSAFE);
2082     callout_reset(&dn_timeout, 1, dummynet, NULL);
2083 }
2084
2085 #ifdef KLD_MODULE
2086 static void
2087 ip_dn_destroy(void)
2088 {
2089     ip_dn_ctl_ptr = NULL;
2090     ip_dn_io_ptr = NULL;
2091     ip_dn_ruledel_ptr = NULL;
2092
2093     callout_stop(&dn_timeout);
2094     dummynet_flush();
2095
2096     DUMMYNET_LOCK_DESTROY();
2097 }
2098 #endif /* KLD_MODULE */
2099
2100 static int
2101 dummynet_modevent(module_t mod, int type, void *data)
2102 {
2103         switch (type) {
2104         case MOD_LOAD:
2105                 if (DUMMYNET_LOADED) {
2106                     printf("DUMMYNET already loaded\n");
2107                     return EEXIST ;
2108                 }
2109                 ip_dn_init();
2110                 break;
2111
2112         case MOD_UNLOAD:
2113 #if !defined(KLD_MODULE)
2114                 printf("dummynet statically compiled, cannot unload\n");
2115                 return EINVAL ;
2116 #else
2117                 ip_dn_destroy();
2118 #endif
2119                 break ;
2120         default:
2121                 return EOPNOTSUPP;
2122                 break ;
2123         }
2124         return 0 ;
2125 }
2126
2127 static moduledata_t dummynet_mod = {
2128         "dummynet",
2129         dummynet_modevent,
2130         NULL
2131 };
2132 DECLARE_MODULE(dummynet, dummynet_mod, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY);
2133 MODULE_DEPEND(dummynet, ipfw, 2, 2, 2);
2134 MODULE_VERSION(dummynet, 1);