Path: blob/main/sys/netpfil/ipfw/dn_sched_fq_codel_helper.h
39482 views
/*1* Codel - The Controlled-Delay Active Queue Management algorithm.2*3* Copyright (C) 2016 Centre for Advanced Internet Architectures,4* Swinburne University of Technology, Melbourne, Australia.5* Portions of this code were made possible in part by a gift from6* The Comcast Innovation Fund.7* Implemented by Rasool Al-Saadi <[email protected]>8*9* Copyright (C) 2011-2014 Kathleen Nichols <[email protected]>.10*11* Redistribution and use in source and binary forms, with or without12* modification, are permitted provided that the following conditions13* are met:14*15* o Redistributions of source code must retain the above copyright16* notice, this list of conditions, and the following disclaimer,17* without modification.18*19* o Redistributions in binary form must reproduce the above copyright20* notice, this list of conditions and the following disclaimer in21* the documentation and/or other materials provided with the22* distribution.23*24* o The names of the authors may not be used to endorse or promote25* products derived from this software without specific prior written26* permission.27*28* Alternatively, provided that this notice is retained in full, this29* software may be distributed under the terms of the GNU General Public30* License ("GPL") version 2, in which case the provisions of the GPL31* apply INSTEAD OF those given above.3233* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS34* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT35* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR36* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT37* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,38* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT39* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,40* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY41* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT42* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE43* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.44*/4546#ifndef _IP_DN_SCHED_FQ_CODEL_HELPER_H47#define _IP_DN_SCHED_FQ_CODEL_HELPER_H4849__inline static struct mbuf *50fqc_dodequeue(struct fq_codel_flow *q, aqm_time_t now, uint16_t *ok_to_drop,51struct fq_codel_si *si)52{53struct mbuf * m;54struct fq_codel_schk *schk = (struct fq_codel_schk *)(si->_si.sched+1);55aqm_time_t pkt_ts, sojourn_time;5657*ok_to_drop = 0;58m = fq_codel_extract_head(q, &pkt_ts, si);5960if (m == NULL) {61/*queue is empty - we can't be above target*/62q->cst.first_above_time= 0;63return m;64}6566/* To span a large range of bandwidths, CoDel runs two67* different AQMs in parallel. One is sojourn-time-based68* and takes effect when the time to send an MTU-sized69* packet is less than target. The 1st term of the "if"70* below does this. The other is backlog-based and takes71* effect when the time to send an MTU-sized packet is >=72* target. The goal here is to keep the output link73* utilization high by never allowing the queue to get74* smaller than the amount that arrives in a typical75* interarrival time (MTU-sized packets arriving spaced76* by the amount of time it takes to send such a packet on77* the bottleneck). The 2nd term of the "if" does this.78*/79sojourn_time = now - pkt_ts;80if (sojourn_time < schk->cfg.ccfg.target || q->stats.len_bytes <= q->cst.maxpkt_size) {81/* went below - stay below for at least interval */82q->cst.first_above_time = 0;83} else {84if (q->cst.first_above_time == 0) {85/* just went above from below. if still above at86* first_above_time, will say it's ok to drop. */87q->cst.first_above_time = now + schk->cfg.ccfg.interval;88} else if (now >= q->cst.first_above_time) {89*ok_to_drop = 1;90}91}92return m;93}9495/* Codel dequeue function */96__inline static struct mbuf *97fqc_codel_dequeue(struct fq_codel_flow *q, struct fq_codel_si *si)98{99struct mbuf *m;100struct dn_aqm_codel_parms *cprms;101struct codel_status *cst;102aqm_time_t now;103uint16_t ok_to_drop;104struct fq_codel_schk *schk = (struct fq_codel_schk *)(si->_si.sched+1);105106cst = &q->cst;107cprms = &schk->cfg.ccfg;108109now = AQM_UNOW;110m = fqc_dodequeue(q, now, &ok_to_drop, si);111112if (cst->dropping) {113if (!ok_to_drop) {114/* sojourn time below target - leave dropping state */115cst->dropping = false;116}117118/* Time for the next drop. Drop current packet and dequeue119* next. If the dequeue doesn't take us out of dropping120* state, schedule the next drop. A large backlog might121* result in drop rates so high that the next drop should122* happen now, hence the 'while' loop.123*/124while (now >= cst->drop_next_time && cst->dropping) {125/* mark the packet */126if (cprms->flags & CODEL_ECN_ENABLED && ecn_mark(m)) {127cst->count++;128/* schedule the next mark. */129cst->drop_next_time = control_law(cst, cprms, cst->drop_next_time);130return m;131}132133/* drop the packet */134fq_update_stats(q, si, 0, 1);135m_freem(m);136m = fqc_dodequeue(q, now, &ok_to_drop, si);137138if (!ok_to_drop) {139/* leave dropping state */140cst->dropping = false;141} else {142cst->count++;143/* schedule the next drop. */144cst->drop_next_time = control_law(cst, cprms, cst->drop_next_time);145}146}147/* If we get here we're not in dropping state. The 'ok_to_drop'148* return from dodequeue means that the sojourn time has been149* above 'target' for 'interval' so enter dropping state.150*/151} else if (ok_to_drop) {152/* if ECN option is disabled or the packet cannot be marked,153* drop the packet and extract another.154*/155if (!(cprms->flags & CODEL_ECN_ENABLED) || !ecn_mark(m)) {156fq_update_stats(q, si, 0, 1);157m_freem(m);158m = fqc_dodequeue(q, now, &ok_to_drop,si);159}160161cst->dropping = true;162163/* If min went above target close to when it last went164* below, assume that the drop rate that controlled the165* queue on the last cycle is a good starting point to166* control it now. ('drop_next' will be at most 'interval'167* later than the time of the last drop so 'now - drop_next'168* is a good approximation of the time from the last drop169* until now.)170*/171cst->count = (cst->count > 2 && ((aqm_stime_t)now -172(aqm_stime_t)cst->drop_next_time) < 8* cprms->interval)? cst->count - 2 : 1;173174/* we don't have to set initial guess for Newton's method isqrt as175* we initilaize isqrt in control_law function when count == 1 */176cst->drop_next_time = control_law(cst, cprms, now);177}178179return m;180}181182#endif183184185