Netdev List
 help / color / mirror / Atom feed
* Re: 2.6.24 regression: reference count leak in PPPoE
From: Pavel Machek @ 2008-01-20 22:59 UTC (permalink / raw)
  To: Andi Kleen; +Cc: netdev, linux-kernel
In-Reply-To: <200801202053.30386.ak@suse.de>

Hi!

> My workstation running 2.6.24-rc8 just hung during shutdown with an endless 
> (or rather I didn't wait more than a few minutes) loop of 
> 
> unregister_netdev: waiting for ppp-device to become free. Usage count = 1
> 
> ppp-device was an active PPPoE device.
> 
> No more information currently.

Actually, I'm getting something similar:

usb 2-2: USB disconnect, address 23
PM: Removing info for No Bus:usbdev2.23_ep83
usb0: unregister 'cdc_ether' usb-0000:00:1d.0-2, CDC Ethernet Device
PM: Removing info for No Bus:usb0
unregister_netdevice: waiting for usb0 to become free. Usage count = 1
unregister_netdevice: waiting for usb0 to become free. Usage count = 1
unregister_netdevice: waiting for usb0 to become free. Usage count = 1
unregister_netdevice: waiting for usb0 to become free. Usage count = 1
unregister_netdevice: waiting for usb0 to become free. Usage count = 1
unregister_netdevice: waiting for usb0 to become free. Usage count = 1
PM: Removing info for usb:2-2:1.0
PM: Removing info for No Bus:usbdev2.23_ep81
PM: Removing info for No Bus:usbdev2.23_ep02

The unregister_netdevice made it onto console, that means pretty
severe log level. Happened while playing with openmoko connected with
USB cable.
									Pavel
-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

^ permalink raw reply

* [PATCH] net classifier: style cleanup's
From: Stephen Hemminger @ 2008-01-20 22:06 UTC (permalink / raw)
  To: David Miller, Patrick McHardy; +Cc: netdev

Classifier code cleanup. Get rid of printk wrapper, and fix whitespace
and other style stuff reported by checkpatch

---
 net/sched/cls_api.c     |  100 +++++++++++++++++++++++-------------------------
 net/sched/cls_tcindex.c |   60 +++++++++++-----------------
 2 files changed, 73 insertions(+), 87 deletions(-)

--- a/net/sched/cls_api.c	2008-01-20 13:33:11.000000000 -0800
+++ b/net/sched/cls_api.c	2008-01-20 13:46:04.000000000 -0800
@@ -29,12 +29,6 @@
 #include <net/pkt_sched.h>
 #include <net/pkt_cls.h>
 
-#if 0 /* control */
-#define DPRINTK(format,args...) printk(KERN_DEBUG format,##args)
-#else
-#define DPRINTK(format,args...)
-#endif
-
 /* The list of all installed classifier types */
 
 static struct tcf_proto_ops *tcf_proto_base;
@@ -44,7 +38,7 @@ static DEFINE_RWLOCK(cls_mod_lock);
 
 /* Find classifier type by string name */
 
-static struct tcf_proto_ops * tcf_proto_lookup_ops(struct rtattr *kind)
+static struct tcf_proto_ops *tcf_proto_lookup_ops(struct rtattr *kind)
 {
 	struct tcf_proto_ops *t = NULL;
 
@@ -81,6 +75,7 @@ out:
 	write_unlock(&cls_mod_lock);
 	return rc;
 }
+EXPORT_SYMBOL(register_tcf_proto_ops);
 
 int unregister_tcf_proto_ops(struct tcf_proto_ops *ops)
 {
@@ -100,6 +95,7 @@ out:
 	write_unlock(&cls_mod_lock);
 	return rc;
 }
+EXPORT_SYMBOL(unregister_tcf_proto_ops);
 
 static int tfilter_notify(struct sk_buff *oskb, struct nlmsghdr *n,
 			  struct tcf_proto *tp, unsigned long fh, int event);
@@ -107,9 +103,9 @@ static int tfilter_notify(struct sk_buff
 
 /* Select new prio value from the range, managed by kernel. */
 
-static __inline__ u32 tcf_auto_prio(struct tcf_proto *tp)
+static inline u32 tcf_auto_prio(struct tcf_proto *tp)
 {
-	u32 first = TC_H_MAKE(0xC0000000U,0U);
+	u32 first = TC_H_MAKE(0xC0000000U, 0U);
 
 	if (tp)
 		first = tp->prio-1;
@@ -154,21 +150,25 @@ replay:
 		/* If no priority is given, user wants we allocated it. */
 		if (n->nlmsg_type != RTM_NEWTFILTER || !(n->nlmsg_flags&NLM_F_CREATE))
 			return -ENOENT;
-		prio = TC_H_MAKE(0x80000000U,0U);
+		prio = TC_H_MAKE(0x80000000U, 0U);
 	}
 
 	/* Find head of filter chain. */
 
 	/* Find link */
-	if ((dev = __dev_get_by_index(&init_net, t->tcm_ifindex)) == NULL)
+	dev = __dev_get_by_index(&init_net, t->tcm_ifindex);
+	if (dev == NULL)
 		return -ENODEV;
 
 	/* Find qdisc */
 	if (!parent) {
 		q = dev->qdisc_sleeping;
 		parent = q->handle;
-	} else if ((q = qdisc_lookup(dev, TC_H_MAJ(t->tcm_parent))) == NULL)
-		return -EINVAL;
+	} else {
+		q = qdisc_lookup(dev, TC_H_MAJ(t->tcm_parent));
+		if (q == NULL)
+			return -EINVAL;
+	}
 
 	/* Is it classful? */
 	if ((cops = q->ops->cl_ops) == NULL)
@@ -213,7 +213,8 @@ replay:
 		/* Create new proto tcf */
 
 		err = -ENOBUFS;
-		if ((tp = kzalloc(sizeof(*tp), GFP_KERNEL)) == NULL)
+		tp = kzalloc(sizeof(*tp), GFP_KERNEL);
+		if (tp == NULL)
 			goto errout;
 		err = -EINVAL;
 		tp_ops = tcf_proto_lookup_ops(tca[TCA_KIND-1]);
@@ -249,7 +250,9 @@ replay:
 		tp->q = q;
 		tp->classify = tp_ops->classify;
 		tp->classid = parent;
-		if ((err = tp_ops->init(tp)) != 0) {
+
+		err = tp_ops->init(tp);
+		if (err != 0) {
 			module_put(tp_ops->owner);
 			kfree(tp);
 			goto errout;
@@ -278,13 +281,14 @@ replay:
 		}
 
 		err = -ENOENT;
-		if (n->nlmsg_type != RTM_NEWTFILTER || !(n->nlmsg_flags&NLM_F_CREATE))
+		if (n->nlmsg_type != RTM_NEWTFILTER ||
+		    !(n->nlmsg_flags & NLM_F_CREATE))
 			goto errout;
 	} else {
 		switch (n->nlmsg_type) {
 		case RTM_NEWTFILTER:
 			err = -EEXIST;
-			if (n->nlmsg_flags&NLM_F_EXCL)
+			if (n->nlmsg_flags & NLM_F_EXCL)
 				goto errout;
 			break;
 		case RTM_DELTFILTER:
@@ -314,9 +318,8 @@ errout:
 	return err;
 }
 
-static int
-tcf_fill_node(struct sk_buff *skb, struct tcf_proto *tp, unsigned long fh,
-	      u32 pid, u32 seq, u16 flags, int event)
+static int tcf_fill_node(struct sk_buff *skb, struct tcf_proto *tp,
+			 unsigned long fh, u32 pid, u32 seq, u16 flags, int event)
 {
 	struct tcmsg *tcm;
 	struct nlmsghdr  *nlh;
@@ -361,19 +364,20 @@ static int tfilter_notify(struct sk_buff
 		return -EINVAL;
 	}
 
-	return rtnetlink_send(skb, &init_net, pid, RTNLGRP_TC, n->nlmsg_flags&NLM_F_ECHO);
+	return rtnetlink_send(skb, &init_net, pid, RTNLGRP_TC,
+			      n->nlmsg_flags & NLM_F_ECHO);
 }
 
-struct tcf_dump_args
-{
+struct tcf_dump_args {
 	struct tcf_walker w;
 	struct sk_buff *skb;
 	struct netlink_callback *cb;
 };
 
-static int tcf_node_dump(struct tcf_proto *tp, unsigned long n, struct tcf_walker *arg)
+static int tcf_node_dump(struct tcf_proto *tp, unsigned long n,
+			 struct tcf_walker *arg)
 {
-	struct tcf_dump_args *a = (void*)arg;
+	struct tcf_dump_args *a = (void *)arg;
 
 	return tcf_fill_node(a->skb, tp, n, NETLINK_CB(a->cb->skb).pid,
 			     a->cb->nlh->nlmsg_seq, NLM_F_MULTI, RTM_NEWTFILTER);
@@ -387,7 +391,7 @@ static int tc_dump_tfilter(struct sk_buf
 	struct net_device *dev;
 	struct Qdisc *q;
 	struct tcf_proto *tp, **chain;
-	struct tcmsg *tcm = (struct tcmsg*)NLMSG_DATA(cb->nlh);
+	struct tcmsg *tcm = (struct tcmsg *)NLMSG_DATA(cb->nlh);
 	unsigned long cl = 0;
 	const struct Qdisc_class_ops *cops;
 	struct tcf_dump_args arg;
@@ -431,9 +435,10 @@ static int tc_dump_tfilter(struct sk_buf
 			memset(&cb->args[1], 0, sizeof(cb->args)-sizeof(cb->args[0]));
 		if (cb->args[1] == 0) {
 			if (tcf_fill_node(skb, tp, 0, NETLINK_CB(cb->skb).pid,
-					  cb->nlh->nlmsg_seq, NLM_F_MULTI, RTM_NEWTFILTER) <= 0) {
+					  cb->nlh->nlmsg_seq, NLM_F_MULTI,
+					  RTM_NEWTFILTER) <= 0)
 				break;
-			}
+
 			cb->args[1] = 1;
 		}
 		if (tp->ops->walk == NULL)
@@ -460,8 +465,7 @@ out:
 	return skb->len;
 }
 
-void
-tcf_exts_destroy(struct tcf_proto *tp, struct tcf_exts *exts)
+void tcf_exts_destroy(struct tcf_proto *tp, struct tcf_exts *exts)
 {
 #ifdef CONFIG_NET_CLS_ACT
 	if (exts->action) {
@@ -470,10 +474,9 @@ tcf_exts_destroy(struct tcf_proto *tp, s
 	}
 #endif
 }
+EXPORT_SYMBOL(tcf_exts_destroy);
 
-
-int
-tcf_exts_validate(struct tcf_proto *tp, struct rtattr **tb,
+int tcf_exts_validate(struct tcf_proto *tp, struct rtattr **tb,
 		  struct rtattr *rate_tlv, struct tcf_exts *exts,
 		  struct tcf_ext_map *map)
 {
@@ -485,8 +488,9 @@ tcf_exts_validate(struct tcf_proto *tp, 
 		struct tc_action *act;
 
 		if (map->police && tb[map->police-1]) {
-			act = tcf_action_init_1(tb[map->police-1], rate_tlv, "police",
-				TCA_ACT_NOREPLACE, TCA_ACT_BIND, &err);
+			act = tcf_action_init_1(tb[map->police-1], rate_tlv,
+						"police", TCA_ACT_NOREPLACE,
+						TCA_ACT_BIND, &err);
 			if (act == NULL)
 				return err;
 
@@ -509,10 +513,10 @@ tcf_exts_validate(struct tcf_proto *tp, 
 
 	return 0;
 }
+EXPORT_SYMBOL(tcf_exts_validate);
 
-void
-tcf_exts_change(struct tcf_proto *tp, struct tcf_exts *dst,
-		struct tcf_exts *src)
+void tcf_exts_change(struct tcf_proto *tp, struct tcf_exts *dst,
+		     struct tcf_exts *src)
 {
 #ifdef CONFIG_NET_CLS_ACT
 	if (src->action) {
@@ -525,9 +529,9 @@ tcf_exts_change(struct tcf_proto *tp, st
 	}
 #endif
 }
+EXPORT_SYMBOL(tcf_exts_change);
 
-int
-tcf_exts_dump(struct sk_buff *skb, struct tcf_exts *exts,
+int tcf_exts_dump(struct sk_buff *skb, struct tcf_exts *exts,
 	      struct tcf_ext_map *map)
 {
 #ifdef CONFIG_NET_CLS_ACT
@@ -556,10 +560,11 @@ tcf_exts_dump(struct sk_buff *skb, struc
 rtattr_failure: __attribute__ ((unused))
 	return -1;
 }
+EXPORT_SYMBOL(tcf_exts_dump);
 
-int
-tcf_exts_dump_stats(struct sk_buff *skb, struct tcf_exts *exts,
-		    struct tcf_ext_map *map)
+
+int tcf_exts_dump_stats(struct sk_buff *skb, struct tcf_exts *exts,
+			struct tcf_ext_map *map)
 {
 #ifdef CONFIG_NET_CLS_ACT
 	if (exts->action)
@@ -570,6 +575,7 @@ tcf_exts_dump_stats(struct sk_buff *skb,
 rtattr_failure: __attribute__ ((unused))
 	return -1;
 }
+EXPORT_SYMBOL(tcf_exts_dump_stats);
 
 static int __init tc_filter_init(void)
 {
@@ -582,11 +588,3 @@ static int __init tc_filter_init(void)
 }
 
 subsys_initcall(tc_filter_init);
-
-EXPORT_SYMBOL(register_tcf_proto_ops);
-EXPORT_SYMBOL(unregister_tcf_proto_ops);
-EXPORT_SYMBOL(tcf_exts_validate);
-EXPORT_SYMBOL(tcf_exts_destroy);
-EXPORT_SYMBOL(tcf_exts_change);
-EXPORT_SYMBOL(tcf_exts_dump);
-EXPORT_SYMBOL(tcf_exts_dump_stats);
--- a/net/sched/cls_tcindex.c	2008-01-20 13:33:47.000000000 -0800
+++ b/net/sched/cls_tcindex.c	2008-01-20 13:50:55.000000000 -0800
@@ -29,19 +29,6 @@
 #define DEFAULT_HASH_SIZE	64	/* optimized for diffserv */
 
 
-#if 1 /* control */
-#define DPRINTK(format,args...) printk(KERN_DEBUG format,##args)
-#else
-#define DPRINTK(format,args...)
-#endif
-
-#if 0 /* data */
-#define D2PRINTK(format,args...) printk(KERN_DEBUG format,##args)
-#else
-#define D2PRINTK(format,args...)
-#endif
-
-
 #define	PRIV(tp)	((struct tcindex_data *) (tp)->root)
 
 
@@ -104,7 +91,8 @@ static int tcindex_classify(struct sk_bu
 	struct tcindex_filter_result *f;
 	int key = (skb->tc_index & p->mask) >> p->shift;
 
-	D2PRINTK("tcindex_classify(skb %p,tp %p,res %p),p %p\n",skb,tp,res,p);
+	pr_debug("tcindex_classify(skb %p,tp %p,res %p),p %p\n",
+		 skb, tp, res, p);
 
 	f = tcindex_lookup(p, key);
 	if (!f) {
@@ -112,11 +100,11 @@ static int tcindex_classify(struct sk_bu
 			return -1;
 		res->classid = TC_H_MAKE(TC_H_MAJ(tp->q->handle), key);
 		res->class = 0;
-		D2PRINTK("alg 0x%x\n",res->classid);
+		pr_debug("alg 0x%x\n", res->classid);
 		return 0;
 	}
 	*res = f->res;
-	D2PRINTK("map 0x%x\n",res->classid);
+	pr_debug("map 0x%x\n", res->classid);
 
 	return tcf_exts_exec(skb, &f->exts, res);
 }
@@ -127,7 +115,7 @@ static unsigned long tcindex_get(struct 
 	struct tcindex_data *p = PRIV(tp);
 	struct tcindex_filter_result *r;
 
-	DPRINTK("tcindex_get(tp %p,handle 0x%08x)\n",tp,handle);
+	pr_debug("tcindex_get(tp %p,handle 0x%08x)\n", tp, handle);
 	if (p->perfect && handle >= p->alloc_hash)
 		return 0;
 	r = tcindex_lookup(p, handle);
@@ -137,7 +125,7 @@ static unsigned long tcindex_get(struct 
 
 static void tcindex_put(struct tcf_proto *tp, unsigned long f)
 {
-	DPRINTK("tcindex_put(tp %p,f 0x%lx)\n",tp,f);
+	pr_debug("tcindex_put(tp %p,f 0x%lx)\n", tp, f);
 }
 
 
@@ -145,8 +133,8 @@ static int tcindex_init(struct tcf_proto
 {
 	struct tcindex_data *p;
 
-	DPRINTK("tcindex_init(tp %p)\n",tp);
-	p = kzalloc(sizeof(struct tcindex_data),GFP_KERNEL);
+	pr_debug("tcindex_init(tp %p)\n", tp);
+	p = kzalloc(sizeof(struct tcindex_data), GFP_KERNEL);
 	if (!p)
 		return -ENOMEM;
 
@@ -166,7 +154,7 @@ __tcindex_delete(struct tcf_proto *tp, u
 	struct tcindex_filter_result *r = (struct tcindex_filter_result *) arg;
 	struct tcindex_filter *f = NULL;
 
-	DPRINTK("tcindex_delete(tp %p,arg 0x%lx),p %p,f %p\n",tp,arg,p,f);
+	pr_debug("tcindex_delete(tp %p,arg 0x%lx),p %p,f %p\n", tp, arg, p, f);
 	if (p->perfect) {
 		if (!r->res.class)
 			return -ENOENT;
@@ -363,7 +351,7 @@ tcindex_change(struct tcf_proto *tp, uns
 	struct tcindex_data *p = PRIV(tp);
 	struct tcindex_filter_result *r = (struct tcindex_filter_result *) *arg;
 
-	DPRINTK("tcindex_change(tp %p,handle 0x%08x,tca %p,arg %p),opt %p,"
+	pr_debug("tcindex_change(tp %p,handle 0x%08x,tca %p,arg %p),opt %p,"
 	    "p %p,r %p,*arg 0x%lx\n",
 	    tp, handle, tca, arg, opt, p, r, arg ? *arg : 0L);
 
@@ -380,10 +368,10 @@ tcindex_change(struct tcf_proto *tp, uns
 static void tcindex_walk(struct tcf_proto *tp, struct tcf_walker *walker)
 {
 	struct tcindex_data *p = PRIV(tp);
-	struct tcindex_filter *f,*next;
+	struct tcindex_filter *f, *next;
 	int i;
 
-	DPRINTK("tcindex_walk(tp %p,walker %p),p %p\n",tp,walker,p);
+	pr_debug("tcindex_walk(tp %p,walker %p),p %p\n", tp, walker, p);
 	if (p->perfect) {
 		for (i = 0; i < p->hash; i++) {
 			if (!p->perfect[i].res.class)
@@ -405,7 +393,7 @@ static void tcindex_walk(struct tcf_prot
 		for (f = p->h[i]; f; f = next) {
 			next = f->next;
 			if (walker->count >= walker->skip) {
-				if (walker->fn(tp,(unsigned long) &f->result,
+				if (walker->fn(tp, (unsigned long) &f->result,
 				    walker) < 0) {
 					walker->stop = 1;
 					return;
@@ -429,11 +417,11 @@ static void tcindex_destroy(struct tcf_p
 	struct tcindex_data *p = PRIV(tp);
 	struct tcf_walker walker;
 
-	DPRINTK("tcindex_destroy(tp %p),p %p\n",tp,p);
+	pr_debug("tcindex_destroy(tp %p),p %p\n", tp, p);
 	walker.count = 0;
 	walker.skip = 0;
 	walker.fn = &tcindex_destroy_element;
-	tcindex_walk(tp,&walker);
+	tcindex_walk(tp, &walker);
 	kfree(p->perfect);
 	kfree(p->h);
 	kfree(p);
@@ -449,17 +437,17 @@ static int tcindex_dump(struct tcf_proto
 	unsigned char *b = skb_tail_pointer(skb);
 	struct rtattr *rta;
 
-	DPRINTK("tcindex_dump(tp %p,fh 0x%lx,skb %p,t %p),p %p,r %p,b %p\n",
-	    tp,fh,skb,t,p,r,b);
-	DPRINTK("p->perfect %p p->h %p\n",p->perfect,p->h);
+	pr_debug("tcindex_dump(tp %p,fh 0x%lx,skb %p,t %p),p %p,r %p,b %p\n",
+		 tp, fh, skb, t, p, r, b);
+	pr_debug("p->perfect %p p->h %p\n", p->perfect, p->h);
 	rta = (struct rtattr *) b;
-	RTA_PUT(skb,TCA_OPTIONS,0,NULL);
+	RTA_PUT(skb, TCA_OPTIONS, 0, NULL);
 	if (!fh) {
 		t->tcm_handle = ~0; /* whatever ... */
-		RTA_PUT(skb,TCA_TCINDEX_HASH,sizeof(p->hash),&p->hash);
-		RTA_PUT(skb,TCA_TCINDEX_MASK,sizeof(p->mask),&p->mask);
-		RTA_PUT(skb,TCA_TCINDEX_SHIFT,sizeof(p->shift),&p->shift);
-		RTA_PUT(skb,TCA_TCINDEX_FALL_THROUGH,sizeof(p->fall_through),
+		RTA_PUT(skb, TCA_TCINDEX_HASH, sizeof(p->hash), &p->hash);
+		RTA_PUT(skb, TCA_TCINDEX_MASK, sizeof(p->mask), &p->mask);
+		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);
 		rta->rta_len = skb_tail_pointer(skb) - b;
 	} else {
@@ -478,7 +466,7 @@ static int tcindex_dump(struct tcf_proto
 				}
 			}
 		}
-		DPRINTK("handle = %d\n",t->tcm_handle);
+		pr_debug("handle = %d\n", t->tcm_handle);
 		if (r->res.class)
 			RTA_PUT(skb, TCA_TCINDEX_CLASSID, 4, &r->res.classid);
 

^ permalink raw reply

* [PATCH] sch_atm: style cleanup
From: Stephen Hemminger @ 2008-01-20 22:03 UTC (permalink / raw)
  To: David Miller, Patrick McHardy, Chas Williams; +Cc: netdev, linux-atm-general

ATM scheduler clean house:
  * get rid of printk and qdisc_priv() wrapper
  * split some assignment in if() statements
  * whitespace and line breaks.

Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>

--- a/net/sched/sch_atm.c	2008-01-20 13:51:58.000000000 -0800
+++ b/net/sched/sch_atm.c	2008-01-20 13:59:16.000000000 -0800
@@ -16,18 +16,6 @@
 
 extern struct socket *sockfd_lookup(int fd, int *err);	/* @@@ fix this */
 
-#if 0 /* control */
-#define DPRINTK(format,args...) printk(KERN_DEBUG format,##args)
-#else
-#define DPRINTK(format,args...)
-#endif
-
-#if 0 /* data */
-#define D2PRINTK(format,args...) printk(KERN_DEBUG format,##args)
-#else
-#define D2PRINTK(format,args...)
-#endif
-
 /*
  * The ATM queuing discipline provides a framework for invoking classifiers
  * (aka "filters"), which in turn select classes of this queuing discipline.
@@ -49,7 +37,6 @@ extern struct socket *sockfd_lookup(int 
  *  - should lock the flow while there is data in the queue (?)
  */
 
-#define PRIV(sch) qdisc_priv(sch)
 #define VCC2FLOW(vcc) ((struct atm_flow_data *) ((vcc)->user_back))
 
 struct atm_flow_data {
@@ -57,7 +44,7 @@ struct atm_flow_data {
 	struct tcf_proto	*filter_list;
 	struct atm_vcc		*vcc;	/* VCC; NULL if VCC is closed */
 	void			(*old_pop)(struct atm_vcc *vcc,
-					   struct sk_buff * skb); /* chaining */
+					   struct sk_buff *skb); /* chaining */
 	struct atm_qdisc_data	*parent;	/* parent qdisc */
 	struct socket		*sock;		/* for closing */
 	u32			classid;	/* x:y type ID */
@@ -84,17 +71,17 @@ static int find_flow(struct atm_qdisc_da
 {
 	struct atm_flow_data *walk;
 
-	DPRINTK("find_flow(qdisc %p,flow %p)\n", qdisc, flow);
+	pr_debug("find_flow(qdisc %p,flow %p)\n", qdisc, flow);
 	for (walk = qdisc->flows; walk; walk = walk->next)
 		if (walk == flow)
 			return 1;
-	DPRINTK("find_flow: not found\n");
+	pr_debug("find_flow: not found\n");
 	return 0;
 }
 
 static inline struct atm_flow_data *lookup_flow(struct Qdisc *sch, u32 classid)
 {
-	struct atm_qdisc_data *p = PRIV(sch);
+	struct atm_qdisc_data *p = qdisc_priv(sch);
 	struct atm_flow_data *flow;
 
 	for (flow = p->flows; flow; flow = flow->next)
@@ -106,10 +93,10 @@ static inline struct atm_flow_data *look
 static int atm_tc_graft(struct Qdisc *sch, unsigned long arg,
 			struct Qdisc *new, struct Qdisc **old)
 {
-	struct atm_qdisc_data *p = PRIV(sch);
+	struct atm_qdisc_data *p = qdisc_priv(sch);
 	struct atm_flow_data *flow = (struct atm_flow_data *)arg;
 
-	DPRINTK("atm_tc_graft(sch %p,[qdisc %p],flow %p,new %p,old %p)\n",
+	pr_debug("atm_tc_graft(sch %p,[qdisc %p],flow %p,new %p,old %p)\n",
 		sch, p, flow, new, old);
 	if (!find_flow(p, flow))
 		return -EINVAL;
@@ -125,20 +112,20 @@ static struct Qdisc *atm_tc_leaf(struct 
 {
 	struct atm_flow_data *flow = (struct atm_flow_data *)cl;
 
-	DPRINTK("atm_tc_leaf(sch %p,flow %p)\n", sch, flow);
+	pr_debug("atm_tc_leaf(sch %p,flow %p)\n", sch, flow);
 	return flow ? flow->q : NULL;
 }
 
 static unsigned long atm_tc_get(struct Qdisc *sch, u32 classid)
 {
-	struct atm_qdisc_data *p __maybe_unused = PRIV(sch);
+	struct atm_qdisc_data *p __maybe_unused = qdisc_priv(sch);
 	struct atm_flow_data *flow;
 
-	DPRINTK("atm_tc_get(sch %p,[qdisc %p],classid %x)\n", sch, p, classid);
+	pr_debug("atm_tc_get(sch %p,[qdisc %p],classid %x)\n", sch, p, classid);
 	flow = lookup_flow(sch, classid);
 	if (flow)
 		flow->ref++;
-	DPRINTK("atm_tc_get: flow %p\n", flow);
+	pr_debug("atm_tc_get: flow %p\n", flow);
 	return (unsigned long)flow;
 }
 
@@ -155,14 +142,14 @@ static unsigned long atm_tc_bind_filter(
  */
 static void atm_tc_put(struct Qdisc *sch, unsigned long cl)
 {
-	struct atm_qdisc_data *p = PRIV(sch);
+	struct atm_qdisc_data *p = qdisc_priv(sch);
 	struct atm_flow_data *flow = (struct atm_flow_data *)cl;
 	struct atm_flow_data **prev;
 
-	DPRINTK("atm_tc_put(sch %p,[qdisc %p],flow %p)\n", sch, p, flow);
+	pr_debug("atm_tc_put(sch %p,[qdisc %p],flow %p)\n", sch, p, flow);
 	if (--flow->ref)
 		return;
-	DPRINTK("atm_tc_put: destroying\n");
+	pr_debug("atm_tc_put: destroying\n");
 	for (prev = &p->flows; *prev; prev = &(*prev)->next)
 		if (*prev == flow)
 			break;
@@ -171,11 +158,11 @@ static void atm_tc_put(struct Qdisc *sch
 		return;
 	}
 	*prev = flow->next;
-	DPRINTK("atm_tc_put: qdisc %p\n", flow->q);
+	pr_debug("atm_tc_put: qdisc %p\n", flow->q);
 	qdisc_destroy(flow->q);
 	tcf_destroy_chain(flow->filter_list);
 	if (flow->sock) {
-		DPRINTK("atm_tc_put: f_count %d\n",
+		pr_debug("atm_tc_put: f_count %d\n",
 			file_count(flow->sock->file));
 		flow->vcc->pop = flow->old_pop;
 		sockfd_put(flow->sock);
@@ -194,7 +181,7 @@ static void sch_atm_pop(struct atm_vcc *
 {
 	struct atm_qdisc_data *p = VCC2FLOW(vcc)->parent;
 
-	D2PRINTK("sch_atm_pop(vcc %p,skb %p,[qdisc %p])\n", vcc, skb, p);
+	pr_debug("sch_atm_pop(vcc %p,skb %p,[qdisc %p])\n", vcc, skb, p);
 	VCC2FLOW(vcc)->old_pop(vcc, skb);
 	tasklet_schedule(&p->task);
 }
@@ -211,7 +198,7 @@ static const u8 llc_oui_ip[] = {
 static int atm_tc_change(struct Qdisc *sch, u32 classid, u32 parent,
 			 struct rtattr **tca, unsigned long *arg)
 {
-	struct atm_qdisc_data *p = PRIV(sch);
+	struct atm_qdisc_data *p = qdisc_priv(sch);
 	struct atm_flow_data *flow = (struct atm_flow_data *)*arg;
 	struct atm_flow_data *excess = NULL;
 	struct rtattr *opt = tca[TCA_OPTIONS - 1];
@@ -220,7 +207,7 @@ static int atm_tc_change(struct Qdisc *s
 	int fd, error, hdr_len;
 	void *hdr;
 
-	DPRINTK("atm_tc_change(sch %p,[qdisc %p],classid %x,parent %x,"
+	pr_debug("atm_tc_change(sch %p,[qdisc %p],classid %x,parent %x,"
 		"flow %p,opt %p)\n", sch, p, classid, parent, flow, opt);
 	/*
 	 * The concept of parents doesn't apply for this qdisc.
@@ -241,7 +228,7 @@ static int atm_tc_change(struct Qdisc *s
 	if (!tb[TCA_ATM_FD - 1] || RTA_PAYLOAD(tb[TCA_ATM_FD - 1]) < sizeof(fd))
 		return -EINVAL;
 	fd = *(int *)RTA_DATA(tb[TCA_ATM_FD - 1]);
-	DPRINTK("atm_tc_change: fd %d\n", fd);
+	pr_debug("atm_tc_change: fd %d\n", fd);
 	if (tb[TCA_ATM_HDR - 1]) {
 		hdr_len = RTA_PAYLOAD(tb[TCA_ATM_HDR - 1]);
 		hdr = RTA_DATA(tb[TCA_ATM_HDR - 1]);
@@ -259,11 +246,12 @@ static int atm_tc_change(struct Qdisc *s
 		if (!excess)
 			return -ENOENT;
 	}
-	DPRINTK("atm_tc_change: type %d, payload %d, hdr_len %d\n",
-		opt->rta_type, RTA_PAYLOAD(opt), hdr_len);
-	if (!(sock = sockfd_lookup(fd, &error)))
+	pr_debug("atm_tc_change: type %d, payload %lu, hdr_len %d\n",
+		 opt->rta_type, RTA_PAYLOAD(opt), hdr_len);
+	sock = sockfd_lookup(fd, &error);
+	if (!sock)
 		return error;	/* f_count++ */
-	DPRINTK("atm_tc_change: f_count %d\n", file_count(sock->file));
+	pr_debug("atm_tc_change: f_count %d\n", file_count(sock->file));
 	if (sock->ops->family != PF_ATMSVC && sock->ops->family != PF_ATMPVC) {
 		error = -EPROTOTYPE;
 		goto err_out;
@@ -272,7 +260,7 @@ static int atm_tc_change(struct Qdisc *s
 	   on vcc->send */
 	if (classid) {
 		if (TC_H_MAJ(classid ^ sch->handle)) {
-			DPRINTK("atm_tc_change: classid mismatch\n");
+			pr_debug("atm_tc_change: classid mismatch\n");
 			error = -EINVAL;
 			goto err_out;
 		}
@@ -286,26 +274,28 @@ static int atm_tc_change(struct Qdisc *s
 
 		for (i = 1; i < 0x8000; i++) {
 			classid = TC_H_MAKE(sch->handle, 0x8000 | i);
-			if (!(cl = atm_tc_get(sch, classid)))
+			cl = atm_tc_get(sch, classid);
+			if (!cl)
 				break;
 			atm_tc_put(sch, cl);
 		}
 	}
-	DPRINTK("atm_tc_change: new id %x\n", classid);
+	pr_debug("atm_tc_change: new id %x\n", classid);
 	flow = kzalloc(sizeof(struct atm_flow_data) + hdr_len, GFP_KERNEL);
-	DPRINTK("atm_tc_change: flow %p\n", flow);
+	pr_debug("atm_tc_change: flow %p\n", flow);
 	if (!flow) {
 		error = -ENOBUFS;
 		goto err_out;
 	}
 	flow->filter_list = NULL;
-	if (!(flow->q = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops, classid)))
+	flow->q = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops, classid);
+	if (!flow->q)
 		flow->q = &noop_qdisc;
-	DPRINTK("atm_tc_change: qdisc %p\n", flow->q);
+	pr_debug("atm_tc_change: qdisc %p\n", flow->q);
 	flow->sock = sock;
 	flow->vcc = ATM_SD(sock);	/* speedup */
 	flow->vcc->user_back = flow;
-	DPRINTK("atm_tc_change: vcc %p\n", flow->vcc);
+	pr_debug("atm_tc_change: vcc %p\n", flow->vcc);
 	flow->old_pop = flow->vcc->pop;
 	flow->parent = p;
 	flow->vcc->pop = sch_atm_pop;
@@ -330,11 +320,11 @@ err_out:
 
 static int atm_tc_delete(struct Qdisc *sch, unsigned long arg)
 {
-	struct atm_qdisc_data *p = PRIV(sch);
+	struct atm_qdisc_data *p = qdisc_priv(sch);
 	struct atm_flow_data *flow = (struct atm_flow_data *)arg;
 
-	DPRINTK("atm_tc_delete(sch %p,[qdisc %p],flow %p)\n", sch, p, flow);
-	if (!find_flow(PRIV(sch), flow))
+	pr_debug("atm_tc_delete(sch %p,[qdisc %p],flow %p)\n", sch, p, flow);
+	if (!find_flow(qdisc_priv(sch), flow))
 		return -EINVAL;
 	if (flow->filter_list || flow == &p->link)
 		return -EBUSY;
@@ -354,10 +344,10 @@ static int atm_tc_delete(struct Qdisc *s
 
 static void atm_tc_walk(struct Qdisc *sch, struct qdisc_walker *walker)
 {
-	struct atm_qdisc_data *p = PRIV(sch);
+	struct atm_qdisc_data *p = qdisc_priv(sch);
 	struct atm_flow_data *flow;
 
-	DPRINTK("atm_tc_walk(sch %p,[qdisc %p],walker %p)\n", sch, p, walker);
+	pr_debug("atm_tc_walk(sch %p,[qdisc %p],walker %p)\n", sch, p, walker);
 	if (walker->stop)
 		return;
 	for (flow = p->flows; flow; flow = flow->next) {
@@ -372,10 +362,10 @@ static void atm_tc_walk(struct Qdisc *sc
 
 static struct tcf_proto **atm_tc_find_tcf(struct Qdisc *sch, unsigned long cl)
 {
-	struct atm_qdisc_data *p = PRIV(sch);
+	struct atm_qdisc_data *p = qdisc_priv(sch);
 	struct atm_flow_data *flow = (struct atm_flow_data *)cl;
 
-	DPRINTK("atm_tc_find_tcf(sch %p,[qdisc %p],flow %p)\n", sch, p, flow);
+	pr_debug("atm_tc_find_tcf(sch %p,[qdisc %p],flow %p)\n", sch, p, flow);
 	return flow ? &flow->filter_list : &p->link.filter_list;
 }
 
@@ -383,13 +373,13 @@ static struct tcf_proto **atm_tc_find_tc
 
 static int atm_tc_enqueue(struct sk_buff *skb, struct Qdisc *sch)
 {
-	struct atm_qdisc_data *p = PRIV(sch);
+	struct atm_qdisc_data *p = qdisc_priv(sch);
 	struct atm_flow_data *flow = NULL;	/* @@@ */
 	struct tcf_result res;
 	int result;
 	int ret = NET_XMIT_POLICED;
 
-	D2PRINTK("atm_tc_enqueue(skb %p,sch %p,[qdisc %p])\n", skb, sch, p);
+	pr_debug("atm_tc_enqueue(skb %p,sch %p,[qdisc %p])\n", skb, sch, p);
 	result = TC_POLICE_OK;	/* be nice to gcc */
 	if (TC_H_MAJ(skb->priority) != sch->handle ||
 	    !(flow = (struct atm_flow_data *)atm_tc_get(sch, skb->priority)))
@@ -430,7 +420,8 @@ static int atm_tc_enqueue(struct sk_buff
 #endif
 	}
 
-	if ((ret = flow->q->enqueue(skb, flow->q)) != 0) {
+	ret = flow->q->enqueue(skb, flow->q);
+	if (ret != 0) {
 drop: __maybe_unused
 		sch->qstats.drops++;
 		if (flow)
@@ -468,11 +459,11 @@ drop: __maybe_unused
 static void sch_atm_dequeue(unsigned long data)
 {
 	struct Qdisc *sch = (struct Qdisc *)data;
-	struct atm_qdisc_data *p = PRIV(sch);
+	struct atm_qdisc_data *p = qdisc_priv(sch);
 	struct atm_flow_data *flow;
 	struct sk_buff *skb;
 
-	D2PRINTK("sch_atm_dequeue(sch %p,[qdisc %p])\n", sch, p);
+	pr_debug("sch_atm_dequeue(sch %p,[qdisc %p])\n", sch, p);
 	for (flow = p->link.next; flow; flow = flow->next)
 		/*
 		 * If traffic is properly shaped, this won't generate nasty
@@ -483,7 +474,7 @@ static void sch_atm_dequeue(unsigned lon
 				(void)flow->q->ops->requeue(skb, flow->q);
 				break;
 			}
-			D2PRINTK("atm_tc_dequeue: sending on class %p\n", flow);
+			pr_debug("atm_tc_dequeue: sending on class %p\n", flow);
 			/* remove any LL header somebody else has attached */
 			skb_pull(skb, skb_network_offset(skb));
 			if (skb_headroom(skb) < flow->hdr_len) {
@@ -495,7 +486,7 @@ static void sch_atm_dequeue(unsigned lon
 					continue;
 				skb = new;
 			}
-			D2PRINTK("sch_atm_dequeue: ip %p, data %p\n",
+			pr_debug("sch_atm_dequeue: ip %p, data %p\n",
 				 skb_network_header(skb), skb->data);
 			ATM_SKB(skb)->vcc = flow->vcc;
 			memcpy(skb_push(skb, flow->hdr_len), flow->hdr,
@@ -509,10 +500,10 @@ static void sch_atm_dequeue(unsigned lon
 
 static struct sk_buff *atm_tc_dequeue(struct Qdisc *sch)
 {
-	struct atm_qdisc_data *p = PRIV(sch);
+	struct atm_qdisc_data *p = qdisc_priv(sch);
 	struct sk_buff *skb;
 
-	D2PRINTK("atm_tc_dequeue(sch %p,[qdisc %p])\n", sch, p);
+	pr_debug("atm_tc_dequeue(sch %p,[qdisc %p])\n", sch, p);
 	tasklet_schedule(&p->task);
 	skb = p->link.q->dequeue(p->link.q);
 	if (skb)
@@ -522,10 +513,10 @@ static struct sk_buff *atm_tc_dequeue(st
 
 static int atm_tc_requeue(struct sk_buff *skb, struct Qdisc *sch)
 {
-	struct atm_qdisc_data *p = PRIV(sch);
+	struct atm_qdisc_data *p = qdisc_priv(sch);
 	int ret;
 
-	D2PRINTK("atm_tc_requeue(skb %p,sch %p,[qdisc %p])\n", skb, sch, p);
+	pr_debug("atm_tc_requeue(skb %p,sch %p,[qdisc %p])\n", skb, sch, p);
 	ret = p->link.q->ops->requeue(skb, p->link.q);
 	if (!ret) {
 		sch->q.qlen++;
@@ -539,11 +530,11 @@ static int atm_tc_requeue(struct sk_buff
 
 static unsigned int atm_tc_drop(struct Qdisc *sch)
 {
-	struct atm_qdisc_data *p = PRIV(sch);
+	struct atm_qdisc_data *p = qdisc_priv(sch);
 	struct atm_flow_data *flow;
 	unsigned int len;
 
-	DPRINTK("atm_tc_drop(sch %p,[qdisc %p])\n", sch, p);
+	pr_debug("atm_tc_drop(sch %p,[qdisc %p])\n", sch, p);
 	for (flow = p->flows; flow; flow = flow->next)
 		if (flow->q->ops->drop && (len = flow->q->ops->drop(flow->q)))
 			return len;
@@ -552,14 +543,14 @@ static unsigned int atm_tc_drop(struct Q
 
 static int atm_tc_init(struct Qdisc *sch, struct rtattr *opt)
 {
-	struct atm_qdisc_data *p = PRIV(sch);
+	struct atm_qdisc_data *p = qdisc_priv(sch);
 
-	DPRINTK("atm_tc_init(sch %p,[qdisc %p],opt %p)\n", sch, p, opt);
+	pr_debug("atm_tc_init(sch %p,[qdisc %p],opt %p)\n", sch, p, opt);
 	p->flows = &p->link;
-	if (!(p->link.q = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops,
-					    sch->handle)))
+	p->link.q = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops, sch->handle);
+	if (!p->link.q)
 		p->link.q = &noop_qdisc;
-	DPRINTK("atm_tc_init: link (%p) qdisc %p\n", &p->link, p->link.q);
+	pr_debug("atm_tc_init: link (%p) qdisc %p\n", &p->link, p->link.q);
 	p->link.filter_list = NULL;
 	p->link.vcc = NULL;
 	p->link.sock = NULL;
@@ -572,10 +563,10 @@ static int atm_tc_init(struct Qdisc *sch
 
 static void atm_tc_reset(struct Qdisc *sch)
 {
-	struct atm_qdisc_data *p = PRIV(sch);
+	struct atm_qdisc_data *p = qdisc_priv(sch);
 	struct atm_flow_data *flow;
 
-	DPRINTK("atm_tc_reset(sch %p,[qdisc %p])\n", sch, p);
+	pr_debug("atm_tc_reset(sch %p,[qdisc %p])\n", sch, p);
 	for (flow = p->flows; flow; flow = flow->next)
 		qdisc_reset(flow->q);
 	sch->q.qlen = 0;
@@ -583,10 +574,10 @@ static void atm_tc_reset(struct Qdisc *s
 
 static void atm_tc_destroy(struct Qdisc *sch)
 {
-	struct atm_qdisc_data *p = PRIV(sch);
+	struct atm_qdisc_data *p = qdisc_priv(sch);
 	struct atm_flow_data *flow;
 
-	DPRINTK("atm_tc_destroy(sch %p,[qdisc %p])\n", sch, p);
+	pr_debug("atm_tc_destroy(sch %p,[qdisc %p])\n", sch, p);
 	/* races ? */
 	while ((flow = p->flows)) {
 		tcf_destroy_chain(flow->filter_list);
@@ -608,12 +599,12 @@ static void atm_tc_destroy(struct Qdisc 
 static int atm_tc_dump_class(struct Qdisc *sch, unsigned long cl,
 			     struct sk_buff *skb, struct tcmsg *tcm)
 {
-	struct atm_qdisc_data *p = PRIV(sch);
+	struct atm_qdisc_data *p = qdisc_priv(sch);
 	struct atm_flow_data *flow = (struct atm_flow_data *)cl;
 	unsigned char *b = skb_tail_pointer(skb);
 	struct rtattr *rta;
 
-	DPRINTK("atm_tc_dump_class(sch %p,[qdisc %p],flow %p,skb %p,tcm %p)\n",
+	pr_debug("atm_tc_dump_class(sch %p,[qdisc %p],flow %p,skb %p,tcm %p)\n",
 		sch, p, flow, skb, tcm);
 	if (!find_flow(p, flow))
 		return -EINVAL;

^ permalink raw reply

* [PATCH 3/4] dsmark: handle cloned and non-linear skb's
From: Stephen Hemminger @ 2008-01-20 21:23 UTC (permalink / raw)
  To: David Miller; +Cc: Patrick McHardy, netdev
In-Reply-To: <20080120131008.2039a35d@deepthought>

Make dsmark work properly with non-linear and cloned skb's
Before modifying the header, it needs to check that skb header is
writeable.

Note: this makes the assumption, that if it queues a good skb
then a good skb will come out of the embedded qdisc.

Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>

--- a/net/sched/sch_dsmark.c	2008-01-20 13:22:54.000000000 -0800
+++ b/net/sched/sch_dsmark.c	2008-01-20 13:23:34.000000000 -0800
@@ -192,13 +192,19 @@ static int dsmark_enqueue(struct sk_buff
 	pr_debug("dsmark_enqueue(skb %p,sch %p,[qdisc %p])\n", skb, sch, p);
 
 	if (p->set_tc_index) {
-		/* FIXME: Safe with non-linear skbs? --RR */
 		switch (skb->protocol) {
 			case __constant_htons(ETH_P_IP):
+				if (skb_cow_head(skb, sizeof(struct iphdr)))
+					goto drop;
+
 				skb->tc_index = ipv4_get_dsfield(ip_hdr(skb))
 					& ~INET_ECN_MASK;
 				break;
+
 			case __constant_htons(ETH_P_IPV6):
+				if (skb_cow_head(skb, sizeof(struct ipv6hdr)))
+					goto drop;
+
 				skb->tc_index = ipv6_get_dsfield(ipv6_hdr(skb))
 					& ~INET_ECN_MASK;
 				break;
@@ -222,14 +228,14 @@ static int dsmark_enqueue(struct sk_buff
 		case TC_ACT_STOLEN:
 			kfree_skb(skb);
 			return NET_XMIT_SUCCESS;
+
 		case TC_ACT_SHOT:
-			kfree_skb(skb);
-			sch->qstats.drops++;
-			return NET_XMIT_BYPASS;
+			goto drop;
 #endif
 		case TC_ACT_OK:
 			skb->tc_index = TC_H_MIN(res.classid);
 			break;
+
 		default:
 			if (p->default_index != NO_DEFAULT_INDEX)
 				skb->tc_index = p->default_index;
@@ -248,6 +254,11 @@ static int dsmark_enqueue(struct sk_buff
 	sch->q.qlen++;
 
 	return NET_XMIT_SUCCESS;
+
+drop:
+	kfree_skb(skb);
+	sch->qstats.drops++;
+	return NET_XMIT_BYPASS;
 }
 
 static struct sk_buff *dsmark_dequeue(struct Qdisc *sch)

^ permalink raw reply

* [PATCH 1/4] dsmark: get rid of wrappers
From: Stephen Hemminger @ 2008-01-20 21:10 UTC (permalink / raw)
  To: David Miller, Patrick McHardy; +Cc: netdev

Remove extraneous macro wrappers for printk and qdisc_priv.

Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>


--- a/net/sched/sch_dsmark.c	2008-01-20 08:36:10.000000000 -0800
+++ b/net/sched/sch_dsmark.c	2008-01-20 08:47:26.000000000 -0800
@@ -15,23 +15,6 @@
 #include <net/inet_ecn.h>
 #include <asm/byteorder.h>
 
-
-#if 0 /* control */
-#define DPRINTK(format,args...) printk(KERN_DEBUG format,##args)
-#else
-#define DPRINTK(format,args...)
-#endif
-
-#if 0 /* data */
-#define D2PRINTK(format,args...) printk(KERN_DEBUG format,##args)
-#else
-#define D2PRINTK(format,args...)
-#endif
-
-
-#define PRIV(sch) ((struct dsmark_qdisc_data *) qdisc_priv(sch))
-
-
 /*
  * classid	class		marking
  * -------	-----		-------
@@ -81,9 +64,9 @@ static inline int dsmark_valid_index(str
 static int dsmark_graft(struct Qdisc *sch, unsigned long arg,
 			struct Qdisc *new, struct Qdisc **old)
 {
-	struct dsmark_qdisc_data *p = PRIV(sch);
+	struct dsmark_qdisc_data *p = qdisc_priv(sch);
 
-	DPRINTK("dsmark_graft(sch %p,[qdisc %p],new %p,old %p)\n",
+	pr_debug("dsmark_graft(sch %p,[qdisc %p],new %p,old %p)\n",
 		sch, p, new, old);
 
 	if (new == NULL) {
@@ -104,13 +87,14 @@ static int dsmark_graft(struct Qdisc *sc
 
 static struct Qdisc *dsmark_leaf(struct Qdisc *sch, unsigned long arg)
 {
-	return PRIV(sch)->q;
+	struct dsmark_qdisc_data *p = qdisc_priv(sch);
+	return p->q;
 }
 
 static unsigned long dsmark_get(struct Qdisc *sch, u32 classid)
 {
-	DPRINTK("dsmark_get(sch %p,[qdisc %p],classid %x)\n",
-		sch, PRIV(sch), classid);
+	pr_debug("dsmark_get(sch %p,[qdisc %p],classid %x)\n",
+		sch, qdisc_priv(sch), classid);
 
 	return TC_H_MIN(classid) + 1;
 }
@@ -128,13 +112,13 @@ static void dsmark_put(struct Qdisc *sch
 static int dsmark_change(struct Qdisc *sch, u32 classid, u32 parent,
 			 struct rtattr **tca, unsigned long *arg)
 {
-	struct dsmark_qdisc_data *p = PRIV(sch);
+	struct dsmark_qdisc_data *p = qdisc_priv(sch);
 	struct rtattr *opt = tca[TCA_OPTIONS-1];
 	struct rtattr *tb[TCA_DSMARK_MAX];
 	int err = -EINVAL;
 	u8 mask = 0;
 
-	DPRINTK("dsmark_change(sch %p,[qdisc %p],classid %x,parent %x),"
+	pr_debug("dsmark_change(sch %p,[qdisc %p],classid %x,parent %x),"
 		"arg 0x%lx\n", sch, p, classid, parent, *arg);
 
 	if (!dsmark_valid_index(p, *arg)) {
@@ -162,7 +146,7 @@ rtattr_failure:
 
 static int dsmark_delete(struct Qdisc *sch, unsigned long arg)
 {
-	struct dsmark_qdisc_data *p = PRIV(sch);
+	struct dsmark_qdisc_data *p = qdisc_priv(sch);
 
 	if (!dsmark_valid_index(p, arg))
 		return -EINVAL;
@@ -175,10 +159,10 @@ static int dsmark_delete(struct Qdisc *s
 
 static void dsmark_walk(struct Qdisc *sch,struct qdisc_walker *walker)
 {
-	struct dsmark_qdisc_data *p = PRIV(sch);
+	struct dsmark_qdisc_data *p = qdisc_priv(sch);
 	int i;
 
-	DPRINTK("dsmark_walk(sch %p,[qdisc %p],walker %p)\n", sch, p, walker);
+	pr_debug("dsmark_walk(sch %p,[qdisc %p],walker %p)\n", sch, p, walker);
 
 	if (walker->stop)
 		return;
@@ -197,19 +181,20 @@ ignore:
 	}
 }
 
-static struct tcf_proto **dsmark_find_tcf(struct Qdisc *sch,unsigned long cl)
+static inline struct tcf_proto **dsmark_find_tcf(struct Qdisc *sch,unsigned long cl)
 {
-	return &PRIV(sch)->filter_list;
+	struct dsmark_qdisc_data *p = qdisc_priv(sch);
+	return &p->filter_list;
 }
 
 /* --------------------------- Qdisc operations ---------------------------- */
 
 static int dsmark_enqueue(struct sk_buff *skb,struct Qdisc *sch)
 {
-	struct dsmark_qdisc_data *p = PRIV(sch);
+	struct dsmark_qdisc_data *p = qdisc_priv(sch);
 	int err;
 
-	D2PRINTK("dsmark_enqueue(skb %p,sch %p,[qdisc %p])\n", skb, sch, p);
+	pr_debug("dsmark_enqueue(skb %p,sch %p,[qdisc %p])\n", skb, sch, p);
 
 	if (p->set_tc_index) {
 		/* FIXME: Safe with non-linear skbs? --RR */
@@ -234,7 +219,7 @@ static int dsmark_enqueue(struct sk_buff
 		struct tcf_result res;
 		int result = tc_classify(skb, p->filter_list, &res);
 
-		D2PRINTK("result %d class 0x%04x\n", result, res.classid);
+		pr_debug("result %d class 0x%04x\n", result, res.classid);
 
 		switch (result) {
 #ifdef CONFIG_NET_CLS_ACT
@@ -272,11 +257,11 @@ static int dsmark_enqueue(struct sk_buff
 
 static struct sk_buff *dsmark_dequeue(struct Qdisc *sch)
 {
-	struct dsmark_qdisc_data *p = PRIV(sch);
+	struct dsmark_qdisc_data *p = qdisc_priv(sch);
 	struct sk_buff *skb;
 	u32 index;
 
-	D2PRINTK("dsmark_dequeue(sch %p,[qdisc %p])\n", sch, p);
+	pr_debug("dsmark_dequeue(sch %p,[qdisc %p])\n", sch, p);
 
 	skb = p->q->ops->dequeue(p->q);
 	if (skb == NULL)
@@ -285,7 +270,7 @@ static struct sk_buff *dsmark_dequeue(st
 	sch->q.qlen--;
 
 	index = skb->tc_index & (p->indices - 1);
-	D2PRINTK("index %d->%d\n", skb->tc_index, index);
+	pr_debug("index %d->%d\n", skb->tc_index, index);
 
 	switch (skb->protocol) {
 		case __constant_htons(ETH_P_IP):
@@ -314,10 +299,10 @@ static struct sk_buff *dsmark_dequeue(st
 
 static int dsmark_requeue(struct sk_buff *skb,struct Qdisc *sch)
 {
-	struct dsmark_qdisc_data *p = PRIV(sch);
+	struct dsmark_qdisc_data *p = qdisc_priv(sch);
 	int err;
 
-	D2PRINTK("dsmark_requeue(skb %p,sch %p,[qdisc %p])\n", skb, sch, p);
+	pr_debug("dsmark_requeue(skb %p,sch %p,[qdisc %p])\n", skb, sch, p);
 
 	err = p->q->ops->requeue(skb, p->q);
 	if (err != NET_XMIT_SUCCESS) {
@@ -333,10 +318,10 @@ static int dsmark_requeue(struct sk_buff
 
 static unsigned int dsmark_drop(struct Qdisc *sch)
 {
-	struct dsmark_qdisc_data *p = PRIV(sch);
+	struct dsmark_qdisc_data *p = qdisc_priv(sch);
 	unsigned int len;
 
-	DPRINTK("dsmark_reset(sch %p,[qdisc %p])\n", sch, p);
+	pr_debug("dsmark_reset(sch %p,[qdisc %p])\n", sch, p);
 
 	if (p->q->ops->drop == NULL)
 		return 0;
@@ -350,14 +335,14 @@ static unsigned int dsmark_drop(struct Q
 
 static int dsmark_init(struct Qdisc *sch, struct rtattr *opt)
 {
-	struct dsmark_qdisc_data *p = PRIV(sch);
+	struct dsmark_qdisc_data *p = qdisc_priv(sch);
 	struct rtattr *tb[TCA_DSMARK_MAX];
 	int err = -EINVAL;
 	u32 default_index = NO_DEFAULT_INDEX;
 	u16 indices;
 	u8 *mask;
 
-	DPRINTK("dsmark_init(sch %p,[qdisc %p],opt %p)\n", sch, p, opt);
+	pr_debug("dsmark_init(sch %p,[qdisc %p],opt %p)\n", sch, p, opt);
 
 	if (!opt || rtattr_parse_nested(tb, TCA_DSMARK_MAX, opt) < 0)
 		goto errout;
@@ -389,7 +374,7 @@ static int dsmark_init(struct Qdisc *sch
 	if (p->q == NULL)
 		p->q = &noop_qdisc;
 
-	DPRINTK("dsmark_init: qdisc %p\n", p->q);
+	pr_debug("dsmark_init: qdisc %p\n", p->q);
 
 	err = 0;
 errout:
@@ -399,18 +384,18 @@ rtattr_failure:
 
 static void dsmark_reset(struct Qdisc *sch)
 {
-	struct dsmark_qdisc_data *p = PRIV(sch);
+	struct dsmark_qdisc_data *p = qdisc_priv(sch);
 
-	DPRINTK("dsmark_reset(sch %p,[qdisc %p])\n", sch, p);
+	pr_debug("dsmark_reset(sch %p,[qdisc %p])\n", sch, p);
 	qdisc_reset(p->q);
 	sch->q.qlen = 0;
 }
 
 static void dsmark_destroy(struct Qdisc *sch)
 {
-	struct dsmark_qdisc_data *p = PRIV(sch);
+	struct dsmark_qdisc_data *p = qdisc_priv(sch);
 
-	DPRINTK("dsmark_destroy(sch %p,[qdisc %p])\n", sch, p);
+	pr_debug("dsmark_destroy(sch %p,[qdisc %p])\n", sch, p);
 
 	tcf_destroy_chain(p->filter_list);
 	qdisc_destroy(p->q);
@@ -420,10 +405,10 @@ static void dsmark_destroy(struct Qdisc 
 static int dsmark_dump_class(struct Qdisc *sch, unsigned long cl,
 			     struct sk_buff *skb, struct tcmsg *tcm)
 {
-	struct dsmark_qdisc_data *p = PRIV(sch);
+	struct dsmark_qdisc_data *p = qdisc_priv(sch);
 	struct rtattr *opts = NULL;
 
-	DPRINTK("dsmark_dump_class(sch %p,[qdisc %p],class %ld\n", sch, p, cl);
+	pr_debug("dsmark_dump_class(sch %p,[qdisc %p],class %ld\n", sch, p, cl);
 
 	if (!dsmark_valid_index(p, cl))
 		return -EINVAL;
@@ -443,7 +428,7 @@ rtattr_failure:
 
 static int dsmark_dump(struct Qdisc *sch, struct sk_buff *skb)
 {
-	struct dsmark_qdisc_data *p = PRIV(sch);
+	struct dsmark_qdisc_data *p = qdisc_priv(sch);
 	struct rtattr *opts = NULL;
 
 	opts = RTA_NEST(skb, TCA_OPTIONS);

^ permalink raw reply

* [PATCH 2/4] dsmark: get rid of trivial function
From: Stephen Hemminger @ 2008-01-20 21:25 UTC (permalink / raw)
  To: David Miller; +Cc: Patrick McHardy, netdev
In-Reply-To: <20080120130542.16720b45@deepthought>

Replace loop in dsmark_valid_indices with equivalent bit math.

Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>

--- a/net/sched/sch_dsmark.c	2008-01-20 13:07:58.000000000 -0800
+++ b/net/sched/sch_dsmark.c	2008-01-20 13:22:54.000000000 -0800
@@ -45,13 +45,8 @@ struct dsmark_qdisc_data {
 
 static inline int dsmark_valid_indices(u16 indices)
 {
-	while (indices != 1) {
-		if (indices & 1)
-			return 0;
-		indices >>= 1;
-	}
-
-	return 1;
+	/* Must have only one bit set */
+	return (indices & (indices - 1)) == 0;
 }
 
 static inline int dsmark_valid_index(struct dsmark_qdisc_data *p, u16 index)

^ permalink raw reply

* [PATCH 4/4] dsmark:  checkpatch warning cleanup
From: Stephen Hemminger @ 2008-01-20 21:25 UTC (permalink / raw)
  To: David Miller; +Cc: Patrick McHardy, netdev
In-Reply-To: <20080120131008.2039a35d@deepthought>

Get rid of all style things checkpatch warns about, indentation
and whitespace.

Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>

--- a/net/sched/sch_dsmark.c	2008-01-20 13:23:34.000000000 -0800
+++ b/net/sched/sch_dsmark.c	2008-01-20 13:24:45.000000000 -0800
@@ -152,7 +152,7 @@ static int dsmark_delete(struct Qdisc *s
 	return 0;
 }
 
-static void dsmark_walk(struct Qdisc *sch,struct qdisc_walker *walker)
+static void dsmark_walk(struct Qdisc *sch, struct qdisc_walker *walker)
 {
 	struct dsmark_qdisc_data *p = qdisc_priv(sch);
 	int i;
@@ -176,7 +176,8 @@ ignore:
 	}
 }
 
-static inline struct tcf_proto **dsmark_find_tcf(struct Qdisc *sch,unsigned long cl)
+static inline struct tcf_proto **dsmark_find_tcf(struct Qdisc *sch,
+						 unsigned long cl)
 {
 	struct dsmark_qdisc_data *p = qdisc_priv(sch);
 	return &p->filter_list;
@@ -184,7 +185,7 @@ static inline struct tcf_proto **dsmark_
 
 /* --------------------------- Qdisc operations ---------------------------- */
 
-static int dsmark_enqueue(struct sk_buff *skb,struct Qdisc *sch)
+static int dsmark_enqueue(struct sk_buff *skb, struct Qdisc *sch)
 {
 	struct dsmark_qdisc_data *p = qdisc_priv(sch);
 	int err;
@@ -193,24 +194,24 @@ static int dsmark_enqueue(struct sk_buff
 
 	if (p->set_tc_index) {
 		switch (skb->protocol) {
-			case __constant_htons(ETH_P_IP):
-				if (skb_cow_head(skb, sizeof(struct iphdr)))
-					goto drop;
+		case __constant_htons(ETH_P_IP):
+			if (skb_cow_head(skb, sizeof(struct iphdr)))
+				goto drop;
 
-				skb->tc_index = ipv4_get_dsfield(ip_hdr(skb))
-					& ~INET_ECN_MASK;
-				break;
+			skb->tc_index = ipv4_get_dsfield(ip_hdr(skb))
+				& ~INET_ECN_MASK;
+			break;
 
-			case __constant_htons(ETH_P_IPV6):
-				if (skb_cow_head(skb, sizeof(struct ipv6hdr)))
-					goto drop;
+		case __constant_htons(ETH_P_IPV6):
+			if (skb_cow_head(skb, sizeof(struct ipv6hdr)))
+				goto drop;
 
-				skb->tc_index = ipv6_get_dsfield(ipv6_hdr(skb))
-					& ~INET_ECN_MASK;
-				break;
-			default:
-				skb->tc_index = 0;
-				break;
+			skb->tc_index = ipv6_get_dsfield(ipv6_hdr(skb))
+				& ~INET_ECN_MASK;
+			break;
+		default:
+			skb->tc_index = 0;
+			break;
 		}
 	}
 
@@ -243,7 +244,7 @@ static int dsmark_enqueue(struct sk_buff
 		}
 	}
 
-	err = p->q->enqueue(skb,p->q);
+	err = p->q->enqueue(skb, p->q);
 	if (err != NET_XMIT_SUCCESS) {
 		sch->qstats.drops++;
 		return err;
@@ -279,31 +280,31 @@ static struct sk_buff *dsmark_dequeue(st
 	pr_debug("index %d->%d\n", skb->tc_index, index);
 
 	switch (skb->protocol) {
-		case __constant_htons(ETH_P_IP):
-			ipv4_change_dsfield(ip_hdr(skb), p->mask[index],
-					    p->value[index]);
+	case __constant_htons(ETH_P_IP):
+		ipv4_change_dsfield(ip_hdr(skb), p->mask[index],
+				    p->value[index]);
 			break;
-		case __constant_htons(ETH_P_IPV6):
-			ipv6_change_dsfield(ipv6_hdr(skb), p->mask[index],
-					    p->value[index]);
-			break;
-		default:
-			/*
-			 * Only complain if a change was actually attempted.
-			 * This way, we can send non-IP traffic through dsmark
-			 * and don't need yet another qdisc as a bypass.
-			 */
-			if (p->mask[index] != 0xff || p->value[index])
-				printk(KERN_WARNING "dsmark_dequeue: "
-				       "unsupported protocol %d\n",
-				       ntohs(skb->protocol));
+	case __constant_htons(ETH_P_IPV6):
+		ipv6_change_dsfield(ipv6_hdr(skb), p->mask[index],
+				    p->value[index]);
 			break;
+	default:
+		/*
+		 * Only complain if a change was actually attempted.
+		 * This way, we can send non-IP traffic through dsmark
+		 * and don't need yet another qdisc as a bypass.
+		 */
+		if (p->mask[index] != 0xff || p->value[index])
+			printk(KERN_WARNING
+			       "dsmark_dequeue: unsupported protocol %d\n",
+			       ntohs(skb->protocol));
+		break;
 	}
 
 	return skb;
 }
 
-static int dsmark_requeue(struct sk_buff *skb,struct Qdisc *sch)
+static int dsmark_requeue(struct sk_buff *skb, struct Qdisc *sch)
 {
 	struct dsmark_qdisc_data *p = qdisc_priv(sch);
 	int err;
@@ -423,8 +424,8 @@ static int dsmark_dump_class(struct Qdis
 	tcm->tcm_info = p->q->handle;
 
 	opts = RTA_NEST(skb, TCA_OPTIONS);
-	RTA_PUT_U8(skb,TCA_DSMARK_MASK, p->mask[cl-1]);
-	RTA_PUT_U8(skb,TCA_DSMARK_VALUE, p->value[cl-1]);
+	RTA_PUT_U8(skb, TCA_DSMARK_MASK, p->mask[cl-1]);
+	RTA_PUT_U8(skb, TCA_DSMARK_VALUE, p->value[cl-1]);
 
 	return RTA_NEST_END(skb, opts);
 

^ permalink raw reply

* Re: 2.6.24 regression: reference count leak in PPPoE
From: Andi Kleen @ 2008-01-20 20:58 UTC (permalink / raw)
  To: Ingo Molnar; +Cc: netdev, linux-kernel, Linus Torvalds
In-Reply-To: <20080120200109.GA31876@elte.hu>


> It seems to have stopped when i stopped using ipsec and started using
> vpnc.

Kernel ipsec was active yes. However I normally don't see it although
it is often active, that was the first time I think

(except long ago) 

> (but no firm info - this was sporadic - happened every few months 
> or so) Are you using ipsec and dynamic IPs by any chance?

and the ISP uses dynamic IPs.

-Andi

^ permalink raw reply

* Re: 2.6.24 regression: reference count leak in PPPoE
From: Malte Schröder @ 2008-01-20 20:16 UTC (permalink / raw)
  To: Andi Kleen; +Cc: netdev, linux-kernel
In-Reply-To: <200801202053.30386.ak@suse.de>

[-- Attachment #1: Type: text/plain, Size: 771 bytes --]

On Sun, 20 Jan 2008 20:53:30 +0100
Andi Kleen <ak@suse.de> wrote:

> 
> My workstation running 2.6.24-rc8 just hung during shutdown with an endless 
> (or rather I didn't wait more than a few minutes) loop of 
> 
> unregister_netdev: waiting for ppp-device to become free. Usage count = 1
> 
> ppp-device was an active PPPoE device.
> 
> No more information currently.

Now that you mention it, this happened to me too this morning. My
system stops the ppp interface (pppoe) and starts it again (my provider
shuts down the link every 24 hours, I want that to happen during the
night, so I do a ifdown ppp0).




-- 
---------------------------------------
Malte Schröder
MalteSch@gmx.de
ICQ# 68121508
---------------------------------------


[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply

* Re: 2.6.24 regression: reference count leak in PPPoE
From: Frans Pop @ 2008-01-20 20:14 UTC (permalink / raw)
  To: Andi Kleen; +Cc: linux-kernel, netdev
In-Reply-To: <200801202053.30386.ak@suse.de>

Andi Kleen wrote:
> My workstation running 2.6.24-rc8 just hung during shutdown with an
> endless (or rather I didn't wait more than a few minutes) loop of
> 
> unregister_netdev: waiting for ppp-device to become free. Usage count = 1

Same as http://lkml.org/lkml/2008/1/20/27? See also follow-up to that.

Cheers,
FJP

^ permalink raw reply

* Re: 2.6.24 regression: reference count leak in PPPoE
From: Daniel Lezcano @ 2008-01-20 20:09 UTC (permalink / raw)
  To: Andi Kleen; +Cc: netdev, linux-kernel
In-Reply-To: <200801202053.30386.ak@suse.de>

Andi Kleen wrote:
> My workstation running 2.6.24-rc8 just hung during shutdown with an endless 
> (or rather I didn't wait more than a few minutes) loop of 
> 
> unregister_netdev: waiting for ppp-device to become free. Usage count = 1
> 
> ppp-device was an active PPPoE device.
> 
> No more information currently.
> 
> -Andi
> --
> To unsubscribe from this list: send the line "unsubscribe netdev" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 

I think this bug has been identified.

[Bug 9778] New: unregister_netdevice: waiting for [device] to become free

Thanks.
   -- Daniel

^ permalink raw reply

* Re: 2.6.24 regression: reference count leak in PPPoE
From: Ingo Molnar @ 2008-01-20 20:01 UTC (permalink / raw)
  To: Andi Kleen; +Cc: netdev, linux-kernel, Linus Torvalds
In-Reply-To: <200801202053.30386.ak@suse.de>


* Andi Kleen <ak@suse.de> wrote:

> My workstation running 2.6.24-rc8 just hung during shutdown with an 
> endless (or rather I didn't wait more than a few minutes) loop of
> 
> unregister_netdev: waiting for ppp-device to become free. Usage count 
> = 1
> 
> ppp-device was an active PPPoE device.
> 
> No more information currently.

i've seen such problems (locked up box with endless loop of usage count 
== 1) with pppoe in the past, and it seemed to be related to dynamic 
IPs. (i saw that well before 2.6.24 - reported it once to davem)

It seems to have stopped when i stopped using ipsec and started using 
vpnc. (but no firm info - this was sporadic - happened every few months 
or so) Are you using ipsec and dynamic IPs by any chance?

	Ingo

^ permalink raw reply

* 2.6.24 regression: reference count leak in PPPoE
From: Andi Kleen @ 2008-01-20 19:53 UTC (permalink / raw)
  To: netdev, linux-kernel


My workstation running 2.6.24-rc8 just hung during shutdown with an endless 
(or rather I didn't wait more than a few minutes) loop of 

unregister_netdev: waiting for ppp-device to become free. Usage count = 1

ppp-device was an active PPPoE device.

No more information currently.

-Andi

^ permalink raw reply

* Re: net 2.6.25 is broken when building with wireless/iwlwifi
From: Jeff Garzik @ 2008-01-20 19:23 UTC (permalink / raw)
  To: Ian Brown
  Cc: netdev-u79uwXL29TY76Z2rM5mHXA, John Linville,
	linux-wireless-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <d0383f90801200601y71472ae6ha638c1567d4abde4-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>

Ian Brown wrote:
> Hello,
> net 2.6.25 is broken when building with the wireless/iwlwifi
> subtree;  we get the following errors (we noticed that iwl_down() and
> iwl_resume()
> implementation do exist in garzik tree, but there are more differences
> so a simple
> patch with only adding these two methods might be risky)
> 
> ...
> ...
> 
>   CHK     include/linux/version.h
>   CHK     include/linux/utsrelease.h
>   CALL    scripts/checksyscalls.sh
>   CHK     include/linux/compile.h
>   CC [M]  drivers/net/wireless/iwlwifi/iwl3945-base.o
> drivers/net/wireless/iwlwifi/iwl3945-base.c: In function 'iwl3945_pci_remove':
> drivers/net/wireless/iwlwifi/iwl3945-base.c:8639: error: implicit
> declaration of function 'iwl_down'
> drivers/net/wireless/iwlwifi/iwl3945-base.c: In function 'iwl3945_pci_resume':
> drivers/net/wireless/iwlwifi/iwl3945-base.c:8779: error: implicit
> declaration of function 'iwl_resume'
> make[4]: *** [drivers/net/wireless/iwlwifi/iwl3945-base.o] Error 1
> make[3]: *** [drivers/net/wireless/iwlwifi] Error 2
> make[2]: *** [drivers/net/wireless] Error 2
> make[1]: *** [drivers/net] Error 2
> make: *** [drivers] Error 2

hrm, that sounds like a potential mis-merge on my part (though 
ultimately linville should be re-syncing with net-2.6.25 soon anyway)

	Jeff

^ permalink raw reply

* Re: [RFC NET_SCHED 05/05]: Consolidate class ops for pseudo classful qdisc
From: Patrick McHardy @ 2008-01-20 18:32 UTC (permalink / raw)
  To: netdev
In-Reply-To: <20080120182855.10972.24622.sendpatchset@localhost.localdomain>

[-- Attachment #1: Type: text/plain, Size: 440 bytes --]

Patrick McHardy wrote:
> commit e97ba18f7a8f9342fa06d0f5606a186b18e1d7f8
> Author: Patrick McHardy <kaber@trash.net>
> Date:   Wed Jan 16 12:22:06 2008 +0100
> 
>     [NET_SCHED]: Consolidate class ops for pseudo classful qdisc
>     
>     Signed-off-by: Patrick McHardy <kaber@trash.net>
> 

>  config NET_SCH_TEQL
>  	tristate "True Link Equalizer (TEQL)"
> +	select NET_SCH_PC


Oops .. this should have been at the NET_SCH_RED entry.


[-- Attachment #2: 05.diff --]
[-- Type: text/x-patch, Size: 21118 bytes --]

commit d89898d2e77b5c1753d21174870277d235994afa
Author: Patrick McHardy <kaber@trash.net>
Date:   Sun Jan 20 19:31:05 2008 +0100

    [NET_SCHED]: Consolidate class ops for pseudo classful qdisc
    
    Signed-off-by: Patrick McHardy <kaber@trash.net>

diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h
index decc339..ca6e4de 100644
--- a/include/net/sch_generic.h
+++ b/include/net/sch_generic.h
@@ -351,4 +351,10 @@ static inline struct sk_buff *skb_act_clone(struct sk_buff *skb, gfp_t gfp_mask)
 }
 #endif
 
+struct pc_sched_data {
+	struct Qdisc	*qdisc;
+};
+
+extern const struct Qdisc_class_ops pseudo_classful_ops;
+
 #endif
diff --git a/net/sched/Kconfig b/net/sched/Kconfig
index f5ab54b..b6b4260 100644
--- a/net/sched/Kconfig
+++ b/net/sched/Kconfig
@@ -43,6 +43,9 @@ if NET_SCHED
 
 comment "Queueing/Scheduling"
 
+config NET_SCH_PC
+	tristate
+
 config NET_SCH_CBQ
 	tristate "Class Based Queueing (CBQ)"
 	---help---
@@ -119,6 +122,7 @@ config NET_SCH_RR
 
 config NET_SCH_RED
 	tristate "Random Early Detection (RED)"
+	select NET_SCH_PC
 	---help---
 	  Say Y here if you want to use the Random Early Detection (RED)
 	  packet scheduling algorithm.
@@ -153,6 +157,7 @@ config NET_SCH_TEQL
 
 config NET_SCH_TBF
 	tristate "Token Bucket Filter (TBF)"
+	select NET_SCH_PC
 	---help---
 	  Say Y here if you want to use the Token Bucket Filter (TBF) packet
 	  scheduling algorithm.
@@ -186,6 +191,7 @@ config NET_SCH_DSMARK
 
 config NET_SCH_NETEM
 	tristate "Network emulator (NETEM)"
+	select NET_SCH_PC
 	---help---
 	  Say Y if you want to emulate network delay, loss, and packet
 	  re-ordering. This is often useful to simulate networks when
diff --git a/net/sched/Makefile b/net/sched/Makefile
index 81ecbe8..593bb3a 100644
--- a/net/sched/Makefile
+++ b/net/sched/Makefile
@@ -14,6 +14,7 @@ obj-$(CONFIG_NET_ACT_IPT)	+= act_ipt.o
 obj-$(CONFIG_NET_ACT_NAT)	+= act_nat.o
 obj-$(CONFIG_NET_ACT_PEDIT)	+= act_pedit.o
 obj-$(CONFIG_NET_ACT_SIMP)	+= act_simple.o
+obj-$(CONFIG_NET_SCH_PC)	+= sch_pseudo_classful.o
 obj-$(CONFIG_NET_SCH_FIFO)	+= sch_fifo.o
 obj-$(CONFIG_NET_SCH_CBQ)	+= sch_cbq.o
 obj-$(CONFIG_NET_SCH_HTB)	+= sch_htb.o
diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c
index f6c24fd..2444a97 100644
--- a/net/sched/sch_netem.c
+++ b/net/sched/sch_netem.c
@@ -52,7 +52,8 @@
 */
 
 struct netem_sched_data {
-	struct Qdisc	*qdisc;
+	struct pc_sched_data class;
+
 	struct qdisc_watchdog watchdog;
 
 	psched_tdiff_t latency;
@@ -218,7 +219,7 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch)
 		now = psched_get_time();
 		cb->time_to_send = now + delay;
 		++q->counter;
-		ret = qdisc_enqueue(skb, q->qdisc);
+		ret = qdisc_enqueue(skb, q->class.qdisc);
 	} else {
 		/*
 		 * Do re-ordering by putting one out of N packets at the front
@@ -226,7 +227,7 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch)
 		 */
 		cb->time_to_send = psched_get_time();
 		q->counter = 0;
-		ret = qdisc_requeue(skb, q->qdisc);
+		ret = qdisc_requeue(skb, q->class.qdisc);
 	}
 
 	if (likely(ret == NET_XMIT_SUCCESS)) {
@@ -246,7 +247,7 @@ static int netem_requeue(struct sk_buff *skb, struct Qdisc *sch)
 	struct netem_sched_data *q = qdisc_priv(sch);
 	int ret;
 
-	ret = qdisc_requeue(skb, q->qdisc);
+	ret = qdisc_requeue(skb, q->class.qdisc);
 	if (ret == NET_XMIT_SUCCESS) {
 		sch->q.qlen++;
 		sch->qstats.requeues++;
@@ -260,7 +261,7 @@ static unsigned int netem_drop(struct Qdisc* sch)
 	struct netem_sched_data *q = qdisc_priv(sch);
 	unsigned int len = 0;
 
-	len = qdisc_drop(q->qdisc);
+	len = qdisc_drop(q->class.qdisc);
 	if (len > 0) {
 		sch->q.qlen--;
 		sch->qstats.drops++;
@@ -277,7 +278,7 @@ static struct sk_buff *netem_dequeue(struct Qdisc *sch)
 	if (sch->flags & TCQ_F_THROTTLED)
 		return NULL;
 
-	skb = qdisc_dequeue(q->qdisc);
+	skb = qdisc_dequeue(q->class.qdisc);
 	if (skb) {
 		const struct netem_skb_cb *cb
 			= (const struct netem_skb_cb *)skb->cb;
@@ -290,11 +291,11 @@ static struct sk_buff *netem_dequeue(struct Qdisc *sch)
 			return skb;
 		}
 
-		if (unlikely(qdisc_requeue(skb, q->qdisc) != NET_XMIT_SUCCESS)) {
-			qdisc_tree_decrease_qlen(q->qdisc, 1);
+		if (unlikely(qdisc_requeue(skb, q->class.qdisc) != NET_XMIT_SUCCESS)) {
+			qdisc_tree_decrease_qlen(q->class.qdisc, 1);
 			sch->qstats.drops++;
 			printk(KERN_ERR "netem: %s could not requeue\n",
-			       q->qdisc->ops->id);
+			       q->class.qdisc->ops->id);
 		}
 
 		qdisc_watchdog_schedule(&q->watchdog, cb->time_to_send);
@@ -307,7 +308,7 @@ static void netem_reset(struct Qdisc *sch)
 {
 	struct netem_sched_data *q = qdisc_priv(sch);
 
-	qdisc_reset(q->qdisc);
+	qdisc_reset(q->class.qdisc);
 	sch->q.qlen = 0;
 	qdisc_watchdog_cancel(&q->watchdog);
 }
@@ -394,7 +395,7 @@ static int netem_change(struct Qdisc *sch, struct rtattr *opt)
 		return -EINVAL;
 
 	qopt = RTA_DATA(opt);
-	ret = fifo_set_limit(q->qdisc, qopt->limit);
+	ret = fifo_set_limit(q->class.qdisc, qopt->limit);
 	if (ret) {
 		pr_debug("netem: can't set fifo limit\n");
 		return ret;
@@ -547,9 +548,9 @@ static int netem_init(struct Qdisc *sch, struct rtattr *opt)
 
 	qdisc_watchdog_init(&q->watchdog, sch);
 
-	q->qdisc = qdisc_create_dflt(sch->dev, &tfifo_qdisc_ops,
-				     TC_H_MAKE(sch->handle, 1));
-	if (!q->qdisc) {
+	q->class.qdisc = qdisc_create_dflt(sch->dev, &tfifo_qdisc_ops,
+					   TC_H_MAKE(sch->handle, 1));
+	if (!q->class.qdisc) {
 		pr_debug("netem: qdisc create failed\n");
 		return -ENOMEM;
 	}
@@ -557,7 +558,7 @@ static int netem_init(struct Qdisc *sch, struct rtattr *opt)
 	ret = netem_change(sch, opt);
 	if (ret) {
 		pr_debug("netem: change failed\n");
-		qdisc_destroy(q->qdisc);
+		qdisc_destroy(q->class.qdisc);
 	}
 	return ret;
 }
@@ -567,7 +568,7 @@ static void netem_destroy(struct Qdisc *sch)
 	struct netem_sched_data *q = qdisc_priv(sch);
 
 	qdisc_watchdog_cancel(&q->watchdog);
-	qdisc_destroy(q->qdisc);
+	qdisc_destroy(q->class.qdisc);
 	kfree(q->delay_dist);
 }
 
@@ -611,95 +612,9 @@ rtattr_failure:
 	return -1;
 }
 
-static int netem_dump_class(struct Qdisc *sch, unsigned long cl,
-			  struct sk_buff *skb, struct tcmsg *tcm)
-{
-	struct netem_sched_data *q = qdisc_priv(sch);
-
-	if (cl != 1) 	/* only one class */
-		return -ENOENT;
-
-	tcm->tcm_handle |= TC_H_MIN(1);
-	tcm->tcm_info = q->qdisc->handle;
-
-	return 0;
-}
-
-static int netem_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new,
-		     struct Qdisc **old)
-{
-	struct netem_sched_data *q = qdisc_priv(sch);
-
-	if (new == NULL)
-		new = &noop_qdisc;
-
-	sch_tree_lock(sch);
-	*old = xchg(&q->qdisc, new);
-	qdisc_tree_decrease_qlen(*old, (*old)->q.qlen);
-	qdisc_reset(*old);
-	sch_tree_unlock(sch);
-
-	return 0;
-}
-
-static struct Qdisc *netem_leaf(struct Qdisc *sch, unsigned long arg)
-{
-	struct netem_sched_data *q = qdisc_priv(sch);
-	return q->qdisc;
-}
-
-static unsigned long netem_get(struct Qdisc *sch, u32 classid)
-{
-	return 1;
-}
-
-static void netem_put(struct Qdisc *sch, unsigned long arg)
-{
-}
-
-static int netem_change_class(struct Qdisc *sch, u32 classid, u32 parentid,
-			    struct rtattr **tca, unsigned long *arg)
-{
-	return -ENOSYS;
-}
-
-static int netem_delete(struct Qdisc *sch, unsigned long arg)
-{
-	return -ENOSYS;
-}
-
-static void netem_walk(struct Qdisc *sch, struct qdisc_walker *walker)
-{
-	if (!walker->stop) {
-		if (walker->count >= walker->skip)
-			if (walker->fn(sch, 1, walker) < 0) {
-				walker->stop = 1;
-				return;
-			}
-		walker->count++;
-	}
-}
-
-static struct tcf_proto **netem_find_tcf(struct Qdisc *sch, unsigned long cl)
-{
-	return NULL;
-}
-
-static const struct Qdisc_class_ops netem_class_ops = {
-	.graft		=	netem_graft,
-	.leaf		=	netem_leaf,
-	.get		=	netem_get,
-	.put		=	netem_put,
-	.change		=	netem_change_class,
-	.delete		=	netem_delete,
-	.walk		=	netem_walk,
-	.tcf_chain	=	netem_find_tcf,
-	.dump		=	netem_dump_class,
-};
-
 static struct Qdisc_ops netem_qdisc_ops __read_mostly = {
 	.id		=	"netem",
-	.cl_ops		=	&netem_class_ops,
+	.cl_ops		=	&pseudo_classful_ops,
 	.priv_size	=	sizeof(struct netem_sched_data),
 	.enqueue	=	netem_enqueue,
 	.dequeue	=	netem_dequeue,
diff --git a/net/sched/sch_pseudo_classful.c b/net/sched/sch_pseudo_classful.c
new file mode 100644
index 0000000..5b9fba5
--- /dev/null
+++ b/net/sched/sch_pseudo_classful.c
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2007 Patrick McHardy, <kaber@trash.net>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/skbuff.h>
+#include <net/sch_generic.h>
+#include <net/pkt_sched.h>
+
+static int sch_pc_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new,
+			struct Qdisc **old)
+{
+	struct pc_sched_data *q = qdisc_priv(sch);
+
+	if (new == NULL)
+		new = &noop_qdisc;
+
+	sch_tree_lock(sch);
+	*old = xchg(&q->qdisc, new);
+	qdisc_tree_decrease_qlen(*old, (*old)->q.qlen);
+	qdisc_reset(*old);
+	sch_tree_unlock(sch);
+	return 0;
+}
+
+static int sch_pc_change_class(struct Qdisc *sch, u32 classid, u32 parentid,
+			       struct rtattr **tca, unsigned long *arg)
+{
+	return -ENOSYS;
+}
+
+static struct Qdisc *sch_pc_leaf(struct Qdisc *sch, unsigned long arg)
+{
+	return ((struct pc_sched_data *)qdisc_priv(sch))->qdisc;
+}
+
+static unsigned long sch_pc_get(struct Qdisc *sch, u32 classid)
+{
+	return 1;
+}
+
+static void sch_pc_put(struct Qdisc *sch, unsigned long arg)
+{
+	return;
+}
+
+static int sch_pc_delete(struct Qdisc *sch, unsigned long arg)
+{
+	return -ENOSYS;
+}
+
+static struct tcf_proto **sch_pc_tcf_chain(struct Qdisc *sch, unsigned long cl)
+{
+	return NULL;
+}
+
+static int sch_pc_dump_class(struct Qdisc *sch, unsigned long cl,
+			     struct sk_buff *skb, struct tcmsg *tcm)
+{
+	struct pc_sched_data *q = qdisc_priv(sch);
+
+	if (cl != 1)
+		return -ENOENT;
+
+	tcm->tcm_handle |= TC_H_MIN(1);
+	tcm->tcm_info = q->qdisc->handle;
+	return 0;
+}
+
+static void sch_pc_walk(struct Qdisc *sch, struct qdisc_walker *walker)
+{
+	if (!walker->stop) {
+		if (walker->count >= walker->skip)
+			if (walker->fn(sch, 1, walker) < 0) {
+				walker->stop = 1;
+				return;
+			}
+		walker->count++;
+	}
+}
+
+const struct Qdisc_class_ops pseudo_classful_ops = {
+	.graft		= sch_pc_graft,
+	.leaf		= sch_pc_leaf,
+	.get		= sch_pc_get,
+	.put		= sch_pc_put,
+	.change		= sch_pc_change_class,
+	.delete		= sch_pc_delete,
+	.walk		= sch_pc_walk,
+	.tcf_chain	= sch_pc_tcf_chain,
+	.dump		= sch_pc_dump_class,
+};
+EXPORT_SYMBOL(pseudo_classful_ops);
+
+MODULE_LICENSE("GPL");
diff --git a/net/sched/sch_red.c b/net/sched/sch_red.c
index 076f1ef..fc61675 100644
--- a/net/sched/sch_red.c
+++ b/net/sched/sch_red.c
@@ -38,11 +38,12 @@
 
 struct red_sched_data
 {
+	struct pc_sched_data	class;
+
 	u32			limit;		/* HARD maximal queue length */
 	unsigned char		flags;
 	struct red_parms	parms;
 	struct red_stats	stats;
-	struct Qdisc		*qdisc;
 };
 
 static inline int red_use_ecn(struct red_sched_data *q)
@@ -58,7 +59,7 @@ static inline int red_use_harddrop(struct red_sched_data *q)
 static int red_enqueue(struct sk_buff *skb, struct Qdisc* sch)
 {
 	struct red_sched_data *q = qdisc_priv(sch);
-	struct Qdisc *child = q->qdisc;
+	struct Qdisc *child = q->class.qdisc;
 	int ret;
 
 	q->parms.qavg = red_calc_qavg(&q->parms, child->qstats.backlog);
@@ -111,7 +112,7 @@ congestion_drop:
 static int red_requeue(struct sk_buff *skb, struct Qdisc* sch)
 {
 	struct red_sched_data *q = qdisc_priv(sch);
-	struct Qdisc *child = q->qdisc;
+	struct Qdisc *child = q->class.qdisc;
 	int ret;
 
 	if (red_is_idling(&q->parms))
@@ -129,7 +130,7 @@ static struct sk_buff * red_dequeue(struct Qdisc* sch)
 {
 	struct sk_buff *skb;
 	struct red_sched_data *q = qdisc_priv(sch);
-	struct Qdisc *child = q->qdisc;
+	struct Qdisc *child = q->class.qdisc;
 
 	skb = qdisc_dequeue(child);
 	if (skb)
@@ -143,7 +144,7 @@ static struct sk_buff * red_dequeue(struct Qdisc* sch)
 static unsigned int red_drop(struct Qdisc* sch)
 {
 	struct red_sched_data *q = qdisc_priv(sch);
-	struct Qdisc *child = q->qdisc;
+	struct Qdisc *child = q->class.qdisc;
 	unsigned int len;
 
 	len = qdisc_drop(child);
@@ -164,7 +165,7 @@ static void red_reset(struct Qdisc* sch)
 {
 	struct red_sched_data *q = qdisc_priv(sch);
 
-	qdisc_reset(q->qdisc);
+	qdisc_reset(q->class.qdisc);
 	sch->q.qlen = 0;
 	red_restart(&q->parms);
 }
@@ -172,7 +173,7 @@ static void red_reset(struct Qdisc* sch)
 static void red_destroy(struct Qdisc *sch)
 {
 	struct red_sched_data *q = qdisc_priv(sch);
-	qdisc_destroy(q->qdisc);
+	qdisc_destroy(q->class.qdisc);
 }
 
 static int red_change(struct Qdisc *sch, struct rtattr *opt)
@@ -203,8 +204,9 @@ static int red_change(struct Qdisc *sch, struct rtattr *opt)
 	q->flags = ctl->flags;
 	q->limit = ctl->limit;
 	if (child) {
-		qdisc_tree_decrease_qlen(q->qdisc, q->qdisc->q.qlen);
-		qdisc_destroy(xchg(&q->qdisc, child));
+		qdisc_tree_decrease_qlen(q->class.qdisc,
+					 q->class.qdisc->q.qlen);
+		qdisc_destroy(xchg(&q->class.qdisc, child));
 	}
 
 	red_set_parms(&q->parms, ctl->qth_min, ctl->qth_max, ctl->Wlog,
@@ -222,7 +224,7 @@ static int red_init(struct Qdisc* sch, struct rtattr *opt)
 {
 	struct red_sched_data *q = qdisc_priv(sch);
 
-	q->qdisc = &noop_qdisc;
+	q->class.qdisc = &noop_qdisc;
 	return red_change(sch, opt);
 }
 
@@ -261,94 +263,10 @@ static int red_dump_stats(struct Qdisc *sch, struct gnet_dump *d)
 	return gnet_stats_copy_app(d, &st, sizeof(st));
 }
 
-static int red_dump_class(struct Qdisc *sch, unsigned long cl,
-			  struct sk_buff *skb, struct tcmsg *tcm)
-{
-	struct red_sched_data *q = qdisc_priv(sch);
-
-	if (cl != 1)
-		return -ENOENT;
-	tcm->tcm_handle |= TC_H_MIN(1);
-	tcm->tcm_info = q->qdisc->handle;
-	return 0;
-}
-
-static int red_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new,
-		     struct Qdisc **old)
-{
-	struct red_sched_data *q = qdisc_priv(sch);
-
-	if (new == NULL)
-		new = &noop_qdisc;
-
-	sch_tree_lock(sch);
-	*old = xchg(&q->qdisc, new);
-	qdisc_tree_decrease_qlen(*old, (*old)->q.qlen);
-	qdisc_reset(*old);
-	sch_tree_unlock(sch);
-	return 0;
-}
-
-static struct Qdisc *red_leaf(struct Qdisc *sch, unsigned long arg)
-{
-	struct red_sched_data *q = qdisc_priv(sch);
-	return q->qdisc;
-}
-
-static unsigned long red_get(struct Qdisc *sch, u32 classid)
-{
-	return 1;
-}
-
-static void red_put(struct Qdisc *sch, unsigned long arg)
-{
-	return;
-}
-
-static int red_change_class(struct Qdisc *sch, u32 classid, u32 parentid,
-			    struct rtattr **tca, unsigned long *arg)
-{
-	return -ENOSYS;
-}
-
-static int red_delete(struct Qdisc *sch, unsigned long cl)
-{
-	return -ENOSYS;
-}
-
-static void red_walk(struct Qdisc *sch, struct qdisc_walker *walker)
-{
-	if (!walker->stop) {
-		if (walker->count >= walker->skip)
-			if (walker->fn(sch, 1, walker) < 0) {
-				walker->stop = 1;
-				return;
-			}
-		walker->count++;
-	}
-}
-
-static struct tcf_proto **red_find_tcf(struct Qdisc *sch, unsigned long cl)
-{
-	return NULL;
-}
-
-static const struct Qdisc_class_ops red_class_ops = {
-	.graft		=	red_graft,
-	.leaf		=	red_leaf,
-	.get		=	red_get,
-	.put		=	red_put,
-	.change		=	red_change_class,
-	.delete		=	red_delete,
-	.walk		=	red_walk,
-	.tcf_chain	=	red_find_tcf,
-	.dump		=	red_dump_class,
-};
-
 static struct Qdisc_ops red_qdisc_ops __read_mostly = {
 	.id		=	"red",
 	.priv_size	=	sizeof(struct red_sched_data),
-	.cl_ops		=	&red_class_ops,
+	.cl_ops		=	&pseudo_classful_ops,
 	.enqueue	=	red_enqueue,
 	.dequeue	=	red_dequeue,
 	.requeue	=	red_requeue,
diff --git a/net/sched/sch_tbf.c b/net/sched/sch_tbf.c
index 5fd4dff..6590ce3 100644
--- a/net/sched/sch_tbf.c
+++ b/net/sched/sch_tbf.c
@@ -99,6 +99,8 @@
 
 struct tbf_sched_data
 {
+	struct pc_sched_data	class;
+
 /* Parameters */
 	u32		limit;		/* Maximal length of backlog: bytes */
 	u32		buffer;		/* Token bucket depth/rate: MUST BE >= MTU/B */
@@ -111,7 +113,6 @@ struct tbf_sched_data
 	long	tokens;			/* Current number of B tokens */
 	long	ptokens;		/* Current number of P tokens */
 	psched_time_t	t_c;		/* Time check-point */
-	struct Qdisc	*qdisc;		/* Inner qdisc, default - bfifo queue */
 	struct qdisc_watchdog watchdog;	/* Watchdog timer */
 };
 
@@ -133,7 +134,7 @@ static int tbf_enqueue(struct sk_buff *skb, struct Qdisc* sch)
 		return NET_XMIT_DROP;
 	}
 
-	ret = qdisc_enqueue(skb, q->qdisc);
+	ret = qdisc_enqueue(skb, q->class.qdisc);
 	if (ret != NET_XMIT_SUCCESS) {
 		sch->qstats.drops++;
 		return ret;
@@ -150,7 +151,7 @@ static int tbf_requeue(struct sk_buff *skb, struct Qdisc* sch)
 	struct tbf_sched_data *q = qdisc_priv(sch);
 	int ret;
 
-	ret = qdisc_requeue(skb, q->qdisc);
+	ret = qdisc_requeue(skb, q->class.qdisc);
 	if (ret == NET_XMIT_SUCCESS) {
 		sch->q.qlen++;
 		sch->qstats.requeues++;
@@ -164,7 +165,7 @@ static unsigned int tbf_drop(struct Qdisc* sch)
 	struct tbf_sched_data *q = qdisc_priv(sch);
 	unsigned int len = 0;
 
-	len = qdisc_drop(q->qdisc);
+	len = qdisc_drop(q->class.qdisc);
 	if (len > 0) {
 		sch->q.qlen--;
 		sch->qstats.drops++;
@@ -177,7 +178,7 @@ static struct sk_buff *tbf_dequeue(struct Qdisc* sch)
 	struct tbf_sched_data *q = qdisc_priv(sch);
 	struct sk_buff *skb;
 
-	skb = qdisc_dequeue(q->qdisc);
+	skb = qdisc_dequeue(q->class.qdisc);
 
 	if (skb) {
 		psched_time_t now;
@@ -222,9 +223,9 @@ static struct sk_buff *tbf_dequeue(struct Qdisc* sch)
 		   (cf. CSZ, HPFQ, HFSC)
 		 */
 
-		if (q->qdisc->ops->requeue(skb, q->qdisc) != NET_XMIT_SUCCESS) {
+		if (q->class.qdisc->ops->requeue(skb, q->class.qdisc) != NET_XMIT_SUCCESS) {
 			/* When requeue fails skb is dropped */
-			qdisc_tree_decrease_qlen(q->qdisc, 1);
+			qdisc_tree_decrease_qlen(q->class.qdisc, 1);
 			sch->qstats.drops++;
 		}
 
@@ -237,7 +238,7 @@ static void tbf_reset(struct Qdisc* sch)
 {
 	struct tbf_sched_data *q = qdisc_priv(sch);
 
-	qdisc_reset(q->qdisc);
+	qdisc_reset(q->class.qdisc);
 	sch->q.qlen = 0;
 	q->t_c = psched_get_time();
 	q->tokens = q->buffer;
@@ -295,8 +296,8 @@ static int tbf_change(struct Qdisc* sch, struct rtattr *opt)
 
 	sch_tree_lock(sch);
 	if (child) {
-		qdisc_tree_decrease_qlen(q->qdisc, q->qdisc->q.qlen);
-		qdisc_destroy(xchg(&q->qdisc, child));
+		qdisc_tree_decrease_qlen(q->class.qdisc, q->class.qdisc->q.qlen);
+		qdisc_destroy(xchg(&q->class.qdisc, child));
 	}
 	q->limit = qopt->limit;
 	q->mtu = qopt->mtu;
@@ -325,7 +326,7 @@ static int tbf_init(struct Qdisc* sch, struct rtattr *opt)
 
 	q->t_c = psched_get_time();
 	qdisc_watchdog_init(&q->watchdog, sch);
-	q->qdisc = &noop_qdisc;
+	q->class.qdisc = &noop_qdisc;
 
 	return tbf_change(sch, opt);
 }
@@ -341,7 +342,7 @@ static void tbf_destroy(struct Qdisc *sch)
 	if (q->R_tab)
 		qdisc_put_rtab(q->R_tab);
 
-	qdisc_destroy(q->qdisc);
+	qdisc_destroy(q->class.qdisc);
 }
 
 static int tbf_dump(struct Qdisc *sch, struct sk_buff *skb)
@@ -372,96 +373,8 @@ rtattr_failure:
 	return -1;
 }
 
-static int tbf_dump_class(struct Qdisc *sch, unsigned long cl,
-			  struct sk_buff *skb, struct tcmsg *tcm)
-{
-	struct tbf_sched_data *q = qdisc_priv(sch);
-
-	if (cl != 1) 	/* only one class */
-		return -ENOENT;
-
-	tcm->tcm_handle |= TC_H_MIN(1);
-	tcm->tcm_info = q->qdisc->handle;
-
-	return 0;
-}
-
-static int tbf_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new,
-		     struct Qdisc **old)
-{
-	struct tbf_sched_data *q = qdisc_priv(sch);
-
-	if (new == NULL)
-		new = &noop_qdisc;
-
-	sch_tree_lock(sch);
-	*old = xchg(&q->qdisc, new);
-	qdisc_tree_decrease_qlen(*old, (*old)->q.qlen);
-	qdisc_reset(*old);
-	sch_tree_unlock(sch);
-
-	return 0;
-}
-
-static struct Qdisc *tbf_leaf(struct Qdisc *sch, unsigned long arg)
-{
-	struct tbf_sched_data *q = qdisc_priv(sch);
-	return q->qdisc;
-}
-
-static unsigned long tbf_get(struct Qdisc *sch, u32 classid)
-{
-	return 1;
-}
-
-static void tbf_put(struct Qdisc *sch, unsigned long arg)
-{
-}
-
-static int tbf_change_class(struct Qdisc *sch, u32 classid, u32 parentid,
-			    struct rtattr **tca, unsigned long *arg)
-{
-	return -ENOSYS;
-}
-
-static int tbf_delete(struct Qdisc *sch, unsigned long arg)
-{
-	return -ENOSYS;
-}
-
-static void tbf_walk(struct Qdisc *sch, struct qdisc_walker *walker)
-{
-	if (!walker->stop) {
-		if (walker->count >= walker->skip)
-			if (walker->fn(sch, 1, walker) < 0) {
-				walker->stop = 1;
-				return;
-			}
-		walker->count++;
-	}
-}
-
-static struct tcf_proto **tbf_find_tcf(struct Qdisc *sch, unsigned long cl)
-{
-	return NULL;
-}
-
-static const struct Qdisc_class_ops tbf_class_ops =
-{
-	.graft		=	tbf_graft,
-	.leaf		=	tbf_leaf,
-	.get		=	tbf_get,
-	.put		=	tbf_put,
-	.change		=	tbf_change_class,
-	.delete		=	tbf_delete,
-	.walk		=	tbf_walk,
-	.tcf_chain	=	tbf_find_tcf,
-	.dump		=	tbf_dump_class,
-};
-
 static struct Qdisc_ops tbf_qdisc_ops __read_mostly = {
-	.next		=	NULL,
-	.cl_ops		=	&tbf_class_ops,
+	.cl_ops		=	&pseudo_classful_ops,
 	.id		=	"tbf",
 	.priv_size	=	sizeof(struct tbf_sched_data),
 	.enqueue	=	tbf_enqueue,

^ permalink raw reply related

* [RFC NET_SCHED 05/05]: Consolidate class ops for pseudo classful qdisc
From: Patrick McHardy @ 2008-01-20 18:28 UTC (permalink / raw)
  To: netdev; +Cc: Patrick McHardy
In-Reply-To: <20080120182848.10972.46380.sendpatchset@localhost.localdomain>

commit e97ba18f7a8f9342fa06d0f5606a186b18e1d7f8
Author: Patrick McHardy <kaber@trash.net>
Date:   Wed Jan 16 12:22:06 2008 +0100

    [NET_SCHED]: Consolidate class ops for pseudo classful qdisc
    
    Signed-off-by: Patrick McHardy <kaber@trash.net>

diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h
index decc339..ca6e4de 100644
--- a/include/net/sch_generic.h
+++ b/include/net/sch_generic.h
@@ -351,4 +351,10 @@ static inline struct sk_buff *skb_act_clone(struct sk_buff *skb, gfp_t gfp_mask)
 }
 #endif
 
+struct pc_sched_data {
+	struct Qdisc	*qdisc;
+};
+
+extern const struct Qdisc_class_ops pseudo_classful_ops;
+
 #endif
diff --git a/net/sched/Kconfig b/net/sched/Kconfig
index f5ab54b..63882c5 100644
--- a/net/sched/Kconfig
+++ b/net/sched/Kconfig
@@ -43,6 +43,9 @@ if NET_SCHED
 
 comment "Queueing/Scheduling"
 
+config NET_SCH_PC
+	tristate
+
 config NET_SCH_CBQ
 	tristate "Class Based Queueing (CBQ)"
 	---help---
@@ -141,6 +144,7 @@ config NET_SCH_SFQ
 
 config NET_SCH_TEQL
 	tristate "True Link Equalizer (TEQL)"
+	select NET_SCH_PC
 	---help---
 	  Say Y here if you want to use the True Link Equalizer (TLE) packet
 	  scheduling algorithm. This queueing discipline allows the combination
@@ -153,6 +157,7 @@ config NET_SCH_TEQL
 
 config NET_SCH_TBF
 	tristate "Token Bucket Filter (TBF)"
+	select NET_SCH_PC
 	---help---
 	  Say Y here if you want to use the Token Bucket Filter (TBF) packet
 	  scheduling algorithm.
@@ -186,6 +191,7 @@ config NET_SCH_DSMARK
 
 config NET_SCH_NETEM
 	tristate "Network emulator (NETEM)"
+	select NET_SCH_PC
 	---help---
 	  Say Y if you want to emulate network delay, loss, and packet
 	  re-ordering. This is often useful to simulate networks when
diff --git a/net/sched/Makefile b/net/sched/Makefile
index 81ecbe8..593bb3a 100644
--- a/net/sched/Makefile
+++ b/net/sched/Makefile
@@ -14,6 +14,7 @@ obj-$(CONFIG_NET_ACT_IPT)	+= act_ipt.o
 obj-$(CONFIG_NET_ACT_NAT)	+= act_nat.o
 obj-$(CONFIG_NET_ACT_PEDIT)	+= act_pedit.o
 obj-$(CONFIG_NET_ACT_SIMP)	+= act_simple.o
+obj-$(CONFIG_NET_SCH_PC)	+= sch_pseudo_classful.o
 obj-$(CONFIG_NET_SCH_FIFO)	+= sch_fifo.o
 obj-$(CONFIG_NET_SCH_CBQ)	+= sch_cbq.o
 obj-$(CONFIG_NET_SCH_HTB)	+= sch_htb.o
diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c
index f6c24fd..2444a97 100644
--- a/net/sched/sch_netem.c
+++ b/net/sched/sch_netem.c
@@ -52,7 +52,8 @@
 */
 
 struct netem_sched_data {
-	struct Qdisc	*qdisc;
+	struct pc_sched_data class;
+
 	struct qdisc_watchdog watchdog;
 
 	psched_tdiff_t latency;
@@ -218,7 +219,7 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch)
 		now = psched_get_time();
 		cb->time_to_send = now + delay;
 		++q->counter;
-		ret = qdisc_enqueue(skb, q->qdisc);
+		ret = qdisc_enqueue(skb, q->class.qdisc);
 	} else {
 		/*
 		 * Do re-ordering by putting one out of N packets at the front
@@ -226,7 +227,7 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch)
 		 */
 		cb->time_to_send = psched_get_time();
 		q->counter = 0;
-		ret = qdisc_requeue(skb, q->qdisc);
+		ret = qdisc_requeue(skb, q->class.qdisc);
 	}
 
 	if (likely(ret == NET_XMIT_SUCCESS)) {
@@ -246,7 +247,7 @@ static int netem_requeue(struct sk_buff *skb, struct Qdisc *sch)
 	struct netem_sched_data *q = qdisc_priv(sch);
 	int ret;
 
-	ret = qdisc_requeue(skb, q->qdisc);
+	ret = qdisc_requeue(skb, q->class.qdisc);
 	if (ret == NET_XMIT_SUCCESS) {
 		sch->q.qlen++;
 		sch->qstats.requeues++;
@@ -260,7 +261,7 @@ static unsigned int netem_drop(struct Qdisc* sch)
 	struct netem_sched_data *q = qdisc_priv(sch);
 	unsigned int len = 0;
 
-	len = qdisc_drop(q->qdisc);
+	len = qdisc_drop(q->class.qdisc);
 	if (len > 0) {
 		sch->q.qlen--;
 		sch->qstats.drops++;
@@ -277,7 +278,7 @@ static struct sk_buff *netem_dequeue(struct Qdisc *sch)
 	if (sch->flags & TCQ_F_THROTTLED)
 		return NULL;
 
-	skb = qdisc_dequeue(q->qdisc);
+	skb = qdisc_dequeue(q->class.qdisc);
 	if (skb) {
 		const struct netem_skb_cb *cb
 			= (const struct netem_skb_cb *)skb->cb;
@@ -290,11 +291,11 @@ static struct sk_buff *netem_dequeue(struct Qdisc *sch)
 			return skb;
 		}
 
-		if (unlikely(qdisc_requeue(skb, q->qdisc) != NET_XMIT_SUCCESS)) {
-			qdisc_tree_decrease_qlen(q->qdisc, 1);
+		if (unlikely(qdisc_requeue(skb, q->class.qdisc) != NET_XMIT_SUCCESS)) {
+			qdisc_tree_decrease_qlen(q->class.qdisc, 1);
 			sch->qstats.drops++;
 			printk(KERN_ERR "netem: %s could not requeue\n",
-			       q->qdisc->ops->id);
+			       q->class.qdisc->ops->id);
 		}
 
 		qdisc_watchdog_schedule(&q->watchdog, cb->time_to_send);
@@ -307,7 +308,7 @@ static void netem_reset(struct Qdisc *sch)
 {
 	struct netem_sched_data *q = qdisc_priv(sch);
 
-	qdisc_reset(q->qdisc);
+	qdisc_reset(q->class.qdisc);
 	sch->q.qlen = 0;
 	qdisc_watchdog_cancel(&q->watchdog);
 }
@@ -394,7 +395,7 @@ static int netem_change(struct Qdisc *sch, struct rtattr *opt)
 		return -EINVAL;
 
 	qopt = RTA_DATA(opt);
-	ret = fifo_set_limit(q->qdisc, qopt->limit);
+	ret = fifo_set_limit(q->class.qdisc, qopt->limit);
 	if (ret) {
 		pr_debug("netem: can't set fifo limit\n");
 		return ret;
@@ -547,9 +548,9 @@ static int netem_init(struct Qdisc *sch, struct rtattr *opt)
 
 	qdisc_watchdog_init(&q->watchdog, sch);
 
-	q->qdisc = qdisc_create_dflt(sch->dev, &tfifo_qdisc_ops,
-				     TC_H_MAKE(sch->handle, 1));
-	if (!q->qdisc) {
+	q->class.qdisc = qdisc_create_dflt(sch->dev, &tfifo_qdisc_ops,
+					   TC_H_MAKE(sch->handle, 1));
+	if (!q->class.qdisc) {
 		pr_debug("netem: qdisc create failed\n");
 		return -ENOMEM;
 	}
@@ -557,7 +558,7 @@ static int netem_init(struct Qdisc *sch, struct rtattr *opt)
 	ret = netem_change(sch, opt);
 	if (ret) {
 		pr_debug("netem: change failed\n");
-		qdisc_destroy(q->qdisc);
+		qdisc_destroy(q->class.qdisc);
 	}
 	return ret;
 }
@@ -567,7 +568,7 @@ static void netem_destroy(struct Qdisc *sch)
 	struct netem_sched_data *q = qdisc_priv(sch);
 
 	qdisc_watchdog_cancel(&q->watchdog);
-	qdisc_destroy(q->qdisc);
+	qdisc_destroy(q->class.qdisc);
 	kfree(q->delay_dist);
 }
 
@@ -611,95 +612,9 @@ rtattr_failure:
 	return -1;
 }
 
-static int netem_dump_class(struct Qdisc *sch, unsigned long cl,
-			  struct sk_buff *skb, struct tcmsg *tcm)
-{
-	struct netem_sched_data *q = qdisc_priv(sch);
-
-	if (cl != 1) 	/* only one class */
-		return -ENOENT;
-
-	tcm->tcm_handle |= TC_H_MIN(1);
-	tcm->tcm_info = q->qdisc->handle;
-
-	return 0;
-}
-
-static int netem_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new,
-		     struct Qdisc **old)
-{
-	struct netem_sched_data *q = qdisc_priv(sch);
-
-	if (new == NULL)
-		new = &noop_qdisc;
-
-	sch_tree_lock(sch);
-	*old = xchg(&q->qdisc, new);
-	qdisc_tree_decrease_qlen(*old, (*old)->q.qlen);
-	qdisc_reset(*old);
-	sch_tree_unlock(sch);
-
-	return 0;
-}
-
-static struct Qdisc *netem_leaf(struct Qdisc *sch, unsigned long arg)
-{
-	struct netem_sched_data *q = qdisc_priv(sch);
-	return q->qdisc;
-}
-
-static unsigned long netem_get(struct Qdisc *sch, u32 classid)
-{
-	return 1;
-}
-
-static void netem_put(struct Qdisc *sch, unsigned long arg)
-{
-}
-
-static int netem_change_class(struct Qdisc *sch, u32 classid, u32 parentid,
-			    struct rtattr **tca, unsigned long *arg)
-{
-	return -ENOSYS;
-}
-
-static int netem_delete(struct Qdisc *sch, unsigned long arg)
-{
-	return -ENOSYS;
-}
-
-static void netem_walk(struct Qdisc *sch, struct qdisc_walker *walker)
-{
-	if (!walker->stop) {
-		if (walker->count >= walker->skip)
-			if (walker->fn(sch, 1, walker) < 0) {
-				walker->stop = 1;
-				return;
-			}
-		walker->count++;
-	}
-}
-
-static struct tcf_proto **netem_find_tcf(struct Qdisc *sch, unsigned long cl)
-{
-	return NULL;
-}
-
-static const struct Qdisc_class_ops netem_class_ops = {
-	.graft		=	netem_graft,
-	.leaf		=	netem_leaf,
-	.get		=	netem_get,
-	.put		=	netem_put,
-	.change		=	netem_change_class,
-	.delete		=	netem_delete,
-	.walk		=	netem_walk,
-	.tcf_chain	=	netem_find_tcf,
-	.dump		=	netem_dump_class,
-};
-
 static struct Qdisc_ops netem_qdisc_ops __read_mostly = {
 	.id		=	"netem",
-	.cl_ops		=	&netem_class_ops,
+	.cl_ops		=	&pseudo_classful_ops,
 	.priv_size	=	sizeof(struct netem_sched_data),
 	.enqueue	=	netem_enqueue,
 	.dequeue	=	netem_dequeue,
diff --git a/net/sched/sch_pseudo_classful.c b/net/sched/sch_pseudo_classful.c
new file mode 100644
index 0000000..5b9fba5
--- /dev/null
+++ b/net/sched/sch_pseudo_classful.c
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2007 Patrick McHardy, <kaber@trash.net>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/skbuff.h>
+#include <net/sch_generic.h>
+#include <net/pkt_sched.h>
+
+static int sch_pc_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new,
+			struct Qdisc **old)
+{
+	struct pc_sched_data *q = qdisc_priv(sch);
+
+	if (new == NULL)
+		new = &noop_qdisc;
+
+	sch_tree_lock(sch);
+	*old = xchg(&q->qdisc, new);
+	qdisc_tree_decrease_qlen(*old, (*old)->q.qlen);
+	qdisc_reset(*old);
+	sch_tree_unlock(sch);
+	return 0;
+}
+
+static int sch_pc_change_class(struct Qdisc *sch, u32 classid, u32 parentid,
+			       struct rtattr **tca, unsigned long *arg)
+{
+	return -ENOSYS;
+}
+
+static struct Qdisc *sch_pc_leaf(struct Qdisc *sch, unsigned long arg)
+{
+	return ((struct pc_sched_data *)qdisc_priv(sch))->qdisc;
+}
+
+static unsigned long sch_pc_get(struct Qdisc *sch, u32 classid)
+{
+	return 1;
+}
+
+static void sch_pc_put(struct Qdisc *sch, unsigned long arg)
+{
+	return;
+}
+
+static int sch_pc_delete(struct Qdisc *sch, unsigned long arg)
+{
+	return -ENOSYS;
+}
+
+static struct tcf_proto **sch_pc_tcf_chain(struct Qdisc *sch, unsigned long cl)
+{
+	return NULL;
+}
+
+static int sch_pc_dump_class(struct Qdisc *sch, unsigned long cl,
+			     struct sk_buff *skb, struct tcmsg *tcm)
+{
+	struct pc_sched_data *q = qdisc_priv(sch);
+
+	if (cl != 1)
+		return -ENOENT;
+
+	tcm->tcm_handle |= TC_H_MIN(1);
+	tcm->tcm_info = q->qdisc->handle;
+	return 0;
+}
+
+static void sch_pc_walk(struct Qdisc *sch, struct qdisc_walker *walker)
+{
+	if (!walker->stop) {
+		if (walker->count >= walker->skip)
+			if (walker->fn(sch, 1, walker) < 0) {
+				walker->stop = 1;
+				return;
+			}
+		walker->count++;
+	}
+}
+
+const struct Qdisc_class_ops pseudo_classful_ops = {
+	.graft		= sch_pc_graft,
+	.leaf		= sch_pc_leaf,
+	.get		= sch_pc_get,
+	.put		= sch_pc_put,
+	.change		= sch_pc_change_class,
+	.delete		= sch_pc_delete,
+	.walk		= sch_pc_walk,
+	.tcf_chain	= sch_pc_tcf_chain,
+	.dump		= sch_pc_dump_class,
+};
+EXPORT_SYMBOL(pseudo_classful_ops);
+
+MODULE_LICENSE("GPL");
diff --git a/net/sched/sch_red.c b/net/sched/sch_red.c
index 076f1ef..fc61675 100644
--- a/net/sched/sch_red.c
+++ b/net/sched/sch_red.c
@@ -38,11 +38,12 @@
 
 struct red_sched_data
 {
+	struct pc_sched_data	class;
+
 	u32			limit;		/* HARD maximal queue length */
 	unsigned char		flags;
 	struct red_parms	parms;
 	struct red_stats	stats;
-	struct Qdisc		*qdisc;
 };
 
 static inline int red_use_ecn(struct red_sched_data *q)
@@ -58,7 +59,7 @@ static inline int red_use_harddrop(struct red_sched_data *q)
 static int red_enqueue(struct sk_buff *skb, struct Qdisc* sch)
 {
 	struct red_sched_data *q = qdisc_priv(sch);
-	struct Qdisc *child = q->qdisc;
+	struct Qdisc *child = q->class.qdisc;
 	int ret;
 
 	q->parms.qavg = red_calc_qavg(&q->parms, child->qstats.backlog);
@@ -111,7 +112,7 @@ congestion_drop:
 static int red_requeue(struct sk_buff *skb, struct Qdisc* sch)
 {
 	struct red_sched_data *q = qdisc_priv(sch);
-	struct Qdisc *child = q->qdisc;
+	struct Qdisc *child = q->class.qdisc;
 	int ret;
 
 	if (red_is_idling(&q->parms))
@@ -129,7 +130,7 @@ static struct sk_buff * red_dequeue(struct Qdisc* sch)
 {
 	struct sk_buff *skb;
 	struct red_sched_data *q = qdisc_priv(sch);
-	struct Qdisc *child = q->qdisc;
+	struct Qdisc *child = q->class.qdisc;
 
 	skb = qdisc_dequeue(child);
 	if (skb)
@@ -143,7 +144,7 @@ static struct sk_buff * red_dequeue(struct Qdisc* sch)
 static unsigned int red_drop(struct Qdisc* sch)
 {
 	struct red_sched_data *q = qdisc_priv(sch);
-	struct Qdisc *child = q->qdisc;
+	struct Qdisc *child = q->class.qdisc;
 	unsigned int len;
 
 	len = qdisc_drop(child);
@@ -164,7 +165,7 @@ static void red_reset(struct Qdisc* sch)
 {
 	struct red_sched_data *q = qdisc_priv(sch);
 
-	qdisc_reset(q->qdisc);
+	qdisc_reset(q->class.qdisc);
 	sch->q.qlen = 0;
 	red_restart(&q->parms);
 }
@@ -172,7 +173,7 @@ static void red_reset(struct Qdisc* sch)
 static void red_destroy(struct Qdisc *sch)
 {
 	struct red_sched_data *q = qdisc_priv(sch);
-	qdisc_destroy(q->qdisc);
+	qdisc_destroy(q->class.qdisc);
 }
 
 static int red_change(struct Qdisc *sch, struct rtattr *opt)
@@ -203,8 +204,9 @@ static int red_change(struct Qdisc *sch, struct rtattr *opt)
 	q->flags = ctl->flags;
 	q->limit = ctl->limit;
 	if (child) {
-		qdisc_tree_decrease_qlen(q->qdisc, q->qdisc->q.qlen);
-		qdisc_destroy(xchg(&q->qdisc, child));
+		qdisc_tree_decrease_qlen(q->class.qdisc,
+					 q->class.qdisc->q.qlen);
+		qdisc_destroy(xchg(&q->class.qdisc, child));
 	}
 
 	red_set_parms(&q->parms, ctl->qth_min, ctl->qth_max, ctl->Wlog,
@@ -222,7 +224,7 @@ static int red_init(struct Qdisc* sch, struct rtattr *opt)
 {
 	struct red_sched_data *q = qdisc_priv(sch);
 
-	q->qdisc = &noop_qdisc;
+	q->class.qdisc = &noop_qdisc;
 	return red_change(sch, opt);
 }
 
@@ -261,94 +263,10 @@ static int red_dump_stats(struct Qdisc *sch, struct gnet_dump *d)
 	return gnet_stats_copy_app(d, &st, sizeof(st));
 }
 
-static int red_dump_class(struct Qdisc *sch, unsigned long cl,
-			  struct sk_buff *skb, struct tcmsg *tcm)
-{
-	struct red_sched_data *q = qdisc_priv(sch);
-
-	if (cl != 1)
-		return -ENOENT;
-	tcm->tcm_handle |= TC_H_MIN(1);
-	tcm->tcm_info = q->qdisc->handle;
-	return 0;
-}
-
-static int red_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new,
-		     struct Qdisc **old)
-{
-	struct red_sched_data *q = qdisc_priv(sch);
-
-	if (new == NULL)
-		new = &noop_qdisc;
-
-	sch_tree_lock(sch);
-	*old = xchg(&q->qdisc, new);
-	qdisc_tree_decrease_qlen(*old, (*old)->q.qlen);
-	qdisc_reset(*old);
-	sch_tree_unlock(sch);
-	return 0;
-}
-
-static struct Qdisc *red_leaf(struct Qdisc *sch, unsigned long arg)
-{
-	struct red_sched_data *q = qdisc_priv(sch);
-	return q->qdisc;
-}
-
-static unsigned long red_get(struct Qdisc *sch, u32 classid)
-{
-	return 1;
-}
-
-static void red_put(struct Qdisc *sch, unsigned long arg)
-{
-	return;
-}
-
-static int red_change_class(struct Qdisc *sch, u32 classid, u32 parentid,
-			    struct rtattr **tca, unsigned long *arg)
-{
-	return -ENOSYS;
-}
-
-static int red_delete(struct Qdisc *sch, unsigned long cl)
-{
-	return -ENOSYS;
-}
-
-static void red_walk(struct Qdisc *sch, struct qdisc_walker *walker)
-{
-	if (!walker->stop) {
-		if (walker->count >= walker->skip)
-			if (walker->fn(sch, 1, walker) < 0) {
-				walker->stop = 1;
-				return;
-			}
-		walker->count++;
-	}
-}
-
-static struct tcf_proto **red_find_tcf(struct Qdisc *sch, unsigned long cl)
-{
-	return NULL;
-}
-
-static const struct Qdisc_class_ops red_class_ops = {
-	.graft		=	red_graft,
-	.leaf		=	red_leaf,
-	.get		=	red_get,
-	.put		=	red_put,
-	.change		=	red_change_class,
-	.delete		=	red_delete,
-	.walk		=	red_walk,
-	.tcf_chain	=	red_find_tcf,
-	.dump		=	red_dump_class,
-};
-
 static struct Qdisc_ops red_qdisc_ops __read_mostly = {
 	.id		=	"red",
 	.priv_size	=	sizeof(struct red_sched_data),
-	.cl_ops		=	&red_class_ops,
+	.cl_ops		=	&pseudo_classful_ops,
 	.enqueue	=	red_enqueue,
 	.dequeue	=	red_dequeue,
 	.requeue	=	red_requeue,
diff --git a/net/sched/sch_tbf.c b/net/sched/sch_tbf.c
index 5fd4dff..6590ce3 100644
--- a/net/sched/sch_tbf.c
+++ b/net/sched/sch_tbf.c
@@ -99,6 +99,8 @@
 
 struct tbf_sched_data
 {
+	struct pc_sched_data	class;
+
 /* Parameters */
 	u32		limit;		/* Maximal length of backlog: bytes */
 	u32		buffer;		/* Token bucket depth/rate: MUST BE >= MTU/B */
@@ -111,7 +113,6 @@ struct tbf_sched_data
 	long	tokens;			/* Current number of B tokens */
 	long	ptokens;		/* Current number of P tokens */
 	psched_time_t	t_c;		/* Time check-point */
-	struct Qdisc	*qdisc;		/* Inner qdisc, default - bfifo queue */
 	struct qdisc_watchdog watchdog;	/* Watchdog timer */
 };
 
@@ -133,7 +134,7 @@ static int tbf_enqueue(struct sk_buff *skb, struct Qdisc* sch)
 		return NET_XMIT_DROP;
 	}
 
-	ret = qdisc_enqueue(skb, q->qdisc);
+	ret = qdisc_enqueue(skb, q->class.qdisc);
 	if (ret != NET_XMIT_SUCCESS) {
 		sch->qstats.drops++;
 		return ret;
@@ -150,7 +151,7 @@ static int tbf_requeue(struct sk_buff *skb, struct Qdisc* sch)
 	struct tbf_sched_data *q = qdisc_priv(sch);
 	int ret;
 
-	ret = qdisc_requeue(skb, q->qdisc);
+	ret = qdisc_requeue(skb, q->class.qdisc);
 	if (ret == NET_XMIT_SUCCESS) {
 		sch->q.qlen++;
 		sch->qstats.requeues++;
@@ -164,7 +165,7 @@ static unsigned int tbf_drop(struct Qdisc* sch)
 	struct tbf_sched_data *q = qdisc_priv(sch);
 	unsigned int len = 0;
 
-	len = qdisc_drop(q->qdisc);
+	len = qdisc_drop(q->class.qdisc);
 	if (len > 0) {
 		sch->q.qlen--;
 		sch->qstats.drops++;
@@ -177,7 +178,7 @@ static struct sk_buff *tbf_dequeue(struct Qdisc* sch)
 	struct tbf_sched_data *q = qdisc_priv(sch);
 	struct sk_buff *skb;
 
-	skb = qdisc_dequeue(q->qdisc);
+	skb = qdisc_dequeue(q->class.qdisc);
 
 	if (skb) {
 		psched_time_t now;
@@ -222,9 +223,9 @@ static struct sk_buff *tbf_dequeue(struct Qdisc* sch)
 		   (cf. CSZ, HPFQ, HFSC)
 		 */
 
-		if (q->qdisc->ops->requeue(skb, q->qdisc) != NET_XMIT_SUCCESS) {
+		if (q->class.qdisc->ops->requeue(skb, q->class.qdisc) != NET_XMIT_SUCCESS) {
 			/* When requeue fails skb is dropped */
-			qdisc_tree_decrease_qlen(q->qdisc, 1);
+			qdisc_tree_decrease_qlen(q->class.qdisc, 1);
 			sch->qstats.drops++;
 		}
 
@@ -237,7 +238,7 @@ static void tbf_reset(struct Qdisc* sch)
 {
 	struct tbf_sched_data *q = qdisc_priv(sch);
 
-	qdisc_reset(q->qdisc);
+	qdisc_reset(q->class.qdisc);
 	sch->q.qlen = 0;
 	q->t_c = psched_get_time();
 	q->tokens = q->buffer;
@@ -295,8 +296,8 @@ static int tbf_change(struct Qdisc* sch, struct rtattr *opt)
 
 	sch_tree_lock(sch);
 	if (child) {
-		qdisc_tree_decrease_qlen(q->qdisc, q->qdisc->q.qlen);
-		qdisc_destroy(xchg(&q->qdisc, child));
+		qdisc_tree_decrease_qlen(q->class.qdisc, q->class.qdisc->q.qlen);
+		qdisc_destroy(xchg(&q->class.qdisc, child));
 	}
 	q->limit = qopt->limit;
 	q->mtu = qopt->mtu;
@@ -325,7 +326,7 @@ static int tbf_init(struct Qdisc* sch, struct rtattr *opt)
 
 	q->t_c = psched_get_time();
 	qdisc_watchdog_init(&q->watchdog, sch);
-	q->qdisc = &noop_qdisc;
+	q->class.qdisc = &noop_qdisc;
 
 	return tbf_change(sch, opt);
 }
@@ -341,7 +342,7 @@ static void tbf_destroy(struct Qdisc *sch)
 	if (q->R_tab)
 		qdisc_put_rtab(q->R_tab);
 
-	qdisc_destroy(q->qdisc);
+	qdisc_destroy(q->class.qdisc);
 }
 
 static int tbf_dump(struct Qdisc *sch, struct sk_buff *skb)
@@ -372,96 +373,8 @@ rtattr_failure:
 	return -1;
 }
 
-static int tbf_dump_class(struct Qdisc *sch, unsigned long cl,
-			  struct sk_buff *skb, struct tcmsg *tcm)
-{
-	struct tbf_sched_data *q = qdisc_priv(sch);
-
-	if (cl != 1) 	/* only one class */
-		return -ENOENT;
-
-	tcm->tcm_handle |= TC_H_MIN(1);
-	tcm->tcm_info = q->qdisc->handle;
-
-	return 0;
-}
-
-static int tbf_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new,
-		     struct Qdisc **old)
-{
-	struct tbf_sched_data *q = qdisc_priv(sch);
-
-	if (new == NULL)
-		new = &noop_qdisc;
-
-	sch_tree_lock(sch);
-	*old = xchg(&q->qdisc, new);
-	qdisc_tree_decrease_qlen(*old, (*old)->q.qlen);
-	qdisc_reset(*old);
-	sch_tree_unlock(sch);
-
-	return 0;
-}
-
-static struct Qdisc *tbf_leaf(struct Qdisc *sch, unsigned long arg)
-{
-	struct tbf_sched_data *q = qdisc_priv(sch);
-	return q->qdisc;
-}
-
-static unsigned long tbf_get(struct Qdisc *sch, u32 classid)
-{
-	return 1;
-}
-
-static void tbf_put(struct Qdisc *sch, unsigned long arg)
-{
-}
-
-static int tbf_change_class(struct Qdisc *sch, u32 classid, u32 parentid,
-			    struct rtattr **tca, unsigned long *arg)
-{
-	return -ENOSYS;
-}
-
-static int tbf_delete(struct Qdisc *sch, unsigned long arg)
-{
-	return -ENOSYS;
-}
-
-static void tbf_walk(struct Qdisc *sch, struct qdisc_walker *walker)
-{
-	if (!walker->stop) {
-		if (walker->count >= walker->skip)
-			if (walker->fn(sch, 1, walker) < 0) {
-				walker->stop = 1;
-				return;
-			}
-		walker->count++;
-	}
-}
-
-static struct tcf_proto **tbf_find_tcf(struct Qdisc *sch, unsigned long cl)
-{
-	return NULL;
-}
-
-static const struct Qdisc_class_ops tbf_class_ops =
-{
-	.graft		=	tbf_graft,
-	.leaf		=	tbf_leaf,
-	.get		=	tbf_get,
-	.put		=	tbf_put,
-	.change		=	tbf_change_class,
-	.delete		=	tbf_delete,
-	.walk		=	tbf_walk,
-	.tcf_chain	=	tbf_find_tcf,
-	.dump		=	tbf_dump_class,
-};
-
 static struct Qdisc_ops tbf_qdisc_ops __read_mostly = {
-	.next		=	NULL,
-	.cl_ops		=	&tbf_class_ops,
+	.cl_ops		=	&pseudo_classful_ops,
 	.id		=	"tbf",
 	.priv_size	=	sizeof(struct tbf_sched_data),
 	.enqueue	=	tbf_enqueue,

^ permalink raw reply related

* [RFC NET_SCHED 04/05]: Use qdisc helpers
From: Patrick McHardy @ 2008-01-20 18:28 UTC (permalink / raw)
  To: netdev; +Cc: Patrick McHardy
In-Reply-To: <20080120182848.10972.46380.sendpatchset@localhost.localdomain>

commit 8b0737e99efbf5b51f950d9fa95d69f96bf0a926
Author: Patrick McHardy <kaber@trash.net>
Date:   Wed Jan 16 12:22:00 2008 +0100

    [NET_SCHED]: Use qdisc helpers
    
    Use the new qdisc helpers where possible. Also pull return value
    assignments out of conditions and use proper NET_XMIT codes where
    possible.
    
    Signed-off-by: Patrick McHardy <kaber@trash.net>

diff --git a/net/core/dev.c b/net/core/dev.c
index 385b799..663031c 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -1673,7 +1673,7 @@ gso:
 		if (q->enqueue) {
 			/* reset queue_mapping to zero */
 			skb_set_queue_mapping(skb, 0);
-			rc = q->enqueue(skb, q);
+			rc = qdisc_enqueue(skb, q);
 			qdisc_run(dev);
 			spin_unlock(&dev->queue_lock);
 
@@ -1970,7 +1970,7 @@ static int ing_filter(struct sk_buff *skb)
 
 	spin_lock(&dev->ingress_lock);
 	if ((q = dev->qdisc_ingress) != NULL)
-		result = q->enqueue(skb, q);
+		result = qdisc_enqueue(skb, q);
 	spin_unlock(&dev->ingress_lock);
 
 	return result;
diff --git a/net/sched/sch_atm.c b/net/sched/sch_atm.c
index d870a41..844774d 100644
--- a/net/sched/sch_atm.c
+++ b/net/sched/sch_atm.c
@@ -430,7 +430,8 @@ static int atm_tc_enqueue(struct sk_buff *skb, struct Qdisc *sch)
 #endif
 	}
 
-	if ((ret = flow->q->enqueue(skb, flow->q)) != 0) {
+	ret = qdisc_enqueue(skb, flow->q);
+	if (ret != NET_XMIT_SUCCESS) {
 drop: __maybe_unused
 		sch->qstats.drops++;
 		if (flow)
@@ -478,9 +479,9 @@ static void sch_atm_dequeue(unsigned long data)
 		 * If traffic is properly shaped, this won't generate nasty
 		 * little bursts. Otherwise, it may ... (but that's okay)
 		 */
-		while ((skb = flow->q->dequeue(flow->q))) {
+		while ((skb = qdisc_dequeue(flow->q))) {
 			if (!atm_may_send(flow->vcc, skb->truesize)) {
-				(void)flow->q->ops->requeue(skb, flow->q);
+				qdisc_requeue(skb, flow->q);
 				break;
 			}
 			D2PRINTK("atm_tc_dequeue: sending on class %p\n", flow);
@@ -514,7 +515,7 @@ static struct sk_buff *atm_tc_dequeue(struct Qdisc *sch)
 
 	D2PRINTK("atm_tc_dequeue(sch %p,[qdisc %p])\n", sch, p);
 	tasklet_schedule(&p->task);
-	skb = p->link.q->dequeue(p->link.q);
+	skb = qdisc_dequeue(p->link.q);
 	if (skb)
 		sch->q.qlen--;
 	return skb;
@@ -526,7 +527,7 @@ static int atm_tc_requeue(struct sk_buff *skb, struct Qdisc *sch)
 	int ret;
 
 	D2PRINTK("atm_tc_requeue(skb %p,sch %p,[qdisc %p])\n", skb, sch, p);
-	ret = p->link.q->ops->requeue(skb, p->link.q);
+	ret = qdisc_requeue(skb, p->link.q);
 	if (!ret) {
 		sch->q.qlen++;
 		sch->qstats.requeues++;
@@ -544,9 +545,11 @@ static unsigned int atm_tc_drop(struct Qdisc *sch)
 	unsigned int len;
 
 	DPRINTK("atm_tc_drop(sch %p,[qdisc %p])\n", sch, p);
-	for (flow = p->flows; flow; flow = flow->next)
-		if (flow->q->ops->drop && (len = flow->q->ops->drop(flow->q)))
+	for (flow = p->flows; flow; flow = flow->next) {
+		len = qdisc_drop(flow->q);
+		if (len > 0)
 			return len;
+	}
 	return 0;
 }
 
diff --git a/net/sched/sch_cbq.c b/net/sched/sch_cbq.c
index bea123f..8731f51 100644
--- a/net/sched/sch_cbq.c
+++ b/net/sched/sch_cbq.c
@@ -396,7 +396,8 @@ cbq_enqueue(struct sk_buff *skb, struct Qdisc *sch)
 #ifdef CONFIG_NET_CLS_ACT
 	cl->q->__parent = sch;
 #endif
-	if ((ret = cl->q->enqueue(skb, cl->q)) == NET_XMIT_SUCCESS) {
+	ret = qdisc_enqueue(skb, cl->q);
+	if (ret == NET_XMIT_SUCCESS) {
 		sch->q.qlen++;
 		sch->bstats.packets++;
 		sch->bstats.bytes+=len;
@@ -432,7 +433,8 @@ cbq_requeue(struct sk_buff *skb, struct Qdisc *sch)
 	q->rx_class = cl;
 	cl->q->__parent = sch;
 #endif
-	if ((ret = cl->q->ops->requeue(skb, cl->q)) == 0) {
+	ret = qdisc_requeue(skb, cl->q);
+	if (ret == NET_XMIT_SUCCESS) {
 		sch->q.qlen++;
 		sch->qstats.requeues++;
 		if (!cl->next_alive)
@@ -580,9 +582,8 @@ static void cbq_ovl_lowprio(struct cbq_class *cl)
 
 static void cbq_ovl_drop(struct cbq_class *cl)
 {
-	if (cl->q->ops->drop)
-		if (cl->q->ops->drop(cl->q))
-			cl->qdisc->q.qlen--;
+	if (qdisc_drop(cl->q))
+		cl->qdisc->q.qlen--;
 	cl->xstats.overactions++;
 	cbq_ovl_classic(cl);
 }
@@ -680,7 +681,7 @@ static int cbq_reshape_fail(struct sk_buff *skb, struct Qdisc *child)
 		q->rx_class = cl;
 		cl->q->__parent = sch;
 
-		if (cl->q->enqueue(skb, cl->q) == 0) {
+		if (qdisc_enqueue(skb, cl->q) == NET_XMIT_SUCCESS) {
 			sch->q.qlen++;
 			sch->bstats.packets++;
 			sch->bstats.bytes+=len;
@@ -880,7 +881,7 @@ cbq_dequeue_prio(struct Qdisc *sch, int prio)
 				goto next_class;
 			}
 
-			skb = cl->q->dequeue(cl->q);
+			skb = qdisc_dequeue(cl->q);
 
 			/* Class did not give us any skb :-(
 			   It could occur even if cl->q->q.qlen != 0
@@ -1226,7 +1227,8 @@ static unsigned int cbq_drop(struct Qdisc* sch)
 
 		cl = cl_head;
 		do {
-			if (cl->q->ops->drop && (len = cl->q->ops->drop(cl->q))) {
+			len = qdisc_drop(cl->q);
+			if (len > 0) {
 				sch->q.qlen--;
 				if (!cl->q->q.qlen)
 					cbq_deactivate_class(cl);
diff --git a/net/sched/sch_dsmark.c b/net/sched/sch_dsmark.c
index b9fe697..9bdb46e 100644
--- a/net/sched/sch_dsmark.c
+++ b/net/sched/sch_dsmark.c
@@ -257,7 +257,7 @@ static int dsmark_enqueue(struct sk_buff *skb,struct Qdisc *sch)
 		}
 	}
 
-	err = p->q->enqueue(skb,p->q);
+	err = qdisc_enqueue(skb, p->q);
 	if (err != NET_XMIT_SUCCESS) {
 		sch->qstats.drops++;
 		return err;
@@ -278,7 +278,7 @@ static struct sk_buff *dsmark_dequeue(struct Qdisc *sch)
 
 	D2PRINTK("dsmark_dequeue(sch %p,[qdisc %p])\n", sch, p);
 
-	skb = p->q->ops->dequeue(p->q);
+	skb = qdisc_dequeue(p->q);
 	if (skb == NULL)
 		return NULL;
 
@@ -319,7 +319,7 @@ static int dsmark_requeue(struct sk_buff *skb,struct Qdisc *sch)
 
 	D2PRINTK("dsmark_requeue(skb %p,sch %p,[qdisc %p])\n", skb, sch, p);
 
-	err = p->q->ops->requeue(skb, p->q);
+	err = qdisc_requeue(skb, p->q);
 	if (err != NET_XMIT_SUCCESS) {
 		sch->qstats.drops++;
 		return err;
@@ -338,10 +338,7 @@ static unsigned int dsmark_drop(struct Qdisc *sch)
 
 	DPRINTK("dsmark_reset(sch %p,[qdisc %p])\n", sch, p);
 
-	if (p->q->ops->drop == NULL)
-		return 0;
-
-	len = p->q->ops->drop(p->q);
+	len = qdisc_drop(p->q);
 	if (len)
 		sch->q.qlen--;
 
diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c
index 8e186e1..483f753 100644
--- a/net/sched/sch_generic.c
+++ b/net/sched/sch_generic.c
@@ -76,7 +76,7 @@ static inline struct sk_buff *dev_dequeue_skb(struct net_device *dev,
 	if ((skb = dev->gso_skb))
 		dev->gso_skb = NULL;
 	else
-		skb = q->dequeue(q);
+		skb = qdisc_dequeue(q);
 
 	return skb;
 }
diff --git a/net/sched/sch_hfsc.c b/net/sched/sch_hfsc.c
index ff03327..71d7442 100644
--- a/net/sched/sch_hfsc.c
+++ b/net/sched/sch_hfsc.c
@@ -892,14 +892,14 @@ qdisc_peek_len(struct Qdisc *sch)
 	struct sk_buff *skb;
 	unsigned int len;
 
-	skb = sch->dequeue(sch);
+	skb = qdisc_dequeue(sch);
 	if (skb == NULL) {
 		if (net_ratelimit())
 			printk("qdisc_peek_len: non work-conserving qdisc ?\n");
 		return 0;
 	}
 	len = skb->len;
-	if (unlikely(sch->ops->requeue(skb, sch) != NET_XMIT_SUCCESS)) {
+	if (unlikely(qdisc_requeue(skb, sch) != NET_XMIT_SUCCESS)) {
 		if (net_ratelimit())
 			printk("qdisc_peek_len: failed to requeue\n");
 		qdisc_tree_decrease_qlen(sch, 1);
@@ -1574,7 +1574,7 @@ hfsc_enqueue(struct sk_buff *skb, struct Qdisc *sch)
 	}
 
 	len = skb->len;
-	err = cl->qdisc->enqueue(skb, cl->qdisc);
+	err = qdisc_enqueue(skb, cl->qdisc);
 	if (unlikely(err != NET_XMIT_SUCCESS)) {
 		cl->qstats.drops++;
 		sch->qstats.drops++;
@@ -1630,7 +1630,7 @@ hfsc_dequeue(struct Qdisc *sch)
 		}
 	}
 
-	skb = cl->qdisc->dequeue(cl->qdisc);
+	skb = qdisc_dequeue(cl->qdisc);
 	if (skb == NULL) {
 		if (net_ratelimit())
 			printk("HFSC: Non-work-conserving qdisc ?\n");
@@ -1681,8 +1681,8 @@ hfsc_drop(struct Qdisc *sch)
 	unsigned int len;
 
 	list_for_each_entry(cl, &q->droplist, dlist) {
-		if (cl->qdisc->ops->drop != NULL &&
-		    (len = cl->qdisc->ops->drop(cl->qdisc)) > 0) {
+		len = qdisc_drop(cl->qdisc);
+		if (len > 0) {
 			if (cl->qdisc->q.qlen == 0) {
 				update_vf(cl, 0, 0);
 				set_passive(cl);
diff --git a/net/sched/sch_htb.c b/net/sched/sch_htb.c
index 72beb66..ca3d4a5 100644
--- a/net/sched/sch_htb.c
+++ b/net/sched/sch_htb.c
@@ -592,7 +592,7 @@ static int htb_enqueue(struct sk_buff *skb, struct Qdisc *sch)
 		kfree_skb(skb);
 		return ret;
 #endif
-	} else if (cl->un.leaf.q->enqueue(skb, cl->un.leaf.q) !=
+	} else if (qdisc_enqueue(skb, cl->un.leaf.q) !=
 		   NET_XMIT_SUCCESS) {
 		sch->qstats.drops++;
 		cl->qstats.drops++;
@@ -629,7 +629,7 @@ static int htb_requeue(struct sk_buff *skb, struct Qdisc *sch)
 			sch->qstats.drops++;
 			return NET_XMIT_CN;
 		}
-	} else if (cl->un.leaf.q->ops->requeue(skb, cl->un.leaf.q) !=
+	} else if (qdisc_requeue(skb, cl->un.leaf.q) !=
 		   NET_XMIT_SUCCESS) {
 		sch->qstats.drops++;
 		cl->qstats.drops++;
@@ -849,7 +849,7 @@ next:
 			goto next;
 		}
 
-		skb = cl->un.leaf.q->dequeue(cl->un.leaf.q);
+		skb = qdisc_dequeue(cl->un.leaf.q);
 		if (likely(skb != NULL))
 			break;
 		if (!cl->warned) {
@@ -949,8 +949,9 @@ static unsigned int htb_drop(struct Qdisc *sch)
 			struct htb_class *cl = list_entry(p, struct htb_class,
 							  un.leaf.drop_list);
 			unsigned int len;
-			if (cl->un.leaf.q->ops->drop &&
-			    (len = cl->un.leaf.q->ops->drop(cl->un.leaf.q))) {
+
+			len = qdisc_drop(cl->un.leaf.q);
+			if (len) {
 				sch->q.qlen--;
 				if (!cl->un.leaf.q->q.qlen)
 					htb_deactivate(q, cl);
diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c
index 3ec4a81..f6c24fd 100644
--- a/net/sched/sch_netem.c
+++ b/net/sched/sch_netem.c
@@ -184,7 +184,7 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch)
 		u32 dupsave = q->duplicate; /* prevent duplicating a dup... */
 		q->duplicate = 0;
 
-		rootq->enqueue(skb2, rootq);
+		qdisc_enqueue(skb2, rootq);
 		q->duplicate = dupsave;
 	}
 
@@ -218,7 +218,7 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch)
 		now = psched_get_time();
 		cb->time_to_send = now + delay;
 		++q->counter;
-		ret = q->qdisc->enqueue(skb, q->qdisc);
+		ret = qdisc_enqueue(skb, q->qdisc);
 	} else {
 		/*
 		 * Do re-ordering by putting one out of N packets at the front
@@ -226,7 +226,7 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch)
 		 */
 		cb->time_to_send = psched_get_time();
 		q->counter = 0;
-		ret = q->qdisc->ops->requeue(skb, q->qdisc);
+		ret = qdisc_requeue(skb, q->qdisc);
 	}
 
 	if (likely(ret == NET_XMIT_SUCCESS)) {
@@ -246,7 +246,8 @@ static int netem_requeue(struct sk_buff *skb, struct Qdisc *sch)
 	struct netem_sched_data *q = qdisc_priv(sch);
 	int ret;
 
-	if ((ret = q->qdisc->ops->requeue(skb, q->qdisc)) == 0) {
+	ret = qdisc_requeue(skb, q->qdisc);
+	if (ret == NET_XMIT_SUCCESS) {
 		sch->q.qlen++;
 		sch->qstats.requeues++;
 	}
@@ -259,7 +260,8 @@ static unsigned int netem_drop(struct Qdisc* sch)
 	struct netem_sched_data *q = qdisc_priv(sch);
 	unsigned int len = 0;
 
-	if (q->qdisc->ops->drop && (len = q->qdisc->ops->drop(q->qdisc)) != 0) {
+	len = qdisc_drop(q->qdisc);
+	if (len > 0) {
 		sch->q.qlen--;
 		sch->qstats.drops++;
 	}
@@ -275,7 +277,7 @@ static struct sk_buff *netem_dequeue(struct Qdisc *sch)
 	if (sch->flags & TCQ_F_THROTTLED)
 		return NULL;
 
-	skb = q->qdisc->dequeue(q->qdisc);
+	skb = qdisc_dequeue(q->qdisc);
 	if (skb) {
 		const struct netem_skb_cb *cb
 			= (const struct netem_skb_cb *)skb->cb;
@@ -288,7 +290,7 @@ static struct sk_buff *netem_dequeue(struct Qdisc *sch)
 			return skb;
 		}
 
-		if (unlikely(q->qdisc->ops->requeue(skb, q->qdisc) != NET_XMIT_SUCCESS)) {
+		if (unlikely(qdisc_requeue(skb, q->qdisc) != NET_XMIT_SUCCESS)) {
 			qdisc_tree_decrease_qlen(q->qdisc, 1);
 			sch->qstats.drops++;
 			printk(KERN_ERR "netem: %s could not requeue\n",
diff --git a/net/sched/sch_prio.c b/net/sched/sch_prio.c
index 2243aaa..800accc 100644
--- a/net/sched/sch_prio.c
+++ b/net/sched/sch_prio.c
@@ -86,7 +86,8 @@ prio_enqueue(struct sk_buff *skb, struct Qdisc *sch)
 	}
 #endif
 
-	if ((ret = qdisc->enqueue(skb, qdisc)) == NET_XMIT_SUCCESS) {
+	ret = qdisc_enqueue(skb, qdisc);
+	if (ret == NET_XMIT_SUCCESS) {
 		sch->bstats.bytes += skb->len;
 		sch->bstats.packets++;
 		sch->q.qlen++;
@@ -113,7 +114,8 @@ prio_requeue(struct sk_buff *skb, struct Qdisc* sch)
 	}
 #endif
 
-	if ((ret = qdisc->ops->requeue(skb, qdisc)) == NET_XMIT_SUCCESS) {
+	ret = qdisc_requeue(skb, qdisc);
+	if (ret == NET_XMIT_SUCCESS) {
 		sch->q.qlen++;
 		sch->qstats.requeues++;
 		return 0;
@@ -138,7 +140,7 @@ prio_dequeue(struct Qdisc* sch)
 		 */
 		if (!__netif_subqueue_stopped(sch->dev, (q->mq ? prio : 0))) {
 			qdisc = q->queues[prio];
-			skb = qdisc->dequeue(qdisc);
+			skb = qdisc_dequeue(qdisc);
 			if (skb) {
 				sch->q.qlen--;
 				return skb;
@@ -168,7 +170,7 @@ static struct sk_buff *rr_dequeue(struct Qdisc* sch)
 		if (!__netif_subqueue_stopped(sch->dev,
 					    (q->mq ? q->curband : 0))) {
 			qdisc = q->queues[q->curband];
-			skb = qdisc->dequeue(qdisc);
+			skb = qdisc_dequeue(qdisc);
 			if (skb) {
 				sch->q.qlen--;
 				q->curband++;
@@ -193,7 +195,8 @@ static unsigned int prio_drop(struct Qdisc* sch)
 
 	for (prio = q->bands-1; prio >= 0; prio--) {
 		qdisc = q->queues[prio];
-		if (qdisc->ops->drop && (len = qdisc->ops->drop(qdisc)) != 0) {
+		len = qdisc_drop(qdisc);
+		if (len > 0) {
 			sch->q.qlen--;
 			return len;
 		}
diff --git a/net/sched/sch_red.c b/net/sched/sch_red.c
index acf06d9..076f1ef 100644
--- a/net/sched/sch_red.c
+++ b/net/sched/sch_red.c
@@ -92,7 +92,7 @@ static int red_enqueue(struct sk_buff *skb, struct Qdisc* sch)
 			break;
 	}
 
-	ret = child->enqueue(skb, child);
+	ret = qdisc_enqueue(skb, child);
 	if (likely(ret == NET_XMIT_SUCCESS)) {
 		sch->bstats.bytes += skb->len;
 		sch->bstats.packets++;
@@ -117,7 +117,7 @@ static int red_requeue(struct sk_buff *skb, struct Qdisc* sch)
 	if (red_is_idling(&q->parms))
 		red_end_of_idle_period(&q->parms);
 
-	ret = child->ops->requeue(skb, child);
+	ret = qdisc_requeue(skb, child);
 	if (likely(ret == NET_XMIT_SUCCESS)) {
 		sch->qstats.requeues++;
 		sch->q.qlen++;
@@ -131,7 +131,7 @@ static struct sk_buff * red_dequeue(struct Qdisc* sch)
 	struct red_sched_data *q = qdisc_priv(sch);
 	struct Qdisc *child = q->qdisc;
 
-	skb = child->dequeue(child);
+	skb = qdisc_dequeue(child);
 	if (skb)
 		sch->q.qlen--;
 	else if (!red_is_idling(&q->parms))
@@ -146,7 +146,8 @@ static unsigned int red_drop(struct Qdisc* sch)
 	struct Qdisc *child = q->qdisc;
 	unsigned int len;
 
-	if (child->ops->drop && (len = child->ops->drop(child)) > 0) {
+	len = qdisc_drop(child);
+	if (len > 0) {
 		q->stats.other++;
 		sch->qstats.drops++;
 		sch->q.qlen--;
diff --git a/net/sched/sch_tbf.c b/net/sched/sch_tbf.c
index bd34355..5fd4dff 100644
--- a/net/sched/sch_tbf.c
+++ b/net/sched/sch_tbf.c
@@ -133,7 +133,8 @@ static int tbf_enqueue(struct sk_buff *skb, struct Qdisc* sch)
 		return NET_XMIT_DROP;
 	}
 
-	if ((ret = q->qdisc->enqueue(skb, q->qdisc)) != 0) {
+	ret = qdisc_enqueue(skb, q->qdisc);
+	if (ret != NET_XMIT_SUCCESS) {
 		sch->qstats.drops++;
 		return ret;
 	}
@@ -149,7 +150,8 @@ static int tbf_requeue(struct sk_buff *skb, struct Qdisc* sch)
 	struct tbf_sched_data *q = qdisc_priv(sch);
 	int ret;
 
-	if ((ret = q->qdisc->ops->requeue(skb, q->qdisc)) == 0) {
+	ret = qdisc_requeue(skb, q->qdisc);
+	if (ret == NET_XMIT_SUCCESS) {
 		sch->q.qlen++;
 		sch->qstats.requeues++;
 	}
@@ -162,7 +164,8 @@ static unsigned int tbf_drop(struct Qdisc* sch)
 	struct tbf_sched_data *q = qdisc_priv(sch);
 	unsigned int len = 0;
 
-	if (q->qdisc->ops->drop && (len = q->qdisc->ops->drop(q->qdisc)) != 0) {
+	len = qdisc_drop(q->qdisc);
+	if (len > 0) {
 		sch->q.qlen--;
 		sch->qstats.drops++;
 	}
@@ -174,7 +177,7 @@ static struct sk_buff *tbf_dequeue(struct Qdisc* sch)
 	struct tbf_sched_data *q = qdisc_priv(sch);
 	struct sk_buff *skb;
 
-	skb = q->qdisc->dequeue(q->qdisc);
+	skb = qdisc_dequeue(q->qdisc);
 
 	if (skb) {
 		psched_time_t now;

^ permalink raw reply related

* [RFC NET_SCHED 03/05]: Introduce child qdisc helpers
From: Patrick McHardy @ 2008-01-20 18:28 UTC (permalink / raw)
  To: netdev; +Cc: Patrick McHardy
In-Reply-To: <20080120182848.10972.46380.sendpatchset@localhost.localdomain>

commit a6d1954517202bffb14f5122756891d8c5b8e2e2
Author: Patrick McHardy <kaber@trash.net>
Date:   Wed Jan 16 12:08:18 2008 +0100

    [NET_SCHED]: Introduce child qdisc helpers
    
    Introduce a few helpers to dispatch calls to child qdiscs without
    repeating the qdisc argument every time.
    
    Signed-off-by: Patrick McHardy <kaber@trash.net>

diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h
index 3ade673..decc339 100644
--- a/include/net/sch_generic.h
+++ b/include/net/sch_generic.h
@@ -180,6 +180,26 @@ extern struct Qdisc *qdisc_create_dflt(struct net_device *dev,
 extern void tcf_destroy(struct tcf_proto *tp);
 extern void tcf_destroy_chain(struct tcf_proto *fl);
 
+static inline int qdisc_enqueue(struct sk_buff *skb, struct Qdisc *sch)
+{
+	return sch->enqueue(skb, sch);
+}
+
+static inline struct sk_buff *qdisc_dequeue(struct Qdisc *sch)
+{
+	return sch->dequeue(sch);
+}
+
+static inline int qdisc_requeue(struct sk_buff *skb, struct Qdisc *sch)
+{
+	return sch->ops->requeue(skb, sch);
+}
+
+static inline unsigned int qdisc_drop(struct Qdisc *sch)
+{
+	return sch->ops->drop ? sch->ops->drop(sch) : 0;
+}
+
 static inline int __qdisc_q_enqueue_tail(struct sk_buff *skb, struct Qdisc *sch,
 					 struct sk_buff_head *list)
 {
@@ -278,7 +298,7 @@ static inline unsigned int qdisc_q_drop(struct Qdisc *sch)
 	return __qdisc_q_drop(sch, &sch->q);
 }
 
-static inline int qdisc_drop(struct sk_buff *skb, struct Qdisc *sch)
+static inline int qdisc_drop_skb(struct sk_buff *skb, struct Qdisc *sch)
 {
 	kfree_skb(skb);
 	sch->qstats.drops++;
diff --git a/net/sched/sch_blackhole.c b/net/sched/sch_blackhole.c
index 507fb48..ac374eb 100644
--- a/net/sched/sch_blackhole.c
+++ b/net/sched/sch_blackhole.c
@@ -19,7 +19,7 @@
 
 static int blackhole_enqueue(struct sk_buff *skb, struct Qdisc *sch)
 {
-	qdisc_drop(skb, sch);
+	qdisc_drop_skb(skb, sch);
 	return NET_XMIT_SUCCESS;
 }
 
diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c
index 6afd59e..8e186e1 100644
--- a/net/sched/sch_generic.c
+++ b/net/sched/sch_generic.c
@@ -347,7 +347,7 @@ static int pfifo_fast_enqueue(struct sk_buff *skb, struct Qdisc* qdisc)
 		return __qdisc_q_enqueue_tail(skb, qdisc, list);
 	}
 
-	return qdisc_drop(skb, qdisc);
+	return qdisc_drop_skb(skb, qdisc);
 }
 
 static struct sk_buff *pfifo_fast_dequeue(struct Qdisc* qdisc)
diff --git a/net/sched/sch_gred.c b/net/sched/sch_gred.c
index d933565..ca65e7c 100644
--- a/net/sched/sch_gred.c
+++ b/net/sched/sch_gred.c
@@ -233,10 +233,10 @@ static int gred_enqueue(struct sk_buff *skb, struct Qdisc* sch)
 
 	q->stats.pdrop++;
 drop:
-	return qdisc_drop(skb, sch);
+	return qdisc_drop_skb(skb, sch);
 
 congestion_drop:
-	qdisc_drop(skb, sch);
+	qdisc_drop_skb(skb, sch);
 	return NET_XMIT_CN;
 }
 
@@ -316,7 +316,7 @@ static unsigned int gred_drop(struct Qdisc* sch)
 				red_start_of_idle_period(&q->parms);
 		}
 
-		qdisc_drop(skb, sch);
+		qdisc_drop_skb(skb, sch);
 		return len;
 	}
 
diff --git a/net/sched/sch_red.c b/net/sched/sch_red.c
index 699f83d..acf06d9 100644
--- a/net/sched/sch_red.c
+++ b/net/sched/sch_red.c
@@ -104,7 +104,7 @@ static int red_enqueue(struct sk_buff *skb, struct Qdisc* sch)
 	return ret;
 
 congestion_drop:
-	qdisc_drop(skb, sch);
+	qdisc_drop_skb(skb, sch);
 	return NET_XMIT_CN;
 }
 
diff --git a/net/sched/sch_sfq.c b/net/sched/sch_sfq.c
index c58fa6e..0b46589 100644
--- a/net/sched/sch_sfq.c
+++ b/net/sched/sch_sfq.c
@@ -257,7 +257,7 @@ sfq_enqueue(struct sk_buff *skb, struct Qdisc* sch)
 	 * i.e. drop _this_ packet.
 	 */
 	if (q->qs[x].qlen >= q->limit)
-		return qdisc_drop(skb, sch);
+		return qdisc_drop_skb(skb, sch);
 
 	sch->qstats.backlog += skb->len;
 	__skb_queue_tail(&q->qs[x], skb);

^ permalink raw reply related

* [RFC NET_SCHED 02/05]: Rename qdisc helpers for built-in queue
From: Patrick McHardy @ 2008-01-20 18:28 UTC (permalink / raw)
  To: netdev; +Cc: Patrick McHardy
In-Reply-To: <20080120182848.10972.46380.sendpatchset@localhost.localdomain>

commit c1f4198dd24ce854b7d55d0ed23a61d36d7defc9
Author: Patrick McHardy <kaber@trash.net>
Date:   Wed Jan 2 21:35:21 2008 +0100

    [NET_SCHED]: Rename qdisc helpers for built-in queue
    
    Rename all helper functions dealing with the built-in queue of
    struct Qdisc (sch->q) to qdisc_q_... to make the naming more
    consistent and avoid naming clashes with the next patch, which
    introduces a few simple helpers that should logically use those
    names.
    
    Signed-off-by: Patrick McHardy <kaber@trash.net>

diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h
index 60b4b35..3ade673 100644
--- a/include/net/sch_generic.h
+++ b/include/net/sch_generic.h
@@ -180,8 +180,8 @@ extern struct Qdisc *qdisc_create_dflt(struct net_device *dev,
 extern void tcf_destroy(struct tcf_proto *tp);
 extern void tcf_destroy_chain(struct tcf_proto *fl);
 
-static inline int __qdisc_enqueue_tail(struct sk_buff *skb, struct Qdisc *sch,
-				       struct sk_buff_head *list)
+static inline int __qdisc_q_enqueue_tail(struct sk_buff *skb, struct Qdisc *sch,
+					 struct sk_buff_head *list)
 {
 	__skb_queue_tail(list, skb);
 	sch->qstats.backlog += skb->len;
@@ -191,13 +191,13 @@ static inline int __qdisc_enqueue_tail(struct sk_buff *skb, struct Qdisc *sch,
 	return NET_XMIT_SUCCESS;
 }
 
-static inline int qdisc_enqueue_tail(struct sk_buff *skb, struct Qdisc *sch)
+static inline int qdisc_q_enqueue_tail(struct sk_buff *skb, struct Qdisc *sch)
 {
-	return __qdisc_enqueue_tail(skb, sch, &sch->q);
+	return __qdisc_q_enqueue_tail(skb, sch, &sch->q);
 }
 
-static inline struct sk_buff *__qdisc_dequeue_head(struct Qdisc *sch,
-						   struct sk_buff_head *list)
+static inline struct sk_buff *__qdisc_q_dequeue_head(struct Qdisc *sch,
+						     struct sk_buff_head *list)
 {
 	struct sk_buff *skb = __skb_dequeue(list);
 
@@ -207,13 +207,13 @@ static inline struct sk_buff *__qdisc_dequeue_head(struct Qdisc *sch,
 	return skb;
 }
 
-static inline struct sk_buff *qdisc_dequeue_head(struct Qdisc *sch)
+static inline struct sk_buff *qdisc_q_dequeue_head(struct Qdisc *sch)
 {
-	return __qdisc_dequeue_head(sch, &sch->q);
+	return __qdisc_q_dequeue_head(sch, &sch->q);
 }
 
-static inline struct sk_buff *__qdisc_dequeue_tail(struct Qdisc *sch,
-						   struct sk_buff_head *list)
+static inline struct sk_buff *__qdisc_q_dequeue_tail(struct Qdisc *sch,
+						     struct sk_buff_head *list)
 {
 	struct sk_buff *skb = __skb_dequeue_tail(list);
 
@@ -223,13 +223,13 @@ static inline struct sk_buff *__qdisc_dequeue_tail(struct Qdisc *sch,
 	return skb;
 }
 
-static inline struct sk_buff *qdisc_dequeue_tail(struct Qdisc *sch)
+static inline struct sk_buff *qdisc_q_dequeue_tail(struct Qdisc *sch)
 {
-	return __qdisc_dequeue_tail(sch, &sch->q);
+	return __qdisc_q_dequeue_tail(sch, &sch->q);
 }
 
-static inline int __qdisc_requeue(struct sk_buff *skb, struct Qdisc *sch,
-				  struct sk_buff_head *list)
+static inline int __qdisc_q_requeue(struct sk_buff *skb, struct Qdisc *sch,
+				    struct sk_buff_head *list)
 {
 	__skb_queue_head(list, skb);
 	sch->qstats.backlog += skb->len;
@@ -238,13 +238,13 @@ static inline int __qdisc_requeue(struct sk_buff *skb, struct Qdisc *sch,
 	return NET_XMIT_SUCCESS;
 }
 
-static inline int qdisc_requeue(struct sk_buff *skb, struct Qdisc *sch)
+static inline int qdisc_q_requeue(struct sk_buff *skb, struct Qdisc *sch)
 {
-	return __qdisc_requeue(skb, sch, &sch->q);
+	return __qdisc_q_requeue(skb, sch, &sch->q);
 }
 
-static inline void __qdisc_reset_queue(struct Qdisc *sch,
-				       struct sk_buff_head *list)
+static inline void __qdisc_q_reset(struct Qdisc *sch,
+				   struct sk_buff_head *list)
 {
 	/*
 	 * We do not know the backlog in bytes of this list, it
@@ -253,16 +253,16 @@ static inline void __qdisc_reset_queue(struct Qdisc *sch,
 	skb_queue_purge(list);
 }
 
-static inline void qdisc_reset_queue(struct Qdisc *sch)
+static inline void qdisc_q_reset(struct Qdisc *sch)
 {
-	__qdisc_reset_queue(sch, &sch->q);
+	__qdisc_q_reset(sch, &sch->q);
 	sch->qstats.backlog = 0;
 }
 
-static inline unsigned int __qdisc_queue_drop(struct Qdisc *sch,
-					      struct sk_buff_head *list)
+static inline unsigned int __qdisc_q_drop(struct Qdisc *sch,
+					  struct sk_buff_head *list)
 {
-	struct sk_buff *skb = __qdisc_dequeue_tail(sch, list);
+	struct sk_buff *skb = __qdisc_q_dequeue_tail(sch, list);
 
 	if (likely(skb != NULL)) {
 		unsigned int len = skb->len;
@@ -273,9 +273,9 @@ static inline unsigned int __qdisc_queue_drop(struct Qdisc *sch,
 	return 0;
 }
 
-static inline unsigned int qdisc_queue_drop(struct Qdisc *sch)
+static inline unsigned int qdisc_q_drop(struct Qdisc *sch)
 {
-	return __qdisc_queue_drop(sch, &sch->q);
+	return __qdisc_q_drop(sch, &sch->q);
 }
 
 static inline int qdisc_drop(struct sk_buff *skb, struct Qdisc *sch)
diff --git a/net/sched/sch_fifo.c b/net/sched/sch_fifo.c
index f9bf58b..e4a4dc2 100644
--- a/net/sched/sch_fifo.c
+++ b/net/sched/sch_fifo.c
@@ -28,7 +28,7 @@ static int bfifo_enqueue(struct sk_buff *skb, struct Qdisc* sch)
 	struct fifo_sched_data *q = qdisc_priv(sch);
 
 	if (likely(sch->qstats.backlog + skb->len <= q->limit))
-		return qdisc_enqueue_tail(skb, sch);
+		return qdisc_q_enqueue_tail(skb, sch);
 
 	return qdisc_reshape_fail(skb, sch);
 }
@@ -38,7 +38,7 @@ static int pfifo_enqueue(struct sk_buff *skb, struct Qdisc* sch)
 	struct fifo_sched_data *q = qdisc_priv(sch);
 
 	if (likely(skb_queue_len(&sch->q) < q->limit))
-		return qdisc_enqueue_tail(skb, sch);
+		return qdisc_q_enqueue_tail(skb, sch);
 
 	return qdisc_reshape_fail(skb, sch);
 }
@@ -82,11 +82,11 @@ struct Qdisc_ops pfifo_qdisc_ops __read_mostly = {
 	.id		=	"pfifo",
 	.priv_size	=	sizeof(struct fifo_sched_data),
 	.enqueue	=	pfifo_enqueue,
-	.dequeue	=	qdisc_dequeue_head,
-	.requeue	=	qdisc_requeue,
-	.drop		=	qdisc_queue_drop,
+	.dequeue	=	qdisc_q_dequeue_head,
+	.requeue	=	qdisc_q_requeue,
+	.drop		=	qdisc_q_drop,
 	.init		=	fifo_init,
-	.reset		=	qdisc_reset_queue,
+	.reset		=	qdisc_q_reset,
 	.change		=	fifo_init,
 	.dump		=	fifo_dump,
 	.owner		=	THIS_MODULE,
@@ -96,11 +96,11 @@ struct Qdisc_ops bfifo_qdisc_ops __read_mostly = {
 	.id		=	"bfifo",
 	.priv_size	=	sizeof(struct fifo_sched_data),
 	.enqueue	=	bfifo_enqueue,
-	.dequeue	=	qdisc_dequeue_head,
-	.requeue	=	qdisc_requeue,
-	.drop		=	qdisc_queue_drop,
+	.dequeue	=	qdisc_q_dequeue_head,
+	.requeue	=	qdisc_q_requeue,
+	.drop		=	qdisc_q_drop,
 	.init		=	fifo_init,
-	.reset		=	qdisc_reset_queue,
+	.reset		=	qdisc_q_reset,
 	.change		=	fifo_init,
 	.dump		=	fifo_dump,
 	.owner		=	THIS_MODULE,
diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c
index 9be2f15..6afd59e 100644
--- a/net/sched/sch_generic.c
+++ b/net/sched/sch_generic.c
@@ -344,7 +344,7 @@ static int pfifo_fast_enqueue(struct sk_buff *skb, struct Qdisc* qdisc)
 
 	if (skb_queue_len(list) < qdisc->dev->tx_queue_len) {
 		qdisc->q.qlen++;
-		return __qdisc_enqueue_tail(skb, qdisc, list);
+		return __qdisc_q_enqueue_tail(skb, qdisc, list);
 	}
 
 	return qdisc_drop(skb, qdisc);
@@ -358,7 +358,7 @@ static struct sk_buff *pfifo_fast_dequeue(struct Qdisc* qdisc)
 	for (prio = 0; prio < PFIFO_FAST_BANDS; prio++) {
 		if (!skb_queue_empty(list + prio)) {
 			qdisc->q.qlen--;
-			return __qdisc_dequeue_head(qdisc, list + prio);
+			return __qdisc_q_dequeue_head(qdisc, list + prio);
 		}
 	}
 
@@ -368,7 +368,7 @@ static struct sk_buff *pfifo_fast_dequeue(struct Qdisc* qdisc)
 static int pfifo_fast_requeue(struct sk_buff *skb, struct Qdisc* qdisc)
 {
 	qdisc->q.qlen++;
-	return __qdisc_requeue(skb, qdisc, prio2list(skb, qdisc));
+	return __qdisc_q_requeue(skb, qdisc, prio2list(skb, qdisc));
 }
 
 static void pfifo_fast_reset(struct Qdisc* qdisc)
@@ -377,7 +377,7 @@ static void pfifo_fast_reset(struct Qdisc* qdisc)
 	struct sk_buff_head *list = qdisc_priv(qdisc);
 
 	for (prio = 0; prio < PFIFO_FAST_BANDS; prio++)
-		__qdisc_reset_queue(qdisc, list + prio);
+		__qdisc_q_reset(qdisc, list + prio);
 
 	qdisc->qstats.backlog = 0;
 	qdisc->q.qlen = 0;
diff --git a/net/sched/sch_gred.c b/net/sched/sch_gred.c
index e2bcd66..d933565 100644
--- a/net/sched/sch_gred.c
+++ b/net/sched/sch_gred.c
@@ -165,7 +165,7 @@ static int gred_enqueue(struct sk_buff *skb, struct Qdisc* sch)
 			 * allows for DP flows to be left untouched.
 			 */
 			if (skb_queue_len(&sch->q) < sch->dev->tx_queue_len)
-				return qdisc_enqueue_tail(skb, sch);
+				return qdisc_q_enqueue_tail(skb, sch);
 			else
 				goto drop;
 		}
@@ -228,7 +228,7 @@ static int gred_enqueue(struct sk_buff *skb, struct Qdisc* sch)
 
 	if (q->backlog + skb->len <= q->limit) {
 		q->backlog += skb->len;
-		return qdisc_enqueue_tail(skb, sch);
+		return qdisc_q_enqueue_tail(skb, sch);
 	}
 
 	q->stats.pdrop++;
@@ -257,7 +257,7 @@ static int gred_requeue(struct sk_buff *skb, struct Qdisc* sch)
 		q->backlog += skb->len;
 	}
 
-	return qdisc_requeue(skb, sch);
+	return qdisc_q_requeue(skb, sch);
 }
 
 static struct sk_buff *gred_dequeue(struct Qdisc* sch)
@@ -265,7 +265,7 @@ static struct sk_buff *gred_dequeue(struct Qdisc* sch)
 	struct sk_buff *skb;
 	struct gred_sched *t = qdisc_priv(sch);
 
-	skb = qdisc_dequeue_head(sch);
+	skb = qdisc_q_dequeue_head(sch);
 
 	if (skb) {
 		struct gred_sched_data *q;
@@ -297,7 +297,7 @@ static unsigned int gred_drop(struct Qdisc* sch)
 	struct sk_buff *skb;
 	struct gred_sched *t = qdisc_priv(sch);
 
-	skb = qdisc_dequeue_tail(sch);
+	skb = qdisc_q_dequeue_tail(sch);
 	if (skb) {
 		unsigned int len = skb->len;
 		struct gred_sched_data *q;
@@ -332,7 +332,7 @@ static void gred_reset(struct Qdisc* sch)
 	int i;
 	struct gred_sched *t = qdisc_priv(sch);
 
-	qdisc_reset_queue(sch);
+	qdisc_q_reset(sch);
 
 	for (i = 0; i < t->DPs; i++) {
 		struct gred_sched_data *q = t->tab[i];
diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c
index 5342a2f..3ec4a81 100644
--- a/net/sched/sch_netem.c
+++ b/net/sched/sch_netem.c
@@ -470,7 +470,7 @@ static int tfifo_enqueue(struct sk_buff *nskb, struct Qdisc *sch)
 		/* Optimize for add at tail */
 		if (likely(skb_queue_empty(list) || tnext >= q->oldest)) {
 			q->oldest = tnext;
-			return qdisc_enqueue_tail(nskb, sch);
+			return qdisc_q_enqueue_tail(nskb, sch);
 		}
 
 		skb_queue_reverse_walk(list, skb) {
@@ -526,11 +526,11 @@ static struct Qdisc_ops tfifo_qdisc_ops __read_mostly = {
 	.id		=	"tfifo",
 	.priv_size	=	sizeof(struct fifo_sched_data),
 	.enqueue	=	tfifo_enqueue,
-	.dequeue	=	qdisc_dequeue_head,
-	.requeue	=	qdisc_requeue,
-	.drop		=	qdisc_queue_drop,
+	.dequeue	=	qdisc_q_dequeue_head,
+	.requeue	=	qdisc_q_requeue,
+	.drop		=	qdisc_q_drop,
 	.init		=	tfifo_init,
-	.reset		=	qdisc_reset_queue,
+	.reset		=	qdisc_q_reset,
 	.change		=	tfifo_init,
 	.dump		=	tfifo_dump,
 };

^ permalink raw reply related

* [RFC NET_SCHED 01/05]: Consolidate default fifo setup
From: Patrick McHardy @ 2008-01-20 18:28 UTC (permalink / raw)
  To: netdev; +Cc: Patrick McHardy
In-Reply-To: <20080120182848.10972.46380.sendpatchset@localhost.localdomain>

commit e56c933715900be7c6ad30bd07d342d31c457112
Author: Patrick McHardy <kaber@trash.net>
Date:   Wed Jan 2 21:35:19 2008 +0100

    [NET_SCHED]: Consolidate default fifo setup
    
    Signed-off-by: Patrick McHardy <kaber@trash.net>

diff --git a/include/net/pkt_sched.h b/include/net/pkt_sched.h
index ab61809..9d06d2d 100644
--- a/include/net/pkt_sched.h
+++ b/include/net/pkt_sched.h
@@ -72,6 +72,10 @@ extern void qdisc_watchdog_cancel(struct qdisc_watchdog *wd);
 extern struct Qdisc_ops pfifo_qdisc_ops;
 extern struct Qdisc_ops bfifo_qdisc_ops;
 
+extern int fifo_set_limit(struct Qdisc *q, unsigned int limit);
+extern struct Qdisc *fifo_create_dflt(struct Qdisc *sch, struct Qdisc_ops *ops,
+				      unsigned int limit);
+
 extern int register_qdisc(struct Qdisc_ops *qops);
 extern int unregister_qdisc(struct Qdisc_ops *qops);
 extern struct Qdisc *qdisc_lookup(struct net_device *dev, u32 handle);
diff --git a/net/sched/sch_fifo.c b/net/sched/sch_fifo.c
index d71dbfc..f9bf58b 100644
--- a/net/sched/sch_fifo.c
+++ b/net/sched/sch_fifo.c
@@ -108,3 +108,45 @@ struct Qdisc_ops bfifo_qdisc_ops __read_mostly = {
 
 EXPORT_SYMBOL(bfifo_qdisc_ops);
 EXPORT_SYMBOL(pfifo_qdisc_ops);
+
+/* Pass size change message down to embedded FIFO */
+int fifo_set_limit(struct Qdisc *q, unsigned int limit)
+{
+	struct rtattr *rta;
+	int ret = -ENOMEM;
+
+	/* Hack to avoid sending change message to non-FIFO */
+	if (strncmp(q->ops->id + 1, "fifo", 4) != 0)
+		return 0;
+
+	rta = kmalloc(RTA_LENGTH(sizeof(struct tc_fifo_qopt)), GFP_KERNEL);
+	if (rta) {
+		rta->rta_type = RTM_NEWQDISC;
+		rta->rta_len = RTA_LENGTH(sizeof(struct tc_fifo_qopt));
+		((struct tc_fifo_qopt *)RTA_DATA(rta))->limit = limit;
+
+		ret = q->ops->change(q, rta);
+		kfree(rta);
+	}
+	return ret;
+}
+EXPORT_SYMBOL(fifo_set_limit);
+
+struct Qdisc *fifo_create_dflt(struct Qdisc *sch, struct Qdisc_ops *ops,
+			       unsigned int limit)
+{
+	struct Qdisc *q;
+	int err = -ENOMEM;
+
+	q = qdisc_create_dflt(sch->dev, ops, TC_H_MAKE(sch->handle, 1));
+	if (q) {
+		err = fifo_set_limit(q, limit);
+		if (err < 0) {
+			qdisc_destroy(q);
+			q = NULL;
+		}
+	}
+
+	return q ? : ERR_PTR(err);
+}
+EXPORT_SYMBOL(fifo_create_dflt);
diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c
index 6c344ad..5342a2f 100644
--- a/net/sched/sch_netem.c
+++ b/net/sched/sch_netem.c
@@ -310,28 +310,6 @@ static void netem_reset(struct Qdisc *sch)
 	qdisc_watchdog_cancel(&q->watchdog);
 }
 
-/* Pass size change message down to embedded FIFO */
-static int set_fifo_limit(struct Qdisc *q, int limit)
-{
-	struct rtattr *rta;
-	int ret = -ENOMEM;
-
-	/* Hack to avoid sending change message to non-FIFO */
-	if (strncmp(q->ops->id + 1, "fifo", 4) != 0)
-		return 0;
-
-	rta = kmalloc(RTA_LENGTH(sizeof(struct tc_fifo_qopt)), GFP_KERNEL);
-	if (rta) {
-		rta->rta_type = RTM_NEWQDISC;
-		rta->rta_len = RTA_LENGTH(sizeof(struct tc_fifo_qopt));
-		((struct tc_fifo_qopt *)RTA_DATA(rta))->limit = limit;
-
-		ret = q->ops->change(q, rta);
-		kfree(rta);
-	}
-	return ret;
-}
-
 /*
  * Distribution data is a variable size payload containing
  * signed 16 bit values.
@@ -414,7 +392,7 @@ static int netem_change(struct Qdisc *sch, struct rtattr *opt)
 		return -EINVAL;
 
 	qopt = RTA_DATA(opt);
-	ret = set_fifo_limit(q->qdisc, qopt->limit);
+	ret = fifo_set_limit(q->qdisc, qopt->limit);
 	if (ret) {
 		pr_debug("netem: can't set fifo limit\n");
 		return ret;
diff --git a/net/sched/sch_red.c b/net/sched/sch_red.c
index f1e9647..699f83d 100644
--- a/net/sched/sch_red.c
+++ b/net/sched/sch_red.c
@@ -174,33 +174,6 @@ static void red_destroy(struct Qdisc *sch)
 	qdisc_destroy(q->qdisc);
 }
 
-static struct Qdisc *red_create_dflt(struct Qdisc *sch, u32 limit)
-{
-	struct Qdisc *q;
-	struct rtattr *rta;
-	int ret;
-
-	q = qdisc_create_dflt(sch->dev, &bfifo_qdisc_ops,
-			      TC_H_MAKE(sch->handle, 1));
-	if (q) {
-		rta = kmalloc(RTA_LENGTH(sizeof(struct tc_fifo_qopt)),
-			      GFP_KERNEL);
-		if (rta) {
-			rta->rta_type = RTM_NEWQDISC;
-			rta->rta_len = RTA_LENGTH(sizeof(struct tc_fifo_qopt));
-			((struct tc_fifo_qopt *)RTA_DATA(rta))->limit = limit;
-
-			ret = q->ops->change(q, rta);
-			kfree(rta);
-
-			if (ret == 0)
-				return q;
-		}
-		qdisc_destroy(q);
-	}
-	return NULL;
-}
-
 static int red_change(struct Qdisc *sch, struct rtattr *opt)
 {
 	struct red_sched_data *q = qdisc_priv(sch);
@@ -220,9 +193,9 @@ static int red_change(struct Qdisc *sch, struct rtattr *opt)
 	ctl = RTA_DATA(tb[TCA_RED_PARMS-1]);
 
 	if (ctl->limit > 0) {
-		child = red_create_dflt(sch, ctl->limit);
-		if (child == NULL)
-			return -ENOMEM;
+		child = fifo_create_dflt(sch, &bfifo_qdisc_ops, ctl->limit);
+		if (IS_ERR(child))
+			return PTR_ERR(child);
 	}
 
 	sch_tree_lock(sch);
diff --git a/net/sched/sch_tbf.c b/net/sched/sch_tbf.c
index d88fea9..bd34355 100644
--- a/net/sched/sch_tbf.c
+++ b/net/sched/sch_tbf.c
@@ -242,33 +242,6 @@ static void tbf_reset(struct Qdisc* sch)
 	qdisc_watchdog_cancel(&q->watchdog);
 }
 
-static struct Qdisc *tbf_create_dflt_qdisc(struct Qdisc *sch, u32 limit)
-{
-	struct Qdisc *q;
-	struct rtattr *rta;
-	int ret;
-
-	q = qdisc_create_dflt(sch->dev, &bfifo_qdisc_ops,
-			      TC_H_MAKE(sch->handle, 1));
-	if (q) {
-		rta = kmalloc(RTA_LENGTH(sizeof(struct tc_fifo_qopt)), GFP_KERNEL);
-		if (rta) {
-			rta->rta_type = RTM_NEWQDISC;
-			rta->rta_len = RTA_LENGTH(sizeof(struct tc_fifo_qopt));
-			((struct tc_fifo_qopt *)RTA_DATA(rta))->limit = limit;
-
-			ret = q->ops->change(q, rta);
-			kfree(rta);
-
-			if (ret == 0)
-				return q;
-		}
-		qdisc_destroy(q);
-	}
-
-	return NULL;
-}
-
 static int tbf_change(struct Qdisc* sch, struct rtattr *opt)
 {
 	int err = -EINVAL;
@@ -312,8 +285,9 @@ static int tbf_change(struct Qdisc* sch, struct rtattr *opt)
 		goto done;
 
 	if (qopt->limit > 0) {
-		if ((child = tbf_create_dflt_qdisc(sch, qopt->limit)) == NULL)
-			goto done;
+		child = fifo_create_dflt(sch, &bfifo_qdisc_ops, qopt->limit);
+		if (IS_ERR(child))
+			return PTR_ERR(child);
 	}
 
 	sch_tree_lock(sch);

^ permalink raw reply related

* [RFC NET_SCHED 00/05]: Pseudo-classful qdisc consolidation
From: Patrick McHardy @ 2008-01-20 18:28 UTC (permalink / raw)
  To: netdev; +Cc: Patrick McHardy

These patches contain some preparatory cleanups and consolidate the
Qdisc_class_ops for pseudo-classful qdiscs. The main reason for
RFC is that the naming is not particular appealing (both qdisc_q_...
and sch_pseudo_classful), suggestions for better names are welcome.


 include/net/pkt_sched.h         |    4 +
 include/net/sch_generic.h       |   78 +++++++++++++-------
 net/core/dev.c                  |    4 +-
 net/sched/Kconfig               |    6 ++
 net/sched/Makefile              |    1 +
 net/sched/sch_atm.c             |   17 +++--
 net/sched/sch_blackhole.c       |    2 +-
 net/sched/sch_cbq.c             |   18 +++--
 net/sched/sch_dsmark.c          |   11 +--
 net/sched/sch_fifo.c            |   62 +++++++++++++---
 net/sched/sch_generic.c         |   12 ++--
 net/sched/sch_gred.c            |   18 ++--
 net/sched/sch_hfsc.c            |   12 ++--
 net/sched/sch_htb.c             |   11 ++-
 net/sched/sch_netem.c           |  157 +++++++--------------------------------
 net/sched/sch_prio.c            |   13 ++-
 net/sched/sch_pseudo_classful.c |  101 +++++++++++++++++++++++++
 net/sched/sch_red.c             |  152 ++++++--------------------------------
 net/sched/sch_sfq.c             |    2 +-
 net/sched/sch_tbf.c             |  150 +++++--------------------------------
 20 files changed, 347 insertions(+), 484 deletions(-)
 create mode 100644 net/sched/sch_pseudo_classful.c

Patrick McHardy (5):
      [NET_SCHED]: Consolidate default fifo setup
      [NET_SCHED]: Rename qdisc helpers for built-in queue
      [NET_SCHED]: Introduce child qdisc helpers
      [NET_SCHED]: Use qdisc helpers
      [NET_SCHED]: Consolidate class ops for pseudo classful qdisc

^ permalink raw reply

* [PATCH] ipv6: addrconf sparse warnings
From: Stephen Hemminger @ 2008-01-20 18:01 UTC (permalink / raw)
  To: David Miller,
	YOSHIFUJI Hideaki / 吉藤英明; +Cc: netdev

Get rid of a couple of sparse warnings in IPV6 addrconf code.

Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>

--- a/net/ipv6/addrconf.c	2008-01-20 09:38:06.000000000 -0800
+++ b/net/ipv6/addrconf.c	2008-01-20 09:57:40.000000000 -0800
@@ -1900,7 +1900,7 @@ int addrconf_set_dstaddr(void __user *ar
 		p.iph.ihl = 5;
 		p.iph.protocol = IPPROTO_IPV6;
 		p.iph.ttl = 64;
-		ifr.ifr_ifru.ifru_data = (void __user *)&p;
+		ifr.ifr_ifru.ifru_data = (__force void __user *)&p;
 
 		oldfs = get_fs(); set_fs(KERNEL_DS);
 		err = dev->do_ioctl(dev, &ifr, SIOCADDTUNNEL);
@@ -2799,6 +2799,7 @@ static struct inet6_ifaddr *if6_get_idx(
 }
 
 static void *if6_seq_start(struct seq_file *seq, loff_t *pos)
+	__acquires(addrconf_hash_lock)
 {
 	read_lock_bh(&addrconf_hash_lock);
 	return if6_get_idx(seq, *pos);
@@ -2814,6 +2815,7 @@ static void *if6_seq_next(struct seq_fil
 }
 
 static void if6_seq_stop(struct seq_file *seq, void *v)
+	__releases(addrconf_hash_lock)
 {
 	read_unlock_bh(&addrconf_hash_lock);
 }

^ permalink raw reply

* [NET]: rtnl_link: fix use-after-free
From: Patrick McHardy @ 2008-01-20 17:21 UTC (permalink / raw)
  To: David S. Miller; +Cc: Pavel Emelianov, Linux Netdev List

[-- Attachment #1: Type: text/plain, Size: 0 bytes --]



[-- Attachment #2: x --]
[-- Type: text/plain, Size: 2248 bytes --]

commit 6e470bd53fb50632fe1878bb74bb8531a21b6731
Author: Patrick McHardy <kaber@trash.net>
Date:   Sun Jan 20 18:19:15 2008 +0100

    [NET]: rtnl_link: fix use-after-free
    
    When unregistering the rtnl_link_ops, all existing devices using
    the ops are destroyed. With nested devices this may lead to a
    use-after-free despite the use of for_each_netdev_safe() in case
    the upper device is next in the device list and is destroyed
    by the NETDEV_UNREGISTER notifier.
    
    The easy fix is to restart scanning the device list after removing
    a device. Alternatively we could add new devices to the front of
    the list to avoid having dependant devices follow the device they
    depend on. A third option would be to only restart scanning if
    dev->iflink of the next device matches dev->ifindex of the current
    one. For now this seems like the safest solution.
    
    With this patch, the veth rtnl_link_ops unregistration can use
    rtnl_link_unregister() directly since it now also handles destruction
    of multiple devices at once.
    
    Signed-off-by: Patrick McHardy <kaber@trash.net>

diff --git a/drivers/net/veth.c b/drivers/net/veth.c
index 43af9e9..3f67a29 100644
--- a/drivers/net/veth.c
+++ b/drivers/net/veth.c
@@ -459,19 +459,7 @@ static __init int veth_init(void)
 
 static __exit void veth_exit(void)
 {
-	struct veth_priv *priv, *next;
-
-	rtnl_lock();
-	/*
-	 * cannot trust __rtnl_link_unregister() to unregister all
-	 * devices, as each ->dellink call will remove two devices
-	 * from the list at once.
-	 */
-	list_for_each_entry_safe(priv, next, &veth_list, list)
-		veth_dellink(priv->dev);
-
-	__rtnl_link_unregister(&veth_link_ops);
-	rtnl_unlock();
+	rtnl_link_unregister(&veth_link_ops);
 }
 
 module_init(veth_init);
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index e1ba26f..fed95a3 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -308,9 +308,12 @@ void __rtnl_link_unregister(struct rtnl_link_ops *ops)
 	struct net *net;
 
 	for_each_net(net) {
+restart:
 		for_each_netdev_safe(net, dev, n) {
-			if (dev->rtnl_link_ops == ops)
+			if (dev->rtnl_link_ops == ops) {
 				ops->dellink(dev);
+				goto restart;
+			}
 		}
 	}
 	list_del(&ops->list);

^ permalink raw reply related

* [VLAN 18/18]: Move protocol determination to seperate function
From: Patrick McHardy @ 2008-01-20 17:11 UTC (permalink / raw)
  To: davem; +Cc: netdev, Patrick McHardy
In-Reply-To: <20080120171117.7980.67072.sendpatchset@localhost.localdomain>

[VLAN]: Move protocol determination to seperate function

I think, that we can make this code flow easier to understand
by introducing the vlan_set_encap_proto() function (I hope the
name is good) to setup the skb proto and merge the paths calling
netif_rx() together.

[Patrick: Modified to apply on top of my previous patches]

Signed-off-by: Pavel Emelyanov <xemul@openvz.org>
Signed-off-by: Patrick McHardy <kaber@trash.net>

---
commit 0e185e8a940c2780362ff815cfe638e7d1269972
tree 62b8568718057b7a12375c34af01d95bae463240
parent c314238cb2135e4bb812487ed47652a5e2e4b748
author Pavel Emelyanov <xemul@openvz.org> Sun, 20 Jan 2008 17:37:32 +0100
committer Patrick McHardy <kaber@trash.net> Sun, 20 Jan 2008 17:37:32 +0100

 net/8021q/vlan_dev.c |   63 ++++++++++++++++++++++++++++----------------------
 1 files changed, 35 insertions(+), 28 deletions(-)

diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c
index 57799af..8059fa4 100644
--- a/net/8021q/vlan_dev.c
+++ b/net/8021q/vlan_dev.c
@@ -89,6 +89,40 @@ static inline struct sk_buff *vlan_check_reorder_header(struct sk_buff *skb)
 	return skb;
 }
 
+static inline void vlan_set_encap_proto(struct sk_buff *skb,
+		struct vlan_hdr *vhdr)
+{
+	__be16 proto;
+	unsigned char *rawp;
+
+	/*
+	 * Was a VLAN packet, grab the encapsulated protocol, which the layer
+	 * three protocols care about.
+	 */
+
+	proto = vhdr->h_vlan_encapsulated_proto;
+	if (ntohs(proto) >= 1536) {
+		skb->protocol = proto;
+		return;
+	}
+
+	rawp = skb->data;
+	if (*(unsigned short *)rawp == 0xFFFF)
+		/*
+		 * This is a magic hack to spot IPX packets. Older Novell
+		 * breaks the protocol design and runs IPX over 802.3 without
+		 * an 802.2 LLC layer. We look for FFFF which isn't a used
+		 * 802.2 SSAP/DSAP. This won't work for fault tolerant netware
+		 * but does for the rest.
+		 */
+		skb->protocol = htons(ETH_P_802_3);
+	else
+		/*
+		 * Real 802.2 LLC
+		 */
+		skb->protocol = htons(ETH_P_802_2);
+}
+
 /*
  *	Determine the packet's protocol ID. The rule here is that we
  *	assume 802.3 if the type field is short enough to be a length.
@@ -114,12 +148,10 @@ static inline struct sk_buff *vlan_check_reorder_header(struct sk_buff *skb)
 int vlan_skb_recv(struct sk_buff *skb, struct net_device *dev,
 		  struct packet_type *ptype, struct net_device *orig_dev)
 {
-	unsigned char *rawp;
 	struct vlan_hdr *vhdr;
 	unsigned short vid;
 	struct net_device_stats *stats;
 	unsigned short vlan_TCI;
-	__be16 proto;
 
 	if (dev->nd_net != &init_net)
 		goto err_free;
@@ -179,33 +211,8 @@ int vlan_skb_recv(struct sk_buff *skb, struct net_device *dev,
 		break;
 	}
 
-	/*  Was a VLAN packet, grab the encapsulated protocol, which the layer
-	 * three protocols care about.
-	 */
-	proto = vhdr->h_vlan_encapsulated_proto;
-	if (ntohs(proto) >= 1536) {
-		skb->protocol = proto;
-		goto recv;
-	}
-
-	/*
-	 * This is a magic hack to spot IPX packets. Older Novell breaks
-	 * the protocol design and runs IPX over 802.3 without an 802.2 LLC
-	 * layer. We look for FFFF which isn't a used 802.2 SSAP/DSAP. This
-	 * won't work for fault tolerant netware but does for the rest.
-	 */
-	rawp = skb->data;
-	if (*(unsigned short *)rawp == 0xFFFF) {
-		skb->protocol = htons(ETH_P_802_3);
-		goto recv;
-	}
-
-	/*
-	 *	Real 802.2 LLC
-	 */
-	skb->protocol = htons(ETH_P_802_2);
+	vlan_set_encap_proto(skb, vhdr);
 
-recv:
 	skb = vlan_check_reorder_header(skb);
 	if (!skb) {
 		stats->rx_errors++;

^ permalink raw reply related

* [VLAN 17/18]: Clean up vlan_skb_recv()
From: Patrick McHardy @ 2008-01-20 17:11 UTC (permalink / raw)
  To: davem; +Cc: netdev, Patrick McHardy
In-Reply-To: <20080120171117.7980.67072.sendpatchset@localhost.localdomain>

[VLAN]: Clean up vlan_skb_recv()

- remove three instances of identical code
- remove unnecessary NULL initialization
- remove obvious and unnecessary comments

Signed-off-by: Patrick McHardy <kaber@trash.net>

---
commit c314238cb2135e4bb812487ed47652a5e2e4b748
tree 42969440a4ea33d5addcbbce4758ed5f377b4a7e
parent e7e221b07c3a3f77df617232ea0f76094edc1071
author Patrick McHardy <kaber@trash.net> Sun, 20 Jan 2008 17:37:32 +0100
committer Patrick McHardy <kaber@trash.net> Sun, 20 Jan 2008 17:37:32 +0100

 net/8021q/vlan_dev.c |  113 +++++++++++---------------------------------------
 1 files changed, 24 insertions(+), 89 deletions(-)

diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c
index e19e491..57799af 100644
--- a/net/8021q/vlan_dev.c
+++ b/net/8021q/vlan_dev.c
@@ -114,77 +114,49 @@ static inline struct sk_buff *vlan_check_reorder_header(struct sk_buff *skb)
 int vlan_skb_recv(struct sk_buff *skb, struct net_device *dev,
 		  struct packet_type *ptype, struct net_device *orig_dev)
 {
-	unsigned char *rawp = NULL;
+	unsigned char *rawp;
 	struct vlan_hdr *vhdr;
 	unsigned short vid;
 	struct net_device_stats *stats;
 	unsigned short vlan_TCI;
 	__be16 proto;
 
-	if (dev->nd_net != &init_net) {
-		kfree_skb(skb);
-		return -1;
-	}
+	if (dev->nd_net != &init_net)
+		goto err_free;
 
 	skb = skb_share_check(skb, GFP_ATOMIC);
 	if (skb == NULL)
-		return -1;
-
-	if (unlikely(!pskb_may_pull(skb, VLAN_HLEN))) {
-		kfree_skb(skb);
-		return -1;
-	}
+		goto err_free;
 
-	vhdr = (struct vlan_hdr *)(skb->data);
+	if (unlikely(!pskb_may_pull(skb, VLAN_HLEN)))
+		goto err_free;
 
-	/* vlan_TCI = ntohs(get_unaligned(&vhdr->h_vlan_TCI)); */
+	vhdr = (struct vlan_hdr *)skb->data;
 	vlan_TCI = ntohs(vhdr->h_vlan_TCI);
-
 	vid = (vlan_TCI & VLAN_VID_MASK);
 
-	/* Ok, we will find the correct VLAN device, strip the header,
-	 * and then go on as usual.
-	 */
-
-	/* We have 12 bits of vlan ID.
-	 *
-	 * We must not drop allow preempt until we hold a
-	 * reference to the device (netif_rx does that) or we
-	 * fail.
-	 */
-
 	rcu_read_lock();
 	skb->dev = __find_vlan_dev(dev, vid);
 	if (!skb->dev) {
-		rcu_read_unlock();
 		pr_debug("%s: ERROR: No net_device for VID: %u on dev: %s\n",
 			 __FUNCTION__, (unsigned int)vid, dev->name);
-		kfree_skb(skb);
-		return -1;
+		goto err_unlock;
 	}
 
 	skb->dev->last_rx = jiffies;
 
-	/* Bump the rx counters for the VLAN device. */
 	stats = &skb->dev->stats;
 	stats->rx_packets++;
 	stats->rx_bytes += skb->len;
 
-	/* Take off the VLAN header (4 bytes currently) */
 	skb_pull_rcsum(skb, VLAN_HLEN);
 
-	/*
-	 * Deal with ingress priority mapping.
-	 */
 	skb->priority = vlan_get_ingress_priority(skb->dev,
 						  ntohs(vhdr->h_vlan_TCI));
 
 	pr_debug("%s: priority: %u for TCI: %hu\n",
 		 __FUNCTION__, skb->priority, ntohs(vhdr->h_vlan_TCI));
 
-	/* The ethernet driver already did the pkt_type calculations
-	 * for us...
-	 */
 	switch (skb->pkt_type) {
 	case PACKET_BROADCAST: /* Yeah, stats collect these together.. */
 		/* stats->broadcast ++; // no such counter :-( */
@@ -201,7 +173,6 @@ int vlan_skb_recv(struct sk_buff *skb, struct net_device *dev,
 		 */
 		if (!compare_ether_addr(eth_hdr(skb)->h_dest,
 					skb->dev->dev_addr))
-			/* It is for our (changed) MAC-address! */
 			skb->pkt_type = PACKET_HOST;
 		break;
 	default:
@@ -211,81 +182,45 @@ int vlan_skb_recv(struct sk_buff *skb, struct net_device *dev,
 	/*  Was a VLAN packet, grab the encapsulated protocol, which the layer
 	 * three protocols care about.
 	 */
-	/* proto = get_unaligned(&vhdr->h_vlan_encapsulated_proto); */
 	proto = vhdr->h_vlan_encapsulated_proto;
-
-	skb->protocol = proto;
 	if (ntohs(proto) >= 1536) {
-		/* place it back on the queue to be handled by
-		 * true layer 3 protocols.
-		 */
-
-		/* See if we are configured to re-write the VLAN header
-		 * to make it look like ethernet...
-		 */
-		skb = vlan_check_reorder_header(skb);
-
-		/* Can be null if skb-clone fails when re-ordering */
-		if (skb) {
-			netif_rx(skb);
-		} else {
-			/* TODO:  Add a more specific counter here. */
-			stats->rx_errors++;
-		}
-		rcu_read_unlock();
-		return 0;
+		skb->protocol = proto;
+		goto recv;
 	}
 
-	rawp = skb->data;
-
 	/*
 	 * This is a magic hack to spot IPX packets. Older Novell breaks
 	 * the protocol design and runs IPX over 802.3 without an 802.2 LLC
 	 * layer. We look for FFFF which isn't a used 802.2 SSAP/DSAP. This
 	 * won't work for fault tolerant netware but does for the rest.
 	 */
+	rawp = skb->data;
 	if (*(unsigned short *)rawp == 0xFFFF) {
 		skb->protocol = htons(ETH_P_802_3);
-		/* place it back on the queue to be handled by true layer 3
-		 * protocols. */
-
-		/* See if we are configured to re-write the VLAN header
-		 * to make it look like ethernet...
-		 */
-		skb = vlan_check_reorder_header(skb);
-
-		/* Can be null if skb-clone fails when re-ordering */
-		if (skb) {
-			netif_rx(skb);
-		} else {
-			/* TODO:  Add a more specific counter here. */
-			stats->rx_errors++;
-		}
-		rcu_read_unlock();
-		return 0;
+		goto recv;
 	}
 
 	/*
 	 *	Real 802.2 LLC
 	 */
 	skb->protocol = htons(ETH_P_802_2);
-	/* place it back on the queue to be handled by upper layer protocols.
-	 */
 
-	/* See if we are configured to re-write the VLAN header
-	 * to make it look like ethernet...
-	 */
+recv:
 	skb = vlan_check_reorder_header(skb);
-
-	/* Can be null if skb-clone fails when re-ordering */
-	if (skb) {
-		netif_rx(skb);
-	} else {
-		/* TODO:  Add a more specific counter here. */
+	if (!skb) {
 		stats->rx_errors++;
+		goto err_unlock;
 	}
+
+	netif_rx(skb);
 	rcu_read_unlock();
-	return 0;
+	return NET_RX_SUCCESS;
+
+err_unlock:
+	rcu_read_unlock();
+err_free:
+	kfree_skb(skb);
+	return NET_RX_DROP;
 }
 
 static inline unsigned short

^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox