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/dn_sched_fq_pie.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  * FQ_PIE - The FlowQueue-PIE scheduler/AQM
    3  *
    4  * $FreeBSD$
    5  * 
    6  * Copyright (C) 2016 Centre for Advanced Internet Architectures,
    7  *  Swinburne University of Technology, Melbourne, Australia.
    8  * Portions of this code were made possible in part by a gift from 
    9  *  The Comcast Innovation Fund.
   10  * Implemented by Rasool Al-Saadi <ralsaadi@swin.edu.au>
   11  *
   12  * Redistribution and use in source and binary forms, with or without
   13  * modification, are permitted provided that the following conditions
   14  * are met:
   15  * 1. Redistributions of source code must retain the above copyright
   16  *    notice, this list of conditions and the following disclaimer.
   17  * 2. Redistributions in binary form must reproduce the above copyright
   18  *    notice, this list of conditions and the following disclaimer in the
   19  *    documentation and/or other materials provided with the distribution.
   20  *
   21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   24  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   31  * SUCH DAMAGE.
   32  */
   33 
   34 /* Important note:
   35  * As there is no an office document for FQ-PIE specification, we used
   36  * FQ-CoDel algorithm with some modifications to implement FQ-PIE.
   37  * This FQ-PIE implementation is a beta version and have not been tested 
   38  * extensively. Our FQ-PIE uses stand-alone PIE AQM per sub-queue. By
   39  * default, timestamp is used to calculate queue delay instead of departure
   40  * rate estimation method. Although departure rate estimation is available 
   41  * as testing option, the results could be incorrect. Moreover, turning PIE on 
   42  * and off option is available but it does not work properly in this version.
   43  */
   44 
   45 #ifdef _KERNEL
   46 #include <sys/malloc.h>
   47 #include <sys/socket.h>
   48 #include <sys/kernel.h>
   49 #include <sys/mbuf.h>
   50 #include <sys/lock.h>
   51 #include <sys/module.h>
   52 #include <sys/mutex.h>
   53 #include <net/if.h>     /* IFNAMSIZ */
   54 #include <netinet/in.h>
   55 #include <netinet/ip_var.h>             /* ipfw_rule_ref */
   56 #include <netinet/ip_fw.h>      /* flow_id */
   57 #include <netinet/ip_dummynet.h>
   58 
   59 #include <sys/proc.h>
   60 #include <sys/rwlock.h>
   61 
   62 #include <netpfil/ipfw/ip_fw_private.h>
   63 #include <sys/sysctl.h>
   64 #include <netinet/ip.h>
   65 #include <netinet/ip6.h>
   66 #include <netinet/ip_icmp.h>
   67 #include <netinet/tcp.h>
   68 #include <netinet/udp.h>
   69 #include <sys/queue.h>
   70 #include <sys/hash.h>
   71 
   72 #include <netpfil/ipfw/dn_heap.h>
   73 #include <netpfil/ipfw/ip_dn_private.h>
   74 
   75 #include <netpfil/ipfw/dn_aqm.h>
   76 #include <netpfil/ipfw/dn_aqm_pie.h>
   77 #include <netpfil/ipfw/dn_sched.h>
   78 
   79 #else
   80 #include <dn_test.h>
   81 #endif
   82 
   83 #define DN_SCHED_FQ_PIE 7
   84 
   85 /* list of queues */
   86 STAILQ_HEAD(fq_pie_list, fq_pie_flow);
   87 
   88 /* FQ_PIE parameters including PIE */
   89 struct dn_sch_fq_pie_parms {
   90         struct dn_aqm_pie_parms pcfg;   /* PIE configuration Parameters */
   91         /* FQ_PIE Parameters */
   92         uint32_t flows_cnt;     /* number of flows */
   93         uint32_t limit; /* hard limit of FQ_PIE queue size*/
   94         uint32_t quantum;
   95 };
   96 
   97 /* flow (sub-queue) stats */
   98 struct flow_stats {
   99         uint64_t tot_pkts;      /* statistics counters  */
  100         uint64_t tot_bytes;
  101         uint32_t length;                /* Queue length, in packets */
  102         uint32_t len_bytes;     /* Queue length, in bytes */
  103         uint32_t drops;
  104 };
  105 
  106 /* A flow of packets (sub-queue)*/
  107 struct fq_pie_flow {
  108         struct mq       mq;     /* list of packets */
  109         struct flow_stats stats;        /* statistics */
  110         int deficit;
  111         int active;             /* 1: flow is active (in a list) */
  112         struct pie_status pst;  /* pie status variables */
  113         struct fq_pie_si_extra *psi_extra;
  114         STAILQ_ENTRY(fq_pie_flow) flowchain;
  115 };
  116 
  117 /* extra fq_pie scheduler configurations */
  118 struct fq_pie_schk {
  119         struct dn_sch_fq_pie_parms cfg;
  120 };
  121 
  122 /* fq_pie scheduler instance extra state vars.
  123  * The purpose of separation this structure is to preserve number of active
  124  * sub-queues and the flows array pointer even after the scheduler instance
  125  * is destroyed.
  126  * Preserving these varaiables allows freeing the allocated memory by
  127  * fqpie_callout_cleanup() independently from fq_pie_free_sched().
  128  */
  129 struct fq_pie_si_extra {
  130         uint32_t nr_active_q;   /* number of active queues */
  131         struct fq_pie_flow *flows;      /* array of flows (queues) */
  132         };
  133 
  134 /* fq_pie scheduler instance */
  135 struct fq_pie_si {
  136         struct dn_sch_inst _si; /* standard scheduler instance. SHOULD BE FIRST */ 
  137         struct dn_queue main_q; /* main queue is after si directly */
  138         uint32_t perturbation;  /* random value */
  139         struct fq_pie_list newflows;    /* list of new queues */
  140         struct fq_pie_list oldflows;    /* list of old queues */
  141         struct fq_pie_si_extra *si_extra; /* extra state vars*/
  142 };
  143 
  144 static struct dn_alg fq_pie_desc;
  145 
  146 /*  Default FQ-PIE parameters including PIE */
  147 /*  PIE defaults
  148  * target=15ms, max_burst=150ms, max_ecnth=0.1, 
  149  * alpha=0.125, beta=1.25, tupdate=15ms
  150  * FQ-
  151  * flows=1024, limit=10240, quantum =1514
  152  */
  153 struct dn_sch_fq_pie_parms 
  154  fq_pie_sysctl = {{15000 * AQM_TIME_1US, 15000 * AQM_TIME_1US,
  155         150000 * AQM_TIME_1US, PIE_SCALE * 0.1, PIE_SCALE * 0.125, 
  156         PIE_SCALE * 1.25,       PIE_CAPDROP_ENABLED | PIE_DERAND_ENABLED},
  157         1024, 10240, 1514};
  158 
  159 static int
  160 fqpie_sysctl_alpha_beta_handler(SYSCTL_HANDLER_ARGS)
  161 {
  162         int error;
  163         long  value;
  164 
  165         if (!strcmp(oidp->oid_name,"alpha"))
  166                 value = fq_pie_sysctl.pcfg.alpha;
  167         else
  168                 value = fq_pie_sysctl.pcfg.beta;
  169                 
  170         value = value * 1000 / PIE_SCALE;
  171         error = sysctl_handle_long(oidp, &value, 0, req);
  172         if (error != 0 || req->newptr == NULL)
  173                 return (error);
  174         if (value < 1 || value > 7 * PIE_SCALE)
  175                 return (EINVAL);
  176         value = (value * PIE_SCALE) / 1000;
  177         if (!strcmp(oidp->oid_name,"alpha"))
  178                         fq_pie_sysctl.pcfg.alpha = value;
  179         else
  180                 fq_pie_sysctl.pcfg.beta = value;
  181         return (0);
  182 }
  183 
  184 static int
  185 fqpie_sysctl_target_tupdate_maxb_handler(SYSCTL_HANDLER_ARGS)
  186 {
  187         int error;
  188         long  value;
  189 
  190         if (!strcmp(oidp->oid_name,"target"))
  191                 value = fq_pie_sysctl.pcfg.qdelay_ref;
  192         else if (!strcmp(oidp->oid_name,"tupdate"))
  193                 value = fq_pie_sysctl.pcfg.tupdate;
  194         else
  195                 value = fq_pie_sysctl.pcfg.max_burst;
  196 
  197         value = value / AQM_TIME_1US;
  198         error = sysctl_handle_long(oidp, &value, 0, req);
  199         if (error != 0 || req->newptr == NULL)
  200                 return (error);
  201         if (value < 1 || value > 10 * AQM_TIME_1S)
  202                 return (EINVAL);
  203         value = value * AQM_TIME_1US;
  204 
  205         if (!strcmp(oidp->oid_name,"target"))
  206                 fq_pie_sysctl.pcfg.qdelay_ref  = value;
  207         else if (!strcmp(oidp->oid_name,"tupdate"))
  208                 fq_pie_sysctl.pcfg.tupdate  = value;
  209         else
  210                 fq_pie_sysctl.pcfg.max_burst = value;
  211         return (0);
  212 }
  213 
  214 static int
  215 fqpie_sysctl_max_ecnth_handler(SYSCTL_HANDLER_ARGS)
  216 {
  217         int error;
  218         long  value;
  219 
  220         value = fq_pie_sysctl.pcfg.max_ecnth;
  221         value = value * 1000 / PIE_SCALE;
  222         error = sysctl_handle_long(oidp, &value, 0, req);
  223         if (error != 0 || req->newptr == NULL)
  224                 return (error);
  225         if (value < 1 || value > PIE_SCALE)
  226                 return (EINVAL);
  227         value = (value * PIE_SCALE) / 1000;
  228         fq_pie_sysctl.pcfg.max_ecnth = value;
  229         return (0);
  230 }
  231 
  232 /* define FQ- PIE sysctl variables */
  233 SYSBEGIN(f4)
  234 SYSCTL_DECL(_net_inet);
  235 SYSCTL_DECL(_net_inet_ip);
  236 SYSCTL_DECL(_net_inet_ip_dummynet);
  237 static SYSCTL_NODE(_net_inet_ip_dummynet, OID_AUTO, fqpie,
  238     CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
  239     "FQ_PIE");
  240 
  241 #ifdef SYSCTL_NODE
  242 
  243 SYSCTL_PROC(_net_inet_ip_dummynet_fqpie, OID_AUTO, target,
  244     CTLTYPE_LONG | CTLFLAG_RW | CTLFLAG_NEEDGIANT, NULL, 0,
  245     fqpie_sysctl_target_tupdate_maxb_handler, "L",
  246     "queue target in microsecond");
  247 
  248 SYSCTL_PROC(_net_inet_ip_dummynet_fqpie, OID_AUTO, tupdate,
  249     CTLTYPE_LONG | CTLFLAG_RW | CTLFLAG_NEEDGIANT, NULL, 0,
  250     fqpie_sysctl_target_tupdate_maxb_handler, "L",
  251     "the frequency of drop probability calculation in microsecond");
  252 
  253 SYSCTL_PROC(_net_inet_ip_dummynet_fqpie, OID_AUTO, max_burst,
  254     CTLTYPE_LONG | CTLFLAG_RW | CTLFLAG_NEEDGIANT, NULL, 0,
  255     fqpie_sysctl_target_tupdate_maxb_handler, "L",
  256     "Burst allowance interval in microsecond");
  257 
  258 SYSCTL_PROC(_net_inet_ip_dummynet_fqpie, OID_AUTO, max_ecnth,
  259     CTLTYPE_LONG | CTLFLAG_RW | CTLFLAG_NEEDGIANT, NULL, 0,
  260     fqpie_sysctl_max_ecnth_handler, "L",
  261     "ECN safeguard threshold scaled by 1000");
  262 
  263 SYSCTL_PROC(_net_inet_ip_dummynet_fqpie, OID_AUTO, alpha,
  264     CTLTYPE_LONG | CTLFLAG_RW | CTLFLAG_NEEDGIANT, NULL, 0,
  265     fqpie_sysctl_alpha_beta_handler, "L",
  266     "PIE alpha scaled by 1000");
  267 
  268 SYSCTL_PROC(_net_inet_ip_dummynet_fqpie, OID_AUTO, beta,
  269     CTLTYPE_LONG | CTLFLAG_RW | CTLFLAG_NEEDGIANT, NULL, 0,
  270     fqpie_sysctl_alpha_beta_handler, "L",
  271     "beta scaled by 1000");
  272 
  273 SYSCTL_UINT(_net_inet_ip_dummynet_fqpie, OID_AUTO, quantum,
  274         CTLFLAG_RW, &fq_pie_sysctl.quantum, 1514, "quantum for FQ_PIE");
  275 SYSCTL_UINT(_net_inet_ip_dummynet_fqpie, OID_AUTO, flows,
  276         CTLFLAG_RW, &fq_pie_sysctl.flows_cnt, 1024, "Number of queues for FQ_PIE");
  277 SYSCTL_UINT(_net_inet_ip_dummynet_fqpie, OID_AUTO, limit,
  278         CTLFLAG_RW, &fq_pie_sysctl.limit, 10240, "limit for FQ_PIE");
  279 #endif
  280 
  281 /* Helper function to update queue&main-queue and scheduler statistics.
  282  * negative len & drop -> drop
  283  * negative len -> dequeue
  284  * positive len -> enqueue
  285  * positive len + drop -> drop during enqueue
  286  */
  287 __inline static void
  288 fq_update_stats(struct fq_pie_flow *q, struct fq_pie_si *si, int len,
  289         int drop)
  290 {
  291         int inc = 0;
  292 
  293         if (len < 0) 
  294                 inc = -1;
  295         else if (len > 0)
  296                 inc = 1;
  297 
  298         if (drop) {
  299                 si->main_q.ni.drops ++;
  300                 q->stats.drops ++;
  301                 si->_si.ni.drops ++;
  302                 V_dn_cfg.io_pkt_drop ++;
  303         } 
  304 
  305         if (!drop || (drop && len < 0)) {
  306                 /* Update stats for the main queue */
  307                 si->main_q.ni.length += inc;
  308                 si->main_q.ni.len_bytes += len;
  309 
  310                 /*update sub-queue stats */
  311                 q->stats.length += inc;
  312                 q->stats.len_bytes += len;
  313 
  314                 /*update scheduler instance stats */
  315                 si->_si.ni.length += inc;
  316                 si->_si.ni.len_bytes += len;
  317         }
  318 
  319         if (inc > 0) {
  320                 si->main_q.ni.tot_bytes += len;
  321                 si->main_q.ni.tot_pkts ++;
  322                 
  323                 q->stats.tot_bytes +=len;
  324                 q->stats.tot_pkts++;
  325                 
  326                 si->_si.ni.tot_bytes +=len;
  327                 si->_si.ni.tot_pkts ++;
  328         }
  329 
  330 }
  331 
  332 /*
  333  * Extract a packet from the head of sub-queue 'q'
  334  * Return a packet or NULL if the queue is empty.
  335  * If getts is set, also extract packet's timestamp from mtag.
  336  */
  337 __inline static struct mbuf *
  338 fq_pie_extract_head(struct fq_pie_flow *q, aqm_time_t *pkt_ts,
  339         struct fq_pie_si *si, int getts)
  340 {
  341         struct mbuf *m;
  342 
  343 next:   m = q->mq.head;
  344         if (m == NULL)
  345                 return m;
  346         q->mq.head = m->m_nextpkt;
  347 
  348         fq_update_stats(q, si, -m->m_pkthdr.len, 0);
  349 
  350         if (si->main_q.ni.length == 0) /* queue is now idle */
  351                         si->main_q.q_time = V_dn_cfg.curr_time;
  352 
  353         if (getts) {
  354                 /* extract packet timestamp*/
  355                 struct m_tag *mtag;
  356                 mtag = m_tag_locate(m, MTAG_ABI_COMPAT, DN_AQM_MTAG_TS, NULL);
  357                 if (mtag == NULL){
  358                         D("PIE timestamp mtag not found!");
  359                         *pkt_ts = 0;
  360                 } else {
  361                         *pkt_ts = *(aqm_time_t *)(mtag + 1);
  362                         m_tag_delete(m,mtag); 
  363                 }
  364         }
  365         if (m->m_pkthdr.rcvif != NULL &&
  366             __predict_false(m_rcvif_restore(m) == NULL)) {
  367                 m_freem(m);
  368                 goto next;
  369         }
  370         return m;
  371 }
  372 
  373 /*
  374  * Callout function for drop probability calculation 
  375  * This function is called over tupdate ms and takes pointer of FQ-PIE
  376  * flow as an argument
  377   */
  378 static void
  379 fq_calculate_drop_prob(void *x)
  380 {
  381         struct fq_pie_flow *q = (struct fq_pie_flow *) x;
  382         struct pie_status *pst = &q->pst;
  383         struct dn_aqm_pie_parms *pprms; 
  384         int64_t p, prob, oldprob;
  385         int p_isneg;
  386 
  387         pprms = pst->parms;
  388         prob = pst->drop_prob;
  389 
  390         /* calculate current qdelay using DRE method.
  391          * If TS is used and no data in the queue, reset current_qdelay
  392          * as it stays at last value during dequeue process.
  393         */
  394         if (pprms->flags & PIE_DEPRATEEST_ENABLED)
  395                 pst->current_qdelay = ((uint64_t)q->stats.len_bytes  * pst->avg_dq_time)
  396                         >> PIE_DQ_THRESHOLD_BITS;
  397         else
  398                 if (!q->stats.len_bytes)
  399                         pst->current_qdelay = 0;
  400 
  401         /* calculate drop probability */
  402         p = (int64_t)pprms->alpha * 
  403                 ((int64_t)pst->current_qdelay - (int64_t)pprms->qdelay_ref); 
  404         p +=(int64_t) pprms->beta * 
  405                 ((int64_t)pst->current_qdelay - (int64_t)pst->qdelay_old); 
  406 
  407         /* take absolute value so right shift result is well defined */
  408         p_isneg = p < 0;
  409         if (p_isneg) {
  410                 p = -p;
  411         }
  412                 
  413         /* We PIE_MAX_PROB shift by 12-bits to increase the division precision  */
  414         p *= (PIE_MAX_PROB << 12) / AQM_TIME_1S;
  415 
  416         /* auto-tune drop probability */
  417         if (prob < (PIE_MAX_PROB / 1000000)) /* 0.000001 */
  418                 p >>= 11 + PIE_FIX_POINT_BITS + 12;
  419         else if (prob < (PIE_MAX_PROB / 100000)) /* 0.00001 */
  420                 p >>= 9 + PIE_FIX_POINT_BITS + 12;
  421         else if (prob < (PIE_MAX_PROB / 10000)) /* 0.0001 */
  422                 p >>= 7 + PIE_FIX_POINT_BITS + 12;
  423         else if (prob < (PIE_MAX_PROB / 1000)) /* 0.001 */
  424                 p >>= 5 + PIE_FIX_POINT_BITS + 12;
  425         else if (prob < (PIE_MAX_PROB / 100)) /* 0.01 */
  426                 p >>= 3 + PIE_FIX_POINT_BITS + 12;
  427         else if (prob < (PIE_MAX_PROB / 10)) /* 0.1 */
  428                 p >>= 1 + PIE_FIX_POINT_BITS + 12;
  429         else
  430                 p >>= PIE_FIX_POINT_BITS + 12;
  431 
  432         oldprob = prob;
  433 
  434         if (p_isneg) {
  435                 prob = prob - p;
  436 
  437                 /* check for multiplication underflow */
  438                 if (prob > oldprob) {
  439                         prob= 0;
  440                         D("underflow");
  441                 }
  442         } else {
  443                 /* Cap Drop adjustment */
  444                 if ((pprms->flags & PIE_CAPDROP_ENABLED) &&
  445                     prob >= PIE_MAX_PROB / 10 &&
  446                     p > PIE_MAX_PROB / 50 ) {
  447                         p = PIE_MAX_PROB / 50;
  448                 }
  449 
  450                 prob = prob + p;
  451 
  452                 /* check for multiplication overflow */
  453                 if (prob<oldprob) {
  454                         D("overflow");
  455                         prob= PIE_MAX_PROB;
  456                 }
  457         }
  458 
  459         /*
  460          * decay the drop probability exponentially
  461          * and restrict it to range 0 to PIE_MAX_PROB
  462          */
  463         if (prob < 0) {
  464                 prob = 0;
  465         } else {
  466                 if (pst->current_qdelay == 0 && pst->qdelay_old == 0) {
  467                         /* 0.98 ~= 1- 1/64 */
  468                         prob = prob - (prob >> 6); 
  469                 }
  470 
  471                 if (prob > PIE_MAX_PROB) {
  472                         prob = PIE_MAX_PROB;
  473                 }
  474         }
  475 
  476         pst->drop_prob = prob;
  477 
  478         /* store current delay value */
  479         pst->qdelay_old = pst->current_qdelay;
  480 
  481         /* update burst allowance */
  482         if ((pst->sflags & PIE_ACTIVE) && pst->burst_allowance) {
  483                 if (pst->burst_allowance > pprms->tupdate)
  484                         pst->burst_allowance -= pprms->tupdate;
  485                 else 
  486                         pst->burst_allowance = 0;
  487         }
  488 
  489         if (pst->sflags & PIE_ACTIVE)
  490         callout_reset_sbt(&pst->aqm_pie_callout,
  491                 (uint64_t)pprms->tupdate * SBT_1US,
  492                 0, fq_calculate_drop_prob, q, 0);
  493 
  494         mtx_unlock(&pst->lock_mtx);
  495 }
  496 
  497 /* 
  498  * Reset PIE variables & activate the queue
  499  */
  500 __inline static void
  501 fq_activate_pie(struct fq_pie_flow *q)
  502 { 
  503         struct pie_status *pst = &q->pst;
  504         struct dn_aqm_pie_parms *pprms;
  505 
  506         mtx_lock(&pst->lock_mtx);
  507         pprms = pst->parms;
  508 
  509         pprms = pst->parms;
  510         pst->drop_prob = 0;
  511         pst->qdelay_old = 0;
  512         pst->burst_allowance = pprms->max_burst;
  513         pst->accu_prob = 0;
  514         pst->dq_count = 0;
  515         pst->avg_dq_time = 0;
  516         pst->sflags = PIE_INMEASUREMENT | PIE_ACTIVE;
  517         pst->measurement_start = AQM_UNOW;
  518 
  519         callout_reset_sbt(&pst->aqm_pie_callout,
  520                 (uint64_t)pprms->tupdate * SBT_1US,
  521                 0, fq_calculate_drop_prob, q, 0);
  522 
  523         mtx_unlock(&pst->lock_mtx);
  524 }
  525 
  526  /* 
  527   * Deactivate PIE and stop probe update callout
  528   */
  529 __inline static void
  530 fq_deactivate_pie(struct pie_status *pst)
  531 { 
  532         mtx_lock(&pst->lock_mtx);
  533         pst->sflags &= ~(PIE_ACTIVE | PIE_INMEASUREMENT);
  534         callout_stop(&pst->aqm_pie_callout);
  535         //D("PIE Deactivated");
  536         mtx_unlock(&pst->lock_mtx);
  537 }
  538 
  539  /* 
  540   * Initialize PIE for sub-queue 'q'
  541   */
  542 static int
  543 pie_init(struct fq_pie_flow *q, struct fq_pie_schk *fqpie_schk)
  544 {
  545         struct pie_status *pst=&q->pst;
  546         struct dn_aqm_pie_parms *pprms = pst->parms;
  547 
  548         int err = 0;
  549         if (!pprms){
  550                 D("AQM_PIE is not configured");
  551                 err = EINVAL;
  552         } else {
  553                 q->psi_extra->nr_active_q++;
  554 
  555                 /* For speed optimization, we caculate 1/3 queue size once here */
  556                 // XXX limit divided by number of queues divided by 3 ??? 
  557                 pst->one_third_q_size = (fqpie_schk->cfg.limit / 
  558                         fqpie_schk->cfg.flows_cnt) / 3;
  559 
  560                 mtx_init(&pst->lock_mtx, "mtx_pie", NULL, MTX_DEF);
  561                 callout_init_mtx(&pst->aqm_pie_callout, &pst->lock_mtx,
  562                         CALLOUT_RETURNUNLOCKED);
  563         }
  564 
  565         return err;
  566 }
  567 
  568 /* 
  569  * callout function to destroy PIE lock, and free fq_pie flows and fq_pie si
  570  * extra memory when number of active sub-queues reaches zero.
  571  * 'x' is a fq_pie_flow to be destroyed
  572  */
  573 static void
  574 fqpie_callout_cleanup(void *x)
  575 {
  576         struct fq_pie_flow *q = x;
  577         struct pie_status *pst = &q->pst;
  578         struct fq_pie_si_extra *psi_extra;
  579 
  580         mtx_unlock(&pst->lock_mtx);
  581         mtx_destroy(&pst->lock_mtx);
  582         psi_extra = q->psi_extra;
  583 
  584         dummynet_sched_lock();
  585         psi_extra->nr_active_q--;
  586 
  587         /* when all sub-queues are destroyed, free flows fq_pie extra vars memory */
  588         if (!psi_extra->nr_active_q) {
  589                 free(psi_extra->flows, M_DUMMYNET);
  590                 free(psi_extra, M_DUMMYNET);
  591                 fq_pie_desc.ref_count--;
  592         }
  593         dummynet_sched_unlock();
  594 }
  595 
  596 /* 
  597  * Clean up PIE status for sub-queue 'q' 
  598  * Stop callout timer and destroy mtx using fqpie_callout_cleanup() callout.
  599  */
  600 static int
  601 pie_cleanup(struct fq_pie_flow *q)
  602 {
  603         struct pie_status *pst  = &q->pst;
  604 
  605         mtx_lock(&pst->lock_mtx);
  606         callout_reset_sbt(&pst->aqm_pie_callout,
  607                 SBT_1US, 0, fqpie_callout_cleanup, q, 0);
  608         mtx_unlock(&pst->lock_mtx);
  609         return 0;
  610 }
  611 
  612 /* 
  613  * Dequeue and return a pcaket from sub-queue 'q' or NULL if 'q' is empty.
  614  * Also, caculate depature time or queue delay using timestamp
  615  */
  616  static struct mbuf *
  617 pie_dequeue(struct fq_pie_flow *q, struct fq_pie_si *si)
  618 {
  619         struct mbuf *m;
  620         struct dn_aqm_pie_parms *pprms;
  621         struct pie_status *pst;
  622         aqm_time_t now;
  623         aqm_time_t pkt_ts, dq_time;
  624         int32_t w;
  625 
  626         pst  = &q->pst;
  627         pprms = q->pst.parms;
  628 
  629         /*we extarct packet ts only when Departure Rate Estimation dis not used*/
  630         m = fq_pie_extract_head(q, &pkt_ts, si, 
  631                 !(pprms->flags & PIE_DEPRATEEST_ENABLED));
  632 
  633         if (!m || !(pst->sflags & PIE_ACTIVE))
  634                 return m;
  635 
  636         now = AQM_UNOW;
  637         if (pprms->flags & PIE_DEPRATEEST_ENABLED) {
  638                 /* calculate average depature time */
  639                 if(pst->sflags & PIE_INMEASUREMENT) {
  640                         pst->dq_count += m->m_pkthdr.len;
  641 
  642                         if (pst->dq_count >= PIE_DQ_THRESHOLD) {
  643                                 dq_time = now - pst->measurement_start;
  644 
  645                                 /* 
  646                                  * if we don't have old avg dq_time i.e PIE is (re)initialized, 
  647                                  * don't use weight to calculate new avg_dq_time
  648                                  */
  649                                 if(pst->avg_dq_time == 0)
  650                                         pst->avg_dq_time = dq_time;
  651                                 else {
  652                                         /*
  653                                          * weight = PIE_DQ_THRESHOLD/2^6, but we scaled
  654                                          * weight by 2^8. Thus, scaled
  655                                          * weight = PIE_DQ_THRESHOLD /2^8
  656                                          * */
  657                                         w = PIE_DQ_THRESHOLD >> 8;
  658                                         pst->avg_dq_time = (dq_time* w
  659                                                 + (pst->avg_dq_time * ((1L << 8) - w))) >> 8;
  660                                         pst->sflags &= ~PIE_INMEASUREMENT;
  661                                 }
  662                         }
  663                 }
  664 
  665                 /*
  666                  * Start new measurement cycle when the queue has
  667                  * PIE_DQ_THRESHOLD worth of bytes.
  668                  */
  669                 if(!(pst->sflags & PIE_INMEASUREMENT) &&
  670                         q->stats.len_bytes >= PIE_DQ_THRESHOLD) {
  671                         pst->sflags |= PIE_INMEASUREMENT;
  672                         pst->measurement_start = now;
  673                         pst->dq_count = 0;
  674                 }
  675         }
  676         /* Optionally, use packet timestamp to estimate queue delay */
  677         else
  678                 pst->current_qdelay = now - pkt_ts;
  679 
  680         return m;
  681 }
  682 
  683  /*
  684  * Enqueue a packet in q, subject to space and FQ-PIE queue management policy
  685  * (whose parameters are in q->fs).
  686  * Update stats for the queue and the scheduler.
  687  * Return 0 on success, 1 on drop. The packet is consumed anyways.
  688  */
  689 static int
  690 pie_enqueue(struct fq_pie_flow *q, struct mbuf* m, struct fq_pie_si *si)
  691 {
  692         uint64_t len;
  693         struct pie_status *pst;
  694         struct dn_aqm_pie_parms *pprms;
  695         int t;
  696 
  697         len = m->m_pkthdr.len;
  698         pst  = &q->pst;
  699         pprms = pst->parms;
  700         t = ENQUE;
  701 
  702         /* drop/mark the packet when PIE is active and burst time elapsed */
  703         if (pst->sflags & PIE_ACTIVE && pst->burst_allowance == 0
  704                 && drop_early(pst, q->stats.len_bytes) == DROP) {
  705                         /* 
  706                          * if drop_prob over ECN threshold, drop the packet 
  707                          * otherwise mark and enqueue it.
  708                          */
  709                         if (pprms->flags & PIE_ECN_ENABLED && pst->drop_prob < 
  710                                 (pprms->max_ecnth << (PIE_PROB_BITS - PIE_FIX_POINT_BITS))
  711                                 && ecn_mark(m))
  712                                 t = ENQUE;
  713                         else
  714                                 t = DROP;
  715                 }
  716 
  717         /* Turn PIE on when 1/3 of the queue is full */ 
  718         if (!(pst->sflags & PIE_ACTIVE) && q->stats.len_bytes >= 
  719                 pst->one_third_q_size) {
  720                 fq_activate_pie(q);
  721         }
  722 
  723         /*  reset burst tolerance and optinally turn PIE off*/
  724         if (pst->drop_prob == 0 && pst->current_qdelay < (pprms->qdelay_ref >> 1)
  725                 && pst->qdelay_old < (pprms->qdelay_ref >> 1)) {
  726                         
  727                         pst->burst_allowance = pprms->max_burst;
  728                 if (pprms->flags & PIE_ON_OFF_MODE_ENABLED && q->stats.len_bytes<=0)
  729                         fq_deactivate_pie(pst);
  730         }
  731 
  732         /* Use timestamp if Departure Rate Estimation mode is disabled */
  733         if (t != DROP && !(pprms->flags & PIE_DEPRATEEST_ENABLED)) {
  734                 /* Add TS to mbuf as a TAG */
  735                 struct m_tag *mtag;
  736                 mtag = m_tag_locate(m, MTAG_ABI_COMPAT, DN_AQM_MTAG_TS, NULL);
  737                 if (mtag == NULL)
  738                         mtag = m_tag_alloc(MTAG_ABI_COMPAT, DN_AQM_MTAG_TS,
  739                                 sizeof(aqm_time_t), M_NOWAIT);
  740                 if (mtag == NULL) {
  741                         t = DROP;
  742                 } else {
  743                         *(aqm_time_t *)(mtag + 1) = AQM_UNOW;
  744                         m_tag_prepend(m, mtag);
  745                 }
  746         }
  747 
  748         if (t != DROP) {
  749                 mq_append(&q->mq, m);
  750                 fq_update_stats(q, si, len, 0);
  751                 return 0;
  752         } else {
  753                 fq_update_stats(q, si, len, 1);
  754                 pst->accu_prob = 0;
  755                 FREE_PKT(m);
  756                 return 1;
  757         }
  758 
  759         return 0;
  760 }
  761 
  762 /* Drop a packet form the head of FQ-PIE sub-queue */
  763 static void
  764 pie_drop_head(struct fq_pie_flow *q, struct fq_pie_si *si)
  765 {
  766         struct mbuf *m = q->mq.head;
  767 
  768         if (m == NULL)
  769                 return;
  770         q->mq.head = m->m_nextpkt;
  771 
  772         fq_update_stats(q, si, -m->m_pkthdr.len, 1);
  773 
  774         if (si->main_q.ni.length == 0) /* queue is now idle */
  775                         si->main_q.q_time = V_dn_cfg.curr_time;
  776         /* reset accu_prob after packet drop */
  777         q->pst.accu_prob = 0;
  778 
  779         FREE_PKT(m);
  780 }
  781 
  782 /*
  783  * Classify a packet to queue number using Jenkins hash function.
  784  * Return: queue number 
  785  * the input of the hash are protocol no, perturbation, src IP, dst IP,
  786  * src port, dst port,
  787  */
  788 static inline int
  789 fq_pie_classify_flow(struct mbuf *m, uint16_t fcount, struct fq_pie_si *si)
  790 {
  791         struct ip *ip;
  792         struct tcphdr *th;
  793         struct udphdr *uh;
  794         uint8_t tuple[41];
  795         uint16_t hash=0;
  796 
  797         ip = (struct ip *)mtodo(m, dn_tag_get(m)->iphdr_off);
  798 //#ifdef INET6
  799         struct ip6_hdr *ip6;
  800         int isip6;
  801         isip6 = (ip->ip_v == 6);
  802 
  803         if(isip6) {
  804                 ip6 = (struct ip6_hdr *)ip;
  805                 *((uint8_t *) &tuple[0]) = ip6->ip6_nxt;
  806                 *((uint32_t *) &tuple[1]) = si->perturbation;
  807                 memcpy(&tuple[5], ip6->ip6_src.s6_addr, 16);
  808                 memcpy(&tuple[21], ip6->ip6_dst.s6_addr, 16);
  809 
  810                 switch (ip6->ip6_nxt) {
  811                 case IPPROTO_TCP:
  812                         th = (struct tcphdr *)(ip6 + 1);
  813                         *((uint16_t *) &tuple[37]) = th->th_dport;
  814                         *((uint16_t *) &tuple[39]) = th->th_sport;
  815                         break;
  816 
  817                 case IPPROTO_UDP:
  818                         uh = (struct udphdr *)(ip6 + 1);
  819                         *((uint16_t *) &tuple[37]) = uh->uh_dport;
  820                         *((uint16_t *) &tuple[39]) = uh->uh_sport;
  821                         break;
  822                 default:
  823                         memset(&tuple[37], 0, 4);
  824                 }
  825 
  826                 hash = jenkins_hash(tuple, 41, HASHINIT) %  fcount;
  827                 return hash;
  828         } 
  829 //#endif
  830 
  831         /* IPv4 */
  832         *((uint8_t *) &tuple[0]) = ip->ip_p;
  833         *((uint32_t *) &tuple[1]) = si->perturbation;
  834         *((uint32_t *) &tuple[5]) = ip->ip_src.s_addr;
  835         *((uint32_t *) &tuple[9]) = ip->ip_dst.s_addr;
  836 
  837         switch (ip->ip_p) {
  838                 case IPPROTO_TCP:
  839                         th = (struct tcphdr *)(ip + 1);
  840                         *((uint16_t *) &tuple[13]) = th->th_dport;
  841                         *((uint16_t *) &tuple[15]) = th->th_sport;
  842                         break;
  843 
  844                 case IPPROTO_UDP:
  845                         uh = (struct udphdr *)(ip + 1);
  846                         *((uint16_t *) &tuple[13]) = uh->uh_dport;
  847                         *((uint16_t *) &tuple[15]) = uh->uh_sport;
  848                         break;
  849                 default:
  850                         memset(&tuple[13], 0, 4);
  851         }
  852         hash = jenkins_hash(tuple, 17, HASHINIT) % fcount;
  853 
  854         return hash;
  855 }
  856 
  857 /*
  858  * Enqueue a packet into an appropriate queue according to
  859  * FQ-CoDe; algorithm.
  860  */
  861 static int 
  862 fq_pie_enqueue(struct dn_sch_inst *_si, struct dn_queue *_q, 
  863         struct mbuf *m)
  864 { 
  865         struct fq_pie_si *si;
  866         struct fq_pie_schk *schk;
  867         struct dn_sch_fq_pie_parms *param;
  868         struct dn_queue *mainq;
  869         struct fq_pie_flow *flows;
  870         int idx, drop, i, maxidx;
  871 
  872         mainq = (struct dn_queue *)(_si + 1);
  873         si = (struct fq_pie_si *)_si;
  874         flows = si->si_extra->flows;
  875         schk = (struct fq_pie_schk *)(si->_si.sched+1);
  876         param = &schk->cfg;
  877 
  878          /* classify a packet to queue number*/
  879         idx = fq_pie_classify_flow(m, param->flows_cnt, si);
  880 
  881         /* enqueue packet into appropriate queue using PIE AQM.
  882          * Note: 'pie_enqueue' function returns 1 only when it unable to 
  883          * add timestamp to packet (no limit check)*/
  884         drop = pie_enqueue(&flows[idx], m, si);
  885 
  886         /* pie unable to timestamp a packet */ 
  887         if (drop)
  888                 return 1;
  889 
  890         /* If the flow (sub-queue) is not active ,then add it to tail of
  891          * new flows list, initialize and activate it.
  892          */
  893         if (!flows[idx].active) {
  894                 STAILQ_INSERT_TAIL(&si->newflows, &flows[idx], flowchain);
  895                 flows[idx].deficit = param->quantum;
  896                 fq_activate_pie(&flows[idx]);
  897                 flows[idx].active = 1;
  898         }
  899 
  900         /* check the limit for all queues and remove a packet from the
  901          * largest one 
  902          */
  903         if (mainq->ni.length > schk->cfg.limit) {
  904                 /* find first active flow */
  905                 for (maxidx = 0; maxidx < schk->cfg.flows_cnt; maxidx++)
  906                         if (flows[maxidx].active)
  907                                 break;
  908                 if (maxidx < schk->cfg.flows_cnt) {
  909                         /* find the largest sub- queue */
  910                         for (i = maxidx + 1; i < schk->cfg.flows_cnt; i++) 
  911                                 if (flows[i].active && flows[i].stats.length >
  912                                         flows[maxidx].stats.length)
  913                                         maxidx = i;
  914                         pie_drop_head(&flows[maxidx], si);
  915                         drop = 1;
  916                 }
  917         }
  918 
  919         return drop;
  920 }
  921 
  922 /*
  923  * Dequeue a packet from an appropriate queue according to
  924  * FQ-CoDel algorithm.
  925  */
  926 static struct mbuf *
  927 fq_pie_dequeue(struct dn_sch_inst *_si)
  928 { 
  929         struct fq_pie_si *si;
  930         struct fq_pie_schk *schk;
  931         struct dn_sch_fq_pie_parms *param;
  932         struct fq_pie_flow *f;
  933         struct mbuf *mbuf;
  934         struct fq_pie_list *fq_pie_flowlist;
  935 
  936         si = (struct fq_pie_si *)_si;
  937         schk = (struct fq_pie_schk *)(si->_si.sched+1);
  938         param = &schk->cfg;
  939 
  940         do {
  941                 /* select a list to start with */
  942                 if (STAILQ_EMPTY(&si->newflows))
  943                         fq_pie_flowlist = &si->oldflows;
  944                 else
  945                         fq_pie_flowlist = &si->newflows;
  946 
  947                 /* Both new and old queue lists are empty, return NULL */
  948                 if (STAILQ_EMPTY(fq_pie_flowlist)) 
  949                         return NULL;
  950 
  951                 f = STAILQ_FIRST(fq_pie_flowlist);
  952                 while (f != NULL)       {
  953                         /* if there is no flow(sub-queue) deficit, increase deficit
  954                          * by quantum, move the flow to the tail of old flows list
  955                          * and try another flow.
  956                          * Otherwise, the flow will be used for dequeue.
  957                          */
  958                         if (f->deficit < 0) {
  959                                  f->deficit += param->quantum;
  960                                  STAILQ_REMOVE_HEAD(fq_pie_flowlist, flowchain);
  961                                  STAILQ_INSERT_TAIL(&si->oldflows, f, flowchain);
  962                          } else 
  963                                  break;
  964 
  965                         f = STAILQ_FIRST(fq_pie_flowlist);
  966                 }
  967                 
  968                 /* the new flows list is empty, try old flows list */
  969                 if (STAILQ_EMPTY(fq_pie_flowlist)) 
  970                         continue;
  971 
  972                 /* Dequeue a packet from the selected flow */
  973                 mbuf = pie_dequeue(f, si);
  974 
  975                 /* pie did not return a packet */
  976                 if (!mbuf) {
  977                         /* If the selected flow belongs to new flows list, then move 
  978                          * it to the tail of old flows list. Otherwise, deactivate it and
  979                          * remove it from the old list and
  980                          */
  981                         if (fq_pie_flowlist == &si->newflows) {
  982                                 STAILQ_REMOVE_HEAD(fq_pie_flowlist, flowchain);
  983                                 STAILQ_INSERT_TAIL(&si->oldflows, f, flowchain);
  984                         }       else {
  985                                 f->active = 0;
  986                                 fq_deactivate_pie(&f->pst);
  987                                 STAILQ_REMOVE_HEAD(fq_pie_flowlist, flowchain);
  988                         }
  989                         /* start again */
  990                         continue;
  991                 }
  992 
  993                 /* we have a packet to return, 
  994                  * update flow deficit and return the packet*/
  995                 f->deficit -= mbuf->m_pkthdr.len;
  996                 return mbuf;
  997 
  998         } while (1);
  999 
 1000         /* unreachable point */
 1001         return NULL;
 1002 }
 1003 
 1004 /*
 1005  * Initialize fq_pie scheduler instance.
 1006  * also, allocate memory for flows array.
 1007  */
 1008 static int
 1009 fq_pie_new_sched(struct dn_sch_inst *_si)
 1010 {
 1011         struct fq_pie_si *si;
 1012         struct dn_queue *q;
 1013         struct fq_pie_schk *schk;
 1014         struct fq_pie_flow *flows;
 1015         int i;
 1016 
 1017         si = (struct fq_pie_si *)_si;
 1018         schk = (struct fq_pie_schk *)(_si->sched+1);
 1019 
 1020         if(si->si_extra) {
 1021                 D("si already configured!");
 1022                 return 0;
 1023         }
 1024 
 1025         /* init the main queue */
 1026         q = &si->main_q;
 1027         set_oid(&q->ni.oid, DN_QUEUE, sizeof(*q));
 1028         q->_si = _si;
 1029         q->fs = _si->sched->fs;
 1030 
 1031         /* allocate memory for scheduler instance extra vars */
 1032         si->si_extra = malloc(sizeof(struct fq_pie_si_extra),
 1033                  M_DUMMYNET, M_NOWAIT | M_ZERO);
 1034         if (si->si_extra == NULL) {
 1035                 D("cannot allocate memory for fq_pie si extra vars");
 1036                 return ENOMEM ; 
 1037         }
 1038         /* allocate memory for flows array */
 1039         si->si_extra->flows = mallocarray(schk->cfg.flows_cnt,
 1040             sizeof(struct fq_pie_flow), M_DUMMYNET, M_NOWAIT | M_ZERO);
 1041         flows = si->si_extra->flows;
 1042         if (flows == NULL) {
 1043                 free(si->si_extra, M_DUMMYNET);
 1044                 si->si_extra = NULL;
 1045                 D("cannot allocate memory for fq_pie flows");
 1046                 return ENOMEM ; 
 1047         }
 1048 
 1049         /* init perturbation for this si */
 1050         si->perturbation = random();
 1051         si->si_extra->nr_active_q = 0;
 1052 
 1053         /* init the old and new flows lists */
 1054         STAILQ_INIT(&si->newflows);
 1055         STAILQ_INIT(&si->oldflows);
 1056 
 1057         /* init the flows (sub-queues) */
 1058         for (i = 0; i < schk->cfg.flows_cnt; i++) {
 1059                 flows[i].pst.parms = &schk->cfg.pcfg;
 1060                 flows[i].psi_extra = si->si_extra;
 1061                 pie_init(&flows[i], schk);
 1062         }
 1063 
 1064         dummynet_sched_lock();
 1065         fq_pie_desc.ref_count++;
 1066         dummynet_sched_unlock();
 1067 
 1068         return 0;
 1069 }
 1070 
 1071 /*
 1072  * Free fq_pie scheduler instance.
 1073  */
 1074 static int
 1075 fq_pie_free_sched(struct dn_sch_inst *_si)
 1076 {
 1077         struct fq_pie_si *si;
 1078         struct fq_pie_schk *schk;
 1079         struct fq_pie_flow *flows;
 1080         int i;
 1081 
 1082         si = (struct fq_pie_si *)_si;
 1083         schk = (struct fq_pie_schk *)(_si->sched+1);
 1084         flows = si->si_extra->flows;
 1085         for (i = 0; i < schk->cfg.flows_cnt; i++) {
 1086                 pie_cleanup(&flows[i]);
 1087         }
 1088         si->si_extra = NULL;
 1089         return 0;
 1090 }
 1091 
 1092 /*
 1093  * Configure FQ-PIE scheduler.
 1094  * the configurations for the scheduler is passed fromipfw  userland.
 1095  */
 1096 static int
 1097 fq_pie_config(struct dn_schk *_schk)
 1098 {
 1099         struct fq_pie_schk *schk;
 1100         struct dn_extra_parms *ep;
 1101         struct dn_sch_fq_pie_parms *fqp_cfg;
 1102 
 1103         schk = (struct fq_pie_schk *)(_schk+1);
 1104         ep = (struct dn_extra_parms *) _schk->cfg;
 1105 
 1106         /* par array contains fq_pie configuration as follow
 1107          * PIE: 0- qdelay_ref,1- tupdate, 2- max_burst
 1108          * 3- max_ecnth, 4- alpha, 5- beta, 6- flags
 1109          * FQ_PIE: 7- quantum, 8- limit, 9- flows
 1110          */
 1111         if (ep && ep->oid.len ==sizeof(*ep) &&
 1112                 ep->oid.subtype == DN_SCH_PARAMS) {
 1113                 fqp_cfg = &schk->cfg;
 1114                 if (ep->par[0] < 0)
 1115                         fqp_cfg->pcfg.qdelay_ref = fq_pie_sysctl.pcfg.qdelay_ref;
 1116                 else
 1117                         fqp_cfg->pcfg.qdelay_ref = ep->par[0];
 1118                 if (ep->par[1] < 0)
 1119                         fqp_cfg->pcfg.tupdate = fq_pie_sysctl.pcfg.tupdate;
 1120                 else
 1121                         fqp_cfg->pcfg.tupdate = ep->par[1];
 1122                 if (ep->par[2] < 0)
 1123                         fqp_cfg->pcfg.max_burst = fq_pie_sysctl.pcfg.max_burst;
 1124                 else
 1125                         fqp_cfg->pcfg.max_burst = ep->par[2];
 1126                 if (ep->par[3] < 0)
 1127                         fqp_cfg->pcfg.max_ecnth = fq_pie_sysctl.pcfg.max_ecnth;
 1128                 else
 1129                         fqp_cfg->pcfg.max_ecnth = ep->par[3];
 1130                 if (ep->par[4] < 0)
 1131                         fqp_cfg->pcfg.alpha = fq_pie_sysctl.pcfg.alpha;
 1132                 else
 1133                         fqp_cfg->pcfg.alpha = ep->par[4];
 1134                 if (ep->par[5] < 0)
 1135                         fqp_cfg->pcfg.beta = fq_pie_sysctl.pcfg.beta;
 1136                 else
 1137                         fqp_cfg->pcfg.beta = ep->par[5];
 1138                 if (ep->par[6] < 0)
 1139                         fqp_cfg->pcfg.flags = 0;
 1140                 else
 1141                         fqp_cfg->pcfg.flags = ep->par[6];
 1142 
 1143                 /* FQ configurations */
 1144                 if (ep->par[7] < 0)
 1145                         fqp_cfg->quantum = fq_pie_sysctl.quantum;
 1146                 else
 1147                         fqp_cfg->quantum = ep->par[7];
 1148                 if (ep->par[8] < 0)
 1149                         fqp_cfg->limit = fq_pie_sysctl.limit;
 1150                 else
 1151                         fqp_cfg->limit = ep->par[8];
 1152                 if (ep->par[9] < 0)
 1153                         fqp_cfg->flows_cnt = fq_pie_sysctl.flows_cnt;
 1154                 else
 1155                         fqp_cfg->flows_cnt = ep->par[9];
 1156 
 1157                 /* Bound the configurations */
 1158                 fqp_cfg->pcfg.qdelay_ref = BOUND_VAR(fqp_cfg->pcfg.qdelay_ref,
 1159                         1, 5 * AQM_TIME_1S);
 1160                 fqp_cfg->pcfg.tupdate = BOUND_VAR(fqp_cfg->pcfg.tupdate,
 1161                         1, 5 * AQM_TIME_1S);
 1162                 fqp_cfg->pcfg.max_burst = BOUND_VAR(fqp_cfg->pcfg.max_burst,
 1163                         0, 5 * AQM_TIME_1S);
 1164                 fqp_cfg->pcfg.max_ecnth = BOUND_VAR(fqp_cfg->pcfg.max_ecnth,
 1165                         0, PIE_SCALE);
 1166                 fqp_cfg->pcfg.alpha = BOUND_VAR(fqp_cfg->pcfg.alpha, 0, 7 * PIE_SCALE);
 1167                 fqp_cfg->pcfg.beta = BOUND_VAR(fqp_cfg->pcfg.beta, 0, 7 * PIE_SCALE);
 1168 
 1169                 fqp_cfg->quantum = BOUND_VAR(fqp_cfg->quantum,1,9000);
 1170                 fqp_cfg->limit= BOUND_VAR(fqp_cfg->limit,1,20480);
 1171                 fqp_cfg->flows_cnt= BOUND_VAR(fqp_cfg->flows_cnt,1,65536);
 1172         }
 1173         else {
 1174                 D("Wrong parameters for fq_pie scheduler");
 1175                 return 1;
 1176         }
 1177 
 1178         return 0;
 1179 }
 1180 
 1181 /*
 1182  * Return FQ-PIE scheduler configurations
 1183  * the configurations for the scheduler is passed to userland.
 1184  */
 1185 static int 
 1186 fq_pie_getconfig (struct dn_schk *_schk, struct dn_extra_parms *ep) {
 1187         struct fq_pie_schk *schk = (struct fq_pie_schk *)(_schk+1);
 1188         struct dn_sch_fq_pie_parms *fqp_cfg;
 1189 
 1190         fqp_cfg = &schk->cfg;
 1191 
 1192         strcpy(ep->name, fq_pie_desc.name);
 1193         ep->par[0] = fqp_cfg->pcfg.qdelay_ref;
 1194         ep->par[1] = fqp_cfg->pcfg.tupdate;
 1195         ep->par[2] = fqp_cfg->pcfg.max_burst;
 1196         ep->par[3] = fqp_cfg->pcfg.max_ecnth;
 1197         ep->par[4] = fqp_cfg->pcfg.alpha;
 1198         ep->par[5] = fqp_cfg->pcfg.beta;
 1199         ep->par[6] = fqp_cfg->pcfg.flags;
 1200 
 1201         ep->par[7] = fqp_cfg->quantum;
 1202         ep->par[8] = fqp_cfg->limit;
 1203         ep->par[9] = fqp_cfg->flows_cnt;
 1204 
 1205         return 0;
 1206 }
 1207 
 1208 /*
 1209  *  FQ-PIE scheduler descriptor
 1210  * contains the type of the scheduler, the name, the size of extra
 1211  * data structures, and function pointers.
 1212  */
 1213 static struct dn_alg fq_pie_desc = {
 1214         _SI( .type = )  DN_SCHED_FQ_PIE,
 1215         _SI( .name = ) "FQ_PIE",
 1216         _SI( .flags = ) 0,
 1217 
 1218         _SI( .schk_datalen = ) sizeof(struct fq_pie_schk),
 1219         _SI( .si_datalen = ) sizeof(struct fq_pie_si) - sizeof(struct dn_sch_inst),
 1220         _SI( .q_datalen = ) 0,
 1221 
 1222         _SI( .enqueue = ) fq_pie_enqueue,
 1223         _SI( .dequeue = ) fq_pie_dequeue,
 1224         _SI( .config = ) fq_pie_config, /* new sched i.e. sched X config ...*/
 1225         _SI( .destroy = ) NULL,  /*sched x delete */
 1226         _SI( .new_sched = ) fq_pie_new_sched, /* new schd instance */
 1227         _SI( .free_sched = ) fq_pie_free_sched, /* delete schd instance */
 1228         _SI( .new_fsk = ) NULL,
 1229         _SI( .free_fsk = ) NULL,
 1230         _SI( .new_queue = ) NULL,
 1231         _SI( .free_queue = ) NULL,
 1232         _SI( .getconfig = )  fq_pie_getconfig,
 1233         _SI( .ref_count = ) 0
 1234 };
 1235 
 1236 DECLARE_DNSCHED_MODULE(dn_fq_pie, &fq_pie_desc);

Cache object: 2bb73b860be73d9d323d5a4a199e99be


[ 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.