patch-2.3.43 linux/net/sched/sch_atm.c

Next file: linux/net/sched/sch_cbq.c
Previous file: linux/net/packet/af_packet.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.3.42/linux/net/sched/sch_atm.c linux/net/sched/sch_atm.c
@@ -1,6 +1,6 @@
 /* net/sched/sch_atm.c - ATM VC selection "queueing discipline" */
 
-/* Written 1998,1999 by Werner Almesberger, EPFL ICA */
+/* Written 1998-2000 by Werner Almesberger, EPFL ICA */
 
 
 #include <linux/config.h>
@@ -56,12 +56,14 @@
 
 
 #define PRIV(sch) ((struct atm_qdisc_data *) (sch)->data)
+#define VCC2FLOW(vcc) ((struct atm_flow_data *) ((vcc)->user_back))
 
 
 struct atm_flow_data {
 	struct Qdisc		*q;		/* FIFO, TBF, etc. */
 	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 socket		*sock;		/* for closing */
 	u32			classid;	/* x:y type ID */
 	int			ref;		/* reference count */
@@ -133,7 +135,7 @@
 
 static unsigned long atm_tc_get(struct Qdisc *sch,u32 classid)
 {
-	struct atm_qdisc_data *p = PRIV(sch);
+	struct atm_qdisc_data *p __attribute__((unused)) = PRIV(sch);
 	struct atm_flow_data *flow;
 
 	DPRINTK("atm_tc_get(sch %p,[qdisc %p],classid %x)\n",sch,p,classid);
@@ -184,6 +186,7 @@
 	}
 	if (flow->sock) {
 		DPRINTK("atm_tc_put: f_count %d\n",file_count(flow->sock->file));
+		flow->vcc->pop = flow->old_pop;
 		sockfd_put(flow->sock);
 	}
 	if (flow->excess) atm_tc_put(sch,(unsigned long) flow->excess);
@@ -195,6 +198,13 @@
 }
 
 
+static void sch_atm_pop(struct atm_vcc *vcc,struct sk_buff *skb)
+{
+	VCC2FLOW(vcc)->old_pop(vcc,skb);
+	mark_bh(NET_BH); /* may allow to send more */
+}
+
+
 static int atm_tc_change(struct Qdisc *sch, u32 classid, u32 parent,
     struct rtattr **tca, unsigned long *arg)
 {
@@ -289,7 +299,10 @@
 	DPRINTK("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);
+	flow->old_pop = flow->vcc->pop;
+	flow->vcc->pop = sch_atm_pop;
 	flow->classid = classid;
 	flow->ref = 1;
 	flow->excess = excess;
@@ -440,6 +453,10 @@
 		 * little bursts. Otherwise, it may ... @@@
 		 */
 		while ((skb = flow->q->dequeue(flow->q))) {
+			if (!atm_may_send(flow->vcc,skb->truesize)) {
+				flow->q->ops->requeue(skb,flow->q);
+				break;
+			}
 			sch->q.qlen--;
 			D2PRINTK("atm_tc_deqeueue: sending on class %p\n",flow);
 			/* remove any LL header somebody else has attached */
@@ -468,6 +485,22 @@
 }
 
 
+static int atm_tc_requeue(struct sk_buff *skb,struct Qdisc *sch)
+{
+	struct atm_qdisc_data *p = PRIV(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);
+	if (!ret) sch->q.qlen++;
+	else {
+		sch->stats.drops++;
+		p->link.stats.drops++;
+	}
+	return ret;
+}
+
+
 static int atm_tc_drop(struct Qdisc *sch)
 {
 	struct atm_qdisc_data *p = PRIV(sch);
@@ -616,7 +649,7 @@
 
 	atm_tc_enqueue,			/* enqueue */
 	atm_tc_dequeue,			/* dequeue */
-	atm_tc_enqueue,			/* requeue; we're cheating a little */
+	atm_tc_requeue,			/* requeue */
 	atm_tc_drop,			/* drop */
 
 	atm_tc_init,			/* init */

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)