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