1e1144d00SMark McLoughlin /*
2e1144d00SMark McLoughlin * Copyright (c) 2003-2008 Fabrice Bellard
3e1144d00SMark McLoughlin * Copyright (c) 2009 Red Hat, Inc.
4e1144d00SMark McLoughlin *
5e1144d00SMark McLoughlin * Permission is hereby granted, free of charge, to any person obtaining a copy
6e1144d00SMark McLoughlin * of this software and associated documentation files (the "Software"), to deal
7e1144d00SMark McLoughlin * in the Software without restriction, including without limitation the rights
8e1144d00SMark McLoughlin * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9e1144d00SMark McLoughlin * copies of the Software, and to permit persons to whom the Software is
10e1144d00SMark McLoughlin * furnished to do so, subject to the following conditions:
11e1144d00SMark McLoughlin *
12e1144d00SMark McLoughlin * The above copyright notice and this permission notice shall be included in
13e1144d00SMark McLoughlin * all copies or substantial portions of the Software.
14e1144d00SMark McLoughlin *
15e1144d00SMark McLoughlin * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16e1144d00SMark McLoughlin * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17e1144d00SMark McLoughlin * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18e1144d00SMark McLoughlin * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19e1144d00SMark McLoughlin * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20e1144d00SMark McLoughlin * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21e1144d00SMark McLoughlin * THE SOFTWARE.
22e1144d00SMark McLoughlin */
23e1144d00SMark McLoughlin
242744d920SPeter Maydell #include "qemu/osdep.h"
25e1144d00SMark McLoughlin #include "net/queue.h"
261de7afc9SPaolo Bonzini #include "qemu/queue.h"
271422e32dSPaolo Bonzini #include "net/net.h"
28e1144d00SMark McLoughlin
29e1144d00SMark McLoughlin /* The delivery handler may only return zero if it will call
30e1144d00SMark McLoughlin * qemu_net_queue_flush() when it determines that it is once again able
31e1144d00SMark McLoughlin * to deliver packets. It must also call qemu_net_queue_purge() in its
32e1144d00SMark McLoughlin * cleanup path.
33e1144d00SMark McLoughlin *
34e1144d00SMark McLoughlin * If a sent callback is provided to send(), the caller must handle a
35e1144d00SMark McLoughlin * zero return from the delivery handler by not sending any more packets
36e1144d00SMark McLoughlin * until we have invoked the callback. Only in that case will we queue
37e1144d00SMark McLoughlin * the packet.
38e1144d00SMark McLoughlin *
39e1144d00SMark McLoughlin * If a sent callback isn't provided, we just drop the packet to avoid
40e1144d00SMark McLoughlin * unbounded queueing.
41e1144d00SMark McLoughlin */
42e1144d00SMark McLoughlin
43e1144d00SMark McLoughlin struct NetPacket {
44e1144d00SMark McLoughlin QTAILQ_ENTRY(NetPacket) entry;
454e68f7a0SStefan Hajnoczi NetClientState *sender;
46e1144d00SMark McLoughlin unsigned flags;
47e1144d00SMark McLoughlin int size;
48e1144d00SMark McLoughlin NetPacketSent *sent_cb;
49f7795e40SPhilippe Mathieu-Daudé uint8_t data[];
50e1144d00SMark McLoughlin };
51e1144d00SMark McLoughlin
52e1144d00SMark McLoughlin struct NetQueue {
53e1144d00SMark McLoughlin void *opaque;
547d91ddd2SLuigi Rizzo uint32_t nq_maxlen;
557d91ddd2SLuigi Rizzo uint32_t nq_count;
563e033a46SYang Hongyang NetQueueDeliverFunc *deliver;
57e1144d00SMark McLoughlin
58b58deb34SPaolo Bonzini QTAILQ_HEAD(, NetPacket) packets;
59e1144d00SMark McLoughlin
60e1144d00SMark McLoughlin unsigned delivering : 1;
61e1144d00SMark McLoughlin };
62e1144d00SMark McLoughlin
qemu_new_net_queue(NetQueueDeliverFunc * deliver,void * opaque)633e033a46SYang Hongyang NetQueue *qemu_new_net_queue(NetQueueDeliverFunc *deliver, void *opaque)
64e1144d00SMark McLoughlin {
65e1144d00SMark McLoughlin NetQueue *queue;
66e1144d00SMark McLoughlin
6758889fe5SMarkus Armbruster queue = g_new0(NetQueue, 1);
68e1144d00SMark McLoughlin
69e1144d00SMark McLoughlin queue->opaque = opaque;
707d91ddd2SLuigi Rizzo queue->nq_maxlen = 10000;
717d91ddd2SLuigi Rizzo queue->nq_count = 0;
723e033a46SYang Hongyang queue->deliver = deliver;
73e1144d00SMark McLoughlin
74e1144d00SMark McLoughlin QTAILQ_INIT(&queue->packets);
75e1144d00SMark McLoughlin
76e1144d00SMark McLoughlin queue->delivering = 0;
77e1144d00SMark McLoughlin
78e1144d00SMark McLoughlin return queue;
79e1144d00SMark McLoughlin }
80e1144d00SMark McLoughlin
qemu_del_net_queue(NetQueue * queue)81e1144d00SMark McLoughlin void qemu_del_net_queue(NetQueue *queue)
82e1144d00SMark McLoughlin {
83e1144d00SMark McLoughlin NetPacket *packet, *next;
84e1144d00SMark McLoughlin
85e1144d00SMark McLoughlin QTAILQ_FOREACH_SAFE(packet, &queue->packets, entry, next) {
86e1144d00SMark McLoughlin QTAILQ_REMOVE(&queue->packets, packet, entry);
877267c094SAnthony Liguori g_free(packet);
88e1144d00SMark McLoughlin }
89e1144d00SMark McLoughlin
907267c094SAnthony Liguori g_free(queue);
91e1144d00SMark McLoughlin }
92e1144d00SMark McLoughlin
qemu_net_queue_append(NetQueue * queue,NetClientState * sender,unsigned flags,const uint8_t * buf,size_t size,NetPacketSent * sent_cb)9306b5f36dSStefan Hajnoczi static void qemu_net_queue_append(NetQueue *queue,
944e68f7a0SStefan Hajnoczi NetClientState *sender,
95e1144d00SMark McLoughlin unsigned flags,
96e1144d00SMark McLoughlin const uint8_t *buf,
97e1144d00SMark McLoughlin size_t size,
98e1144d00SMark McLoughlin NetPacketSent *sent_cb)
99e1144d00SMark McLoughlin {
100e1144d00SMark McLoughlin NetPacket *packet;
101e1144d00SMark McLoughlin
1027d91ddd2SLuigi Rizzo if (queue->nq_count >= queue->nq_maxlen && !sent_cb) {
1037d91ddd2SLuigi Rizzo return; /* drop if queue full and no callback */
1047d91ddd2SLuigi Rizzo }
1057267c094SAnthony Liguori packet = g_malloc(sizeof(NetPacket) + size);
106e1144d00SMark McLoughlin packet->sender = sender;
107e1144d00SMark McLoughlin packet->flags = flags;
108e1144d00SMark McLoughlin packet->size = size;
109e1144d00SMark McLoughlin packet->sent_cb = sent_cb;
110e1144d00SMark McLoughlin memcpy(packet->data, buf, size);
111e1144d00SMark McLoughlin
1127d91ddd2SLuigi Rizzo queue->nq_count++;
113e1144d00SMark McLoughlin QTAILQ_INSERT_TAIL(&queue->packets, packet, entry);
114e1144d00SMark McLoughlin }
115e1144d00SMark McLoughlin
qemu_net_queue_append_iov(NetQueue * queue,NetClientState * sender,unsigned flags,const struct iovec * iov,int iovcnt,NetPacketSent * sent_cb)116b68c7f76SYang Hongyang void qemu_net_queue_append_iov(NetQueue *queue,
1174e68f7a0SStefan Hajnoczi NetClientState *sender,
118e1144d00SMark McLoughlin unsigned flags,
119e1144d00SMark McLoughlin const struct iovec *iov,
120e1144d00SMark McLoughlin int iovcnt,
121e1144d00SMark McLoughlin NetPacketSent *sent_cb)
122e1144d00SMark McLoughlin {
123e1144d00SMark McLoughlin NetPacket *packet;
124e1144d00SMark McLoughlin size_t max_len = 0;
125e1144d00SMark McLoughlin int i;
126e1144d00SMark McLoughlin
1277d91ddd2SLuigi Rizzo if (queue->nq_count >= queue->nq_maxlen && !sent_cb) {
1287d91ddd2SLuigi Rizzo return; /* drop if queue full and no callback */
1297d91ddd2SLuigi Rizzo }
130e1144d00SMark McLoughlin for (i = 0; i < iovcnt; i++) {
131e1144d00SMark McLoughlin max_len += iov[i].iov_len;
132e1144d00SMark McLoughlin }
133e1144d00SMark McLoughlin
1347267c094SAnthony Liguori packet = g_malloc(sizeof(NetPacket) + max_len);
135e1144d00SMark McLoughlin packet->sender = sender;
136e1144d00SMark McLoughlin packet->sent_cb = sent_cb;
137e1144d00SMark McLoughlin packet->flags = flags;
138e1144d00SMark McLoughlin packet->size = 0;
139e1144d00SMark McLoughlin
140e1144d00SMark McLoughlin for (i = 0; i < iovcnt; i++) {
141e1144d00SMark McLoughlin size_t len = iov[i].iov_len;
142e1144d00SMark McLoughlin
143e1144d00SMark McLoughlin memcpy(packet->data + packet->size, iov[i].iov_base, len);
144e1144d00SMark McLoughlin packet->size += len;
145e1144d00SMark McLoughlin }
146e1144d00SMark McLoughlin
1477d91ddd2SLuigi Rizzo queue->nq_count++;
148e1144d00SMark McLoughlin QTAILQ_INSERT_TAIL(&queue->packets, packet, entry);
149e1144d00SMark McLoughlin }
150e1144d00SMark McLoughlin
qemu_net_queue_deliver(NetQueue * queue,NetClientState * sender,unsigned flags,const uint8_t * data,size_t size)151e1144d00SMark McLoughlin static ssize_t qemu_net_queue_deliver(NetQueue *queue,
1524e68f7a0SStefan Hajnoczi NetClientState *sender,
153e1144d00SMark McLoughlin unsigned flags,
154e1144d00SMark McLoughlin const uint8_t *data,
155e1144d00SMark McLoughlin size_t size)
156e1144d00SMark McLoughlin {
157e1144d00SMark McLoughlin ssize_t ret = -1;
158fefe2a78SYang Hongyang struct iovec iov = {
159fefe2a78SYang Hongyang .iov_base = (void *)data,
160fefe2a78SYang Hongyang .iov_len = size
161fefe2a78SYang Hongyang };
162e1144d00SMark McLoughlin
163e1144d00SMark McLoughlin queue->delivering = 1;
1643e033a46SYang Hongyang ret = queue->deliver(sender, flags, &iov, 1, queue->opaque);
165e1144d00SMark McLoughlin queue->delivering = 0;
166e1144d00SMark McLoughlin
167e1144d00SMark McLoughlin return ret;
168e1144d00SMark McLoughlin }
169e1144d00SMark McLoughlin
qemu_net_queue_deliver_iov(NetQueue * queue,NetClientState * sender,unsigned flags,const struct iovec * iov,int iovcnt)170e1144d00SMark McLoughlin static ssize_t qemu_net_queue_deliver_iov(NetQueue *queue,
1714e68f7a0SStefan Hajnoczi NetClientState *sender,
172e1144d00SMark McLoughlin unsigned flags,
173e1144d00SMark McLoughlin const struct iovec *iov,
174e1144d00SMark McLoughlin int iovcnt)
175e1144d00SMark McLoughlin {
176e1144d00SMark McLoughlin ssize_t ret = -1;
177e1144d00SMark McLoughlin
178e1144d00SMark McLoughlin queue->delivering = 1;
1793e033a46SYang Hongyang ret = queue->deliver(sender, flags, iov, iovcnt, queue->opaque);
180e1144d00SMark McLoughlin queue->delivering = 0;
181e1144d00SMark McLoughlin
182e1144d00SMark McLoughlin return ret;
183e1144d00SMark McLoughlin }
184e1144d00SMark McLoughlin
qemu_net_queue_receive(NetQueue * queue,const uint8_t * data,size_t size)185*705df546SJason Wang ssize_t qemu_net_queue_receive(NetQueue *queue,
186*705df546SJason Wang const uint8_t *data,
187*705df546SJason Wang size_t size)
188*705df546SJason Wang {
189*705df546SJason Wang if (queue->delivering) {
190*705df546SJason Wang return 0;
191*705df546SJason Wang }
192*705df546SJason Wang
193*705df546SJason Wang return qemu_net_queue_deliver(queue, NULL, 0, data, size);
194*705df546SJason Wang }
195*705df546SJason Wang
qemu_net_queue_send(NetQueue * queue,NetClientState * sender,unsigned flags,const uint8_t * data,size_t size,NetPacketSent * sent_cb)196e1144d00SMark McLoughlin ssize_t qemu_net_queue_send(NetQueue *queue,
1974e68f7a0SStefan Hajnoczi NetClientState *sender,
198e1144d00SMark McLoughlin unsigned flags,
199e1144d00SMark McLoughlin const uint8_t *data,
200e1144d00SMark McLoughlin size_t size,
201e1144d00SMark McLoughlin NetPacketSent *sent_cb)
202e1144d00SMark McLoughlin {
203e1144d00SMark McLoughlin ssize_t ret;
204e1144d00SMark McLoughlin
205691a4f3aSZhi Yong Wu if (queue->delivering || !qemu_can_send_packet(sender)) {
20606b5f36dSStefan Hajnoczi qemu_net_queue_append(queue, sender, flags, data, size, sent_cb);
20706b5f36dSStefan Hajnoczi return 0;
208e1144d00SMark McLoughlin }
209e1144d00SMark McLoughlin
210e1144d00SMark McLoughlin ret = qemu_net_queue_deliver(queue, sender, flags, data, size);
211839f368fSMark McLoughlin if (ret == 0) {
212e1144d00SMark McLoughlin qemu_net_queue_append(queue, sender, flags, data, size, sent_cb);
213e1144d00SMark McLoughlin return 0;
214e1144d00SMark McLoughlin }
215e1144d00SMark McLoughlin
216e1144d00SMark McLoughlin qemu_net_queue_flush(queue);
217e1144d00SMark McLoughlin
218e1144d00SMark McLoughlin return ret;
219e1144d00SMark McLoughlin }
220e1144d00SMark McLoughlin
qemu_net_queue_send_iov(NetQueue * queue,NetClientState * sender,unsigned flags,const struct iovec * iov,int iovcnt,NetPacketSent * sent_cb)221e1144d00SMark McLoughlin ssize_t qemu_net_queue_send_iov(NetQueue *queue,
2224e68f7a0SStefan Hajnoczi NetClientState *sender,
223e1144d00SMark McLoughlin unsigned flags,
224e1144d00SMark McLoughlin const struct iovec *iov,
225e1144d00SMark McLoughlin int iovcnt,
226e1144d00SMark McLoughlin NetPacketSent *sent_cb)
227e1144d00SMark McLoughlin {
228e1144d00SMark McLoughlin ssize_t ret;
229e1144d00SMark McLoughlin
230691a4f3aSZhi Yong Wu if (queue->delivering || !qemu_can_send_packet(sender)) {
23106b5f36dSStefan Hajnoczi qemu_net_queue_append_iov(queue, sender, flags, iov, iovcnt, sent_cb);
23206b5f36dSStefan Hajnoczi return 0;
233e1144d00SMark McLoughlin }
234e1144d00SMark McLoughlin
235e1144d00SMark McLoughlin ret = qemu_net_queue_deliver_iov(queue, sender, flags, iov, iovcnt);
236839f368fSMark McLoughlin if (ret == 0) {
237e1144d00SMark McLoughlin qemu_net_queue_append_iov(queue, sender, flags, iov, iovcnt, sent_cb);
238e1144d00SMark McLoughlin return 0;
239e1144d00SMark McLoughlin }
240e1144d00SMark McLoughlin
241e1144d00SMark McLoughlin qemu_net_queue_flush(queue);
242e1144d00SMark McLoughlin
243e1144d00SMark McLoughlin return ret;
244e1144d00SMark McLoughlin }
245e1144d00SMark McLoughlin
qemu_net_queue_purge(NetQueue * queue,NetClientState * from)2464e68f7a0SStefan Hajnoczi void qemu_net_queue_purge(NetQueue *queue, NetClientState *from)
247e1144d00SMark McLoughlin {
248e1144d00SMark McLoughlin NetPacket *packet, *next;
249e1144d00SMark McLoughlin
250e1144d00SMark McLoughlin QTAILQ_FOREACH_SAFE(packet, &queue->packets, entry, next) {
251e1144d00SMark McLoughlin if (packet->sender == from) {
252e1144d00SMark McLoughlin QTAILQ_REMOVE(&queue->packets, packet, entry);
2537d91ddd2SLuigi Rizzo queue->nq_count--;
25407d80846SMichael S. Tsirkin if (packet->sent_cb) {
25507d80846SMichael S. Tsirkin packet->sent_cb(packet->sender, 0);
25607d80846SMichael S. Tsirkin }
2577267c094SAnthony Liguori g_free(packet);
258e1144d00SMark McLoughlin }
259e1144d00SMark McLoughlin }
260e1144d00SMark McLoughlin }
261e1144d00SMark McLoughlin
qemu_net_queue_flush(NetQueue * queue)262987a9b48SPaolo Bonzini bool qemu_net_queue_flush(NetQueue *queue)
263e1144d00SMark McLoughlin {
26422dc8663SJason Wang if (queue->delivering)
26522dc8663SJason Wang return false;
26622dc8663SJason Wang
267e1144d00SMark McLoughlin while (!QTAILQ_EMPTY(&queue->packets)) {
268e1144d00SMark McLoughlin NetPacket *packet;
269e1144d00SMark McLoughlin int ret;
270e1144d00SMark McLoughlin
271e1144d00SMark McLoughlin packet = QTAILQ_FIRST(&queue->packets);
272e1144d00SMark McLoughlin QTAILQ_REMOVE(&queue->packets, packet, entry);
2737d91ddd2SLuigi Rizzo queue->nq_count--;
274e1144d00SMark McLoughlin
275e1144d00SMark McLoughlin ret = qemu_net_queue_deliver(queue,
276e1144d00SMark McLoughlin packet->sender,
277e1144d00SMark McLoughlin packet->flags,
278e1144d00SMark McLoughlin packet->data,
279e1144d00SMark McLoughlin packet->size);
280839f368fSMark McLoughlin if (ret == 0) {
2817d91ddd2SLuigi Rizzo queue->nq_count++;
282e1144d00SMark McLoughlin QTAILQ_INSERT_HEAD(&queue->packets, packet, entry);
283987a9b48SPaolo Bonzini return false;
284e1144d00SMark McLoughlin }
285e1144d00SMark McLoughlin
286e1144d00SMark McLoughlin if (packet->sent_cb) {
287e1144d00SMark McLoughlin packet->sent_cb(packet->sender, ret);
288e1144d00SMark McLoughlin }
289e1144d00SMark McLoughlin
2907267c094SAnthony Liguori g_free(packet);
291e1144d00SMark McLoughlin }
292987a9b48SPaolo Bonzini return true;
293e1144d00SMark McLoughlin }
294