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