1e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet/*
2e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet * net/sched/sch_sfb.c	  Stochastic Fair Blue
3e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet *
4e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet * Copyright (c) 2008-2011 Juliusz Chroboczek <jch@pps.jussieu.fr>
5e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet * Copyright (c) 2011 Eric Dumazet <eric.dumazet@gmail.com>
6e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet *
7e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet * This program is free software; you can redistribute it and/or
8e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet * modify it under the terms of the GNU General Public License
9e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet * version 2 as published by the Free Software Foundation.
10e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet *
11e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet * W. Feng, D. Kandlur, D. Saha, K. Shin. Blue:
12e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet * A New Class of Active Queue Management Algorithms.
13e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet * U. Michigan CSE-TR-387-99, April 1999.
14e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet *
15e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet * http://www.thefengs.com/wuchang/blue/CSE-TR-387-99.pdf
16e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet *
17e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet */
18e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet
19e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet#include <linux/module.h>
20e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet#include <linux/types.h>
21e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet#include <linux/kernel.h>
22e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet#include <linux/errno.h>
23e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet#include <linux/skbuff.h>
24e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet#include <linux/random.h>
25e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet#include <linux/jhash.h>
26e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet#include <net/ip.h>
27e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet#include <net/pkt_sched.h>
28e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet#include <net/inet_ecn.h>
29a00bd469b6604aa5f165dcc4d07dc07499439a6bEric Dumazet#include <net/flow_keys.h>
30e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet
31e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet/*
32e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet * SFB uses two B[l][n] : L x N arrays of bins (L levels, N bins per level)
33e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet * This implementation uses L = 8 and N = 16
34e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet * This permits us to split one 32bit hash (provided per packet by rxhash or
35e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet * external classifier) into 8 subhashes of 4 bits.
36e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet */
37e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet#define SFB_BUCKET_SHIFT 4
38e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet#define SFB_NUMBUCKETS	(1 << SFB_BUCKET_SHIFT) /* N bins per Level */
39e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet#define SFB_BUCKET_MASK (SFB_NUMBUCKETS - 1)
40e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet#define SFB_LEVELS	(32 / SFB_BUCKET_SHIFT) /* L */
41e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet
42e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet/* SFB algo uses a virtual queue, named "bin" */
43e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazetstruct sfb_bucket {
44e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	u16		qlen; /* length of virtual queue */
45e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	u16		p_mark; /* marking probability */
46e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet};
47e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet
48e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet/* We use a double buffering right before hash change
49e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet * (Section 4.4 of SFB reference : moving hash functions)
50e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet */
51e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazetstruct sfb_bins {
52e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	u32		  perturbation; /* jhash perturbation */
53e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	struct sfb_bucket bins[SFB_LEVELS][SFB_NUMBUCKETS];
54e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet};
55e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet
56e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazetstruct sfb_sched_data {
57e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	struct Qdisc	*qdisc;
5825d8c0d55f241ce2d360df1bea48e23a55836ee6John Fastabend	struct tcf_proto __rcu *filter_list;
59e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	unsigned long	rehash_interval;
60e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	unsigned long	warmup_time;	/* double buffering warmup time in jiffies */
61e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	u32		max;
62e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	u32		bin_size;	/* maximum queue length per bin */
63e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	u32		increment;	/* d1 */
64e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	u32		decrement;	/* d2 */
65e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	u32		limit;		/* HARD maximal queue length */
66e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	u32		penalty_rate;
67e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	u32		penalty_burst;
68e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	u32		tokens_avail;
69e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	unsigned long	rehash_time;
70e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	unsigned long	token_time;
71e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet
72e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	u8		slot;		/* current active bins (0 or 1) */
73e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	bool		double_buffering;
74e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	struct sfb_bins bins[2];
75e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet
76e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	struct {
77e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet		u32	earlydrop;
78e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet		u32	penaltydrop;
79e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet		u32	bucketdrop;
80e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet		u32	queuedrop;
81e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet		u32	childdrop;	/* drops in child qdisc */
82e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet		u32	marked;		/* ECN mark */
83e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	} stats;
84e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet};
85e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet
86e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet/*
87e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet * Each queued skb might be hashed on one or two bins
88e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet * We store in skb_cb the two hash values.
89e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet * (A zero value means double buffering was not used)
90e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet */
91e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazetstruct sfb_skb_cb {
92e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	u32 hashes[2];
93e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet};
94e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet
95e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazetstatic inline struct sfb_skb_cb *sfb_skb_cb(const struct sk_buff *skb)
96e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet{
9716bda13d90c8d5da243e2cfa1677e62ecce26860David S. Miller	qdisc_cb_private_validate(skb, sizeof(struct sfb_skb_cb));
98e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	return (struct sfb_skb_cb *)qdisc_skb_cb(skb)->data;
99e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet}
100e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet
101e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet/*
102e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet * If using 'internal' SFB flow classifier, hash comes from skb rxhash
103e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet * If using external classifier, hash comes from the classid.
104e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet */
105e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazetstatic u32 sfb_hash(const struct sk_buff *skb, u32 slot)
106e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet{
107e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	return sfb_skb_cb(skb)->hashes[slot];
108e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet}
109e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet
110e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet/* Probabilities are coded as Q0.16 fixed-point values,
111e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet * with 0xFFFF representing 65535/65536 (almost 1.0)
112e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet * Addition and subtraction are saturating in [0, 65535]
113e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet */
114e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazetstatic u32 prob_plus(u32 p1, u32 p2)
115e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet{
116e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	u32 res = p1 + p2;
117e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet
118e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	return min_t(u32, res, SFB_MAX_PROB);
119e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet}
120e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet
121e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazetstatic u32 prob_minus(u32 p1, u32 p2)
122e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet{
123e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	return p1 > p2 ? p1 - p2 : 0;
124e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet}
125e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet
126e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazetstatic void increment_one_qlen(u32 sfbhash, u32 slot, struct sfb_sched_data *q)
127e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet{
128e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	int i;
129e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	struct sfb_bucket *b = &q->bins[slot].bins[0][0];
130e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet
131e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	for (i = 0; i < SFB_LEVELS; i++) {
132e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet		u32 hash = sfbhash & SFB_BUCKET_MASK;
133e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet
134e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet		sfbhash >>= SFB_BUCKET_SHIFT;
135e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet		if (b[hash].qlen < 0xFFFF)
136e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet			b[hash].qlen++;
137e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet		b += SFB_NUMBUCKETS; /* next level */
138e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	}
139e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet}
140e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet
141e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazetstatic void increment_qlen(const struct sk_buff *skb, struct sfb_sched_data *q)
142e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet{
143e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	u32 sfbhash;
144e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet
145e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	sfbhash = sfb_hash(skb, 0);
146e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	if (sfbhash)
147e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet		increment_one_qlen(sfbhash, 0, q);
148e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet
149e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	sfbhash = sfb_hash(skb, 1);
150e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	if (sfbhash)
151e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet		increment_one_qlen(sfbhash, 1, q);
152e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet}
153e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet
154e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazetstatic void decrement_one_qlen(u32 sfbhash, u32 slot,
155e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet			       struct sfb_sched_data *q)
156e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet{
157e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	int i;
158e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	struct sfb_bucket *b = &q->bins[slot].bins[0][0];
159e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet
160e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	for (i = 0; i < SFB_LEVELS; i++) {
161e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet		u32 hash = sfbhash & SFB_BUCKET_MASK;
162e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet
163e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet		sfbhash >>= SFB_BUCKET_SHIFT;
164e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet		if (b[hash].qlen > 0)
165e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet			b[hash].qlen--;
166e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet		b += SFB_NUMBUCKETS; /* next level */
167e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	}
168e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet}
169e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet
170e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazetstatic void decrement_qlen(const struct sk_buff *skb, struct sfb_sched_data *q)
171e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet{
172e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	u32 sfbhash;
173e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet
174e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	sfbhash = sfb_hash(skb, 0);
175e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	if (sfbhash)
176e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet		decrement_one_qlen(sfbhash, 0, q);
177e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet
178e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	sfbhash = sfb_hash(skb, 1);
179e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	if (sfbhash)
180e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet		decrement_one_qlen(sfbhash, 1, q);
181e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet}
182e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet
183e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazetstatic void decrement_prob(struct sfb_bucket *b, struct sfb_sched_data *q)
184e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet{
185e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	b->p_mark = prob_minus(b->p_mark, q->decrement);
186e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet}
187e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet
188e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazetstatic void increment_prob(struct sfb_bucket *b, struct sfb_sched_data *q)
189e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet{
190e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	b->p_mark = prob_plus(b->p_mark, q->increment);
191e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet}
192e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet
193e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazetstatic void sfb_zero_all_buckets(struct sfb_sched_data *q)
194e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet{
195e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	memset(&q->bins, 0, sizeof(q->bins));
196e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet}
197e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet
198e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet/*
199e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet * compute max qlen, max p_mark, and avg p_mark
200e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet */
201e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazetstatic u32 sfb_compute_qlen(u32 *prob_r, u32 *avgpm_r, const struct sfb_sched_data *q)
202e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet{
203e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	int i;
204e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	u32 qlen = 0, prob = 0, totalpm = 0;
205e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	const struct sfb_bucket *b = &q->bins[q->slot].bins[0][0];
206e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet
207e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	for (i = 0; i < SFB_LEVELS * SFB_NUMBUCKETS; i++) {
208e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet		if (qlen < b->qlen)
209e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet			qlen = b->qlen;
210e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet		totalpm += b->p_mark;
211e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet		if (prob < b->p_mark)
212e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet			prob = b->p_mark;
213e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet		b++;
214e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	}
215e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	*prob_r = prob;
216e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	*avgpm_r = totalpm / (SFB_LEVELS * SFB_NUMBUCKETS);
217e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	return qlen;
218e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet}
219e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet
220e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet
221e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazetstatic void sfb_init_perturbation(u32 slot, struct sfb_sched_data *q)
222e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet{
22363862b5bef7349dd1137e4c70702c67d77565785Aruna-Hewapathirane	q->bins[slot].perturbation = prandom_u32();
224e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet}
225e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet
226e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazetstatic void sfb_swap_slot(struct sfb_sched_data *q)
227e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet{
228e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	sfb_init_perturbation(q->slot, q);
229e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	q->slot ^= 1;
230e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	q->double_buffering = false;
231e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet}
232e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet
233e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet/* Non elastic flows are allowed to use part of the bandwidth, expressed
234e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet * in "penalty_rate" packets per second, with "penalty_burst" burst
235e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet */
236e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazetstatic bool sfb_rate_limit(struct sk_buff *skb, struct sfb_sched_data *q)
237e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet{
238e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	if (q->penalty_rate == 0 || q->penalty_burst == 0)
239e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet		return true;
240e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet
241e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	if (q->tokens_avail < 1) {
242e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet		unsigned long age = min(10UL * HZ, jiffies - q->token_time);
243e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet
244e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet		q->tokens_avail = (age * q->penalty_rate) / HZ;
245e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet		if (q->tokens_avail > q->penalty_burst)
246e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet			q->tokens_avail = q->penalty_burst;
247e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet		q->token_time = jiffies;
248e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet		if (q->tokens_avail < 1)
249e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet			return true;
250e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	}
251e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet
252e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	q->tokens_avail--;
253e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	return false;
254e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet}
255e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet
25625d8c0d55f241ce2d360df1bea48e23a55836ee6John Fastabendstatic bool sfb_classify(struct sk_buff *skb, struct tcf_proto *fl,
257e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet			 int *qerr, u32 *salt)
258e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet{
259e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	struct tcf_result res;
260e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	int result;
261e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet
26225d8c0d55f241ce2d360df1bea48e23a55836ee6John Fastabend	result = tc_classify(skb, fl, &res);
263e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	if (result >= 0) {
264e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet#ifdef CONFIG_NET_CLS_ACT
265e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet		switch (result) {
266e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet		case TC_ACT_STOLEN:
267e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet		case TC_ACT_QUEUED:
268e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet			*qerr = NET_XMIT_SUCCESS | __NET_XMIT_STOLEN;
269e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet		case TC_ACT_SHOT:
270e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet			return false;
271e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet		}
272e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet#endif
273e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet		*salt = TC_H_MIN(res.classid);
274e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet		return true;
275e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	}
276e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	return false;
277e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet}
278e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet
279e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazetstatic int sfb_enqueue(struct sk_buff *skb, struct Qdisc *sch)
280e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet{
281e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet
282e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	struct sfb_sched_data *q = qdisc_priv(sch);
283e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	struct Qdisc *child = q->qdisc;
28425d8c0d55f241ce2d360df1bea48e23a55836ee6John Fastabend	struct tcf_proto *fl;
285e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	int i;
286e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	u32 p_min = ~0;
287e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	u32 minqlen = ~0;
288e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	u32 r, slot, salt, sfbhash;
289e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	int ret = NET_XMIT_SUCCESS | __NET_XMIT_BYPASS;
290a00bd469b6604aa5f165dcc4d07dc07499439a6bEric Dumazet	struct flow_keys keys;
291e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet
292363437f40a23bacdead80bb80d08d8193a20cfceEric Dumazet	if (unlikely(sch->q.qlen >= q->limit)) {
29325331d6ce42bcf4b34b6705fce4da15c3fabe62fJohn Fastabend		qdisc_qstats_overlimit(sch);
294363437f40a23bacdead80bb80d08d8193a20cfceEric Dumazet		q->stats.queuedrop++;
295363437f40a23bacdead80bb80d08d8193a20cfceEric Dumazet		goto drop;
296363437f40a23bacdead80bb80d08d8193a20cfceEric Dumazet	}
297363437f40a23bacdead80bb80d08d8193a20cfceEric Dumazet
298e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	if (q->rehash_interval > 0) {
299e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet		unsigned long limit = q->rehash_time + q->rehash_interval;
300e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet
301e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet		if (unlikely(time_after(jiffies, limit))) {
302e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet			sfb_swap_slot(q);
303e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet			q->rehash_time = jiffies;
304e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet		} else if (unlikely(!q->double_buffering && q->warmup_time > 0 &&
305e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet				    time_after(jiffies, limit - q->warmup_time))) {
306e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet			q->double_buffering = true;
307e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet		}
308e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	}
309e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet
31025d8c0d55f241ce2d360df1bea48e23a55836ee6John Fastabend	fl = rcu_dereference_bh(q->filter_list);
31125d8c0d55f241ce2d360df1bea48e23a55836ee6John Fastabend	if (fl) {
312e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet		/* If using external classifiers, get result and record it. */
31325d8c0d55f241ce2d360df1bea48e23a55836ee6John Fastabend		if (!sfb_classify(skb, fl, &ret, &salt))
314e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet			goto other_drop;
315a00bd469b6604aa5f165dcc4d07dc07499439a6bEric Dumazet		keys.src = salt;
316a00bd469b6604aa5f165dcc4d07dc07499439a6bEric Dumazet		keys.dst = 0;
317a00bd469b6604aa5f165dcc4d07dc07499439a6bEric Dumazet		keys.ports = 0;
318e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	} else {
319a00bd469b6604aa5f165dcc4d07dc07499439a6bEric Dumazet		skb_flow_dissect(skb, &keys);
320e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	}
321e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet
322e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	slot = q->slot;
323e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet
324a00bd469b6604aa5f165dcc4d07dc07499439a6bEric Dumazet	sfbhash = jhash_3words((__force u32)keys.dst,
325a00bd469b6604aa5f165dcc4d07dc07499439a6bEric Dumazet			       (__force u32)keys.src,
326a00bd469b6604aa5f165dcc4d07dc07499439a6bEric Dumazet			       (__force u32)keys.ports,
327a00bd469b6604aa5f165dcc4d07dc07499439a6bEric Dumazet			       q->bins[slot].perturbation);
328e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	if (!sfbhash)
329e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet		sfbhash = 1;
330e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	sfb_skb_cb(skb)->hashes[slot] = sfbhash;
331e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet
332e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	for (i = 0; i < SFB_LEVELS; i++) {
333e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet		u32 hash = sfbhash & SFB_BUCKET_MASK;
334e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet		struct sfb_bucket *b = &q->bins[slot].bins[i][hash];
335e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet
336e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet		sfbhash >>= SFB_BUCKET_SHIFT;
337e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet		if (b->qlen == 0)
338e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet			decrement_prob(b, q);
339e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet		else if (b->qlen >= q->bin_size)
340e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet			increment_prob(b, q);
341e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet		if (minqlen > b->qlen)
342e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet			minqlen = b->qlen;
343e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet		if (p_min > b->p_mark)
344e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet			p_min = b->p_mark;
345e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	}
346e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet
347e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	slot ^= 1;
348e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	sfb_skb_cb(skb)->hashes[slot] = 0;
349e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet
350363437f40a23bacdead80bb80d08d8193a20cfceEric Dumazet	if (unlikely(minqlen >= q->max)) {
35125331d6ce42bcf4b34b6705fce4da15c3fabe62fJohn Fastabend		qdisc_qstats_overlimit(sch);
352363437f40a23bacdead80bb80d08d8193a20cfceEric Dumazet		q->stats.bucketdrop++;
353e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet		goto drop;
354e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	}
355e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet
356e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	if (unlikely(p_min >= SFB_MAX_PROB)) {
357e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet		/* Inelastic flow */
358e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet		if (q->double_buffering) {
359a00bd469b6604aa5f165dcc4d07dc07499439a6bEric Dumazet			sfbhash = jhash_3words((__force u32)keys.dst,
360a00bd469b6604aa5f165dcc4d07dc07499439a6bEric Dumazet					       (__force u32)keys.src,
361a00bd469b6604aa5f165dcc4d07dc07499439a6bEric Dumazet					       (__force u32)keys.ports,
362a00bd469b6604aa5f165dcc4d07dc07499439a6bEric Dumazet					       q->bins[slot].perturbation);
363e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet			if (!sfbhash)
364e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet				sfbhash = 1;
365e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet			sfb_skb_cb(skb)->hashes[slot] = sfbhash;
366e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet
367e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet			for (i = 0; i < SFB_LEVELS; i++) {
368e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet				u32 hash = sfbhash & SFB_BUCKET_MASK;
369e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet				struct sfb_bucket *b = &q->bins[slot].bins[i][hash];
370e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet
371e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet				sfbhash >>= SFB_BUCKET_SHIFT;
372e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet				if (b->qlen == 0)
373e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet					decrement_prob(b, q);
374e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet				else if (b->qlen >= q->bin_size)
375e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet					increment_prob(b, q);
376e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet			}
377e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet		}
378e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet		if (sfb_rate_limit(skb, q)) {
37925331d6ce42bcf4b34b6705fce4da15c3fabe62fJohn Fastabend			qdisc_qstats_overlimit(sch);
380e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet			q->stats.penaltydrop++;
381e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet			goto drop;
382e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet		}
383e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet		goto enqueue;
384e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	}
385e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet
38663862b5bef7349dd1137e4c70702c67d77565785Aruna-Hewapathirane	r = prandom_u32() & SFB_MAX_PROB;
387e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet
388e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	if (unlikely(r < p_min)) {
389e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet		if (unlikely(p_min > SFB_MAX_PROB / 2)) {
390e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet			/* If we're marking that many packets, then either
391e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet			 * this flow is unresponsive, or we're badly congested.
392e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet			 * In either case, we want to start dropping packets.
393e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet			 */
394e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet			if (r < (p_min - SFB_MAX_PROB / 2) * 2) {
395e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet				q->stats.earlydrop++;
396e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet				goto drop;
397e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet			}
398e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet		}
399e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet		if (INET_ECN_set_ce(skb)) {
400e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet			q->stats.marked++;
401e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet		} else {
402e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet			q->stats.earlydrop++;
403e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet			goto drop;
404e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet		}
405e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	}
406e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet
407e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazetenqueue:
408e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	ret = qdisc_enqueue(skb, child);
409e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	if (likely(ret == NET_XMIT_SUCCESS)) {
410e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet		sch->q.qlen++;
411e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet		increment_qlen(skb, q);
412e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	} else if (net_xmit_drop_count(ret)) {
413e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet		q->stats.childdrop++;
41425331d6ce42bcf4b34b6705fce4da15c3fabe62fJohn Fastabend		qdisc_qstats_drop(sch);
415e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	}
416e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	return ret;
417e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet
418e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazetdrop:
419e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	qdisc_drop(skb, sch);
420e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	return NET_XMIT_CN;
421e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazetother_drop:
422e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	if (ret & __NET_XMIT_BYPASS)
42325331d6ce42bcf4b34b6705fce4da15c3fabe62fJohn Fastabend		qdisc_qstats_drop(sch);
424e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	kfree_skb(skb);
425e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	return ret;
426e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet}
427e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet
428e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazetstatic struct sk_buff *sfb_dequeue(struct Qdisc *sch)
429e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet{
430e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	struct sfb_sched_data *q = qdisc_priv(sch);
431e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	struct Qdisc *child = q->qdisc;
432e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	struct sk_buff *skb;
433e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet
434e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	skb = child->dequeue(q->qdisc);
435e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet
436e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	if (skb) {
437e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet		qdisc_bstats_update(sch, skb);
438e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet		sch->q.qlen--;
439e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet		decrement_qlen(skb, q);
440e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	}
441e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet
442e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	return skb;
443e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet}
444e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet
445e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazetstatic struct sk_buff *sfb_peek(struct Qdisc *sch)
446e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet{
447e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	struct sfb_sched_data *q = qdisc_priv(sch);
448e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	struct Qdisc *child = q->qdisc;
449e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet
450e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	return child->ops->peek(child);
451e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet}
452e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet
453e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet/* No sfb_drop -- impossible since the child doesn't return the dropped skb. */
454e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet
455e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazetstatic void sfb_reset(struct Qdisc *sch)
456e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet{
457e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	struct sfb_sched_data *q = qdisc_priv(sch);
458e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet
459e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	qdisc_reset(q->qdisc);
460e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	sch->q.qlen = 0;
461e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	q->slot = 0;
462e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	q->double_buffering = false;
463e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	sfb_zero_all_buckets(q);
464e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	sfb_init_perturbation(0, q);
465e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet}
466e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet
467e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazetstatic void sfb_destroy(struct Qdisc *sch)
468e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet{
469e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	struct sfb_sched_data *q = qdisc_priv(sch);
470e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet
471e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	tcf_destroy_chain(&q->filter_list);
472e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	qdisc_destroy(q->qdisc);
473e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet}
474e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet
475e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazetstatic const struct nla_policy sfb_policy[TCA_SFB_MAX + 1] = {
476e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	[TCA_SFB_PARMS]	= { .len = sizeof(struct tc_sfb_qopt) },
477e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet};
478e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet
479e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazetstatic const struct tc_sfb_qopt sfb_default_ops = {
480e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	.rehash_interval = 600 * MSEC_PER_SEC,
481e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	.warmup_time = 60 * MSEC_PER_SEC,
482e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	.limit = 0,
483e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	.max = 25,
484e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	.bin_size = 20,
485e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	.increment = (SFB_MAX_PROB + 500) / 1000, /* 0.1 % */
486e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	.decrement = (SFB_MAX_PROB + 3000) / 6000,
487e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	.penalty_rate = 10,
488e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	.penalty_burst = 20,
489e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet};
490e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet
491e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazetstatic int sfb_change(struct Qdisc *sch, struct nlattr *opt)
492e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet{
493e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	struct sfb_sched_data *q = qdisc_priv(sch);
494e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	struct Qdisc *child;
495e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	struct nlattr *tb[TCA_SFB_MAX + 1];
496e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	const struct tc_sfb_qopt *ctl = &sfb_default_ops;
497e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	u32 limit;
498e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	int err;
499e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet
500e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	if (opt) {
501e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet		err = nla_parse_nested(tb, TCA_SFB_MAX, opt, sfb_policy);
502e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet		if (err < 0)
503e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet			return -EINVAL;
504e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet
505e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet		if (tb[TCA_SFB_PARMS] == NULL)
506e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet			return -EINVAL;
507e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet
508e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet		ctl = nla_data(tb[TCA_SFB_PARMS]);
509e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	}
510e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet
511e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	limit = ctl->limit;
512e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	if (limit == 0)
513e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet		limit = max_t(u32, qdisc_dev(sch)->tx_queue_len, 1);
514e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet
515e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	child = fifo_create_dflt(sch, &pfifo_qdisc_ops, limit);
516e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	if (IS_ERR(child))
517e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet		return PTR_ERR(child);
518e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet
519e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	sch_tree_lock(sch);
520e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet
521e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	qdisc_tree_decrease_qlen(q->qdisc, q->qdisc->q.qlen);
522e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	qdisc_destroy(q->qdisc);
523e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	q->qdisc = child;
524e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet
525e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	q->rehash_interval = msecs_to_jiffies(ctl->rehash_interval);
526e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	q->warmup_time = msecs_to_jiffies(ctl->warmup_time);
527e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	q->rehash_time = jiffies;
528e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	q->limit = limit;
529e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	q->increment = ctl->increment;
530e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	q->decrement = ctl->decrement;
531e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	q->max = ctl->max;
532e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	q->bin_size = ctl->bin_size;
533e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	q->penalty_rate = ctl->penalty_rate;
534e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	q->penalty_burst = ctl->penalty_burst;
535e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	q->tokens_avail = ctl->penalty_burst;
536e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	q->token_time = jiffies;
537e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet
538e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	q->slot = 0;
539e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	q->double_buffering = false;
540e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	sfb_zero_all_buckets(q);
541e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	sfb_init_perturbation(0, q);
542e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	sfb_init_perturbation(1, q);
543e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet
544e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	sch_tree_unlock(sch);
545e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet
546e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	return 0;
547e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet}
548e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet
549e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazetstatic int sfb_init(struct Qdisc *sch, struct nlattr *opt)
550e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet{
551e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	struct sfb_sched_data *q = qdisc_priv(sch);
552e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet
553e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	q->qdisc = &noop_qdisc;
554e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	return sfb_change(sch, opt);
555e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet}
556e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet
557e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazetstatic int sfb_dump(struct Qdisc *sch, struct sk_buff *skb)
558e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet{
559e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	struct sfb_sched_data *q = qdisc_priv(sch);
560e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	struct nlattr *opts;
561e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	struct tc_sfb_qopt opt = {
562e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet		.rehash_interval = jiffies_to_msecs(q->rehash_interval),
563e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet		.warmup_time = jiffies_to_msecs(q->warmup_time),
564e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet		.limit = q->limit,
565e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet		.max = q->max,
566e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet		.bin_size = q->bin_size,
567e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet		.increment = q->increment,
568e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet		.decrement = q->decrement,
569e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet		.penalty_rate = q->penalty_rate,
570e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet		.penalty_burst = q->penalty_burst,
571e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	};
572e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet
573e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	sch->qstats.backlog = q->qdisc->qstats.backlog;
574e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	opts = nla_nest_start(skb, TCA_OPTIONS);
5757ac2908e4b2edaec60e9090ddb4d9ceb76c05e7dAlan Cox	if (opts == NULL)
5767ac2908e4b2edaec60e9090ddb4d9ceb76c05e7dAlan Cox		goto nla_put_failure;
5771b34ec43c9b3de44a5420841ab293d1b2035a94cDavid S. Miller	if (nla_put(skb, TCA_SFB_PARMS, sizeof(opt), &opt))
5781b34ec43c9b3de44a5420841ab293d1b2035a94cDavid S. Miller		goto nla_put_failure;
579e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	return nla_nest_end(skb, opts);
580e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet
581e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazetnla_put_failure:
582e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	nla_nest_cancel(skb, opts);
583e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	return -EMSGSIZE;
584e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet}
585e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet
586e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazetstatic int sfb_dump_stats(struct Qdisc *sch, struct gnet_dump *d)
587e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet{
588e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	struct sfb_sched_data *q = qdisc_priv(sch);
589e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	struct tc_sfb_xstats st = {
590e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet		.earlydrop = q->stats.earlydrop,
591e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet		.penaltydrop = q->stats.penaltydrop,
592e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet		.bucketdrop = q->stats.bucketdrop,
593e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet		.queuedrop = q->stats.queuedrop,
594e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet		.childdrop = q->stats.childdrop,
595e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet		.marked = q->stats.marked,
596e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	};
597e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet
598e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	st.maxqlen = sfb_compute_qlen(&st.maxprob, &st.avgprob, q);
599e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet
600e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	return gnet_stats_copy_app(d, &st, sizeof(st));
601e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet}
602e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet
603e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazetstatic int sfb_dump_class(struct Qdisc *sch, unsigned long cl,
604e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet			  struct sk_buff *skb, struct tcmsg *tcm)
605e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet{
606e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	return -ENOSYS;
607e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet}
608e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet
609e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazetstatic int sfb_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new,
610e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet		     struct Qdisc **old)
611e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet{
612e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	struct sfb_sched_data *q = qdisc_priv(sch);
613e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet
614e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	if (new == NULL)
615e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet		new = &noop_qdisc;
616e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet
617e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	sch_tree_lock(sch);
618e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	*old = q->qdisc;
619e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	q->qdisc = new;
620e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	qdisc_tree_decrease_qlen(*old, (*old)->q.qlen);
621e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	qdisc_reset(*old);
622e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	sch_tree_unlock(sch);
623e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	return 0;
624e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet}
625e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet
626e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazetstatic struct Qdisc *sfb_leaf(struct Qdisc *sch, unsigned long arg)
627e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet{
628e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	struct sfb_sched_data *q = qdisc_priv(sch);
629e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet
630e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	return q->qdisc;
631e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet}
632e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet
633e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazetstatic unsigned long sfb_get(struct Qdisc *sch, u32 classid)
634e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet{
635e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	return 1;
636e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet}
637e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet
638e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazetstatic void sfb_put(struct Qdisc *sch, unsigned long arg)
639e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet{
640e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet}
641e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet
642e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazetstatic int sfb_change_class(struct Qdisc *sch, u32 classid, u32 parentid,
643e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet			    struct nlattr **tca, unsigned long *arg)
644e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet{
645e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	return -ENOSYS;
646e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet}
647e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet
648e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazetstatic int sfb_delete(struct Qdisc *sch, unsigned long cl)
649e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet{
650e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	return -ENOSYS;
651e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet}
652e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet
653e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazetstatic void sfb_walk(struct Qdisc *sch, struct qdisc_walker *walker)
654e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet{
655e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	if (!walker->stop) {
656e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet		if (walker->count >= walker->skip)
657e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet			if (walker->fn(sch, 1, walker) < 0) {
658e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet				walker->stop = 1;
659e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet				return;
660e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet			}
661e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet		walker->count++;
662e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	}
663e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet}
664e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet
66525d8c0d55f241ce2d360df1bea48e23a55836ee6John Fastabendstatic struct tcf_proto __rcu **sfb_find_tcf(struct Qdisc *sch,
66625d8c0d55f241ce2d360df1bea48e23a55836ee6John Fastabend					     unsigned long cl)
667e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet{
668e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	struct sfb_sched_data *q = qdisc_priv(sch);
669e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet
670e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	if (cl)
671e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet		return NULL;
672e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	return &q->filter_list;
673e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet}
674e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet
675e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazetstatic unsigned long sfb_bind(struct Qdisc *sch, unsigned long parent,
676e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet			      u32 classid)
677e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet{
678e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	return 0;
679e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet}
680e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet
681e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet
682e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazetstatic const struct Qdisc_class_ops sfb_class_ops = {
683e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	.graft		=	sfb_graft,
684e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	.leaf		=	sfb_leaf,
685e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	.get		=	sfb_get,
686e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	.put		=	sfb_put,
687e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	.change		=	sfb_change_class,
688e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	.delete		=	sfb_delete,
689e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	.walk		=	sfb_walk,
690e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	.tcf_chain	=	sfb_find_tcf,
691e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	.bind_tcf	=	sfb_bind,
692e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	.unbind_tcf	=	sfb_put,
693e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	.dump		=	sfb_dump_class,
694e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet};
695e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet
696e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazetstatic struct Qdisc_ops sfb_qdisc_ops __read_mostly = {
697e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	.id		=	"sfb",
698e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	.priv_size	=	sizeof(struct sfb_sched_data),
699e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	.cl_ops		=	&sfb_class_ops,
700e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	.enqueue	=	sfb_enqueue,
701e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	.dequeue	=	sfb_dequeue,
702e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	.peek		=	sfb_peek,
703e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	.init		=	sfb_init,
704e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	.reset		=	sfb_reset,
705e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	.destroy	=	sfb_destroy,
706e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	.change		=	sfb_change,
707e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	.dump		=	sfb_dump,
708e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	.dump_stats	=	sfb_dump_stats,
709e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	.owner		=	THIS_MODULE,
710e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet};
711e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet
712e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazetstatic int __init sfb_module_init(void)
713e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet{
714e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	return register_qdisc(&sfb_qdisc_ops);
715e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet}
716e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet
717e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazetstatic void __exit sfb_module_exit(void)
718e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet{
719e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet	unregister_qdisc(&sfb_qdisc_ops);
720e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet}
721e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet
722e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazetmodule_init(sfb_module_init)
723e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazetmodule_exit(sfb_module_exit)
724e13e02a3c68d899169c78d9a18689bd73491d59aEric Dumazet
725e13e02a3c68d899169c78d9a18689bd73491d59aEric DumazetMODULE_DESCRIPTION("Stochastic Fair Blue queue discipline");
726e13e02a3c68d899169c78d9a18689bd73491d59aEric DumazetMODULE_AUTHOR("Juliusz Chroboczek");
727e13e02a3c68d899169c78d9a18689bd73491d59aEric DumazetMODULE_AUTHOR("Eric Dumazet");
728e13e02a3c68d899169c78d9a18689bd73491d59aEric DumazetMODULE_LICENSE("GPL");
729