]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - sys/netpfil/ipfw/ip_dn_glue.c
MFC r300779, r300781, r300783, r300784, r300949, r301162, r301180
[FreeBSD/stable/10.git] / sys / netpfil / ipfw / ip_dn_glue.c
1 /*-
2  * Copyright (c) 2010 Riccardo Panicucci, Universita` di Pisa
3  * All rights reserved
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26
27 /*
28  * $FreeBSD$
29  *
30  * Binary compatibility support for /sbin/ipfw RELENG_7 and RELENG_8
31  */
32
33 #include "opt_inet6.h"
34
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/malloc.h>
38 #include <sys/mbuf.h>
39 #include <sys/kernel.h>
40 #include <sys/lock.h>
41 #include <sys/module.h>
42 #include <sys/priv.h>
43 #include <sys/proc.h>
44 #include <sys/rwlock.h>
45 #include <sys/socket.h>
46 #include <sys/socketvar.h>
47 #include <sys/time.h>
48 #include <sys/taskqueue.h>
49 #include <net/if.h>     /* IFNAMSIZ, struct ifaddr, ifq head, lock.h mutex.h */
50 #include <netinet/in.h>
51 #include <netinet/ip_var.h>     /* ip_output(), IP_FORWARDING */
52 #include <netinet/ip_fw.h>
53 #include <netinet/ip_dummynet.h>
54
55 #include <netpfil/ipfw/ip_fw_private.h>
56 #include <netpfil/ipfw/dn_heap.h>
57 #include <netpfil/ipfw/ip_dn_private.h>
58 #ifdef NEW_AQM
59 #include <netpfil/ipfw/dn_aqm.h>
60 #endif
61 #include <netpfil/ipfw/dn_sched.h>
62
63 /* FREEBSD7.2 ip_dummynet.h r191715*/
64
65 struct dn_heap_entry7 {
66         int64_t key;        /* sorting key. Topmost element is smallest one */
67         void *object;      /* object pointer */
68 };
69
70 struct dn_heap7 {
71         int size;
72         int elements;
73         int offset; /* XXX if > 0 this is the offset of direct ptr to obj */
74         struct dn_heap_entry7 *p;   /* really an array of "size" entries */
75 };
76
77 /* Common to 7.2 and 8 */
78 struct dn_flow_set {
79         SLIST_ENTRY(dn_flow_set)    next;   /* linked list in a hash slot */
80
81         u_short fs_nr ;             /* flow_set number       */
82         u_short flags_fs;
83 #define DNOLD_HAVE_FLOW_MASK   0x0001
84 #define DNOLD_IS_RED       0x0002
85 #define DNOLD_IS_GENTLE_RED    0x0004
86 #define DNOLD_QSIZE_IS_BYTES   0x0008  /* queue size is measured in bytes */
87 #define DNOLD_NOERROR      0x0010  /* do not report ENOBUFS on drops  */
88 #define DNOLD_HAS_PROFILE      0x0020  /* the pipe has a delay profile. */
89 #define DNOLD_IS_PIPE      0x4000
90 #define DNOLD_IS_QUEUE     0x8000
91
92         struct dn_pipe7 *pipe ;  /* pointer to parent pipe */
93         u_short parent_nr ;     /* parent pipe#, 0 if local to a pipe */
94
95         int weight ;        /* WFQ queue weight */
96         int qsize ;         /* queue size in slots or bytes */
97         int plr ;           /* pkt loss rate (2^31-1 means 100%) */
98
99         struct ipfw_flow_id flow_mask ;
100
101         /* hash table of queues onto this flow_set */
102         int rq_size ;       /* number of slots */
103         int rq_elements ;       /* active elements */
104         struct dn_flow_queue7 **rq;  /* array of rq_size entries */
105
106         u_int32_t last_expired ;    /* do not expire too frequently */
107         int backlogged ;        /* #active queues for this flowset */
108
109         /* RED parameters */
110 #define SCALE_RED               16
111 #define SCALE(x)                ( (x) << SCALE_RED )
112 #define SCALE_VAL(x)            ( (x) >> SCALE_RED )
113 #define SCALE_MUL(x,y)          ( ( (x) * (y) ) >> SCALE_RED )
114         int w_q ;           /* queue weight (scaled) */
115         int max_th ;        /* maximum threshold for queue (scaled) */
116         int min_th ;        /* minimum threshold for queue (scaled) */
117         int max_p ;         /* maximum value for p_b (scaled) */
118         u_int c_1 ;         /* max_p/(max_th-min_th) (scaled) */
119         u_int c_2 ;         /* max_p*min_th/(max_th-min_th) (scaled) */
120         u_int c_3 ;         /* for GRED, (1-max_p)/max_th (scaled) */
121         u_int c_4 ;         /* for GRED, 1 - 2*max_p (scaled) */
122         u_int * w_q_lookup ;    /* lookup table for computing (1-w_q)^t */
123         u_int lookup_depth ;    /* depth of lookup table */
124         int lookup_step ;       /* granularity inside the lookup table */
125         int lookup_weight ;     /* equal to (1-w_q)^t / (1-w_q)^(t+1) */
126         int avg_pkt_size ;      /* medium packet size */
127         int max_pkt_size ;      /* max packet size */
128 };
129 SLIST_HEAD(dn_flow_set_head, dn_flow_set);
130
131 #define DN_IS_PIPE              0x4000
132 #define DN_IS_QUEUE             0x8000
133 struct dn_flow_queue7 {
134         struct dn_flow_queue7 *next ;
135         struct ipfw_flow_id id ;
136
137         struct mbuf *head, *tail ;  /* queue of packets */
138         u_int len ;
139         u_int len_bytes ;
140
141         u_long numbytes;
142
143         u_int64_t tot_pkts ;    /* statistics counters  */
144         u_int64_t tot_bytes ;
145         u_int32_t drops ;
146
147         int hash_slot ;     /* debugging/diagnostic */
148
149         /* RED parameters */
150         int avg ;                   /* average queue length est. (scaled) */
151         int count ;                 /* arrivals since last RED drop */
152         int random ;                /* random value (scaled) */
153         u_int32_t q_time;      /* start of queue idle time */
154
155         /* WF2Q+ support */
156         struct dn_flow_set *fs ;    /* parent flow set */
157         int heap_pos ;      /* position (index) of struct in heap */
158         int64_t sched_time ;     /* current time when queue enters ready_heap */
159
160         int64_t S,F ;        /* start time, finish time */
161 };
162
163 struct dn_pipe7 {        /* a pipe */
164         SLIST_ENTRY(dn_pipe7)    next;   /* linked list in a hash slot */
165
166         int pipe_nr ;       /* number   */
167         int bandwidth;      /* really, bytes/tick.  */
168         int delay ;         /* really, ticks    */
169
170         struct  mbuf *head, *tail ; /* packets in delay line */
171
172         /* WF2Q+ */
173         struct dn_heap7 scheduler_heap ; /* top extract - key Finish time*/
174         struct dn_heap7 not_eligible_heap; /* top extract- key Start time */
175         struct dn_heap7 idle_heap ; /* random extract - key Start=Finish time */
176
177         int64_t V ;          /* virtual time */
178         int sum;            /* sum of weights of all active sessions */
179
180         int numbytes;
181
182         int64_t sched_time ;     /* time pipe was scheduled in ready_heap */
183
184         /*
185         * When the tx clock come from an interface (if_name[0] != '\0'), its name
186         * is stored below, whereas the ifp is filled when the rule is configured.
187         */
188         char if_name[IFNAMSIZ];
189         struct ifnet *ifp ;
190         int ready ; /* set if ifp != NULL and we got a signal from it */
191
192         struct dn_flow_set fs ; /* used with fixed-rate flows */
193 };
194 SLIST_HEAD(dn_pipe_head7, dn_pipe7);
195
196
197 /* FREEBSD8 ip_dummynet.h r196045 */
198 struct dn_flow_queue8 {
199         struct dn_flow_queue8 *next ;
200         struct ipfw_flow_id id ;
201
202         struct mbuf *head, *tail ;  /* queue of packets */
203         u_int len ;
204         u_int len_bytes ;
205
206         uint64_t numbytes ;     /* credit for transmission (dynamic queues) */
207         int64_t extra_bits;     /* extra bits simulating unavailable channel */
208
209         u_int64_t tot_pkts ;    /* statistics counters  */
210         u_int64_t tot_bytes ;
211         u_int32_t drops ;
212
213         int hash_slot ;     /* debugging/diagnostic */
214
215         /* RED parameters */
216         int avg ;                   /* average queue length est. (scaled) */
217         int count ;                 /* arrivals since last RED drop */
218         int random ;                /* random value (scaled) */
219         int64_t idle_time;       /* start of queue idle time */
220
221         /* WF2Q+ support */
222         struct dn_flow_set *fs ;    /* parent flow set */
223         int heap_pos ;      /* position (index) of struct in heap */
224         int64_t sched_time ;     /* current time when queue enters ready_heap */
225
226         int64_t S,F ;        /* start time, finish time */
227 };
228
229 struct dn_pipe8 {        /* a pipe */
230         SLIST_ENTRY(dn_pipe8)    next;   /* linked list in a hash slot */
231
232         int pipe_nr ;       /* number   */
233         int bandwidth;      /* really, bytes/tick.  */
234         int delay ;         /* really, ticks    */
235
236         struct  mbuf *head, *tail ; /* packets in delay line */
237
238         /* WF2Q+ */
239         struct dn_heap7 scheduler_heap ; /* top extract - key Finish time*/
240         struct dn_heap7 not_eligible_heap; /* top extract- key Start time */
241         struct dn_heap7 idle_heap ; /* random extract - key Start=Finish time */
242
243         int64_t V ;          /* virtual time */
244         int sum;            /* sum of weights of all active sessions */
245
246         /* Same as in dn_flow_queue, numbytes can become large */
247         int64_t numbytes;       /* bits I can transmit (more or less). */
248         uint64_t burst;     /* burst size, scaled: bits * hz */
249
250         int64_t sched_time ;     /* time pipe was scheduled in ready_heap */
251         int64_t idle_time;       /* start of pipe idle time */
252
253         char if_name[IFNAMSIZ];
254         struct ifnet *ifp ;
255         int ready ; /* set if ifp != NULL and we got a signal from it */
256
257         struct dn_flow_set fs ; /* used with fixed-rate flows */
258
259     /* fields to simulate a delay profile */
260 #define ED_MAX_NAME_LEN     32
261         char name[ED_MAX_NAME_LEN];
262         int loss_level;
263         int samples_no;
264         int *samples;
265 };
266
267 #define ED_MAX_SAMPLES_NO   1024
268 struct dn_pipe_max8 {
269         struct dn_pipe8 pipe;
270         int samples[ED_MAX_SAMPLES_NO];
271 };
272 SLIST_HEAD(dn_pipe_head8, dn_pipe8);
273
274 /*
275  * Changes from 7.2 to 8:
276  * dn_pipe:
277  *      numbytes from int to int64_t
278  *      add burst (int64_t)
279  *      add idle_time (int64_t)
280  *      add profile
281  *      add struct dn_pipe_max
282  *      add flag DN_HAS_PROFILE
283  *
284  * dn_flow_queue
285  *      numbytes from u_long to int64_t
286  *      add extra_bits (int64_t)
287  *      q_time from u_int32_t to int64_t and name idle_time
288  *
289  * dn_flow_set unchanged
290  *
291  */
292
293 /* NOTE:XXX copied from dummynet.c */
294 #define O_NEXT(p, len) ((void *)((char *)p + len))
295 static void
296 oid_fill(struct dn_id *oid, int len, int type, uintptr_t id)
297 {
298         oid->len = len;
299         oid->type = type;
300         oid->subtype = 0;
301         oid->id = id;
302 }
303 /* make room in the buffer and move the pointer forward */
304 static void *
305 o_next(struct dn_id **o, int len, int type)
306 {
307         struct dn_id *ret = *o;
308         oid_fill(ret, len, type, 0);
309         *o = O_NEXT(*o, len);
310         return ret;
311 }
312
313
314 static size_t pipesize7 = sizeof(struct dn_pipe7);
315 static size_t pipesize8 = sizeof(struct dn_pipe8);
316 static size_t pipesizemax8 = sizeof(struct dn_pipe_max8);
317
318 /* Indicate 'ipfw' version
319  * 1: from FreeBSD 7.2
320  * 0: from FreeBSD 8
321  * -1: unknown (for now is unused)
322  *
323  * It is update when a IP_DUMMYNET_DEL or IP_DUMMYNET_CONFIGURE request arrives
324  * NOTE: if a IP_DUMMYNET_GET arrives and the 'ipfw' version is unknown,
325  *       it is suppose to be the FreeBSD 8 version.
326  */
327 static int is7 = 0;
328
329 static int
330 convertflags2new(int src)
331 {
332         int dst = 0;
333
334         if (src & DNOLD_HAVE_FLOW_MASK)
335                 dst |= DN_HAVE_MASK;
336         if (src & DNOLD_QSIZE_IS_BYTES)
337                 dst |= DN_QSIZE_BYTES;
338         if (src & DNOLD_NOERROR)
339                 dst |= DN_NOERROR;
340         if (src & DNOLD_IS_RED)
341                 dst |= DN_IS_RED;
342         if (src & DNOLD_IS_GENTLE_RED)
343                 dst |= DN_IS_GENTLE_RED;
344         if (src & DNOLD_HAS_PROFILE)
345                 dst |= DN_HAS_PROFILE;
346
347         return dst;
348 }
349
350 static int
351 convertflags2old(int src)
352 {
353         int dst = 0;
354
355         if (src & DN_HAVE_MASK)
356                 dst |= DNOLD_HAVE_FLOW_MASK;
357         if (src & DN_IS_RED)
358                 dst |= DNOLD_IS_RED;
359         if (src & DN_IS_GENTLE_RED)
360                 dst |= DNOLD_IS_GENTLE_RED;
361         if (src & DN_NOERROR)
362                 dst |= DNOLD_NOERROR;
363         if (src & DN_HAS_PROFILE)
364                 dst |= DNOLD_HAS_PROFILE;
365         if (src & DN_QSIZE_BYTES)
366                 dst |= DNOLD_QSIZE_IS_BYTES;
367
368         return dst;
369 }
370
371 static int
372 dn_compat_del(void *v)
373 {
374         struct dn_pipe7 *p = (struct dn_pipe7 *) v;
375         struct dn_pipe8 *p8 = (struct dn_pipe8 *) v;
376         struct {
377                 struct dn_id oid;
378                 uintptr_t a[1]; /* add more if we want a list */
379         } cmd;
380
381         /* XXX DN_API_VERSION ??? */
382         oid_fill((void *)&cmd, sizeof(cmd), DN_CMD_DELETE, DN_API_VERSION);
383
384         if (is7) {
385                 if (p->pipe_nr == 0 && p->fs.fs_nr == 0)
386                         return EINVAL;
387                 if (p->pipe_nr != 0 && p->fs.fs_nr != 0)
388                         return EINVAL;
389         } else {
390                 if (p8->pipe_nr == 0 && p8->fs.fs_nr == 0)
391                         return EINVAL;
392                 if (p8->pipe_nr != 0 && p8->fs.fs_nr != 0)
393                         return EINVAL;
394         }
395
396         if (p->pipe_nr != 0) { /* pipe x delete */
397                 cmd.a[0] = p->pipe_nr;
398                 cmd.oid.subtype = DN_LINK;
399         } else { /* queue x delete */
400                 cmd.oid.subtype = DN_FS;
401                 cmd.a[0] = (is7) ? p->fs.fs_nr : p8->fs.fs_nr;
402         }
403
404         return do_config(&cmd, cmd.oid.len);
405 }
406
407 static int
408 dn_compat_config_queue(struct dn_fs *fs, void* v)
409 {
410         struct dn_pipe7 *p7 = (struct dn_pipe7 *)v;
411         struct dn_pipe8 *p8 = (struct dn_pipe8 *)v;
412         struct dn_flow_set *f;
413
414         if (is7)
415                 f = &p7->fs;
416         else
417                 f = &p8->fs;
418
419         fs->fs_nr = f->fs_nr;
420         fs->sched_nr = f->parent_nr;
421         fs->flow_mask = f->flow_mask;
422         fs->buckets = f->rq_size;
423         fs->qsize = f->qsize;
424         fs->plr = f->plr;
425         fs->par[0] = f->weight;
426         fs->flags = convertflags2new(f->flags_fs);
427         if (fs->flags & DN_IS_GENTLE_RED || fs->flags & DN_IS_RED) {
428                 fs->w_q = f->w_q;
429                 fs->max_th = f->max_th;
430                 fs->min_th = f->min_th;
431                 fs->max_p = f->max_p;
432         }
433
434         return 0;
435 }
436
437 static int
438 dn_compat_config_pipe(struct dn_sch *sch, struct dn_link *p, 
439                       struct dn_fs *fs, void* v)
440 {
441         struct dn_pipe7 *p7 = (struct dn_pipe7 *)v;
442         struct dn_pipe8 *p8 = (struct dn_pipe8 *)v;
443         int i = p7->pipe_nr;
444
445         sch->sched_nr = i;
446         sch->oid.subtype = 0;
447         p->link_nr = i;
448         fs->fs_nr = i + 2*DN_MAX_ID;
449         fs->sched_nr = i + DN_MAX_ID;
450
451         /* Common to 7 and 8 */
452         p->bandwidth = p7->bandwidth;
453         p->delay = p7->delay;
454         if (!is7) {
455                 /* FreeBSD 8 has burst  */
456                 p->burst = p8->burst;
457         }
458
459         /* fill the fifo flowset */
460         dn_compat_config_queue(fs, v);
461         fs->fs_nr = i + 2*DN_MAX_ID;
462         fs->sched_nr = i + DN_MAX_ID;
463
464         /* Move scheduler related parameter from fs to sch */
465         sch->buckets = fs->buckets; /*XXX*/
466         fs->buckets = 0;
467         if (fs->flags & DN_HAVE_MASK) {
468                 sch->flags |= DN_HAVE_MASK;
469                 fs->flags &= ~DN_HAVE_MASK;
470                 sch->sched_mask = fs->flow_mask;
471                 bzero(&fs->flow_mask, sizeof(struct ipfw_flow_id));
472         }
473
474         return 0;
475 }
476
477 static int
478 dn_compat_config_profile(struct dn_profile *pf, struct dn_link *p,
479                          void *v)
480 {
481         struct dn_pipe8 *p8 = (struct dn_pipe8 *)v;
482
483         p8->samples = &(((struct dn_pipe_max8 *)p8)->samples[0]);
484         
485         pf->link_nr = p->link_nr;
486         pf->loss_level = p8->loss_level;
487 //      pf->bandwidth = p->bandwidth; //XXX bandwidth redundant?
488         pf->samples_no = p8->samples_no;
489         strncpy(pf->name, p8->name,sizeof(pf->name));
490         bcopy(p8->samples, pf->samples, sizeof(pf->samples));
491
492         return 0;
493 }
494
495 /*
496  * If p->pipe_nr != 0 the command is 'pipe x config', so need to create
497  * the three main struct, else only a flowset is created
498  */
499 static int
500 dn_compat_configure(void *v)
501 {
502         struct dn_id *buf = NULL, *base;
503         struct dn_sch *sch = NULL;
504         struct dn_link *p = NULL;
505         struct dn_fs *fs = NULL;
506         struct dn_profile *pf = NULL;
507         int lmax;
508         int error;
509
510         struct dn_pipe7 *p7 = (struct dn_pipe7 *)v;
511         struct dn_pipe8 *p8 = (struct dn_pipe8 *)v;
512
513         int i; /* number of object to configure */
514
515         lmax = sizeof(struct dn_id);    /* command header */
516         lmax += sizeof(struct dn_sch) + sizeof(struct dn_link) +
517                 sizeof(struct dn_fs) + sizeof(struct dn_profile);
518
519         base = buf = malloc(lmax, M_DUMMYNET, M_WAITOK|M_ZERO);
520         o_next(&buf, sizeof(struct dn_id), DN_CMD_CONFIG);
521         base->id = DN_API_VERSION;
522
523         /* pipe_nr is the same in p7 and p8 */
524         i = p7->pipe_nr;
525         if (i != 0) { /* pipe config */
526                 sch = o_next(&buf, sizeof(*sch), DN_SCH);
527                 p = o_next(&buf, sizeof(*p), DN_LINK);
528                 fs = o_next(&buf, sizeof(*fs), DN_FS);
529
530                 error = dn_compat_config_pipe(sch, p, fs, v);
531                 if (error) {
532                         free(buf, M_DUMMYNET);
533                         return error;
534                 }
535                 if (!is7 && p8->samples_no > 0) {
536                         /* Add profiles*/
537                         pf = o_next(&buf, sizeof(*pf), DN_PROFILE);
538                         error = dn_compat_config_profile(pf, p, v);
539                         if (error) {
540                                 free(buf, M_DUMMYNET);
541                                 return error;
542                         }
543                 }
544         } else { /* queue config */
545                 fs = o_next(&buf, sizeof(*fs), DN_FS);
546                 error = dn_compat_config_queue(fs, v);
547                 if (error) {
548                         free(buf, M_DUMMYNET);
549                         return error;
550                 }
551         }
552         error = do_config(base, (char *)buf - (char *)base);
553
554         if (buf)
555                 free(buf, M_DUMMYNET);
556         return error;
557 }
558
559 int
560 dn_compat_calc_size(void)
561 {
562         int need = 0;
563         /* XXX use FreeBSD 8 struct size */
564         /* NOTE:
565          * - half scheduler:            schk_count/2
566          * - all flowset:               fsk_count
567          * - all flowset queues:        queue_count
568          * - all pipe queue:            si_count
569          */
570         need += dn_cfg.schk_count * sizeof(struct dn_pipe8) / 2;
571         need += dn_cfg.fsk_count * sizeof(struct dn_flow_set);
572         need += dn_cfg.si_count * sizeof(struct dn_flow_queue8);
573         need += dn_cfg.queue_count * sizeof(struct dn_flow_queue8);
574
575         return need;
576 }
577
578 int
579 dn_c_copy_q (void *_ni, void *arg)
580 {
581         struct copy_args *a = arg;
582         struct dn_flow_queue7 *fq7 = (struct dn_flow_queue7 *)*a->start;
583         struct dn_flow_queue8 *fq8 = (struct dn_flow_queue8 *)*a->start;
584         struct dn_flow *ni = (struct dn_flow *)_ni;
585         int size = 0;
586
587         /* XXX hash slot not set */
588         /* No difference between 7.2/8 */
589         fq7->len = ni->length;
590         fq7->len_bytes = ni->len_bytes;
591         fq7->id = ni->fid;
592
593         if (is7) {
594                 size = sizeof(struct dn_flow_queue7);
595                 fq7->tot_pkts = ni->tot_pkts;
596                 fq7->tot_bytes = ni->tot_bytes;
597                 fq7->drops = ni->drops;
598         } else {
599                 size = sizeof(struct dn_flow_queue8);
600                 fq8->tot_pkts = ni->tot_pkts;
601                 fq8->tot_bytes = ni->tot_bytes;
602                 fq8->drops = ni->drops;
603         }
604
605         *a->start += size;
606         return 0;
607 }
608
609 int
610 dn_c_copy_pipe(struct dn_schk *s, struct copy_args *a, int nq)
611 {
612         struct dn_link *l = &s->link;
613         struct dn_fsk *f = s->fs;
614
615         struct dn_pipe7 *pipe7 = (struct dn_pipe7 *)*a->start;
616         struct dn_pipe8 *pipe8 = (struct dn_pipe8 *)*a->start;
617         struct dn_flow_set *fs;
618         int size = 0;
619
620         if (is7) {
621                 fs = &pipe7->fs;
622                 size = sizeof(struct dn_pipe7);
623         } else {
624                 fs = &pipe8->fs;
625                 size = sizeof(struct dn_pipe8);
626         }
627
628         /* These 4 field are the same in pipe7 and pipe8 */
629         pipe7->next.sle_next = (struct dn_pipe7 *)DN_IS_PIPE;
630         pipe7->bandwidth = l->bandwidth;
631         pipe7->delay = l->delay * 1000 / hz;
632         pipe7->pipe_nr = l->link_nr - DN_MAX_ID;
633
634         if (!is7) {
635                 if (s->profile) {
636                         struct dn_profile *pf = s->profile;
637                         strncpy(pipe8->name, pf->name, sizeof(pf->name));
638                         pipe8->loss_level = pf->loss_level;
639                         pipe8->samples_no = pf->samples_no;
640                 }
641                 pipe8->burst = div64(l->burst , 8 * hz);
642         }
643
644         fs->flow_mask = s->sch.sched_mask;
645         fs->rq_size = s->sch.buckets ? s->sch.buckets : 1;
646
647         fs->parent_nr = l->link_nr - DN_MAX_ID;
648         fs->qsize = f->fs.qsize;
649         fs->plr = f->fs.plr;
650         fs->w_q = f->fs.w_q;
651         fs->max_th = f->max_th;
652         fs->min_th = f->min_th;
653         fs->max_p = f->fs.max_p;
654         fs->rq_elements = nq;
655
656         fs->flags_fs = convertflags2old(f->fs.flags);
657
658         *a->start += size;
659         return 0;
660 }
661
662
663 int
664 dn_compat_copy_pipe(struct copy_args *a, void *_o)
665 {
666         int have = a->end - *a->start;
667         int need = 0;
668         int pipe_size = sizeof(struct dn_pipe8);
669         int queue_size = sizeof(struct dn_flow_queue8);
670         int n_queue = 0; /* number of queues */
671
672         struct dn_schk *s = (struct dn_schk *)_o;
673         /* calculate needed space:
674          * - struct dn_pipe
675          * - if there are instances, dn_queue * n_instances
676          */
677         n_queue = (s->sch.flags & DN_HAVE_MASK ? dn_ht_entries(s->siht) :
678                                                 (s->siht ? 1 : 0));
679         need = pipe_size + queue_size * n_queue;
680         if (have < need) {
681                 D("have %d < need %d", have, need);
682                 return 1;
683         }
684         /* copy pipe */
685         dn_c_copy_pipe(s, a, n_queue);
686
687         /* copy queues */
688         if (s->sch.flags & DN_HAVE_MASK)
689                 dn_ht_scan(s->siht, dn_c_copy_q, a);
690         else if (s->siht)
691                 dn_c_copy_q(s->siht, a);
692         return 0;
693 }
694
695 int
696 dn_c_copy_fs(struct dn_fsk *f, struct copy_args *a, int nq)
697 {
698         struct dn_flow_set *fs = (struct dn_flow_set *)*a->start;
699
700         fs->next.sle_next = (struct dn_flow_set *)DN_IS_QUEUE;
701         fs->fs_nr = f->fs.fs_nr;
702         fs->qsize = f->fs.qsize;
703         fs->plr = f->fs.plr;
704         fs->w_q = f->fs.w_q;
705         fs->max_th = f->max_th;
706         fs->min_th = f->min_th;
707         fs->max_p = f->fs.max_p;
708         fs->flow_mask = f->fs.flow_mask;
709         fs->rq_elements = nq;
710         fs->rq_size = (f->fs.buckets ? f->fs.buckets : 1);
711         fs->parent_nr = f->fs.sched_nr;
712         fs->weight = f->fs.par[0];
713
714         fs->flags_fs = convertflags2old(f->fs.flags);
715         *a->start += sizeof(struct dn_flow_set);
716         return 0;
717 }
718
719 int
720 dn_compat_copy_queue(struct copy_args *a, void *_o)
721 {
722         int have = a->end - *a->start;
723         int need = 0;
724         int fs_size = sizeof(struct dn_flow_set);
725         int queue_size = sizeof(struct dn_flow_queue8);
726
727         struct dn_fsk *fs = (struct dn_fsk *)_o;
728         int n_queue = 0; /* number of queues */
729
730         n_queue = (fs->fs.flags & DN_HAVE_MASK ? dn_ht_entries(fs->qht) :
731                                                 (fs->qht ? 1 : 0));
732
733         need = fs_size + queue_size * n_queue;
734         if (have < need) {
735                 D("have < need");
736                 return 1;
737         }
738
739         /* copy flowset */
740         dn_c_copy_fs(fs, a, n_queue);
741
742         /* copy queues */
743         if (fs->fs.flags & DN_HAVE_MASK)
744                 dn_ht_scan(fs->qht, dn_c_copy_q, a);
745         else if (fs->qht)
746                 dn_c_copy_q(fs->qht, a);
747
748         return 0;
749 }
750
751 int
752 copy_data_helper_compat(void *_o, void *_arg)
753 {
754         struct copy_args *a = _arg;
755
756         if (a->type == DN_COMPAT_PIPE) {
757                 struct dn_schk *s = _o;
758                 if (s->sch.oid.subtype != 1 || s->sch.sched_nr <= DN_MAX_ID) {
759                         return 0;       /* not old type */
760                 }
761                 /* copy pipe parameters, and if instance exists, copy
762                  * other parameters and eventually queues.
763                  */
764                 if(dn_compat_copy_pipe(a, _o))
765                         return DNHT_SCAN_END;
766         } else if (a->type == DN_COMPAT_QUEUE) {
767                 struct dn_fsk *fs = _o;
768                 if (fs->fs.fs_nr >= DN_MAX_ID)
769                         return 0;
770                 if (dn_compat_copy_queue(a, _o))
771                         return DNHT_SCAN_END;
772         }
773         return 0;
774 }
775
776 /* Main function to manage old requests */
777 int
778 ip_dummynet_compat(struct sockopt *sopt)
779 {
780         int error=0;
781         void *v = NULL;
782         struct dn_id oid;
783
784         /* Lenght of data, used to found ipfw version... */
785         int len = sopt->sopt_valsize;
786
787         /* len can be 0 if command was dummynet_flush */
788         if (len == pipesize7) {
789                 D("setting compatibility with FreeBSD 7.2");
790                 is7 = 1;
791         }
792         else if (len == pipesize8 || len == pipesizemax8) {
793                 D("setting compatibility with FreeBSD 8");
794                 is7 = 0;
795         }
796
797         switch (sopt->sopt_name) {
798         default:
799                 printf("dummynet: -- unknown option %d", sopt->sopt_name);
800                 error = EINVAL;
801                 break;
802
803         case IP_DUMMYNET_FLUSH:
804                 oid_fill(&oid, sizeof(oid), DN_CMD_FLUSH, DN_API_VERSION);
805                 do_config(&oid, oid.len);
806                 break;
807
808         case IP_DUMMYNET_DEL:
809                 v = malloc(len, M_TEMP, M_WAITOK);
810                 error = sooptcopyin(sopt, v, len, len);
811                 if (error)
812                         break;
813                 error = dn_compat_del(v);
814                 free(v, M_TEMP);
815                 break;
816
817         case IP_DUMMYNET_CONFIGURE:
818                 v = malloc(len, M_TEMP, M_WAITOK);
819                 error = sooptcopyin(sopt, v, len, len);
820                 if (error)
821                         break;
822                 error = dn_compat_configure(v);
823                 free(v, M_TEMP);
824                 break;
825
826         case IP_DUMMYNET_GET: {
827                 void *buf;
828                 int ret;
829                 int original_size = sopt->sopt_valsize;
830                 int size;
831
832                 ret = dummynet_get(sopt, &buf);
833                 if (ret)
834                         return 0;//XXX ?
835                 size = sopt->sopt_valsize;
836                 sopt->sopt_valsize = original_size;
837                 D("size=%d, buf=%p", size, buf);
838                 ret = sooptcopyout(sopt, buf, size);
839                 if (ret)
840                         printf("  %s ERROR sooptcopyout\n", __FUNCTION__);
841                 if (buf)
842                         free(buf, M_DUMMYNET);
843             }
844         }
845
846         return error;
847 }
848
849