diff -urN ../v2.2.21-ds8/linux/include/linux/pkt_sched.h linux/include/linux/pkt_sched.h --- ../v2.2.21-ds8/linux/include/linux/pkt_sched.h Wed Jul 31 03:00:59 2002 +++ linux/include/linux/pkt_sched.h Sun Aug 4 17:54:40 2002 @@ -189,6 +189,16 @@ unsigned char Wlog; /* log(W) */ unsigned char Plog; /* log(P_max/(qth_max-qth_min)) */ unsigned char Scell_log; /* cell size for idle damping */ + unsigned char flags; +#define TC_RED_ECN 1 +}; + +struct tc_red_xstats +{ + __u32 early; /* Early drops */ + __u32 pdrop; /* Drops due to queue limits */ + __u32 other; /* Drops due to drop() calls */ + __u32 marked; /* Marked packets */ }; /* GRED section */ diff -urN ../v2.2.21-ds8/linux/include/net/pkt_cls.h linux/include/net/pkt_cls.h --- ../v2.2.21-ds8/linux/include/net/pkt_cls.h Sat Oct 21 15:11:28 2000 +++ linux/include/net/pkt_cls.h Thu Aug 1 03:12:52 2002 @@ -77,16 +77,6 @@ return -1; } -extern __inline__ unsigned long cls_set_class(unsigned long *clp, unsigned long cl) -{ - unsigned long old_cl; - - old_cl = *clp; - *clp = cl; - synchronize_bh(); - return old_cl; -} - extern int register_tcf_proto_ops(struct tcf_proto_ops *ops); extern int unregister_tcf_proto_ops(struct tcf_proto_ops *ops); diff -urN ../v2.2.21-ds8/linux/include/net/pkt_sched.h linux/include/net/pkt_sched.h --- ../v2.2.21-ds8/linux/include/net/pkt_sched.h Wed Jul 31 03:00:59 2002 +++ linux/include/net/pkt_sched.h Wed Aug 7 03:23:36 2002 @@ -8,6 +8,7 @@ #define PSCHED_CLOCK_SOURCE PSCHED_JIFFIES #include +#include #include struct rtattr; @@ -78,6 +79,7 @@ unsigned flags; #define TCQ_F_BUILTIN 1 #define TCQ_F_THROTTLED 2 +#define TCQ_F_INGRES 4 struct Qdisc_ops *ops; struct Qdisc *next; u32 handle; @@ -85,7 +87,6 @@ struct sk_buff_head q; struct device *dev; - int ingress; struct tc_stats stats; unsigned long tx_timeo; unsigned long tx_last; @@ -107,6 +108,111 @@ int refcnt; }; +#ifndef MODULE_LICENSE +#define MODULE_LICENSE(X) +#endif + +#ifndef NET_XMIT_SUCCESS +#define NET_XMIT_SUCCESS 0 +#define NET_XMIT_DROP 1 /* skb dropped */ +#define NET_XMIT_CN 2 /* congestion notification */ +#define NET_XMIT_POLICED 3 /* skb is shot by police */ +#define NET_XMIT_BYPASS 4 /* packet does not leave via dequeue; + (TC use only - dev_queue_xmit + returns this as NET_XMIT_SUCCESS) */ +#endif + +#define likely(e) (e) +#define unlikely(e) (e) + +#ifndef min_t +#define min_t(type,x,y) \ + ({ type __x = (x); type __y = (y); __x < __y ? __x: __y; }) +#define max_t(type,x,y) \ + ({ type __x = (x); type __y = (y); __x > __y ? __x: __y; }) +#endif + +static inline void list_del_init(struct list_head *entry) +{ + __list_del(entry->prev, entry->next); + INIT_LIST_HEAD(entry); +} + +static inline void __skb_queue_purge(struct sk_buff_head *list) +{ + struct sk_buff *skb; + while ((skb=__skb_dequeue(list))!=NULL) + kfree_skb(skb); +} +#define del_timer_sync(t) del_timer(t) + +#define netif_schedule qdisc_wakeup +#define netif_queue_stopped(D) (D->tbusy) +#ifndef BUG_TRAP +#define BUG_TRAP(x) if (!(x)) { printk("Assertion (" #x ") failed at " __FILE__ "(%d):" __FUNCTION__ "\n", __LINE__); } +#endif + +static inline void IP_ECN_set_ce(struct iphdr *iph) +{ + u32 check = iph->check; + check += __constant_htons(0xFFFE); + iph->check = check + (check>=0xFFFF); + iph->tos |= 1; +} + +static inline void sch_tree_lock(struct Qdisc *q) +{ + start_bh_atomic(); +} + +static inline void sch_tree_unlock(struct Qdisc *q) +{ + end_bh_atomic(); +} + +static inline void tcf_tree_lock(struct tcf_proto *tp) +{ + wmb(); +} + +static inline void tcf_tree_unlock(struct tcf_proto *tp) +{ + synchronize_bh(); +} + +static inline void sch_dev_queue_lock(struct device *dev) +{ + start_bh_atomic(); +} + +static inline void sch_dev_queue_unlock(struct device *dev) +{ + end_bh_atomic(); +} + + +static inline unsigned long +cls_set_class(struct tcf_proto *tp, unsigned long *clp, unsigned long cl) +{ + unsigned long old_cl; + + old_cl = *clp; + wmb(); + *clp = cl; + synchronize_bh(); + return old_cl; +} + +static inline unsigned long +__cls_set_class(unsigned long *clp, unsigned long cl) +{ + unsigned long old_cl; + + old_cl = *clp; + *clp = cl; + return old_cl; +} + /* Timer resolution MUST BE < 10% of min_schedulable_packet_size/bandwidth @@ -177,7 +283,7 @@ #define PSCHED_EXPORTLIST_2 -#if ~0UL == 0xFFFFFFFF +#if BITS_PER_LONG <= 32 #define PSCHED_WATCHER unsigned long @@ -208,7 +314,7 @@ #define PSCHED_US2JIFFIE(delay) (((delay)+psched_clock_per_hz-1)/psched_clock_per_hz) -#if CPU == 586 || CPU == 686 +#ifdef CONFIG_X86_TSC #define PSCHED_GET_TIME(stamp) \ ({ u64 __cur; \ @@ -314,8 +420,8 @@ #define PSCHED_TDIFF(tv1, tv2) (long)((tv1) - (tv2)) #define PSCHED_TDIFF_SAFE(tv1, tv2, bound, guard) \ ({ \ - long __delta = (tv1) - (tv2); \ - if ( __delta > (bound)) { __delta = (bound); guard; } \ + long long __delta = (tv1) - (tv2); \ + if ( __delta > (long long)(bound)) { __delta = (bound); guard; } \ __delta; \ }) @@ -350,6 +456,7 @@ struct tc_stats stats; }; +extern int qdisc_copy_stats(struct sk_buff *skb, struct tc_stats *st); extern void tcf_police_destroy(struct tcf_police *p); extern struct tcf_police * tcf_police_locate(struct rtattr *rta, struct rtattr *est); extern int tcf_police_dump(struct sk_buff *skb, struct tcf_police *p); diff -urN ../v2.2.21-ds8/linux/net/core/skbuff.c linux/net/core/skbuff.c --- ../v2.2.21-ds8/linux/net/core/skbuff.c Wed Jul 31 03:00:59 2002 +++ linux/net/core/skbuff.c Sun Aug 4 16:18:42 2002 @@ -310,6 +310,9 @@ #ifdef CONFIG_IP_FIREWALL n->fwmark = skb->fwmark; #endif +#ifdef CONFIG_NET_SCHED + n->tc_index = skb->tc_index; +#endif return n; } @@ -358,6 +361,9 @@ n->security=skb->security; #ifdef CONFIG_IP_FIREWALL n->fwmark = skb->fwmark; +#endif +#ifdef CONFIG_NET_SCHED + n->tc_index = skb->tc_index; #endif return n; diff -urN ../v2.2.21-ds8/linux/net/ipv4/ip_input.c linux/net/ipv4/ip_input.c --- ../v2.2.21-ds8/linux/net/ipv4/ip_input.c Wed Jul 31 03:00:59 2002 +++ linux/net/ipv4/ip_input.c Tue Aug 6 14:02:54 2002 @@ -151,7 +151,7 @@ #include #ifdef CONFIG_FIREWALL -#ifdef CONFIG_NET_SCH_INGRESS +#if defined(CONFIG_NET_SCH_INGRESS) || defined(CONFIG_NET_SCH_INGRESS_MODULE) #include #endif #endif @@ -475,9 +475,8 @@ fwres = call_in_firewall(PF_INET, dev, iph, &rport, &skb); if (fwres < FW_ACCEPT && fwres != FW_REJECT) goto drop; -#ifdef CONFIG_NET_SCH_INGRESS - fwres = call_in_ingress(skb); - if (fwres != FW_ACCEPT) +#if defined(CONFIG_NET_SCH_INGRESS) || defined(CONFIG_NET_SCH_INGRESS_MODULE) + if (FW_ACCEPT != call_in_ingress(skb)) goto drop; #endif diff -urN ../v2.2.21-ds8/linux/net/netsyms.c linux/net/netsyms.c --- ../v2.2.21-ds8/linux/net/netsyms.c Wed Jul 31 03:00:59 2002 +++ linux/net/netsyms.c Tue Aug 6 13:40:17 2002 @@ -548,6 +548,7 @@ EXPORT_SYMBOL(unregister_qdisc); EXPORT_SYMBOL(qdisc_get_rtab); EXPORT_SYMBOL(qdisc_put_rtab); +EXPORT_SYMBOL(qdisc_copy_stats); #ifdef CONFIG_NET_ESTIMATOR EXPORT_SYMBOL(qdisc_new_estimator); EXPORT_SYMBOL(qdisc_kill_estimator); diff -urN ../v2.2.21-ds8/linux/net/sched/cls_api.c linux/net/sched/cls_api.c --- ../v2.2.21-ds8/linux/net/sched/cls_api.c Wed Jul 31 03:00:59 2002 +++ linux/net/sched/cls_api.c Sun Aug 4 19:57:48 2002 @@ -217,8 +217,10 @@ kfree(tp); goto errout; } + sch_dev_queue_lock(dev); tp->next = *back; *back = tp; + sch_dev_queue_unlock(dev); } else if (tca[TCA_KIND-1] && rtattr_strcmp(tca[TCA_KIND-1], tp->ops->kind)) goto errout; diff -urN ../v2.2.21-ds8/linux/net/sched/cls_fw.c linux/net/sched/cls_fw.c --- ../v2.2.21-ds8/linux/net/sched/cls_fw.c Sat Oct 21 15:10:57 2000 +++ linux/net/sched/cls_fw.c Thu Aug 1 03:34:59 2002 @@ -136,7 +136,7 @@ unsigned long cl; head->ht[h] = f->next; - if ((cl = cls_set_class(&f->res.class, 0)) != 0) + if ((cl = __cls_set_class(&f->res.class, 0)) != 0) tp->q->ops->cl_ops->unbind_tcf(tp->q, cl); #ifdef CONFIG_NET_CLS_POLICE tcf_police_release(f->police); @@ -161,10 +161,11 @@ if (*fp == f) { unsigned long cl; + tcf_tree_lock(tp); *fp = f->next; - synchronize_bh(); + tcf_tree_unlock(tp); - if ((cl = cls_set_class(&f->res.class, 0)) != 0) + if ((cl = cls_set_class(tp, &f->res.class, 0)) != 0) tp->q->ops->cl_ops->unbind_tcf(tp->q, cl); #ifdef CONFIG_NET_CLS_POLICE tcf_police_release(f->police); @@ -203,7 +204,7 @@ f->res.classid = *(u32*)RTA_DATA(tb[TCA_FW_CLASSID-1]); cl = tp->q->ops->cl_ops->bind_tcf(tp->q, base, f->res.classid); - cl = cls_set_class(&f->res.class, cl); + cl = cls_set_class(tp, &f->res.class, cl); if (cl) tp->q->ops->cl_ops->unbind_tcf(tp->q, cl); } @@ -211,8 +212,9 @@ if (tb[TCA_FW_POLICE-1]) { struct tcf_police *police = tcf_police_locate(tb[TCA_FW_POLICE-1], tca[TCA_RATE-1]); + tcf_tree_lock(tp); police = xchg(&f->police, police); - synchronize_bh(); + tcf_tree_unlock(tp); tcf_police_release(police); } @@ -229,8 +231,9 @@ return -ENOBUFS; memset(head, 0, sizeof(*head)); + tcf_tree_lock(tp); tp->root = head; - synchronize_bh(); + tcf_tree_unlock(tp); } f = kmalloc(sizeof(struct fw_filter), GFP_KERNEL); @@ -245,7 +248,7 @@ if (RTA_PAYLOAD(tb[TCA_FW_CLASSID-1]) != 4) goto errout; f->res.classid = *(u32*)RTA_DATA(tb[TCA_FW_CLASSID-1]); - cls_set_class(&f->res.class, tp->q->ops->cl_ops->bind_tcf(tp->q, base, f->res.classid)); + cls_set_class(tp, &f->res.class, tp->q->ops->cl_ops->bind_tcf(tp->q, base, f->res.classid)); } #ifdef CONFIG_NET_CLS_POLICE @@ -254,8 +257,9 @@ #endif f->next = head->ht[fw_hash(handle)]; - wmb(); + tcf_tree_lock(tp); head->ht[fw_hash(handle)] = f; + tcf_tree_unlock(tp); *arg = (unsigned long)f; return 0; @@ -294,7 +298,6 @@ } } -#ifdef CONFIG_RTNETLINK static int fw_dump(struct tcf_proto *tp, unsigned long fh, struct sk_buff *skb, struct tcmsg *t) { @@ -335,7 +338,8 @@ rta->rta_len = skb->tail - b; #ifdef CONFIG_NET_CLS_POLICE if (f->police) { - RTA_PUT(skb, TCA_STATS, sizeof(struct tc_stats), &f->police->stats); + if (qdisc_copy_stats(skb, &f->police->stats)) + goto rtattr_failure; } #endif return skb->len; @@ -344,8 +348,6 @@ skb_trim(skb, b - skb->data); return -1; } -#endif - struct tcf_proto_ops cls_fw_ops = { NULL, @@ -359,11 +361,7 @@ fw_change, fw_delete, fw_walk, -#ifdef CONFIG_RTNETLINK fw_dump -#else - NULL -#endif }; #ifdef MODULE diff -urN ../v2.2.21-ds8/linux/net/sched/cls_route.c linux/net/sched/cls_route.c --- ../v2.2.21-ds8/linux/net/sched/cls_route.c Sat Oct 21 15:10:50 2000 +++ linux/net/sched/cls_route.c Sun Aug 4 20:08:47 2002 @@ -83,11 +83,11 @@ return id&0xF; } -static void route4_reset_fastmap(struct route4_head *head, u32 id) +static void route4_reset_fastmap(struct device *dev, struct route4_head *head, u32 id) { - start_bh_atomic(); + sch_dev_queue_lock(dev); memset(head->fastmap, 0, sizeof(head->fastmap)); - end_bh_atomic(); + sch_dev_queue_unlock(dev); } static void __inline__ @@ -297,7 +297,7 @@ unsigned long cl; b->ht[h2] = f->next; - if ((cl = cls_set_class(&f->res.class, 0)) != 0) + if ((cl = __cls_set_class(&f->res.class, 0)) != 0) tp->q->ops->cl_ops->unbind_tcf(tp->q, cl); #ifdef CONFIG_NET_CLS_POLICE tcf_police_release(f->police); @@ -316,25 +316,27 @@ { struct route4_head *head = (struct route4_head*)tp->root; struct route4_filter **fp, *f = (struct route4_filter*)arg; - unsigned h = f->handle; + unsigned h = 0; struct route4_bucket *b; int i; if (!head || !f) return -EINVAL; + h = f->handle; b = f->bkt; for (fp = &b->ht[from_hash(h>>16)]; *fp; fp = &(*fp)->next) { if (*fp == f) { unsigned long cl; + tcf_tree_lock(tp); *fp = f->next; - synchronize_bh(); + tcf_tree_unlock(tp); - route4_reset_fastmap(head, f->id); + route4_reset_fastmap(tp->q->dev, head, f->id); - if ((cl = cls_set_class(&f->res.class, 0)) != 0) + if ((cl = cls_set_class(tp, &f->res.class, 0)) != 0) tp->q->ops->cl_ops->unbind_tcf(tp->q, cl); #ifdef CONFIG_NET_CLS_POLICE @@ -349,8 +351,9 @@ return 0; /* OK, session has no flows */ + tcf_tree_lock(tp); head->table[to_hash(h)] = NULL; - synchronize_bh(); + tcf_tree_unlock(tp); kfree(b); return 0; @@ -387,7 +390,7 @@ unsigned long cl; f->res.classid = *(u32*)RTA_DATA(tb[TCA_ROUTE4_CLASSID-1]); - cl = cls_set_class(&f->res.class, tp->q->ops->cl_ops->bind_tcf(tp->q, base, f->res.classid)); + cl = cls_set_class(tp, &f->res.class, tp->q->ops->cl_ops->bind_tcf(tp->q, base, f->res.classid)); if (cl) tp->q->ops->cl_ops->unbind_tcf(tp->q, cl); } @@ -395,8 +398,9 @@ if (tb[TCA_ROUTE4_POLICE-1]) { struct tcf_police *police = tcf_police_locate(tb[TCA_ROUTE4_POLICE-1], tca[TCA_RATE-1]); + tcf_tree_lock(tp); police = xchg(&f->police, police); - synchronize_bh(); + tcf_tree_unlock(tp); tcf_police_release(police); } @@ -412,8 +416,9 @@ return -ENOBUFS; memset(head, 0, sizeof(struct route4_head)); + tcf_tree_lock(tp); tp->root = head; - synchronize_bh(); + tcf_tree_unlock(tp); } f = kmalloc(sizeof(struct route4_filter), GFP_KERNEL); @@ -475,8 +480,9 @@ goto errout; memset(b, 0, sizeof(*b)); + tcf_tree_lock(tp); head->table[h1] = b; - synchronize_bh(); + tcf_tree_unlock(tp); } f->bkt = b; @@ -489,17 +495,18 @@ goto errout; } - cls_set_class(&f->res.class, tp->q->ops->cl_ops->bind_tcf(tp->q, base, f->res.classid)); + cls_set_class(tp, &f->res.class, tp->q->ops->cl_ops->bind_tcf(tp->q, base, f->res.classid)); #ifdef CONFIG_NET_CLS_POLICE if (tb[TCA_ROUTE4_POLICE-1]) f->police = tcf_police_locate(tb[TCA_ROUTE4_POLICE-1], tca[TCA_RATE-1]); #endif f->next = f1; - wmb(); + tcf_tree_lock(tp); *ins_f = f; + tcf_tree_unlock(tp); - route4_reset_fastmap(head, f->id); + route4_reset_fastmap(tp->q->dev, head, f->id); *arg = (unsigned long)f; return 0; @@ -543,7 +550,6 @@ } } -#ifdef CONFIG_RTNETLINK static int route4_dump(struct tcf_proto *tp, unsigned long fh, struct sk_buff *skb, struct tcmsg *t) { @@ -589,7 +595,8 @@ rta->rta_len = skb->tail - b; #ifdef CONFIG_NET_CLS_POLICE if (f->police) { - RTA_PUT(skb, TCA_STATS, sizeof(struct tc_stats), &f->police->stats); + if (qdisc_copy_stats(skb, &f->police->stats)) + goto rtattr_failure; } #endif return skb->len; @@ -598,7 +605,6 @@ skb_trim(skb, b - skb->data); return -1; } -#endif struct tcf_proto_ops cls_route4_ops = { NULL, @@ -612,11 +618,7 @@ route4_change, route4_delete, route4_walk, -#ifdef CONFIG_RTNETLINK route4_dump -#else - NULL -#endif }; #ifdef MODULE @@ -630,3 +632,4 @@ unregister_tcf_proto_ops(&cls_route4_ops); } #endif +MODULE_LICENSE("GPL"); diff -urN ../v2.2.21-ds8/linux/net/sched/cls_rsvp.c linux/net/sched/cls_rsvp.c --- ../v2.2.21-ds8/linux/net/sched/cls_rsvp.c Thu Apr 30 08:46:59 1998 +++ linux/net/sched/cls_rsvp.c Tue Nov 13 03:29:33 2001 @@ -39,3 +39,4 @@ #define RSVP_OPS cls_rsvp_ops #include "cls_rsvp.h" +MODULE_LICENSE("GPL"); diff -urN ../v2.2.21-ds8/linux/net/sched/cls_rsvp.h linux/net/sched/cls_rsvp.h --- ../v2.2.21-ds8/linux/net/sched/cls_rsvp.h Sat Oct 21 15:10:57 2000 +++ linux/net/sched/cls_rsvp.h Sun Mar 31 06:18:28 2002 @@ -282,7 +282,7 @@ unsigned long cl; s->ht[h2] = f->next; - if ((cl = cls_set_class(&f->res.class, 0)) != 0) + if ((cl = __cls_set_class(&f->res.class, 0)) != 0) tp->q->ops->cl_ops->unbind_tcf(tp->q, cl); #ifdef CONFIG_NET_CLS_POLICE tcf_police_release(f->police); @@ -310,10 +310,11 @@ unsigned long cl; + tcf_tree_lock(tp); *fp = f->next; - synchronize_bh(); + tcf_tree_unlock(tp); - if ((cl = cls_set_class(&f->res.class, 0)) != 0) + if ((cl = cls_set_class(tp, &f->res.class, 0)) != 0) tp->q->ops->cl_ops->unbind_tcf(tp->q, cl); #ifdef CONFIG_NET_CLS_POLICE @@ -332,8 +333,9 @@ for (sp = &((struct rsvp_head*)tp->root)->ht[h&0xFF]; *sp; sp = &(*sp)->next) { if (*sp == s) { + tcf_tree_lock(tp); *sp = s->next; - synchronize_bh(); + tcf_tree_unlock(tp); kfree(s); return 0; @@ -446,7 +448,7 @@ unsigned long cl; f->res.classid = *(u32*)RTA_DATA(tb[TCA_RSVP_CLASSID-1]); - cl = cls_set_class(&f->res.class, tp->q->ops->cl_ops->bind_tcf(tp->q, base, f->res.classid)); + cl = cls_set_class(tp, &f->res.class, tp->q->ops->cl_ops->bind_tcf(tp->q, base, f->res.classid)); if (cl) tp->q->ops->cl_ops->unbind_tcf(tp->q, cl); } @@ -454,8 +456,9 @@ if (tb[TCA_RSVP_POLICE-1]) { struct tcf_police *police = tcf_police_locate(tb[TCA_RSVP_POLICE-1], tca[TCA_RATE-1]); + tcf_tree_lock(tp); police = xchg(&f->police, police); - synchronize_bh(); + tcf_tree_unlock(tp); tcf_police_release(police); } @@ -536,7 +539,7 @@ f->sess = s; if (f->tunnelhdr == 0) - cls_set_class(&f->res.class, tp->q->ops->cl_ops->bind_tcf(tp->q, base, f->res.classid)); + cls_set_class(tp, &f->res.class, tp->q->ops->cl_ops->bind_tcf(tp->q, base, f->res.classid)); #ifdef CONFIG_NET_CLS_POLICE if (tb[TCA_RSVP_POLICE-1]) f->police = tcf_police_locate(tb[TCA_RSVP_POLICE-1], tca[TCA_RATE-1]); @@ -612,7 +615,6 @@ } } -#ifdef CONFIG_RTNETLINK static int rsvp_dump(struct tcf_proto *tp, unsigned long fh, struct sk_buff *skb, struct tcmsg *t) { @@ -659,7 +661,8 @@ rta->rta_len = skb->tail - b; #ifdef CONFIG_NET_CLS_POLICE if (f->police) { - RTA_PUT(skb, TCA_STATS, sizeof(struct tc_stats), &f->police->stats); + if (qdisc_copy_stats(skb, &f->police->stats)) + goto rtattr_failure; } #endif return skb->len; @@ -668,7 +671,6 @@ skb_trim(skb, b - skb->data); return -1; } -#endif struct tcf_proto_ops RSVP_OPS = { NULL, @@ -682,11 +684,7 @@ rsvp_change, rsvp_delete, rsvp_walk, -#ifdef CONFIG_RTNETLINK rsvp_dump -#else - NULL -#endif }; #ifdef MODULE diff -urN ../v2.2.21-ds8/linux/net/sched/cls_rsvp6.c linux/net/sched/cls_rsvp6.c --- ../v2.2.21-ds8/linux/net/sched/cls_rsvp6.c Thu Apr 30 08:46:59 1998 +++ linux/net/sched/cls_rsvp6.c Tue Nov 13 03:29:33 2001 @@ -40,3 +40,4 @@ #define RSVP_OPS cls_rsvp6_ops #include "cls_rsvp.h" +MODULE_LICENSE("GPL"); diff -urN ../v2.2.21-ds8/linux/net/sched/cls_tcindex.c linux/net/sched/cls_tcindex.c --- ../v2.2.21-ds8/linux/net/sched/cls_tcindex.c Wed Jul 31 03:00:59 2002 +++ linux/net/sched/cls_tcindex.c Sun Mar 31 06:18:28 2002 @@ -4,6 +4,7 @@ * Written 1998,1999 by Werner Almesberger, EPFL ICA */ +#include #include #include #include @@ -75,11 +76,13 @@ struct tcindex_filter *f; if (p->perfect) - return p->perfect[key].res.classid ? p->perfect+key : NULL; - if (!p->h) return NULL; - for (f = p->h[key % p->hash]; f; f = f->next) + return p->perfect[key].res.class ? p->perfect+key : NULL; + if (!p->h) + return NULL; + for (f = p->h[key % p->hash]; f; f = f->next) { if (f->key == key) return &f->result; + } return NULL; } @@ -92,13 +95,10 @@ D2PRINTK("tcindex_classify(skb %p,tp %p,res %p),p %p\n",skb,tp,res,p); -/* -printk("tc_index 0x%x, mask 0x%x, shift %d, res 0x%x\n",skb->tc_index, - p->mask,p->shift,(skb->tc_index & p->mask) >> p->shift); -*/ f = lookup(p,(skb->tc_index & p->mask) >> p->shift); if (!f) { - if (!p->fall_through) return -1; + if (!p->fall_through) + return -1; res->classid = TC_H_MAKE(TC_H_MAJ(tp->q->handle), (skb->tc_index& p->mask) >> p->shift); res->class = 0; @@ -122,8 +122,14 @@ static unsigned long tcindex_get(struct tcf_proto *tp, u32 handle) { + struct tcindex_data *p = PRIV(tp); + struct tcindex_filter_result *r; + DPRINTK("tcindex_get(tp %p,handle 0x%08x)\n",tp,handle); - return (unsigned long) lookup(PRIV(tp),handle); + if (p->perfect && handle >= p->alloc_hash) + return 0; + r = lookup(PRIV(tp),handle); + return r && r->res.class ? (unsigned long) r : 0; } @@ -164,24 +170,32 @@ DPRINTK("tcindex_delete(tp %p,arg 0x%lx),p %p,f %p\n",tp,arg,p,f); if (p->perfect) { - if (!r->res.classid) return -ENOENT; - } - else { + if (!r->res.class) + return -ENOENT; + } else { int i; struct tcindex_filter **walk = NULL; - for (i = 0; !f && i < p->hash; i++) - for (walk = p->h+i; !f && *walk; walk = &(*walk)->next) - if (&(*walk)->result == r) f = *walk; - if (!f) return -ENOENT; + for (i = 0; i < p->hash; i++) + for (walk = p->h+i; *walk; walk = &(*walk)->next) + if (&(*walk)->result == r) + goto found; + return -ENOENT; + +found: + f = *walk; + tcf_tree_lock(tp); *walk = f->next; + tcf_tree_unlock(tp); } - cl = cls_set_class(&r->res.class,0); - if (cl) tp->q->ops->cl_ops->unbind_tcf(tp->q,cl); + cl = __cls_set_class(&r->res.class,0); + if (cl) + tp->q->ops->cl_ops->unbind_tcf(tp->q,cl); #ifdef CONFIG_NET_CLS_POLICE tcf_police_release(r->police); #endif - if (f) kfree(f); + if (f) + kfree(f); return 0; } @@ -204,36 +218,47 @@ struct tcindex_filter *f; struct tcindex_filter_result *r = (struct tcindex_filter_result *) *arg; struct tcindex_filter **walk; - int hash; + int hash,shift; __u16 mask; DPRINTK("tcindex_change(tp %p,handle 0x%08x,tca %p,arg %p),opt %p," "p %p,r %p\n",tp,handle,tca,arg,opt,p,r); - if (arg) DPRINTK("*arg = 0x%lx\n",*arg); - if (!opt) return 0; + if (arg) + DPRINTK("*arg = 0x%lx\n",*arg); + if (!opt) + return 0; if (rtattr_parse(tb,TCA_TCINDEX_MAX,RTA_DATA(opt),RTA_PAYLOAD(opt)) < 0) return -EINVAL; - if (!tb[TCA_TCINDEX_HASH-1]) hash = p->hash; - else { + if (!tb[TCA_TCINDEX_HASH-1]) { + hash = p->hash; + } else { if (RTA_PAYLOAD(tb[TCA_TCINDEX_HASH-1]) < sizeof(int)) return -EINVAL; hash = *(int *) RTA_DATA(tb[TCA_TCINDEX_HASH-1]); } - if (!tb[TCA_TCINDEX_MASK-1]) mask = p->mask; - else { + if (!tb[TCA_TCINDEX_MASK-1]) { + mask = p->mask; + } else { if (RTA_PAYLOAD(tb[TCA_TCINDEX_MASK-1]) < sizeof(__u16)) return -EINVAL; mask = *(__u16 *) RTA_DATA(tb[TCA_TCINDEX_MASK-1]); } - if (p->perfect && hash <= mask) return -EBUSY; - if ((p->perfect || p->h) && hash > p->alloc_hash) return -EBUSY; - p->hash = hash; - p->mask = mask; - if (tb[TCA_TCINDEX_SHIFT-1]) { + if (!tb[TCA_TCINDEX_SHIFT-1]) + shift = p->shift; + else { if (RTA_PAYLOAD(tb[TCA_TCINDEX_SHIFT-1]) < sizeof(__u16)) return -EINVAL; - p->shift = *(int *) RTA_DATA(tb[TCA_TCINDEX_SHIFT-1]); + shift = *(int *) RTA_DATA(tb[TCA_TCINDEX_SHIFT-1]); } + if (p->perfect && hash <= (mask >> shift)) + return -EBUSY; + if (p->perfect && hash > p->alloc_hash) + return -EBUSY; + if (p->h && hash != p->alloc_hash) + return -EBUSY; + p->hash = hash; + p->mask = mask; + p->shift = shift; if (tb[TCA_TCINDEX_FALL_THROUGH-1]) { if (RTA_PAYLOAD(tb[TCA_TCINDEX_FALL_THROUGH-1]) < sizeof(int)) return -EINVAL; @@ -242,68 +267,87 @@ } DPRINTK("classid/police %p/%p\n",tb[TCA_TCINDEX_CLASSID-1], tb[TCA_TCINDEX_POLICE-1]); - if (!tb[TCA_TCINDEX_CLASSID-1] && !tb[TCA_TCINDEX_POLICE-1]) return 0; - if (!p->hash) { - if (p->mask < PERFECT_HASH_THRESHOLD) - p->hash = p->mask+1; - else + if (!tb[TCA_TCINDEX_CLASSID-1] && !tb[TCA_TCINDEX_POLICE-1]) + return 0; + if (!hash) { + if ((mask >> shift) < PERFECT_HASH_THRESHOLD) { + p->hash = (mask >> shift)+1; + } else { p->hash = DEFAULT_HASH_SIZE; + } } if (!p->perfect && !p->h) { p->alloc_hash = p->hash; DPRINTK("hash %d mask %d\n",p->hash,p->mask); - if (p->hash > p->mask) { + if (p->hash > (mask >> shift)) { p->perfect = kmalloc(p->hash* sizeof(struct tcindex_filter_result),GFP_KERNEL); - if (!p->perfect) return -ENOMEM; - memset(p->perfect,0,p->hash* - sizeof(struct tcindex_filter_result)); - } - else { + if (!p->perfect) + return -ENOMEM; + memset(p->perfect, 0, + p->hash * sizeof(struct tcindex_filter_result)); + } else { p->h = kmalloc(p->hash*sizeof(struct tcindex_filter *), GFP_KERNEL); - if (!p->h) return -ENOMEM; - memset(p->h,0,p->hash*sizeof(struct tcindex_filter *)); + if (!p->h) + return -ENOMEM; + memset(p->h, 0, p->hash*sizeof(struct tcindex_filter *)); } } - if (handle > p->mask) return -EINVAL; - if (p->perfect) r = p->perfect+handle; - else { + /* + * Note: this could be as restrictive as + * if (handle & ~(mask >> shift)) + * but then, we'd fail handles that may become valid after some + * future mask change. While this is extremely unlikely to ever + * matter, the check below is safer (and also more + * backwards-compatible). + */ + if (p->perfect && handle >= p->alloc_hash) + return -EINVAL; + if (p->perfect) { + r = p->perfect+handle; + } else { r = lookup(p,handle); DPRINTK("r=%p\n",r); - if (!r) r = &new_filter_result; + if (!r) + r = &new_filter_result; } DPRINTK("r=%p\n",r); if (tb[TCA_TCINDEX_CLASSID-1]) { - unsigned long cl = cls_set_class(&r->res.class,0); + unsigned long cl = cls_set_class(tp,&r->res.class,0); - if (cl) tp->q->ops->cl_ops->unbind_tcf(tp->q,cl); + if (cl) + tp->q->ops->cl_ops->unbind_tcf(tp->q,cl); r->res.classid = *(__u32 *) RTA_DATA(tb[TCA_TCINDEX_CLASSID-1]); r->res.class = tp->q->ops->cl_ops->bind_tcf(tp->q,base, - r->res.classid); + r->res.classid); if (!r->res.class) { r->res.classid = 0; return -ENOENT; } } #ifdef CONFIG_NET_CLS_POLICE - if (!tb[TCA_TCINDEX_POLICE-1]) r->police = NULL; - else { - struct tcf_police *police = - tcf_police_locate(tb[TCA_TCINDEX_POLICE-1],NULL); + { + struct tcf_police *police; + police = tb[TCA_TCINDEX_POLICE-1] ? + tcf_police_locate(tb[TCA_TCINDEX_POLICE-1],NULL) : NULL; + tcf_tree_lock(tp); police = xchg(&r->police,police); - synchronize_bh(); + tcf_tree_unlock(tp); tcf_police_release(police); - } + } #endif - if (r != &new_filter_result) return 0; + if (r != &new_filter_result) + return 0; f = kmalloc(sizeof(struct tcindex_filter),GFP_KERNEL); - if (!f) return -ENOMEM; + if (!f) + return -ENOMEM; f->key = handle; f->result = new_filter_result; f->next = NULL; - for (walk = p->h+(handle % p->hash); *walk; walk = &(*walk)->next); + for (walk = p->h+(handle % p->hash); *walk; walk = &(*walk)->next) + /* nothing */; wmb(); *walk = f; return 0; @@ -313,33 +357,40 @@ static void tcindex_walk(struct tcf_proto *tp, struct tcf_walker *walker) { struct tcindex_data *p = PRIV(tp); - struct tcindex_filter *f; + struct tcindex_filter *f,*next; int i; DPRINTK("tcindex_walk(tp %p,walker %p),p %p\n",tp,walker,p); - if (p->perfect) + if (p->perfect) { for (i = 0; i < p->hash; i++) { - if (!p->perfect[i].res.classid) continue; - if (walker->count >= walker->skip) + if (!p->perfect[i].res.class) + continue; + if (walker->count >= walker->skip) { if (walker->fn(tp, (unsigned long) (p->perfect+i), walker) < 0) { walker->stop = 1; return; } + } walker->count++; } - if (!p->h) return; - for (i = 0; i < p->hash; i++) - for (f = p->h[i]; f; f = f->next) { - if (walker->count >= walker->skip) + } + if (!p->h) + return; + for (i = 0; i < p->hash; i++) { + for (f = p->h[i]; f; f = next) { + next = f->next; + if (walker->count >= walker->skip) { if (walker->fn(tp,(unsigned long) &f->result, walker) < 0) { walker->stop = 1; return; } + } walker->count++; } + } } @@ -360,16 +411,16 @@ walker.skip = 0; walker.fn = &tcindex_destroy_element; tcindex_walk(tp,&walker); - if (p->perfect) kfree(p->perfect); - if (p->h) kfree(p->h); + if (p->perfect) + kfree(p->perfect); + if (p->h) + kfree(p->h); kfree(p); tp->root = NULL; MOD_DEC_USE_COUNT; } -#ifdef CONFIG_RTNETLINK - static int tcindex_dump(struct tcf_proto *tp, unsigned long fh, struct sk_buff *skb, struct tcmsg *t) { @@ -390,23 +441,25 @@ RTA_PUT(skb,TCA_TCINDEX_SHIFT,sizeof(p->shift),&p->shift); RTA_PUT(skb,TCA_TCINDEX_FALL_THROUGH,sizeof(p->fall_through), &p->fall_through); - } - else { - if (p->perfect) t->tcm_handle = r-p->perfect; - else { + } else { + if (p->perfect) { + t->tcm_handle = r-p->perfect; + } else { struct tcindex_filter *f; int i; t->tcm_handle = 0; - for (i = 0; !t->tcm_handle && i < p->hash; i++) + for (i = 0; !t->tcm_handle && i < p->hash; i++) { for (f = p->h[i]; !t->tcm_handle && f; - f = f->next) + f = f->next) { if (&f->result == r) t->tcm_handle = f->key; + } + } } DPRINTK("handle = %d\n",t->tcm_handle); - if (r->res.class) RTA_PUT(skb,TCA_TCINDEX_CLASSID,4, - &r->res.classid); + if (r->res.class) + RTA_PUT(skb, TCA_TCINDEX_CLASSID, 4, &r->res.classid); #ifdef CONFIG_NET_CLS_POLICE if (r->police) { struct rtattr *p_rta = (struct rtattr *) skb->tail; @@ -422,13 +475,10 @@ return skb->len; rtattr_failure: - skb_trim(skb,b-skb->data); + skb_trim(skb, b - skb->data); return -1; } -#endif - - struct tcf_proto_ops cls_tcindex_ops = { NULL, "tcindex", @@ -441,22 +491,19 @@ tcindex_change, tcindex_delete, tcindex_walk, -#ifdef CONFIG_RTNETLINK tcindex_dump -#else - NULL -#endif }; + #ifdef MODULE int init_module(void) { return register_tcf_proto_ops(&cls_tcindex_ops); } -void cleanup_module(void) +void cleanup_module(void) { unregister_tcf_proto_ops(&cls_tcindex_ops); } #endif - +MODULE_LICENSE("GPL"); diff -urN ../v2.2.21-ds8/linux/net/sched/cls_u32.c linux/net/sched/cls_u32.c --- ../v2.2.21-ds8/linux/net/sched/cls_u32.c Sat Aug 4 15:52:33 2001 +++ linux/net/sched/cls_u32.c Sun Mar 31 06:18:28 2002 @@ -52,8 +52,6 @@ #include #include -#define BUG_TRAP(x) if (!(x)) { printk("Assertion (" #x ") failed at " __FILE__ "(%d):" __FUNCTION__ "\n", __LINE__); } - struct tc_u_knode { @@ -164,7 +162,7 @@ if (!(n->sel.flags&(TC_U32_VAROFFSET|TC_U32_OFFSET|TC_U32_EAT))) goto next_ht; - if (n->sel.flags&(TC_U32_EAT|TC_U32_VAROFFSET)) { + if (n->sel.flags&(TC_U32_OFFSET|TC_U32_VAROFFSET)) { off2 = n->sel.off + 3; if (n->sel.flags&TC_U32_VAROFFSET) off2 += ntohs(n->sel.offmask & *(u16*)(ptr+n->sel.offoff)) >>n->sel.offshift; @@ -307,7 +305,7 @@ { unsigned long cl; - if ((cl = cls_set_class(&n->res.class, 0)) != 0) + if ((cl = __cls_set_class(&n->res.class, 0)) != 0) tp->q->ops->cl_ops->unbind_tcf(tp->q, cl); #ifdef CONFIG_NET_CLS_POLICE tcf_police_release(n->police); @@ -326,8 +324,9 @@ if (ht) { for (kp = &ht->ht[TC_U32_HASH(key->handle)]; *kp; kp = &(*kp)->next) { if (*kp == key) { + tcf_tree_lock(tp); *kp = key->next; - synchronize_bh(); + tcf_tree_unlock(tp); u32_destroy_key(tp, key); return 0; @@ -346,7 +345,6 @@ for (h=0; h<=ht->divisor; h++) { while ((n = ht->ht[h]) != NULL) { ht->ht[h] = n->next; - synchronize_bh(); u32_destroy_key(tp, n); } @@ -465,8 +463,9 @@ ht_down->refcnt++; } + sch_tree_lock(q); ht_down = xchg(&n->ht_down, ht_down); - synchronize_bh(); + sch_tree_unlock(q); if (ht_down) ht_down->refcnt--; @@ -475,7 +474,9 @@ unsigned long cl; n->res.classid = *(u32*)RTA_DATA(tb[TCA_U32_CLASSID-1]); - cl = cls_set_class(&n->res.class, q->ops->cl_ops->bind_tcf(q, base, n->res.classid)); + sch_tree_lock(q); + cl = __cls_set_class(&n->res.class, q->ops->cl_ops->bind_tcf(q, base, n->res.classid)); + sch_tree_unlock(q); if (cl) q->ops->cl_ops->unbind_tcf(q, cl); } @@ -483,8 +484,9 @@ if (tb[TCA_U32_POLICE-1]) { struct tcf_police *police = tcf_police_locate(tb[TCA_U32_POLICE-1], est); + sch_tree_lock(q); police = xchg(&n->police, police); - synchronize_bh(); + sch_tree_unlock(q); tcf_police_release(police); } @@ -633,7 +635,6 @@ } } -#ifdef CONFIG_RTNETLINK static int u32_dump(struct tcf_proto *tp, unsigned long fh, struct sk_buff *skb, struct tcmsg *t) { @@ -682,7 +683,8 @@ rta->rta_len = skb->tail - b; #ifdef CONFIG_NET_CLS_POLICE if (TC_U32_KEY(n->handle) && n->police) { - RTA_PUT(skb, TCA_STATS, sizeof(struct tc_stats), &n->police->stats); + if (qdisc_copy_stats(skb, &n->police->stats)) + goto rtattr_failure; } #endif return skb->len; @@ -691,7 +693,6 @@ skb_trim(skb, b - skb->data); return -1; } -#endif struct tcf_proto_ops cls_u32_ops = { NULL, @@ -705,11 +706,7 @@ u32_change, u32_delete, u32_walk, -#ifdef CONFIG_RTNETLINK u32_dump -#else - NULL -#endif }; #ifdef MODULE @@ -723,3 +720,4 @@ unregister_tcf_proto_ops(&cls_u32_ops); } #endif +MODULE_LICENSE("GPL"); diff -urN ../v2.2.21-ds8/linux/net/sched/police.c linux/net/sched/police.c --- ../v2.2.21-ds8/linux/net/sched/police.c Sat Oct 21 15:10:47 2000 +++ linux/net/sched/police.c Thu Aug 8 02:28:12 2002 @@ -31,8 +31,6 @@ #include #include -#define BUG_TRAP(x) if (!(x)) { printk("Assertion (" #x ") failed at " __FILE__ "(%d):" __FUNCTION__ "\n", __LINE__); } - #define L2T(p,L) ((p)->R_tab->data[(L)>>(p)->R_tab->rate.cell_log]) #define L2T_P(p,L) ((p)->P_tab->data[(L)>>(p)->P_tab->rate.cell_log]) @@ -74,6 +72,7 @@ for (p1p = &tcf_police_ht[h]; *p1p; p1p = &(*p1p)->next) { if (*p1p == p) { *p1p = p->next; + synchronize_bh(); #ifdef CONFIG_NET_ESTIMATOR qdisc_kill_estimator(&p->stats); #endif @@ -145,7 +144,9 @@ #endif h = tcf_police_hash(p->index); p->next = tcf_police_ht[h]; + wmb(); tcf_police_ht[h] = p; + synchronize_bh(); return p; failure: diff -urN ../v2.2.21-ds8/linux/net/sched/sch_api.c linux/net/sched/sch_api.c --- ../v2.2.21-ds8/linux/net/sched/sch_api.c Wed Jul 31 03:00:59 2002 +++ linux/net/sched/sch_api.c Thu Aug 8 02:27:29 2002 @@ -44,15 +44,11 @@ #include #include -#define BUG_TRAP(x) if (!(x)) { printk("Assertion (" #x ") failed at " __FILE__ "(%d):" __FUNCTION__ "\n", __LINE__); } - #ifdef CONFIG_RTNETLINK static int qdisc_notify(struct sk_buff *oskb, struct nlmsghdr *n, u32 clid, struct Qdisc *old, struct Qdisc *new); static int tclass_notify(struct sk_buff *oskb, struct nlmsghdr *n, struct Qdisc *q, unsigned long cl, int event); -static int qdisc_append (struct sk_buff *oskb, struct nlmsghdr *n, u32 clid, - struct Qdisc *q,struct rtattr **tca); #endif /* @@ -101,9 +97,15 @@ ---enqueue - enqueue returns number of enqueued packets i.e. this number is 1, - if packet was enqueued successfully and <1 if something (not - necessary THIS packet) was dropped. + enqueue returns 0, if packet was enqueued successfully. + If packet (this one or another one) was dropped, it returns + not zero error code. + NET_XMIT_DROP - this packet dropped + Expected action: do not backoff, but wait until queue will clear. + NET_XMIT_CN - probably this packet enqueued, but another one dropped. + Expected action: backoff or ignore + NET_XMIT_POLICED - dropped by police. + Expected action: backoff or error to real-time apps. Auxiliary routines: @@ -145,9 +147,11 @@ { struct Qdisc_ops *q, **qp; - for (qp = &qdisc_base; (q=*qp)!=NULL; qp = &q->next) - if (strcmp(qops->id, q->id) == 0) + for (qp = &qdisc_base; (q=*qp)!=NULL; qp = &q->next) { + if (strcmp(qops->id, q->id) == 0) { return -EEXIST; + } + } if (qops->enqueue == NULL) qops->enqueue = noop_qdisc_ops.enqueue; @@ -164,14 +168,17 @@ int unregister_qdisc(struct Qdisc_ops *qops) { struct Qdisc_ops *q, **qp; + int err = -ENOENT; + for (qp = &qdisc_base; (q=*qp)!=NULL; qp = &q->next) if (q == qops) break; - if (!q) - return -ENOENT; - *qp = q->next; - q->next = NULL; - return 0; + if (q) { + *qp = q->next; + q->next = NULL; + err = 0; + } + return err; } /* We know handle. Find qdisc among all qdisc's attached to device @@ -198,6 +205,7 @@ if (cops == NULL) return NULL; cl = cops->get(p, classid); + if (cl == 0) return NULL; leaf = cops->leaf(p, cl); @@ -209,15 +217,15 @@ struct Qdisc_ops *qdisc_lookup_ops(struct rtattr *kind) { - struct Qdisc_ops *q; + struct Qdisc_ops *q = NULL; if (kind) { for (q = qdisc_base; q; q = q->next) { if (rtattr_strcmp(kind, q->id) == 0) - return q; + break; } } - return NULL; + return q; } static struct qdisc_rate_table *qdisc_rtab_list; @@ -273,7 +281,7 @@ do { autohandle += TC_H_MAKE(0x10000U, 0); - if ((autohandle == TC_H_MAKE(TC_H_ROOT, 0))|| (autohandle == TC_H_MAKE(TC_H_INGRESS, 0))) + if (autohandle == TC_H_MAKE(TC_H_ROOT, 0)) autohandle = TC_H_MAKE(0x80000000U, 0); } while (qdisc_lookup(dev, autohandle) && --i > 0); @@ -283,24 +291,27 @@ /* Attach toplevel qdisc to device dev */ static struct Qdisc * -dev_graft_qdisc(struct device *dev, struct Qdisc *qdisc, int ingress) +dev_graft_qdisc(struct device *dev, struct Qdisc *qdisc) { struct Qdisc *oqdisc; if (dev->flags & IFF_UP) dev_deactivate(dev); - start_bh_atomic(); - - if (ingress) { + if (qdisc && qdisc->flags&TCQ_F_INGRES) { oqdisc = dev->qdisc_ingress; /* Prune old scheduler */ - if (oqdisc && atomic_read(&oqdisc->refcnt) <= 1) + if (oqdisc && atomic_read(&oqdisc->refcnt) <= 1) { + /* delete */ qdisc_reset(oqdisc); + dev->qdisc_ingress = NULL; + } else { /* new */ + dev->qdisc_ingress = qdisc; + } - dev->qdisc_ingress = qdisc; } else { + oqdisc = dev->qdisc_sleeping; /* Prune old scheduler */ @@ -310,7 +321,6 @@ /* ... and graft new one */ if (qdisc == NULL) qdisc = &noop_qdisc; - dev->qdisc_sleeping = qdisc; dev->qdisc = &noop_qdisc; } @@ -331,12 +341,18 @@ */ int qdisc_graft(struct device *dev, struct Qdisc *parent, u32 classid, - struct Qdisc *new, struct Qdisc **old,int type) + struct Qdisc *new, struct Qdisc **old) { int err = 0; + struct Qdisc *q = *old; - if (parent == NULL) { - *old = dev_graft_qdisc(dev, new, type); + + if (parent == NULL) { + if (q && q->flags&TCQ_F_INGRES) { + *old = dev_graft_qdisc(dev, q); + } else { + *old = dev_graft_qdisc(dev, new); + } } else { struct Qdisc_class_ops *cops = parent->ops->cl_ops; @@ -353,8 +369,6 @@ return err; } -#ifdef CONFIG_RTNETLINK - /* Allocate and initialize new qdisc. @@ -395,24 +409,23 @@ goto err_out; /* Grrr... Resolve race condition with module unload */ - + err = -EINVAL; if (ops != qdisc_lookup_ops(kind)) goto err_out; memset(sch, 0, size); + skb_queue_head_init(&sch->q); + if (handle == TC_H_INGRESS) - sch->ingress=1; - else - skb_queue_head_init(&sch->q); + sch->flags |= TCQ_F_INGRES; sch->ops = ops; sch->enqueue = ops->enqueue; sch->dequeue = ops->dequeue; sch->dev = dev; atomic_set(&sch->refcnt, 1); - if (handle == 0) { handle = qdisc_alloc_handle(dev); err = -ENOMEM; @@ -420,10 +433,10 @@ goto err_out; } - if (handle == TC_H_INGRESS) - sch->handle =TC_H_MAKE(TC_H_INGRESS, 0); - else - sch->handle = handle; + if (handle == TC_H_INGRESS) + sch->handle =TC_H_MAKE(TC_H_INGRESS, 0); + else + sch->handle = handle; if (!ops->init || (err = ops->init(sch, tca[TCA_OPTIONS-1])) == 0) { sch->next = dev->qdisc_list; @@ -522,17 +535,15 @@ if (clid) { if (clid != TC_H_ROOT) { if (TC_H_MAJ(clid) != TC_H_MAJ(TC_H_INGRESS)) { - if ((p = qdisc_lookup(dev, TC_H_MAJ(clid))) == NULL) - return -ENOENT; - q = qdisc_leaf(p, clid); + if ((p = qdisc_lookup(dev, TC_H_MAJ(clid))) == NULL) + return -ENOENT; + q = qdisc_leaf(p, clid); } else { /* ingress */ - if (dev->qdisc_ingress) { - q=dev->qdisc_ingress; - } - } - } else + q = dev->qdisc_ingress; + } + } else { q = dev->qdisc_sleeping; - + } if (!q) return -ENOENT; @@ -543,7 +554,6 @@ return -ENOENT; } - if (tca[TCA_KIND-1] && rtattr_strcmp(tca[TCA_KIND-1], q->ops->id)) return -EINVAL; @@ -552,13 +562,13 @@ return -EINVAL; if (q->handle == 0) return -ENOENT; - - if ((err = qdisc_graft(dev, p, clid, NULL, &q,q->ingress)) != 0) + if ((err = qdisc_graft(dev, p, clid, NULL, &q)) != 0) return err; - if (q) { qdisc_notify(skb, n, clid, q, NULL); + sch_dev_queue_lock(dev); qdisc_destroy(q); + sch_dev_queue_unlock(dev); } } else { qdisc_notify(skb, n, clid, NULL, q); @@ -585,14 +595,13 @@ if (clid) { if (clid != TC_H_ROOT) { - if (clid != TC_H_INGRESS) { - if ((p = qdisc_lookup(dev, TC_H_MAJ(clid))) == NULL) - return -ENOENT; - q = qdisc_leaf(p, clid); - } else { /*ingress */ - if (dev->qdisc_ingress) - q=dev->qdisc_ingress; - } + if (clid != TC_H_INGRESS) { + if ((p = qdisc_lookup(dev, TC_H_MAJ(clid))) == NULL) + return -ENOENT; + q = qdisc_leaf(p, clid); + } else { /*ingress */ + q = dev->qdisc_ingress; + } } else { q = dev->qdisc_sleeping; } @@ -603,14 +612,12 @@ if (!q || !tcm->tcm_handle || q->handle != tcm->tcm_handle) { if (tcm->tcm_handle) { - if (q && !(n->nlmsg_flags&(NLM_F_REPLACE|NLM_F_APPEND))) + if (q && !(n->nlmsg_flags&NLM_F_REPLACE)) return -EEXIST; if (TC_H_MIN(tcm->tcm_handle)) return -EINVAL; if ((q = qdisc_lookup(dev, tcm->tcm_handle)) == NULL) goto create_n_graft; - if (q && (n->nlmsg_flags&NLM_F_APPEND)) - goto append; if (n->nlmsg_flags&NLM_F_EXCL) return -EEXIST; if (tca[TCA_KIND-1] && rtattr_strcmp(tca[TCA_KIND-1], q->ops->id)) @@ -656,12 +663,11 @@ return -EINVAL; q = qdisc_lookup(dev, tcm->tcm_handle); } + /* Change qdisc parameters */ if (q == NULL) return -ENOENT; - if (n->nlmsg_flags&NLM_F_APPEND) - goto append; - if (n->nlmsg_flags& NLM_F_EXCL ) + if (n->nlmsg_flags&NLM_F_EXCL) return -EEXIST; if (tca[TCA_KIND-1] && rtattr_strcmp(tca[TCA_KIND-1], q->ops->id)) return -EINVAL; @@ -674,31 +680,47 @@ if (!(n->nlmsg_flags&NLM_F_CREATE)) return -ENOENT; if (clid == TC_H_INGRESS) - q = qdisc_create(dev, tcm->tcm_parent, tca, &err); - else - q = qdisc_create(dev, tcm->tcm_handle, tca, &err); + q = qdisc_create(dev, tcm->tcm_parent, tca, &err); + else + q = qdisc_create(dev, tcm->tcm_handle, tca, &err); if (q == NULL) return err; graft: if (1) { struct Qdisc *old_q = NULL; - err = qdisc_graft(dev, p, clid, q, &old_q,q->ingress); + err = qdisc_graft(dev, p, clid, q, &old_q); if (err) { - if (q) + if (q) { + sch_dev_queue_lock(dev); qdisc_destroy(q); + sch_dev_queue_unlock(dev); + } return err; } qdisc_notify(skb, n, clid, old_q, q); - if (old_q) + if (old_q) { + sch_dev_queue_lock(dev); qdisc_destroy(old_q); + sch_dev_queue_unlock(dev); + } } return 0; -append: - qdisc_append(skb,n,clid,q,tca); +} + +int qdisc_copy_stats(struct sk_buff *skb, struct tc_stats *st) +{ + start_bh_atomic(); + RTA_PUT(skb, TCA_STATS, sizeof(*st), st); + end_bh_atomic(); return 0; + +rtattr_failure: + end_bh_atomic(); + return -1; } + static int tc_fill_qdisc(struct sk_buff *skb, struct Qdisc *q, u32 clid, u32 pid, u32 seq, unsigned flags, int event) { @@ -718,7 +740,8 @@ if (q->ops->dump && q->ops->dump(q, skb) < 0) goto rtattr_failure; q->stats.qlen = q->q.qlen; - RTA_PUT(skb, TCA_STATS, sizeof(q->stats), &q->stats); + if (qdisc_copy_stats(skb, &q->stats)) + goto rtattr_failure; nlh->nlmsg_len = skb->tail - b; return skb->len; @@ -728,36 +751,6 @@ return -1; } -static int qdisc_append (struct sk_buff *oskb, struct nlmsghdr *n, u32 clid, - struct Qdisc *q,struct rtattr **tca) -{ - struct sk_buff *skb; - int err; - u32 pid = oskb ? NETLINK_CB(oskb).pid : 0; - - skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); - if (!skb) - return -ENOBUFS; - if (!q || !q->handle || !q->ops ) - goto err_out; -/* - if (q->ops->init && (err = q->ops->init(q, tca[TCA_OPTIONS-1])) != 0) -*/ - if (q->ops->change && (err = q->ops->change(q, tca[TCA_OPTIONS-1])) != 0) - goto err_out; - if (tc_fill_qdisc(skb, q, clid, pid, n->nlmsg_seq, 0, RTM_NEWQDISC) < 0) - goto err_out; - if (skb->len) - return rtnetlink_send(skb, pid, RTMGRP_TC, - n->nlmsg_flags&NLM_F_ECHO); - -err_out: - printk("\n APPEND ERROR !!!!!!!!!!!!!\n"); - kfree_skb(skb); - return -EINVAL; -} - - static int qdisc_notify(struct sk_buff *oskb, struct nlmsghdr *n, u32 clid, struct Qdisc *old, struct Qdisc *new) { @@ -804,8 +797,9 @@ if (q_idx < s_q_idx) continue; if (tc_fill_qdisc(skb, q, 0, NETLINK_CB(cb->skb).pid, - cb->nlh->nlmsg_seq, NLM_F_MULTI, RTM_NEWQDISC) <= 0) + cb->nlh->nlmsg_seq, NLM_F_MULTI, RTM_NEWQDISC) <= 0) { goto done; + } } } @@ -1016,10 +1010,7 @@ for (q=dev->qdisc_list, t=0; q; q = q->next, t++) { if (t < s_t) continue; -/* if (!q->ops->cl_ops) continue; -*/ - if ((!q->ops->cl_ops)|| (!q->ops->cl_ops->dump)) continue; if (tcm->tcm_parent && TC_H_MAJ(tcm->tcm_parent) != q->handle) continue; if (t > s_t) @@ -1040,9 +1031,8 @@ return skb->len; } -#endif -#ifdef CONFIG_NET_SCH_INGRESS +#if defined(CONFIG_NET_SCH_INGRESS) || defined(CONFIG_NET_SCH_INGRESS_MODULE) int call_in_ingress(struct sk_buff *skb) { if (!skb->dev->qdisc_ingress) return FW_ACCEPT; @@ -1059,8 +1049,9 @@ { int len; - len = sprintf(buffer, "%08x %08x\n", - psched_tick_per_us, psched_us_per_tick); + len = sprintf(buffer, "%08x %08x %08x %08x\n", + psched_tick_per_us, psched_us_per_tick, + 1000000, HZ); len -= offset; @@ -1103,7 +1094,7 @@ static void psched_tick(unsigned long); static struct timer_list psched_timer = - { NULL, NULL, 0, 0L, psched_tick }; + { function: psched_tick }; static void psched_tick(unsigned long dummy) { @@ -1114,7 +1105,7 @@ psched_timer.expires = jiffies + 1*HZ; #else unsigned long now = jiffies; - psched_time_base = ((u64)now)<R_tab->data[(len)>>(cl)->R_tab->rate.cell_log]) -#define BUG_TRAP(x) if (!(x)) { printk("Assertion (" #x ") failed at " __FILE__ "(%d):" __FUNCTION__ "\n", __LINE__); } - static __inline__ unsigned cbq_hash(u32 h) { @@ -284,6 +282,7 @@ case TC_POLICE_SHOT: return NULL; default: + break; } #endif if (cl->level == 0) @@ -397,6 +396,7 @@ struct cbq_sched_data *q = (struct cbq_sched_data *)sch->data; struct cbq_class *cl = cbq_classify(skb, sch); int len = skb->len; + int ret = NET_XMIT_POLICED; #ifdef CONFIG_NET_CLS_POLICE q->rx_class = cl; @@ -405,14 +405,14 @@ #ifdef CONFIG_NET_CLS_POLICE cl->q->__parent = sch; #endif - if (cl->q->enqueue(skb, cl->q) == 1) { + if ((ret = cl->q->enqueue(skb, cl->q)) == 0) { sch->q.qlen++; sch->stats.packets++; sch->stats.bytes+=len; cbq_mark_toplevel(q, cl); if (!cl->next_alive) cbq_activate_class(cl); - return 1; + return 0; } } @@ -423,7 +423,7 @@ cbq_mark_toplevel(q, cl); cl->stats.drops++; } - return 0; + return ret; } static int @@ -431,11 +431,12 @@ { struct cbq_sched_data *q = (struct cbq_sched_data *)sch->data; struct cbq_class *cl; + int ret; if ((cl = q->tx_class) == NULL) { kfree_skb(skb); sch->stats.drops++; - return 0; + return NET_XMIT_CN; } q->tx_class = NULL; @@ -445,15 +446,15 @@ q->rx_class = cl; cl->q->__parent = sch; #endif - if (cl->q->ops->requeue(skb, cl->q) == 1) { + if ((ret = cl->q->ops->requeue(skb, cl->q)) == 0) { sch->q.qlen++; if (!cl->next_alive) cbq_activate_class(cl); - return 1; + return 0; } sch->stats.drops++; cl->stats.drops++; - return 0; + return ret; } /* Overlimit actions */ @@ -597,8 +598,9 @@ static void cbq_watchdog(unsigned long arg) { struct Qdisc *sch = (struct Qdisc*)arg; + sch->flags &= ~TCQ_F_THROTTLED; - qdisc_wakeup(sch->dev); + netif_schedule(sch->dev); } static unsigned long cbq_undelay_prio(struct cbq_sched_data *q, int prio) @@ -666,7 +668,7 @@ } sch->flags &= ~TCQ_F_THROTTLED; - qdisc_wakeup(sch->dev); + netif_schedule(sch->dev); } @@ -688,7 +690,7 @@ q->rx_class = cl; cl->q->__parent = sch; - if (cl->q->enqueue(skb, cl->q) == 1) { + if (cl->q->enqueue(skb, cl->q) == 0) { sch->q.qlen++; sch->stats.packets++; sch->stats.bytes+=len; @@ -877,7 +879,7 @@ /* Start round */ do { - struct cbq_class *borrow = NULL; + struct cbq_class *borrow = cl; if (cl->q->q.qlen && (borrow = cbq_under_limit(cl)) == NULL) @@ -1052,16 +1054,11 @@ if (sch->q.qlen) { sch->stats.overlimits++; - if (q->wd_expires && !sch->dev->tbusy) { + if (q->wd_expires && !netif_queue_stopped(sch->dev)) { long delay = PSCHED_US2JIFFIE(q->wd_expires); del_timer(&q->wd_timer); if (delay <= 0) delay = 1; - if (delay > 10*HZ) { - if (net_ratelimit()) - printk(KERN_DEBUG "CBQ delay %ld > 10sec\n", delay); - delay = 10*HZ; - } q->wd_timer.expires = jiffies + delay; add_timer(&q->wd_timer); sch->flags |= TCQ_F_THROTTLED; @@ -1248,8 +1245,10 @@ cl = cl_head; do { - if (cl->q->ops->drop && cl->q->ops->drop(cl->q)) + if (cl->q->ops->drop && cl->q->ops->drop(cl->q)) { + sch->q.qlen--; return 1; + } } while ((cl = cl->next_alive) != cl_head); } return 0; @@ -1457,8 +1456,6 @@ return 0; } -#ifdef CONFIG_RTNETLINK - static __inline__ int cbq_dump_rate(struct sk_buff *skb, struct cbq_class *cl) { unsigned char *b = skb->tail; @@ -1580,6 +1577,16 @@ return 0; } +int cbq_copy_xstats(struct sk_buff *skb, struct tc_cbq_xstats *st) +{ + RTA_PUT(skb, TCA_XSTATS, sizeof(*st), st); + return 0; + +rtattr_failure: + return -1; +} + + static int cbq_dump(struct Qdisc *sch, struct sk_buff *skb) { struct cbq_sched_data *q = (struct cbq_sched_data*)sch->data; @@ -1591,8 +1598,13 @@ if (cbq_dump_attr(skb, &q->link) < 0) goto rtattr_failure; rta->rta_len = skb->tail - b; + sch_dev_queue_lock(sch->dev); q->link.xstats.avgidle = q->link.avgidle; - RTA_PUT(skb, TCA_XSTATS, sizeof(q->link.xstats), &q->link.xstats); + if (cbq_copy_xstats(skb, &q->link.xstats)) { + sch_dev_queue_unlock(sch->dev); + goto rtattr_failure; + } + sch_dev_queue_unlock(sch->dev); return skb->len; rtattr_failure: @@ -1622,12 +1634,19 @@ goto rtattr_failure; rta->rta_len = skb->tail - b; cl->stats.qlen = cl->q->q.qlen; - RTA_PUT(skb, TCA_STATS, sizeof(cl->stats), &cl->stats); + if (qdisc_copy_stats(skb, &cl->stats)) + goto rtattr_failure; + sch_dev_queue_lock(sch->dev); cl->xstats.avgidle = cl->avgidle; cl->xstats.undertime = 0; if (!PSCHED_IS_PASTPERFECT(cl->undertime)) cl->xstats.undertime = PSCHED_TDIFF(cl->undertime, q->now); - RTA_PUT(skb, TCA_XSTATS, sizeof(cl->xstats), &cl->xstats); + q->link.xstats.avgidle = q->link.avgidle; + if (cbq_copy_xstats(skb, &cl->xstats)) { + sch_dev_queue_unlock(sch->dev); + goto rtattr_failure; + } + sch_dev_queue_unlock(sch->dev); return skb->len; @@ -1636,8 +1655,6 @@ return -1; } -#endif - static int cbq_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new, struct Qdisc **old) { @@ -1653,8 +1670,11 @@ new->reshape_fail = cbq_reshape_fail; #endif } - if ((*old = xchg(&cl->q, new)) != NULL) - qdisc_reset(*old); + sch_tree_lock(sch); + *old = cl->q; + cl->q = new; + qdisc_reset(*old); + sch_tree_unlock(sch); return 0; } @@ -1718,9 +1738,13 @@ } for (h = 0; h < 16; h++) { - for (cl = q->classes[h]; cl; cl = cl->next) + struct cbq_class *next; + + for (cl = q->classes[h]; cl; cl = next) { + next = cl->next; if (cl != &q->link) cbq_destroy_class(cl); + } } qdisc_put_rtab(q->link.R_tab); @@ -1729,19 +1753,20 @@ static void cbq_put(struct Qdisc *sch, unsigned long arg) { - struct cbq_sched_data *q = (struct cbq_sched_data *)sch->data; struct cbq_class *cl = (struct cbq_class*)arg; - start_bh_atomic(); if (--cl->refcnt == 0) { #ifdef CONFIG_NET_CLS_POLICE + struct cbq_sched_data *q = (struct cbq_sched_data *)sch->data; + + sch_dev_queue_lock(sch->dev); if (q->rx_class == cl) q->rx_class = NULL; + sch_dev_queue_unlock(sch->dev); #endif + cbq_destroy_class(cl); } - end_bh_atomic(); - return; } static int @@ -1802,7 +1827,7 @@ } /* Change class parameters */ - start_bh_atomic(); + sch_tree_lock(sch); if (cl->next_alive != NULL) cbq_deactivate_class(cl); @@ -1834,7 +1859,7 @@ if (cl->q->q.qlen) cbq_activate_class(cl); - end_bh_atomic(); + sch_tree_unlock(sch); #ifdef CONFIG_NET_ESTIMATOR if (tca[TCA_RATE-1]) { @@ -1901,7 +1926,7 @@ cl->quantum = cl->allot; cl->weight = cl->R_tab->rate.rate; - start_bh_atomic(); + sch_tree_lock(sch); cbq_link_class(cl); cl->borrow = cl->tparent; if (cl->tparent != &q->link) @@ -1925,7 +1950,7 @@ #endif if (tb[TCA_CBQ_FOPT-1]) cbq_set_fopt(cl, RTA_DATA(tb[TCA_CBQ_FOPT-1])); - end_bh_atomic(); + sch_tree_unlock(sch); #ifdef CONFIG_NET_ESTIMATOR if (tca[TCA_RATE-1]) @@ -1948,7 +1973,7 @@ if (cl->filters || cl->children || cl == &q->link) return -EBUSY; - start_bh_atomic(); + sch_tree_lock(sch); if (cl->next_alive) cbq_deactivate_class(cl); @@ -1970,12 +1995,11 @@ cbq_sync_defmap(cl); cbq_rmprio(q, cl); + sch_tree_unlock(sch); if (--cl->refcnt == 0) cbq_destroy_class(cl); - end_bh_atomic(); - return 0; } @@ -2052,9 +2076,7 @@ cbq_bind_filter, cbq_unbind_filter, -#ifdef CONFIG_RTNETLINK cbq_dump_class, -#endif }; struct Qdisc_ops cbq_qdisc_ops = @@ -2074,9 +2096,7 @@ cbq_destroy, NULL /* cbq_change */, -#ifdef CONFIG_RTNETLINK cbq_dump, -#endif }; #ifdef MODULE @@ -2090,3 +2110,4 @@ unregister_qdisc(&cbq_qdisc_ops); } #endif +MODULE_LICENSE("GPL"); diff -urN ../v2.2.21-ds8/linux/net/sched/sch_csz.c linux/net/sched/sch_csz.c --- ../v2.2.21-ds8/linux/net/sched/sch_csz.c Sat Oct 21 15:10:47 2000 +++ linux/net/sched/sch_csz.c Sat Jun 14 09:49:00 2003 @@ -56,7 +56,7 @@ CSZ presents a more precise but less flexible and less efficient approach. As I understand it, the main idea is to create WFQ flows for each guaranteed service and to allocate - the rest of bandwith to dummy flow-0. Flow-0 comprises + the rest of bandwidth to dummy flow-0. Flow-0 comprises the predictive services and the best effort traffic; it is handled by a priority scheduler with the highest priority band allocated for predictive services, and the rest --- @@ -477,7 +477,7 @@ if (this->q.qlen >= this->limit || this->L_tab == NULL) { sch->stats.drops++; kfree_skb(skb); - return 0; + return NET_XMIT_DROP; } R = csz_update(sch); @@ -505,7 +505,7 @@ sch->q.qlen++; sch->stats.bytes += skb->len; sch->stats.packets++; - return 1; + return 0; } static __inline__ struct sk_buff * @@ -749,6 +749,14 @@ static void csz_destroy(struct Qdisc* sch) { + struct csz_sched_data *q = (struct csz_sched_data *)sch->data; + struct tcf_proto *tp; + + while ((tp = q->filter_list) != NULL) { + q->filter_list = tp->next; + tp->ops->destroy(tp); + } + MOD_DEC_USE_COUNT; } @@ -795,7 +803,6 @@ return 0; } -#ifdef CONFIG_RTNETLINK static int csz_dump(struct Qdisc *sch, struct sk_buff *skb) { struct csz_sched_data *q = (struct csz_sched_data *)sch->data; @@ -817,8 +824,6 @@ skb_trim(skb, b - skb->data); return -1; } -#endif - static int csz_graft(struct Qdisc *sch, unsigned long cl, struct Qdisc *new, struct Qdisc **old) @@ -885,7 +890,7 @@ a = &q->flow[cl]; - start_bh_atomic(); + sch_dev_queue_lock(sch->dev); #if 0 a->rate_log = copt->rate_log; #endif @@ -899,7 +904,7 @@ if (tb[TCA_CSZ_RTAB-1]) memcpy(a->L_tab, RTA_DATA(tb[TCA_CSZ_RTAB-1]), 1024); - end_bh_atomic(); + sch_dev_queue_unlock(sch->dev); return 0; } /* NI */ @@ -920,19 +925,18 @@ a = &q->flow[cl]; - start_bh_atomic(); + sch_dev_queue_lock(sch->dev); a->fprev->fnext = a->fnext; a->fnext->fprev = a->fprev; a->sprev->snext = a->snext; a->snext->sprev = a->sprev; a->start = a->finish = 0; kfree(xchg(&q->flow[cl].L_tab, NULL)); - end_bh_atomic(); + sch_dev_queue_unlock(sch->dev); return 0; } -#ifdef CONFIG_RTNETLINK static int csz_dump_class(struct Qdisc *sch, unsigned long cl, struct sk_buff *skb, struct tcmsg *tcm) { struct csz_sched_data *q = (struct csz_sched_data *)sch->data; @@ -978,7 +982,6 @@ skb_trim(skb, b - skb->data); return -1; } -#endif static void csz_walk(struct Qdisc *sch, struct qdisc_walker *arg) { @@ -1030,9 +1033,7 @@ csz_bind, csz_put, -#ifdef CONFIG_RTNETLINK csz_dump_class, -#endif }; struct Qdisc_ops csz_qdisc_ops = @@ -1052,9 +1053,7 @@ csz_destroy, NULL /* csz_change */, -#ifdef CONFIG_RTNETLINK csz_dump, -#endif }; @@ -1069,3 +1068,4 @@ unregister_qdisc(&csz_qdisc_ops); } #endif +MODULE_LICENSE("GPL"); diff -urN ../v2.2.21-ds8/linux/net/sched/sch_dsmark.c linux/net/sched/sch_dsmark.c --- ../v2.2.21-ds8/linux/net/sched/sch_dsmark.c Wed Jul 31 03:00:59 2002 +++ linux/net/sched/sch_dsmark.c Sun Mar 31 06:18:30 2002 @@ -1,11 +1,13 @@ /* net/sched/sch_dsmark.c - Differentiated Services field marker */ -/* Written 1998,1999 by Werner Almesberger, EPFL ICA */ +/* Written 1998-2000 by Werner Almesberger, EPFL ICA */ #include #include #include +#include +#include #include #include /* for pkt_sched */ #include @@ -39,16 +41,22 @@ * x:y y>0 y+1 use entry [y] * ... ... ... * x:indices-1 indices use entry [indices-1] + * ... ... ... + * x:y y+1 use entry [y & (indices-1)] + * ... ... ... + * 0xffff 0x10000 use entry [indices-1] */ +#define NO_DEFAULT_INDEX (1 << 16) + struct dsmark_qdisc_data { struct Qdisc *q; struct tcf_proto *filter_list; __u8 *mask; /* "owns" the array */ __u8 *value; __u16 indices; - __u16 default_index; + __u32 default_index; /* index range is 0...0xffff */ int set_tc_index; }; @@ -63,22 +71,28 @@ DPRINTK("dsmark_graft(sch %p,[qdisc %p],new %p,old %p)\n",sch,p,new, old); - if (!new) new = &noop_qdisc; + if (!new) + new = &noop_qdisc; + sch_tree_lock(sch); *old = xchg(&p->q,new); - if (*old) qdisc_reset(*old); + if (*old) + qdisc_reset(*old); + sch_tree_unlock(sch); /* @@@ move up ? */ return 0; } static struct Qdisc *dsmark_leaf(struct Qdisc *sch, unsigned long arg) { - return NULL; + struct dsmark_qdisc_data *p = PRIV(sch); + + return p->q; } static unsigned long dsmark_get(struct Qdisc *sch,u32 classid) { - struct dsmark_qdisc_data *p = PRIV(sch); + struct dsmark_qdisc_data *p __attribute__((unused)) = PRIV(sch); DPRINTK("dsmark_get(sch %p,[qdisc %p],classid %x)\n",sch,p,classid); return TC_H_MIN(classid)+1; @@ -106,9 +120,11 @@ DPRINTK("dsmark_change(sch %p,[qdisc %p],classid %x,parent %x)," "arg 0x%lx\n",sch,p,classid,parent,*arg); - if (*arg > p->indices) return -ENOENT; - if (!opt || rtattr_parse(tb,TCA_DSMARK_MAX,RTA_DATA(opt), - RTA_PAYLOAD(opt))) return -EINVAL; + if (*arg > p->indices) + return -ENOENT; + if (!opt || rtattr_parse(tb, TCA_DSMARK_MAX, RTA_DATA(opt), + RTA_PAYLOAD(opt))) + return -EINVAL; if (tb[TCA_DSMARK_MASK-1]) { if (!RTA_PAYLOAD(tb[TCA_DSMARK_MASK-1])) return -EINVAL; @@ -127,7 +143,8 @@ { struct dsmark_qdisc_data *p = PRIV(sch); - if (!arg || arg > p->indices) return -EINVAL; + if (!arg || arg > p->indices) + return -EINVAL; p->mask[arg-1] = 0xff; p->value[arg-1] = 0; return 0; @@ -140,14 +157,17 @@ int i; DPRINTK("dsmark_walk(sch %p,[qdisc %p],walker %p)\n",sch,p,walker); - if (walker->stop) return; + if (walker->stop) + return; for (i = 0; i < p->indices; i++) { - if (p->mask[i] == 0xff && !p->value[i]) continue; - if (walker->count >= walker->skip) - if (walker->fn(sch,i+1,walker) < 0) { + if (p->mask[i] == 0xff && !p->value[i]) + continue; + if (walker->count >= walker->skip) { + if (walker->fn(sch, i+1, walker) < 0) { walker->stop = 1; break; } + } walker->count++; } } @@ -169,9 +189,10 @@ struct dsmark_qdisc_data *p = PRIV(sch); struct tcf_result res; int result; + int ret = NET_XMIT_POLICED; D2PRINTK("dsmark_enqueue(skb %p,sch %p,[qdisc %p])\n",skb,sch,p); - if (p->set_tc_index) + if (p->set_tc_index) { switch (skb->protocol) { case __constant_htons(ETH_P_IP): skb->tc_index = ipv4_get_dsfield(skb->nh.iph); @@ -181,11 +202,13 @@ break; default: skb->tc_index = 0; - } + break; + }; + } result = TC_POLICE_OK; /* be nice to gcc */ - if (TC_H_MAJ(skb->priority) == sch->handle) + if (TC_H_MAJ(skb->priority) == sch->handle) { skb->tc_index = TC_H_MIN(skb->priority); - else { + } else { result = tc_classify(skb,p->filter_list,&res); D2PRINTK("result %d class 0x%04x\n",result,res.classid); switch (result) { @@ -204,23 +227,24 @@ case TC_POLICE_UNSPEC: /* fall through */ default: - if (p->default_index) + if (p->default_index != NO_DEFAULT_INDEX) skb->tc_index = p->default_index; break; - } + }; } if ( #ifdef CONFIG_NET_CLS_POLICE result == TC_POLICE_SHOT || #endif - p->q->enqueue(skb,p->q) != 1) { + + ((ret = p->q->enqueue(skb,p->q)) != 0)) { sch->stats.drops++; - return 0; + return ret; } sch->stats.bytes += skb->len; sch->stats.packets++; sch->q.qlen++; - return 1; + return ret; } @@ -232,7 +256,8 @@ D2PRINTK("dsmark_dequeue(sch %p,[qdisc %p])\n",sch,p); skb = p->q->ops->dequeue(p->q); - if (!skb) return NULL; + if (!skb) + return NULL; sch->q.qlen--; index = skb->tc_index & (p->indices-1); D2PRINTK("index %d->%d\n",skb->tc_index,index); @@ -253,9 +278,10 @@ */ if (p->mask[index] != 0xff || p->value[index]) printk(KERN_WARNING "dsmark_dequeue: " - "unsupported protocol %d\n", - htons(skb->protocol)); - } + "unsupported protocol %d\n", + htons(skb->protocol)); + break; + }; return skb; } @@ -266,13 +292,12 @@ struct dsmark_qdisc_data *p = PRIV(sch); D2PRINTK("dsmark_requeue(skb %p,sch %p,[qdisc %p])\n",skb,sch,p); - if ((ret = p->q->ops->requeue(skb, p->q)) == 0) { + if ((ret = p->q->ops->requeue(skb, p->q)) == 0) { sch->q.qlen++; - return 1; + return 0; } sch->stats.drops++; - return ret; - + return ret; } @@ -281,8 +306,10 @@ struct dsmark_qdisc_data *p = PRIV(sch); DPRINTK("dsmark_reset(sch %p,[qdisc %p])\n",sch,p); - if (!p->q->ops->drop) return 0; - if (!p->q->ops->drop(p->q)) return 0; + if (!p->q->ops->drop) + return 0; + if (!p->q->ops->drop(p->q)) + return 0; sch->q.qlen--; return 1; } @@ -295,32 +322,34 @@ __u16 tmp; DPRINTK("dsmark_init(sch %p,[qdisc %p],opt %p)\n",sch,p,opt); - if (rtattr_parse(tb,TCA_DSMARK_MAX,RTA_DATA(opt),RTA_PAYLOAD(opt)) < 0 - || !tb[TCA_DSMARK_INDICES-1] || + if (rtattr_parse(tb,TCA_DSMARK_MAX,RTA_DATA(opt),RTA_PAYLOAD(opt)) < 0 || + !tb[TCA_DSMARK_INDICES-1] || RTA_PAYLOAD(tb[TCA_DSMARK_INDICES-1]) < sizeof(__u16)) return -EINVAL; memset(p,0,sizeof(*p)); p->filter_list = NULL; p->indices = *(__u16 *) RTA_DATA(tb[TCA_DSMARK_INDICES-1]); - if (!p->indices) return -EINVAL; - for (tmp = p->indices; tmp != 1; tmp >>= 1) - if (tmp & 1) return -EINVAL; - p->default_index = 0; + if (!p->indices) + return -EINVAL; + for (tmp = p->indices; tmp != 1; tmp >>= 1) { + if (tmp & 1) + return -EINVAL; + } + p->default_index = NO_DEFAULT_INDEX; if (tb[TCA_DSMARK_DEFAULT_INDEX-1]) { if (RTA_PAYLOAD(tb[TCA_DSMARK_DEFAULT_INDEX-1]) < sizeof(__u16)) return -EINVAL; p->default_index = *(__u16 *) RTA_DATA(tb[TCA_DSMARK_DEFAULT_INDEX-1]); - if (!p->default_index || p->default_index >= p->indices) - return -EINVAL; } p->set_tc_index = !!tb[TCA_DSMARK_SET_TC_INDEX-1]; p->mask = kmalloc(p->indices*2,GFP_KERNEL); - if (!p->mask) return -ENOMEM; + if (!p->mask) + return -ENOMEM; p->value = p->mask+p->indices; memset(p->mask,0xff,p->indices); memset(p->value,0,p->indices); - if (!(p->q = qdisc_create_dflt(sch->dev,&pfifo_qdisc_ops))) + if (!(p->q = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops))) p->q = &noop_qdisc; DPRINTK("dsmark_init: qdisc %p\n",&p->q); MOD_INC_USE_COUNT; @@ -356,8 +385,6 @@ } -#ifdef CONFIG_RTNETLINK - static int dsmark_dump_class(struct Qdisc *sch, unsigned long cl, struct sk_buff *skb, struct tcmsg *tcm) { @@ -366,7 +393,8 @@ struct rtattr *rta; DPRINTK("dsmark_dump_class(sch %p,[qdisc %p],class %ld\n",sch,p,cl); - if (!cl || cl > p->indices) return -EINVAL; + if (!cl || cl > p->indices) + return -EINVAL; tcm->tcm_handle = TC_H_MAKE(TC_H_MAJ(sch->handle),cl-1); rta = (struct rtattr *) b; RTA_PUT(skb,TCA_OPTIONS,0,NULL); @@ -389,10 +417,13 @@ rta = (struct rtattr *) b; RTA_PUT(skb,TCA_OPTIONS,0,NULL); RTA_PUT(skb,TCA_DSMARK_INDICES,sizeof(__u16),&p->indices); - if (p->default_index) - RTA_PUT(skb,TCA_DSMARK_DEFAULT_INDEX,sizeof(__u16), - &p->default_index); - if (p->set_tc_index) RTA_PUT(skb,TCA_DSMARK_SET_TC_INDEX,0,NULL); + if (p->default_index != NO_DEFAULT_INDEX) { + __u16 tmp = p->default_index; + + RTA_PUT(skb,TCA_DSMARK_DEFAULT_INDEX, sizeof(__u16), &tmp); + } + if (p->set_tc_index) + RTA_PUT(skb, TCA_DSMARK_SET_TC_INDEX, 0, NULL); rta->rta_len = skb->tail-b; return skb->len; @@ -401,9 +432,6 @@ return -1; } -#endif - - static struct Qdisc_class_ops dsmark_class_ops = { dsmark_graft, /* graft */ @@ -418,9 +446,7 @@ dsmark_bind_filter, /* bind_tcf */ dsmark_put, /* unbind_tcf */ -#ifdef CONFIG_RTNETLINK dsmark_dump_class, /* dump */ -#endif }; struct Qdisc_ops dsmark_qdisc_ops = @@ -440,9 +466,7 @@ dsmark_destroy, /* destroy */ NULL, /* change */ -#ifdef CONFIG_RTNETLINK dsmark_dump /* dump */ -#endif }; #ifdef MODULE @@ -457,3 +481,4 @@ unregister_qdisc(&dsmark_qdisc_ops); } #endif +MODULE_LICENSE("GPL"); diff -urN ../v2.2.21-ds8/linux/net/sched/sch_fifo.c linux/net/sched/sch_fifo.c --- ../v2.2.21-ds8/linux/net/sched/sch_fifo.c Sat Oct 21 15:10:47 2000 +++ linux/net/sched/sch_fifo.c Sun Mar 31 06:18:30 2002 @@ -51,14 +51,14 @@ sch->stats.backlog += skb->len; sch->stats.bytes += skb->len; sch->stats.packets++; - return 1; + return 0; } sch->stats.drops++; #ifdef CONFIG_NET_CLS_POLICE if (sch->reshape_fail==NULL || sch->reshape_fail(skb, sch)) #endif kfree_skb(skb); - return 0; + return NET_XMIT_DROP; } static int @@ -66,7 +66,7 @@ { __skb_queue_head(&sch->q, skb); sch->stats.backlog += skb->len; - return 1; + return 0; } static struct sk_buff * @@ -110,21 +110,21 @@ __skb_queue_tail(&sch->q, skb); sch->stats.bytes += skb->len; sch->stats.packets++; - return 1; + return 0; } sch->stats.drops++; #ifdef CONFIG_NET_CLS_POLICE if (sch->reshape_fail==NULL || sch->reshape_fail(skb, sch)) #endif kfree_skb(skb); - return 0; + return NET_XMIT_DROP; } static int pfifo_requeue(struct sk_buff *skb, struct Qdisc* sch) { __skb_queue_head(&sch->q, skb); - return 1; + return 0; } @@ -152,7 +152,6 @@ return 0; } -#ifdef CONFIG_RTNETLINK static int fifo_dump(struct Qdisc *sch, struct sk_buff *skb) { struct fifo_sched_data *q = (void*)sch->data; @@ -168,7 +167,6 @@ skb_trim(skb, b - skb->data); return -1; } -#endif struct Qdisc_ops pfifo_qdisc_ops = { @@ -187,9 +185,7 @@ NULL, fifo_init, -#ifdef CONFIG_RTNETLINK fifo_dump, -#endif }; struct Qdisc_ops bfifo_qdisc_ops = @@ -208,7 +204,5 @@ fifo_reset, NULL, fifo_init, -#ifdef CONFIG_RTNETLINK fifo_dump, -#endif }; diff -urN ../v2.2.21-ds8/linux/net/sched/sch_generic.c linux/net/sched/sch_generic.c --- ../v2.2.21-ds8/linux/net/sched/sch_generic.c Wed Jul 31 03:00:59 2002 +++ linux/net/sched/sch_generic.c Thu Aug 8 02:26:44 2002 @@ -32,8 +32,6 @@ #include #include -#define BUG_TRAP(x) if (!(x)) { printk("Assertion (" #x ") failed at " __FILE__ "(%d):" __FUNCTION__ "\n", __LINE__); } - /* Main transmission queue. */ struct Qdisc_head qdisc_head = { &qdisc_head }; @@ -151,7 +149,7 @@ noop_enqueue(struct sk_buff *skb, struct Qdisc * qdisc) { kfree_skb(skb); - return 0; + return NET_XMIT_CN; } static struct sk_buff * @@ -166,7 +164,7 @@ if (net_ratelimit()) printk(KERN_DEBUG "%s deferred output. It is buggy.\n", skb->dev->name); kfree_skb(skb); - return 0; + return NET_XMIT_CN; } struct Qdisc_ops noop_qdisc_ops = @@ -208,7 +206,7 @@ { { NULL }, NULL, - NULL, + noop_dequeue, TCQ_F_BUILTIN, &noqueue_qdisc_ops, }; @@ -229,14 +227,14 @@ list = ((struct sk_buff_head*)qdisc->data) + prio2band[skb->priority&TC_PRIO_MAX]; - if (list->qlen <= skb->dev->tx_queue_len) { + if (list->qlen <= qdisc->dev->tx_queue_len) { __skb_queue_tail(list, skb); qdisc->q.qlen++; - return 1; + return 0; } qdisc->stats.drops++; kfree_skb(skb); - return 0; + return NET_XMIT_DROP; } static struct sk_buff * @@ -266,7 +264,7 @@ __skb_queue_head(list, skb); qdisc->q.qlen++; - return 1; + return 0; } static void @@ -334,52 +332,42 @@ void qdisc_reset(struct Qdisc *qdisc) { - struct Qdisc_ops *ops; + struct Qdisc_ops *ops = qdisc->ops; - if ((qdisc==NULL)||(NULL==(ops = qdisc->ops))) - goto bye; - start_bh_atomic(); if (ops->reset) ops->reset(qdisc); - - end_bh_atomic(); -bye: } void qdisc_destroy(struct Qdisc *qdisc) { - struct Qdisc_ops *ops; - - if ((qdisc==NULL)||(NULL==(ops = qdisc->ops))) - goto bye; + struct Qdisc_ops *ops = qdisc->ops; + struct device *dev; if (!atomic_dec_and_test(&qdisc->refcnt)) return; + dev = qdisc->dev; + #ifdef CONFIG_NET_SCHED - if (qdisc->dev) { + if (dev) { struct Qdisc *q, **qp; - for (qp = &qdisc->dev->qdisc_list; (q=*qp) != NULL; qp = &q->next) + for (qp = &qdisc->dev->qdisc_list; (q=*qp) != NULL; qp = &q->next) { if (q == qdisc) { *qp = q->next; - q->next = NULL; break; } + } } #ifdef CONFIG_NET_ESTIMATOR qdisc_kill_estimator(&qdisc->stats); #endif #endif - start_bh_atomic(); if (ops->reset) ops->reset(qdisc); - if (ops->destroy) ops->destroy(qdisc); - end_bh_atomic(); if (!(qdisc->flags&TCQ_F_BUILTIN)) kfree(qdisc); -bye: } @@ -392,19 +380,20 @@ */ if (dev->qdisc_sleeping == &noop_qdisc) { + struct Qdisc *qdisc; if (dev->tx_queue_len) { - struct Qdisc *qdisc; qdisc = qdisc_create_dflt(dev, &pfifo_fast_ops); if (qdisc == NULL) { printk(KERN_INFO "%s: activation failed\n", dev->name); return; } - dev->qdisc_sleeping = qdisc; - } else - dev->qdisc_sleeping = &noqueue_qdisc; + } else { + qdisc = &noqueue_qdisc; + } + dev->qdisc_sleeping = qdisc; } - start_bh_atomic(); + sch_dev_queue_lock(dev); if ((dev->qdisc = dev->qdisc_sleeping) != &noqueue_qdisc) { dev->qdisc->tx_timeo = 5*HZ; dev->qdisc->tx_last = jiffies - dev->qdisc->tx_timeo; @@ -412,16 +401,17 @@ dev_watchdog.expires = jiffies + 5*HZ; add_timer(&dev_watchdog); } - end_bh_atomic(); + sch_dev_queue_unlock(dev); } void dev_deactivate(struct device *dev) { struct Qdisc *qdisc; - start_bh_atomic(); + sch_dev_queue_lock(dev); - qdisc = xchg(&dev->qdisc, &noop_qdisc); + qdisc = dev->qdisc; + dev->qdisc = &noop_qdisc; qdisc_reset(qdisc); @@ -437,7 +427,7 @@ } } - end_bh_atomic(); + sch_dev_queue_unlock(dev); } void dev_init_scheduler(struct device *dev) @@ -451,20 +441,16 @@ { struct Qdisc *qdisc; - start_bh_atomic(); + sch_dev_queue_lock(dev); qdisc = dev->qdisc_sleeping; dev->qdisc = &noop_qdisc; dev->qdisc_sleeping = &noop_qdisc; qdisc_destroy(qdisc); -#ifdef CONFIG_NET_SCH_INGRESS - if (dev->qdisc_ingress) { - qdisc = dev->qdisc_ingress; - qdisc_destroy(qdisc); - } -#endif + if ((qdisc = dev->qdisc_ingress) != NULL) { + dev->qdisc_ingress = NULL; + qdisc_destroy(qdisc); + } BUG_TRAP(dev->qdisc_list == NULL); dev->qdisc_list = NULL; - dev->qdisc_ingress = NULL; - end_bh_atomic(); + sch_dev_queue_unlock(dev); } - diff -urN ../v2.2.21-ds8/linux/net/sched/sch_gred.c linux/net/sched/sch_gred.c --- ../v2.2.21-ds8/linux/net/sched/sch_gred.c Wed Jul 31 03:00:59 2002 +++ linux/net/sched/sch_gred.c Sat Jun 14 09:49:14 2003 @@ -7,7 +7,7 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * - * Authors: J Hadi Salim (hadi@nortelnetworks.com) 1998,1999 + * Authors: J Hadi Salim (hadi@cyberus.ca) 1998-2002 * * 991129: - Bug fix with grio mode * - a better sing. AvgQ mode with Grio(WRED) @@ -67,7 +67,7 @@ u32 limit; /* HARD maximal queue length */ u32 qth_min; /* Min average length threshold: A scaled */ u32 qth_max; /* Max average length threshold: A scaled */ - u32 DP; /* the drop pramaters */ + u32 DP; /* the drop pramaters */ char Wlog; /* log(W) */ char Plog; /* random number bits */ u32 Scell_max; @@ -110,16 +110,13 @@ unsigned long qave=0; int i=0; - if (!t->initd) { - DPRINTK("NO GRED Queues setup yet! Enqueued anyway\n"); - if (q->backlog <= q->limit) { - __skb_queue_tail(&sch->q, skb); - return 1; - } + if (!t->initd && skb_queue_len(&sch->q) <= sch->dev->tx_queue_len) { + D2PRINTK("NO GRED Queues setup yet! Enqueued anyway\n"); + goto do_enqueue; } - if ( ((skb->tc_index&0xf) > t->DPs) || !(q=t->tab[skb->tc_index&0xf])) { + if ( ((skb->tc_index&0xf) > (t->DPs -1)) || !(q=t->tab[skb->tc_index&0xf])) { printk("GRED: setting to default (%d)\n ",t->def); if (!(q=t->tab[t->def])) { DPRINTK("GRED: setting to default FAILED! dropping!! " @@ -146,8 +143,8 @@ } - q->packetsin++; - q->bytesin+=skb->len; + q->packetsin++; + q->bytesin+=skb->len; if (t->eqp && t->grio) { qave=0; @@ -179,12 +176,13 @@ q->qcount = -1; enqueue: if (q->backlog <= q->limit) { + q->backlog += skb->len; +do_enqueue: __skb_queue_tail(&sch->q, skb); sch->stats.backlog += skb->len; sch->stats.bytes += skb->len; sch->stats.packets++; - q->backlog += skb->len; - return 1; + return 0; } else { q->pdrop++; } @@ -192,7 +190,7 @@ drop: kfree_skb(skb); sch->stats.drops++; - return 0; + return NET_XMIT_DROP; } if ((q->qave+qave) >= q->qth_max) { q->qcount = -1; @@ -218,14 +216,14 @@ { struct gred_sched_data *q; struct gred_sched *t= (struct gred_sched *)sch->data; - q= t->tab[(skb->tc_index&0xf)]; + q= t->tab[(skb->tc_index&0xf)]; /* error checking here -- probably unnecessary */ PSCHED_SET_PASTPERFECT(q->qidlestart); __skb_queue_head(&sch->q, skb); sch->stats.backlog += skb->len; q->backlog += skb->len; - return 1; + return 0; } static struct sk_buff * @@ -300,14 +298,12 @@ static void gred_reset(struct Qdisc* sch) { - struct sk_buff *skb; int i; - struct gred_sched_data *q; struct gred_sched *t= (struct gred_sched *)sch->data; - while((skb=__skb_dequeue(&sch->q))!=NULL) - kfree_skb(skb); + __skb_queue_purge(&sch->q); + sch->stats.backlog = 0; for (i=0;iDPs;i++) { @@ -329,27 +325,29 @@ { struct gred_sched *table = (struct gred_sched *)sch->data; struct gred_sched_data *q; - struct tc_gred_qopt *ctl; - struct tc_gred_sopt *sopt; - struct rtattr *tb[TCA_GRED_STAB]; - struct rtattr *tb2[TCA_GRED_STAB]; + struct tc_gred_qopt *ctl; + struct tc_gred_sopt *sopt; + struct rtattr *tb[TCA_GRED_STAB]; + struct rtattr *tb2[TCA_GRED_DPS]; int i; - if (opt == NULL || - rtattr_parse(tb, TCA_GRED_STAB, RTA_DATA(opt), RTA_PAYLOAD(opt)) ) - return -EINVAL; + if (opt == NULL || + rtattr_parse(tb, TCA_GRED_STAB, RTA_DATA(opt), RTA_PAYLOAD(opt)) ) + return -EINVAL; - if (tb[TCA_GRED_PARMS-1] == 0 && tb[TCA_GRED_STAB-1] == 0 && - tb[TCA_GRED_DPS-1] != 0) { + if (tb[TCA_GRED_PARMS-1] == 0 && tb[TCA_GRED_STAB-1] == 0) { rtattr_parse(tb2, TCA_GRED_DPS, RTA_DATA(opt), RTA_PAYLOAD(opt)); - sopt = RTA_DATA(tb2[TCA_GRED_DPS-1]); - table->DPs=sopt->DPs; - table->def=sopt->def_DP; - table->grio=sopt->grio; + if (tb2[TCA_GRED_DPS-1] == 0) + return -EINVAL; + + sopt = RTA_DATA(tb2[TCA_GRED_DPS-1]); + table->DPs=sopt->DPs; + table->def=sopt->def_DP; + table->grio=sopt->grio; table->initd=0; - /* probably need to clear all the table DP entries as well */ + /* probably need to clear all the table DP entries as well */ MOD_INC_USE_COUNT; return 0; } @@ -361,7 +359,7 @@ return -EINVAL; ctl = RTA_DATA(tb[TCA_GRED_PARMS-1]); - if (ctl->DP > MAX_DPs-1 || ctl->DP <0) { + if (ctl->DP > MAX_DPs-1 ) { /* misbehaving is punished! Put in the default drop probability */ DPRINTK("\nGRED: DP %u not in the proper range fixed. New DP " "set to default at %d\n",ctl->DP,table->def); @@ -371,6 +369,8 @@ if (table->tab[ctl->DP] == NULL) { table->tab[ctl->DP]=kmalloc(sizeof(struct gred_sched_data), GFP_KERNEL); + if (NULL == table->tab[ctl->DP]) + return -ENOMEM; memset(table->tab[ctl->DP], 0, (sizeof(struct gred_sched_data))); } q= table->tab[ctl->DP]; @@ -378,13 +378,13 @@ if (table->grio) { if (ctl->prio <=0) { if (table->def && table->tab[table->def]) { - DPRINTK("\nGRED: DP %u does not have a prio setting " - "default to %d\n",ctl->DP, + DPRINTK("\nGRED: DP %u does not have a prio" + "setting default to %d\n",ctl->DP, table->tab[table->def]->prio); q->prio=table->tab[table->def]->prio; } else { - DPRINTK("\nGRED: DP %u does not have a prio setting " - "default to 8\n",ctl->DP); + DPRINTK("\nGRED: DP %u does not have a prio" + " setting default to 8\n",ctl->DP); q->prio=8; } } else { @@ -392,7 +392,7 @@ } } else { q->prio=8; - } + } q->DP=ctl->DP; @@ -437,10 +437,13 @@ if (table->tab[table->def] == NULL) { table->tab[table->def]= - kmalloc(sizeof(struct gred_sched_data), GFP_KERNEL); + kmalloc(sizeof(struct gred_sched_data), GFP_KERNEL); + if (NULL == table->tab[table->def]) + return -ENOMEM; + memset(table->tab[table->def], 0, (sizeof(struct gred_sched_data))); - } + } q= table->tab[table->def]; q->DP=table->def; q->Wlog = ctl->Wlog; @@ -452,54 +455,54 @@ q->qth_min = ctl->qth_min<Wlog; q->qth_max = ctl->qth_max<Wlog; - if (table->grio) + if (table->grio) q->prio=table->tab[ctl->DP]->prio; - else + else q->prio=8; q->qcount = -1; PSCHED_SET_PASTPERFECT(q->qidlestart); memcpy(q->Stab, RTA_DATA(tb[TCA_GRED_STAB-1]), 256); } - return 0; + return 0; } static int gred_init(struct Qdisc *sch, struct rtattr *opt) { struct gred_sched *table = (struct gred_sched *)sch->data; - struct tc_gred_sopt *sopt; - struct rtattr *tb[TCA_GRED_STAB]; - struct rtattr *tb2[TCA_GRED_STAB]; - - if (opt == NULL || - rtattr_parse(tb, TCA_GRED_STAB, RTA_DATA(opt), RTA_PAYLOAD(opt)) ) - return -EINVAL; + struct tc_gred_sopt *sopt; + struct rtattr *tb[TCA_GRED_STAB]; + struct rtattr *tb2[TCA_GRED_DPS]; - if (tb[TCA_GRED_PARMS-1] == 0 && tb[TCA_GRED_STAB-1] == 0 && - tb[TCA_GRED_DPS-1] != 0) { - rtattr_parse(tb2, TCA_GRED_DPS, RTA_DATA(opt), - RTA_PAYLOAD(opt)); + if (opt == NULL || + rtattr_parse(tb, TCA_GRED_STAB, RTA_DATA(opt), RTA_PAYLOAD(opt)) ) + return -EINVAL; + + if (tb[TCA_GRED_PARMS-1] == 0 && tb[TCA_GRED_STAB-1] == 0 ) { + rtattr_parse(tb2, TCA_GRED_DPS, RTA_DATA(opt),RTA_PAYLOAD(opt)); + + if (tb2[TCA_GRED_DPS-1] == 0) + return -EINVAL; - sopt = RTA_DATA(tb2[TCA_GRED_DPS-1]); - table->DPs=sopt->DPs; - table->def=sopt->def_DP; - table->grio=sopt->grio; + sopt = RTA_DATA(tb2[TCA_GRED_DPS-1]); + table->DPs=sopt->DPs; + table->def=sopt->def_DP; + table->grio=sopt->grio; table->initd=0; MOD_INC_USE_COUNT; return 0; } - DPRINTK("\n GRED_INIT error!\n"); + DPRINTK("\n GRED_INIT error!\n"); return -EINVAL; } -#ifdef CONFIG_RTNETLINK static int gred_dump(struct Qdisc *sch, struct sk_buff *skb) { unsigned long qave; struct rtattr *rta; - struct tc_gred_qopt *opt; + struct tc_gred_qopt *opt = NULL ; struct tc_gred_qopt *dst; struct gred_sched *table = (struct gred_sched *)sch->data; struct gred_sched_data *q; @@ -512,7 +515,7 @@ opt=kmalloc(sizeof(struct tc_gred_qopt)*MAX_DPs, GFP_KERNEL); if (opt == NULL) { - DPRINTK("gred_dump:failed to malloc for %d\n", + DPRINTK("gred_dump:failed to malloc for %Zd\n", sizeof(struct tc_gred_qopt)*MAX_DPs); goto rtattr_failure; } @@ -521,7 +524,6 @@ if (!table->initd) { DPRINTK("NO GRED Queues setup!\n"); - return -1; } for (i=0;irta_len = skb->tail - b; + kfree(opt); return skb->len; rtattr_failure: + if (opt) + kfree(opt); DPRINTK("gred_dump: FAILURE!!!!\n"); /* also free the opt struct here */ skb_trim(skb, b - skb->data); return -1; } -#endif static void gred_destroy(struct Qdisc *sch) { @@ -615,9 +619,7 @@ gred_reset, gred_destroy, gred_change, /* change */ -#ifdef CONFIG_RTNETLINK gred_dump, -#endif }; @@ -632,3 +634,4 @@ unregister_qdisc(&gred_qdisc_ops); } #endif +MODULE_LICENSE("GPL"); diff -urN ../v2.2.21-ds8/linux/net/sched/sch_ingress.c linux/net/sched/sch_ingress.c --- ../v2.2.21-ds8/linux/net/sched/sch_ingress.c Wed Jul 31 03:00:59 2002 +++ linux/net/sched/sch_ingress.c Sun Aug 4 21:02:57 2002 @@ -13,14 +13,15 @@ #include #include +#undef DEBUG_INGRESS -#if 1 /* control */ +#ifdef DEBUG_INGRESS /* control */ #define DPRINTK(format,args...) printk(KERN_DEBUG format,##args) #else #define DPRINTK(format,args...) #endif -#if 0 /* data */ +#if 0 /* data */ #define D2PRINTK(format,args...) printk(KERN_DEBUG format,##args) #else #define D2PRINTK(format,args...) @@ -43,10 +44,12 @@ static int ingress_graft(struct Qdisc *sch,unsigned long arg, struct Qdisc *new,struct Qdisc **old) { +#ifdef DEBUG_INGRESS struct ingress_qdisc_data *p = PRIV(sch); +#endif - DPRINTK("ingress_graft(sch %p,[qdisc %p],new %p,old %p)\n",sch,p,new, - old); + DPRINTK("ingress_graft(sch %p,[qdisc %p],new %p,old %p)\n", + sch, p, new, old); DPRINTK("\n ingress_graft: You cannot add qdiscs to classes"); return 1; } @@ -60,17 +63,18 @@ static unsigned long ingress_get(struct Qdisc *sch,u32 classid) { +#ifdef DEBUG_INGRESS struct ingress_qdisc_data *p = PRIV(sch); - - DPRINTK("ingress_get(sch %p,[qdisc %p],classid %x)\n",sch,p,classid); - return TC_H_MIN(classid)+1; +#endif + DPRINTK("ingress_get(sch %p,[qdisc %p],classid %x)\n", sch, p, classid); + return TC_H_MIN(classid) + 1; } static unsigned long ingress_bind_filter(struct Qdisc *sch, unsigned long parent, u32 classid) { - return ingress_get(sch,classid); + return ingress_get(sch, classid); } @@ -82,10 +86,11 @@ static int ingress_change(struct Qdisc *sch, u32 classid, u32 parent, struct rtattr **tca, unsigned long *arg) { +#ifdef DEBUG_INGRESS struct ingress_qdisc_data *p = PRIV(sch); - +#endif DPRINTK("ingress_change(sch %p,[qdisc %p],classid %x,parent %x)," - "arg 0x%lx\n",sch,p,classid,parent,*arg); + "arg 0x%lx\n", sch, p, classid, parent, *arg); DPRINTK("No effect. sch_ingress doesnt maintain classes at the moment"); return 0; } @@ -94,9 +99,10 @@ static void ingress_walk(struct Qdisc *sch,struct qdisc_walker *walker) { +#ifdef DEBUG_INGRESS struct ingress_qdisc_data *p = PRIV(sch); - - DPRINTK("ingress_walk(sch %p,[qdisc %p],walker %p)\n",sch,p,walker); +#endif + DPRINTK("ingress_walk(sch %p,[qdisc %p],walker %p)\n", sch, p, walker); DPRINTK("No effect. sch_ingress doesnt maintain classes at the moment"); } @@ -118,32 +124,34 @@ struct tcf_result res; int result; - D2PRINTK("ingress_enqueue(skb %p,sch %p,[qdisc %p])\n",skb,sch,p); - - result = tc_classify(skb,p->filter_list,&res); - D2PRINTK("result %d class 0x%04x\n",result,res.classid); + D2PRINTK("ingress_enqueue(skb %p,sch %p,[qdisc %p])\n", skb, sch, p); + result = tc_classify(skb, p->filter_list, &res); + D2PRINTK("result %d class 0x%04x\n", result, res.classid); /* * Unlike normal "enqueue" functions, ingress_enqueue returns a * firewall FW_* code. */ - switch (result) { #ifdef CONFIG_NET_CLS_POLICE + switch (result) { case TC_POLICE_SHOT: result = FW_BLOCK; + sch->stats.drops++; break; case TC_POLICE_RECLASSIFY: /* DSCP remarking here ? */ case TC_POLICE_OK: case TC_POLICE_UNSPEC: default: + sch->stats.packets++; + sch->stats.bytes += skb->len; result = FW_ACCEPT; break; -#endif - } - -#ifdef CONFIG_NET_CLS_TCINDEX - skb->tc_index = TC_H_MIN(res.classid); + }; +#else + sch->stats.packets++; + sch->stats.bytes += skb->len; #endif + skb->tc_index = TC_H_MIN(res.classid); return result; } @@ -152,8 +160,8 @@ { /* struct ingress_qdisc_data *p = PRIV(sch); -*/ D2PRINTK("ingress_dequeue(sch %p,[qdisc %p])\n",sch,PRIV(p)); +*/ return NULL; } @@ -162,16 +170,17 @@ { /* struct ingress_qdisc_data *p = PRIV(sch); -*/ D2PRINTK("ingress_requeue(skb %p,sch %p,[qdisc %p])\n",skb,sch,PRIV(p)); +*/ return 0; } static int ingress_drop(struct Qdisc *sch) { +#ifdef DEBUG_INGRESS struct ingress_qdisc_data *p = PRIV(sch); - - DPRINTK("ingress_drop(sch %p,[qdisc %p])\n",sch,p); +#endif + DPRINTK("ingress_drop(sch %p,[qdisc %p])\n", sch, p); return 0; } @@ -181,10 +190,9 @@ struct ingress_qdisc_data *p = PRIV(sch); DPRINTK("ingress_init(sch %p,[qdisc %p],opt %p)\n",sch,p,opt); - memset(p,0,sizeof(*p)); + memset(p, 0, sizeof(*p)); p->filter_list = NULL; - p->q=NULL; - DPRINTK("ingress_init: qdisc %p\n",sch); + p->q = &noop_qdisc; MOD_INC_USE_COUNT; return 0; } @@ -194,13 +202,16 @@ { struct ingress_qdisc_data *p = PRIV(sch); - DPRINTK("ingress_reset(sch %p,[qdisc %p])\n",sch,p); + DPRINTK("ingress_reset(sch %p,[qdisc %p])\n", sch, p); /* - sch->ingress=0; +#if 0 */ /* for future use */ qdisc_reset(p->q); +/* +#endif +*/ } @@ -209,46 +220,40 @@ struct ingress_qdisc_data *p = PRIV(sch); struct tcf_proto *tp; - DPRINTK("ingress_destroy(sch %p,[qdisc %p])\n",sch,p); + DPRINTK("ingress_destroy(sch %p,[qdisc %p])\n", sch, p); while (p->filter_list) { tp = p->filter_list; p->filter_list = tp->next; tp->ops->destroy(tp); } - memset(p,0,sizeof(*p)); - p->filter_list = NULL; + memset(p, 0, sizeof(*p)); + p->filter_list = NULL; +#if 0 /* for future use */ qdisc_destroy(p->q); - +#endif + MOD_DEC_USE_COUNT; -} - -#ifdef CONFIG_RTNETLINK +} static int ingress_dump(struct Qdisc *sch, struct sk_buff *skb) { -/* - struct ingress_qdisc_data *p = PRIV(sch); -*/ unsigned char *b = skb->tail; struct rtattr *rta; rta = (struct rtattr *) b; - RTA_PUT(skb,TCA_OPTIONS,0,NULL); - rta->rta_len = skb->tail-b; + RTA_PUT(skb, TCA_OPTIONS, 0, NULL); + rta->rta_len = skb->tail - b; return skb->len; rtattr_failure: - skb_trim(skb,b-skb->data); + skb_trim(skb, b - skb->data); return -1; } -#endif - - static struct Qdisc_class_ops ingress_class_ops = { ingress_graft, /* graft */ @@ -263,9 +268,7 @@ ingress_bind_filter, /* bind_tcf */ ingress_put, /* unbind_tcf */ -#ifdef CONFIG_RTNETLINK NULL, /* dump */ -#endif }; struct Qdisc_ops ingress_qdisc_ops = @@ -285,15 +288,21 @@ ingress_destroy, /* destroy */ NULL, /* change */ -#ifdef CONFIG_RTNETLINK ingress_dump, /* dump */ -#endif }; + #ifdef MODULE int init_module(void) { - return register_qdisc(&ingress_qdisc_ops); + int ret = 0; + + if ((ret = register_qdisc(&ingress_qdisc_ops)) < 0) { + printk("Unable to register Ingress qdisc\n"); + return ret; + } + + return ret; } diff -urN ../v2.2.21-ds8/linux/net/sched/sch_prio.c linux/net/sched/sch_prio.c --- ../v2.2.21-ds8/linux/net/sched/sch_prio.c Wed Jul 31 03:00:59 2002 +++ linux/net/sched/sch_prio.c Sat Jul 6 01:06:27 2002 @@ -71,17 +71,18 @@ { struct prio_sched_data *q = (struct prio_sched_data *)sch->data; struct Qdisc *qdisc; + int ret; qdisc = q->queues[prio_classify(skb, sch)]; - if (qdisc->enqueue(skb, qdisc) == 1) { + if ((ret = qdisc->enqueue(skb, qdisc)) == 0) { sch->stats.bytes += skb->len; sch->stats.packets++; sch->q.qlen++; - return 1; + return 0; } sch->stats.drops++; - return 0; + return ret; } @@ -90,15 +91,16 @@ { struct prio_sched_data *q = (struct prio_sched_data *)sch->data; struct Qdisc *qdisc; + int ret; qdisc = q->queues[prio_classify(skb, sch)]; - if (qdisc->ops->requeue(skb, qdisc) == 1) { + if ((ret = qdisc->ops->requeue(skb, qdisc)) == 0) { sch->q.qlen++; - return 1; + return 0; } sch->stats.drops++; - return 0; + return ret; } @@ -180,7 +182,7 @@ return -EINVAL; } - start_bh_atomic(); + sch_tree_lock(sch); q->bands = qopt->bands; memcpy(q->prio2band, qopt->priomap, TC_PRIO_MAX+1); @@ -189,7 +191,7 @@ if (child != &noop_qdisc) qdisc_destroy(child); } - end_bh_atomic(); + sch_tree_unlock(sch); for (i=0; i<=TC_PRIO_MAX; i++) { int band = q->prio2band[i]; @@ -197,11 +199,12 @@ struct Qdisc *child; child = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops); if (child) { + sch_tree_lock(sch); child = xchg(&q->queues[band], child); - synchronize_bh(); if (child != &noop_qdisc) qdisc_destroy(child); + sch_tree_unlock(sch); } } } @@ -210,10 +213,6 @@ static int prio_init(struct Qdisc *sch, struct rtattr *opt) { -/* - static const u8 prio2band[TC_PRIO_MAX+1] = - { 1, 2, 2, 2, 1, 2, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1 }; -*/ struct prio_sched_data *q = (struct prio_sched_data *)sch->data; int i; @@ -232,7 +231,6 @@ return 0; } -#ifdef CONFIG_RTNETLINK static int prio_dump(struct Qdisc *sch, struct sk_buff *skb) { struct prio_sched_data *q = (struct prio_sched_data *)sch->data; @@ -248,7 +246,6 @@ skb_trim(skb, b - skb->data); return -1; } -#endif static int prio_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new, struct Qdisc **old) @@ -262,7 +259,11 @@ if (new == NULL) new = &noop_qdisc; - *old = xchg(&q->queues[band], new); + sch_tree_lock(sch); + *old = q->queues[band]; + q->queues[band] = new; + qdisc_reset(*old); + sch_tree_unlock(sch); return 0; } @@ -319,7 +320,6 @@ } -#ifdef CONFIG_RTNETLINK static int prio_dump_class(struct Qdisc *sch, unsigned long cl, struct sk_buff *skb, struct tcmsg *tcm) { @@ -327,11 +327,11 @@ if (cl - 1 > q->bands) return -ENOENT; + tcm->tcm_handle |= TC_H_MIN(cl); if (q->queues[cl-1]) tcm->tcm_info = q->queues[cl-1]->handle; return 0; } -#endif static void prio_walk(struct Qdisc *sch, struct qdisc_walker *arg) { @@ -378,9 +378,7 @@ prio_bind, prio_put, -#ifdef CONFIG_RTNETLINK prio_dump_class, -#endif }; struct Qdisc_ops prio_qdisc_ops = @@ -400,9 +398,7 @@ prio_destroy, prio_tune, -#ifdef CONFIG_RTNETLINK prio_dump, -#endif }; #ifdef MODULE @@ -418,3 +414,4 @@ } #endif +MODULE_LICENSE("GPL"); diff -urN ../v2.2.21-ds8/linux/net/sched/sch_red.c linux/net/sched/sch_red.c --- ../v2.2.21-ds8/linux/net/sched/sch_red.c Sat Oct 21 15:11:29 2000 +++ linux/net/sched/sch_red.c Fri Aug 2 05:41:03 2002 @@ -10,6 +10,8 @@ * * Changes: * J Hadi Salim 980914: computation fixes + * Alexey Makarenko 990814: qave on idle link was calculated incorrectly. + * J Hadi Salim 980816: ECN support */ #include @@ -38,6 +40,9 @@ #include #include +#define RED_ECN_ECT 0x02 +#define RED_ECN_CE 0x01 + /* Random Early Detection (RED) algorithm. ======================================= @@ -137,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; @@ -148,8 +154,43 @@ 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)) + IP_ECN_set_ce(skb->nh.iph); + + 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) { @@ -159,6 +200,8 @@ if (!PSCHED_IS_PASTPERFECT(q->qidlestart)) { long us_idle; + int shift; + PSCHED_GET_TIME(now); us_idle = PSCHED_TDIFF_SAFE(now, q->qidlestart, q->Scell_max, 0); PSCHED_SET_PASTPERFECT(q->qidlestart); @@ -179,7 +222,25 @@ I believe that a simpler model may be used here, but it is field for experiments. */ - q->qave >>= q->Stab[(us_idle>>q->Scell_log)&0xFF]; + shift = q->Stab[us_idle>>q->Scell_log]; + + if (shift) { + q->qave >>= shift; + } else { + /* Approximate initial part of exponent + with linear function: + (1-W)^m ~= 1-mW + ... + + Seems, it is the best solution to + problem of too coarce exponent tabulation. + */ + + us_idle = (q->qave * us_idle)>>q->Scell_log; + if (us_idle < q->qave/2) + q->qave -= us_idle; + else + q->qave >>= 1; + } } else { q->qave += sch->stats.backlog - (q->qave >> q->Wlog); /* NOTE: @@ -200,18 +261,26 @@ sch->stats.backlog += skb->len; sch->stats.bytes += skb->len; sch->stats.packets++; - return 1; + return NET_XMIT_SUCCESS; + } else { + q->st.pdrop++; } -drop: kfree_skb(skb); sch->stats.drops++; - return 0; + return NET_XMIT_DROP; } if (q->qave >= q->qth_max) { q->qcount = -1; sch->stats.overlimits++; - goto drop; +mark: + 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. @@ -234,10 +303,15 @@ q->qcount = 0; q->qR = net_random()&q->Rmask; sch->stats.overlimits++; - goto drop; + goto mark; } q->qR = net_random()&q->Rmask; goto enqueue; + +drop: + kfree_skb(skb); + sch->stats.drops++; + return NET_XMIT_CN; } static int @@ -249,7 +323,7 @@ __skb_queue_head(&sch->q, skb); sch->stats.backlog += skb->len; - return 1; + return 0; } static struct sk_buff * @@ -277,6 +351,7 @@ if (skb) { sch->stats.backlog -= skb->len; sch->stats.drops++; + q->st.other++; kfree_skb(skb); return 1; } @@ -287,17 +362,15 @@ static void red_reset(struct Qdisc* sch) { struct red_sched_data *q = (struct red_sched_data *)sch->data; - struct sk_buff *skb; - while((skb=__skb_dequeue(&sch->q))!=NULL) - kfree_skb(skb); + __skb_queue_purge(&sch->q); sch->stats.backlog = 0; PSCHED_SET_PASTPERFECT(q->qidlestart); q->qave = 0; q->qcount = -1; } -static int red_init(struct Qdisc *sch, struct rtattr *opt) +static int red_change(struct Qdisc *sch, struct rtattr *opt) { struct red_sched_data *q = (struct red_sched_data *)sch->data; struct rtattr *tb[TCA_RED_STAB]; @@ -312,6 +385,8 @@ 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<Plog) - 1) : ~0UL; @@ -323,12 +398,34 @@ memcpy(q->Stab, RTA_DATA(tb[TCA_RED_STAB-1]), 256); q->qcount = -1; - PSCHED_SET_PASTPERFECT(q->qidlestart); - MOD_INC_USE_COUNT; + if (skb_queue_len(&sch->q) == 0) + PSCHED_SET_PASTPERFECT(q->qidlestart); + sch_tree_unlock(sch); return 0; } -#ifdef CONFIG_RTNETLINK +static int red_init(struct Qdisc* sch, struct rtattr *opt) +{ + int err; + + MOD_INC_USE_COUNT; + + if ((err = red_change(sch, opt)) != 0) { + MOD_DEC_USE_COUNT; + } + return err; +} + + +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; @@ -344,16 +441,19 @@ 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: skb_trim(skb, b - skb->data); return -1; } -#endif static void red_destroy(struct Qdisc *sch) { @@ -375,11 +475,9 @@ red_init, red_reset, red_destroy, - NULL /* red_change */, + red_change, -#ifdef CONFIG_RTNETLINK red_dump, -#endif }; @@ -394,3 +492,4 @@ unregister_qdisc(&red_qdisc_ops); } #endif +MODULE_LICENSE("GPL"); diff -urN ../v2.2.21-ds8/linux/net/sched/sch_sfq.c linux/net/sched/sch_sfq.c --- ../v2.2.21-ds8/linux/net/sched/sch_sfq.c Sat Oct 21 15:10:57 2000 +++ linux/net/sched/sch_sfq.c Sat Jul 6 01:06:27 2002 @@ -105,6 +105,7 @@ /* Parameters */ int perturb_period; unsigned quantum; /* Allotment per round: MUST BE >= MTU */ + int limit; /* Variables */ struct timer_list perturb_timer; @@ -275,14 +276,14 @@ q->tail = x; } } - if (++sch->q.qlen < SFQ_DEPTH-1) { + if (++sch->q.qlen < q->limit-1) { sch->stats.bytes += skb->len; sch->stats.packets++; - return 1; + return 0; } sfq_drop(sch); - return 0; + return NET_XMIT_CN; } static int @@ -310,12 +311,12 @@ q->tail = x; } } - if (++sch->q.qlen < SFQ_DEPTH-1) - return 1; + if (++sch->q.qlen < q->limit - 1) + return 0; sch->stats.drops++; sfq_drop(sch); - return 0; + return NET_XMIT_CN; } @@ -387,16 +388,21 @@ if (opt->rta_len < RTA_LENGTH(sizeof(*ctl))) return -EINVAL; - start_bh_atomic(); + sch_tree_lock(sch); q->quantum = ctl->quantum ? : psched_mtu(sch->dev); q->perturb_period = ctl->perturb_period*HZ; + if (ctl->limit) + q->limit = min_t(u32, ctl->limit, SFQ_DEPTH); + + while (sch->q.qlen >= q->limit-1) + sfq_drop(sch); del_timer(&q->perturb_timer); if (q->perturb_period) { q->perturb_timer.expires = jiffies + q->perturb_period; add_timer(&q->perturb_timer); } - end_bh_atomic(); + sch_tree_unlock(sch); return 0; } @@ -416,6 +422,7 @@ q->dep[i+SFQ_DEPTH].next = i+SFQ_DEPTH; q->dep[i+SFQ_DEPTH].prev = i+SFQ_DEPTH; } + q->limit = SFQ_DEPTH; q->max_depth = 0; q->tail = SFQ_DEPTH; if (opt == NULL) { @@ -439,7 +446,6 @@ MOD_DEC_USE_COUNT; } -#ifdef CONFIG_RTNETLINK static int sfq_dump(struct Qdisc *sch, struct sk_buff *skb) { struct sfq_sched_data *q = (struct sfq_sched_data *)sch->data; @@ -449,9 +455,9 @@ opt.quantum = q->quantum; opt.perturb_period = q->perturb_period/HZ; - opt.limit = SFQ_DEPTH; + opt.limit = q->limit; opt.divisor = SFQ_HASH_DIVISOR; - opt.flows = SFQ_DEPTH; + opt.flows = q->limit; RTA_PUT(skb, TCA_OPTIONS, sizeof(opt), &opt); @@ -461,7 +467,6 @@ skb_trim(skb, b - skb->data); return -1; } -#endif struct Qdisc_ops sfq_qdisc_ops = { @@ -480,9 +485,7 @@ sfq_destroy, NULL, /* sfq_change */ -#ifdef CONFIG_RTNETLINK sfq_dump, -#endif }; #ifdef MODULE @@ -496,3 +499,4 @@ unregister_qdisc(&sfq_qdisc_ops); } #endif +MODULE_LICENSE("GPL"); diff -urN ../v2.2.21-ds8/linux/net/sched/sch_tbf.c linux/net/sched/sch_tbf.c --- ../v2.2.21-ds8/linux/net/sched/sch_tbf.c Sat Oct 21 15:10:47 2000 +++ linux/net/sched/sch_tbf.c Sun Mar 31 06:18:30 2002 @@ -66,7 +66,7 @@ N(t+delta) = min{B/R, N(t) + delta} If the first packet in queue has length S, it may be - transmited only at the time t_* when S/R <= N(t_*), + transmitted only at the time t_* when S/R <= N(t_*), and in this case N(t) jumps: N(t_* + 0) = N(t_* - 0) - S/R. @@ -139,7 +139,7 @@ if ((sch->stats.backlog += skb->len) <= q->limit) { sch->stats.bytes += skb->len; sch->stats.packets++; - return 1; + return 0; } /* Drop action: undo the things that we just did, @@ -155,7 +155,7 @@ if (sch->reshape_fail==NULL || sch->reshape_fail(skb, sch)) #endif kfree_skb(skb); - return 0; + return NET_XMIT_DROP; } static int @@ -163,7 +163,7 @@ { __skb_queue_head(&sch->q, skb); sch->stats.backlog += skb->len; - return 1; + return 0; } static int @@ -186,7 +186,7 @@ struct Qdisc *sch = (struct Qdisc*)arg; sch->flags &= ~TCQ_F_THROTTLED; - qdisc_wakeup(sch->dev); + netif_schedule(sch->dev); } static struct sk_buff * @@ -226,15 +226,13 @@ return skb; } - if (!sch->dev->tbusy) { - long delay = PSCHED_US2JIFFIE(max(-toks, -ptoks)); + if (!netif_queue_stopped(sch->dev)) { + long delay = PSCHED_US2JIFFIE(max_t(long, -toks, -ptoks)); if (delay == 0) delay = 1; - del_timer(&q->wd_timer); - q->wd_timer.expires = jiffies + delay; - add_timer(&q->wd_timer); + mod_timer(&q->wd_timer, jiffies+delay); } /* Maybe we have a shorter packet in the queue, @@ -278,7 +276,7 @@ struct tc_tbf_qopt *qopt; struct qdisc_rate_table *rtab = NULL; struct qdisc_rate_table *ptab = NULL; - int max_size; + int max_size,n; if (rtattr_parse(tb, TCA_TBF_PTAB, RTA_DATA(opt), RTA_PAYLOAD(opt)) || tb[TCA_TBF_PARMS-1] == NULL || @@ -297,18 +295,21 @@ goto done; } - max_size = psched_mtu(sch->dev); + for (n = 0; n < 256; n++) + if (rtab->data[n] > qopt->buffer) break; + max_size = (n << qopt->rate.cell_log)-1; if (ptab) { - int n = max_size>>qopt->peakrate.cell_log; - while (n>0 && ptab->data[n-1] > qopt->mtu) { - max_size -= (1<peakrate.cell_log); - n--; - } + int size; + + for (n = 0; n < 256; n++) + if (ptab->data[n] > qopt->mtu) break; + size = (n << qopt->peakrate.cell_log)-1; + if (size < max_size) max_size = size; } - if (rtab->data[max_size>>qopt->rate.cell_log] > qopt->buffer) + if (max_size < 0) goto done; - start_bh_atomic(); + sch_tree_lock(sch); q->limit = qopt->limit; q->mtu = qopt->mtu; q->max_size = max_size; @@ -317,7 +318,7 @@ q->ptokens = q->mtu; rtab = xchg(&q->R_tab, rtab); ptab = xchg(&q->P_tab, ptab); - end_bh_atomic(); + sch_tree_unlock(sch); err = 0; done: if (rtab) @@ -362,7 +363,6 @@ MOD_DEC_USE_COUNT; } -#ifdef CONFIG_RTNETLINK static int tbf_dump(struct Qdisc *sch, struct sk_buff *skb) { struct tbf_sched_data *q = (struct tbf_sched_data *)sch->data; @@ -390,7 +390,6 @@ skb_trim(skb, b - skb->data); return -1; } -#endif struct Qdisc_ops tbf_qdisc_ops = { @@ -409,9 +408,7 @@ tbf_destroy, tbf_change, -#ifdef CONFIG_RTNETLINK tbf_dump, -#endif }; @@ -426,3 +423,4 @@ unregister_qdisc(&tbf_qdisc_ops); } #endif +MODULE_LICENSE("GPL"); diff -urN ../v2.2.21-ds8/linux/net/sched/sch_teql.c linux/net/sched/sch_teql.c --- ../v2.2.21-ds8/linux/net/sched/sch_teql.c Sat Oct 21 15:10:47 2000 +++ linux/net/sched/sch_teql.c Sun Aug 4 21:06:40 2002 @@ -97,13 +97,13 @@ if (q->q.qlen <= dev->tx_queue_len) { sch->stats.bytes += skb->len; sch->stats.packets++; - return 1; + return 0; } __skb_unlink(skb, &q->q); kfree_skb(skb); sch->stats.drops++; - return 0; + return NET_XMIT_DROP; } static int @@ -112,7 +112,7 @@ struct teql_sched_data *q = (struct teql_sched_data *)sch->data; __skb_queue_head(&q->q, skb); - return 1; + return 0; } static struct sk_buff * @@ -167,7 +167,9 @@ master->slaves = NEXT_SLAVE(q); if (q == master->slaves) { master->slaves = NULL; + sch_dev_queue_lock(&master->dev); qdisc_reset(master->dev.qdisc); + sch_dev_queue_unlock(&master->dev); } } skb_queue_purge(&dat->q); @@ -189,6 +191,9 @@ if (dev->hard_header_len > m->dev.hard_header_len) return -EINVAL; + + if (&m->dev == dev) + return -ELOOP; q->m = m;