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