The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/netpfil/ipfw/ip_dn_glue.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: fd8ad8c359c1b8e67240355f1fb709d1


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.