diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2000-03-07 15:45:24 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2000-03-07 15:45:24 +0000 |
commit | 9f9f3e6e8548a596697778337110a423c384b6f3 (patch) | |
tree | 5dd4b290ef532cf5ecb058e1a92cd3435afeac8c /net/sched | |
parent | d5c9a365ee7d2fded249aa5abfc5e89587583029 (diff) |
Merge with Linux 2.3.49.
Diffstat (limited to 'net/sched')
-rw-r--r-- | net/sched/sch_generic.c | 41 | ||||
-rw-r--r-- | net/sched/sch_red.c | 79 |
2 files changed, 95 insertions, 25 deletions
diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c index 8ee8ab54f..d0c0539aa 100644 --- a/net/sched/sch_generic.c +++ b/net/sched/sch_generic.c @@ -146,16 +146,17 @@ static void dev_watchdog(unsigned long arg) spin_lock(&dev->xmit_lock); if (dev->qdisc != &noop_qdisc) { - if (netif_queue_stopped(dev) && - (jiffies - dev->trans_start) > dev->watchdog_timeo) { - printk(KERN_INFO "NETDEV WATCHDOG: %s: transmit timed out\n", dev->name); - dev->tx_timeout(dev); + if (netif_device_present(dev) && + netif_running(dev) && + netif_carrier_ok(dev)) { + if (netif_queue_stopped(dev) && + (jiffies - dev->trans_start) > dev->watchdog_timeo) { + printk(KERN_INFO "NETDEV WATCHDOG: %s: transmit timed out\n", dev->name); + dev->tx_timeout(dev); + } + if (!mod_timer(&dev->watchdog_timer, jiffies + dev->watchdog_timeo)) + dev_hold(dev); } - if (!del_timer(&dev->watchdog_timer)) - dev_hold(dev); - - dev->watchdog_timer.expires = jiffies + dev->watchdog_timeo; - add_timer(&dev->watchdog_timer); } spin_unlock(&dev->xmit_lock); @@ -169,33 +170,31 @@ static void dev_watchdog_init(struct net_device *dev) dev->watchdog_timer.function = dev_watchdog; } -static void dev_watchdog_up(struct net_device *dev) +void __netdev_watchdog_up(struct net_device *dev) { - spin_lock_bh(&dev->xmit_lock); - if (dev->tx_timeout) { if (dev->watchdog_timeo <= 0) dev->watchdog_timeo = 5*HZ; - if (!del_timer(&dev->watchdog_timer)) + if (!mod_timer(&dev->watchdog_timer, jiffies + dev->watchdog_timeo)) dev_hold(dev); - dev->watchdog_timer.expires = jiffies + dev->watchdog_timeo; - add_timer(&dev->watchdog_timer); } +} + +static void dev_watchdog_up(struct net_device *dev) +{ + spin_lock_bh(&dev->xmit_lock); + __netdev_watchdog_up(dev); spin_unlock_bh(&dev->xmit_lock); } static void dev_watchdog_down(struct net_device *dev) { spin_lock_bh(&dev->xmit_lock); - - if (dev->tx_timeout) { - if (del_timer(&dev->watchdog_timer)) - __dev_put(dev); - } + if (del_timer(&dev->watchdog_timer)) + __dev_put(dev); spin_unlock_bh(&dev->xmit_lock); } - /* "NOOP" scheduler: the best scheduler, recommended for all interfaces under all circumstances. It is difficult to invent anything faster or cheaper. diff --git a/net/sched/sch_red.c b/net/sched/sch_red.c index 84deb1ce4..d8c117247 100644 --- a/net/sched/sch_red.c +++ b/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 @@ struct red_sched_data 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 @@ struct red_sched_data 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 @@ enqueue: 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 @@ enqueue: 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 @@ mark: } 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 @@ red_drop(struct Qdisc* sch) if (skb) { sch->stats.backlog -= skb->len; sch->stats.drops++; + q->st.other++; kfree_skb(skb); return 1; } @@ -336,6 +393,7 @@ static int red_change(struct Qdisc *sch, struct rtattr *opt) 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 @@ static int red_init(struct Qdisc* sch, struct rtattr *opt) #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,9 +449,13 @@ static int red_dump(struct Qdisc *sch, struct sk_buff *skb) 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; rtattr_failure: |