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