root / net / queue.c @ 6ce2d77a
History | View | Annotate | Download (7.5 kB)
1 | f7105843 | Mark McLoughlin | /*
|
---|---|---|---|
2 | f7105843 | Mark McLoughlin | * Copyright (c) 2003-2008 Fabrice Bellard
|
3 | f7105843 | Mark McLoughlin | * Copyright (c) 2009 Red Hat, Inc.
|
4 | f7105843 | Mark McLoughlin | *
|
5 | f7105843 | Mark McLoughlin | * Permission is hereby granted, free of charge, to any person obtaining a copy
|
6 | f7105843 | Mark McLoughlin | * of this software and associated documentation files (the "Software"), to deal
|
7 | f7105843 | Mark McLoughlin | * in the Software without restriction, including without limitation the rights
|
8 | f7105843 | Mark McLoughlin | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9 | f7105843 | Mark McLoughlin | * copies of the Software, and to permit persons to whom the Software is
|
10 | f7105843 | Mark McLoughlin | * furnished to do so, subject to the following conditions:
|
11 | f7105843 | Mark McLoughlin | *
|
12 | f7105843 | Mark McLoughlin | * The above copyright notice and this permission notice shall be included in
|
13 | f7105843 | Mark McLoughlin | * all copies or substantial portions of the Software.
|
14 | f7105843 | Mark McLoughlin | *
|
15 | f7105843 | Mark McLoughlin | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16 | f7105843 | Mark McLoughlin | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17 | f7105843 | Mark McLoughlin | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
18 | f7105843 | Mark McLoughlin | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19 | f7105843 | Mark McLoughlin | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20 | f7105843 | Mark McLoughlin | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21 | f7105843 | Mark McLoughlin | * THE SOFTWARE.
|
22 | f7105843 | Mark McLoughlin | */
|
23 | f7105843 | Mark McLoughlin | |
24 | e1144d00 | Mark McLoughlin | #include "net/queue.h" |
25 | f7105843 | Mark McLoughlin | #include "qemu-queue.h" |
26 | f7105843 | Mark McLoughlin | |
27 | f7105843 | Mark McLoughlin | /* The delivery handler may only return zero if it will call
|
28 | f7105843 | Mark McLoughlin | * qemu_net_queue_flush() when it determines that it is once again able
|
29 | f7105843 | Mark McLoughlin | * to deliver packets. It must also call qemu_net_queue_purge() in its
|
30 | f7105843 | Mark McLoughlin | * cleanup path.
|
31 | f7105843 | Mark McLoughlin | *
|
32 | f7105843 | Mark McLoughlin | * If a sent callback is provided to send(), the caller must handle a
|
33 | f7105843 | Mark McLoughlin | * zero return from the delivery handler by not sending any more packets
|
34 | f7105843 | Mark McLoughlin | * until we have invoked the callback. Only in that case will we queue
|
35 | f7105843 | Mark McLoughlin | * the packet.
|
36 | f7105843 | Mark McLoughlin | *
|
37 | f7105843 | Mark McLoughlin | * If a sent callback isn't provided, we just drop the packet to avoid
|
38 | f7105843 | Mark McLoughlin | * unbounded queueing.
|
39 | f7105843 | Mark McLoughlin | */
|
40 | f7105843 | Mark McLoughlin | |
41 | f7105843 | Mark McLoughlin | struct NetPacket {
|
42 | f7105843 | Mark McLoughlin | QTAILQ_ENTRY(NetPacket) entry; |
43 | f7105843 | Mark McLoughlin | VLANClientState *sender; |
44 | c0b8e49c | Mark McLoughlin | unsigned flags;
|
45 | f7105843 | Mark McLoughlin | int size;
|
46 | f7105843 | Mark McLoughlin | NetPacketSent *sent_cb; |
47 | f7105843 | Mark McLoughlin | uint8_t data[0];
|
48 | f7105843 | Mark McLoughlin | }; |
49 | f7105843 | Mark McLoughlin | |
50 | f7105843 | Mark McLoughlin | struct NetQueue {
|
51 | f7105843 | Mark McLoughlin | NetPacketDeliver *deliver; |
52 | f7105843 | Mark McLoughlin | NetPacketDeliverIOV *deliver_iov; |
53 | f7105843 | Mark McLoughlin | void *opaque;
|
54 | f7105843 | Mark McLoughlin | |
55 | f7105843 | Mark McLoughlin | QTAILQ_HEAD(packets, NetPacket) packets; |
56 | f7105843 | Mark McLoughlin | |
57 | f7105843 | Mark McLoughlin | unsigned delivering : 1; |
58 | f7105843 | Mark McLoughlin | }; |
59 | f7105843 | Mark McLoughlin | |
60 | f7105843 | Mark McLoughlin | NetQueue *qemu_new_net_queue(NetPacketDeliver *deliver, |
61 | f7105843 | Mark McLoughlin | NetPacketDeliverIOV *deliver_iov, |
62 | f7105843 | Mark McLoughlin | void *opaque)
|
63 | f7105843 | Mark McLoughlin | { |
64 | f7105843 | Mark McLoughlin | NetQueue *queue; |
65 | f7105843 | Mark McLoughlin | |
66 | 7267c094 | Anthony Liguori | queue = g_malloc0(sizeof(NetQueue));
|
67 | f7105843 | Mark McLoughlin | |
68 | f7105843 | Mark McLoughlin | queue->deliver = deliver; |
69 | f7105843 | Mark McLoughlin | queue->deliver_iov = deliver_iov; |
70 | f7105843 | Mark McLoughlin | queue->opaque = opaque; |
71 | f7105843 | Mark McLoughlin | |
72 | f7105843 | Mark McLoughlin | QTAILQ_INIT(&queue->packets); |
73 | f7105843 | Mark McLoughlin | |
74 | f7105843 | Mark McLoughlin | queue->delivering = 0;
|
75 | f7105843 | Mark McLoughlin | |
76 | f7105843 | Mark McLoughlin | return queue;
|
77 | f7105843 | Mark McLoughlin | } |
78 | f7105843 | Mark McLoughlin | |
79 | f7105843 | Mark McLoughlin | void qemu_del_net_queue(NetQueue *queue)
|
80 | f7105843 | Mark McLoughlin | { |
81 | f7105843 | Mark McLoughlin | NetPacket *packet, *next; |
82 | f7105843 | Mark McLoughlin | |
83 | f7105843 | Mark McLoughlin | QTAILQ_FOREACH_SAFE(packet, &queue->packets, entry, next) { |
84 | f7105843 | Mark McLoughlin | QTAILQ_REMOVE(&queue->packets, packet, entry); |
85 | 7267c094 | Anthony Liguori | g_free(packet); |
86 | f7105843 | Mark McLoughlin | } |
87 | f7105843 | Mark McLoughlin | |
88 | 7267c094 | Anthony Liguori | g_free(queue); |
89 | f7105843 | Mark McLoughlin | } |
90 | f7105843 | Mark McLoughlin | |
91 | f7105843 | Mark McLoughlin | static ssize_t qemu_net_queue_append(NetQueue *queue,
|
92 | f7105843 | Mark McLoughlin | VLANClientState *sender, |
93 | c0b8e49c | Mark McLoughlin | unsigned flags,
|
94 | f7105843 | Mark McLoughlin | const uint8_t *buf,
|
95 | f7105843 | Mark McLoughlin | size_t size, |
96 | f7105843 | Mark McLoughlin | NetPacketSent *sent_cb) |
97 | f7105843 | Mark McLoughlin | { |
98 | f7105843 | Mark McLoughlin | NetPacket *packet; |
99 | f7105843 | Mark McLoughlin | |
100 | 7267c094 | Anthony Liguori | packet = g_malloc(sizeof(NetPacket) + size);
|
101 | f7105843 | Mark McLoughlin | packet->sender = sender; |
102 | c0b8e49c | Mark McLoughlin | packet->flags = flags; |
103 | f7105843 | Mark McLoughlin | packet->size = size; |
104 | f7105843 | Mark McLoughlin | packet->sent_cb = sent_cb; |
105 | f7105843 | Mark McLoughlin | memcpy(packet->data, buf, size); |
106 | f7105843 | Mark McLoughlin | |
107 | f7105843 | Mark McLoughlin | QTAILQ_INSERT_TAIL(&queue->packets, packet, entry); |
108 | f7105843 | Mark McLoughlin | |
109 | f7105843 | Mark McLoughlin | return size;
|
110 | f7105843 | Mark McLoughlin | } |
111 | f7105843 | Mark McLoughlin | |
112 | f7105843 | Mark McLoughlin | static ssize_t qemu_net_queue_append_iov(NetQueue *queue,
|
113 | f7105843 | Mark McLoughlin | VLANClientState *sender, |
114 | c0b8e49c | Mark McLoughlin | unsigned flags,
|
115 | f7105843 | Mark McLoughlin | const struct iovec *iov, |
116 | f7105843 | Mark McLoughlin | int iovcnt,
|
117 | f7105843 | Mark McLoughlin | NetPacketSent *sent_cb) |
118 | f7105843 | Mark McLoughlin | { |
119 | f7105843 | Mark McLoughlin | NetPacket *packet; |
120 | f7105843 | Mark McLoughlin | size_t max_len = 0;
|
121 | f7105843 | Mark McLoughlin | int i;
|
122 | f7105843 | Mark McLoughlin | |
123 | f7105843 | Mark McLoughlin | for (i = 0; i < iovcnt; i++) { |
124 | f7105843 | Mark McLoughlin | max_len += iov[i].iov_len; |
125 | f7105843 | Mark McLoughlin | } |
126 | f7105843 | Mark McLoughlin | |
127 | 7267c094 | Anthony Liguori | packet = g_malloc(sizeof(NetPacket) + max_len);
|
128 | f7105843 | Mark McLoughlin | packet->sender = sender; |
129 | f7105843 | Mark McLoughlin | packet->sent_cb = sent_cb; |
130 | c0b8e49c | Mark McLoughlin | packet->flags = flags; |
131 | f7105843 | Mark McLoughlin | packet->size = 0;
|
132 | f7105843 | Mark McLoughlin | |
133 | f7105843 | Mark McLoughlin | for (i = 0; i < iovcnt; i++) { |
134 | f7105843 | Mark McLoughlin | size_t len = iov[i].iov_len; |
135 | f7105843 | Mark McLoughlin | |
136 | f7105843 | Mark McLoughlin | memcpy(packet->data + packet->size, iov[i].iov_base, len); |
137 | f7105843 | Mark McLoughlin | packet->size += len; |
138 | f7105843 | Mark McLoughlin | } |
139 | f7105843 | Mark McLoughlin | |
140 | f7105843 | Mark McLoughlin | QTAILQ_INSERT_TAIL(&queue->packets, packet, entry); |
141 | f7105843 | Mark McLoughlin | |
142 | f7105843 | Mark McLoughlin | return packet->size;
|
143 | f7105843 | Mark McLoughlin | } |
144 | f7105843 | Mark McLoughlin | |
145 | f7105843 | Mark McLoughlin | static ssize_t qemu_net_queue_deliver(NetQueue *queue,
|
146 | f7105843 | Mark McLoughlin | VLANClientState *sender, |
147 | c0b8e49c | Mark McLoughlin | unsigned flags,
|
148 | f7105843 | Mark McLoughlin | const uint8_t *data,
|
149 | f7105843 | Mark McLoughlin | size_t size) |
150 | f7105843 | Mark McLoughlin | { |
151 | f7105843 | Mark McLoughlin | ssize_t ret = -1;
|
152 | f7105843 | Mark McLoughlin | |
153 | f7105843 | Mark McLoughlin | queue->delivering = 1;
|
154 | c0b8e49c | Mark McLoughlin | ret = queue->deliver(sender, flags, data, size, queue->opaque); |
155 | f7105843 | Mark McLoughlin | queue->delivering = 0;
|
156 | f7105843 | Mark McLoughlin | |
157 | f7105843 | Mark McLoughlin | return ret;
|
158 | f7105843 | Mark McLoughlin | } |
159 | f7105843 | Mark McLoughlin | |
160 | f7105843 | Mark McLoughlin | static ssize_t qemu_net_queue_deliver_iov(NetQueue *queue,
|
161 | f7105843 | Mark McLoughlin | VLANClientState *sender, |
162 | c0b8e49c | Mark McLoughlin | unsigned flags,
|
163 | f7105843 | Mark McLoughlin | const struct iovec *iov, |
164 | f7105843 | Mark McLoughlin | int iovcnt)
|
165 | f7105843 | Mark McLoughlin | { |
166 | f7105843 | Mark McLoughlin | ssize_t ret = -1;
|
167 | f7105843 | Mark McLoughlin | |
168 | f7105843 | Mark McLoughlin | queue->delivering = 1;
|
169 | c0b8e49c | Mark McLoughlin | ret = queue->deliver_iov(sender, flags, iov, iovcnt, queue->opaque); |
170 | f7105843 | Mark McLoughlin | queue->delivering = 0;
|
171 | f7105843 | Mark McLoughlin | |
172 | f7105843 | Mark McLoughlin | return ret;
|
173 | f7105843 | Mark McLoughlin | } |
174 | f7105843 | Mark McLoughlin | |
175 | f7105843 | Mark McLoughlin | ssize_t qemu_net_queue_send(NetQueue *queue, |
176 | f7105843 | Mark McLoughlin | VLANClientState *sender, |
177 | c0b8e49c | Mark McLoughlin | unsigned flags,
|
178 | f7105843 | Mark McLoughlin | const uint8_t *data,
|
179 | f7105843 | Mark McLoughlin | size_t size, |
180 | f7105843 | Mark McLoughlin | NetPacketSent *sent_cb) |
181 | f7105843 | Mark McLoughlin | { |
182 | f7105843 | Mark McLoughlin | ssize_t ret; |
183 | f7105843 | Mark McLoughlin | |
184 | f7105843 | Mark McLoughlin | if (queue->delivering) {
|
185 | c0b8e49c | Mark McLoughlin | return qemu_net_queue_append(queue, sender, flags, data, size, NULL); |
186 | f7105843 | Mark McLoughlin | } |
187 | f7105843 | Mark McLoughlin | |
188 | c0b8e49c | Mark McLoughlin | ret = qemu_net_queue_deliver(queue, sender, flags, data, size); |
189 | 839f368f | Mark McLoughlin | if (ret == 0) { |
190 | c0b8e49c | Mark McLoughlin | qemu_net_queue_append(queue, sender, flags, data, size, sent_cb); |
191 | f7105843 | Mark McLoughlin | return 0; |
192 | f7105843 | Mark McLoughlin | } |
193 | f7105843 | Mark McLoughlin | |
194 | f7105843 | Mark McLoughlin | qemu_net_queue_flush(queue); |
195 | f7105843 | Mark McLoughlin | |
196 | f7105843 | Mark McLoughlin | return ret;
|
197 | f7105843 | Mark McLoughlin | } |
198 | f7105843 | Mark McLoughlin | |
199 | f7105843 | Mark McLoughlin | ssize_t qemu_net_queue_send_iov(NetQueue *queue, |
200 | f7105843 | Mark McLoughlin | VLANClientState *sender, |
201 | c0b8e49c | Mark McLoughlin | unsigned flags,
|
202 | f7105843 | Mark McLoughlin | const struct iovec *iov, |
203 | f7105843 | Mark McLoughlin | int iovcnt,
|
204 | f7105843 | Mark McLoughlin | NetPacketSent *sent_cb) |
205 | f7105843 | Mark McLoughlin | { |
206 | f7105843 | Mark McLoughlin | ssize_t ret; |
207 | f7105843 | Mark McLoughlin | |
208 | f7105843 | Mark McLoughlin | if (queue->delivering) {
|
209 | c0b8e49c | Mark McLoughlin | return qemu_net_queue_append_iov(queue, sender, flags, iov, iovcnt, NULL); |
210 | f7105843 | Mark McLoughlin | } |
211 | f7105843 | Mark McLoughlin | |
212 | c0b8e49c | Mark McLoughlin | ret = qemu_net_queue_deliver_iov(queue, sender, flags, iov, iovcnt); |
213 | 839f368f | Mark McLoughlin | if (ret == 0) { |
214 | c0b8e49c | Mark McLoughlin | qemu_net_queue_append_iov(queue, sender, flags, iov, iovcnt, sent_cb); |
215 | f7105843 | Mark McLoughlin | return 0; |
216 | f7105843 | Mark McLoughlin | } |
217 | f7105843 | Mark McLoughlin | |
218 | f7105843 | Mark McLoughlin | qemu_net_queue_flush(queue); |
219 | f7105843 | Mark McLoughlin | |
220 | f7105843 | Mark McLoughlin | return ret;
|
221 | f7105843 | Mark McLoughlin | } |
222 | f7105843 | Mark McLoughlin | |
223 | f7105843 | Mark McLoughlin | void qemu_net_queue_purge(NetQueue *queue, VLANClientState *from)
|
224 | f7105843 | Mark McLoughlin | { |
225 | f7105843 | Mark McLoughlin | NetPacket *packet, *next; |
226 | f7105843 | Mark McLoughlin | |
227 | f7105843 | Mark McLoughlin | QTAILQ_FOREACH_SAFE(packet, &queue->packets, entry, next) { |
228 | f7105843 | Mark McLoughlin | if (packet->sender == from) {
|
229 | f7105843 | Mark McLoughlin | QTAILQ_REMOVE(&queue->packets, packet, entry); |
230 | 7267c094 | Anthony Liguori | g_free(packet); |
231 | f7105843 | Mark McLoughlin | } |
232 | f7105843 | Mark McLoughlin | } |
233 | f7105843 | Mark McLoughlin | } |
234 | f7105843 | Mark McLoughlin | |
235 | f7105843 | Mark McLoughlin | void qemu_net_queue_flush(NetQueue *queue)
|
236 | f7105843 | Mark McLoughlin | { |
237 | f7105843 | Mark McLoughlin | while (!QTAILQ_EMPTY(&queue->packets)) {
|
238 | f7105843 | Mark McLoughlin | NetPacket *packet; |
239 | f7105843 | Mark McLoughlin | int ret;
|
240 | f7105843 | Mark McLoughlin | |
241 | f7105843 | Mark McLoughlin | packet = QTAILQ_FIRST(&queue->packets); |
242 | f7105843 | Mark McLoughlin | QTAILQ_REMOVE(&queue->packets, packet, entry); |
243 | f7105843 | Mark McLoughlin | |
244 | f7105843 | Mark McLoughlin | ret = qemu_net_queue_deliver(queue, |
245 | f7105843 | Mark McLoughlin | packet->sender, |
246 | c0b8e49c | Mark McLoughlin | packet->flags, |
247 | f7105843 | Mark McLoughlin | packet->data, |
248 | f7105843 | Mark McLoughlin | packet->size); |
249 | 839f368f | Mark McLoughlin | if (ret == 0) { |
250 | f7105843 | Mark McLoughlin | QTAILQ_INSERT_HEAD(&queue->packets, packet, entry); |
251 | f7105843 | Mark McLoughlin | break;
|
252 | f7105843 | Mark McLoughlin | } |
253 | f7105843 | Mark McLoughlin | |
254 | f7105843 | Mark McLoughlin | if (packet->sent_cb) {
|
255 | f7105843 | Mark McLoughlin | packet->sent_cb(packet->sender, ret); |
256 | f7105843 | Mark McLoughlin | } |
257 | f7105843 | Mark McLoughlin | |
258 | 7267c094 | Anthony Liguori | g_free(packet); |
259 | f7105843 | Mark McLoughlin | } |
260 | f7105843 | Mark McLoughlin | } |