Skip to content

Commit

Permalink
net_sched: red: split red_parms into parms and vars
Browse files Browse the repository at this point in the history
This patch splits the red_parms structure into two components.

One holding the RED 'constant' parameters, and one containing the
variables.

This permits a size reduction of GRED qdisc, and is a preliminary step
to add an optional RED unit to SFQ.

SFQRED will have a single red_parms structure shared by all flows, and a
private red_vars per flow.

Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
CC: Dave Taht <dave.taht@gmail.com>
CC: Stephen Hemminger <shemminger@vyatta.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Eric Dumazet authored and davem330 committed Jan 5, 2012
1 parent 18cb809 commit eeca668
Show file tree
Hide file tree
Showing 4 changed files with 117 additions and 95 deletions.
98 changes: 55 additions & 43 deletions include/net/red.h
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,9 @@ struct red_parms {
u8 Wlog; /* log(W) */
u8 Plog; /* random number bits */
u8 Stab[RED_STAB_SIZE];
};

struct red_vars {
/* Variables */
int qcount; /* Number of packets since last random
number generation */
Expand All @@ -152,6 +154,16 @@ static inline u32 red_maxp(u8 Plog)
return Plog < 32 ? (~0U >> Plog) : ~0U;
}

static inline void red_set_vars(struct red_vars *v)
{
/* Reset average queue length, the value is strictly bound
* to the parameters below, reseting hurts a bit but leaving
* it might result in an unreasonable qavg for a while. --TGR
*/
v->qavg = 0;

v->qcount = -1;
}

