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
bfifo_enqueue(struct sk_buff * skb,struct Qdisc * sch)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 + skb->len <= 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
bfifo_requeue(struct sk_buff * skb,struct Qdisc * sch)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 *
bfifo_dequeue(struct Qdisc * sch)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 unsigned int
fifo_drop(struct Qdisc * sch)84 fifo_drop(struct Qdisc* sch)
85 {
86 	struct sk_buff *skb;
87 
88 	skb = __skb_dequeue_tail(&sch->q);
89 	if (skb) {
90 		unsigned int len = skb->len;
91 		sch->stats.backlog -= len;
92 		kfree_skb(skb);
93 		return len;
94 	}
95 	return 0;
96 }
97 
98 static void
fifo_reset(struct Qdisc * sch)99 fifo_reset(struct Qdisc* sch)
100 {
101 	skb_queue_purge(&sch->q);
102 	sch->stats.backlog = 0;
103 }
104 
105 static int
pfifo_enqueue(struct sk_buff * skb,struct Qdisc * sch)106 pfifo_enqueue(struct sk_buff *skb, struct Qdisc* sch)
107 {
108 	struct fifo_sched_data *q = (struct fifo_sched_data *)sch->data;
109 
110 	if (sch->q.qlen < q->limit) {
111 		__skb_queue_tail(&sch->q, skb);
112 		sch->stats.bytes += skb->len;
113 		sch->stats.packets++;
114 		return 0;
115 	}
116 	sch->stats.drops++;
117 #ifdef CONFIG_NET_CLS_POLICE
118 	if (sch->reshape_fail==NULL || sch->reshape_fail(skb, sch))
119 #endif
120 		kfree_skb(skb);
121 	return NET_XMIT_DROP;
122 }
123 
124 static int
pfifo_requeue(struct sk_buff * skb,struct Qdisc * sch)125 pfifo_requeue(struct sk_buff *skb, struct Qdisc* sch)
126 {
127 	__skb_queue_head(&sch->q, skb);
128 	return 0;
129 }
130 
131 
132 static struct sk_buff *
pfifo_dequeue(struct Qdisc * sch)133 pfifo_dequeue(struct Qdisc* sch)
134 {
135 	return __skb_dequeue(&sch->q);
136 }
137 
fifo_init(struct Qdisc * sch,struct rtattr * opt)138 static int fifo_init(struct Qdisc *sch, struct rtattr *opt)
139 {
140 	struct fifo_sched_data *q = (void*)sch->data;
141 
142 	if (opt == NULL) {
143 		unsigned int limit = sch->dev->tx_queue_len ? : 1;
144 
145 		if (sch->ops == &bfifo_qdisc_ops)
146 			q->limit = limit*sch->dev->mtu;
147 		else
148 			q->limit = limit;
149 	} else {
150 		struct tc_fifo_qopt *ctl = RTA_DATA(opt);
151 		if (opt->rta_len < RTA_LENGTH(sizeof(*ctl)))
152 			return -EINVAL;
153 		q->limit = ctl->limit;
154 	}
155 	return 0;
156 }
157 
fifo_dump(struct Qdisc * sch,struct sk_buff * skb)158 static int fifo_dump(struct Qdisc *sch, struct sk_buff *skb)
159 {
160 	struct fifo_sched_data *q = (void*)sch->data;
161 	unsigned char	 *b = skb->tail;
162 	struct tc_fifo_qopt opt;
163 
164 	opt.limit = q->limit;
165 	RTA_PUT(skb, TCA_OPTIONS, sizeof(opt), &opt);
166 
167 	return skb->len;
168 
169 rtattr_failure:
170 	skb_trim(skb, b - skb->data);
171 	return -1;
172 }
173 
174 struct Qdisc_ops pfifo_qdisc_ops =
175 {
176 	NULL,
177 	NULL,
178 	"pfifo",
179 	sizeof(struct fifo_sched_data),
180 
181 	pfifo_enqueue,
182 	pfifo_dequeue,
183 	pfifo_requeue,
184 	fifo_drop,
185 
186 	fifo_init,
187 	fifo_reset,
188 	NULL,
189 	fifo_init,
190 
191 	fifo_dump,
192 };
193 
194 struct Qdisc_ops bfifo_qdisc_ops =
195 {
196 	NULL,
197 	NULL,
198 	"bfifo",
199 	sizeof(struct fifo_sched_data),
200 
201 	bfifo_enqueue,
202 	bfifo_dequeue,
203 	bfifo_requeue,
204 	fifo_drop,
205 
206 	fifo_init,
207 	fifo_reset,
208 	NULL,
209 	fifo_init,
210 	fifo_dump,
211 };
212