diff options
Diffstat (limited to 'net/sched/sch_gred.c')
| -rw-r--r-- | net/sched/sch_gred.c | 195 | 
1 files changed, 108 insertions, 87 deletions
diff --git a/net/sched/sch_gred.c b/net/sched/sch_gred.c index 51dcc2aa5c9..12cbc09157f 100644 --- a/net/sched/sch_gred.c +++ b/net/sched/sch_gred.c @@ -32,16 +32,16 @@  struct gred_sched_data;  struct gred_sched; -struct gred_sched_data -{ +struct gred_sched_data {  	u32		limit;		/* HARD maximal queue length	*/ -	u32      	DP;		/* the drop pramaters */ +	u32		DP;		/* the drop parameters */  	u32		bytesin;	/* bytes seen on virtualQ so far*/  	u32		packetsin;	/* packets seen on virtualQ so far*/  	u32		backlog;	/* bytes on the virtualQ */  	u8		prio;		/* the prio of this vq */  	struct red_parms parms; +	struct red_vars  vars;  	struct red_stats stats;  }; @@ -50,14 +50,13 @@ enum {  	GRED_RIO_MODE,  }; -struct gred_sched -{ +struct gred_sched {  	struct gred_sched_data *tab[MAX_DPs];  	unsigned long	flags;  	u32		red_flags;  	u32 		DPs;  	u32 		def; -	struct red_parms wred_set; +	struct red_vars wred_set;  };  static inline int gred_wred_mode(struct gred_sched *table) @@ -103,9 +102,8 @@ static inline int gred_wred_mode_check(struct Qdisc *sch)  		if (q == NULL)  			continue; -		for (n = 0; n < table->DPs; n++) -			if (table->tab[n] && table->tab[n] != q && -			    table->tab[n]->prio == q->prio) +		for (n = i + 1; n < table->DPs; n++) +			if (table->tab[n] && table->tab[n]->prio == q->prio)  				return 1;  	} @@ -127,17 +125,18 @@ static inline u16 tc_index_to_dp(struct sk_buff *skb)  	return skb->tc_index & GRED_VQ_MASK;  } -static inline void gred_load_wred_set(struct gred_sched *table, +static inline void gred_load_wred_set(const struct gred_sched *table,  				      struct gred_sched_data *q)  { -	q->parms.qavg = table->wred_set.qavg; -	q->parms.qidlestart = table->wred_set.qidlestart; +	q->vars.qavg = table->wred_set.qavg; +	q->vars.qidlestart = table->wred_set.qidlestart;  }  static inline void gred_store_wred_set(struct gred_sched *table,  				       struct gred_sched_data *q)  { -	table->wred_set.qavg = q->parms.qavg; +	table->wred_set.qavg = q->vars.qavg; +	table->wred_set.qidlestart = q->vars.qidlestart;  }  static inline int gred_use_ecn(struct gred_sched *t) @@ -150,17 +149,18 @@ static inline int gred_use_harddrop(struct gred_sched *t)  	return t->red_flags & TC_RED_HARDDROP;  } -static int gred_enqueue(struct sk_buff *skb, struct Qdisc* sch) +static int gred_enqueue(struct sk_buff *skb, struct Qdisc *sch)  { -	struct gred_sched_data *q=NULL; -	struct gred_sched *t= qdisc_priv(sch); +	struct gred_sched_data *q = NULL; +	struct gred_sched *t = qdisc_priv(sch);  	unsigned long qavg = 0;  	u16 dp = tc_index_to_dp(skb); -	if (dp >= t->DPs  || (q = t->tab[dp]) == NULL) { +	if (dp >= t->DPs || (q = t->tab[dp]) == NULL) {  		dp = t->def; -		if ((q = t->tab[dp]) == NULL) { +		q = t->tab[dp]; +		if (!q) {  			/* Pass through packets not assigned to a DP  			 * if no default DP has been configured. This  			 * allows for DP flows to be left untouched. @@ -171,19 +171,19 @@ static int gred_enqueue(struct sk_buff *skb, struct Qdisc* sch)  				goto drop;  		} -		/* fix tc_index? --could be controvesial but needed for +		/* fix tc_index? --could be controversial but needed for  		   requeueing */  		skb->tc_index = (skb->tc_index & ~GRED_VQ_MASK) | dp;  	} -	/* sum up all the qaves of prios <= to ours to get the new qave */ +	/* sum up all the qaves of prios < ours to get the new qave */  	if (!gred_wred_mode(t) && gred_rio_mode(t)) {  		int i;  		for (i = 0; i < t->DPs; i++) {  			if (t->tab[i] && t->tab[i]->prio < q->prio && -			    !red_is_idling(&t->tab[i]->parms)) -				qavg +=t->tab[i]->parms.qavg; +			    !red_is_idling(&t->tab[i]->vars)) +				qavg += t->tab[i]->vars.qavg;  		}  	} @@ -194,37 +194,39 @@ static int gred_enqueue(struct sk_buff *skb, struct Qdisc* sch)  	if (gred_wred_mode(t))  		gred_load_wred_set(t, q); -	q->parms.qavg = red_calc_qavg(&q->parms, gred_backlog(t, q, sch)); +	q->vars.qavg = red_calc_qavg(&q->parms, +				     &q->vars, +				     gred_backlog(t, q, sch)); -	if (red_is_idling(&q->parms)) -		red_end_of_idle_period(&q->parms); +	if (red_is_idling(&q->vars)) +		red_end_of_idle_period(&q->vars);  	if (gred_wred_mode(t))  		gred_store_wred_set(t, q); -	switch (red_action(&q->parms, q->parms.qavg + qavg)) { -		case RED_DONT_MARK: -			break; +	switch (red_action(&q->parms, &q->vars, q->vars.qavg + qavg)) { +	case RED_DONT_MARK: +		break; -		case RED_PROB_MARK: -			sch->qstats.overlimits++; -			if (!gred_use_ecn(t) || !INET_ECN_set_ce(skb)) { -				q->stats.prob_drop++; -				goto congestion_drop; -			} +	case RED_PROB_MARK: +		sch->qstats.overlimits++; +		if (!gred_use_ecn(t) || !INET_ECN_set_ce(skb)) { +			q->stats.prob_drop++; +			goto congestion_drop; +		} -			q->stats.prob_mark++; -			break; +		q->stats.prob_mark++; +		break; -		case RED_HARD_MARK: -			sch->qstats.overlimits++; -			if (gred_use_harddrop(t) || !gred_use_ecn(t) || -			    !INET_ECN_set_ce(skb)) { -				q->stats.forced_drop++; -				goto congestion_drop; -			} -			q->stats.forced_mark++; -			break; +	case RED_HARD_MARK: +		sch->qstats.overlimits++; +		if (gred_use_harddrop(t) || !gred_use_ecn(t) || +		    !INET_ECN_set_ce(skb)) { +			q->stats.forced_drop++; +			goto congestion_drop; +		} +		q->stats.forced_mark++; +		break;  	}  	if (q->backlog + qdisc_pkt_len(skb) <= q->limit) { @@ -241,7 +243,7 @@ congestion_drop:  	return NET_XMIT_CN;  } -static struct sk_buff *gred_dequeue(struct Qdisc* sch) +static struct sk_buff *gred_dequeue(struct Qdisc *sch)  {  	struct sk_buff *skb;  	struct gred_sched *t = qdisc_priv(sch); @@ -253,27 +255,27 @@ static struct sk_buff *gred_dequeue(struct Qdisc* sch)  		u16 dp = tc_index_to_dp(skb);  		if (dp >= t->DPs || (q = t->tab[dp]) == NULL) { -			if (net_ratelimit()) -				printk(KERN_WARNING "GRED: Unable to relocate " -				       "VQ 0x%x after dequeue, screwing up " -				       "backlog.\n", tc_index_to_dp(skb)); +			net_warn_ratelimited("GRED: Unable to relocate VQ 0x%x after dequeue, screwing up backlog\n", +					     tc_index_to_dp(skb));  		} else {  			q->backlog -= qdisc_pkt_len(skb); -			if (!q->backlog && !gred_wred_mode(t)) -				red_start_of_idle_period(&q->parms); +			if (gred_wred_mode(t)) { +				if (!sch->qstats.backlog) +					red_start_of_idle_period(&t->wred_set); +			} else { +				if (!q->backlog) +					red_start_of_idle_period(&q->vars); +			}  		}  		return skb;  	} -	if (gred_wred_mode(t) && !red_is_idling(&t->wred_set)) -		red_start_of_idle_period(&t->wred_set); -  	return NULL;  } -static unsigned int gred_drop(struct Qdisc* sch) +static unsigned int gred_drop(struct Qdisc *sch)  {  	struct sk_buff *skb;  	struct gred_sched *t = qdisc_priv(sch); @@ -285,30 +287,29 @@ static unsigned int gred_drop(struct Qdisc* sch)  		u16 dp = tc_index_to_dp(skb);  		if (dp >= t->DPs || (q = t->tab[dp]) == NULL) { -			if (net_ratelimit()) -				printk(KERN_WARNING "GRED: Unable to relocate " -				       "VQ 0x%x while dropping, screwing up " -				       "backlog.\n", tc_index_to_dp(skb)); +			net_warn_ratelimited("GRED: Unable to relocate VQ 0x%x while dropping, screwing up backlog\n", +					     tc_index_to_dp(skb));  		} else {  			q->backlog -= len;  			q->stats.other++; -			if (!q->backlog && !gred_wred_mode(t)) -				red_start_of_idle_period(&q->parms); +			if (gred_wred_mode(t)) { +				if (!sch->qstats.backlog) +					red_start_of_idle_period(&t->wred_set); +			} else { +				if (!q->backlog) +					red_start_of_idle_period(&q->vars); +			}  		}  		qdisc_drop(skb, sch);  		return len;  	} -	if (gred_wred_mode(t) && !red_is_idling(&t->wred_set)) -		red_start_of_idle_period(&t->wred_set); -  	return 0; -  } -static void gred_reset(struct Qdisc* sch) +static void gred_reset(struct Qdisc *sch)  {  	int i;  	struct gred_sched *t = qdisc_priv(sch); @@ -321,7 +322,7 @@ static void gred_reset(struct Qdisc* sch)  		if (!q)  			continue; -		red_restart(&q->parms); +		red_restart(&q->vars);  		q->backlog = 0;  	}  } @@ -369,8 +370,8 @@ static inline int gred_change_table_def(struct Qdisc *sch, struct nlattr *dps)  	for (i = table->DPs; i < MAX_DPs; i++) {  		if (table->tab[i]) { -			printk(KERN_WARNING "GRED: Warning: Destroying " -			       "shadowed VQ 0x%x\n", i); +			pr_warn("GRED: Warning: Destroying shadowed VQ 0x%x\n", +				i);  			gred_destroy_vq(table->tab[i]);  			table->tab[i] = NULL;  		} @@ -380,29 +381,31 @@ static inline int gred_change_table_def(struct Qdisc *sch, struct nlattr *dps)  }  static inline int gred_change_vq(struct Qdisc *sch, int dp, -				 struct tc_gred_qopt *ctl, int prio, u8 *stab) +				 struct tc_gred_qopt *ctl, int prio, +				 u8 *stab, u32 max_P, +				 struct gred_sched_data **prealloc)  {  	struct gred_sched *table = qdisc_priv(sch); -	struct gred_sched_data *q; +	struct gred_sched_data *q = table->tab[dp]; -	if (table->tab[dp] == NULL) { -		table->tab[dp] = kzalloc(sizeof(*q), GFP_KERNEL); -		if (table->tab[dp] == NULL) +	if (!q) { +		table->tab[dp] = q = *prealloc; +		*prealloc = NULL; +		if (!q)  			return -ENOMEM;  	} -	q = table->tab[dp];  	q->DP = dp;  	q->prio = prio;  	q->limit = ctl->limit;  	if (q->backlog == 0) -		red_end_of_idle_period(&q->parms); +		red_end_of_idle_period(&q->vars);  	red_set_parms(&q->parms,  		      ctl->qth_min, ctl->qth_max, ctl->Wlog, ctl->Plog, -		      ctl->Scell_log, stab); - +		      ctl->Scell_log, stab, max_P); +	red_set_vars(&q->vars);  	return 0;  } @@ -410,6 +413,7 @@ static const struct nla_policy gred_policy[TCA_GRED_MAX + 1] = {  	[TCA_GRED_PARMS]	= { .len = sizeof(struct tc_gred_qopt) },  	[TCA_GRED_STAB]		= { .len = 256 },  	[TCA_GRED_DPS]		= { .len = sizeof(struct tc_gred_sopt) }, +	[TCA_GRED_MAX_P]	= { .type = NLA_U32 },  };  static int gred_change(struct Qdisc *sch, struct nlattr *opt) @@ -419,6 +423,8 @@ static int gred_change(struct Qdisc *sch, struct nlattr *opt)  	struct nlattr *tb[TCA_GRED_MAX + 1];  	int err, prio = GRED_DEF_PRIO;  	u8 *stab; +	u32 max_P; +	struct gred_sched_data *prealloc;  	if (opt == NULL)  		return -EINVAL; @@ -434,6 +440,8 @@ static int gred_change(struct Qdisc *sch, struct nlattr *opt)  	    tb[TCA_GRED_STAB] == NULL)  		return -EINVAL; +	max_P = tb[TCA_GRED_MAX_P] ? nla_get_u32(tb[TCA_GRED_MAX_P]) : 0; +  	err = -EINVAL;  	ctl = nla_data(tb[TCA_GRED_PARMS]);  	stab = nla_data(tb[TCA_GRED_STAB]); @@ -456,9 +464,10 @@ static int gred_change(struct Qdisc *sch, struct nlattr *opt)  			prio = ctl->prio;  	} +	prealloc = kzalloc(sizeof(*prealloc), GFP_KERNEL);  	sch_tree_lock(sch); -	err = gred_change_vq(sch, ctl->DP, ctl, prio, stab); +	err = gred_change_vq(sch, ctl->DP, ctl, prio, stab, max_P, &prealloc);  	if (err < 0)  		goto errout_locked; @@ -472,6 +481,7 @@ static int gred_change(struct Qdisc *sch, struct nlattr *opt)  errout_locked:  	sch_tree_unlock(sch); +	kfree(prealloc);  errout:  	return err;  } @@ -499,6 +509,7 @@ static int gred_dump(struct Qdisc *sch, struct sk_buff *skb)  	struct gred_sched *table = qdisc_priv(sch);  	struct nlattr *parms, *opts = NULL;  	int i; +	u32 max_p[MAX_DPs];  	struct tc_gred_sopt sopt = {  		.DPs	= table->DPs,  		.def_DP	= table->def, @@ -509,7 +520,17 @@ static int gred_dump(struct Qdisc *sch, struct sk_buff *skb)  	opts = nla_nest_start(skb, TCA_OPTIONS);  	if (opts == NULL)  		goto nla_put_failure; -	NLA_PUT(skb, TCA_GRED_DPS, sizeof(sopt), &sopt); +	if (nla_put(skb, TCA_GRED_DPS, sizeof(sopt), &sopt)) +		goto nla_put_failure; + +	for (i = 0; i < MAX_DPs; i++) { +		struct gred_sched_data *q = table->tab[i]; + +		max_p[i] = q ? q->parms.max_P : 0; +	} +	if (nla_put(skb, TCA_GRED_MAX_P, sizeof(max_p), max_p)) +		goto nla_put_failure; +  	parms = nla_nest_start(skb, TCA_GRED_PARMS);  	if (parms == NULL)  		goto nla_put_failure; @@ -517,6 +538,7 @@ static int gred_dump(struct Qdisc *sch, struct sk_buff *skb)  	for (i = 0; i < MAX_DPs; i++) {  		struct gred_sched_data *q = table->tab[i];  		struct tc_gred_qopt opt; +		unsigned long qavg;  		memset(&opt, 0, sizeof(opt)); @@ -545,13 +567,12 @@ static int gred_dump(struct Qdisc *sch, struct sk_buff *skb)  		opt.packets	= q->packetsin;  		opt.bytesin	= q->bytesin; -		if (gred_wred_mode(table)) { -			q->parms.qidlestart = -				table->tab[table->def]->parms.qidlestart; -			q->parms.qavg = table->tab[table->def]->parms.qavg; -		} +		if (gred_wred_mode(table)) +			gred_load_wred_set(table, q); -		opt.qave = red_calc_qavg(&q->parms, q->parms.qavg); +		qavg = red_calc_qavg(&q->parms, &q->vars, +				     q->vars.qavg >> q->parms.Wlog); +		opt.qave = qavg >> q->parms.Wlog;  append_opt:  		if (nla_append(skb, sizeof(opt), &opt) < 0)  | 