static inline void red_set_parms(struct red_parms *p,
u32 qth_min, u32 qth_max, u8 Wlog, u8 Plog,
Expand All @@ -160,13 +172,6 @@ static inline void red_set_parms(struct red_parms *p,
int delta = qth_max - qth_min;
u32 max_p_delta;

/* Reset average queue length, the value is strictly bound
* to the parameters below, reseting hurts a bit but leaving
* it might result in an unreasonable qavg for a while. --TGR
*/
p->qavg = 0;

p->qcount = -1;
p->qth_min = qth_min << Wlog;
p->qth_max = qth_max << Wlog;
p->Wlog = Wlog;
Expand Down Expand Up @@ -197,31 +202,32 @@ static inline void red_set_parms(struct red_parms *p,
memcpy(p->Stab, stab, sizeof(p->Stab));
}

static inline int red_is_idling(const struct red_parms *p)
static inline int red_is_idling(const struct red_vars *v)
{
return p->qidlestart.tv64 != 0;
return v->qidlestart.tv64 != 0;
}

static inline void red_start_of_idle_period(struct red_parms *p)
static inline void red_start_of_idle_period(struct red_vars *v)
{
p->qidlestart = ktime_get();
v->qidlestart = ktime_get();
}

static inline void red_end_of_idle_period(struct red_parms *p)
static inline void red_end_of_idle_period(struct red_vars *v)
{
p->qidlestart.tv64 = 0;
v->qidlestart.tv64 = 0;
}

static inline void red_restart(struct red_parms *p)
static inline void red_restart(struct red_vars *v)
{
red_end_of_idle_period(p);
p->qavg = 0;
p->qcount = -1;
red_end_of_idle_period(v);
v->qavg = 0;
v->qcount = -1;
}

static inline unsigned long red_calc_qavg_from_idle_time(const struct red_parms *p)
static inline unsigned long red_calc_qavg_from_idle_time(const struct red_parms *p,
const struct red_vars *v)
{
s64 delta = ktime_us_delta(ktime_get(), p->qidlestart);
s64 delta = ktime_us_delta(ktime_get(), v->qidlestart);
long us_idle = min_t(s64, delta, p->Scell_max);
int shift;

Expand All @@ -248,7 +254,7 @@ static inline unsigned long red_calc_qavg_from_idle_time(const struct red_parms
shift = p->Stab[(us_idle >> p->Scell_log) & RED_STAB_MASK];

if (shift)
return p->qavg >> shift;
return v->qavg >> shift;
else {
/* Approximate initial part of exponent with linear function:
*
Expand All @@ -257,16 +263,17 @@ static inline unsigned long red_calc_qavg_from_idle_time(const struct red_parms
* Seems, it is the best solution to
* problem of too coarse exponent tabulation.
*/
us_idle = (p->qavg * (u64)us_idle) >> p->Scell_log;
us_idle = (v->qavg * (u64)us_idle) >> p->Scell_log;

if (us_idle < (p->qavg >> 1))
return p->qavg - us_idle;
if (us_idle < (v->qavg >> 1))
return v->qavg - us_idle;
else
return p->qavg >> 1;
return v->qavg >> 1;
}
}

static inline unsigned long red_calc_qavg_no_idle_time(const struct red_parms *p,
const struct red_vars *v,
unsigned int backlog)
{
/*
Expand All @@ -278,16 +285,17 @@ static inline unsigned long red_calc_qavg_no_idle_time(const struct red_parms *p
*
* --ANK (980924)
*/
return p->qavg + (backlog - (p->qavg >> p->Wlog));
return v->qavg + (backlog - (v->qavg >> p->Wlog));
}

static inline unsigned long red_calc_qavg(const struct red_parms *p,
const struct red_vars *v,
unsigned int backlog)
{
if (!red_is_idling(p))
return red_calc_qavg_no_idle_time(p, backlog);
if (!red_is_idling(v))
return red_calc_qavg_no_idle_time(p, v, backlog);
else
return red_calc_qavg_from_idle_time(p);
return red_calc_qavg_from_idle_time(p, v);
}


Expand All @@ -296,7 +304,9 @@ static inline u32 red_random(const struct red_parms *p)
return reciprocal_divide(net_random(), p->max_P_reciprocal);
}

static inline int red_mark_probability(const struct red_parms *p, unsigned long qavg)
static inline int red_mark_probability(const struct red_parms *p,
const struct red_vars *v,
unsigned long qavg)
{
/* The formula used below causes questions.
Expand All @@ -314,7 +324,7 @@ static inline int red_mark_probability(const struct red_parms *p, unsigned long
Any questions? --ANK (980924)
*/
return !(((qavg - p->qth_min) >> p->Wlog) * p->qcount < p->qR);
return !(((qavg - p->qth_min) >> p->Wlog) * v->qcount < v->qR);
}

enum {
Expand All @@ -323,7 +333,7 @@ enum {
RED_ABOVE_MAX_TRESH,
};

static inline int red_cmp_thresh(struct red_parms *p, unsigned long qavg)
static inline int red_cmp_thresh(const struct red_parms *p, unsigned long qavg)
{
if (qavg < p->qth_min)
return RED_BELOW_MIN_THRESH;
Expand All @@ -339,42 +349,44 @@ enum {
RED_HARD_MARK,
};

static inline int red_action(struct red_parms *p, unsigned long qavg)
static inline int red_action(const struct red_parms *p,
struct red_vars *v,
unsigned long qavg)
{
switch (red_cmp_thresh(p, qavg)) {
case RED_BELOW_MIN_THRESH:
p->qcount = -1;
v->qcount = -1;
return RED_DONT_MARK;

case RED_BETWEEN_TRESH:
if (++p->qcount) {
if (red_mark_probability(p, qavg)) {
p->qcount = 0;
p->qR = red_random(p);
if (++v->qcount) {
if (red_mark_probability(p, v, qavg)) {
v->qcount = 0;
v->qR = red_random(p);
return RED_PROB_MARK;
}
} else
p->qR = red_random(p);
v->qR = red_random(p);

return RED_DONT_MARK;

case RED_ABOVE_MAX_TRESH:
p->qcount = -1;
v->qcount = -1;
return RED_HARD_MARK;
}

BUG();
return RED_DONT_MARK;
}

static inline void red_adaptative_algo(struct red_parms *p)
static inline void red_adaptative_algo(struct red_parms *p, struct red_vars *v)
{
unsigned long qavg;
u32 max_p_delta;

qavg = p->qavg;
if (red_is_idling(p))
qavg = red_calc_qavg_from_idle_time(p);
qavg = v->qavg;
if (red_is_idling(v))
qavg = red_calc_qavg_from_idle_time(p, v);

/* p->qavg is fixed point number with point at Wlog */
qavg >>= p->Wlog;
Expand Down
40 changes: 21 additions & 19 deletions net/sched/sch_choke.c
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ struct choke_sched_data {
struct red_parms parms;

/* Variables */
struct red_vars vars;
struct tcf_proto *filter_list;
struct {
u32 prob_drop; /* Early probability drops */
Expand Down Expand Up @@ -265,7 +266,7 @@ static bool choke_match_random(const struct choke_sched_data *q,
static int choke_enqueue(struct sk_buff *skb, struct Qdisc *sch)
{
struct choke_sched_data *q = qdisc_priv(sch);
struct red_parms *p = &q->parms;
const struct red_parms *p = &q->parms;
int ret = NET_XMIT_SUCCESS | __NET_XMIT_BYPASS;

if (q->filter_list) {
Expand All @@ -276,13 +277,13 @@ static int choke_enqueue(struct sk_buff *skb, struct Qdisc *sch)

choke_skb_cb(skb)->keys_valid = 0;
/* Compute average queue usage (see RED) */
p->qavg = red_calc_qavg(p, sch->q.qlen);
if (red_is_idling(p))
red_end_of_idle_period(p);
q->vars.qavg = red_calc_qavg(p, &q->vars, sch->q.qlen);
if (red_is_idling(&q->vars))
red_end_of_idle_period(&q->vars);

/* Is queue small? */
if (p->qavg <= p->qth_min)
p->qcount = -1;
if (q->vars.qavg <= p->qth_min)
q->vars.qcount = -1;
else {
unsigned int idx;

Expand All @@ -294,8 +295,8 @@ static int choke_enqueue(struct sk_buff *skb, struct Qdisc *sch)
}

/* Queue is large, always mark/drop */
if (p->qavg > p->qth_max) {
p->qcount = -1;
if (q->vars.qavg > p->qth_max) {
q->vars.qcount = -1;

sch->qstats.overlimits++;
if (use_harddrop(q) || !use_ecn(q) ||
Expand All @@ -305,10 +306,10 @@ static int choke_enqueue(struct sk_buff *skb, struct Qdisc *sch)
}

q->stats.forced_mark++;
} else if (++p->qcount) {
if (red_mark_probability(p, p->qavg)) {
p->qcount = 0;
p->qR = red_random(p);
} else if (++q->vars.qcount) {
if (red_mark_probability(p, &q->vars, q->vars.qavg)) {
q->vars.qcount = 0;
q->vars.qR = red_random(p);

sch->qstats.overlimits++;
if (!use_ecn(q) || !INET_ECN_set_ce(skb)) {
Expand All @@ -319,7 +320,7 @@ static int choke_enqueue(struct sk_buff *skb, struct Qdisc *sch)
q->stats.prob_mark++;
}
} else
p->qR = red_random(p);
q->vars.qR = red_random(p);
}

/* Admit new packet */
Expand Down Expand Up @@ -353,8 +354,8 @@ static struct sk_buff *choke_dequeue(struct Qdisc *sch)
struct sk_buff *skb;

if (q->head == q->tail) {
if (!red_is_idling(&q->parms))
red_start_of_idle_period(&q->parms);
if (!red_is_idling(&q->vars))
red_start_of_idle_period(&q->vars);
return NULL;
}

Expand All @@ -377,8 +378,8 @@ static unsigned int choke_drop(struct Qdisc *sch)
if (len > 0)
q->stats.other++;
else {
if (!red_is_idling(&q->parms))
red_start_of_idle_period(&q->parms);
if (!red_is_idling(&q->vars))
red_start_of_idle_period(&q->vars);
}

return len;
Expand All @@ -388,7 +389,7 @@ static void choke_reset(struct Qdisc *sch)
{
struct choke_sched_data *q = qdisc_priv(sch);

red_restart(&q->parms);
red_restart(&q->vars);
}

static const struct nla_policy choke_policy[TCA_CHOKE_MAX + 1] = {
Expand Down Expand Up @@ -482,9 +483,10 @@ static int choke_change(struct Qdisc *sch, struct nlattr *opt)
ctl->Plog, ctl->Scell_log,
nla_data(tb[TCA_CHOKE_STAB]),
max_P);
red_set_vars(&q->vars);

if (q->head == q->tail)
red_end_of_idle_period(&q->parms);
red_end_of_idle_period(&q->vars);

sch_tree_unlock(sch);
choke_free(old);
Expand Down
Loading

0 comments on commit eeca668

Please sign in to comment.