xref: /freebsd/sys/netpfil/ipfw/dn_sched_fq_codel.h (revision 95ee2897e98f5d444f26ed2334cc7c439f9c16c6)
191336b40SDon Lewis /*-
291336b40SDon Lewis  * Copyright (C) 2016 Centre for Advanced Internet Architectures,
391336b40SDon Lewis  *  Swinburne University of Technology, Melbourne, Australia.
491336b40SDon Lewis  * Portions of this code were made possible in part by a gift from
591336b40SDon Lewis  *  The Comcast Innovation Fund.
691336b40SDon Lewis  * Implemented by Rasool Al-Saadi <ralsaadi@swin.edu.au>
791336b40SDon Lewis  *
891336b40SDon Lewis  * Redistribution and use in source and binary forms, with or without
991336b40SDon Lewis  * modification, are permitted provided that the following conditions
1091336b40SDon Lewis  * are met:
1191336b40SDon Lewis  * 1. Redistributions of source code must retain the above copyright
1291336b40SDon Lewis  *    notice, this list of conditions and the following disclaimer.
1391336b40SDon Lewis  * 2. Redistributions in binary form must reproduce the above copyright
1491336b40SDon Lewis  *    notice, this list of conditions and the following disclaimer in the
1591336b40SDon Lewis  *    documentation and/or other materials provided with the distribution.
1691336b40SDon Lewis  *
1791336b40SDon Lewis  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1891336b40SDon Lewis  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1991336b40SDon Lewis  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2091336b40SDon Lewis  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2191336b40SDon Lewis  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2291336b40SDon Lewis  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2391336b40SDon Lewis  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2491336b40SDon Lewis  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2591336b40SDon Lewis  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2691336b40SDon Lewis  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2791336b40SDon Lewis  * SUCH DAMAGE.
2891336b40SDon Lewis  */
2991336b40SDon Lewis 
3091336b40SDon Lewis /*
3191336b40SDon Lewis  * FQ_Codel Structures and helper functions
3291336b40SDon Lewis  */
3391336b40SDon Lewis 
3491336b40SDon Lewis #ifndef _IP_DN_SCHED_FQ_CODEL_H
3591336b40SDon Lewis #define _IP_DN_SCHED_FQ_CODEL_H
3691336b40SDon Lewis 
3791336b40SDon Lewis /* list of queues */
3891336b40SDon Lewis STAILQ_HEAD(fq_codel_list, fq_codel_flow);
3991336b40SDon Lewis 
4091336b40SDon Lewis /* fq_codel parameters including codel */
4191336b40SDon Lewis struct dn_sch_fq_codel_parms {
4291336b40SDon Lewis 	struct dn_aqm_codel_parms	ccfg;	/* CoDel Parameters */
4391336b40SDon Lewis 	/* FQ_CODEL Parameters */
4491336b40SDon Lewis 	uint32_t flows_cnt;	/* number of flows */
4591336b40SDon Lewis 	uint32_t limit;	/* hard limit of fq_codel queue size*/
4691336b40SDon Lewis 	uint32_t quantum;
4791336b40SDon Lewis };	/* defaults */
4891336b40SDon Lewis 
4991336b40SDon Lewis /* flow (sub-queue) stats */
5091336b40SDon Lewis struct flow_stats {
5191336b40SDon Lewis 	uint64_t tot_pkts;	/* statistics counters  */
5291336b40SDon Lewis 	uint64_t tot_bytes;
5391336b40SDon Lewis 	uint32_t length;		/* Queue length, in packets */
5491336b40SDon Lewis 	uint32_t len_bytes;	/* Queue length, in bytes */
5591336b40SDon Lewis 	uint32_t drops;
5691336b40SDon Lewis };
5791336b40SDon Lewis 
5891336b40SDon Lewis /* A flow of packets (sub-queue).*/
5991336b40SDon Lewis struct fq_codel_flow {
6091336b40SDon Lewis 	struct mq	mq;	/* list of packets */
6191336b40SDon Lewis 	struct flow_stats stats;	/* statistics */
6291336b40SDon Lewis 	int	deficit;
6391336b40SDon Lewis 	int active;		/* 1: flow is active (in a list) */
6491336b40SDon Lewis 	struct codel_status cst;
6591336b40SDon Lewis 	STAILQ_ENTRY(fq_codel_flow) flowchain;
6691336b40SDon Lewis };
6791336b40SDon Lewis 
6891336b40SDon Lewis /* extra fq_codel scheduler configurations */
6991336b40SDon Lewis struct fq_codel_schk {
7091336b40SDon Lewis 	struct dn_sch_fq_codel_parms cfg;
7191336b40SDon Lewis };
7291336b40SDon Lewis 
7391336b40SDon Lewis /* fq_codel scheduler instance */
7491336b40SDon Lewis struct fq_codel_si {
7591336b40SDon Lewis 	struct dn_sch_inst _si;	/* standard scheduler instance */
7691336b40SDon Lewis 	struct dn_queue main_q; /* main queue is after si directly */
7791336b40SDon Lewis 
7891336b40SDon Lewis 	struct fq_codel_flow *flows; /* array of flows (queues) */
7991336b40SDon Lewis 	uint32_t perturbation; /* random value */
8091336b40SDon Lewis 	struct fq_codel_list newflows;	/* list of new queues */
8191336b40SDon Lewis 	struct fq_codel_list oldflows;		/* list of old queues */
8291336b40SDon Lewis };
8391336b40SDon Lewis 
8491336b40SDon Lewis /* Helper function to update queue&main-queue and scheduler statistics.
8591336b40SDon Lewis  * negative len + drop -> drop
8691336b40SDon Lewis  * negative len -> dequeue
8791336b40SDon Lewis  * positive len -> enqueue
8891336b40SDon Lewis  * positive len + drop -> drop during enqueue
8991336b40SDon Lewis  */
9091336b40SDon Lewis __inline static void
fq_update_stats(struct fq_codel_flow * q,struct fq_codel_si * si,int len,int drop)9191336b40SDon Lewis fq_update_stats(struct fq_codel_flow *q, struct fq_codel_si *si, int len,
9291336b40SDon Lewis 	int drop)
9391336b40SDon Lewis {
9491336b40SDon Lewis 	int inc = 0;
9591336b40SDon Lewis 
9691336b40SDon Lewis 	if (len < 0)
9791336b40SDon Lewis 		inc = -1;
9891336b40SDon Lewis 	else if (len > 0)
9991336b40SDon Lewis 		inc = 1;
10091336b40SDon Lewis 
10191336b40SDon Lewis 	if (drop) {
10291336b40SDon Lewis 		si->main_q.ni.drops ++;
10391336b40SDon Lewis 		q->stats.drops ++;
10491336b40SDon Lewis 		si->_si.ni.drops ++;
105fe3bcfbdSTom Jones 		V_dn_cfg.io_pkt_drop ++;
10691336b40SDon Lewis 	}
10791336b40SDon Lewis 
10891336b40SDon Lewis 	if (!drop || (drop && len < 0)) {
10991336b40SDon Lewis 		/* Update stats for the main queue */
11091336b40SDon Lewis 		si->main_q.ni.length += inc;
11191336b40SDon Lewis 		si->main_q.ni.len_bytes += len;
11291336b40SDon Lewis 
11391336b40SDon Lewis 		/*update sub-queue stats */
11491336b40SDon Lewis 		q->stats.length += inc;
11591336b40SDon Lewis 		q->stats.len_bytes += len;
11691336b40SDon Lewis 
11791336b40SDon Lewis 		/*update scheduler instance stats */
11891336b40SDon Lewis 		si->_si.ni.length += inc;
11991336b40SDon Lewis 		si->_si.ni.len_bytes += len;
12091336b40SDon Lewis 	}
12191336b40SDon Lewis 
12291336b40SDon Lewis 	if (inc > 0) {
12391336b40SDon Lewis 		si->main_q.ni.tot_bytes += len;
12491336b40SDon Lewis 		si->main_q.ni.tot_pkts ++;
12591336b40SDon Lewis 
12691336b40SDon Lewis 		q->stats.tot_bytes +=len;
12791336b40SDon Lewis 		q->stats.tot_pkts++;
12891336b40SDon Lewis 
12991336b40SDon Lewis 		si->_si.ni.tot_bytes +=len;
13091336b40SDon Lewis 		si->_si.ni.tot_pkts ++;
13191336b40SDon Lewis 	}
13291336b40SDon Lewis 
13391336b40SDon Lewis }
13491336b40SDon Lewis 
13591336b40SDon Lewis /* extract the head of fq_codel sub-queue */
13691336b40SDon Lewis __inline static struct mbuf *
fq_codel_extract_head(struct fq_codel_flow * q,aqm_time_t * pkt_ts,struct fq_codel_si * si)13791336b40SDon Lewis fq_codel_extract_head(struct fq_codel_flow *q, aqm_time_t *pkt_ts, struct fq_codel_si *si)
13891336b40SDon Lewis {
139*8ef7beb2SGleb Smirnoff 	struct mbuf *m;
14091336b40SDon Lewis 
141*8ef7beb2SGleb Smirnoff next:	m = q->mq.head;
14291336b40SDon Lewis 	if (m == NULL)
14391336b40SDon Lewis 		return m;
14491336b40SDon Lewis 	q->mq.head = m->m_nextpkt;
14591336b40SDon Lewis 
14691336b40SDon Lewis 	fq_update_stats(q, si, -m->m_pkthdr.len, 0);
14791336b40SDon Lewis 
14891336b40SDon Lewis 	if (si->main_q.ni.length == 0) /* queue is now idle */
149fe3bcfbdSTom Jones 			si->main_q.q_time = V_dn_cfg.curr_time;
15091336b40SDon Lewis 
15191336b40SDon Lewis 	/* extract packet timestamp*/
15291336b40SDon Lewis 	struct m_tag *mtag;
15391336b40SDon Lewis 	mtag = m_tag_locate(m, MTAG_ABI_COMPAT, DN_AQM_MTAG_TS, NULL);
15491336b40SDon Lewis 	if (mtag == NULL){
15591336b40SDon Lewis 		D("timestamp tag is not found!");
15691336b40SDon Lewis 		*pkt_ts = 0;
15791336b40SDon Lewis 	} else {
15891336b40SDon Lewis 		*pkt_ts = *(aqm_time_t *)(mtag + 1);
15991336b40SDon Lewis 		m_tag_delete(m,mtag);
16091336b40SDon Lewis 	}
161*8ef7beb2SGleb Smirnoff 	if (m->m_pkthdr.rcvif != NULL &&
162*8ef7beb2SGleb Smirnoff 	    __predict_false(m_rcvif_restore(m) == NULL)) {
163*8ef7beb2SGleb Smirnoff 		m_freem(m);
164*8ef7beb2SGleb Smirnoff 		goto next;
165*8ef7beb2SGleb Smirnoff 	}
16691336b40SDon Lewis 	return m;
16791336b40SDon Lewis }
16891336b40SDon Lewis 
16991336b40SDon Lewis #endif
170