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