191336b40SDon Lewis /* 291336b40SDon Lewis * FQ_PIE - The FlowQueue-PIE scheduler/AQM 391336b40SDon Lewis * 491336b40SDon Lewis * $FreeBSD$ 591336b40SDon Lewis * 691336b40SDon Lewis * Copyright (C) 2016 Centre for Advanced Internet Architectures, 791336b40SDon Lewis * Swinburne University of Technology, Melbourne, Australia. 891336b40SDon Lewis * Portions of this code were made possible in part by a gift from 991336b40SDon Lewis * The Comcast Innovation Fund. 1091336b40SDon Lewis * Implemented by Rasool Al-Saadi <ralsaadi@swin.edu.au> 1191336b40SDon Lewis * 1291336b40SDon Lewis * Redistribution and use in source and binary forms, with or without 1391336b40SDon Lewis * modification, are permitted provided that the following conditions 1491336b40SDon Lewis * are met: 1591336b40SDon Lewis * 1. Redistributions of source code must retain the above copyright 1691336b40SDon Lewis * notice, this list of conditions and the following disclaimer. 1791336b40SDon Lewis * 2. Redistributions in binary form must reproduce the above copyright 1891336b40SDon Lewis * notice, this list of conditions and the following disclaimer in the 1991336b40SDon Lewis * documentation and/or other materials provided with the distribution. 2091336b40SDon Lewis * 2191336b40SDon Lewis * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 2291336b40SDon Lewis * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2391336b40SDon Lewis * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2491336b40SDon Lewis * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2591336b40SDon Lewis * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2691336b40SDon Lewis * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2791336b40SDon Lewis * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2891336b40SDon Lewis * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2991336b40SDon Lewis * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3091336b40SDon Lewis * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3191336b40SDon Lewis * SUCH DAMAGE. 3291336b40SDon Lewis */ 3391336b40SDon Lewis 3491336b40SDon Lewis /* Important note: 3591336b40SDon Lewis * As there is no an office document for FQ-PIE specification, we used 3691336b40SDon Lewis * FQ-CoDel algorithm with some modifications to implement FQ-PIE. 3791336b40SDon Lewis * This FQ-PIE implementation is a beta version and have not been tested 3891336b40SDon Lewis * extensively. Our FQ-PIE uses stand-alone PIE AQM per sub-queue. By 3991336b40SDon Lewis * default, timestamp is used to calculate queue delay instead of departure 4091336b40SDon Lewis * rate estimation method. Although departure rate estimation is available 4191336b40SDon Lewis * as testing option, the results could be incorrect. Moreover, turning PIE on 4291336b40SDon Lewis * and off option is available but it does not work properly in this version. 4391336b40SDon Lewis */ 4491336b40SDon Lewis 4591336b40SDon Lewis #ifdef _KERNEL 4691336b40SDon Lewis #include <sys/malloc.h> 4791336b40SDon Lewis #include <sys/socket.h> 4891336b40SDon Lewis #include <sys/kernel.h> 4991336b40SDon Lewis #include <sys/mbuf.h> 5091336b40SDon Lewis #include <sys/lock.h> 5191336b40SDon Lewis #include <sys/module.h> 5291336b40SDon Lewis #include <sys/mutex.h> 5391336b40SDon Lewis #include <net/if.h> /* IFNAMSIZ */ 5491336b40SDon Lewis #include <netinet/in.h> 5591336b40SDon Lewis #include <netinet/ip_var.h> /* ipfw_rule_ref */ 5691336b40SDon Lewis #include <netinet/ip_fw.h> /* flow_id */ 5791336b40SDon Lewis #include <netinet/ip_dummynet.h> 5891336b40SDon Lewis 5991336b40SDon Lewis #include <sys/proc.h> 6091336b40SDon Lewis #include <sys/rwlock.h> 6191336b40SDon Lewis 6291336b40SDon Lewis #include <netpfil/ipfw/ip_fw_private.h> 6391336b40SDon Lewis #include <sys/sysctl.h> 6491336b40SDon Lewis #include <netinet/ip.h> 6591336b40SDon Lewis #include <netinet/ip6.h> 6691336b40SDon Lewis #include <netinet/ip_icmp.h> 6791336b40SDon Lewis #include <netinet/tcp.h> 6891336b40SDon Lewis #include <netinet/udp.h> 6991336b40SDon Lewis #include <sys/queue.h> 7091336b40SDon Lewis #include <sys/hash.h> 7191336b40SDon Lewis 7291336b40SDon Lewis #include <netpfil/ipfw/dn_heap.h> 7391336b40SDon Lewis #include <netpfil/ipfw/ip_dn_private.h> 7491336b40SDon Lewis 7591336b40SDon Lewis #include <netpfil/ipfw/dn_aqm.h> 7691336b40SDon Lewis #include <netpfil/ipfw/dn_aqm_pie.h> 7791336b40SDon Lewis #include <netpfil/ipfw/dn_sched.h> 7891336b40SDon Lewis 7991336b40SDon Lewis #else 8091336b40SDon Lewis #include <dn_test.h> 8191336b40SDon Lewis #endif 8291336b40SDon Lewis 8391336b40SDon Lewis #define DN_SCHED_FQ_PIE 7 8491336b40SDon Lewis 8591336b40SDon Lewis /* list of queues */ 8691336b40SDon Lewis STAILQ_HEAD(fq_pie_list, fq_pie_flow) ; 8791336b40SDon Lewis 8891336b40SDon Lewis /* FQ_PIE parameters including PIE */ 8991336b40SDon Lewis struct dn_sch_fq_pie_parms { 9091336b40SDon Lewis struct dn_aqm_pie_parms pcfg; /* PIE configuration Parameters */ 9191336b40SDon Lewis /* FQ_PIE Parameters */ 9291336b40SDon Lewis uint32_t flows_cnt; /* number of flows */ 9391336b40SDon Lewis uint32_t limit; /* hard limit of FQ_PIE queue size*/ 9491336b40SDon Lewis uint32_t quantum; 9591336b40SDon Lewis }; 9691336b40SDon Lewis 9791336b40SDon Lewis /* flow (sub-queue) stats */ 9891336b40SDon Lewis struct flow_stats { 9991336b40SDon Lewis uint64_t tot_pkts; /* statistics counters */ 10091336b40SDon Lewis uint64_t tot_bytes; 10191336b40SDon Lewis uint32_t length; /* Queue length, in packets */ 10291336b40SDon Lewis uint32_t len_bytes; /* Queue length, in bytes */ 10391336b40SDon Lewis uint32_t drops; 10491336b40SDon Lewis }; 10591336b40SDon Lewis 10691336b40SDon Lewis /* A flow of packets (sub-queue)*/ 10791336b40SDon Lewis struct fq_pie_flow { 10891336b40SDon Lewis struct mq mq; /* list of packets */ 10991336b40SDon Lewis struct flow_stats stats; /* statistics */ 11091336b40SDon Lewis int deficit; 11191336b40SDon Lewis int active; /* 1: flow is active (in a list) */ 11291336b40SDon Lewis struct pie_status pst; /* pie status variables */ 11398e82c02SDon Lewis struct fq_pie_si_extra *psi_extra; 11491336b40SDon Lewis STAILQ_ENTRY(fq_pie_flow) flowchain; 11591336b40SDon Lewis }; 11691336b40SDon Lewis 11791336b40SDon Lewis /* extra fq_pie scheduler configurations */ 11891336b40SDon Lewis struct fq_pie_schk { 11991336b40SDon Lewis struct dn_sch_fq_pie_parms cfg; 12091336b40SDon Lewis }; 12191336b40SDon Lewis 12298e82c02SDon Lewis /* fq_pie scheduler instance extra state vars. 12398e82c02SDon Lewis * The purpose of separation this structure is to preserve number of active 12498e82c02SDon Lewis * sub-queues and the flows array pointer even after the scheduler instance 12598e82c02SDon Lewis * is destroyed. 12698e82c02SDon Lewis * Preserving these varaiables allows freeing the allocated memory by 12798e82c02SDon Lewis * fqpie_callout_cleanup() independently from fq_pie_free_sched(). 12898e82c02SDon Lewis */ 12998e82c02SDon Lewis struct fq_pie_si_extra { 13098e82c02SDon Lewis uint32_t nr_active_q; /* number of active queues */ 13198e82c02SDon Lewis struct fq_pie_flow *flows; /* array of flows (queues) */ 13298e82c02SDon Lewis }; 13398e82c02SDon Lewis 13491336b40SDon Lewis /* fq_pie scheduler instance */ 13591336b40SDon Lewis struct fq_pie_si { 13698e82c02SDon Lewis struct dn_sch_inst _si; /* standard scheduler instance. SHOULD BE FIRST */ 13791336b40SDon Lewis struct dn_queue main_q; /* main queue is after si directly */ 13891336b40SDon Lewis uint32_t perturbation; /* random value */ 13991336b40SDon Lewis struct fq_pie_list newflows; /* list of new queues */ 14091336b40SDon Lewis struct fq_pie_list oldflows; /* list of old queues */ 14198e82c02SDon Lewis struct fq_pie_si_extra *si_extra; /* extra state vars*/ 14291336b40SDon Lewis }; 14391336b40SDon Lewis 14491336b40SDon Lewis static struct dn_alg fq_pie_desc; 14591336b40SDon Lewis 14691336b40SDon Lewis /* Default FQ-PIE parameters including PIE */ 14791336b40SDon Lewis /* PIE defaults 14891336b40SDon Lewis * target=15ms, max_burst=150ms, max_ecnth=0.1, 14991336b40SDon Lewis * alpha=0.125, beta=1.25, tupdate=15ms 15091336b40SDon Lewis * FQ- 15191336b40SDon Lewis * flows=1024, limit=10240, quantum =1514 15291336b40SDon Lewis */ 15391336b40SDon Lewis struct dn_sch_fq_pie_parms 15491336b40SDon Lewis fq_pie_sysctl = {{15000 * AQM_TIME_1US, 15000 * AQM_TIME_1US, 15591336b40SDon Lewis 150000 * AQM_TIME_1US, PIE_SCALE * 0.1, PIE_SCALE * 0.125, 15691336b40SDon Lewis PIE_SCALE * 1.25, PIE_CAPDROP_ENABLED | PIE_DERAND_ENABLED}, 15791336b40SDon Lewis 1024, 10240, 1514}; 15891336b40SDon Lewis 15991336b40SDon Lewis static int 16091336b40SDon Lewis fqpie_sysctl_alpha_beta_handler(SYSCTL_HANDLER_ARGS) 16191336b40SDon Lewis { 16291336b40SDon Lewis int error; 16391336b40SDon Lewis long value; 16491336b40SDon Lewis 16591336b40SDon Lewis if (!strcmp(oidp->oid_name,"alpha")) 16691336b40SDon Lewis value = fq_pie_sysctl.pcfg.alpha; 16791336b40SDon Lewis else 16891336b40SDon Lewis value = fq_pie_sysctl.pcfg.beta; 16991336b40SDon Lewis 17091336b40SDon Lewis value = value * 1000 / PIE_SCALE; 17191336b40SDon Lewis error = sysctl_handle_long(oidp, &value, 0, req); 17291336b40SDon Lewis if (error != 0 || req->newptr == NULL) 17391336b40SDon Lewis return (error); 17491336b40SDon Lewis if (value < 1 || value > 7 * PIE_SCALE) 17591336b40SDon Lewis return (EINVAL); 17691336b40SDon Lewis value = (value * PIE_SCALE) / 1000; 17791336b40SDon Lewis if (!strcmp(oidp->oid_name,"alpha")) 17891336b40SDon Lewis fq_pie_sysctl.pcfg.alpha = value; 17991336b40SDon Lewis else 18091336b40SDon Lewis fq_pie_sysctl.pcfg.beta = value; 18191336b40SDon Lewis return (0); 18291336b40SDon Lewis } 18391336b40SDon Lewis 18491336b40SDon Lewis static int 18591336b40SDon Lewis fqpie_sysctl_target_tupdate_maxb_handler(SYSCTL_HANDLER_ARGS) 18691336b40SDon Lewis { 18791336b40SDon Lewis int error; 18891336b40SDon Lewis long value; 18991336b40SDon Lewis 19091336b40SDon Lewis if (!strcmp(oidp->oid_name,"target")) 19191336b40SDon Lewis value = fq_pie_sysctl.pcfg.qdelay_ref; 19291336b40SDon Lewis else if (!strcmp(oidp->oid_name,"tupdate")) 19391336b40SDon Lewis value = fq_pie_sysctl.pcfg.tupdate; 19491336b40SDon Lewis else 19591336b40SDon Lewis value = fq_pie_sysctl.pcfg.max_burst; 19691336b40SDon Lewis 19791336b40SDon Lewis value = value / AQM_TIME_1US; 19891336b40SDon Lewis error = sysctl_handle_long(oidp, &value, 0, req); 19991336b40SDon Lewis if (error != 0 || req->newptr == NULL) 20091336b40SDon Lewis return (error); 20191336b40SDon Lewis if (value < 1 || value > 10 * AQM_TIME_1S) 20291336b40SDon Lewis return (EINVAL); 20391336b40SDon Lewis value = value * AQM_TIME_1US; 20491336b40SDon Lewis 20591336b40SDon Lewis if (!strcmp(oidp->oid_name,"target")) 20691336b40SDon Lewis fq_pie_sysctl.pcfg.qdelay_ref = value; 20791336b40SDon Lewis else if (!strcmp(oidp->oid_name,"tupdate")) 20891336b40SDon Lewis fq_pie_sysctl.pcfg.tupdate = value; 20991336b40SDon Lewis else 21091336b40SDon Lewis fq_pie_sysctl.pcfg.max_burst = value; 21191336b40SDon Lewis return (0); 21291336b40SDon Lewis } 21391336b40SDon Lewis 21491336b40SDon Lewis static int 21591336b40SDon Lewis fqpie_sysctl_max_ecnth_handler(SYSCTL_HANDLER_ARGS) 21691336b40SDon Lewis { 21791336b40SDon Lewis int error; 21891336b40SDon Lewis long value; 21991336b40SDon Lewis 22091336b40SDon Lewis value = fq_pie_sysctl.pcfg.max_ecnth; 22191336b40SDon Lewis value = value * 1000 / PIE_SCALE; 22291336b40SDon Lewis error = sysctl_handle_long(oidp, &value, 0, req); 22391336b40SDon Lewis if (error != 0 || req->newptr == NULL) 22491336b40SDon Lewis return (error); 22591336b40SDon Lewis if (value < 1 || value > PIE_SCALE) 22691336b40SDon Lewis return (EINVAL); 22791336b40SDon Lewis value = (value * PIE_SCALE) / 1000; 22891336b40SDon Lewis fq_pie_sysctl.pcfg.max_ecnth = value; 22991336b40SDon Lewis return (0); 23091336b40SDon Lewis } 23191336b40SDon Lewis 23291336b40SDon Lewis /* define FQ- PIE sysctl variables */ 23391336b40SDon Lewis SYSBEGIN(f4) 23491336b40SDon Lewis SYSCTL_DECL(_net_inet); 23591336b40SDon Lewis SYSCTL_DECL(_net_inet_ip); 23691336b40SDon Lewis SYSCTL_DECL(_net_inet_ip_dummynet); 23791336b40SDon Lewis static SYSCTL_NODE(_net_inet_ip_dummynet, OID_AUTO, fqpie, 2387029da5cSPawel Biernacki CTLFLAG_RW | CTLFLAG_MPSAFE, 0, 2397029da5cSPawel Biernacki "FQ_PIE"); 24091336b40SDon Lewis 24191336b40SDon Lewis #ifdef SYSCTL_NODE 24291336b40SDon Lewis 24391336b40SDon Lewis SYSCTL_PROC(_net_inet_ip_dummynet_fqpie, OID_AUTO, target, 2447029da5cSPawel Biernacki CTLTYPE_LONG | CTLFLAG_RW | CTLFLAG_NEEDGIANT, NULL, 0, 24591336b40SDon Lewis fqpie_sysctl_target_tupdate_maxb_handler, "L", 24691336b40SDon Lewis "queue target in microsecond"); 24791336b40SDon Lewis 24891336b40SDon Lewis SYSCTL_PROC(_net_inet_ip_dummynet_fqpie, OID_AUTO, tupdate, 2497029da5cSPawel Biernacki CTLTYPE_LONG | CTLFLAG_RW | CTLFLAG_NEEDGIANT, NULL, 0, 25091336b40SDon Lewis fqpie_sysctl_target_tupdate_maxb_handler, "L", 25191336b40SDon Lewis "the frequency of drop probability calculation in microsecond"); 25291336b40SDon Lewis 25391336b40SDon Lewis SYSCTL_PROC(_net_inet_ip_dummynet_fqpie, OID_AUTO, max_burst, 2547029da5cSPawel Biernacki CTLTYPE_LONG | CTLFLAG_RW | CTLFLAG_NEEDGIANT, NULL, 0, 25591336b40SDon Lewis fqpie_sysctl_target_tupdate_maxb_handler, "L", 25691336b40SDon Lewis "Burst allowance interval in microsecond"); 25791336b40SDon Lewis 25891336b40SDon Lewis SYSCTL_PROC(_net_inet_ip_dummynet_fqpie, OID_AUTO, max_ecnth, 2597029da5cSPawel Biernacki CTLTYPE_LONG | CTLFLAG_RW | CTLFLAG_NEEDGIANT, NULL, 0, 26091336b40SDon Lewis fqpie_sysctl_max_ecnth_handler, "L", 26191336b40SDon Lewis "ECN safeguard threshold scaled by 1000"); 26291336b40SDon Lewis 26391336b40SDon Lewis SYSCTL_PROC(_net_inet_ip_dummynet_fqpie, OID_AUTO, alpha, 2647029da5cSPawel Biernacki CTLTYPE_LONG | CTLFLAG_RW | CTLFLAG_NEEDGIANT, NULL, 0, 2657029da5cSPawel Biernacki fqpie_sysctl_alpha_beta_handler, "L", 2667029da5cSPawel Biernacki "PIE alpha scaled by 1000"); 26791336b40SDon Lewis 26891336b40SDon Lewis SYSCTL_PROC(_net_inet_ip_dummynet_fqpie, OID_AUTO, beta, 2697029da5cSPawel Biernacki CTLTYPE_LONG | CTLFLAG_RW | CTLFLAG_NEEDGIANT, NULL, 0, 2707029da5cSPawel Biernacki fqpie_sysctl_alpha_beta_handler, "L", 2717029da5cSPawel Biernacki "beta scaled by 1000"); 27291336b40SDon Lewis 27391336b40SDon Lewis SYSCTL_UINT(_net_inet_ip_dummynet_fqpie, OID_AUTO, quantum, 27491336b40SDon Lewis CTLFLAG_RW, &fq_pie_sysctl.quantum, 1514, "quantum for FQ_PIE"); 27591336b40SDon Lewis SYSCTL_UINT(_net_inet_ip_dummynet_fqpie, OID_AUTO, flows, 27691336b40SDon Lewis CTLFLAG_RW, &fq_pie_sysctl.flows_cnt, 1024, "Number of queues for FQ_PIE"); 27791336b40SDon Lewis SYSCTL_UINT(_net_inet_ip_dummynet_fqpie, OID_AUTO, limit, 27891336b40SDon Lewis CTLFLAG_RW, &fq_pie_sysctl.limit, 10240, "limit for FQ_PIE"); 27991336b40SDon Lewis #endif 28091336b40SDon Lewis 28191336b40SDon Lewis /* Helper function to update queue&main-queue and scheduler statistics. 28291336b40SDon Lewis * negative len & drop -> drop 28391336b40SDon Lewis * negative len -> dequeue 28491336b40SDon Lewis * positive len -> enqueue 28591336b40SDon Lewis * positive len + drop -> drop during enqueue 28691336b40SDon Lewis */ 28791336b40SDon Lewis __inline static void 28891336b40SDon Lewis fq_update_stats(struct fq_pie_flow *q, struct fq_pie_si *si, int len, 28991336b40SDon Lewis int drop) 29091336b40SDon Lewis { 29191336b40SDon Lewis int inc = 0; 29291336b40SDon Lewis 29391336b40SDon Lewis if (len < 0) 29491336b40SDon Lewis inc = -1; 29591336b40SDon Lewis else if (len > 0) 29691336b40SDon Lewis inc = 1; 29791336b40SDon Lewis 29891336b40SDon Lewis if (drop) { 29991336b40SDon Lewis si->main_q.ni.drops ++; 30091336b40SDon Lewis q->stats.drops ++; 30191336b40SDon Lewis si->_si.ni.drops ++; 302cd5671efSKristof Provost dn_cfg.io_pkt_drop ++; 30391336b40SDon Lewis } 30491336b40SDon Lewis 30591336b40SDon Lewis if (!drop || (drop && len < 0)) { 30691336b40SDon Lewis /* Update stats for the main queue */ 30791336b40SDon Lewis si->main_q.ni.length += inc; 30891336b40SDon Lewis si->main_q.ni.len_bytes += len; 30991336b40SDon Lewis 31091336b40SDon Lewis /*update sub-queue stats */ 31191336b40SDon Lewis q->stats.length += inc; 31291336b40SDon Lewis q->stats.len_bytes += len; 31391336b40SDon Lewis 31491336b40SDon Lewis /*update scheduler instance stats */ 31591336b40SDon Lewis si->_si.ni.length += inc; 31691336b40SDon Lewis si->_si.ni.len_bytes += len; 31791336b40SDon Lewis } 31891336b40SDon Lewis 31991336b40SDon Lewis if (inc > 0) { 32091336b40SDon Lewis si->main_q.ni.tot_bytes += len; 32191336b40SDon Lewis si->main_q.ni.tot_pkts ++; 32291336b40SDon Lewis 32391336b40SDon Lewis q->stats.tot_bytes +=len; 32491336b40SDon Lewis q->stats.tot_pkts++; 32591336b40SDon Lewis 32691336b40SDon Lewis si->_si.ni.tot_bytes +=len; 32791336b40SDon Lewis si->_si.ni.tot_pkts ++; 32891336b40SDon Lewis } 32991336b40SDon Lewis 33091336b40SDon Lewis } 33191336b40SDon Lewis 33291336b40SDon Lewis /* 33391336b40SDon Lewis * Extract a packet from the head of sub-queue 'q' 33491336b40SDon Lewis * Return a packet or NULL if the queue is empty. 33591336b40SDon Lewis * If getts is set, also extract packet's timestamp from mtag. 33691336b40SDon Lewis */ 33791336b40SDon Lewis __inline static struct mbuf * 33891336b40SDon Lewis fq_pie_extract_head(struct fq_pie_flow *q, aqm_time_t *pkt_ts, 33991336b40SDon Lewis struct fq_pie_si *si, int getts) 34091336b40SDon Lewis { 34191336b40SDon Lewis struct mbuf *m = q->mq.head; 34291336b40SDon Lewis 34391336b40SDon Lewis if (m == NULL) 34491336b40SDon Lewis return m; 34591336b40SDon Lewis q->mq.head = m->m_nextpkt; 34691336b40SDon Lewis 34791336b40SDon Lewis fq_update_stats(q, si, -m->m_pkthdr.len, 0); 34891336b40SDon Lewis 34991336b40SDon Lewis if (si->main_q.ni.length == 0) /* queue is now idle */ 35091336b40SDon Lewis si->main_q.q_time = dn_cfg.curr_time; 35191336b40SDon Lewis 35291336b40SDon Lewis if (getts) { 35391336b40SDon Lewis /* extract packet timestamp*/ 35491336b40SDon Lewis struct m_tag *mtag; 35591336b40SDon Lewis mtag = m_tag_locate(m, MTAG_ABI_COMPAT, DN_AQM_MTAG_TS, NULL); 35691336b40SDon Lewis if (mtag == NULL){ 35791336b40SDon Lewis D("PIE timestamp mtag not found!"); 35891336b40SDon Lewis *pkt_ts = 0; 35991336b40SDon Lewis } else { 36091336b40SDon Lewis *pkt_ts = *(aqm_time_t *)(mtag + 1); 36191336b40SDon Lewis m_tag_delete(m,mtag); 36291336b40SDon Lewis } 36391336b40SDon Lewis } 36491336b40SDon Lewis return m; 36591336b40SDon Lewis } 36691336b40SDon Lewis 36791336b40SDon Lewis /* 36891336b40SDon Lewis * Callout function for drop probability calculation 36991336b40SDon Lewis * This function is called over tupdate ms and takes pointer of FQ-PIE 37091336b40SDon Lewis * flow as an argument 37191336b40SDon Lewis */ 37291336b40SDon Lewis static void 37391336b40SDon Lewis fq_calculate_drop_prob(void *x) 37491336b40SDon Lewis { 37591336b40SDon Lewis struct fq_pie_flow *q = (struct fq_pie_flow *) x; 37691336b40SDon Lewis struct pie_status *pst = &q->pst; 37791336b40SDon Lewis struct dn_aqm_pie_parms *pprms; 37891336b40SDon Lewis int64_t p, prob, oldprob; 37991336b40SDon Lewis aqm_time_t now; 38036fb8be6SDon Lewis int p_isneg; 38191336b40SDon Lewis 38291336b40SDon Lewis now = AQM_UNOW; 38391336b40SDon Lewis pprms = pst->parms; 38491336b40SDon Lewis prob = pst->drop_prob; 38591336b40SDon Lewis 386d196c9eeSDon Lewis /* calculate current qdelay using DRE method. 387d196c9eeSDon Lewis * If TS is used and no data in the queue, reset current_qdelay 388d196c9eeSDon Lewis * as it stays at last value during dequeue process. 389d196c9eeSDon Lewis */ 390d196c9eeSDon Lewis if (pprms->flags & PIE_DEPRATEEST_ENABLED) 39191336b40SDon Lewis pst->current_qdelay = ((uint64_t)q->stats.len_bytes * pst->avg_dq_time) 39291336b40SDon Lewis >> PIE_DQ_THRESHOLD_BITS; 393d196c9eeSDon Lewis else 394d196c9eeSDon Lewis if (!q->stats.len_bytes) 395d196c9eeSDon Lewis pst->current_qdelay = 0; 39691336b40SDon Lewis 39791336b40SDon Lewis /* calculate drop probability */ 39891336b40SDon Lewis p = (int64_t)pprms->alpha * 39991336b40SDon Lewis ((int64_t)pst->current_qdelay - (int64_t)pprms->qdelay_ref); 40091336b40SDon Lewis p +=(int64_t) pprms->beta * 40191336b40SDon Lewis ((int64_t)pst->current_qdelay - (int64_t)pst->qdelay_old); 40291336b40SDon Lewis 40336fb8be6SDon Lewis /* take absolute value so right shift result is well defined */ 40436fb8be6SDon Lewis p_isneg = p < 0; 40536fb8be6SDon Lewis if (p_isneg) { 40636fb8be6SDon Lewis p = -p; 40736fb8be6SDon Lewis } 40836fb8be6SDon Lewis 40991336b40SDon Lewis /* We PIE_MAX_PROB shift by 12-bits to increase the division precision */ 41091336b40SDon Lewis p *= (PIE_MAX_PROB << 12) / AQM_TIME_1S; 41191336b40SDon Lewis 41291336b40SDon Lewis /* auto-tune drop probability */ 413d6736547SDon Lewis if (prob < (PIE_MAX_PROB / 1000000)) /* 0.000001 */ 41491336b40SDon Lewis p >>= 11 + PIE_FIX_POINT_BITS + 12; 415d6736547SDon Lewis else if (prob < (PIE_MAX_PROB / 100000)) /* 0.00001 */ 41691336b40SDon Lewis p >>= 9 + PIE_FIX_POINT_BITS + 12; 417d6736547SDon Lewis else if (prob < (PIE_MAX_PROB / 10000)) /* 0.0001 */ 41891336b40SDon Lewis p >>= 7 + PIE_FIX_POINT_BITS + 12; 419d6736547SDon Lewis else if (prob < (PIE_MAX_PROB / 1000)) /* 0.001 */ 42091336b40SDon Lewis p >>= 5 + PIE_FIX_POINT_BITS + 12; 421d6736547SDon Lewis else if (prob < (PIE_MAX_PROB / 100)) /* 0.01 */ 42291336b40SDon Lewis p >>= 3 + PIE_FIX_POINT_BITS + 12; 423d6736547SDon Lewis else if (prob < (PIE_MAX_PROB / 10)) /* 0.1 */ 42491336b40SDon Lewis p >>= 1 + PIE_FIX_POINT_BITS + 12; 42591336b40SDon Lewis else 42691336b40SDon Lewis p >>= PIE_FIX_POINT_BITS + 12; 42791336b40SDon Lewis 42891336b40SDon Lewis oldprob = prob; 42991336b40SDon Lewis 43036fb8be6SDon Lewis if (p_isneg) { 43136fb8be6SDon Lewis prob = prob - p; 43236fb8be6SDon Lewis 43336fb8be6SDon Lewis /* check for multiplication underflow */ 43436fb8be6SDon Lewis if (prob > oldprob) { 43536fb8be6SDon Lewis prob= 0; 43636fb8be6SDon Lewis D("underflow"); 43736fb8be6SDon Lewis } 43836fb8be6SDon Lewis } else { 43991336b40SDon Lewis /* Cap Drop adjustment */ 44036fb8be6SDon Lewis if ((pprms->flags & PIE_CAPDROP_ENABLED) && 44136fb8be6SDon Lewis prob >= PIE_MAX_PROB / 10 && 44236fb8be6SDon Lewis p > PIE_MAX_PROB / 50 ) { 44391336b40SDon Lewis p = PIE_MAX_PROB / 50; 44436fb8be6SDon Lewis } 44591336b40SDon Lewis 44691336b40SDon Lewis prob = prob + p; 44791336b40SDon Lewis 44836fb8be6SDon Lewis /* check for multiplication overflow */ 44991336b40SDon Lewis if (prob<oldprob) { 45091336b40SDon Lewis D("overflow"); 45191336b40SDon Lewis prob= PIE_MAX_PROB; 45291336b40SDon Lewis } 45391336b40SDon Lewis } 45436fb8be6SDon Lewis 45536fb8be6SDon Lewis /* 45636fb8be6SDon Lewis * decay the drop probability exponentially 45736fb8be6SDon Lewis * and restrict it to range 0 to PIE_MAX_PROB 45836fb8be6SDon Lewis */ 45936fb8be6SDon Lewis if (prob < 0) { 46091336b40SDon Lewis prob = 0; 46136fb8be6SDon Lewis } else { 46236fb8be6SDon Lewis if (pst->current_qdelay == 0 && pst->qdelay_old == 0) { 46336fb8be6SDon Lewis /* 0.98 ~= 1- 1/64 */ 46436fb8be6SDon Lewis prob = prob - (prob >> 6); 46591336b40SDon Lewis } 46691336b40SDon Lewis 46736fb8be6SDon Lewis if (prob > PIE_MAX_PROB) { 46891336b40SDon Lewis prob = PIE_MAX_PROB; 46936fb8be6SDon Lewis } 47036fb8be6SDon Lewis } 47191336b40SDon Lewis 47291336b40SDon Lewis pst->drop_prob = prob; 47391336b40SDon Lewis 47491336b40SDon Lewis /* store current delay value */ 47591336b40SDon Lewis pst->qdelay_old = pst->current_qdelay; 47691336b40SDon Lewis 47791336b40SDon Lewis /* update burst allowance */ 47891336b40SDon Lewis if ((pst->sflags & PIE_ACTIVE) && pst->burst_allowance) { 47991336b40SDon Lewis if (pst->burst_allowance > pprms->tupdate) 48091336b40SDon Lewis pst->burst_allowance -= pprms->tupdate; 48191336b40SDon Lewis else 48291336b40SDon Lewis pst->burst_allowance = 0; 48391336b40SDon Lewis } 48491336b40SDon Lewis 48591336b40SDon Lewis if (pst->sflags & PIE_ACTIVE) 48691336b40SDon Lewis callout_reset_sbt(&pst->aqm_pie_callout, 48791336b40SDon Lewis (uint64_t)pprms->tupdate * SBT_1US, 48891336b40SDon Lewis 0, fq_calculate_drop_prob, q, 0); 48991336b40SDon Lewis 49091336b40SDon Lewis mtx_unlock(&pst->lock_mtx); 49191336b40SDon Lewis } 49291336b40SDon Lewis 49391336b40SDon Lewis /* 49491336b40SDon Lewis * Reset PIE variables & activate the queue 49591336b40SDon Lewis */ 49691336b40SDon Lewis __inline static void 49791336b40SDon Lewis fq_activate_pie(struct fq_pie_flow *q) 49891336b40SDon Lewis { 49991336b40SDon Lewis struct pie_status *pst = &q->pst; 50091336b40SDon Lewis struct dn_aqm_pie_parms *pprms; 50191336b40SDon Lewis 50291336b40SDon Lewis mtx_lock(&pst->lock_mtx); 50391336b40SDon Lewis pprms = pst->parms; 50491336b40SDon Lewis 50591336b40SDon Lewis pprms = pst->parms; 50691336b40SDon Lewis pst->drop_prob = 0; 50791336b40SDon Lewis pst->qdelay_old = 0; 50891336b40SDon Lewis pst->burst_allowance = pprms->max_burst; 50991336b40SDon Lewis pst->accu_prob = 0; 51091336b40SDon Lewis pst->dq_count = 0; 51191336b40SDon Lewis pst->avg_dq_time = 0; 51291336b40SDon Lewis pst->sflags = PIE_INMEASUREMENT | PIE_ACTIVE; 51391336b40SDon Lewis pst->measurement_start = AQM_UNOW; 51491336b40SDon Lewis 51591336b40SDon Lewis callout_reset_sbt(&pst->aqm_pie_callout, 51691336b40SDon Lewis (uint64_t)pprms->tupdate * SBT_1US, 51791336b40SDon Lewis 0, fq_calculate_drop_prob, q, 0); 51891336b40SDon Lewis 51991336b40SDon Lewis mtx_unlock(&pst->lock_mtx); 52091336b40SDon Lewis } 52191336b40SDon Lewis 52291336b40SDon Lewis /* 52391336b40SDon Lewis * Deactivate PIE and stop probe update callout 52491336b40SDon Lewis */ 52591336b40SDon Lewis __inline static void 52691336b40SDon Lewis fq_deactivate_pie(struct pie_status *pst) 52791336b40SDon Lewis { 52891336b40SDon Lewis mtx_lock(&pst->lock_mtx); 52991336b40SDon Lewis pst->sflags &= ~(PIE_ACTIVE | PIE_INMEASUREMENT); 53091336b40SDon Lewis callout_stop(&pst->aqm_pie_callout); 53191336b40SDon Lewis //D("PIE Deactivated"); 53291336b40SDon Lewis mtx_unlock(&pst->lock_mtx); 53391336b40SDon Lewis } 53491336b40SDon Lewis 53591336b40SDon Lewis /* 53691336b40SDon Lewis * Initialize PIE for sub-queue 'q' 53791336b40SDon Lewis */ 53891336b40SDon Lewis static int 53998e82c02SDon Lewis pie_init(struct fq_pie_flow *q, struct fq_pie_schk *fqpie_schk) 54091336b40SDon Lewis { 54191336b40SDon Lewis struct pie_status *pst=&q->pst; 54291336b40SDon Lewis struct dn_aqm_pie_parms *pprms = pst->parms; 54391336b40SDon Lewis 54491336b40SDon Lewis int err = 0; 54591336b40SDon Lewis if (!pprms){ 54691336b40SDon Lewis D("AQM_PIE is not configured"); 54791336b40SDon Lewis err = EINVAL; 54891336b40SDon Lewis } else { 54998e82c02SDon Lewis q->psi_extra->nr_active_q++; 55091336b40SDon Lewis 55191336b40SDon Lewis /* For speed optimization, we caculate 1/3 queue size once here */ 55291336b40SDon Lewis // XXX limit divided by number of queues divided by 3 ??? 55391336b40SDon Lewis pst->one_third_q_size = (fqpie_schk->cfg.limit / 55491336b40SDon Lewis fqpie_schk->cfg.flows_cnt) / 3; 55591336b40SDon Lewis 55691336b40SDon Lewis mtx_init(&pst->lock_mtx, "mtx_pie", NULL, MTX_DEF); 55791336b40SDon Lewis callout_init_mtx(&pst->aqm_pie_callout, &pst->lock_mtx, 55891336b40SDon Lewis CALLOUT_RETURNUNLOCKED); 55991336b40SDon Lewis } 56091336b40SDon Lewis 56191336b40SDon Lewis return err; 56291336b40SDon Lewis } 56391336b40SDon Lewis 56491336b40SDon Lewis /* 56598e82c02SDon Lewis * callout function to destroy PIE lock, and free fq_pie flows and fq_pie si 56698e82c02SDon Lewis * extra memory when number of active sub-queues reaches zero. 56798e82c02SDon Lewis * 'x' is a fq_pie_flow to be destroyed 56898e82c02SDon Lewis */ 56998e82c02SDon Lewis static void 57098e82c02SDon Lewis fqpie_callout_cleanup(void *x) 57198e82c02SDon Lewis { 57298e82c02SDon Lewis struct fq_pie_flow *q = x; 57398e82c02SDon Lewis struct pie_status *pst = &q->pst; 57498e82c02SDon Lewis struct fq_pie_si_extra *psi_extra; 57598e82c02SDon Lewis 57698e82c02SDon Lewis mtx_unlock(&pst->lock_mtx); 57798e82c02SDon Lewis mtx_destroy(&pst->lock_mtx); 57898e82c02SDon Lewis psi_extra = q->psi_extra; 57998e82c02SDon Lewis 58098e82c02SDon Lewis DN_BH_WLOCK(); 58198e82c02SDon Lewis psi_extra->nr_active_q--; 58298e82c02SDon Lewis 58398e82c02SDon Lewis /* when all sub-queues are destroyed, free flows fq_pie extra vars memory */ 58498e82c02SDon Lewis if (!psi_extra->nr_active_q) { 58598e82c02SDon Lewis free(psi_extra->flows, M_DUMMYNET); 58698e82c02SDon Lewis free(psi_extra, M_DUMMYNET); 58798e82c02SDon Lewis fq_pie_desc.ref_count--; 58898e82c02SDon Lewis } 58998e82c02SDon Lewis DN_BH_WUNLOCK(); 59098e82c02SDon Lewis } 59198e82c02SDon Lewis 59298e82c02SDon Lewis /* 59391336b40SDon Lewis * Clean up PIE status for sub-queue 'q' 59498e82c02SDon Lewis * Stop callout timer and destroy mtx using fqpie_callout_cleanup() callout. 59591336b40SDon Lewis */ 59691336b40SDon Lewis static int 59791336b40SDon Lewis pie_cleanup(struct fq_pie_flow *q) 59891336b40SDon Lewis { 59991336b40SDon Lewis struct pie_status *pst = &q->pst; 60091336b40SDon Lewis 60191336b40SDon Lewis mtx_lock(&pst->lock_mtx); 60298e82c02SDon Lewis callout_reset_sbt(&pst->aqm_pie_callout, 60398e82c02SDon Lewis SBT_1US, 0, fqpie_callout_cleanup, q, 0); 60491336b40SDon Lewis mtx_unlock(&pst->lock_mtx); 60591336b40SDon Lewis return 0; 60691336b40SDon Lewis } 60791336b40SDon Lewis 60891336b40SDon Lewis /* 60991336b40SDon Lewis * Dequeue and return a pcaket from sub-queue 'q' or NULL if 'q' is empty. 61091336b40SDon Lewis * Also, caculate depature time or queue delay using timestamp 61191336b40SDon Lewis */ 61291336b40SDon Lewis static struct mbuf * 61391336b40SDon Lewis pie_dequeue(struct fq_pie_flow *q, struct fq_pie_si *si) 61491336b40SDon Lewis { 61591336b40SDon Lewis struct mbuf *m; 61691336b40SDon Lewis struct dn_aqm_pie_parms *pprms; 61791336b40SDon Lewis struct pie_status *pst; 61891336b40SDon Lewis aqm_time_t now; 61991336b40SDon Lewis aqm_time_t pkt_ts, dq_time; 62091336b40SDon Lewis int32_t w; 62191336b40SDon Lewis 62291336b40SDon Lewis pst = &q->pst; 62391336b40SDon Lewis pprms = q->pst.parms; 62491336b40SDon Lewis 62591336b40SDon Lewis /*we extarct packet ts only when Departure Rate Estimation dis not used*/ 62691336b40SDon Lewis m = fq_pie_extract_head(q, &pkt_ts, si, 62791336b40SDon Lewis !(pprms->flags & PIE_DEPRATEEST_ENABLED)); 62891336b40SDon Lewis 62991336b40SDon Lewis if (!m || !(pst->sflags & PIE_ACTIVE)) 63091336b40SDon Lewis return m; 63191336b40SDon Lewis 63291336b40SDon Lewis now = AQM_UNOW; 63391336b40SDon Lewis if (pprms->flags & PIE_DEPRATEEST_ENABLED) { 63491336b40SDon Lewis /* calculate average depature time */ 63591336b40SDon Lewis if(pst->sflags & PIE_INMEASUREMENT) { 63691336b40SDon Lewis pst->dq_count += m->m_pkthdr.len; 63791336b40SDon Lewis 63891336b40SDon Lewis if (pst->dq_count >= PIE_DQ_THRESHOLD) { 63991336b40SDon Lewis dq_time = now - pst->measurement_start; 64091336b40SDon Lewis 64191336b40SDon Lewis /* 64291336b40SDon Lewis * if we don't have old avg dq_time i.e PIE is (re)initialized, 64391336b40SDon Lewis * don't use weight to calculate new avg_dq_time 64491336b40SDon Lewis */ 64591336b40SDon Lewis if(pst->avg_dq_time == 0) 64691336b40SDon Lewis pst->avg_dq_time = dq_time; 64791336b40SDon Lewis else { 64891336b40SDon Lewis /* 64991336b40SDon Lewis * weight = PIE_DQ_THRESHOLD/2^6, but we scaled 65091336b40SDon Lewis * weight by 2^8. Thus, scaled 65191336b40SDon Lewis * weight = PIE_DQ_THRESHOLD /2^8 65291336b40SDon Lewis * */ 65391336b40SDon Lewis w = PIE_DQ_THRESHOLD >> 8; 65491336b40SDon Lewis pst->avg_dq_time = (dq_time* w 65591336b40SDon Lewis + (pst->avg_dq_time * ((1L << 8) - w))) >> 8; 65691336b40SDon Lewis pst->sflags &= ~PIE_INMEASUREMENT; 65791336b40SDon Lewis } 65891336b40SDon Lewis } 65991336b40SDon Lewis } 66091336b40SDon Lewis 66191336b40SDon Lewis /* 66291336b40SDon Lewis * Start new measurment cycle when the queue has 66391336b40SDon Lewis * PIE_DQ_THRESHOLD worth of bytes. 66491336b40SDon Lewis */ 66591336b40SDon Lewis if(!(pst->sflags & PIE_INMEASUREMENT) && 66691336b40SDon Lewis q->stats.len_bytes >= PIE_DQ_THRESHOLD) { 66791336b40SDon Lewis pst->sflags |= PIE_INMEASUREMENT; 66891336b40SDon Lewis pst->measurement_start = now; 66991336b40SDon Lewis pst->dq_count = 0; 67091336b40SDon Lewis } 67191336b40SDon Lewis } 67291336b40SDon Lewis /* Optionally, use packet timestamp to estimate queue delay */ 67391336b40SDon Lewis else 67491336b40SDon Lewis pst->current_qdelay = now - pkt_ts; 67591336b40SDon Lewis 67691336b40SDon Lewis return m; 67791336b40SDon Lewis } 67891336b40SDon Lewis 67991336b40SDon Lewis /* 68091336b40SDon Lewis * Enqueue a packet in q, subject to space and FQ-PIE queue management policy 68191336b40SDon Lewis * (whose parameters are in q->fs). 68291336b40SDon Lewis * Update stats for the queue and the scheduler. 68391336b40SDon Lewis * Return 0 on success, 1 on drop. The packet is consumed anyways. 68491336b40SDon Lewis */ 68591336b40SDon Lewis static int 68691336b40SDon Lewis pie_enqueue(struct fq_pie_flow *q, struct mbuf* m, struct fq_pie_si *si) 68791336b40SDon Lewis { 68891336b40SDon Lewis uint64_t len; 68991336b40SDon Lewis struct pie_status *pst; 69091336b40SDon Lewis struct dn_aqm_pie_parms *pprms; 69191336b40SDon Lewis int t; 69291336b40SDon Lewis 69391336b40SDon Lewis len = m->m_pkthdr.len; 69491336b40SDon Lewis pst = &q->pst; 69591336b40SDon Lewis pprms = pst->parms; 69691336b40SDon Lewis t = ENQUE; 69791336b40SDon Lewis 69891336b40SDon Lewis /* drop/mark the packet when PIE is active and burst time elapsed */ 69991336b40SDon Lewis if (pst->sflags & PIE_ACTIVE && pst->burst_allowance == 0 70091336b40SDon Lewis && drop_early(pst, q->stats.len_bytes) == DROP) { 70191336b40SDon Lewis /* 70291336b40SDon Lewis * if drop_prob over ECN threshold, drop the packet 70391336b40SDon Lewis * otherwise mark and enqueue it. 70491336b40SDon Lewis */ 70591336b40SDon Lewis if (pprms->flags & PIE_ECN_ENABLED && pst->drop_prob < 70691336b40SDon Lewis (pprms->max_ecnth << (PIE_PROB_BITS - PIE_FIX_POINT_BITS)) 70791336b40SDon Lewis && ecn_mark(m)) 70891336b40SDon Lewis t = ENQUE; 70991336b40SDon Lewis else 71091336b40SDon Lewis t = DROP; 71191336b40SDon Lewis } 71291336b40SDon Lewis 71391336b40SDon Lewis /* Turn PIE on when 1/3 of the queue is full */ 71491336b40SDon Lewis if (!(pst->sflags & PIE_ACTIVE) && q->stats.len_bytes >= 71591336b40SDon Lewis pst->one_third_q_size) { 71691336b40SDon Lewis fq_activate_pie(q); 71791336b40SDon Lewis } 71891336b40SDon Lewis 71991336b40SDon Lewis /* reset burst tolerance and optinally turn PIE off*/ 72091336b40SDon Lewis if (pst->drop_prob == 0 && pst->current_qdelay < (pprms->qdelay_ref >> 1) 72191336b40SDon Lewis && pst->qdelay_old < (pprms->qdelay_ref >> 1)) { 72291336b40SDon Lewis 72391336b40SDon Lewis pst->burst_allowance = pprms->max_burst; 72491336b40SDon Lewis if (pprms->flags & PIE_ON_OFF_MODE_ENABLED && q->stats.len_bytes<=0) 72591336b40SDon Lewis fq_deactivate_pie(pst); 72691336b40SDon Lewis } 72791336b40SDon Lewis 72891336b40SDon Lewis /* Use timestamp if Departure Rate Estimation mode is disabled */ 72991336b40SDon Lewis if (t != DROP && !(pprms->flags & PIE_DEPRATEEST_ENABLED)) { 73091336b40SDon Lewis /* Add TS to mbuf as a TAG */ 73191336b40SDon Lewis struct m_tag *mtag; 73291336b40SDon Lewis mtag = m_tag_locate(m, MTAG_ABI_COMPAT, DN_AQM_MTAG_TS, NULL); 73391336b40SDon Lewis if (mtag == NULL) 73491336b40SDon Lewis mtag = m_tag_alloc(MTAG_ABI_COMPAT, DN_AQM_MTAG_TS, 73591336b40SDon Lewis sizeof(aqm_time_t), M_NOWAIT); 73691336b40SDon Lewis if (mtag == NULL) { 73791336b40SDon Lewis t = DROP; 738*c4a6258dSMark Johnston } else { 73991336b40SDon Lewis *(aqm_time_t *)(mtag + 1) = AQM_UNOW; 74091336b40SDon Lewis m_tag_prepend(m, mtag); 74191336b40SDon Lewis } 742*c4a6258dSMark Johnston } 74391336b40SDon Lewis 74491336b40SDon Lewis if (t != DROP) { 74591336b40SDon Lewis mq_append(&q->mq, m); 74691336b40SDon Lewis fq_update_stats(q, si, len, 0); 74791336b40SDon Lewis return 0; 74891336b40SDon Lewis } else { 74991336b40SDon Lewis fq_update_stats(q, si, len, 1); 75091336b40SDon Lewis pst->accu_prob = 0; 75191336b40SDon Lewis FREE_PKT(m); 75291336b40SDon Lewis return 1; 75391336b40SDon Lewis } 75491336b40SDon Lewis 75591336b40SDon Lewis return 0; 75691336b40SDon Lewis } 75791336b40SDon Lewis 75891336b40SDon Lewis /* Drop a packet form the head of FQ-PIE sub-queue */ 75991336b40SDon Lewis static void 76091336b40SDon Lewis pie_drop_head(struct fq_pie_flow *q, struct fq_pie_si *si) 76191336b40SDon Lewis { 76291336b40SDon Lewis struct mbuf *m = q->mq.head; 76391336b40SDon Lewis 76491336b40SDon Lewis if (m == NULL) 76591336b40SDon Lewis return; 76691336b40SDon Lewis q->mq.head = m->m_nextpkt; 76791336b40SDon Lewis 76891336b40SDon Lewis fq_update_stats(q, si, -m->m_pkthdr.len, 1); 76991336b40SDon Lewis 77091336b40SDon Lewis if (si->main_q.ni.length == 0) /* queue is now idle */ 77191336b40SDon Lewis si->main_q.q_time = dn_cfg.curr_time; 77291336b40SDon Lewis /* reset accu_prob after packet drop */ 77391336b40SDon Lewis q->pst.accu_prob = 0; 77491336b40SDon Lewis 77591336b40SDon Lewis FREE_PKT(m); 77691336b40SDon Lewis } 77791336b40SDon Lewis 77891336b40SDon Lewis /* 77991336b40SDon Lewis * Classify a packet to queue number using Jenkins hash function. 78091336b40SDon Lewis * Return: queue number 78191336b40SDon Lewis * the input of the hash are protocol no, perturbation, src IP, dst IP, 78291336b40SDon Lewis * src port, dst port, 78391336b40SDon Lewis */ 78491336b40SDon Lewis static inline int 78591336b40SDon Lewis fq_pie_classify_flow(struct mbuf *m, uint16_t fcount, struct fq_pie_si *si) 78691336b40SDon Lewis { 78791336b40SDon Lewis struct ip *ip; 78891336b40SDon Lewis struct tcphdr *th; 78991336b40SDon Lewis struct udphdr *uh; 79091336b40SDon Lewis uint8_t tuple[41]; 79191336b40SDon Lewis uint16_t hash=0; 79291336b40SDon Lewis 7934001fcbeSDon Lewis ip = (struct ip *)mtodo(m, dn_tag_get(m)->iphdr_off); 79491336b40SDon Lewis //#ifdef INET6 79591336b40SDon Lewis struct ip6_hdr *ip6; 79691336b40SDon Lewis int isip6; 7974001fcbeSDon Lewis isip6 = (ip->ip_v == 6); 79891336b40SDon Lewis 79991336b40SDon Lewis if(isip6) { 8004001fcbeSDon Lewis ip6 = (struct ip6_hdr *)ip; 80191336b40SDon Lewis *((uint8_t *) &tuple[0]) = ip6->ip6_nxt; 80291336b40SDon Lewis *((uint32_t *) &tuple[1]) = si->perturbation; 80391336b40SDon Lewis memcpy(&tuple[5], ip6->ip6_src.s6_addr, 16); 80491336b40SDon Lewis memcpy(&tuple[21], ip6->ip6_dst.s6_addr, 16); 80591336b40SDon Lewis 80691336b40SDon Lewis switch (ip6->ip6_nxt) { 80791336b40SDon Lewis case IPPROTO_TCP: 80891336b40SDon Lewis th = (struct tcphdr *)(ip6 + 1); 80991336b40SDon Lewis *((uint16_t *) &tuple[37]) = th->th_dport; 81091336b40SDon Lewis *((uint16_t *) &tuple[39]) = th->th_sport; 81191336b40SDon Lewis break; 81291336b40SDon Lewis 81391336b40SDon Lewis case IPPROTO_UDP: 81491336b40SDon Lewis uh = (struct udphdr *)(ip6 + 1); 81591336b40SDon Lewis *((uint16_t *) &tuple[37]) = uh->uh_dport; 81691336b40SDon Lewis *((uint16_t *) &tuple[39]) = uh->uh_sport; 81791336b40SDon Lewis break; 81891336b40SDon Lewis default: 81991336b40SDon Lewis memset(&tuple[37], 0, 4); 82091336b40SDon Lewis } 82191336b40SDon Lewis 82291336b40SDon Lewis hash = jenkins_hash(tuple, 41, HASHINIT) % fcount; 82391336b40SDon Lewis return hash; 82491336b40SDon Lewis } 82591336b40SDon Lewis //#endif 82691336b40SDon Lewis 82791336b40SDon Lewis /* IPv4 */ 82891336b40SDon Lewis *((uint8_t *) &tuple[0]) = ip->ip_p; 82991336b40SDon Lewis *((uint32_t *) &tuple[1]) = si->perturbation; 83091336b40SDon Lewis *((uint32_t *) &tuple[5]) = ip->ip_src.s_addr; 83191336b40SDon Lewis *((uint32_t *) &tuple[9]) = ip->ip_dst.s_addr; 83291336b40SDon Lewis 83391336b40SDon Lewis switch (ip->ip_p) { 83491336b40SDon Lewis case IPPROTO_TCP: 83591336b40SDon Lewis th = (struct tcphdr *)(ip + 1); 83691336b40SDon Lewis *((uint16_t *) &tuple[13]) = th->th_dport; 83791336b40SDon Lewis *((uint16_t *) &tuple[15]) = th->th_sport; 83891336b40SDon Lewis break; 83991336b40SDon Lewis 84091336b40SDon Lewis case IPPROTO_UDP: 84191336b40SDon Lewis uh = (struct udphdr *)(ip + 1); 84291336b40SDon Lewis *((uint16_t *) &tuple[13]) = uh->uh_dport; 84391336b40SDon Lewis *((uint16_t *) &tuple[15]) = uh->uh_sport; 84491336b40SDon Lewis break; 84591336b40SDon Lewis default: 84691336b40SDon Lewis memset(&tuple[13], 0, 4); 84791336b40SDon Lewis } 84891336b40SDon Lewis hash = jenkins_hash(tuple, 17, HASHINIT) % fcount; 84991336b40SDon Lewis 85091336b40SDon Lewis return hash; 85191336b40SDon Lewis } 85291336b40SDon Lewis 85391336b40SDon Lewis /* 85491336b40SDon Lewis * Enqueue a packet into an appropriate queue according to 85591336b40SDon Lewis * FQ-CoDe; algorithm. 85691336b40SDon Lewis */ 85791336b40SDon Lewis static int 85891336b40SDon Lewis fq_pie_enqueue(struct dn_sch_inst *_si, struct dn_queue *_q, 85991336b40SDon Lewis struct mbuf *m) 86091336b40SDon Lewis { 86191336b40SDon Lewis struct fq_pie_si *si; 86291336b40SDon Lewis struct fq_pie_schk *schk; 86391336b40SDon Lewis struct dn_sch_fq_pie_parms *param; 86491336b40SDon Lewis struct dn_queue *mainq; 86598e82c02SDon Lewis struct fq_pie_flow *flows; 86691336b40SDon Lewis int idx, drop, i, maxidx; 86791336b40SDon Lewis 86891336b40SDon Lewis mainq = (struct dn_queue *)(_si + 1); 86991336b40SDon Lewis si = (struct fq_pie_si *)_si; 87098e82c02SDon Lewis flows = si->si_extra->flows; 87191336b40SDon Lewis schk = (struct fq_pie_schk *)(si->_si.sched+1); 87291336b40SDon Lewis param = &schk->cfg; 87391336b40SDon Lewis 87491336b40SDon Lewis /* classify a packet to queue number*/ 87591336b40SDon Lewis idx = fq_pie_classify_flow(m, param->flows_cnt, si); 87691336b40SDon Lewis 87791336b40SDon Lewis /* enqueue packet into appropriate queue using PIE AQM. 87891336b40SDon Lewis * Note: 'pie_enqueue' function returns 1 only when it unable to 87991336b40SDon Lewis * add timestamp to packet (no limit check)*/ 88098e82c02SDon Lewis drop = pie_enqueue(&flows[idx], m, si); 88191336b40SDon Lewis 88291336b40SDon Lewis /* pie unable to timestamp a packet */ 88391336b40SDon Lewis if (drop) 88491336b40SDon Lewis return 1; 88591336b40SDon Lewis 88691336b40SDon Lewis /* If the flow (sub-queue) is not active ,then add it to tail of 88791336b40SDon Lewis * new flows list, initialize and activate it. 88891336b40SDon Lewis */ 88998e82c02SDon Lewis if (!flows[idx].active) { 89098e82c02SDon Lewis STAILQ_INSERT_TAIL(&si->newflows, &flows[idx], flowchain); 89198e82c02SDon Lewis flows[idx].deficit = param->quantum; 89298e82c02SDon Lewis fq_activate_pie(&flows[idx]); 89398e82c02SDon Lewis flows[idx].active = 1; 89491336b40SDon Lewis } 89591336b40SDon Lewis 89691336b40SDon Lewis /* check the limit for all queues and remove a packet from the 89791336b40SDon Lewis * largest one 89891336b40SDon Lewis */ 89991336b40SDon Lewis if (mainq->ni.length > schk->cfg.limit) { 90091336b40SDon Lewis /* find first active flow */ 90191336b40SDon Lewis for (maxidx = 0; maxidx < schk->cfg.flows_cnt; maxidx++) 90298e82c02SDon Lewis if (flows[maxidx].active) 90391336b40SDon Lewis break; 90491336b40SDon Lewis if (maxidx < schk->cfg.flows_cnt) { 90591336b40SDon Lewis /* find the largest sub- queue */ 90691336b40SDon Lewis for (i = maxidx + 1; i < schk->cfg.flows_cnt; i++) 90798e82c02SDon Lewis if (flows[i].active && flows[i].stats.length > 90898e82c02SDon Lewis flows[maxidx].stats.length) 90991336b40SDon Lewis maxidx = i; 91098e82c02SDon Lewis pie_drop_head(&flows[maxidx], si); 91191336b40SDon Lewis drop = 1; 91291336b40SDon Lewis } 91391336b40SDon Lewis } 91491336b40SDon Lewis 91591336b40SDon Lewis return drop; 91691336b40SDon Lewis } 91791336b40SDon Lewis 91891336b40SDon Lewis /* 91991336b40SDon Lewis * Dequeue a packet from an appropriate queue according to 92091336b40SDon Lewis * FQ-CoDel algorithm. 92191336b40SDon Lewis */ 92291336b40SDon Lewis static struct mbuf * 92391336b40SDon Lewis fq_pie_dequeue(struct dn_sch_inst *_si) 92491336b40SDon Lewis { 92591336b40SDon Lewis struct fq_pie_si *si; 92691336b40SDon Lewis struct fq_pie_schk *schk; 92791336b40SDon Lewis struct dn_sch_fq_pie_parms *param; 92891336b40SDon Lewis struct fq_pie_flow *f; 92991336b40SDon Lewis struct mbuf *mbuf; 93091336b40SDon Lewis struct fq_pie_list *fq_pie_flowlist; 93191336b40SDon Lewis 93291336b40SDon Lewis si = (struct fq_pie_si *)_si; 93391336b40SDon Lewis schk = (struct fq_pie_schk *)(si->_si.sched+1); 93491336b40SDon Lewis param = &schk->cfg; 93591336b40SDon Lewis 93691336b40SDon Lewis do { 93791336b40SDon Lewis /* select a list to start with */ 93891336b40SDon Lewis if (STAILQ_EMPTY(&si->newflows)) 93991336b40SDon Lewis fq_pie_flowlist = &si->oldflows; 94091336b40SDon Lewis else 94191336b40SDon Lewis fq_pie_flowlist = &si->newflows; 94291336b40SDon Lewis 94391336b40SDon Lewis /* Both new and old queue lists are empty, return NULL */ 94491336b40SDon Lewis if (STAILQ_EMPTY(fq_pie_flowlist)) 94591336b40SDon Lewis return NULL; 94691336b40SDon Lewis 94791336b40SDon Lewis f = STAILQ_FIRST(fq_pie_flowlist); 94891336b40SDon Lewis while (f != NULL) { 94991336b40SDon Lewis /* if there is no flow(sub-queue) deficit, increase deficit 95091336b40SDon Lewis * by quantum, move the flow to the tail of old flows list 95191336b40SDon Lewis * and try another flow. 95291336b40SDon Lewis * Otherwise, the flow will be used for dequeue. 95391336b40SDon Lewis */ 95491336b40SDon Lewis if (f->deficit < 0) { 95591336b40SDon Lewis f->deficit += param->quantum; 95691336b40SDon Lewis STAILQ_REMOVE_HEAD(fq_pie_flowlist, flowchain); 95791336b40SDon Lewis STAILQ_INSERT_TAIL(&si->oldflows, f, flowchain); 95891336b40SDon Lewis } else 95991336b40SDon Lewis break; 96091336b40SDon Lewis 96191336b40SDon Lewis f = STAILQ_FIRST(fq_pie_flowlist); 96291336b40SDon Lewis } 96391336b40SDon Lewis 96491336b40SDon Lewis /* the new flows list is empty, try old flows list */ 96591336b40SDon Lewis if (STAILQ_EMPTY(fq_pie_flowlist)) 96691336b40SDon Lewis continue; 96791336b40SDon Lewis 96891336b40SDon Lewis /* Dequeue a packet from the selected flow */ 96991336b40SDon Lewis mbuf = pie_dequeue(f, si); 97091336b40SDon Lewis 97191336b40SDon Lewis /* pie did not return a packet */ 97291336b40SDon Lewis if (!mbuf) { 97391336b40SDon Lewis /* If the selected flow belongs to new flows list, then move 97491336b40SDon Lewis * it to the tail of old flows list. Otherwise, deactivate it and 97591336b40SDon Lewis * remove it from the old list and 97691336b40SDon Lewis */ 97791336b40SDon Lewis if (fq_pie_flowlist == &si->newflows) { 97891336b40SDon Lewis STAILQ_REMOVE_HEAD(fq_pie_flowlist, flowchain); 97991336b40SDon Lewis STAILQ_INSERT_TAIL(&si->oldflows, f, flowchain); 98091336b40SDon Lewis } else { 98191336b40SDon Lewis f->active = 0; 98291336b40SDon Lewis fq_deactivate_pie(&f->pst); 98391336b40SDon Lewis STAILQ_REMOVE_HEAD(fq_pie_flowlist, flowchain); 98491336b40SDon Lewis } 98591336b40SDon Lewis /* start again */ 98691336b40SDon Lewis continue; 98791336b40SDon Lewis } 98891336b40SDon Lewis 98991336b40SDon Lewis /* we have a packet to return, 99091336b40SDon Lewis * update flow deficit and return the packet*/ 99191336b40SDon Lewis f->deficit -= mbuf->m_pkthdr.len; 99291336b40SDon Lewis return mbuf; 99391336b40SDon Lewis 99491336b40SDon Lewis } while (1); 99591336b40SDon Lewis 99691336b40SDon Lewis /* unreachable point */ 99791336b40SDon Lewis return NULL; 99891336b40SDon Lewis } 99991336b40SDon Lewis 100091336b40SDon Lewis /* 100191336b40SDon Lewis * Initialize fq_pie scheduler instance. 100291336b40SDon Lewis * also, allocate memory for flows array. 100391336b40SDon Lewis */ 100491336b40SDon Lewis static int 100591336b40SDon Lewis fq_pie_new_sched(struct dn_sch_inst *_si) 100691336b40SDon Lewis { 100791336b40SDon Lewis struct fq_pie_si *si; 100891336b40SDon Lewis struct dn_queue *q; 100991336b40SDon Lewis struct fq_pie_schk *schk; 101098e82c02SDon Lewis struct fq_pie_flow *flows; 101191336b40SDon Lewis int i; 101291336b40SDon Lewis 101391336b40SDon Lewis si = (struct fq_pie_si *)_si; 101491336b40SDon Lewis schk = (struct fq_pie_schk *)(_si->sched+1); 101591336b40SDon Lewis 101698e82c02SDon Lewis if(si->si_extra) { 101791336b40SDon Lewis D("si already configured!"); 101891336b40SDon Lewis return 0; 101991336b40SDon Lewis } 102091336b40SDon Lewis 102191336b40SDon Lewis /* init the main queue */ 102291336b40SDon Lewis q = &si->main_q; 102391336b40SDon Lewis set_oid(&q->ni.oid, DN_QUEUE, sizeof(*q)); 102491336b40SDon Lewis q->_si = _si; 102591336b40SDon Lewis q->fs = _si->sched->fs; 102691336b40SDon Lewis 102798e82c02SDon Lewis /* allocate memory for scheduler instance extra vars */ 102898e82c02SDon Lewis si->si_extra = malloc(sizeof(struct fq_pie_si_extra), 102991336b40SDon Lewis M_DUMMYNET, M_NOWAIT | M_ZERO); 103098e82c02SDon Lewis if (si->si_extra == NULL) { 103198e82c02SDon Lewis D("cannot allocate memory for fq_pie si extra vars"); 103298e82c02SDon Lewis return ENOMEM ; 103398e82c02SDon Lewis } 103498e82c02SDon Lewis /* allocate memory for flows array */ 1035454529cdSPedro F. Giffuni si->si_extra->flows = mallocarray(schk->cfg.flows_cnt, 1036454529cdSPedro F. Giffuni sizeof(struct fq_pie_flow), M_DUMMYNET, M_NOWAIT | M_ZERO); 103798e82c02SDon Lewis flows = si->si_extra->flows; 103898e82c02SDon Lewis if (flows == NULL) { 103998e82c02SDon Lewis free(si->si_extra, M_DUMMYNET); 104098e82c02SDon Lewis si->si_extra = NULL; 104198e82c02SDon Lewis D("cannot allocate memory for fq_pie flows"); 104291336b40SDon Lewis return ENOMEM ; 104391336b40SDon Lewis } 104491336b40SDon Lewis 104591336b40SDon Lewis /* init perturbation for this si */ 104691336b40SDon Lewis si->perturbation = random(); 104798e82c02SDon Lewis si->si_extra->nr_active_q = 0; 104891336b40SDon Lewis 104991336b40SDon Lewis /* init the old and new flows lists */ 105091336b40SDon Lewis STAILQ_INIT(&si->newflows); 105191336b40SDon Lewis STAILQ_INIT(&si->oldflows); 105291336b40SDon Lewis 105391336b40SDon Lewis /* init the flows (sub-queues) */ 105491336b40SDon Lewis for (i = 0; i < schk->cfg.flows_cnt; i++) { 105598e82c02SDon Lewis flows[i].pst.parms = &schk->cfg.pcfg; 105698e82c02SDon Lewis flows[i].psi_extra = si->si_extra; 105798e82c02SDon Lewis pie_init(&flows[i], schk); 105891336b40SDon Lewis } 105991336b40SDon Lewis 106091336b40SDon Lewis fq_pie_desc.ref_count++; 106191336b40SDon Lewis 106291336b40SDon Lewis return 0; 106391336b40SDon Lewis } 106491336b40SDon Lewis 106591336b40SDon Lewis /* 106691336b40SDon Lewis * Free fq_pie scheduler instance. 106791336b40SDon Lewis */ 106891336b40SDon Lewis static int 106991336b40SDon Lewis fq_pie_free_sched(struct dn_sch_inst *_si) 107091336b40SDon Lewis { 107191336b40SDon Lewis struct fq_pie_si *si; 107291336b40SDon Lewis struct fq_pie_schk *schk; 107398e82c02SDon Lewis struct fq_pie_flow *flows; 107491336b40SDon Lewis int i; 107591336b40SDon Lewis 107691336b40SDon Lewis si = (struct fq_pie_si *)_si; 107791336b40SDon Lewis schk = (struct fq_pie_schk *)(_si->sched+1); 107898e82c02SDon Lewis flows = si->si_extra->flows; 107991336b40SDon Lewis for (i = 0; i < schk->cfg.flows_cnt; i++) { 108098e82c02SDon Lewis pie_cleanup(&flows[i]); 108191336b40SDon Lewis } 108298e82c02SDon Lewis si->si_extra = NULL; 108391336b40SDon Lewis return 0; 108491336b40SDon Lewis } 108591336b40SDon Lewis 108691336b40SDon Lewis /* 108791336b40SDon Lewis * Configure FQ-PIE scheduler. 108891336b40SDon Lewis * the configurations for the scheduler is passed fromipfw userland. 108991336b40SDon Lewis */ 109091336b40SDon Lewis static int 109191336b40SDon Lewis fq_pie_config(struct dn_schk *_schk) 109291336b40SDon Lewis { 109391336b40SDon Lewis struct fq_pie_schk *schk; 109491336b40SDon Lewis struct dn_extra_parms *ep; 109591336b40SDon Lewis struct dn_sch_fq_pie_parms *fqp_cfg; 109691336b40SDon Lewis 109791336b40SDon Lewis schk = (struct fq_pie_schk *)(_schk+1); 109891336b40SDon Lewis ep = (struct dn_extra_parms *) _schk->cfg; 109991336b40SDon Lewis 110091336b40SDon Lewis /* par array contains fq_pie configuration as follow 110191336b40SDon Lewis * PIE: 0- qdelay_ref,1- tupdate, 2- max_burst 110291336b40SDon Lewis * 3- max_ecnth, 4- alpha, 5- beta, 6- flags 110391336b40SDon Lewis * FQ_PIE: 7- quantum, 8- limit, 9- flows 110491336b40SDon Lewis */ 110591336b40SDon Lewis if (ep && ep->oid.len ==sizeof(*ep) && 110691336b40SDon Lewis ep->oid.subtype == DN_SCH_PARAMS) { 110791336b40SDon Lewis fqp_cfg = &schk->cfg; 110891336b40SDon Lewis if (ep->par[0] < 0) 110991336b40SDon Lewis fqp_cfg->pcfg.qdelay_ref = fq_pie_sysctl.pcfg.qdelay_ref; 111091336b40SDon Lewis else 111191336b40SDon Lewis fqp_cfg->pcfg.qdelay_ref = ep->par[0]; 111291336b40SDon Lewis if (ep->par[1] < 0) 111391336b40SDon Lewis fqp_cfg->pcfg.tupdate = fq_pie_sysctl.pcfg.tupdate; 111491336b40SDon Lewis else 111591336b40SDon Lewis fqp_cfg->pcfg.tupdate = ep->par[1]; 111691336b40SDon Lewis if (ep->par[2] < 0) 111791336b40SDon Lewis fqp_cfg->pcfg.max_burst = fq_pie_sysctl.pcfg.max_burst; 111891336b40SDon Lewis else 111991336b40SDon Lewis fqp_cfg->pcfg.max_burst = ep->par[2]; 112091336b40SDon Lewis if (ep->par[3] < 0) 112191336b40SDon Lewis fqp_cfg->pcfg.max_ecnth = fq_pie_sysctl.pcfg.max_ecnth; 112291336b40SDon Lewis else 112391336b40SDon Lewis fqp_cfg->pcfg.max_ecnth = ep->par[3]; 112491336b40SDon Lewis if (ep->par[4] < 0) 112591336b40SDon Lewis fqp_cfg->pcfg.alpha = fq_pie_sysctl.pcfg.alpha; 112691336b40SDon Lewis else 112791336b40SDon Lewis fqp_cfg->pcfg.alpha = ep->par[4]; 112891336b40SDon Lewis if (ep->par[5] < 0) 112991336b40SDon Lewis fqp_cfg->pcfg.beta = fq_pie_sysctl.pcfg.beta; 113091336b40SDon Lewis else 113191336b40SDon Lewis fqp_cfg->pcfg.beta = ep->par[5]; 113291336b40SDon Lewis if (ep->par[6] < 0) 113391336b40SDon Lewis fqp_cfg->pcfg.flags = 0; 113491336b40SDon Lewis else 113591336b40SDon Lewis fqp_cfg->pcfg.flags = ep->par[6]; 113691336b40SDon Lewis 113791336b40SDon Lewis /* FQ configurations */ 113891336b40SDon Lewis if (ep->par[7] < 0) 113991336b40SDon Lewis fqp_cfg->quantum = fq_pie_sysctl.quantum; 114091336b40SDon Lewis else 114191336b40SDon Lewis fqp_cfg->quantum = ep->par[7]; 114291336b40SDon Lewis if (ep->par[8] < 0) 114391336b40SDon Lewis fqp_cfg->limit = fq_pie_sysctl.limit; 114491336b40SDon Lewis else 114591336b40SDon Lewis fqp_cfg->limit = ep->par[8]; 114691336b40SDon Lewis if (ep->par[9] < 0) 114791336b40SDon Lewis fqp_cfg->flows_cnt = fq_pie_sysctl.flows_cnt; 114891336b40SDon Lewis else 114991336b40SDon Lewis fqp_cfg->flows_cnt = ep->par[9]; 115091336b40SDon Lewis 115191336b40SDon Lewis /* Bound the configurations */ 115291336b40SDon Lewis fqp_cfg->pcfg.qdelay_ref = BOUND_VAR(fqp_cfg->pcfg.qdelay_ref, 115391336b40SDon Lewis 1, 5 * AQM_TIME_1S); 115491336b40SDon Lewis fqp_cfg->pcfg.tupdate = BOUND_VAR(fqp_cfg->pcfg.tupdate, 115591336b40SDon Lewis 1, 5 * AQM_TIME_1S); 115691336b40SDon Lewis fqp_cfg->pcfg.max_burst = BOUND_VAR(fqp_cfg->pcfg.max_burst, 115791336b40SDon Lewis 0, 5 * AQM_TIME_1S); 115891336b40SDon Lewis fqp_cfg->pcfg.max_ecnth = BOUND_VAR(fqp_cfg->pcfg.max_ecnth, 115991336b40SDon Lewis 0, PIE_SCALE); 116091336b40SDon Lewis fqp_cfg->pcfg.alpha = BOUND_VAR(fqp_cfg->pcfg.alpha, 0, 7 * PIE_SCALE); 116191336b40SDon Lewis fqp_cfg->pcfg.beta = BOUND_VAR(fqp_cfg->pcfg.beta, 0, 7 * PIE_SCALE); 116291336b40SDon Lewis 116391336b40SDon Lewis fqp_cfg->quantum = BOUND_VAR(fqp_cfg->quantum,1,9000); 116491336b40SDon Lewis fqp_cfg->limit= BOUND_VAR(fqp_cfg->limit,1,20480); 116591336b40SDon Lewis fqp_cfg->flows_cnt= BOUND_VAR(fqp_cfg->flows_cnt,1,65536); 116691336b40SDon Lewis } 116791336b40SDon Lewis else { 116891336b40SDon Lewis D("Wrong parameters for fq_pie scheduler"); 116991336b40SDon Lewis return 1; 117091336b40SDon Lewis } 117191336b40SDon Lewis 117291336b40SDon Lewis return 0; 117391336b40SDon Lewis } 117491336b40SDon Lewis 117591336b40SDon Lewis /* 117691336b40SDon Lewis * Return FQ-PIE scheduler configurations 117791336b40SDon Lewis * the configurations for the scheduler is passed to userland. 117891336b40SDon Lewis */ 117991336b40SDon Lewis static int 118091336b40SDon Lewis fq_pie_getconfig (struct dn_schk *_schk, struct dn_extra_parms *ep) { 118191336b40SDon Lewis struct fq_pie_schk *schk = (struct fq_pie_schk *)(_schk+1); 118291336b40SDon Lewis struct dn_sch_fq_pie_parms *fqp_cfg; 118391336b40SDon Lewis 118491336b40SDon Lewis fqp_cfg = &schk->cfg; 118591336b40SDon Lewis 118691336b40SDon Lewis strcpy(ep->name, fq_pie_desc.name); 118791336b40SDon Lewis ep->par[0] = fqp_cfg->pcfg.qdelay_ref; 118891336b40SDon Lewis ep->par[1] = fqp_cfg->pcfg.tupdate; 118991336b40SDon Lewis ep->par[2] = fqp_cfg->pcfg.max_burst; 119091336b40SDon Lewis ep->par[3] = fqp_cfg->pcfg.max_ecnth; 119191336b40SDon Lewis ep->par[4] = fqp_cfg->pcfg.alpha; 119291336b40SDon Lewis ep->par[5] = fqp_cfg->pcfg.beta; 119391336b40SDon Lewis ep->par[6] = fqp_cfg->pcfg.flags; 119491336b40SDon Lewis 119591336b40SDon Lewis ep->par[7] = fqp_cfg->quantum; 119691336b40SDon Lewis ep->par[8] = fqp_cfg->limit; 119791336b40SDon Lewis ep->par[9] = fqp_cfg->flows_cnt; 119891336b40SDon Lewis 119991336b40SDon Lewis return 0; 120091336b40SDon Lewis } 120191336b40SDon Lewis 120291336b40SDon Lewis /* 120391336b40SDon Lewis * FQ-PIE scheduler descriptor 120491336b40SDon Lewis * contains the type of the scheduler, the name, the size of extra 120591336b40SDon Lewis * data structures, and function pointers. 120691336b40SDon Lewis */ 120791336b40SDon Lewis static struct dn_alg fq_pie_desc = { 120891336b40SDon Lewis _SI( .type = ) DN_SCHED_FQ_PIE, 120991336b40SDon Lewis _SI( .name = ) "FQ_PIE", 121091336b40SDon Lewis _SI( .flags = ) 0, 121191336b40SDon Lewis 121291336b40SDon Lewis _SI( .schk_datalen = ) sizeof(struct fq_pie_schk), 121391336b40SDon Lewis _SI( .si_datalen = ) sizeof(struct fq_pie_si) - sizeof(struct dn_sch_inst), 121491336b40SDon Lewis _SI( .q_datalen = ) 0, 121591336b40SDon Lewis 121691336b40SDon Lewis _SI( .enqueue = ) fq_pie_enqueue, 121791336b40SDon Lewis _SI( .dequeue = ) fq_pie_dequeue, 121891336b40SDon Lewis _SI( .config = ) fq_pie_config, /* new sched i.e. sched X config ...*/ 121991336b40SDon Lewis _SI( .destroy = ) NULL, /*sched x delete */ 122091336b40SDon Lewis _SI( .new_sched = ) fq_pie_new_sched, /* new schd instance */ 122191336b40SDon Lewis _SI( .free_sched = ) fq_pie_free_sched, /* delete schd instance */ 122291336b40SDon Lewis _SI( .new_fsk = ) NULL, 122391336b40SDon Lewis _SI( .free_fsk = ) NULL, 122491336b40SDon Lewis _SI( .new_queue = ) NULL, 122591336b40SDon Lewis _SI( .free_queue = ) NULL, 122691336b40SDon Lewis _SI( .getconfig = ) fq_pie_getconfig, 122791336b40SDon Lewis _SI( .ref_count = ) 0 122891336b40SDon Lewis }; 122991336b40SDon Lewis 123091336b40SDon Lewis DECLARE_DNSCHED_MODULE(dn_fq_pie, &fq_pie_desc); 1231