patch-2.3.49 linux/net/sched/sch_red.c
Next file: linux/net/unix/af_unix.c
Previous file: linux/net/sched/sch_generic.c
Back to the patch index
Back to the overall index
- Lines: 161
- Date:
Sun Feb 27 18:45:10 2000
- Orig file:
v2.3.48/linux/net/sched/sch_red.c
- Orig date:
Thu Aug 26 13:05:46 1999
diff -u --recursive --new-file v2.3.48/linux/net/sched/sch_red.c linux/net/sched/sch_red.c
@@ -11,6 +11,7 @@
* Changes:
* J Hadi Salim <hadi@nortel.com> 980914: computation fixes
* Alexey Makarenko <makar@phoenix.kharkov.ua> 990814: qave on idle link was calculated incorrectly.
+ * J Hadi Salim <hadi@nortelnetworks.com> 980816: ECN support
*/
#include <linux/config.h>
@@ -39,6 +40,9 @@
#include <net/sock.h>
#include <net/pkt_sched.h>
+#define RED_ECN_ECT 0x02
+#define RED_ECN_CE 0x01
+
/* Random Early Detection (RED) algorithm.
=======================================
@@ -138,6 +142,7 @@
u32 qth_max; /* Max average length threshold: A scaled */
u32 Rmask;
u32 Scell_max;
+ unsigned char flags;
char Wlog; /* log(W) */
char Plog; /* random number bits */
char Scell_log;
@@ -149,8 +154,48 @@
u32 qR; /* Cached random number */
psched_time_t qidlestart; /* Start of idle period */
+ struct tc_red_xstats st;
};
+static int red_ecn_mark(struct sk_buff *skb)
+{
+ if (skb->nh.raw + 20 < skb->tail)
+ return 0;
+
+ switch (skb->protocol) {
+ case __constant_htons(ETH_P_IP):
+ {
+ u8 tos = skb->nh.iph->tos;
+
+ if (!(tos & RED_ECN_ECT))
+ return 0;
+
+ if (!(tos & RED_ECN_CE)) {
+ u32 check = skb->nh.iph->check;
+
+ check += __constant_htons(0xFFFE);
+ skb->nh.iph->check = check + (check>>16);
+
+ skb->nh.iph->tos = tos | RED_ECN_CE;
+ }
+ return 1;
+ }
+
+ case __constant_htons(ETH_P_IPV6):
+ {
+ u32 label = *(u32*)skb->nh.raw;
+
+ if (!(label & __constant_htonl(RED_ECN_ECT<<20)))
+ return 0;
+ label |= __constant_htonl(RED_ECN_CE<<20);
+ return 1;
+ }
+
+ default:
+ return 0;
+ }
+}
+
static int
red_enqueue(struct sk_buff *skb, struct Qdisc* sch)
{
@@ -221,7 +266,9 @@
sch->stats.backlog += skb->len;
sch->stats.bytes += skb->len;
sch->stats.packets++;
- return 0;
+ return NET_XMIT_SUCCESS;
+ } else {
+ q->st.pdrop++;
}
kfree_skb(skb);
sch->stats.drops++;
@@ -231,10 +278,14 @@
q->qcount = -1;
sch->stats.overlimits++;
mark:
- kfree_skb(skb);
- sch->stats.drops++;
- return NET_XMIT_CN;
+ if (!(q->flags&TC_RED_ECN) || !red_ecn_mark(skb)) {
+ q->st.early++;
+ goto drop;
+ }
+ q->st.marked++;
+ goto enqueue;
}
+
if (++q->qcount) {
/* The formula used below causes questions.
@@ -261,6 +312,11 @@
}
q->qR = net_random()&q->Rmask;
goto enqueue;
+
+drop:
+ kfree_skb(skb);
+ sch->stats.drops++;
+ return NET_XMIT_CN;
}
static int
@@ -300,6 +356,7 @@
if (skb) {
sch->stats.backlog -= skb->len;
sch->stats.drops++;
+ q->st.other++;
kfree_skb(skb);
return 1;
}
@@ -336,6 +393,7 @@
ctl = RTA_DATA(tb[TCA_RED_PARMS-1]);
sch_tree_lock(sch);
+ q->flags = ctl->flags;
q->Wlog = ctl->Wlog;
q->Plog = ctl->Plog;
q->Rmask = ctl->Plog < 32 ? ((1<<ctl->Plog) - 1) : ~0UL;
@@ -367,6 +425,15 @@
#ifdef CONFIG_RTNETLINK
+int red_copy_xstats(struct sk_buff *skb, struct tc_red_xstats *st)
+{
+ RTA_PUT(skb, TCA_XSTATS, sizeof(*st), st);
+ return 0;
+
+rtattr_failure:
+ return 1;
+}
+
static int red_dump(struct Qdisc *sch, struct sk_buff *skb)
{
struct red_sched_data *q = (struct red_sched_data *)sch->data;
@@ -382,8 +449,12 @@
opt.Wlog = q->Wlog;
opt.Plog = q->Plog;
opt.Scell_log = q->Scell_log;
+ opt.flags = q->flags;
RTA_PUT(skb, TCA_RED_PARMS, sizeof(opt), &opt);
rta->rta_len = skb->tail - b;
+
+ if (red_copy_xstats(skb, &q->st))
+ goto rtattr_failure;
return skb->len;
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)