Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

sched: add head drop fifo queue

This adds an additional queuing strategy, called pfifo_head_drop,
to remove the oldest skb in the case of an overflow within the queue -
the head element - instead of the last skb (tail). To remove the oldest
skb in congested situations is useful for sensor network environments
where newer packets reflect the superior information.

Reviewed-by: Florian Westphal <fw@strlen.de>
Acked-by: Patrick McHardy <kaber@trash.net>
Signed-off-by: Hagen Paul Pfeifer <hagen@jauu.net>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Hagen Paul Pfeifer and committed by
David S. Miller
57dbb2d8 d74340d3

+55
+1
include/net/pkt_sched.h
··· 71 71 72 72 extern struct Qdisc_ops pfifo_qdisc_ops; 73 73 extern struct Qdisc_ops bfifo_qdisc_ops; 74 + extern struct Qdisc_ops pfifo_head_drop_qdisc_ops; 74 75 75 76 extern int fifo_set_limit(struct Qdisc *q, unsigned int limit); 76 77 extern struct Qdisc *fifo_create_dflt(struct Qdisc *sch, struct Qdisc_ops *ops,
+19
include/net/sch_generic.h
··· 427 427 return __qdisc_dequeue_head(sch, &sch->q); 428 428 } 429 429 430 + static inline unsigned int __qdisc_queue_drop_head(struct Qdisc *sch, 431 + struct sk_buff_head *list) 432 + { 433 + struct sk_buff *skb = __qdisc_dequeue_head(sch, list); 434 + 435 + if (likely(skb != NULL)) { 436 + unsigned int len = qdisc_pkt_len(skb); 437 + kfree_skb(skb); 438 + return len; 439 + } 440 + 441 + return 0; 442 + } 443 + 444 + static inline unsigned int qdisc_queue_drop_head(struct Qdisc *sch) 445 + { 446 + return __qdisc_queue_drop_head(sch, &sch->q); 447 + } 448 + 430 449 static inline struct sk_buff *__qdisc_dequeue_tail(struct Qdisc *sch, 431 450 struct sk_buff_head *list) 432 451 {
+1
net/sched/sch_api.c
··· 1707 1707 { 1708 1708 register_qdisc(&pfifo_qdisc_ops); 1709 1709 register_qdisc(&bfifo_qdisc_ops); 1710 + register_qdisc(&pfifo_head_drop_qdisc_ops); 1710 1711 register_qdisc(&mq_qdisc_ops); 1711 1712 proc_net_fops_create(&init_net, "psched", 0, &psched_fops); 1712 1713
+34
net/sched/sch_fifo.c
··· 43 43 return qdisc_reshape_fail(skb, sch); 44 44 } 45 45 46 + static int pfifo_tail_enqueue(struct sk_buff *skb, struct Qdisc* sch) 47 + { 48 + struct sk_buff *skb_head; 49 + struct fifo_sched_data *q = qdisc_priv(sch); 50 + 51 + if (likely(skb_queue_len(&sch->q) < q->limit)) 52 + return qdisc_enqueue_tail(skb, sch); 53 + 54 + /* queue full, remove one skb to fulfill the limit */ 55 + skb_head = qdisc_dequeue_head(sch); 56 + sch->bstats.bytes -= qdisc_pkt_len(skb_head); 57 + sch->bstats.packets--; 58 + sch->qstats.drops++; 59 + kfree_skb(skb_head); 60 + 61 + qdisc_enqueue_tail(skb, sch); 62 + 63 + return NET_XMIT_CN; 64 + } 65 + 46 66 static int fifo_init(struct Qdisc *sch, struct nlattr *opt) 47 67 { 48 68 struct fifo_sched_data *q = qdisc_priv(sch); ··· 127 107 .owner = THIS_MODULE, 128 108 }; 129 109 EXPORT_SYMBOL(bfifo_qdisc_ops); 110 + 111 + struct Qdisc_ops pfifo_head_drop_qdisc_ops __read_mostly = { 112 + .id = "pfifo_head_drop", 113 + .priv_size = sizeof(struct fifo_sched_data), 114 + .enqueue = pfifo_tail_enqueue, 115 + .dequeue = qdisc_dequeue_head, 116 + .peek = qdisc_peek_head, 117 + .drop = qdisc_queue_drop_head, 118 + .init = fifo_init, 119 + .reset = qdisc_reset_queue, 120 + .change = fifo_init, 121 + .dump = fifo_dump, 122 + .owner = THIS_MODULE, 123 + }; 130 124 131 125 /* Pass size change message down to embedded FIFO */ 132 126 int fifo_set_limit(struct Qdisc *q, unsigned int limit)