176e3cc12SEric Dumazet #ifndef __NET_SCHED_CODEL_H
276e3cc12SEric Dumazet #define __NET_SCHED_CODEL_H
376e3cc12SEric Dumazet
476e3cc12SEric Dumazet /*
576e3cc12SEric Dumazet * Codel - The Controlled-Delay Active Queue Management algorithm
676e3cc12SEric Dumazet *
776e3cc12SEric Dumazet * Copyright (C) 2011-2012 Kathleen Nichols <nichols@pollere.com>
876e3cc12SEric Dumazet * Copyright (C) 2011-2012 Van Jacobson <van@pollere.net>
976e3cc12SEric Dumazet * Copyright (C) 2012 Michael D. Taht <dave.taht@bufferbloat.net>
1080ba92faSEric Dumazet * Copyright (C) 2012,2015 Eric Dumazet <edumazet@google.com>
1176e3cc12SEric Dumazet *
1276e3cc12SEric Dumazet * Redistribution and use in source and binary forms, with or without
1376e3cc12SEric Dumazet * modification, are permitted provided that the following conditions
1476e3cc12SEric Dumazet * are met:
1576e3cc12SEric Dumazet * 1. Redistributions of source code must retain the above copyright
1676e3cc12SEric Dumazet * notice, this list of conditions, and the following disclaimer,
1776e3cc12SEric Dumazet * without modification.
1876e3cc12SEric Dumazet * 2. Redistributions in binary form must reproduce the above copyright
1976e3cc12SEric Dumazet * notice, this list of conditions and the following disclaimer in the
2076e3cc12SEric Dumazet * documentation and/or other materials provided with the distribution.
2176e3cc12SEric Dumazet * 3. The names of the authors may not be used to endorse or promote products
2276e3cc12SEric Dumazet * derived from this software without specific prior written permission.
2376e3cc12SEric Dumazet *
2476e3cc12SEric Dumazet * Alternatively, provided that this notice is retained in full, this
2576e3cc12SEric Dumazet * software may be distributed under the terms of the GNU General
2676e3cc12SEric Dumazet * Public License ("GPL") version 2, in which case the provisions of the
2776e3cc12SEric Dumazet * GPL apply INSTEAD OF those given above.
2876e3cc12SEric Dumazet *
2976e3cc12SEric Dumazet * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
3076e3cc12SEric Dumazet * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
3176e3cc12SEric Dumazet * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
3276e3cc12SEric Dumazet * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
3376e3cc12SEric Dumazet * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
3476e3cc12SEric Dumazet * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
3576e3cc12SEric Dumazet * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
3676e3cc12SEric Dumazet * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
3776e3cc12SEric Dumazet * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3876e3cc12SEric Dumazet * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
3976e3cc12SEric Dumazet * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
4076e3cc12SEric Dumazet * DAMAGE.
4176e3cc12SEric Dumazet *
4276e3cc12SEric Dumazet */
4376e3cc12SEric Dumazet
4476e3cc12SEric Dumazet #include <linux/types.h>
4576e3cc12SEric Dumazet #include <linux/ktime.h>
4676e3cc12SEric Dumazet #include <linux/skbuff.h>
4776e3cc12SEric Dumazet
4876e3cc12SEric Dumazet /* Controlling Queue Delay (CoDel) algorithm
4976e3cc12SEric Dumazet * =========================================
5076e3cc12SEric Dumazet * Source : Kathleen Nichols and Van Jacobson
5176e3cc12SEric Dumazet * http://queue.acm.org/detail.cfm?id=2209336
5276e3cc12SEric Dumazet *
5376e3cc12SEric Dumazet * Implemented on linux by Dave Taht and Eric Dumazet
5476e3cc12SEric Dumazet */
5576e3cc12SEric Dumazet
5676e3cc12SEric Dumazet
5776e3cc12SEric Dumazet /* CoDel uses a 1024 nsec clock, encoded in u32
5876e3cc12SEric Dumazet * This gives a range of 2199 seconds, because of signed compares
5976e3cc12SEric Dumazet */
6076e3cc12SEric Dumazet typedef u32 codel_time_t;
6176e3cc12SEric Dumazet typedef s32 codel_tdiff_t;
6276e3cc12SEric Dumazet #define CODEL_SHIFT 10
6376e3cc12SEric Dumazet #define MS2TIME(a) ((a * NSEC_PER_MSEC) >> CODEL_SHIFT)
6476e3cc12SEric Dumazet
codel_get_time(void)6576e3cc12SEric Dumazet static inline codel_time_t codel_get_time(void)
6676e3cc12SEric Dumazet {
67d2de875cSEric Dumazet u64 ns = ktime_get_ns();
6876e3cc12SEric Dumazet
6976e3cc12SEric Dumazet return ns >> CODEL_SHIFT;
7076e3cc12SEric Dumazet }
7176e3cc12SEric Dumazet
721ba3aab3SJesper Dangaard Brouer /* Dealing with timer wrapping, according to RFC 1982, as desc in wikipedia:
731ba3aab3SJesper Dangaard Brouer * https://en.wikipedia.org/wiki/Serial_number_arithmetic#General_Solution
741ba3aab3SJesper Dangaard Brouer * codel_time_after(a,b) returns true if the time a is after time b.
751ba3aab3SJesper Dangaard Brouer */
761ba3aab3SJesper Dangaard Brouer #define codel_time_after(a, b) \
771ba3aab3SJesper Dangaard Brouer (typecheck(codel_time_t, a) && \
781ba3aab3SJesper Dangaard Brouer typecheck(codel_time_t, b) && \
791ba3aab3SJesper Dangaard Brouer ((s32)((a) - (b)) > 0))
801ba3aab3SJesper Dangaard Brouer #define codel_time_before(a, b) codel_time_after(b, a)
811ba3aab3SJesper Dangaard Brouer
821ba3aab3SJesper Dangaard Brouer #define codel_time_after_eq(a, b) \
831ba3aab3SJesper Dangaard Brouer (typecheck(codel_time_t, a) && \
841ba3aab3SJesper Dangaard Brouer typecheck(codel_time_t, b) && \
851ba3aab3SJesper Dangaard Brouer ((s32)((a) - (b)) >= 0))
861ba3aab3SJesper Dangaard Brouer #define codel_time_before_eq(a, b) codel_time_after_eq(b, a)
8776e3cc12SEric Dumazet
codel_time_to_us(codel_time_t val)8876e3cc12SEric Dumazet static inline u32 codel_time_to_us(codel_time_t val)
8976e3cc12SEric Dumazet {
9076e3cc12SEric Dumazet u64 valns = ((u64)val << CODEL_SHIFT);
9176e3cc12SEric Dumazet
9276e3cc12SEric Dumazet do_div(valns, NSEC_PER_USEC);
9376e3cc12SEric Dumazet return (u32)valns;
9476e3cc12SEric Dumazet }
9576e3cc12SEric Dumazet
9676e3cc12SEric Dumazet /**
9776e3cc12SEric Dumazet * struct codel_params - contains codel parameters
9876e3cc12SEric Dumazet * @target: target queue size (in time units)
9980ba92faSEric Dumazet * @ce_threshold: threshold for marking packets with ECN CE
10076e3cc12SEric Dumazet * @interval: width of moving time window
101a5d28090SEric Dumazet * @mtu: device mtu, or minimal queue backlog in bytes.
10276e3cc12SEric Dumazet * @ecn: is Explicit Congestion Notification enabled
103dfcb63ceSToke Høiland-Jørgensen * @ce_threshold_selector: apply ce_threshold to packets matching this value
104dfcb63ceSToke Høiland-Jørgensen * in the diffserv/ECN byte of the IP header
105dfcb63ceSToke Høiland-Jørgensen * @ce_threshold_mask: mask to apply to ce_threshold_selector comparison
10676e3cc12SEric Dumazet */
10776e3cc12SEric Dumazet struct codel_params {
10876e3cc12SEric Dumazet codel_time_t target;
10980ba92faSEric Dumazet codel_time_t ce_threshold;
11076e3cc12SEric Dumazet codel_time_t interval;
111a5d28090SEric Dumazet u32 mtu;
11276e3cc12SEric Dumazet bool ecn;
113dfcb63ceSToke Høiland-Jørgensen u8 ce_threshold_selector;
114dfcb63ceSToke Høiland-Jørgensen u8 ce_threshold_mask;
11576e3cc12SEric Dumazet };
11676e3cc12SEric Dumazet
11776e3cc12SEric Dumazet /**
11876e3cc12SEric Dumazet * struct codel_vars - contains codel variables
11976e3cc12SEric Dumazet * @count: how many drops we've done since the last time we
12076e3cc12SEric Dumazet * entered dropping state
12176e3cc12SEric Dumazet * @lastcount: count at entry to dropping state
12276e3cc12SEric Dumazet * @dropping: set to true if in dropping state
123536edd67SEric Dumazet * @rec_inv_sqrt: reciprocal value of sqrt(count) >> 1
12476e3cc12SEric Dumazet * @first_above_time: when we went (or will go) continuously above target
12576e3cc12SEric Dumazet * for interval
12676e3cc12SEric Dumazet * @drop_next: time to drop next packet, or when we dropped last
12776e3cc12SEric Dumazet * @ldelay: sojourn time of last dequeued packet
12876e3cc12SEric Dumazet */
12976e3cc12SEric Dumazet struct codel_vars {
13076e3cc12SEric Dumazet u32 count;
13176e3cc12SEric Dumazet u32 lastcount;
1326ff272c9SEric Dumazet bool dropping;
1336ff272c9SEric Dumazet u16 rec_inv_sqrt;
13476e3cc12SEric Dumazet codel_time_t first_above_time;
13576e3cc12SEric Dumazet codel_time_t drop_next;
13676e3cc12SEric Dumazet codel_time_t ldelay;
13776e3cc12SEric Dumazet };
13876e3cc12SEric Dumazet
1396ff272c9SEric Dumazet #define REC_INV_SQRT_BITS (8 * sizeof(u16)) /* or sizeof_in_bits(rec_inv_sqrt) */
1406ff272c9SEric Dumazet /* needed shift to get a Q0.32 number from rec_inv_sqrt */
1416ff272c9SEric Dumazet #define REC_INV_SQRT_SHIFT (32 - REC_INV_SQRT_BITS)
1426ff272c9SEric Dumazet
14376e3cc12SEric Dumazet /**
14476e3cc12SEric Dumazet * struct codel_stats - contains codel shared variables and stats
14576e3cc12SEric Dumazet * @maxpacket: largest packet we've seen so far
14676e3cc12SEric Dumazet * @drop_count: temp count of dropped packets in dequeue()
1472ccccf5fSWANG Cong * @drop_len: bytes of dropped packets in dequeue()
148*cfe57122SRandy Dunlap * @ecn_mark: number of packets we ECN marked instead of dropping
149*cfe57122SRandy Dunlap * @ce_mark: number of packets CE marked because sojourn time was above ce_threshold
15076e3cc12SEric Dumazet */
15176e3cc12SEric Dumazet struct codel_stats {
15276e3cc12SEric Dumazet u32 maxpacket;
15376e3cc12SEric Dumazet u32 drop_count;
1542ccccf5fSWANG Cong u32 drop_len;
15576e3cc12SEric Dumazet u32 ecn_mark;
15680ba92faSEric Dumazet u32 ce_mark;
15776e3cc12SEric Dumazet };
15876e3cc12SEric Dumazet
15980ba92faSEric Dumazet #define CODEL_DISABLED_THRESHOLD INT_MAX
16080ba92faSEric Dumazet
16179bdc4c8SMichal Kazior typedef u32 (*codel_skb_len_t)(const struct sk_buff *skb);
16279bdc4c8SMichal Kazior typedef codel_time_t (*codel_skb_time_t)(const struct sk_buff *skb);
16379bdc4c8SMichal Kazior typedef void (*codel_skb_drop_t)(struct sk_buff *skb, void *ctx);
16479bdc4c8SMichal Kazior typedef struct sk_buff * (*codel_skb_dequeue_t)(struct codel_vars *vars,
16579bdc4c8SMichal Kazior void *ctx);
16679bdc4c8SMichal Kazior
16776e3cc12SEric Dumazet #endif
168