2 * sch_dtht: Deep Thought Scheduler
3 * Copyright (C) 2011 Daniel Borkmann <borkmann@iogearbox.net>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * A simple, stupid drop, dup, corrupt, hi-jitter and just for fun
16 * network scheduler! Probably he won't give you the answer to the
17 * ultimate question of life, the universe, and everything, but he will
18 * take his time thinking about it. ;-)
20 * enable on egress: tc qdisc add dev eth10 root dtht
21 * disable on egress: tc qdisc del dev eth10 root dtht
24 #include <linux/kernel.h>
25 #include <linux/module.h>
26 #include <linux/types.h>
27 #include <linux/skbuff.h>
28 #include <linux/net.h>
29 #include <net/pkt_sched.h>
30 #include <net/sch_generic.h>
32 #define MODULE_NAME "sch_dtht"
33 #define MODULE_DESC "Deep Thought Scheduler"
35 struct sock_time_inf
{
39 #define SKB_DT_INF(skb) ((struct sock_time_inf *) (qdisc_skb_cb(skb)->data))
41 static int deepthought_enqueue(struct sk_buff
*skb
, struct Qdisc
*sch
)
43 int drop
= 0, dup
= 0, corr
= 0;
44 struct sk_buff
*skb2
= NULL
;
46 if (likely(sch
->qstats
.backlog
+ qdisc_pkt_len(skb
) <= sch
->limit
)) {
47 if ((net_random() & 0x7) == 1)
49 if ((net_random() & 0xf) == 1)
51 if ((net_random() & 0xf) == 1 &&
52 sch
->qstats
.backlog
+ qdisc_pkt_len(skb
) * 2 <=
65 skb2
= skb_clone(skb
, GFP_ATOMIC
);
66 SKB_DT_INF(skb2
)->depart
= psched_get_time() +
67 (net_random() & 0xffff);
68 qdisc_enqueue_tail(skb2
, sch
);
71 if (!(skb
= skb_unshare(skb
, GFP_ATOMIC
)) ||
72 (skb
->ip_summed
== CHECKSUM_PARTIAL
&&
73 skb_checksum_help(skb
)))
75 skb
->data
[net_random() % skb_headlen(skb
)] ^= 1 << (net_random() % 8);
77 SKB_DT_INF(skb
)->depart
= psched_get_time() + (net_random() & 0xffff);
78 return qdisc_enqueue_tail(skb
, sch
);
81 static struct sk_buff
*deepthought_dequeue(struct Qdisc
*sch
)
83 struct sk_buff
*skb
= qdisc_dequeue_head(sch
);
85 if (psched_get_time() >= SKB_DT_INF(skb
)->depart
)
88 qdisc_enqueue_tail(skb
, sch
);
93 static int deepthought_qinit(struct Qdisc
*sch
, struct nlattr
*opt
)
95 u32 limit
= qdisc_dev(sch
)->tx_queue_len
? : 1;
96 limit
*= psched_mtu(qdisc_dev(sch
));
101 static int deepthought_dump(struct Qdisc
*sch
, struct sk_buff
*skb
)
103 struct tc_fifo_qopt opt
= {
106 NLA_PUT(skb
, TCA_OPTIONS
, sizeof(opt
), &opt
);
112 static struct Qdisc_ops deepthought_qdisc_ops __read_mostly
= {
115 .enqueue
= deepthought_enqueue
,
116 .dequeue
= deepthought_dequeue
,
117 .peek
= qdisc_peek_head
,
118 .drop
= qdisc_queue_drop
,
119 .init
= deepthought_qinit
,
120 .reset
= qdisc_reset_queue
,
121 .change
= deepthought_qinit
,
122 .dump
= deepthought_dump
,
123 .owner
= THIS_MODULE
,
126 static int __init
deepthought_init(void)
128 printk(KERN_INFO
"%s: %s loaded!\n", MODULE_NAME
, MODULE_DESC
);
129 return register_qdisc(&deepthought_qdisc_ops
);
132 static void __exit
deepthought_exit(void)
134 unregister_qdisc(&deepthought_qdisc_ops
);
135 printk(KERN_INFO
"%s: removed!\n", MODULE_NAME
);
138 module_init(deepthought_init
);
139 module_exit(deepthought_exit
);
141 MODULE_LICENSE("GPL");
142 MODULE_DESCRIPTION(MODULE_DESC
);
143 MODULE_AUTHOR("Daniel Borkmann <borkmann@iogearbox.net>");