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