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
39struct fifo_sched_data
40{
41	unsigned limit;
42};
43
44static int
45bfifo_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
64static int
65bfifo_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
72static struct sk_buff *
73bfifo_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
83static int
84fifo_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
97static void
98fifo_reset(struct Qdisc* sch)
99{
100	skb_queue_purge(&sch->q);
101	sch->stats.backlog = 0;
102}
103
104static int
105pfifo_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
123static int
124pfifo_requeue(struct sk_buff *skb, struct Qdisc* sch)
125{
126	__skb_queue_head(&sch->q, skb);
127	return 0;
128}
129
130
131static struct sk_buff *
132pfifo_dequeue(struct Qdisc* sch)
133{
134	return __skb_dequeue(&sch->q);
135}
136
137static 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
155static int fifo_dump(struct Qdisc *sch, struct sk_buff *skb)
156{
157	struct fifo_sched_data *q = (void*)sch->data;
158	unsigned char	 *b = skb->tail;
159	struct tc_fifo_qopt opt;
160
161	opt.limit = q->limit;
162	RTA_PUT(skb, TCA_OPTIONS, sizeof(opt), &opt);
163
164	return skb->len;
165
166rtattr_failure:
167	skb_trim(skb, b - skb->data);
168	return -1;
169}
170
171struct Qdisc_ops pfifo_qdisc_ops =
172{
173	NULL,
174	NULL,
175	"pfifo",
176	sizeof(struct fifo_sched_data),
177
178	pfifo_enqueue,
179	pfifo_dequeue,
180	pfifo_requeue,
181	fifo_drop,
182
183	fifo_init,
184	fifo_reset,
185	NULL,
186	fifo_init,
187
188	fifo_dump,
189};
190
191struct Qdisc_ops bfifo_qdisc_ops =
192{
193	NULL,
194	NULL,
195	"bfifo",
196	sizeof(struct fifo_sched_data),
197
198	bfifo_enqueue,
199	bfifo_dequeue,
200	bfifo_requeue,
201	fifo_drop,
202
203	fifo_init,
204	fifo_reset,
205	NULL,
206	fifo_init,
207	fifo_dump,
208};
209