File: /usr/src/linux/net/sched/sch_fifo.c

1     /*
2      * net/sched/sch_fifo.c	The simplest FIFO queue.
3      *
4      *		This program is free software; you can redistribute it and/or
5      *		modify it under the terms of the GNU General Public License
6      *		as published by the Free Software Foundation; either version
7      *		2 of the License, or (at your option) any later version.
8      *
9      * Authors:	Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
10      */
11     
12     #include <linux/config.h>
13     #include <asm/uaccess.h>
14     #include <asm/system.h>
15     #include <asm/bitops.h>
16     #include <linux/types.h>
17     #include <linux/kernel.h>
18     #include <linux/sched.h>
19     #include <linux/string.h>
20     #include <linux/mm.h>
21     #include <linux/socket.h>
22     #include <linux/sockios.h>
23     #include <linux/in.h>
24     #include <linux/errno.h>
25     #include <linux/interrupt.h>
26     #include <linux/if_ether.h>
27     #include <linux/inet.h>
28     #include <linux/netdevice.h>
29     #include <linux/etherdevice.h>
30     #include <linux/notifier.h>
31     #include <net/ip.h>
32     #include <net/route.h>
33     #include <linux/skbuff.h>
34     #include <net/sock.h>
35     #include <net/pkt_sched.h>
36     
37     /* 1 band FIFO pseudo-"scheduler" */
38     
39     struct fifo_sched_data
40     {
41     	unsigned limit;
42     };
43     
44     static int
45     bfifo_enqueue(struct sk_buff *skb, struct Qdisc* sch)
46     {
47     	struct fifo_sched_data *q = (struct fifo_sched_data *)sch->data;
48     
49     	if (sch->stats.backlog <= q->limit) {
50     		__skb_queue_tail(&sch->q, skb);
51     		sch->stats.backlog += skb->len;
52     		sch->stats.bytes += skb->len;
53     		sch->stats.packets++;
54     		return 0;
55     	}
56     	sch->stats.drops++;
57     #ifdef CONFIG_NET_CLS_POLICE
58     	if (sch->reshape_fail==NULL || sch->reshape_fail(skb, sch))
59     #endif
60     		kfree_skb(skb);
61     	return NET_XMIT_DROP;
62     }
63     
64     static int
65     bfifo_requeue(struct sk_buff *skb, struct Qdisc* sch)
66     {
67     	__skb_queue_head(&sch->q, skb);
68     	sch->stats.backlog += skb->len;
69     	return 0;
70     }
71     
72     static struct sk_buff *
73     bfifo_dequeue(struct Qdisc* sch)
74     {
75     	struct sk_buff *skb;
76     
77     	skb = __skb_dequeue(&sch->q);
78     	if (skb)
79     		sch->stats.backlog -= skb->len;
80     	return skb;
81     }
82     
83     static int
84     fifo_drop(struct Qdisc* sch)
85     {
86     	struct sk_buff *skb;
87     
88     	skb = __skb_dequeue_tail(&sch->q);
89     	if (skb) {
90     		sch->stats.backlog -= skb->len;
91     		kfree_skb(skb);
92     		return 1;
93     	}
94     	return 0;
95     }
96     
97     static void
98     fifo_reset(struct Qdisc* sch)
99     {
100     	skb_queue_purge(&sch->q);
101     	sch->stats.backlog = 0;
102     }
103     
104     static int
105     pfifo_enqueue(struct sk_buff *skb, struct Qdisc* sch)
106     {
107     	struct fifo_sched_data *q = (struct fifo_sched_data *)sch->data;
108     
109     	if (sch->q.qlen <= q->limit) {
110     		__skb_queue_tail(&sch->q, skb);
111     		sch->stats.bytes += skb->len;
112     		sch->stats.packets++;
113     		return 0;
114     	}
115     	sch->stats.drops++;
116     #ifdef CONFIG_NET_CLS_POLICE
117     	if (sch->reshape_fail==NULL || sch->reshape_fail(skb, sch))
118     #endif
119     		kfree_skb(skb);
120     	return NET_XMIT_DROP;
121     }
122     
123     static int
124     pfifo_requeue(struct sk_buff *skb, struct Qdisc* sch)
125     {
126     	__skb_queue_head(&sch->q, skb);
127     	return 0;
128     }
129     
130     
131     static struct sk_buff *
132     pfifo_dequeue(struct Qdisc* sch)
133     {
134     	return __skb_dequeue(&sch->q);
135     }
136     
137     static int fifo_init(struct Qdisc *sch, struct rtattr *opt)
138     {
139     	struct fifo_sched_data *q = (void*)sch->data;
140     
141     	if (opt == NULL) {
142     		if (sch->ops == &bfifo_qdisc_ops)
143     			q->limit = sch->dev->tx_queue_len*sch->dev->mtu;
144     		else	
145     			q->limit = sch->dev->tx_queue_len;
146     	} else {
147     		struct tc_fifo_qopt *ctl = RTA_DATA(opt);
148     		if (opt->rta_len < RTA_LENGTH(sizeof(*ctl)))
149     			return -EINVAL;
150     		q->limit = ctl->limit;
151     	}
152     	return 0;
153     }
154     
155     #ifdef CONFIG_RTNETLINK
156     static int fifo_dump(struct Qdisc *sch, struct sk_buff *skb)
157     {
158     	struct fifo_sched_data *q = (void*)sch->data;
159     	unsigned char	 *b = skb->tail;
160     	struct tc_fifo_qopt opt;
161     
162     	opt.limit = q->limit;
163     	RTA_PUT(skb, TCA_OPTIONS, sizeof(opt), &opt);
164     
165     	return skb->len;
166     
167     rtattr_failure:
168     	skb_trim(skb, b - skb->data);
169     	return -1;
170     }
171     #endif
172     
173     struct Qdisc_ops pfifo_qdisc_ops =
174     {
175     	NULL,
176     	NULL,
177     	"pfifo",
178     	sizeof(struct fifo_sched_data),
179     
180     	pfifo_enqueue,
181     	pfifo_dequeue,
182     	pfifo_requeue,
183     	fifo_drop,
184     
185     	fifo_init,
186     	fifo_reset,
187     	NULL,
188     	fifo_init,
189     
190     #ifdef CONFIG_RTNETLINK
191     	fifo_dump,
192     #endif
193     };
194     
195     struct Qdisc_ops bfifo_qdisc_ops =
196     {
197     	NULL,
198     	NULL,
199     	"bfifo",
200     	sizeof(struct fifo_sched_data),
201     
202     	bfifo_enqueue,
203     	bfifo_dequeue,
204     	bfifo_requeue,
205     	fifo_drop,
206     
207     	fifo_init,
208     	fifo_reset,
209     	NULL,
210     	fifo_init,
211     #ifdef CONFIG_RTNETLINK
212     	fifo_dump,
213     #endif
214     };
215