xref: /openbmc/linux/net/sched/sch_fifo.c (revision 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2)
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 <linux/module.h>
14 #include <asm/uaccess.h>
15 #include <asm/system.h>
16 #include <linux/bitops.h>
17 #include <linux/types.h>
18 #include <linux/kernel.h>
19 #include <linux/sched.h>
20 #include <linux/string.h>
21 #include <linux/mm.h>
22 #include <linux/socket.h>
23 #include <linux/sockios.h>
24 #include <linux/in.h>
25 #include <linux/errno.h>
26 #include <linux/interrupt.h>
27 #include <linux/if_ether.h>
28 #include <linux/inet.h>
29 #include <linux/netdevice.h>
30 #include <linux/etherdevice.h>
31 #include <linux/notifier.h>
32 #include <net/ip.h>
33 #include <net/route.h>
34 #include <linux/skbuff.h>
35 #include <net/sock.h>
36 #include <net/pkt_sched.h>
37 
38 /* 1 band FIFO pseudo-"scheduler" */
39 
40 struct fifo_sched_data
41 {
42 	unsigned limit;
43 };
44 
45 static int
46 bfifo_enqueue(struct sk_buff *skb, struct Qdisc* sch)
47 {
48 	struct fifo_sched_data *q = qdisc_priv(sch);
49 
50 	if (sch->qstats.backlog + skb->len <= q->limit) {
51 		__skb_queue_tail(&sch->q, skb);
52 		sch->qstats.backlog += skb->len;
53 		sch->bstats.bytes += skb->len;
54 		sch->bstats.packets++;
55 		return 0;
56 	}
57 	sch->qstats.drops++;
58 #ifdef CONFIG_NET_CLS_POLICE
59 	if (sch->reshape_fail==NULL || sch->reshape_fail(skb, sch))
60 #endif
61 		kfree_skb(skb);
62 	return NET_XMIT_DROP;
63 }
64 
65 static int
66 bfifo_requeue(struct sk_buff *skb, struct Qdisc* sch)
67 {
68 	__skb_queue_head(&sch->q, skb);
69 	sch->qstats.backlog += skb->len;
70 	sch->qstats.requeues++;
71 	return 0;
72 }
73 
74 static struct sk_buff *
75 bfifo_dequeue(struct Qdisc* sch)
76 {
77 	struct sk_buff *skb;
78 
79 	skb = __skb_dequeue(&sch->q);
80 	if (skb)
81 		sch->qstats.backlog -= skb->len;
82 	return skb;
83 }
84 
85 static unsigned int
86 fifo_drop(struct Qdisc* sch)
87 {
88 	struct sk_buff *skb;
89 
90 	skb = __skb_dequeue_tail(&sch->q);
91 	if (skb) {
92 		unsigned int len = skb->len;
93 		sch->qstats.backlog -= len;
94 		kfree_skb(skb);
95 		return len;
96 	}
97 	return 0;
98 }
99 
100 static void
101 fifo_reset(struct Qdisc* sch)
102 {
103 	skb_queue_purge(&sch->q);
104 	sch->qstats.backlog = 0;
105 }
106 
107 static int
108 pfifo_enqueue(struct sk_buff *skb, struct Qdisc* sch)
109 {
110 	struct fifo_sched_data *q = qdisc_priv(sch);
111 
112 	if (sch->q.qlen < q->limit) {
113 		__skb_queue_tail(&sch->q, skb);
114 		sch->bstats.bytes += skb->len;
115 		sch->bstats.packets++;
116 		return 0;
117 	}
118 	sch->qstats.drops++;
119 #ifdef CONFIG_NET_CLS_POLICE
120 	if (sch->reshape_fail==NULL || sch->reshape_fail(skb, sch))
121 #endif
122 		kfree_skb(skb);
123 	return NET_XMIT_DROP;
124 }
125 
126 static int
127 pfifo_requeue(struct sk_buff *skb, struct Qdisc* sch)
128 {
129 	__skb_queue_head(&sch->q, skb);
130 	sch->qstats.requeues++;
131 	return 0;
132 }
133 
134 
135 static struct sk_buff *
136 pfifo_dequeue(struct Qdisc* sch)
137 {
138 	return __skb_dequeue(&sch->q);
139 }
140 
141 static int fifo_init(struct Qdisc *sch, struct rtattr *opt)
142 {
143 	struct fifo_sched_data *q = qdisc_priv(sch);
144 
145 	if (opt == NULL) {
146 		unsigned int limit = sch->dev->tx_queue_len ? : 1;
147 
148 		if (sch->ops == &bfifo_qdisc_ops)
149 			q->limit = limit*sch->dev->mtu;
150 		else
151 			q->limit = limit;
152 	} else {
153 		struct tc_fifo_qopt *ctl = RTA_DATA(opt);
154 		if (opt->rta_len < RTA_LENGTH(sizeof(*ctl)))
155 			return -EINVAL;
156 		q->limit = ctl->limit;
157 	}
158 	return 0;
159 }
160 
161 static int fifo_dump(struct Qdisc *sch, struct sk_buff *skb)
162 {
163 	struct fifo_sched_data *q = qdisc_priv(sch);
164 	unsigned char	 *b = skb->tail;
165 	struct tc_fifo_qopt opt;
166 
167 	opt.limit = q->limit;
168 	RTA_PUT(skb, TCA_OPTIONS, sizeof(opt), &opt);
169 
170 	return skb->len;
171 
172 rtattr_failure:
173 	skb_trim(skb, b - skb->data);
174 	return -1;
175 }
176 
177 struct Qdisc_ops pfifo_qdisc_ops = {
178 	.next		=	NULL,
179 	.cl_ops		=	NULL,
180 	.id		=	"pfifo",
181 	.priv_size	=	sizeof(struct fifo_sched_data),
182 	.enqueue	=	pfifo_enqueue,
183 	.dequeue	=	pfifo_dequeue,
184 	.requeue	=	pfifo_requeue,
185 	.drop		=	fifo_drop,
186 	.init		=	fifo_init,
187 	.reset		=	fifo_reset,
188 	.destroy	=	NULL,
189 	.change		=	fifo_init,
190 	.dump		=	fifo_dump,
191 	.owner		=	THIS_MODULE,
192 };
193 
194 struct Qdisc_ops bfifo_qdisc_ops = {
195 	.next		=	NULL,
196 	.cl_ops		=	NULL,
197 	.id		=	"bfifo",
198 	.priv_size	=	sizeof(struct fifo_sched_data),
199 	.enqueue	=	bfifo_enqueue,
200 	.dequeue	=	bfifo_dequeue,
201 	.requeue	=	bfifo_requeue,
202 	.drop		=	fifo_drop,
203 	.init		=	fifo_init,
204 	.reset		=	fifo_reset,
205 	.destroy	=	NULL,
206 	.change		=	fifo_init,
207 	.dump		=	fifo_dump,
208 	.owner		=	THIS_MODULE,
209 };
210 
211 EXPORT_SYMBOL(bfifo_qdisc_ops);
212 EXPORT_SYMBOL(pfifo_qdisc_ops);
213