xref: /openbmc/qemu/net/queue.c (revision a719a27c)
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_malloc0(sizeof(NetQueue));
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 
156     queue->delivering = 1;
157     ret = qemu_deliver_packet(sender, flags, data, size, queue->opaque);
158     queue->delivering = 0;
159 
160     return ret;
161 }
162 
163 static ssize_t qemu_net_queue_deliver_iov(NetQueue *queue,
164                                           NetClientState *sender,
165                                           unsigned flags,
166                                           const struct iovec *iov,
167                                           int iovcnt)
168 {
169     ssize_t ret = -1;
170 
171     queue->delivering = 1;
172     ret = qemu_deliver_packet_iov(sender, flags, iov, iovcnt, queue->opaque);
173     queue->delivering = 0;
174 
175     return ret;
176 }
177 
178 ssize_t qemu_net_queue_send(NetQueue *queue,
179                             NetClientState *sender,
180                             unsigned flags,
181                             const uint8_t *data,
182                             size_t size,
183                             NetPacketSent *sent_cb)
184 {
185     ssize_t ret;
186 
187     if (queue->delivering || !qemu_can_send_packet(sender)) {
188         qemu_net_queue_append(queue, sender, flags, data, size, sent_cb);
189         return 0;
190     }
191 
192     ret = qemu_net_queue_deliver(queue, sender, flags, data, size);
193     if (ret == 0) {
194         qemu_net_queue_append(queue, sender, flags, data, size, sent_cb);
195         return 0;
196     }
197 
198     qemu_net_queue_flush(queue);
199 
200     return ret;
201 }
202 
203 ssize_t qemu_net_queue_send_iov(NetQueue *queue,
204                                 NetClientState *sender,
205                                 unsigned flags,
206                                 const struct iovec *iov,
207                                 int iovcnt,
208                                 NetPacketSent *sent_cb)
209 {
210     ssize_t ret;
211 
212     if (queue->delivering || !qemu_can_send_packet(sender)) {
213         qemu_net_queue_append_iov(queue, sender, flags, iov, iovcnt, sent_cb);
214         return 0;
215     }
216 
217     ret = qemu_net_queue_deliver_iov(queue, sender, flags, iov, iovcnt);
218     if (ret == 0) {
219         qemu_net_queue_append_iov(queue, sender, flags, iov, iovcnt, sent_cb);
220         return 0;
221     }
222 
223     qemu_net_queue_flush(queue);
224 
225     return ret;
226 }
227 
228 void qemu_net_queue_purge(NetQueue *queue, NetClientState *from)
229 {
230     NetPacket *packet, *next;
231 
232     QTAILQ_FOREACH_SAFE(packet, &queue->packets, entry, next) {
233         if (packet->sender == from) {
234             QTAILQ_REMOVE(&queue->packets, packet, entry);
235             queue->nq_count--;
236             g_free(packet);
237         }
238     }
239 }
240 
241 bool qemu_net_queue_flush(NetQueue *queue)
242 {
243     while (!QTAILQ_EMPTY(&queue->packets)) {
244         NetPacket *packet;
245         int ret;
246 
247         packet = QTAILQ_FIRST(&queue->packets);
248         QTAILQ_REMOVE(&queue->packets, packet, entry);
249         queue->nq_count--;
250 
251         ret = qemu_net_queue_deliver(queue,
252                                      packet->sender,
253                                      packet->flags,
254                                      packet->data,
255                                      packet->size);
256         if (ret == 0) {
257             queue->nq_count++;
258             QTAILQ_INSERT_HEAD(&queue->packets, packet, entry);
259             return false;
260         }
261 
262         if (packet->sent_cb) {
263             packet->sent_cb(packet->sender, ret);
264         }
265 
266         g_free(packet);
267     }
268     return true;
269 }
270