Statistics
| Branch: | Revision:

root / net / queue.c @ 54cdaa1b

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 f7105843 Mark McLoughlin
    queue = qemu_mallocz(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 f7105843 Mark McLoughlin
        qemu_free(packet);
86 f7105843 Mark McLoughlin
    }
87 f7105843 Mark McLoughlin
88 f7105843 Mark McLoughlin
    qemu_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 f7105843 Mark McLoughlin
    packet = qemu_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 f7105843 Mark McLoughlin
    packet = qemu_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 f7105843 Mark McLoughlin
            qemu_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 f7105843 Mark McLoughlin
        qemu_free(packet);
259 f7105843 Mark McLoughlin
    }
260 f7105843 Mark McLoughlin
}