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