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