[PKT_SCHED]: GRED: Support ECN marking

Adds a new u8 flags in a unused padding area of the netlink
message. Adds ECN marking support to be used instead of dropping
packets immediately.

Signed-off-by: Thomas Graf <tgraf@suug.ch>
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
diff --git a/include/linux/pkt_sched.h b/include/linux/pkt_sched.h
index d053add..0ebe320 100644
--- a/include/linux/pkt_sched.h
+++ b/include/linux/pkt_sched.h
@@ -220,8 +220,8 @@
 	__u32		DPs;
 	__u32		def_DP;
 	__u8		grio;
-	__u8		pad1;
-	__u16		pad2;
+	__u8		flags;
+	__u16		pad1;
 };
 
 /* HTB section */
diff --git a/net/sched/sch_gred.c b/net/sched/sch_gred.c
index 69f0fd4..079b0a4 100644
--- a/net/sched/sch_gred.c
+++ b/net/sched/sch_gred.c
@@ -55,6 +55,7 @@
 {
 	struct gred_sched_data *tab[MAX_DPs];
 	unsigned long	flags;
+	u32		red_flags;
 	u32 		DPs;
 	u32 		def;
 	struct red_parms wred_set;
@@ -140,6 +141,11 @@
 	table->wred_set.qavg = q->parms.qavg;
 }
 
+static inline int gred_use_ecn(struct gred_sched *t)
+{
+	return t->red_flags & TC_RED_ECN;
+}
+
 static int gred_enqueue(struct sk_buff *skb, struct Qdisc* sch)
 {
 	struct gred_sched_data *q=NULL;
@@ -198,13 +204,22 @@
 
 		case RED_PROB_MARK:
 			sch->qstats.overlimits++;
-			q->stats.prob_drop++;
-			goto congestion_drop;
+			if (!gred_use_ecn(t) || !INET_ECN_set_ce(skb)) {
+				q->stats.prob_drop++;
+				goto congestion_drop;
+			}
+
+			q->stats.prob_mark++;
+			break;
 
 		case RED_HARD_MARK:
 			sch->qstats.overlimits++;
-			q->stats.forced_drop++;
-			goto congestion_drop;
+			if (!gred_use_ecn(t) || !INET_ECN_set_ce(skb)) {
+				q->stats.forced_drop++;
+				goto congestion_drop;
+			}
+			q->stats.forced_mark++;
+			break;
 	}
 
 	if (q->backlog + skb->len <= q->limit) {
@@ -348,6 +363,7 @@
 	sch_tree_lock(sch);
 	table->DPs = sopt->DPs;
 	table->def = sopt->def_DP;
+	table->red_flags = sopt->flags;
 
 	/*
 	 * Every entry point to GRED is synchronized with the above code
@@ -489,6 +505,7 @@
 		.DPs	= table->DPs,
 		.def_DP	= table->def,
 		.grio	= gred_rio_mode(table),
+		.flags	= table->red_flags,
 	};
 
 	opts = RTA_NEST(skb, TCA_OPTIONS);