1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24#include "net/queue.h"
25#include "qemu/queue.h"
26#include "net/net.h"
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42struct 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
51struct 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
61NetQueue *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
78void 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
90static 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;
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
113static 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;
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
148static 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
163static 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
178ssize_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
203ssize_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
228void 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 if (packet->sent_cb) {
237 packet->sent_cb(packet->sender, 0);
238 }
239 g_free(packet);
240 }
241 }
242}
243
244bool qemu_net_queue_flush(NetQueue *queue)
245{
246 while (!QTAILQ_EMPTY(&queue->packets)) {
247 NetPacket *packet;
248 int ret;
249
250 packet = QTAILQ_FIRST(&queue->packets);
251 QTAILQ_REMOVE(&queue->packets, packet, entry);
252 queue->nq_count--;
253
254 ret = qemu_net_queue_deliver(queue,
255 packet->sender,
256 packet->flags,
257 packet->data,
258 packet->size);
259 if (ret == 0) {
260 queue->nq_count++;
261 QTAILQ_INSERT_HEAD(&queue->packets, packet, entry);
262 return false;
263 }
264
265 if (packet->sent_cb) {
266 packet->sent_cb(packet->sender, ret);
267 }
268
269 g_free(packet);
270 }
271 return true;
272}
273