ip_dn_glue.c revision 206425
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 206425 2010-04-09 16:06:53Z 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 = NULL, *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 if (buf) 551 free(buf, M_DUMMYNET); 552 return error; 553} 554 555int 556dn_compat_calc_size(void) 557{ 558 int need = 0; 559 /* XXX use FreeBSD 8 struct size */ 560 /* NOTE: 561 * - half scheduler: schk_count/2 562 * - all flowset: fsk_count 563 * - all flowset queues: queue_count 564 * - all pipe queue: si_count 565 */ 566 need += dn_cfg.schk_count * sizeof(struct dn_pipe8) / 2; 567 need += dn_cfg.fsk_count * sizeof(struct dn_flow_set); 568 need += dn_cfg.si_count * sizeof(struct dn_flow_queue8); 569 need += dn_cfg.queue_count * sizeof(struct dn_flow_queue8); 570 571 return need; 572} 573 574int 575dn_c_copy_q (void *_ni, void *arg) 576{ 577 struct copy_args *a = arg; 578 struct dn_flow_queue7 *fq7 = (struct dn_flow_queue7 *)*a->start; 579 struct dn_flow_queue8 *fq8 = (struct dn_flow_queue8 *)*a->start; 580 struct dn_flow *ni = (struct dn_flow *)_ni; 581 int size = 0; 582 583 /* XXX hash slot not set */ 584 /* No difference between 7.2/8 */ 585 fq7->len = ni->length; 586 fq7->len_bytes = ni->len_bytes; 587 fq7->id = ni->fid; 588 589 if (is7) { 590 size = sizeof(struct dn_flow_queue7); 591 fq7->tot_pkts = ni->tot_pkts; 592 fq7->tot_bytes = ni->tot_bytes; 593 fq7->drops = ni->drops; 594 } else { 595 size = sizeof(struct dn_flow_queue8); 596 fq8->tot_pkts = ni->tot_pkts; 597 fq8->tot_bytes = ni->tot_bytes; 598 fq8->drops = ni->drops; 599 } 600 601 *a->start += size; 602 return 0; 603} 604 605int 606dn_c_copy_pipe(struct dn_schk *s, struct copy_args *a, int nq) 607{ 608 struct dn_link *l = &s->link; 609 struct dn_fsk *f = s->fs; 610 611 struct dn_pipe7 *pipe7 = (struct dn_pipe7 *)*a->start; 612 struct dn_pipe8 *pipe8 = (struct dn_pipe8 *)*a->start; 613 struct dn_flow_set *fs; 614 int size = 0; 615 616 if (is7) { 617 fs = &pipe7->fs; 618 size = sizeof(struct dn_pipe7); 619 } else { 620 fs = &pipe8->fs; 621 size = sizeof(struct dn_pipe8); 622 } 623 624 /* These 4 field are the same in pipe7 and pipe8 */ 625 pipe7->next.sle_next = (struct dn_pipe7 *)DN_IS_PIPE; 626 pipe7->bandwidth = l->bandwidth; 627 pipe7->delay = l->delay; 628 pipe7->pipe_nr = l->link_nr - DN_MAX_ID; 629 630 if (!is7) { 631 if (s->profile) { 632 struct dn_profile *pf = s->profile; 633 strncpy(pipe8->name, pf->name, sizeof(pf->name)); 634 pipe8->loss_level = pf->loss_level; 635 pipe8->samples_no = pf->samples_no; 636 } 637 pipe8->burst = div64(l->burst , 8 * hz); 638 } 639 640 fs->flow_mask = s->sch.sched_mask; 641 fs->rq_size = s->sch.buckets ? s->sch.buckets : 1; 642 643 fs->parent_nr = l->link_nr - DN_MAX_ID; 644 fs->qsize = f->fs.qsize; 645 fs->plr = f->fs.plr; 646 fs->w_q = f->fs.w_q; 647 fs->max_th = f->max_th; 648 fs->min_th = f->min_th; 649 fs->max_p = f->fs.max_p; 650 fs->rq_elements = nq; 651 652 fs->flags_fs = convertflags2old(f->fs.flags); 653 654 *a->start += size; 655 return 0; 656} 657 658 659int 660dn_compat_copy_pipe(struct copy_args *a, void *_o) 661{ 662 int have = a->end - *a->start; 663 int need = 0; 664 int pipe_size = sizeof(struct dn_pipe8); 665 int queue_size = sizeof(struct dn_flow_queue8); 666 int n_queue = 0; /* number of queues */ 667 668 struct dn_schk *s = (struct dn_schk *)_o; 669 /* calculate needed space: 670 * - struct dn_pipe 671 * - if there are instances, dn_queue * n_instances 672 */ 673 n_queue = (s->sch.flags & DN_HAVE_MASK ? dn_ht_entries(s->siht) : 674 (s->siht ? 1 : 0)); 675 need = pipe_size + queue_size * n_queue; 676 if (have < need) { 677 D("have %d < need %d", have, need); 678 return 1; 679 } 680 /* copy pipe */ 681 dn_c_copy_pipe(s, a, n_queue); 682 683 /* copy queues */ 684 if (s->sch.flags & DN_HAVE_MASK) 685 dn_ht_scan(s->siht, dn_c_copy_q, a); 686 else if (s->siht) 687 dn_c_copy_q(s->siht, a); 688 return 0; 689} 690 691int 692dn_c_copy_fs(struct dn_fsk *f, struct copy_args *a, int nq) 693{ 694 struct dn_flow_set *fs = (struct dn_flow_set *)*a->start; 695 696 fs->next.sle_next = (struct dn_flow_set *)DN_IS_QUEUE; 697 fs->fs_nr = f->fs.fs_nr; 698 fs->qsize = f->fs.qsize; 699 fs->plr = f->fs.plr; 700 fs->w_q = f->fs.w_q; 701 fs->max_th = f->max_th; 702 fs->min_th = f->min_th; 703 fs->max_p = f->fs.max_p; 704 fs->flow_mask = f->fs.flow_mask; 705 fs->rq_elements = nq; 706 fs->rq_size = (f->fs.buckets ? f->fs.buckets : 1); 707 fs->parent_nr = f->fs.sched_nr; 708 fs->weight = f->fs.par[0]; 709 710 fs->flags_fs = convertflags2old(f->fs.flags); 711 *a->start += sizeof(struct dn_flow_set); 712 return 0; 713} 714 715int 716dn_compat_copy_queue(struct copy_args *a, void *_o) 717{ 718 int have = a->end - *a->start; 719 int need = 0; 720 int fs_size = sizeof(struct dn_flow_set); 721 int queue_size = sizeof(struct dn_flow_queue8); 722 723 struct dn_fsk *fs = (struct dn_fsk *)_o; 724 int n_queue = 0; /* number of queues */ 725 726 n_queue = (fs->fs.flags & DN_HAVE_MASK ? dn_ht_entries(fs->qht) : 727 (fs->qht ? 1 : 0)); 728 729 need = fs_size + queue_size * n_queue; 730 if (have < need) { 731 D("have < need"); 732 return 1; 733 } 734 735 /* copy flowset */ 736 dn_c_copy_fs(fs, a, n_queue); 737 738 /* copy queues */ 739 if (fs->fs.flags & DN_HAVE_MASK) 740 dn_ht_scan(fs->qht, dn_c_copy_q, a); 741 else if (fs->qht) 742 dn_c_copy_q(fs->qht, a); 743 744 return 0; 745} 746 747int 748copy_data_helper_compat(void *_o, void *_arg) 749{ 750 struct copy_args *a = _arg; 751 752 if (a->type == DN_COMPAT_PIPE) { 753 struct dn_schk *s = _o; 754 if (s->sch.oid.subtype != 1 || s->sch.sched_nr <= DN_MAX_ID) { 755 return 0; /* not old type */ 756 } 757 /* copy pipe parameters, and if instance exists, copy 758 * other parameters and eventually queues. 759 */ 760 if(dn_compat_copy_pipe(a, _o)) 761 return DNHT_SCAN_END; 762 } else if (a->type == DN_COMPAT_QUEUE) { 763 struct dn_fsk *fs = _o; 764 if (fs->fs.fs_nr >= DN_MAX_ID) 765 return 0; 766 if (dn_compat_copy_queue(a, _o)) 767 return DNHT_SCAN_END; 768 } 769 return 0; 770} 771 772/* Main function to manage old requests */ 773int 774ip_dummynet_compat(struct sockopt *sopt) 775{ 776 int error=0; 777 void *v = NULL; 778 struct dn_id oid; 779 780 /* Lenght of data, used to found ipfw version... */ 781 int len = sopt->sopt_valsize; 782 783 /* len can be 0 if command was dummynet_flush */ 784 if (len == pipesize7) { 785 D("setting compatibility with FreeBSD 7.2"); 786 is7 = 1; 787 } 788 else if (len == pipesize8 || len == pipesizemax8) { 789 D("setting compatibility with FreeBSD 8"); 790 is7 = 0; 791 } 792 793 switch (sopt->sopt_name) { 794 default: 795 printf("dummynet: -- unknown option %d", sopt->sopt_name); 796 error = EINVAL; 797 break; 798 799 case IP_DUMMYNET_FLUSH: 800 oid_fill(&oid, sizeof(oid), DN_CMD_FLUSH, DN_API_VERSION); 801 do_config(&oid, oid.len); 802 break; 803 804 case IP_DUMMYNET_DEL: 805 v = malloc(len, M_TEMP, M_WAITOK); 806 error = sooptcopyin(sopt, v, len, len); 807 if (error) 808 break; 809 error = dn_compat_del(v); 810 free(v, M_DUMMYNET); 811 break; 812 813 case IP_DUMMYNET_CONFIGURE: 814 v = malloc(len, M_TEMP, M_WAITOK); 815 error = sooptcopyin(sopt, v, len, len); 816 if (error) 817 break; 818 error = dn_compat_configure(v); 819 free(v, M_DUMMYNET); 820 break; 821 822 case IP_DUMMYNET_GET: { 823 void *buf; 824 int ret; 825 int original_size = sopt->sopt_valsize; 826 int size; 827 828 ret = dummynet_get(sopt, &buf); 829 if (ret) 830 return 0;//XXX ? 831 size = sopt->sopt_valsize; 832 sopt->sopt_valsize = original_size; 833 D("size=%d, buf=%p", size, buf); 834 ret = sooptcopyout(sopt, buf, size); 835 if (ret) 836 printf(" %s ERROR sooptcopyout\n", __FUNCTION__); 837 if (buf) 838 free(buf, M_DUMMYNET); 839 } 840 } 841 842 return error; 843} 844 845 846