debuggers.hg

view tools/remus/kmod/sch_queue.c @ 21220:373daaeb636e

Remus: make ebt_imq and sch_queue compatible with pvops

Signed-off-by: Brendan Cully <brendan@cs.ubc.ca>
author Keir Fraser <keir.fraser@citrix.com>
date Thu Apr 15 08:42:08 2010 +0100 (2010-04-15)
parents 989014ce7b4a
children
line source
1 /*
2 * sch_queue.c Queue traffic until an explicit release command
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 * The operation of the buffer is as follows:
10 * When a checkpoint begins, a barrier is inserted into the
11 * network queue by a netlink request (it operates by storing
12 * a pointer to the next packet which arrives and blocking dequeue
13 * when that packet is at the head of the queue).
14 * When a checkpoint completes (the backup acknowledges receipt),
15 * currently-queued packets are released.
16 * So it supports two operations, barrier and release.
17 */
19 #include <linux/version.h>
20 #if LINUX_VERSION_CODE == KERNEL_VERSION(2,6,18)
21 # define OLDKERNEL
22 #endif
24 #ifdef OLDKERNEL
25 # include <linux/config.h>
26 #endif
27 #include <linux/module.h>
28 #include <linux/types.h>
29 #include <linux/kernel.h>
30 #include <linux/errno.h>
31 #include <linux/netdevice.h>
32 #include <linux/skbuff.h>
33 #include <net/pkt_sched.h>
35 #ifdef OLDKERNEL
36 # define compatnlattr rtattr
37 # define compatnllen RTA_PAYLOAD
38 # define compatnldata RTA_DATA
39 #else
40 # include <xen/features.h>
41 # define compatnlattr nlattr
42 # define compatnllen nla_len
43 # define compatnldata nla_data
44 #endif
46 /* xenbus directory */
47 #define FIFO_BUF (10*1024*1024)
49 #define TCQ_CHECKPOINT 0
50 #define TCQ_DEQUEUE 1
52 struct queue_sched_data {
53 /* this packet is the first packet which should not be delivered.
54 * If it is NULL, queue_enqueue will set it to the next packet it sees. */
55 struct sk_buff *stop;
56 };
58 struct tc_queue_qopt {
59 /* 0: reset stop packet pointer
60 * 1: dequeue to stop pointer */
61 int action;
62 };
64 #ifdef OLDKERNEL
65 /* borrowed from drivers/xen/netback/loopback.c */
66 #ifdef CONFIG_X86
67 static int is_foreign(unsigned long pfn)
68 {
69 /* NB. Play it safe for auto-translation mode. */
70 return (xen_feature(XENFEAT_auto_translated_physmap) ||
71 (phys_to_machine_mapping[pfn] & FOREIGN_FRAME_BIT));
72 }
73 #else
74 /* How to detect a foreign mapping? Play it safe. */
75 #define is_foreign(pfn) (1)
76 #endif
78 static int skb_remove_foreign_references(struct sk_buff *skb)
79 {
80 struct page *page;
81 unsigned long pfn;
82 int i, off;
83 char *vaddr;
85 BUG_ON(skb_shinfo(skb)->frag_list);
87 for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
88 pfn = page_to_pfn(skb_shinfo(skb)->frags[i].page);
89 if (!is_foreign(pfn))
90 continue;
91 /*
92 printk("foreign ref found\n");
93 */
94 page = alloc_page(GFP_ATOMIC | __GFP_NOWARN);
95 if (unlikely(!page))
96 return 0;
98 vaddr = kmap_skb_frag(&skb_shinfo(skb)->frags[i]);
99 off = skb_shinfo(skb)->frags[i].page_offset;
100 memcpy(page_address(page) + off, vaddr + off,
101 skb_shinfo(skb)->frags[i].size);
102 kunmap_skb_frag(vaddr);
104 put_page(skb_shinfo(skb)->frags[i].page);
105 skb_shinfo(skb)->frags[i].page = page;
106 }
108 return 1;
109 }
110 #else /* OLDKERNEL */
111 static int skb_remove_foreign_references(struct sk_buff *skb)
112 {
113 return !skb_linearize(skb);
114 }
115 #endif /* OLDKERNEL */
117 static int queue_enqueue(struct sk_buff *skb, struct Qdisc* sch)
118 {
119 struct queue_sched_data *q = qdisc_priv(sch);
121 if (likely(sch->qstats.backlog + skb->len <= FIFO_BUF))
122 {
123 if (!q->stop)
124 q->stop = skb;
126 if (!skb_remove_foreign_references(skb)) {
127 printk("error removing foreign ref\n");
128 return qdisc_reshape_fail(skb, sch);
129 }
131 return qdisc_enqueue_tail(skb, sch);
132 }
133 printk("queue reported full: %d,%d\n", sch->qstats.backlog, skb->len);
135 return qdisc_reshape_fail(skb, sch);
136 }
138 /* dequeue doesn't actually dequeue until the release command is
139 * received. */
140 static struct sk_buff *queue_dequeue(struct Qdisc* sch)
141 {
142 struct queue_sched_data *q = qdisc_priv(sch);
143 struct sk_buff* peek;
144 /*
145 struct timeval tv;
147 if (!q->stop) {
148 do_gettimeofday(&tv);
149 printk("packet dequeued at %lu.%06lu\n", tv.tv_sec, tv.tv_usec);
150 }
151 */
153 if (sch->flags & TCQ_F_THROTTLED)
154 return NULL;
156 peek = (struct sk_buff *)((sch->q).next);
158 /* this pointer comparison may be shady */
159 if (peek == q->stop) {
160 /*
161 do_gettimeofday(&tv);
162 printk("stop packet at %lu.%06lu\n", tv.tv_sec, tv.tv_usec);
163 */
165 /* this is the tail of the last round. Release it and block the queue */
166 sch->flags |= TCQ_F_THROTTLED;
167 return NULL;
168 }
170 return qdisc_dequeue_head(sch);
171 }
173 static int queue_init(struct Qdisc *sch, struct compatnlattr *opt)
174 {
175 sch->flags |= TCQ_F_THROTTLED;
177 return 0;
178 }
180 /* receives two messages:
181 * 0: checkpoint queue (set stop to next packet)
182 * 1: dequeue until stop */
183 static int queue_change(struct Qdisc* sch, struct compatnlattr* opt)
184 {
185 struct queue_sched_data *q = qdisc_priv(sch);
186 struct tc_queue_qopt* msg;
187 /*
188 struct timeval tv;
189 */
191 if (!opt || compatnllen(opt) < sizeof(*msg))
192 return -EINVAL;
194 msg = compatnldata(opt);
196 if (msg->action == TCQ_CHECKPOINT) {
197 /* reset stop */
198 q->stop = NULL;
199 } else if (msg->action == TCQ_DEQUEUE) {
200 /* dequeue */
201 sch->flags &= ~TCQ_F_THROTTLED;
202 #ifdef OLDKERNEL
203 netif_schedule(sch->dev);
204 #else
205 netif_schedule_queue(sch->dev_queue);
206 #endif
207 /*
208 do_gettimeofday(&tv);
209 printk("queue release at %lu.%06lu (%d bytes)\n", tv.tv_sec, tv.tv_usec,
210 sch->qstats.backlog);
211 */
212 } else {
213 return -EINVAL;
214 }
216 return 0;
217 }
219 struct Qdisc_ops queue_qdisc_ops = {
220 .id = "queue",
221 .priv_size = sizeof(struct queue_sched_data),
222 .enqueue = queue_enqueue,
223 .dequeue = queue_dequeue,
224 #ifndef OLDKERNEL
225 .peek = qdisc_peek_head,
226 #endif
227 .init = queue_init,
228 .change = queue_change,
229 .owner = THIS_MODULE,
230 };
232 static int __init queue_module_init(void)
233 {
234 printk("loading queue\n");
235 return register_qdisc(&queue_qdisc_ops);
236 }
238 static void __exit queue_module_exit(void)
239 {
240 printk("queue unloaded\n");
241 unregister_qdisc(&queue_qdisc_ops);
242 }
243 module_init(queue_module_init)
244 module_exit(queue_module_exit)
245 MODULE_LICENSE("GPL");