diff options
Diffstat (limited to 'net/sched')
-rw-r--r-- | net/sched/Kconfig | 12 | ||||
-rw-r--r-- | net/sched/Makefile | 11 | ||||
-rw-r--r-- | net/sched/act_api.c | 4 | ||||
-rw-r--r-- | net/sched/cls_fw.c | 31 | ||||
-rw-r--r-- | net/sched/sch_api.c | 1 | ||||
-rw-r--r-- | net/sched/sch_generic.c | 5 | ||||
-rw-r--r-- | net/sched/sch_htb.c | 4 | ||||
-rw-r--r-- | net/sched/sch_netem.c | 131 | ||||
-rw-r--r-- | net/sched/simple.c | 93 |
9 files changed, 230 insertions, 62 deletions
diff --git a/net/sched/Kconfig b/net/sched/Kconfig index 3d1d902dd1a1..b0941186f867 100644 --- a/net/sched/Kconfig +++ b/net/sched/Kconfig | |||
@@ -185,7 +185,7 @@ config NET_SCH_GRED | |||
185 | depends on NET_SCHED | 185 | depends on NET_SCHED |
186 | help | 186 | help |
187 | Say Y here if you want to use the Generic Random Early Detection | 187 | Say Y here if you want to use the Generic Random Early Detection |
188 | (RED) packet scheduling algorithm for some of your network devices | 188 | (GRED) packet scheduling algorithm for some of your network devices |
189 | (see the top of <file:net/sched/sch_red.c> for details and | 189 | (see the top of <file:net/sched/sch_red.c> for details and |
190 | references about the algorithm). | 190 | references about the algorithm). |
191 | 191 | ||
@@ -506,3 +506,13 @@ config NET_CLS_POLICE | |||
506 | Say Y to support traffic policing (bandwidth limits). Needed for | 506 | Say Y to support traffic policing (bandwidth limits). Needed for |
507 | ingress and egress rate limiting. | 507 | ingress and egress rate limiting. |
508 | 508 | ||
509 | config NET_ACT_SIMP | ||
510 | tristate "Simple action" | ||
511 | depends on NET_CLS_ACT | ||
512 | ---help--- | ||
513 | You must have new iproute2 to use this feature. | ||
514 | This adds a very simple action for demonstration purposes | ||
515 | The idea is to give action authors a basic example to look at. | ||
516 | All this action will do is print on the console the configured | ||
517 | policy string followed by _ then packet count. | ||
518 | |||
diff --git a/net/sched/Makefile b/net/sched/Makefile index 431e55786efd..eb3fe583eba8 100644 --- a/net/sched/Makefile +++ b/net/sched/Makefile | |||
@@ -6,13 +6,14 @@ obj-y := sch_generic.o | |||
6 | 6 | ||
7 | obj-$(CONFIG_NET_SCHED) += sch_api.o sch_fifo.o | 7 | obj-$(CONFIG_NET_SCHED) += sch_api.o sch_fifo.o |
8 | obj-$(CONFIG_NET_CLS) += cls_api.o | 8 | obj-$(CONFIG_NET_CLS) += cls_api.o |
9 | obj-$(CONFIG_NET_CLS_ACT) += act_api.o | 9 | obj-$(CONFIG_NET_CLS_ACT) += act_api.o |
10 | obj-$(CONFIG_NET_ACT_POLICE) += police.o | 10 | obj-$(CONFIG_NET_ACT_POLICE) += police.o |
11 | obj-$(CONFIG_NET_CLS_POLICE) += police.o | 11 | obj-$(CONFIG_NET_CLS_POLICE) += police.o |
12 | obj-$(CONFIG_NET_ACT_GACT) += gact.o | 12 | obj-$(CONFIG_NET_ACT_GACT) += gact.o |
13 | obj-$(CONFIG_NET_ACT_MIRRED) += mirred.o | 13 | obj-$(CONFIG_NET_ACT_MIRRED) += mirred.o |
14 | obj-$(CONFIG_NET_ACT_IPT) += ipt.o | 14 | obj-$(CONFIG_NET_ACT_IPT) += ipt.o |
15 | obj-$(CONFIG_NET_ACT_PEDIT) += pedit.o | 15 | obj-$(CONFIG_NET_ACT_PEDIT) += pedit.o |
16 | obj-$(CONFIG_NET_ACT_SIMP) += simple.o | ||
16 | obj-$(CONFIG_NET_SCH_CBQ) += sch_cbq.o | 17 | obj-$(CONFIG_NET_SCH_CBQ) += sch_cbq.o |
17 | obj-$(CONFIG_NET_SCH_HTB) += sch_htb.o | 18 | obj-$(CONFIG_NET_SCH_HTB) += sch_htb.o |
18 | obj-$(CONFIG_NET_SCH_HPFQ) += sch_hpfq.o | 19 | obj-$(CONFIG_NET_SCH_HPFQ) += sch_hpfq.o |
diff --git a/net/sched/act_api.c b/net/sched/act_api.c index 5e6cc371b39e..cafcb084098d 100644 --- a/net/sched/act_api.c +++ b/net/sched/act_api.c | |||
@@ -171,10 +171,10 @@ repeat: | |||
171 | skb->tc_verd = SET_TC_OK2MUNGE(skb->tc_verd); | 171 | skb->tc_verd = SET_TC_OK2MUNGE(skb->tc_verd); |
172 | skb->tc_verd = CLR_TC_MUNGED(skb->tc_verd); | 172 | skb->tc_verd = CLR_TC_MUNGED(skb->tc_verd); |
173 | } | 173 | } |
174 | if (ret != TC_ACT_PIPE) | ||
175 | goto exec_done; | ||
176 | if (ret == TC_ACT_REPEAT) | 174 | if (ret == TC_ACT_REPEAT) |
177 | goto repeat; /* we need a ttl - JHS */ | 175 | goto repeat; /* we need a ttl - JHS */ |
176 | if (ret != TC_ACT_PIPE) | ||
177 | goto exec_done; | ||
178 | } | 178 | } |
179 | act = a->next; | 179 | act = a->next; |
180 | } | 180 | } |
diff --git a/net/sched/cls_fw.c b/net/sched/cls_fw.c index fdfc83af3d1f..29d8b9a4d162 100644 --- a/net/sched/cls_fw.c +++ b/net/sched/cls_fw.c | |||
@@ -46,9 +46,11 @@ | |||
46 | #include <net/act_api.h> | 46 | #include <net/act_api.h> |
47 | #include <net/pkt_cls.h> | 47 | #include <net/pkt_cls.h> |
48 | 48 | ||
49 | #define HTSIZE (PAGE_SIZE/sizeof(struct fw_filter *)) | ||
50 | |||
49 | struct fw_head | 51 | struct fw_head |
50 | { | 52 | { |
51 | struct fw_filter *ht[256]; | 53 | struct fw_filter *ht[HTSIZE]; |
52 | }; | 54 | }; |
53 | 55 | ||
54 | struct fw_filter | 56 | struct fw_filter |
@@ -69,7 +71,28 @@ static struct tcf_ext_map fw_ext_map = { | |||
69 | 71 | ||
70 | static __inline__ int fw_hash(u32 handle) | 72 | static __inline__ int fw_hash(u32 handle) |
71 | { | 73 | { |
72 | return handle&0xFF; | 74 | if (HTSIZE == 4096) |
75 | return ((handle >> 24) & 0xFFF) ^ | ||
76 | ((handle >> 12) & 0xFFF) ^ | ||
77 | (handle & 0xFFF); | ||
78 | else if (HTSIZE == 2048) | ||
79 | return ((handle >> 22) & 0x7FF) ^ | ||
80 | ((handle >> 11) & 0x7FF) ^ | ||
81 | (handle & 0x7FF); | ||
82 | else if (HTSIZE == 1024) | ||
83 | return ((handle >> 20) & 0x3FF) ^ | ||
84 | ((handle >> 10) & 0x3FF) ^ | ||
85 | (handle & 0x3FF); | ||
86 | else if (HTSIZE == 512) | ||
87 | return (handle >> 27) ^ | ||
88 | ((handle >> 18) & 0x1FF) ^ | ||
89 | ((handle >> 9) & 0x1FF) ^ | ||
90 | (handle & 0x1FF); | ||
91 | else if (HTSIZE == 256) { | ||
92 | u8 *t = (u8 *) &handle; | ||
93 | return t[0] ^ t[1] ^ t[2] ^ t[3]; | ||
94 | } else | ||
95 | return handle & (HTSIZE - 1); | ||
73 | } | 96 | } |
74 | 97 | ||
75 | static int fw_classify(struct sk_buff *skb, struct tcf_proto *tp, | 98 | static int fw_classify(struct sk_buff *skb, struct tcf_proto *tp, |
@@ -152,7 +175,7 @@ static void fw_destroy(struct tcf_proto *tp) | |||
152 | if (head == NULL) | 175 | if (head == NULL) |
153 | return; | 176 | return; |
154 | 177 | ||
155 | for (h=0; h<256; h++) { | 178 | for (h=0; h<HTSIZE; h++) { |
156 | while ((f=head->ht[h]) != NULL) { | 179 | while ((f=head->ht[h]) != NULL) { |
157 | head->ht[h] = f->next; | 180 | head->ht[h] = f->next; |
158 | fw_delete_filter(tp, f); | 181 | fw_delete_filter(tp, f); |
@@ -291,7 +314,7 @@ static void fw_walk(struct tcf_proto *tp, struct tcf_walker *arg) | |||
291 | if (arg->stop) | 314 | if (arg->stop) |
292 | return; | 315 | return; |
293 | 316 | ||
294 | for (h = 0; h < 256; h++) { | 317 | for (h = 0; h < HTSIZE; h++) { |
295 | struct fw_filter *f; | 318 | struct fw_filter *f; |
296 | 319 | ||
297 | for (f = head->ht[h]; f; f = f->next) { | 320 | for (f = head->ht[h]; f; f = f->next) { |
diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c index 4323a74eea30..07977f8f2679 100644 --- a/net/sched/sch_api.c +++ b/net/sched/sch_api.c | |||
@@ -1289,6 +1289,7 @@ static int __init pktsched_init(void) | |||
1289 | 1289 | ||
1290 | subsys_initcall(pktsched_init); | 1290 | subsys_initcall(pktsched_init); |
1291 | 1291 | ||
1292 | EXPORT_SYMBOL(qdisc_lookup); | ||
1292 | EXPORT_SYMBOL(qdisc_get_rtab); | 1293 | EXPORT_SYMBOL(qdisc_get_rtab); |
1293 | EXPORT_SYMBOL(qdisc_put_rtab); | 1294 | EXPORT_SYMBOL(qdisc_put_rtab); |
1294 | EXPORT_SYMBOL(register_qdisc); | 1295 | EXPORT_SYMBOL(register_qdisc); |
diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c index 8c01e023f02e..87e48a4e1051 100644 --- a/net/sched/sch_generic.c +++ b/net/sched/sch_generic.c | |||
@@ -179,6 +179,7 @@ requeue: | |||
179 | netif_schedule(dev); | 179 | netif_schedule(dev); |
180 | return 1; | 180 | return 1; |
181 | } | 181 | } |
182 | BUG_ON((int) q->q.qlen < 0); | ||
182 | return q->q.qlen; | 183 | return q->q.qlen; |
183 | } | 184 | } |
184 | 185 | ||
@@ -539,6 +540,10 @@ void dev_activate(struct net_device *dev) | |||
539 | write_unlock_bh(&qdisc_tree_lock); | 540 | write_unlock_bh(&qdisc_tree_lock); |
540 | } | 541 | } |
541 | 542 | ||
543 | if (!netif_carrier_ok(dev)) | ||
544 | /* Delay activation until next carrier-on event */ | ||
545 | return; | ||
546 | |||
542 | spin_lock_bh(&dev->queue_lock); | 547 | spin_lock_bh(&dev->queue_lock); |
543 | rcu_assign_pointer(dev->qdisc, dev->qdisc_sleeping); | 548 | rcu_assign_pointer(dev->qdisc, dev->qdisc_sleeping); |
544 | if (dev->qdisc != &noqueue_qdisc) { | 549 | if (dev->qdisc != &noqueue_qdisc) { |
diff --git a/net/sched/sch_htb.c b/net/sched/sch_htb.c index a85935e7d53d..558cc087e602 100644 --- a/net/sched/sch_htb.c +++ b/net/sched/sch_htb.c | |||
@@ -717,6 +717,10 @@ static int htb_enqueue(struct sk_buff *skb, struct Qdisc *sch) | |||
717 | if (q->direct_queue.qlen < q->direct_qlen) { | 717 | if (q->direct_queue.qlen < q->direct_qlen) { |
718 | __skb_queue_tail(&q->direct_queue, skb); | 718 | __skb_queue_tail(&q->direct_queue, skb); |
719 | q->direct_pkts++; | 719 | q->direct_pkts++; |
720 | } else { | ||
721 | kfree_skb(skb); | ||
722 | sch->qstats.drops++; | ||
723 | return NET_XMIT_DROP; | ||
720 | } | 724 | } |
721 | #ifdef CONFIG_NET_CLS_ACT | 725 | #ifdef CONFIG_NET_CLS_ACT |
722 | } else if (!cl) { | 726 | } else if (!cl) { |
diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c index 31c29deb139d..e0c9fbe73b15 100644 --- a/net/sched/sch_netem.c +++ b/net/sched/sch_netem.c | |||
@@ -138,38 +138,77 @@ static long tabledist(unsigned long mu, long sigma, | |||
138 | } | 138 | } |
139 | 139 | ||
140 | /* Put skb in the private delayed queue. */ | 140 | /* Put skb in the private delayed queue. */ |
141 | static int delay_skb(struct Qdisc *sch, struct sk_buff *skb) | 141 | static int netem_delay(struct Qdisc *sch, struct sk_buff *skb) |
142 | { | 142 | { |
143 | struct netem_sched_data *q = qdisc_priv(sch); | 143 | struct netem_sched_data *q = qdisc_priv(sch); |
144 | struct netem_skb_cb *cb = (struct netem_skb_cb *)skb->cb; | ||
145 | psched_tdiff_t td; | 144 | psched_tdiff_t td; |
146 | psched_time_t now; | 145 | psched_time_t now; |
147 | 146 | ||
148 | PSCHED_GET_TIME(now); | 147 | PSCHED_GET_TIME(now); |
149 | td = tabledist(q->latency, q->jitter, &q->delay_cor, q->delay_dist); | 148 | td = tabledist(q->latency, q->jitter, &q->delay_cor, q->delay_dist); |
150 | PSCHED_TADD2(now, td, cb->time_to_send); | ||
151 | 149 | ||
152 | /* Always queue at tail to keep packets in order */ | 150 | /* Always queue at tail to keep packets in order */ |
153 | if (likely(q->delayed.qlen < q->limit)) { | 151 | if (likely(q->delayed.qlen < q->limit)) { |
152 | struct netem_skb_cb *cb = (struct netem_skb_cb *)skb->cb; | ||
153 | |||
154 | PSCHED_TADD2(now, td, cb->time_to_send); | ||
155 | |||
156 | pr_debug("netem_delay: skb=%p now=%llu tosend=%llu\n", skb, | ||
157 | now, cb->time_to_send); | ||
158 | |||
154 | __skb_queue_tail(&q->delayed, skb); | 159 | __skb_queue_tail(&q->delayed, skb); |
155 | if (!timer_pending(&q->timer)) { | ||
156 | q->timer.expires = jiffies + PSCHED_US2JIFFIE(td); | ||
157 | add_timer(&q->timer); | ||
158 | } | ||
159 | return NET_XMIT_SUCCESS; | 160 | return NET_XMIT_SUCCESS; |
160 | } | 161 | } |
161 | 162 | ||
163 | pr_debug("netem_delay: queue over limit %d\n", q->limit); | ||
164 | sch->qstats.overlimits++; | ||
162 | kfree_skb(skb); | 165 | kfree_skb(skb); |
163 | return NET_XMIT_DROP; | 166 | return NET_XMIT_DROP; |
164 | } | 167 | } |
165 | 168 | ||
169 | /* | ||
170 | * Move a packet that is ready to send from the delay holding | ||
171 | * list to the underlying qdisc. | ||
172 | */ | ||
173 | static int netem_run(struct Qdisc *sch) | ||
174 | { | ||
175 | struct netem_sched_data *q = qdisc_priv(sch); | ||
176 | struct sk_buff *skb; | ||
177 | psched_time_t now; | ||
178 | |||
179 | PSCHED_GET_TIME(now); | ||
180 | |||
181 | skb = skb_peek(&q->delayed); | ||
182 | if (skb) { | ||
183 | const struct netem_skb_cb *cb | ||
184 | = (const struct netem_skb_cb *)skb->cb; | ||
185 | long delay | ||
186 | = PSCHED_US2JIFFIE(PSCHED_TDIFF(cb->time_to_send, now)); | ||
187 | pr_debug("netem_run: skb=%p delay=%ld\n", skb, delay); | ||
188 | |||
189 | /* if more time remaining? */ | ||
190 | if (delay > 0) { | ||
191 | mod_timer(&q->timer, jiffies + delay); | ||
192 | return 1; | ||
193 | } | ||
194 | |||
195 | __skb_unlink(skb, &q->delayed); | ||
196 | |||
197 | if (q->qdisc->enqueue(skb, q->qdisc)) { | ||
198 | sch->q.qlen--; | ||
199 | sch->qstats.drops++; | ||
200 | } | ||
201 | } | ||
202 | |||
203 | return 0; | ||
204 | } | ||
205 | |||
166 | static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch) | 206 | static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch) |
167 | { | 207 | { |
168 | struct netem_sched_data *q = qdisc_priv(sch); | 208 | struct netem_sched_data *q = qdisc_priv(sch); |
169 | struct sk_buff *skb2; | ||
170 | int ret; | 209 | int ret; |
171 | 210 | ||
172 | pr_debug("netem_enqueue skb=%p @%lu\n", skb, jiffies); | 211 | pr_debug("netem_enqueue skb=%p\n", skb); |
173 | 212 | ||
174 | /* Random packet drop 0 => none, ~0 => all */ | 213 | /* Random packet drop 0 => none, ~0 => all */ |
175 | if (q->loss && q->loss >= get_crandom(&q->loss_cor)) { | 214 | if (q->loss && q->loss >= get_crandom(&q->loss_cor)) { |
@@ -180,11 +219,21 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch) | |||
180 | } | 219 | } |
181 | 220 | ||
182 | /* Random duplication */ | 221 | /* Random duplication */ |
183 | if (q->duplicate && q->duplicate >= get_crandom(&q->dup_cor) | 222 | if (q->duplicate && q->duplicate >= get_crandom(&q->dup_cor)) { |
184 | && (skb2 = skb_clone(skb, GFP_ATOMIC)) != NULL) { | 223 | struct sk_buff *skb2; |
185 | pr_debug("netem_enqueue: dup %p\n", skb2); | 224 | |
225 | skb2 = skb_clone(skb, GFP_ATOMIC); | ||
226 | if (skb2 && netem_delay(sch, skb2) == NET_XMIT_SUCCESS) { | ||
227 | struct Qdisc *qp; | ||
228 | |||
229 | /* Since one packet can generate two packets in the | ||
230 | * queue, the parent's qlen accounting gets confused, | ||
231 | * so fix it. | ||
232 | */ | ||
233 | qp = qdisc_lookup(sch->dev, TC_H_MAJ(sch->parent)); | ||
234 | if (qp) | ||
235 | qp->q.qlen++; | ||
186 | 236 | ||
187 | if (delay_skb(sch, skb2)) { | ||
188 | sch->q.qlen++; | 237 | sch->q.qlen++; |
189 | sch->bstats.bytes += skb2->len; | 238 | sch->bstats.bytes += skb2->len; |
190 | sch->bstats.packets++; | 239 | sch->bstats.packets++; |
@@ -202,7 +251,8 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch) | |||
202 | ret = q->qdisc->enqueue(skb, q->qdisc); | 251 | ret = q->qdisc->enqueue(skb, q->qdisc); |
203 | } else { | 252 | } else { |
204 | q->counter = 0; | 253 | q->counter = 0; |
205 | ret = delay_skb(sch, skb); | 254 | ret = netem_delay(sch, skb); |
255 | netem_run(sch); | ||
206 | } | 256 | } |
207 | 257 | ||
208 | if (likely(ret == NET_XMIT_SUCCESS)) { | 258 | if (likely(ret == NET_XMIT_SUCCESS)) { |
@@ -212,6 +262,7 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch) | |||
212 | } else | 262 | } else |
213 | sch->qstats.drops++; | 263 | sch->qstats.drops++; |
214 | 264 | ||
265 | pr_debug("netem: enqueue ret %d\n", ret); | ||
215 | return ret; | 266 | return ret; |
216 | } | 267 | } |
217 | 268 | ||
@@ -241,56 +292,35 @@ static unsigned int netem_drop(struct Qdisc* sch) | |||
241 | return len; | 292 | return len; |
242 | } | 293 | } |
243 | 294 | ||
244 | /* Dequeue packet. | ||
245 | * Move all packets that are ready to send from the delay holding | ||
246 | * list to the underlying qdisc, then just call dequeue | ||
247 | */ | ||
248 | static struct sk_buff *netem_dequeue(struct Qdisc *sch) | 295 | static struct sk_buff *netem_dequeue(struct Qdisc *sch) |
249 | { | 296 | { |
250 | struct netem_sched_data *q = qdisc_priv(sch); | 297 | struct netem_sched_data *q = qdisc_priv(sch); |
251 | struct sk_buff *skb; | 298 | struct sk_buff *skb; |
299 | int pending; | ||
300 | |||
301 | pending = netem_run(sch); | ||
252 | 302 | ||
253 | skb = q->qdisc->dequeue(q->qdisc); | 303 | skb = q->qdisc->dequeue(q->qdisc); |
254 | if (skb) | 304 | if (skb) { |
305 | pr_debug("netem_dequeue: return skb=%p\n", skb); | ||
255 | sch->q.qlen--; | 306 | sch->q.qlen--; |
307 | sch->flags &= ~TCQ_F_THROTTLED; | ||
308 | } | ||
309 | else if (pending) { | ||
310 | pr_debug("netem_dequeue: throttling\n"); | ||
311 | sch->flags |= TCQ_F_THROTTLED; | ||
312 | } | ||
313 | |||
256 | return skb; | 314 | return skb; |
257 | } | 315 | } |
258 | 316 | ||
259 | static void netem_watchdog(unsigned long arg) | 317 | static void netem_watchdog(unsigned long arg) |
260 | { | 318 | { |
261 | struct Qdisc *sch = (struct Qdisc *)arg; | 319 | struct Qdisc *sch = (struct Qdisc *)arg; |
262 | struct netem_sched_data *q = qdisc_priv(sch); | ||
263 | struct net_device *dev = sch->dev; | ||
264 | struct sk_buff *skb; | ||
265 | psched_time_t now; | ||
266 | |||
267 | pr_debug("netem_watchdog: fired @%lu\n", jiffies); | ||
268 | |||
269 | spin_lock_bh(&dev->queue_lock); | ||
270 | PSCHED_GET_TIME(now); | ||
271 | |||
272 | while ((skb = skb_peek(&q->delayed)) != NULL) { | ||
273 | const struct netem_skb_cb *cb | ||
274 | = (const struct netem_skb_cb *)skb->cb; | ||
275 | long delay | ||
276 | = PSCHED_US2JIFFIE(PSCHED_TDIFF(cb->time_to_send, now)); | ||
277 | pr_debug("netem_watchdog: skb %p@%lu %ld\n", | ||
278 | skb, jiffies, delay); | ||
279 | 320 | ||
280 | /* if more time remaining? */ | 321 | pr_debug("netem_watchdog qlen=%d\n", sch->q.qlen); |
281 | if (delay > 0) { | 322 | sch->flags &= ~TCQ_F_THROTTLED; |
282 | mod_timer(&q->timer, jiffies + delay); | 323 | netif_schedule(sch->dev); |
283 | break; | ||
284 | } | ||
285 | __skb_unlink(skb, &q->delayed); | ||
286 | |||
287 | if (q->qdisc->enqueue(skb, q->qdisc)) { | ||
288 | sch->q.qlen--; | ||
289 | sch->qstats.drops++; | ||
290 | } | ||
291 | } | ||
292 | qdisc_run(dev); | ||
293 | spin_unlock_bh(&dev->queue_lock); | ||
294 | } | 324 | } |
295 | 325 | ||
296 | static void netem_reset(struct Qdisc *sch) | 326 | static void netem_reset(struct Qdisc *sch) |
@@ -301,6 +331,7 @@ static void netem_reset(struct Qdisc *sch) | |||
301 | skb_queue_purge(&q->delayed); | 331 | skb_queue_purge(&q->delayed); |
302 | 332 | ||
303 | sch->q.qlen = 0; | 333 | sch->q.qlen = 0; |
334 | sch->flags &= ~TCQ_F_THROTTLED; | ||
304 | del_timer_sync(&q->timer); | 335 | del_timer_sync(&q->timer); |
305 | } | 336 | } |
306 | 337 | ||
diff --git a/net/sched/simple.c b/net/sched/simple.c new file mode 100644 index 000000000000..3ab4c675ab5d --- /dev/null +++ b/net/sched/simple.c | |||
@@ -0,0 +1,93 @@ | |||
1 | /* | ||
2 | * net/sched/simp.c Simple example of an action | ||
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: Jamal Hadi Salim (2005) | ||
10 | * | ||
11 | */ | ||
12 | |||
13 | #include <linux/config.h> | ||
14 | #include <linux/module.h> | ||
15 | #include <linux/init.h> | ||
16 | #include <linux/kernel.h> | ||
17 | #include <linux/netdevice.h> | ||
18 | #include <linux/skbuff.h> | ||
19 | #include <linux/rtnetlink.h> | ||
20 | #include <net/pkt_sched.h> | ||
21 | |||
22 | #define TCA_ACT_SIMP 22 | ||
23 | |||
24 | /* XXX: Hide all these common elements under some macro | ||
25 | * probably | ||
26 | */ | ||
27 | #include <linux/tc_act/tc_defact.h> | ||
28 | #include <net/tc_act/tc_defact.h> | ||
29 | |||
30 | /* use generic hash table with 8 buckets */ | ||
31 | #define MY_TAB_SIZE 8 | ||
32 | #define MY_TAB_MASK (MY_TAB_SIZE - 1) | ||
33 | static u32 idx_gen; | ||
34 | static struct tcf_defact *tcf_simp_ht[MY_TAB_SIZE]; | ||
35 | static DEFINE_RWLOCK(simp_lock); | ||
36 | |||
37 | /* override the defaults */ | ||
38 | #define tcf_st tcf_defact | ||
39 | #define tc_st tc_defact | ||
40 | #define tcf_t_lock simp_lock | ||
41 | #define tcf_ht tcf_simp_ht | ||
42 | |||
43 | #define CONFIG_NET_ACT_INIT 1 | ||
44 | #include <net/pkt_act.h> | ||
45 | #include <net/act_generic.h> | ||
46 | |||
47 | static int tcf_simp(struct sk_buff **pskb, struct tc_action *a) | ||
48 | { | ||
49 | struct sk_buff *skb = *pskb; | ||
50 | struct tcf_defact *p = PRIV(a, defact); | ||
51 | |||
52 | spin_lock(&p->lock); | ||
53 | p->tm.lastuse = jiffies; | ||
54 | p->bstats.bytes += skb->len; | ||
55 | p->bstats.packets++; | ||
56 | |||
57 | /* print policy string followed by _ then packet count | ||
58 | * Example if this was the 3rd packet and the string was "hello" | ||
59 | * then it would look like "hello_3" (without quotes) | ||
60 | **/ | ||
61 | printk("simple: %s_%d\n", (char *)p->defdata, p->bstats.packets); | ||
62 | spin_unlock(&p->lock); | ||
63 | return p->action; | ||
64 | } | ||
65 | |||
66 | static struct tc_action_ops act_simp_ops = { | ||
67 | .kind = "simple", | ||
68 | .type = TCA_ACT_SIMP, | ||
69 | .capab = TCA_CAP_NONE, | ||
70 | .owner = THIS_MODULE, | ||
71 | .act = tcf_simp, | ||
72 | tca_use_default_ops | ||
73 | }; | ||
74 | |||
75 | MODULE_AUTHOR("Jamal Hadi Salim(2005)"); | ||
76 | MODULE_DESCRIPTION("Simple example action"); | ||
77 | MODULE_LICENSE("GPL"); | ||
78 | |||
79 | static int __init simp_init_module(void) | ||
80 | { | ||
81 | int ret = tcf_register_action(&act_simp_ops); | ||
82 | if (!ret) | ||
83 | printk("Simple TC action Loaded\n"); | ||
84 | return ret; | ||
85 | } | ||
86 | |||
87 | static void __exit simp_cleanup_module(void) | ||
88 | { | ||
89 | tcf_unregister_action(&act_simp_ops); | ||
90 | } | ||
91 | |||
92 | module_init(simp_init_module); | ||
93 | module_exit(simp_cleanup_module); | ||