ip_dn_glue.c revision 240494
1285242Sachim/*- 2285242Sachim * Copyright (c) 2010 Riccardo Panicucci, Universita` di Pisa 3285242Sachim * All rights reserved 4285242Sachim * 5285242Sachim * Redistribution and use in source and binary forms, with or without 6285242Sachim * modification, are permitted provided that the following conditions 7285242Sachim * are met: 8285242Sachim * 1. Redistributions of source code must retain the above copyright 9285242Sachim * notice, this list of conditions and the following disclaimer. 10285242Sachim * 2. Redistributions in binary form must reproduce the above copyright 11285242Sachim * notice, this list of conditions and the following disclaimer in the 12285242Sachim * documentation and/or other materials provided with the distribution. 13285242Sachim * 14285242Sachim * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15285242Sachim * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16285242Sachim * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17285242Sachim * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18285242Sachim * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19285242Sachim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20285242Sachim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21285242Sachim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22285242Sachim * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23285242Sachim * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24285242Sachim * SUCH DAMAGE. 25285242Sachim */ 26285242Sachim 27285242Sachim/* 28285242Sachim * $FreeBSD: head/sys/netpfil/ipfw/ip_dn_glue.c 240494 2012-09-14 11:51:49Z glebius $ 29285242Sachim * 30285242Sachim * Binary compatibility support for /sbin/ipfw RELENG_7 and RELENG_8 31285242Sachim */ 32285242Sachim 33285242Sachim#include "opt_inet6.h" 34285242Sachim 35285242Sachim#include <sys/param.h> 36285242Sachim#include <sys/systm.h> 37285242Sachim#include <sys/malloc.h> 38285242Sachim#include <sys/mbuf.h> 39285242Sachim#include <sys/kernel.h> 40285242Sachim#include <sys/lock.h> 41285242Sachim#include <sys/module.h> 42285242Sachim#include <sys/priv.h> 43285242Sachim#include <sys/proc.h> 44285242Sachim#include <sys/rwlock.h> 45285242Sachim#include <sys/socket.h> 46285242Sachim#include <sys/socketvar.h> 47285242Sachim#include <sys/time.h> 48285242Sachim#include <sys/taskqueue.h> 49285242Sachim#include <net/if.h> /* IFNAMSIZ, struct ifaddr, ifq head, lock.h mutex.h */ 50285242Sachim#include <netinet/in.h> 51285242Sachim#include <netinet/ip_var.h> /* ip_output(), IP_FORWARDING */ 52285242Sachim#include <netinet/ip_fw.h> 53285242Sachim#include <netinet/ip_dummynet.h> 54285242Sachim 55285242Sachim#include <netpfil/ipfw/ip_fw_private.h> 56285242Sachim#include <netpfil/ipfw/dn_heap.h> 57285242Sachim#include <netpfil/ipfw/ip_dn_private.h> 58285242Sachim#include <netpfil/ipfw/dn_sched.h> 59285242Sachim 60285242Sachim/* FREEBSD7.2 ip_dummynet.h r191715*/ 61285242Sachim 62285242Sachimstruct dn_heap_entry7 { 63285242Sachim int64_t key; /* sorting key. Topmost element is smallest one */ 64285242Sachim void *object; /* object pointer */ 65285242Sachim}; 66285242Sachim 67285242Sachimstruct dn_heap7 { 68285242Sachim int size; 69285242Sachim int elements; 70285242Sachim int offset; /* XXX if > 0 this is the offset of direct ptr to obj */ 71285242Sachim struct dn_heap_entry7 *p; /* really an array of "size" entries */ 72285242Sachim}; 73285242Sachim 74285242Sachim/* Common to 7.2 and 8 */ 75285242Sachimstruct dn_flow_set { 76285242Sachim SLIST_ENTRY(dn_flow_set) next; /* linked list in a hash slot */ 77285242Sachim 78285242Sachim u_short fs_nr ; /* flow_set number */ 79285242Sachim u_short flags_fs; 80285242Sachim#define DNOLD_HAVE_FLOW_MASK 0x0001 81285242Sachim#define DNOLD_IS_RED 0x0002 82285242Sachim#define DNOLD_IS_GENTLE_RED 0x0004 83285242Sachim#define DNOLD_QSIZE_IS_BYTES 0x0008 /* queue size is measured in bytes */ 84285242Sachim#define DNOLD_NOERROR 0x0010 /* do not report ENOBUFS on drops */ 85285242Sachim#define DNOLD_HAS_PROFILE 0x0020 /* the pipe has a delay profile. */ 86285242Sachim#define DNOLD_IS_PIPE 0x4000 87285242Sachim#define DNOLD_IS_QUEUE 0x8000 88285242Sachim 89285242Sachim struct dn_pipe7 *pipe ; /* pointer to parent pipe */ 90285242Sachim u_short parent_nr ; /* parent pipe#, 0 if local to a pipe */ 91285242Sachim 92285242Sachim int weight ; /* WFQ queue weight */ 93285242Sachim int qsize ; /* queue size in slots or bytes */ 94285242Sachim int plr ; /* pkt loss rate (2^31-1 means 100%) */ 95285242Sachim 96285242Sachim struct ipfw_flow_id flow_mask ; 97285242Sachim 98285242Sachim /* hash table of queues onto this flow_set */ 99285242Sachim int rq_size ; /* number of slots */ 100285242Sachim int rq_elements ; /* active elements */ 101285242Sachim struct dn_flow_queue7 **rq; /* array of rq_size entries */ 102285242Sachim 103285242Sachim u_int32_t last_expired ; /* do not expire too frequently */ 104285242Sachim int backlogged ; /* #active queues for this flowset */ 105285242Sachim 106285242Sachim /* RED parameters */ 107285242Sachim#define SCALE_RED 16 108285242Sachim#define SCALE(x) ( (x) << SCALE_RED ) 109285242Sachim#define SCALE_VAL(x) ( (x) >> SCALE_RED ) 110285242Sachim#define SCALE_MUL(x,y) ( ( (x) * (y) ) >> SCALE_RED ) 111285242Sachim int w_q ; /* queue weight (scaled) */ 112285242Sachim int max_th ; /* maximum threshold for queue (scaled) */ 113285242Sachim int min_th ; /* minimum threshold for queue (scaled) */ 114285242Sachim int max_p ; /* maximum value for p_b (scaled) */ 115285242Sachim u_int c_1 ; /* max_p/(max_th-min_th) (scaled) */ 116285242Sachim u_int c_2 ; /* max_p*min_th/(max_th-min_th) (scaled) */ 117285242Sachim u_int c_3 ; /* for GRED, (1-max_p)/max_th (scaled) */ 118285242Sachim u_int c_4 ; /* for GRED, 1 - 2*max_p (scaled) */ 119285242Sachim u_int * w_q_lookup ; /* lookup table for computing (1-w_q)^t */ 120285242Sachim u_int lookup_depth ; /* depth of lookup table */ 121285242Sachim int lookup_step ; /* granularity inside the lookup table */ 122285242Sachim int lookup_weight ; /* equal to (1-w_q)^t / (1-w_q)^(t+1) */ 123285242Sachim int avg_pkt_size ; /* medium packet size */ 124285242Sachim int max_pkt_size ; /* max packet size */ 125285242Sachim}; 126285242SachimSLIST_HEAD(dn_flow_set_head, dn_flow_set); 127285242Sachim 128285242Sachim#define DN_IS_PIPE 0x4000 129285242Sachim#define DN_IS_QUEUE 0x8000 130285242Sachimstruct dn_flow_queue7 { 131285242Sachim struct dn_flow_queue7 *next ; 132285242Sachim struct ipfw_flow_id id ; 133285242Sachim 134285242Sachim struct mbuf *head, *tail ; /* queue of packets */ 135285242Sachim u_int len ; 136285242Sachim u_int len_bytes ; 137285242Sachim 138285242Sachim u_long numbytes; 139285242Sachim 140285242Sachim u_int64_t tot_pkts ; /* statistics counters */ 141285242Sachim u_int64_t tot_bytes ; 142285242Sachim u_int32_t drops ; 143285242Sachim 144285242Sachim int hash_slot ; /* debugging/diagnostic */ 145285242Sachim 146285242Sachim /* RED parameters */ 147285242Sachim int avg ; /* average queue length est. (scaled) */ 148285242Sachim int count ; /* arrivals since last RED drop */ 149285242Sachim int random ; /* random value (scaled) */ 150285242Sachim u_int32_t q_time; /* start of queue idle time */ 151285242Sachim 152285242Sachim /* WF2Q+ support */ 153285242Sachim struct dn_flow_set *fs ; /* parent flow set */ 154285242Sachim int heap_pos ; /* position (index) of struct in heap */ 155285242Sachim int64_t sched_time ; /* current time when queue enters ready_heap */ 156285242Sachim 157285242Sachim int64_t S,F ; /* start time, finish time */ 158285242Sachim}; 159285242Sachim 160285242Sachimstruct dn_pipe7 { /* a pipe */ 161285242Sachim SLIST_ENTRY(dn_pipe7) next; /* linked list in a hash slot */ 162285242Sachim 163285242Sachim int pipe_nr ; /* number */ 164285242Sachim int bandwidth; /* really, bytes/tick. */ 165285242Sachim int delay ; /* really, ticks */ 166285242Sachim 167285242Sachim struct mbuf *head, *tail ; /* packets in delay line */ 168285242Sachim 169285242Sachim /* WF2Q+ */ 170285242Sachim struct dn_heap7 scheduler_heap ; /* top extract - key Finish time*/ 171285242Sachim struct dn_heap7 not_eligible_heap; /* top extract- key Start time */ 172285242Sachim struct dn_heap7 idle_heap ; /* random extract - key Start=Finish time */ 173285242Sachim 174285242Sachim int64_t V ; /* virtual time */ 175285242Sachim int sum; /* sum of weights of all active sessions */ 176285242Sachim 177285242Sachim int numbytes; 178285242Sachim 179285242Sachim int64_t sched_time ; /* time pipe was scheduled in ready_heap */ 180285242Sachim 181285242Sachim /* 182285242Sachim * When the tx clock come from an interface (if_name[0] != '\0'), its name 183285242Sachim * is stored below, whereas the ifp is filled when the rule is configured. 184285242Sachim */ 185285242Sachim char if_name[IFNAMSIZ]; 186285242Sachim struct ifnet *ifp ; 187285242Sachim int ready ; /* set if ifp != NULL and we got a signal from it */ 188285242Sachim 189285242Sachim struct dn_flow_set fs ; /* used with fixed-rate flows */ 190285242Sachim}; 191285242SachimSLIST_HEAD(dn_pipe_head7, dn_pipe7); 192285242Sachim 193285242Sachim 194285242Sachim/* FREEBSD8 ip_dummynet.h r196045 */ 195285242Sachimstruct dn_flow_queue8 { 196285242Sachim struct dn_flow_queue8 *next ; 197285242Sachim struct ipfw_flow_id id ; 198285242Sachim 199285242Sachim struct mbuf *head, *tail ; /* queue of packets */ 200285242Sachim u_int len ; 201285242Sachim u_int len_bytes ; 202285242Sachim 203285242Sachim uint64_t numbytes ; /* credit for transmission (dynamic queues) */ 204285242Sachim int64_t extra_bits; /* extra bits simulating unavailable channel */ 205285242Sachim 206285242Sachim u_int64_t tot_pkts ; /* statistics counters */ 207285242Sachim u_int64_t tot_bytes ; 208285242Sachim u_int32_t drops ; 209285242Sachim 210285242Sachim int hash_slot ; /* debugging/diagnostic */ 211285242Sachim 212285242Sachim /* RED parameters */ 213285242Sachim int avg ; /* average queue length est. (scaled) */ 214285242Sachim int count ; /* arrivals since last RED drop */ 215285242Sachim int random ; /* random value (scaled) */ 216285242Sachim int64_t idle_time; /* start of queue idle time */ 217285242Sachim 218285242Sachim /* WF2Q+ support */ 219285242Sachim struct dn_flow_set *fs ; /* parent flow set */ 220285242Sachim int heap_pos ; /* position (index) of struct in heap */ 221285242Sachim int64_t sched_time ; /* current time when queue enters ready_heap */ 222285242Sachim 223285242Sachim int64_t S,F ; /* start time, finish time */ 224285242Sachim}; 225285242Sachim 226285242Sachimstruct dn_pipe8 { /* a pipe */ 227285242Sachim SLIST_ENTRY(dn_pipe8) next; /* linked list in a hash slot */ 228285242Sachim 229285242Sachim int pipe_nr ; /* number */ 230285242Sachim int bandwidth; /* really, bytes/tick. */ 231285242Sachim int delay ; /* really, ticks */ 232285242Sachim 233285242Sachim struct mbuf *head, *tail ; /* packets in delay line */ 234285242Sachim 235285242Sachim /* WF2Q+ */ 236285242Sachim struct dn_heap7 scheduler_heap ; /* top extract - key Finish time*/ 237285242Sachim struct dn_heap7 not_eligible_heap; /* top extract- key Start time */ 238285242Sachim struct dn_heap7 idle_heap ; /* random extract - key Start=Finish time */ 239285242Sachim 240285242Sachim int64_t V ; /* virtual time */ 241285242Sachim int sum; /* sum of weights of all active sessions */ 242285242Sachim 243285242Sachim /* Same as in dn_flow_queue, numbytes can become large */ 244285242Sachim int64_t numbytes; /* bits I can transmit (more or less). */ 245285242Sachim uint64_t burst; /* burst size, scaled: bits * hz */ 246285242Sachim 247285242Sachim int64_t sched_time ; /* time pipe was scheduled in ready_heap */ 248285242Sachim int64_t idle_time; /* start of pipe idle time */ 249285242Sachim 250285242Sachim char if_name[IFNAMSIZ]; 251285242Sachim struct ifnet *ifp ; 252285242Sachim int ready ; /* set if ifp != NULL and we got a signal from it */ 253285242Sachim 254285242Sachim struct dn_flow_set fs ; /* used with fixed-rate flows */ 255285242Sachim 256285242Sachim /* fields to simulate a delay profile */ 257285242Sachim#define ED_MAX_NAME_LEN 32 258285242Sachim char name[ED_MAX_NAME_LEN]; 259285242Sachim int loss_level; 260285242Sachim int samples_no; 261285242Sachim int *samples; 262285242Sachim}; 263285242Sachim 264285242Sachim#define ED_MAX_SAMPLES_NO 1024 265285242Sachimstruct dn_pipe_max8 { 266285242Sachim struct dn_pipe8 pipe; 267285242Sachim int samples[ED_MAX_SAMPLES_NO]; 268285242Sachim}; 269285242SachimSLIST_HEAD(dn_pipe_head8, dn_pipe8); 270285242Sachim 271285242Sachim/* 272285242Sachim * Changes from 7.2 to 8: 273285242Sachim * dn_pipe: 274285242Sachim * numbytes from int to int64_t 275285242Sachim * add burst (int64_t) 276285242Sachim * add idle_time (int64_t) 277285242Sachim * add profile 278285242Sachim * add struct dn_pipe_max 279285242Sachim * add flag DN_HAS_PROFILE 280285242Sachim * 281285242Sachim * dn_flow_queue 282285242Sachim * numbytes from u_long to int64_t 283285242Sachim * add extra_bits (int64_t) 284285242Sachim * q_time from u_int32_t to int64_t and name idle_time 285285242Sachim * 286285242Sachim * dn_flow_set unchanged 287285242Sachim * 288285242Sachim */ 289285242Sachim 290285242Sachim/* NOTE:XXX copied from dummynet.c */ 291285242Sachim#define O_NEXT(p, len) ((void *)((char *)p + len)) 292285242Sachimstatic void 293285242Sachimoid_fill(struct dn_id *oid, int len, int type, uintptr_t id) 294285242Sachim{ 295285242Sachim oid->len = len; 296285242Sachim oid->type = type; 297285242Sachim oid->subtype = 0; 298285242Sachim oid->id = id; 299285242Sachim} 300285242Sachim/* make room in the buffer and move the pointer forward */ 301285242Sachimstatic void * 302285242Sachimo_next(struct dn_id **o, int len, int type) 303285242Sachim{ 304285242Sachim struct dn_id *ret = *o; 305285242Sachim oid_fill(ret, len, type, 0); 306285242Sachim *o = O_NEXT(*o, len); 307285242Sachim return ret; 308285242Sachim} 309285242Sachim 310285242Sachim 311285242Sachimstatic size_t pipesize7 = sizeof(struct dn_pipe7); 312285242Sachimstatic size_t pipesize8 = sizeof(struct dn_pipe8); 313285242Sachimstatic size_t pipesizemax8 = sizeof(struct dn_pipe_max8); 314285242Sachim 315285242Sachim/* Indicate 'ipfw' version 316285242Sachim * 1: from FreeBSD 7.2 317285242Sachim * 0: from FreeBSD 8 318285242Sachim * -1: unknow (for now is unused) 319285242Sachim * 320285242Sachim * It is update when a IP_DUMMYNET_DEL or IP_DUMMYNET_CONFIGURE request arrives 321285242Sachim * NOTE: if a IP_DUMMYNET_GET arrives and the 'ipfw' version is unknow, 322285242Sachim * it is suppose to be the FreeBSD 8 version. 323285242Sachim */ 324285242Sachimstatic int is7 = 0; 325285242Sachim 326285242Sachimstatic int 327285242Sachimconvertflags2new(int src) 328285242Sachim{ 329285242Sachim int dst = 0; 330285242Sachim 331285242Sachim if (src & DNOLD_HAVE_FLOW_MASK) 332285242Sachim dst |= DN_HAVE_MASK; 333285242Sachim if (src & DNOLD_QSIZE_IS_BYTES) 334285242Sachim dst |= DN_QSIZE_BYTES; 335285242Sachim if (src & DNOLD_NOERROR) 336285242Sachim dst |= DN_NOERROR; 337285242Sachim if (src & DNOLD_IS_RED) 338285242Sachim dst |= DN_IS_RED; 339285242Sachim if (src & DNOLD_IS_GENTLE_RED) 340285242Sachim dst |= DN_IS_GENTLE_RED; 341285242Sachim if (src & DNOLD_HAS_PROFILE) 342285242Sachim dst |= DN_HAS_PROFILE; 343285242Sachim 344285242Sachim return dst; 345285242Sachim} 346285242Sachim 347285242Sachimstatic int 348285242Sachimconvertflags2old(int src) 349285242Sachim{ 350285242Sachim int dst = 0; 351285242Sachim 352285242Sachim if (src & DN_HAVE_MASK) 353285242Sachim dst |= DNOLD_HAVE_FLOW_MASK; 354285242Sachim if (src & DN_IS_RED) 355285242Sachim dst |= DNOLD_IS_RED; 356285242Sachim if (src & DN_IS_GENTLE_RED) 357285242Sachim dst |= DNOLD_IS_GENTLE_RED; 358285242Sachim if (src & DN_NOERROR) 359285242Sachim dst |= DNOLD_NOERROR; 360285242Sachim if (src & DN_HAS_PROFILE) 361285242Sachim dst |= DNOLD_HAS_PROFILE; 362285242Sachim if (src & DN_QSIZE_BYTES) 363285242Sachim dst |= DNOLD_QSIZE_IS_BYTES; 364285242Sachim 365285242Sachim return dst; 366285242Sachim} 367285242Sachim 368285242Sachimstatic int 369285242Sachimdn_compat_del(void *v) 370285242Sachim{ 371285242Sachim struct dn_pipe7 *p = (struct dn_pipe7 *) v; 372285242Sachim struct dn_pipe8 *p8 = (struct dn_pipe8 *) v; 373285242Sachim struct { 374285242Sachim struct dn_id oid; 375285242Sachim uintptr_t a[1]; /* add more if we want a list */ 376285242Sachim } cmd; 377285242Sachim 378285242Sachim /* XXX DN_API_VERSION ??? */ 379285242Sachim oid_fill((void *)&cmd, sizeof(cmd), DN_CMD_DELETE, DN_API_VERSION); 380285242Sachim 381285242Sachim if (is7) { 382285242Sachim if (p->pipe_nr == 0 && p->fs.fs_nr == 0) 383285242Sachim return EINVAL; 384285242Sachim if (p->pipe_nr != 0 && p->fs.fs_nr != 0) 385285242Sachim return EINVAL; 386285242Sachim } else { 387285242Sachim if (p8->pipe_nr == 0 && p8->fs.fs_nr == 0) 388285242Sachim return EINVAL; 389285242Sachim if (p8->pipe_nr != 0 && p8->fs.fs_nr != 0) 390285242Sachim return EINVAL; 391285242Sachim } 392285242Sachim 393285242Sachim if (p->pipe_nr != 0) { /* pipe x delete */ 394285242Sachim cmd.a[0] = p->pipe_nr; 395285242Sachim cmd.oid.subtype = DN_LINK; 396285242Sachim } else { /* queue x delete */ 397285242Sachim cmd.oid.subtype = DN_FS; 398285242Sachim cmd.a[0] = (is7) ? p->fs.fs_nr : p8->fs.fs_nr; 399285242Sachim } 400285242Sachim 401285242Sachim return do_config(&cmd, cmd.oid.len); 402285242Sachim} 403285242Sachim 404285242Sachimstatic int 405285242Sachimdn_compat_config_queue(struct dn_fs *fs, void* v) 406285242Sachim{ 407285242Sachim struct dn_pipe7 *p7 = (struct dn_pipe7 *)v; 408285242Sachim struct dn_pipe8 *p8 = (struct dn_pipe8 *)v; 409285242Sachim struct dn_flow_set *f; 410285242Sachim 411285242Sachim if (is7) 412285242Sachim f = &p7->fs; 413285242Sachim else 414285242Sachim f = &p8->fs; 415285242Sachim 416285242Sachim fs->fs_nr = f->fs_nr; 417285242Sachim fs->sched_nr = f->parent_nr; 418285242Sachim fs->flow_mask = f->flow_mask; 419285242Sachim fs->buckets = f->rq_size; 420285242Sachim fs->qsize = f->qsize; 421285242Sachim fs->plr = f->plr; 422285242Sachim fs->par[0] = f->weight; 423285242Sachim fs->flags = convertflags2new(f->flags_fs); 424285242Sachim if (fs->flags & DN_IS_GENTLE_RED || fs->flags & DN_IS_RED) { 425285242Sachim fs->w_q = f->w_q; 426285242Sachim fs->max_th = f->max_th; 427285242Sachim fs->min_th = f->min_th; 428285242Sachim fs->max_p = f->max_p; 429285242Sachim } 430285242Sachim 431285242Sachim return 0; 432285242Sachim} 433285242Sachim 434285242Sachimstatic int 435285242Sachimdn_compat_config_pipe(struct dn_sch *sch, struct dn_link *p, 436285242Sachim struct dn_fs *fs, void* v) 437285242Sachim{ 438285242Sachim struct dn_pipe7 *p7 = (struct dn_pipe7 *)v; 439285242Sachim struct dn_pipe8 *p8 = (struct dn_pipe8 *)v; 440285242Sachim int i = p7->pipe_nr; 441285242Sachim 442285242Sachim sch->sched_nr = i; 443285242Sachim sch->oid.subtype = 0; 444285242Sachim p->link_nr = i; 445285242Sachim fs->fs_nr = i + 2*DN_MAX_ID; 446285242Sachim fs->sched_nr = i + DN_MAX_ID; 447285242Sachim 448285242Sachim /* Common to 7 and 8 */ 449285242Sachim p->bandwidth = p7->bandwidth; 450285242Sachim p->delay = p7->delay; 451285242Sachim if (!is7) { 452285242Sachim /* FreeBSD 8 has burst */ 453285242Sachim p->burst = p8->burst; 454285242Sachim } 455285242Sachim 456285242Sachim /* fill the fifo flowset */ 457285242Sachim dn_compat_config_queue(fs, v); 458285242Sachim fs->fs_nr = i + 2*DN_MAX_ID; 459285242Sachim fs->sched_nr = i + DN_MAX_ID; 460285242Sachim 461285242Sachim /* Move scheduler related parameter from fs to sch */ 462285242Sachim sch->buckets = fs->buckets; /*XXX*/ 463285242Sachim fs->buckets = 0; 464285242Sachim if (fs->flags & DN_HAVE_MASK) { 465285242Sachim sch->flags |= DN_HAVE_MASK; 466285242Sachim fs->flags &= ~DN_HAVE_MASK; 467285242Sachim sch->sched_mask = fs->flow_mask; 468285242Sachim bzero(&fs->flow_mask, sizeof(struct ipfw_flow_id)); 469285242Sachim } 470285242Sachim 471285242Sachim return 0; 472285242Sachim} 473285242Sachim 474285242Sachimstatic int 475285242Sachimdn_compat_config_profile(struct dn_profile *pf, struct dn_link *p, 476285242Sachim void *v) 477285242Sachim{ 478285242Sachim struct dn_pipe8 *p8 = (struct dn_pipe8 *)v; 479285242Sachim 480285242Sachim p8->samples = &(((struct dn_pipe_max8 *)p8)->samples[0]); 481285242Sachim 482285242Sachim pf->link_nr = p->link_nr; 483285242Sachim pf->loss_level = p8->loss_level; 484285242Sachim// pf->bandwidth = p->bandwidth; //XXX bandwidth redundant? 485285242Sachim pf->samples_no = p8->samples_no; 486285242Sachim strncpy(pf->name, p8->name,sizeof(pf->name)); 487285242Sachim bcopy(p8->samples, pf->samples, sizeof(pf->samples)); 488285242Sachim 489285242Sachim return 0; 490285242Sachim} 491285242Sachim 492285242Sachim/* 493285242Sachim * If p->pipe_nr != 0 the command is 'pipe x config', so need to create 494285242Sachim * the three main struct, else only a flowset is created 495285242Sachim */ 496285242Sachimstatic int 497285242Sachimdn_compat_configure(void *v) 498285242Sachim{ 499285242Sachim struct dn_id *buf = NULL, *base; 500285242Sachim struct dn_sch *sch = NULL; 501285242Sachim struct dn_link *p = NULL; 502285242Sachim struct dn_fs *fs = NULL; 503285242Sachim struct dn_profile *pf = NULL; 504285242Sachim int lmax; 505285242Sachim int error; 506285242Sachim 507285242Sachim struct dn_pipe7 *p7 = (struct dn_pipe7 *)v; 508285242Sachim struct dn_pipe8 *p8 = (struct dn_pipe8 *)v; 509285242Sachim 510285242Sachim int i; /* number of object to configure */ 511285242Sachim 512285242Sachim lmax = sizeof(struct dn_id); /* command header */ 513285242Sachim lmax += sizeof(struct dn_sch) + sizeof(struct dn_link) + 514285242Sachim sizeof(struct dn_fs) + sizeof(struct dn_profile); 515285242Sachim 516285242Sachim base = buf = malloc(lmax, M_DUMMYNET, M_WAIT|M_ZERO); 517285242Sachim o_next(&buf, sizeof(struct dn_id), DN_CMD_CONFIG); 518285242Sachim base->id = DN_API_VERSION; 519285242Sachim 520285242Sachim /* pipe_nr is the same in p7 and p8 */ 521285242Sachim i = p7->pipe_nr; 522285242Sachim if (i != 0) { /* pipe config */ 523285242Sachim sch = o_next(&buf, sizeof(*sch), DN_SCH); 524285242Sachim p = o_next(&buf, sizeof(*p), DN_LINK); 525285242Sachim fs = o_next(&buf, sizeof(*fs), DN_FS); 526285242Sachim 527285242Sachim error = dn_compat_config_pipe(sch, p, fs, v); 528285242Sachim if (error) { 529285242Sachim free(buf, M_DUMMYNET); 530285242Sachim return error; 531285242Sachim } 532285242Sachim if (!is7 && p8->samples_no > 0) { 533285242Sachim /* Add profiles*/ 534285242Sachim pf = o_next(&buf, sizeof(*pf), DN_PROFILE); 535285242Sachim error = dn_compat_config_profile(pf, p, v); 536285242Sachim if (error) { 537285242Sachim free(buf, M_DUMMYNET); 538285242Sachim return error; 539285242Sachim } 540285242Sachim } 541285242Sachim } else { /* queue config */ 542285242Sachim fs = o_next(&buf, sizeof(*fs), DN_FS); 543285242Sachim error = dn_compat_config_queue(fs, v); 544285242Sachim if (error) { 545285242Sachim free(buf, M_DUMMYNET); 546285242Sachim return error; 547285242Sachim } 548285242Sachim } 549285242Sachim error = do_config(base, (char *)buf - (char *)base); 550285242Sachim 551285242Sachim if (buf) 552285242Sachim free(buf, M_DUMMYNET); 553285242Sachim return error; 554285242Sachim} 555285242Sachim 556285242Sachimint 557285242Sachimdn_compat_calc_size(void) 558285242Sachim{ 559285242Sachim int need = 0; 560285242Sachim /* XXX use FreeBSD 8 struct size */ 561285242Sachim /* NOTE: 562285242Sachim * - half scheduler: schk_count/2 563285242Sachim * - all flowset: fsk_count 564285242Sachim * - all flowset queues: queue_count 565285242Sachim * - all pipe queue: si_count 566285242Sachim */ 567285242Sachim need += dn_cfg.schk_count * sizeof(struct dn_pipe8) / 2; 568285242Sachim need += dn_cfg.fsk_count * sizeof(struct dn_flow_set); 569285242Sachim need += dn_cfg.si_count * sizeof(struct dn_flow_queue8); 570285242Sachim need += dn_cfg.queue_count * sizeof(struct dn_flow_queue8); 571285242Sachim 572285242Sachim return need; 573285242Sachim} 574285242Sachim 575285242Sachimint 576285242Sachimdn_c_copy_q (void *_ni, void *arg) 577285242Sachim{ 578285242Sachim struct copy_args *a = arg; 579285242Sachim struct dn_flow_queue7 *fq7 = (struct dn_flow_queue7 *)*a->start; 580285242Sachim struct dn_flow_queue8 *fq8 = (struct dn_flow_queue8 *)*a->start; 581285242Sachim struct dn_flow *ni = (struct dn_flow *)_ni; 582285242Sachim int size = 0; 583285242Sachim 584285242Sachim /* XXX hash slot not set */ 585285242Sachim /* No difference between 7.2/8 */ 586285242Sachim fq7->len = ni->length; 587285242Sachim fq7->len_bytes = ni->len_bytes; 588285242Sachim fq7->id = ni->fid; 589285242Sachim 590285242Sachim if (is7) { 591285242Sachim size = sizeof(struct dn_flow_queue7); 592285242Sachim fq7->tot_pkts = ni->tot_pkts; 593285242Sachim fq7->tot_bytes = ni->tot_bytes; 594285242Sachim fq7->drops = ni->drops; 595285242Sachim } else { 596285242Sachim size = sizeof(struct dn_flow_queue8); 597285242Sachim fq8->tot_pkts = ni->tot_pkts; 598285242Sachim fq8->tot_bytes = ni->tot_bytes; 599285242Sachim fq8->drops = ni->drops; 600285242Sachim } 601285242Sachim 602285242Sachim *a->start += size; 603285242Sachim return 0; 604285242Sachim} 605285242Sachim 606285242Sachimint 607285242Sachimdn_c_copy_pipe(struct dn_schk *s, struct copy_args *a, int nq) 608285242Sachim{ 609285242Sachim struct dn_link *l = &s->link; 610285242Sachim struct dn_fsk *f = s->fs; 611285242Sachim 612285242Sachim struct dn_pipe7 *pipe7 = (struct dn_pipe7 *)*a->start; 613285242Sachim struct dn_pipe8 *pipe8 = (struct dn_pipe8 *)*a->start; 614285242Sachim struct dn_flow_set *fs; 615285242Sachim int size = 0; 616285242Sachim 617285242Sachim if (is7) { 618285242Sachim fs = &pipe7->fs; 619285242Sachim size = sizeof(struct dn_pipe7); 620285242Sachim } else { 621285242Sachim fs = &pipe8->fs; 622285242Sachim size = sizeof(struct dn_pipe8); 623285242Sachim } 624285242Sachim 625285242Sachim /* These 4 field are the same in pipe7 and pipe8 */ 626285242Sachim pipe7->next.sle_next = (struct dn_pipe7 *)DN_IS_PIPE; 627285242Sachim pipe7->bandwidth = l->bandwidth; 628285242Sachim pipe7->delay = l->delay * 1000 / hz; 629285242Sachim pipe7->pipe_nr = l->link_nr - DN_MAX_ID; 630285242Sachim 631285242Sachim if (!is7) { 632285242Sachim if (s->profile) { 633285242Sachim struct dn_profile *pf = s->profile; 634285242Sachim strncpy(pipe8->name, pf->name, sizeof(pf->name)); 635285242Sachim pipe8->loss_level = pf->loss_level; 636285242Sachim pipe8->samples_no = pf->samples_no; 637285242Sachim } 638285242Sachim pipe8->burst = div64(l->burst , 8 * hz); 639285242Sachim } 640285242Sachim 641285242Sachim fs->flow_mask = s->sch.sched_mask; 642285242Sachim fs->rq_size = s->sch.buckets ? s->sch.buckets : 1; 643285242Sachim 644285242Sachim fs->parent_nr = l->link_nr - DN_MAX_ID; 645285242Sachim fs->qsize = f->fs.qsize; 646285242Sachim fs->plr = f->fs.plr; 647285242Sachim fs->w_q = f->fs.w_q; 648285242Sachim fs->max_th = f->max_th; 649285242Sachim fs->min_th = f->min_th; 650285242Sachim fs->max_p = f->fs.max_p; 651285242Sachim fs->rq_elements = nq; 652285242Sachim 653285242Sachim fs->flags_fs = convertflags2old(f->fs.flags); 654285242Sachim 655285242Sachim *a->start += size; 656285242Sachim return 0; 657285242Sachim} 658285242Sachim 659285242Sachim 660285242Sachimint 661285242Sachimdn_compat_copy_pipe(struct copy_args *a, void *_o) 662285242Sachim{ 663285242Sachim int have = a->end - *a->start; 664285242Sachim int need = 0; 665285242Sachim int pipe_size = sizeof(struct dn_pipe8); 666285242Sachim int queue_size = sizeof(struct dn_flow_queue8); 667285242Sachim int n_queue = 0; /* number of queues */ 668285242Sachim 669285242Sachim struct dn_schk *s = (struct dn_schk *)_o; 670285242Sachim /* calculate needed space: 671285242Sachim * - struct dn_pipe 672285242Sachim * - if there are instances, dn_queue * n_instances 673285242Sachim */ 674285242Sachim n_queue = (s->sch.flags & DN_HAVE_MASK ? dn_ht_entries(s->siht) : 675285242Sachim (s->siht ? 1 : 0)); 676285242Sachim need = pipe_size + queue_size * n_queue; 677285242Sachim if (have < need) { 678285242Sachim D("have %d < need %d", have, need); 679285242Sachim return 1; 680285242Sachim } 681285242Sachim /* copy pipe */ 682285242Sachim dn_c_copy_pipe(s, a, n_queue); 683285242Sachim 684285242Sachim /* copy queues */ 685285242Sachim if (s->sch.flags & DN_HAVE_MASK) 686285242Sachim dn_ht_scan(s->siht, dn_c_copy_q, a); 687285242Sachim else if (s->siht) 688285242Sachim dn_c_copy_q(s->siht, a); 689285242Sachim return 0; 690285242Sachim} 691285242Sachim 692285242Sachimint 693285242Sachimdn_c_copy_fs(struct dn_fsk *f, struct copy_args *a, int nq) 694285242Sachim{ 695285242Sachim struct dn_flow_set *fs = (struct dn_flow_set *)*a->start; 696285242Sachim 697285242Sachim fs->next.sle_next = (struct dn_flow_set *)DN_IS_QUEUE; 698285242Sachim fs->fs_nr = f->fs.fs_nr; 699285242Sachim fs->qsize = f->fs.qsize; 700285242Sachim fs->plr = f->fs.plr; 701285242Sachim fs->w_q = f->fs.w_q; 702285242Sachim fs->max_th = f->max_th; 703285242Sachim fs->min_th = f->min_th; 704285242Sachim fs->max_p = f->fs.max_p; 705285242Sachim fs->flow_mask = f->fs.flow_mask; 706285242Sachim fs->rq_elements = nq; 707285242Sachim fs->rq_size = (f->fs.buckets ? f->fs.buckets : 1); 708285242Sachim fs->parent_nr = f->fs.sched_nr; 709285242Sachim fs->weight = f->fs.par[0]; 710 711 fs->flags_fs = convertflags2old(f->fs.flags); 712 *a->start += sizeof(struct dn_flow_set); 713 return 0; 714} 715 716int 717dn_compat_copy_queue(struct copy_args *a, void *_o) 718{ 719 int have = a->end - *a->start; 720 int need = 0; 721 int fs_size = sizeof(struct dn_flow_set); 722 int queue_size = sizeof(struct dn_flow_queue8); 723 724 struct dn_fsk *fs = (struct dn_fsk *)_o; 725 int n_queue = 0; /* number of queues */ 726 727 n_queue = (fs->fs.flags & DN_HAVE_MASK ? dn_ht_entries(fs->qht) : 728 (fs->qht ? 1 : 0)); 729 730 need = fs_size + queue_size * n_queue; 731 if (have < need) { 732 D("have < need"); 733 return 1; 734 } 735 736 /* copy flowset */ 737 dn_c_copy_fs(fs, a, n_queue); 738 739 /* copy queues */ 740 if (fs->fs.flags & DN_HAVE_MASK) 741 dn_ht_scan(fs->qht, dn_c_copy_q, a); 742 else if (fs->qht) 743 dn_c_copy_q(fs->qht, a); 744 745 return 0; 746} 747 748int 749copy_data_helper_compat(void *_o, void *_arg) 750{ 751 struct copy_args *a = _arg; 752 753 if (a->type == DN_COMPAT_PIPE) { 754 struct dn_schk *s = _o; 755 if (s->sch.oid.subtype != 1 || s->sch.sched_nr <= DN_MAX_ID) { 756 return 0; /* not old type */ 757 } 758 /* copy pipe parameters, and if instance exists, copy 759 * other parameters and eventually queues. 760 */ 761 if(dn_compat_copy_pipe(a, _o)) 762 return DNHT_SCAN_END; 763 } else if (a->type == DN_COMPAT_QUEUE) { 764 struct dn_fsk *fs = _o; 765 if (fs->fs.fs_nr >= DN_MAX_ID) 766 return 0; 767 if (dn_compat_copy_queue(a, _o)) 768 return DNHT_SCAN_END; 769 } 770 return 0; 771} 772 773/* Main function to manage old requests */ 774int 775ip_dummynet_compat(struct sockopt *sopt) 776{ 777 int error=0; 778 void *v = NULL; 779 struct dn_id oid; 780 781 /* Lenght of data, used to found ipfw version... */ 782 int len = sopt->sopt_valsize; 783 784 /* len can be 0 if command was dummynet_flush */ 785 if (len == pipesize7) { 786 D("setting compatibility with FreeBSD 7.2"); 787 is7 = 1; 788 } 789 else if (len == pipesize8 || len == pipesizemax8) { 790 D("setting compatibility with FreeBSD 8"); 791 is7 = 0; 792 } 793 794 switch (sopt->sopt_name) { 795 default: 796 printf("dummynet: -- unknown option %d", sopt->sopt_name); 797 error = EINVAL; 798 break; 799 800 case IP_DUMMYNET_FLUSH: 801 oid_fill(&oid, sizeof(oid), DN_CMD_FLUSH, DN_API_VERSION); 802 do_config(&oid, oid.len); 803 break; 804 805 case IP_DUMMYNET_DEL: 806 v = malloc(len, M_TEMP, M_WAITOK); 807 error = sooptcopyin(sopt, v, len, len); 808 if (error) 809 break; 810 error = dn_compat_del(v); 811 free(v, M_TEMP); 812 break; 813 814 case IP_DUMMYNET_CONFIGURE: 815 v = malloc(len, M_TEMP, M_WAITOK); 816 error = sooptcopyin(sopt, v, len, len); 817 if (error) 818 break; 819 error = dn_compat_configure(v); 820 free(v, M_TEMP); 821 break; 822 823 case IP_DUMMYNET_GET: { 824 void *buf; 825 int ret; 826 int original_size = sopt->sopt_valsize; 827 int size; 828 829 ret = dummynet_get(sopt, &buf); 830 if (ret) 831 return 0;//XXX ? 832 size = sopt->sopt_valsize; 833 sopt->sopt_valsize = original_size; 834 D("size=%d, buf=%p", size, buf); 835 ret = sooptcopyout(sopt, buf, size); 836 if (ret) 837 printf(" %s ERROR sooptcopyout\n", __FUNCTION__); 838 if (buf) 839 free(buf, M_DUMMYNET); 840 } 841 } 842 843 return error; 844} 845 846 847