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