root / hw / net / virtio-net.c @ c7bcc85d
History | View | Annotate | Download (48.2 kB)
1 | fbe78f4f | aliguori | /*
|
---|---|---|---|
2 | fbe78f4f | aliguori | * Virtio Network Device
|
3 | fbe78f4f | aliguori | *
|
4 | fbe78f4f | aliguori | * Copyright IBM, Corp. 2007
|
5 | fbe78f4f | aliguori | *
|
6 | fbe78f4f | aliguori | * Authors:
|
7 | fbe78f4f | aliguori | * Anthony Liguori <aliguori@us.ibm.com>
|
8 | fbe78f4f | aliguori | *
|
9 | fbe78f4f | aliguori | * This work is licensed under the terms of the GNU GPL, version 2. See
|
10 | fbe78f4f | aliguori | * the COPYING file in the top-level directory.
|
11 | fbe78f4f | aliguori | *
|
12 | fbe78f4f | aliguori | */
|
13 | fbe78f4f | aliguori | |
14 | 1de7afc9 | Paolo Bonzini | #include "qemu/iov.h" |
15 | 0d09e41a | Paolo Bonzini | #include "hw/virtio/virtio.h" |
16 | 1422e32d | Paolo Bonzini | #include "net/net.h" |
17 | 7200ac3c | Mark McLoughlin | #include "net/checksum.h" |
18 | a8ed73f7 | Mark McLoughlin | #include "net/tap.h" |
19 | 1de7afc9 | Paolo Bonzini | #include "qemu/error-report.h" |
20 | 1de7afc9 | Paolo Bonzini | #include "qemu/timer.h" |
21 | 0d09e41a | Paolo Bonzini | #include "hw/virtio/virtio-net.h" |
22 | 0d09e41a | Paolo Bonzini | #include "net/vhost_net.h" |
23 | 17ec5a86 | KONRAD Frederic | #include "hw/virtio/virtio-bus.h" |
24 | b1be4280 | Amos Kong | #include "qapi/qmp/qjson.h" |
25 | b1be4280 | Amos Kong | #include "monitor/monitor.h" |
26 | fbe78f4f | aliguori | |
27 | 0ce0e8f4 | Mark McLoughlin | #define VIRTIO_NET_VM_VERSION 11 |
28 | b6503ed9 | aliguori | |
29 | 4ffb17f5 | Alex Williamson | #define MAC_TABLE_ENTRIES 64 |
30 | f21c0ed9 | aliguori | #define MAX_VLAN (1 << 12) /* Per 802.1Q definition */ |
31 | 9d6271b8 | aliguori | |
32 | 14f9b664 | Jesse Larrew | /*
|
33 | 14f9b664 | Jesse Larrew | * Calculate the number of bytes up to and including the given 'field' of
|
34 | 14f9b664 | Jesse Larrew | * 'container'.
|
35 | 14f9b664 | Jesse Larrew | */
|
36 | 14f9b664 | Jesse Larrew | #define endof(container, field) \
|
37 | 14f9b664 | Jesse Larrew | (offsetof(container, field) + sizeof(((container *)0)->field)) |
38 | 14f9b664 | Jesse Larrew | |
39 | 14f9b664 | Jesse Larrew | typedef struct VirtIOFeature { |
40 | 14f9b664 | Jesse Larrew | uint32_t flags; |
41 | 14f9b664 | Jesse Larrew | size_t end; |
42 | 14f9b664 | Jesse Larrew | } VirtIOFeature; |
43 | 14f9b664 | Jesse Larrew | |
44 | 14f9b664 | Jesse Larrew | static VirtIOFeature feature_sizes[] = {
|
45 | 14f9b664 | Jesse Larrew | {.flags = 1 << VIRTIO_NET_F_MAC,
|
46 | 14f9b664 | Jesse Larrew | .end = endof(struct virtio_net_config, mac)},
|
47 | 14f9b664 | Jesse Larrew | {.flags = 1 << VIRTIO_NET_F_STATUS,
|
48 | 14f9b664 | Jesse Larrew | .end = endof(struct virtio_net_config, status)},
|
49 | 14f9b664 | Jesse Larrew | {.flags = 1 << VIRTIO_NET_F_MQ,
|
50 | 14f9b664 | Jesse Larrew | .end = endof(struct virtio_net_config, max_virtqueue_pairs)},
|
51 | 14f9b664 | Jesse Larrew | {} |
52 | 14f9b664 | Jesse Larrew | }; |
53 | 14f9b664 | Jesse Larrew | |
54 | fed699f9 | Jason Wang | static VirtIONetQueue *virtio_net_get_subqueue(NetClientState *nc)
|
55 | 0c87e93e | Jason Wang | { |
56 | 0c87e93e | Jason Wang | VirtIONet *n = qemu_get_nic_opaque(nc); |
57 | 0c87e93e | Jason Wang | |
58 | fed699f9 | Jason Wang | return &n->vqs[nc->queue_index];
|
59 | 0c87e93e | Jason Wang | } |
60 | fed699f9 | Jason Wang | |
61 | fed699f9 | Jason Wang | static int vq2q(int queue_index) |
62 | fed699f9 | Jason Wang | { |
63 | fed699f9 | Jason Wang | return queue_index / 2; |
64 | fed699f9 | Jason Wang | } |
65 | fed699f9 | Jason Wang | |
66 | fbe78f4f | aliguori | /* TODO
|
67 | fbe78f4f | aliguori | * - we could suppress RX interrupt if we were so inclined.
|
68 | fbe78f4f | aliguori | */
|
69 | fbe78f4f | aliguori | |
70 | 0f03eca6 | aliguori | static void virtio_net_get_config(VirtIODevice *vdev, uint8_t *config) |
71 | fbe78f4f | aliguori | { |
72 | 17a0ca55 | KONRAD Frederic | VirtIONet *n = VIRTIO_NET(vdev); |
73 | fbe78f4f | aliguori | struct virtio_net_config netcfg;
|
74 | fbe78f4f | aliguori | |
75 | b46d97f2 | Stefan Hajnoczi | stw_p(&netcfg.status, n->status); |
76 | fed699f9 | Jason Wang | stw_p(&netcfg.max_virtqueue_pairs, n->max_queues); |
77 | 79674068 | aliguori | memcpy(netcfg.mac, n->mac, ETH_ALEN); |
78 | 14f9b664 | Jesse Larrew | memcpy(config, &netcfg, n->config_size); |
79 | fbe78f4f | aliguori | } |
80 | fbe78f4f | aliguori | |
81 | 0f03eca6 | aliguori | static void virtio_net_set_config(VirtIODevice *vdev, const uint8_t *config) |
82 | 0f03eca6 | aliguori | { |
83 | 17a0ca55 | KONRAD Frederic | VirtIONet *n = VIRTIO_NET(vdev); |
84 | 14f9b664 | Jesse Larrew | struct virtio_net_config netcfg = {};
|
85 | 0f03eca6 | aliguori | |
86 | 14f9b664 | Jesse Larrew | memcpy(&netcfg, config, n->config_size); |
87 | 0f03eca6 | aliguori | |
88 | 17a0ca55 | KONRAD Frederic | if (!(vdev->guest_features >> VIRTIO_NET_F_CTRL_MAC_ADDR & 1) && |
89 | c1943a3f | Amos Kong | memcmp(netcfg.mac, n->mac, ETH_ALEN)) { |
90 | 79674068 | aliguori | memcpy(n->mac, netcfg.mac, ETH_ALEN); |
91 | b356f76d | Jason Wang | qemu_format_nic_info_str(qemu_get_queue(n->nic), n->mac); |
92 | 0f03eca6 | aliguori | } |
93 | 0f03eca6 | aliguori | } |
94 | 0f03eca6 | aliguori | |
95 | 783e7706 | Michael S. Tsirkin | static bool virtio_net_started(VirtIONet *n, uint8_t status) |
96 | 783e7706 | Michael S. Tsirkin | { |
97 | 17a0ca55 | KONRAD Frederic | VirtIODevice *vdev = VIRTIO_DEVICE(n); |
98 | 783e7706 | Michael S. Tsirkin | return (status & VIRTIO_CONFIG_S_DRIVER_OK) &&
|
99 | 17a0ca55 | KONRAD Frederic | (n->status & VIRTIO_NET_S_LINK_UP) && vdev->vm_running; |
100 | 783e7706 | Michael S. Tsirkin | } |
101 | 783e7706 | Michael S. Tsirkin | |
102 | 783e7706 | Michael S. Tsirkin | static void virtio_net_vhost_status(VirtIONet *n, uint8_t status) |
103 | afbaa7b4 | Michael S. Tsirkin | { |
104 | 17a0ca55 | KONRAD Frederic | VirtIODevice *vdev = VIRTIO_DEVICE(n); |
105 | b356f76d | Jason Wang | NetClientState *nc = qemu_get_queue(n->nic); |
106 | fed699f9 | Jason Wang | int queues = n->multiqueue ? n->max_queues : 1; |
107 | b356f76d | Jason Wang | |
108 | b356f76d | Jason Wang | if (!nc->peer) {
|
109 | afbaa7b4 | Michael S. Tsirkin | return;
|
110 | afbaa7b4 | Michael S. Tsirkin | } |
111 | b356f76d | Jason Wang | if (nc->peer->info->type != NET_CLIENT_OPTIONS_KIND_TAP) {
|
112 | afbaa7b4 | Michael S. Tsirkin | return;
|
113 | afbaa7b4 | Michael S. Tsirkin | } |
114 | afbaa7b4 | Michael S. Tsirkin | |
115 | b356f76d | Jason Wang | if (!tap_get_vhost_net(nc->peer)) {
|
116 | afbaa7b4 | Michael S. Tsirkin | return;
|
117 | afbaa7b4 | Michael S. Tsirkin | } |
118 | fed699f9 | Jason Wang | |
119 | d7108d90 | Jason Wang | if (!!n->vhost_started ==
|
120 | d7108d90 | Jason Wang | (virtio_net_started(n, status) && !nc->peer->link_down)) { |
121 | afbaa7b4 | Michael S. Tsirkin | return;
|
122 | afbaa7b4 | Michael S. Tsirkin | } |
123 | afbaa7b4 | Michael S. Tsirkin | if (!n->vhost_started) {
|
124 | 5430a28f | mst@redhat.com | int r;
|
125 | 17a0ca55 | KONRAD Frederic | if (!vhost_net_query(tap_get_vhost_net(nc->peer), vdev)) {
|
126 | 5430a28f | mst@redhat.com | return;
|
127 | 5430a28f | mst@redhat.com | } |
128 | 1830b80f | Michael S. Tsirkin | n->vhost_started = 1;
|
129 | 17a0ca55 | KONRAD Frederic | r = vhost_net_start(vdev, n->nic->ncs, queues); |
130 | afbaa7b4 | Michael S. Tsirkin | if (r < 0) { |
131 | e7b43f7e | Stefan Hajnoczi | error_report("unable to start vhost net: %d: "
|
132 | e7b43f7e | Stefan Hajnoczi | "falling back on userspace virtio", -r);
|
133 | 1830b80f | Michael S. Tsirkin | n->vhost_started = 0;
|
134 | afbaa7b4 | Michael S. Tsirkin | } |
135 | afbaa7b4 | Michael S. Tsirkin | } else {
|
136 | 17a0ca55 | KONRAD Frederic | vhost_net_stop(vdev, n->nic->ncs, queues); |
137 | afbaa7b4 | Michael S. Tsirkin | n->vhost_started = 0;
|
138 | afbaa7b4 | Michael S. Tsirkin | } |
139 | afbaa7b4 | Michael S. Tsirkin | } |
140 | afbaa7b4 | Michael S. Tsirkin | |
141 | 783e7706 | Michael S. Tsirkin | static void virtio_net_set_status(struct VirtIODevice *vdev, uint8_t status) |
142 | 783e7706 | Michael S. Tsirkin | { |
143 | 17a0ca55 | KONRAD Frederic | VirtIONet *n = VIRTIO_NET(vdev); |
144 | fed699f9 | Jason Wang | VirtIONetQueue *q; |
145 | fed699f9 | Jason Wang | int i;
|
146 | fed699f9 | Jason Wang | uint8_t queue_status; |
147 | 783e7706 | Michael S. Tsirkin | |
148 | 783e7706 | Michael S. Tsirkin | virtio_net_vhost_status(n, status); |
149 | 783e7706 | Michael S. Tsirkin | |
150 | fed699f9 | Jason Wang | for (i = 0; i < n->max_queues; i++) { |
151 | fed699f9 | Jason Wang | q = &n->vqs[i]; |
152 | 783e7706 | Michael S. Tsirkin | |
153 | fed699f9 | Jason Wang | if ((!n->multiqueue && i != 0) || i >= n->curr_queues) { |
154 | fed699f9 | Jason Wang | queue_status = 0;
|
155 | 783e7706 | Michael S. Tsirkin | } else {
|
156 | fed699f9 | Jason Wang | queue_status = status; |
157 | 783e7706 | Michael S. Tsirkin | } |
158 | fed699f9 | Jason Wang | |
159 | fed699f9 | Jason Wang | if (!q->tx_waiting) {
|
160 | fed699f9 | Jason Wang | continue;
|
161 | fed699f9 | Jason Wang | } |
162 | fed699f9 | Jason Wang | |
163 | fed699f9 | Jason Wang | if (virtio_net_started(n, queue_status) && !n->vhost_started) {
|
164 | fed699f9 | Jason Wang | if (q->tx_timer) {
|
165 | bc72ad67 | Alex Bligh | timer_mod(q->tx_timer, |
166 | bc72ad67 | Alex Bligh | qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + n->tx_timeout); |
167 | fed699f9 | Jason Wang | } else {
|
168 | fed699f9 | Jason Wang | qemu_bh_schedule(q->tx_bh); |
169 | fed699f9 | Jason Wang | } |
170 | 783e7706 | Michael S. Tsirkin | } else {
|
171 | fed699f9 | Jason Wang | if (q->tx_timer) {
|
172 | bc72ad67 | Alex Bligh | timer_del(q->tx_timer); |
173 | fed699f9 | Jason Wang | } else {
|
174 | fed699f9 | Jason Wang | qemu_bh_cancel(q->tx_bh); |
175 | fed699f9 | Jason Wang | } |
176 | 783e7706 | Michael S. Tsirkin | } |
177 | 783e7706 | Michael S. Tsirkin | } |
178 | 783e7706 | Michael S. Tsirkin | } |
179 | 783e7706 | Michael S. Tsirkin | |
180 | 4e68f7a0 | Stefan Hajnoczi | static void virtio_net_set_link_status(NetClientState *nc) |
181 | 554c97dd | aliguori | { |
182 | cc1f0f45 | Jason Wang | VirtIONet *n = qemu_get_nic_opaque(nc); |
183 | 17a0ca55 | KONRAD Frederic | VirtIODevice *vdev = VIRTIO_DEVICE(n); |
184 | 554c97dd | aliguori | uint16_t old_status = n->status; |
185 | 554c97dd | aliguori | |
186 | eb6b6c12 | Mark McLoughlin | if (nc->link_down)
|
187 | 554c97dd | aliguori | n->status &= ~VIRTIO_NET_S_LINK_UP; |
188 | 554c97dd | aliguori | else
|
189 | 554c97dd | aliguori | n->status |= VIRTIO_NET_S_LINK_UP; |
190 | 554c97dd | aliguori | |
191 | 554c97dd | aliguori | if (n->status != old_status)
|
192 | 17a0ca55 | KONRAD Frederic | virtio_notify_config(vdev); |
193 | afbaa7b4 | Michael S. Tsirkin | |
194 | 17a0ca55 | KONRAD Frederic | virtio_net_set_status(vdev, vdev->status); |
195 | 554c97dd | aliguori | } |
196 | 554c97dd | aliguori | |
197 | b1be4280 | Amos Kong | static void rxfilter_notify(NetClientState *nc) |
198 | b1be4280 | Amos Kong | { |
199 | b1be4280 | Amos Kong | QObject *event_data; |
200 | b1be4280 | Amos Kong | VirtIONet *n = qemu_get_nic_opaque(nc); |
201 | b1be4280 | Amos Kong | |
202 | b1be4280 | Amos Kong | if (nc->rxfilter_notify_enabled) {
|
203 | 96e35046 | Amos Kong | gchar *path = object_get_canonical_path(OBJECT(n->qdev)); |
204 | b1be4280 | Amos Kong | if (n->netclient_name) {
|
205 | b1be4280 | Amos Kong | event_data = qobject_from_jsonf("{ 'name': %s, 'path': %s }",
|
206 | 96e35046 | Amos Kong | n->netclient_name, path); |
207 | b1be4280 | Amos Kong | } else {
|
208 | 96e35046 | Amos Kong | event_data = qobject_from_jsonf("{ 'path': %s }", path);
|
209 | b1be4280 | Amos Kong | } |
210 | b1be4280 | Amos Kong | monitor_protocol_event(QEVENT_NIC_RX_FILTER_CHANGED, event_data); |
211 | b1be4280 | Amos Kong | qobject_decref(event_data); |
212 | 96e35046 | Amos Kong | g_free(path); |
213 | b1be4280 | Amos Kong | |
214 | b1be4280 | Amos Kong | /* disable event notification to avoid events flooding */
|
215 | b1be4280 | Amos Kong | nc->rxfilter_notify_enabled = 0;
|
216 | b1be4280 | Amos Kong | } |
217 | b1be4280 | Amos Kong | } |
218 | b1be4280 | Amos Kong | |
219 | b1be4280 | Amos Kong | static char *mac_strdup_printf(const uint8_t *mac) |
220 | b1be4280 | Amos Kong | { |
221 | b1be4280 | Amos Kong | return g_strdup_printf("%.2x:%.2x:%.2x:%.2x:%.2x:%.2x", mac[0], |
222 | b1be4280 | Amos Kong | mac[1], mac[2], mac[3], mac[4], mac[5]); |
223 | b1be4280 | Amos Kong | } |
224 | b1be4280 | Amos Kong | |
225 | b1be4280 | Amos Kong | static RxFilterInfo *virtio_net_query_rxfilter(NetClientState *nc)
|
226 | b1be4280 | Amos Kong | { |
227 | b1be4280 | Amos Kong | VirtIONet *n = qemu_get_nic_opaque(nc); |
228 | b1be4280 | Amos Kong | RxFilterInfo *info; |
229 | b1be4280 | Amos Kong | strList *str_list, *entry; |
230 | b1be4280 | Amos Kong | intList *int_list, *int_entry; |
231 | b1be4280 | Amos Kong | int i, j;
|
232 | b1be4280 | Amos Kong | |
233 | b1be4280 | Amos Kong | info = g_malloc0(sizeof(*info));
|
234 | b1be4280 | Amos Kong | info->name = g_strdup(nc->name); |
235 | b1be4280 | Amos Kong | info->promiscuous = n->promisc; |
236 | b1be4280 | Amos Kong | |
237 | b1be4280 | Amos Kong | if (n->nouni) {
|
238 | b1be4280 | Amos Kong | info->unicast = RX_STATE_NONE; |
239 | b1be4280 | Amos Kong | } else if (n->alluni) { |
240 | b1be4280 | Amos Kong | info->unicast = RX_STATE_ALL; |
241 | b1be4280 | Amos Kong | } else {
|
242 | b1be4280 | Amos Kong | info->unicast = RX_STATE_NORMAL; |
243 | b1be4280 | Amos Kong | } |
244 | b1be4280 | Amos Kong | |
245 | b1be4280 | Amos Kong | if (n->nomulti) {
|
246 | b1be4280 | Amos Kong | info->multicast = RX_STATE_NONE; |
247 | b1be4280 | Amos Kong | } else if (n->allmulti) { |
248 | b1be4280 | Amos Kong | info->multicast = RX_STATE_ALL; |
249 | b1be4280 | Amos Kong | } else {
|
250 | b1be4280 | Amos Kong | info->multicast = RX_STATE_NORMAL; |
251 | b1be4280 | Amos Kong | } |
252 | b1be4280 | Amos Kong | |
253 | b1be4280 | Amos Kong | info->broadcast_allowed = n->nobcast; |
254 | b1be4280 | Amos Kong | info->multicast_overflow = n->mac_table.multi_overflow; |
255 | b1be4280 | Amos Kong | info->unicast_overflow = n->mac_table.uni_overflow; |
256 | b1be4280 | Amos Kong | |
257 | b1be4280 | Amos Kong | info->main_mac = mac_strdup_printf(n->mac); |
258 | b1be4280 | Amos Kong | |
259 | b1be4280 | Amos Kong | str_list = NULL;
|
260 | b1be4280 | Amos Kong | for (i = 0; i < n->mac_table.first_multi; i++) { |
261 | b1be4280 | Amos Kong | entry = g_malloc0(sizeof(*entry));
|
262 | b1be4280 | Amos Kong | entry->value = mac_strdup_printf(n->mac_table.macs + i * ETH_ALEN); |
263 | b1be4280 | Amos Kong | entry->next = str_list; |
264 | b1be4280 | Amos Kong | str_list = entry; |
265 | b1be4280 | Amos Kong | } |
266 | b1be4280 | Amos Kong | info->unicast_table = str_list; |
267 | b1be4280 | Amos Kong | |
268 | b1be4280 | Amos Kong | str_list = NULL;
|
269 | b1be4280 | Amos Kong | for (i = n->mac_table.first_multi; i < n->mac_table.in_use; i++) {
|
270 | b1be4280 | Amos Kong | entry = g_malloc0(sizeof(*entry));
|
271 | b1be4280 | Amos Kong | entry->value = mac_strdup_printf(n->mac_table.macs + i * ETH_ALEN); |
272 | b1be4280 | Amos Kong | entry->next = str_list; |
273 | b1be4280 | Amos Kong | str_list = entry; |
274 | b1be4280 | Amos Kong | } |
275 | b1be4280 | Amos Kong | info->multicast_table = str_list; |
276 | b1be4280 | Amos Kong | |
277 | b1be4280 | Amos Kong | int_list = NULL;
|
278 | b1be4280 | Amos Kong | for (i = 0; i < MAX_VLAN >> 5; i++) { |
279 | b1be4280 | Amos Kong | for (j = 0; n->vlans[i] && j < 0x1f; j++) { |
280 | b1be4280 | Amos Kong | if (n->vlans[i] & (1U << j)) { |
281 | b1be4280 | Amos Kong | int_entry = g_malloc0(sizeof(*int_entry));
|
282 | b1be4280 | Amos Kong | int_entry->value = (i << 5) + j;
|
283 | b1be4280 | Amos Kong | int_entry->next = int_list; |
284 | b1be4280 | Amos Kong | int_list = int_entry; |
285 | b1be4280 | Amos Kong | } |
286 | b1be4280 | Amos Kong | } |
287 | b1be4280 | Amos Kong | } |
288 | b1be4280 | Amos Kong | info->vlan_table = int_list; |
289 | b1be4280 | Amos Kong | |
290 | b1be4280 | Amos Kong | /* enable event notification after query */
|
291 | b1be4280 | Amos Kong | nc->rxfilter_notify_enabled = 1;
|
292 | b1be4280 | Amos Kong | |
293 | b1be4280 | Amos Kong | return info;
|
294 | b1be4280 | Amos Kong | } |
295 | b1be4280 | Amos Kong | |
296 | 002437cd | aliguori | static void virtio_net_reset(VirtIODevice *vdev) |
297 | 002437cd | aliguori | { |
298 | 17a0ca55 | KONRAD Frederic | VirtIONet *n = VIRTIO_NET(vdev); |
299 | 002437cd | aliguori | |
300 | 002437cd | aliguori | /* Reset back to compatibility mode */
|
301 | 002437cd | aliguori | n->promisc = 1;
|
302 | 002437cd | aliguori | n->allmulti = 0;
|
303 | 015cb166 | Alex Williamson | n->alluni = 0;
|
304 | 015cb166 | Alex Williamson | n->nomulti = 0;
|
305 | 015cb166 | Alex Williamson | n->nouni = 0;
|
306 | 015cb166 | Alex Williamson | n->nobcast = 0;
|
307 | fed699f9 | Jason Wang | /* multiqueue is disabled by default */
|
308 | fed699f9 | Jason Wang | n->curr_queues = 1;
|
309 | b6503ed9 | aliguori | |
310 | f21c0ed9 | aliguori | /* Flush any MAC and VLAN filter table state */
|
311 | b6503ed9 | aliguori | n->mac_table.in_use = 0;
|
312 | 2d9aba39 | Alex Williamson | n->mac_table.first_multi = 0;
|
313 | 8fd2a2f1 | Alex Williamson | n->mac_table.multi_overflow = 0;
|
314 | 8fd2a2f1 | Alex Williamson | n->mac_table.uni_overflow = 0;
|
315 | b6503ed9 | aliguori | memset(n->mac_table.macs, 0, MAC_TABLE_ENTRIES * ETH_ALEN);
|
316 | 41dc8a67 | Michael S. Tsirkin | memcpy(&n->mac[0], &n->nic->conf->macaddr, sizeof(n->mac)); |
317 | 702d66a8 | Michael S. Tsirkin | qemu_format_nic_info_str(qemu_get_queue(n->nic), n->mac); |
318 | f21c0ed9 | aliguori | memset(n->vlans, 0, MAX_VLAN >> 3); |
319 | 002437cd | aliguori | } |
320 | 002437cd | aliguori | |
321 | 6e371ab8 | Michael S. Tsirkin | static void peer_test_vnet_hdr(VirtIONet *n) |
322 | 3a330134 | Mark McLoughlin | { |
323 | b356f76d | Jason Wang | NetClientState *nc = qemu_get_queue(n->nic); |
324 | b356f76d | Jason Wang | if (!nc->peer) {
|
325 | 6e371ab8 | Michael S. Tsirkin | return;
|
326 | b356f76d | Jason Wang | } |
327 | 3a330134 | Mark McLoughlin | |
328 | b356f76d | Jason Wang | if (nc->peer->info->type != NET_CLIENT_OPTIONS_KIND_TAP) {
|
329 | 6e371ab8 | Michael S. Tsirkin | return;
|
330 | b356f76d | Jason Wang | } |
331 | 3a330134 | Mark McLoughlin | |
332 | b356f76d | Jason Wang | n->has_vnet_hdr = tap_has_vnet_hdr(nc->peer); |
333 | 6e371ab8 | Michael S. Tsirkin | } |
334 | 3a330134 | Mark McLoughlin | |
335 | 6e371ab8 | Michael S. Tsirkin | static int peer_has_vnet_hdr(VirtIONet *n) |
336 | 6e371ab8 | Michael S. Tsirkin | { |
337 | 3a330134 | Mark McLoughlin | return n->has_vnet_hdr;
|
338 | 3a330134 | Mark McLoughlin | } |
339 | 3a330134 | Mark McLoughlin | |
340 | 0ce0e8f4 | Mark McLoughlin | static int peer_has_ufo(VirtIONet *n) |
341 | 0ce0e8f4 | Mark McLoughlin | { |
342 | 0ce0e8f4 | Mark McLoughlin | if (!peer_has_vnet_hdr(n))
|
343 | 0ce0e8f4 | Mark McLoughlin | return 0; |
344 | 0ce0e8f4 | Mark McLoughlin | |
345 | b356f76d | Jason Wang | n->has_ufo = tap_has_ufo(qemu_get_queue(n->nic)->peer); |
346 | 0ce0e8f4 | Mark McLoughlin | |
347 | 0ce0e8f4 | Mark McLoughlin | return n->has_ufo;
|
348 | 0ce0e8f4 | Mark McLoughlin | } |
349 | 0ce0e8f4 | Mark McLoughlin | |
350 | ff3a8066 | Michael S. Tsirkin | static void virtio_net_set_mrg_rx_bufs(VirtIONet *n, int mergeable_rx_bufs) |
351 | ff3a8066 | Michael S. Tsirkin | { |
352 | fed699f9 | Jason Wang | int i;
|
353 | fed699f9 | Jason Wang | NetClientState *nc; |
354 | fed699f9 | Jason Wang | |
355 | ff3a8066 | Michael S. Tsirkin | n->mergeable_rx_bufs = mergeable_rx_bufs; |
356 | ff3a8066 | Michael S. Tsirkin | |
357 | ff3a8066 | Michael S. Tsirkin | n->guest_hdr_len = n->mergeable_rx_bufs ? |
358 | ff3a8066 | Michael S. Tsirkin | sizeof(struct virtio_net_hdr_mrg_rxbuf) : sizeof(struct virtio_net_hdr); |
359 | ff3a8066 | Michael S. Tsirkin | |
360 | fed699f9 | Jason Wang | for (i = 0; i < n->max_queues; i++) { |
361 | fed699f9 | Jason Wang | nc = qemu_get_subqueue(n->nic, i); |
362 | fed699f9 | Jason Wang | |
363 | fed699f9 | Jason Wang | if (peer_has_vnet_hdr(n) &&
|
364 | fed699f9 | Jason Wang | tap_has_vnet_hdr_len(nc->peer, n->guest_hdr_len)) { |
365 | fed699f9 | Jason Wang | tap_set_vnet_hdr_len(nc->peer, n->guest_hdr_len); |
366 | fed699f9 | Jason Wang | n->host_hdr_len = n->guest_hdr_len; |
367 | fed699f9 | Jason Wang | } |
368 | ff3a8066 | Michael S. Tsirkin | } |
369 | ff3a8066 | Michael S. Tsirkin | } |
370 | ff3a8066 | Michael S. Tsirkin | |
371 | fed699f9 | Jason Wang | static int peer_attach(VirtIONet *n, int index) |
372 | fed699f9 | Jason Wang | { |
373 | fed699f9 | Jason Wang | NetClientState *nc = qemu_get_subqueue(n->nic, index); |
374 | fed699f9 | Jason Wang | |
375 | fed699f9 | Jason Wang | if (!nc->peer) {
|
376 | fed699f9 | Jason Wang | return 0; |
377 | fed699f9 | Jason Wang | } |
378 | fed699f9 | Jason Wang | |
379 | fed699f9 | Jason Wang | if (nc->peer->info->type != NET_CLIENT_OPTIONS_KIND_TAP) {
|
380 | fed699f9 | Jason Wang | return 0; |
381 | fed699f9 | Jason Wang | } |
382 | fed699f9 | Jason Wang | |
383 | fed699f9 | Jason Wang | return tap_enable(nc->peer);
|
384 | fed699f9 | Jason Wang | } |
385 | fed699f9 | Jason Wang | |
386 | fed699f9 | Jason Wang | static int peer_detach(VirtIONet *n, int index) |
387 | fed699f9 | Jason Wang | { |
388 | fed699f9 | Jason Wang | NetClientState *nc = qemu_get_subqueue(n->nic, index); |
389 | fed699f9 | Jason Wang | |
390 | fed699f9 | Jason Wang | if (!nc->peer) {
|
391 | fed699f9 | Jason Wang | return 0; |
392 | fed699f9 | Jason Wang | } |
393 | fed699f9 | Jason Wang | |
394 | fed699f9 | Jason Wang | if (nc->peer->info->type != NET_CLIENT_OPTIONS_KIND_TAP) {
|
395 | fed699f9 | Jason Wang | return 0; |
396 | fed699f9 | Jason Wang | } |
397 | fed699f9 | Jason Wang | |
398 | fed699f9 | Jason Wang | return tap_disable(nc->peer);
|
399 | fed699f9 | Jason Wang | } |
400 | fed699f9 | Jason Wang | |
401 | fed699f9 | Jason Wang | static void virtio_net_set_queues(VirtIONet *n) |
402 | fed699f9 | Jason Wang | { |
403 | fed699f9 | Jason Wang | int i;
|
404 | fed699f9 | Jason Wang | |
405 | fed699f9 | Jason Wang | for (i = 0; i < n->max_queues; i++) { |
406 | fed699f9 | Jason Wang | if (i < n->curr_queues) {
|
407 | fed699f9 | Jason Wang | assert(!peer_attach(n, i)); |
408 | fed699f9 | Jason Wang | } else {
|
409 | fed699f9 | Jason Wang | assert(!peer_detach(n, i)); |
410 | fed699f9 | Jason Wang | } |
411 | fed699f9 | Jason Wang | } |
412 | fed699f9 | Jason Wang | } |
413 | fed699f9 | Jason Wang | |
414 | ec57db16 | Jason Wang | static void virtio_net_set_multiqueue(VirtIONet *n, int multiqueue); |
415 | fed699f9 | Jason Wang | |
416 | 8172539d | Michael S. Tsirkin | static uint32_t virtio_net_get_features(VirtIODevice *vdev, uint32_t features)
|
417 | fbe78f4f | aliguori | { |
418 | 17a0ca55 | KONRAD Frederic | VirtIONet *n = VIRTIO_NET(vdev); |
419 | b356f76d | Jason Wang | NetClientState *nc = qemu_get_queue(n->nic); |
420 | fbe78f4f | aliguori | |
421 | c9f79a3f | Michael S. Tsirkin | features |= (1 << VIRTIO_NET_F_MAC);
|
422 | c9f79a3f | Michael S. Tsirkin | |
423 | 6e371ab8 | Michael S. Tsirkin | if (!peer_has_vnet_hdr(n)) {
|
424 | 8172539d | Michael S. Tsirkin | features &= ~(0x1 << VIRTIO_NET_F_CSUM);
|
425 | 8172539d | Michael S. Tsirkin | features &= ~(0x1 << VIRTIO_NET_F_HOST_TSO4);
|
426 | 8172539d | Michael S. Tsirkin | features &= ~(0x1 << VIRTIO_NET_F_HOST_TSO6);
|
427 | 8172539d | Michael S. Tsirkin | features &= ~(0x1 << VIRTIO_NET_F_HOST_ECN);
|
428 | 8172539d | Michael S. Tsirkin | |
429 | 8172539d | Michael S. Tsirkin | features &= ~(0x1 << VIRTIO_NET_F_GUEST_CSUM);
|
430 | 8172539d | Michael S. Tsirkin | features &= ~(0x1 << VIRTIO_NET_F_GUEST_TSO4);
|
431 | 8172539d | Michael S. Tsirkin | features &= ~(0x1 << VIRTIO_NET_F_GUEST_TSO6);
|
432 | 8172539d | Michael S. Tsirkin | features &= ~(0x1 << VIRTIO_NET_F_GUEST_ECN);
|
433 | 8172539d | Michael S. Tsirkin | } |
434 | 3a330134 | Mark McLoughlin | |
435 | 8172539d | Michael S. Tsirkin | if (!peer_has_vnet_hdr(n) || !peer_has_ufo(n)) {
|
436 | 8172539d | Michael S. Tsirkin | features &= ~(0x1 << VIRTIO_NET_F_GUEST_UFO);
|
437 | 8172539d | Michael S. Tsirkin | features &= ~(0x1 << VIRTIO_NET_F_HOST_UFO);
|
438 | 3a330134 | Mark McLoughlin | } |
439 | 3a330134 | Mark McLoughlin | |
440 | b356f76d | Jason Wang | if (!nc->peer || nc->peer->info->type != NET_CLIENT_OPTIONS_KIND_TAP) {
|
441 | 9bc6304c | Michael S. Tsirkin | return features;
|
442 | 9bc6304c | Michael S. Tsirkin | } |
443 | b356f76d | Jason Wang | if (!tap_get_vhost_net(nc->peer)) {
|
444 | 9bc6304c | Michael S. Tsirkin | return features;
|
445 | 9bc6304c | Michael S. Tsirkin | } |
446 | b356f76d | Jason Wang | return vhost_net_get_features(tap_get_vhost_net(nc->peer), features);
|
447 | fbe78f4f | aliguori | } |
448 | fbe78f4f | aliguori | |
449 | 8eca6b1b | aliguori | static uint32_t virtio_net_bad_features(VirtIODevice *vdev)
|
450 | 8eca6b1b | aliguori | { |
451 | 8eca6b1b | aliguori | uint32_t features = 0;
|
452 | 8eca6b1b | aliguori | |
453 | 8eca6b1b | aliguori | /* Linux kernel 2.6.25. It understood MAC (as everyone must),
|
454 | 8eca6b1b | aliguori | * but also these: */
|
455 | 8eca6b1b | aliguori | features |= (1 << VIRTIO_NET_F_MAC);
|
456 | 184bd048 | Dustin Kirkland | features |= (1 << VIRTIO_NET_F_CSUM);
|
457 | 184bd048 | Dustin Kirkland | features |= (1 << VIRTIO_NET_F_HOST_TSO4);
|
458 | 184bd048 | Dustin Kirkland | features |= (1 << VIRTIO_NET_F_HOST_TSO6);
|
459 | 184bd048 | Dustin Kirkland | features |= (1 << VIRTIO_NET_F_HOST_ECN);
|
460 | 8eca6b1b | aliguori | |
461 | 8172539d | Michael S. Tsirkin | return features;
|
462 | 8eca6b1b | aliguori | } |
463 | 8eca6b1b | aliguori | |
464 | 644c9858 | Dmitry Fleytman | static void virtio_net_apply_guest_offloads(VirtIONet *n) |
465 | 644c9858 | Dmitry Fleytman | { |
466 | 644c9858 | Dmitry Fleytman | tap_set_offload(qemu_get_subqueue(n->nic, 0)->peer,
|
467 | 644c9858 | Dmitry Fleytman | !!(n->curr_guest_offloads & (1ULL << VIRTIO_NET_F_GUEST_CSUM)),
|
468 | 644c9858 | Dmitry Fleytman | !!(n->curr_guest_offloads & (1ULL << VIRTIO_NET_F_GUEST_TSO4)),
|
469 | 644c9858 | Dmitry Fleytman | !!(n->curr_guest_offloads & (1ULL << VIRTIO_NET_F_GUEST_TSO6)),
|
470 | 644c9858 | Dmitry Fleytman | !!(n->curr_guest_offloads & (1ULL << VIRTIO_NET_F_GUEST_ECN)),
|
471 | 644c9858 | Dmitry Fleytman | !!(n->curr_guest_offloads & (1ULL << VIRTIO_NET_F_GUEST_UFO)));
|
472 | 644c9858 | Dmitry Fleytman | } |
473 | 644c9858 | Dmitry Fleytman | |
474 | 644c9858 | Dmitry Fleytman | static uint64_t virtio_net_guest_offloads_by_features(uint32_t features)
|
475 | 644c9858 | Dmitry Fleytman | { |
476 | 644c9858 | Dmitry Fleytman | static const uint64_t guest_offloads_mask = |
477 | 644c9858 | Dmitry Fleytman | (1ULL << VIRTIO_NET_F_GUEST_CSUM) |
|
478 | 644c9858 | Dmitry Fleytman | (1ULL << VIRTIO_NET_F_GUEST_TSO4) |
|
479 | 644c9858 | Dmitry Fleytman | (1ULL << VIRTIO_NET_F_GUEST_TSO6) |
|
480 | 644c9858 | Dmitry Fleytman | (1ULL << VIRTIO_NET_F_GUEST_ECN) |
|
481 | 644c9858 | Dmitry Fleytman | (1ULL << VIRTIO_NET_F_GUEST_UFO);
|
482 | 644c9858 | Dmitry Fleytman | |
483 | 644c9858 | Dmitry Fleytman | return guest_offloads_mask & features;
|
484 | 644c9858 | Dmitry Fleytman | } |
485 | 644c9858 | Dmitry Fleytman | |
486 | 644c9858 | Dmitry Fleytman | static inline uint64_t virtio_net_supported_guest_offloads(VirtIONet *n) |
487 | 644c9858 | Dmitry Fleytman | { |
488 | 644c9858 | Dmitry Fleytman | VirtIODevice *vdev = VIRTIO_DEVICE(n); |
489 | 644c9858 | Dmitry Fleytman | return virtio_net_guest_offloads_by_features(vdev->guest_features);
|
490 | 644c9858 | Dmitry Fleytman | } |
491 | 644c9858 | Dmitry Fleytman | |
492 | fbe78f4f | aliguori | static void virtio_net_set_features(VirtIODevice *vdev, uint32_t features) |
493 | fbe78f4f | aliguori | { |
494 | 17a0ca55 | KONRAD Frederic | VirtIONet *n = VIRTIO_NET(vdev); |
495 | fed699f9 | Jason Wang | int i;
|
496 | fed699f9 | Jason Wang | |
497 | ec57db16 | Jason Wang | virtio_net_set_multiqueue(n, !!(features & (1 << VIRTIO_NET_F_MQ)));
|
498 | fbe78f4f | aliguori | |
499 | ff3a8066 | Michael S. Tsirkin | virtio_net_set_mrg_rx_bufs(n, !!(features & (1 << VIRTIO_NET_F_MRG_RXBUF)));
|
500 | f5436dd9 | Mark McLoughlin | |
501 | f5436dd9 | Mark McLoughlin | if (n->has_vnet_hdr) {
|
502 | 644c9858 | Dmitry Fleytman | n->curr_guest_offloads = |
503 | 644c9858 | Dmitry Fleytman | virtio_net_guest_offloads_by_features(features); |
504 | 644c9858 | Dmitry Fleytman | virtio_net_apply_guest_offloads(n); |
505 | f5436dd9 | Mark McLoughlin | } |
506 | fed699f9 | Jason Wang | |
507 | fed699f9 | Jason Wang | for (i = 0; i < n->max_queues; i++) { |
508 | fed699f9 | Jason Wang | NetClientState *nc = qemu_get_subqueue(n->nic, i); |
509 | fed699f9 | Jason Wang | |
510 | fed699f9 | Jason Wang | if (!nc->peer || nc->peer->info->type != NET_CLIENT_OPTIONS_KIND_TAP) {
|
511 | fed699f9 | Jason Wang | continue;
|
512 | fed699f9 | Jason Wang | } |
513 | fed699f9 | Jason Wang | if (!tap_get_vhost_net(nc->peer)) {
|
514 | fed699f9 | Jason Wang | continue;
|
515 | fed699f9 | Jason Wang | } |
516 | fed699f9 | Jason Wang | vhost_net_ack_features(tap_get_vhost_net(nc->peer), features); |
517 | dc14a397 | David L Stevens | } |
518 | fbe78f4f | aliguori | } |
519 | fbe78f4f | aliguori | |
520 | 002437cd | aliguori | static int virtio_net_handle_rx_mode(VirtIONet *n, uint8_t cmd, |
521 | 921ac5d0 | Michael S. Tsirkin | struct iovec *iov, unsigned int iov_cnt) |
522 | 002437cd | aliguori | { |
523 | 002437cd | aliguori | uint8_t on; |
524 | 921ac5d0 | Michael S. Tsirkin | size_t s; |
525 | b1be4280 | Amos Kong | NetClientState *nc = qemu_get_queue(n->nic); |
526 | 002437cd | aliguori | |
527 | 921ac5d0 | Michael S. Tsirkin | s = iov_to_buf(iov, iov_cnt, 0, &on, sizeof(on)); |
528 | 921ac5d0 | Michael S. Tsirkin | if (s != sizeof(on)) { |
529 | 921ac5d0 | Michael S. Tsirkin | return VIRTIO_NET_ERR;
|
530 | 002437cd | aliguori | } |
531 | 002437cd | aliguori | |
532 | dd23454b | Amos Kong | if (cmd == VIRTIO_NET_CTRL_RX_PROMISC) {
|
533 | 002437cd | aliguori | n->promisc = on; |
534 | dd23454b | Amos Kong | } else if (cmd == VIRTIO_NET_CTRL_RX_ALLMULTI) { |
535 | 002437cd | aliguori | n->allmulti = on; |
536 | dd23454b | Amos Kong | } else if (cmd == VIRTIO_NET_CTRL_RX_ALLUNI) { |
537 | 015cb166 | Alex Williamson | n->alluni = on; |
538 | dd23454b | Amos Kong | } else if (cmd == VIRTIO_NET_CTRL_RX_NOMULTI) { |
539 | 015cb166 | Alex Williamson | n->nomulti = on; |
540 | dd23454b | Amos Kong | } else if (cmd == VIRTIO_NET_CTRL_RX_NOUNI) { |
541 | 015cb166 | Alex Williamson | n->nouni = on; |
542 | dd23454b | Amos Kong | } else if (cmd == VIRTIO_NET_CTRL_RX_NOBCAST) { |
543 | 015cb166 | Alex Williamson | n->nobcast = on; |
544 | 921ac5d0 | Michael S. Tsirkin | } else {
|
545 | 002437cd | aliguori | return VIRTIO_NET_ERR;
|
546 | 921ac5d0 | Michael S. Tsirkin | } |
547 | 002437cd | aliguori | |
548 | b1be4280 | Amos Kong | rxfilter_notify(nc); |
549 | b1be4280 | Amos Kong | |
550 | 002437cd | aliguori | return VIRTIO_NET_OK;
|
551 | 002437cd | aliguori | } |
552 | 002437cd | aliguori | |
553 | 644c9858 | Dmitry Fleytman | static int virtio_net_handle_offloads(VirtIONet *n, uint8_t cmd, |
554 | 644c9858 | Dmitry Fleytman | struct iovec *iov, unsigned int iov_cnt) |
555 | 644c9858 | Dmitry Fleytman | { |
556 | 644c9858 | Dmitry Fleytman | VirtIODevice *vdev = VIRTIO_DEVICE(n); |
557 | 644c9858 | Dmitry Fleytman | uint64_t offloads; |
558 | 644c9858 | Dmitry Fleytman | size_t s; |
559 | 644c9858 | Dmitry Fleytman | |
560 | 644c9858 | Dmitry Fleytman | if (!((1 << VIRTIO_NET_F_CTRL_GUEST_OFFLOADS) & vdev->guest_features)) { |
561 | 644c9858 | Dmitry Fleytman | return VIRTIO_NET_ERR;
|
562 | 644c9858 | Dmitry Fleytman | } |
563 | 644c9858 | Dmitry Fleytman | |
564 | 644c9858 | Dmitry Fleytman | s = iov_to_buf(iov, iov_cnt, 0, &offloads, sizeof(offloads)); |
565 | 644c9858 | Dmitry Fleytman | if (s != sizeof(offloads)) { |
566 | 644c9858 | Dmitry Fleytman | return VIRTIO_NET_ERR;
|
567 | 644c9858 | Dmitry Fleytman | } |
568 | 644c9858 | Dmitry Fleytman | |
569 | 644c9858 | Dmitry Fleytman | if (cmd == VIRTIO_NET_CTRL_GUEST_OFFLOADS_SET) {
|
570 | 644c9858 | Dmitry Fleytman | uint64_t supported_offloads; |
571 | 644c9858 | Dmitry Fleytman | |
572 | 644c9858 | Dmitry Fleytman | if (!n->has_vnet_hdr) {
|
573 | 644c9858 | Dmitry Fleytman | return VIRTIO_NET_ERR;
|
574 | 644c9858 | Dmitry Fleytman | } |
575 | 644c9858 | Dmitry Fleytman | |
576 | 644c9858 | Dmitry Fleytman | supported_offloads = virtio_net_supported_guest_offloads(n); |
577 | 644c9858 | Dmitry Fleytman | if (offloads & ~supported_offloads) {
|
578 | 644c9858 | Dmitry Fleytman | return VIRTIO_NET_ERR;
|
579 | 644c9858 | Dmitry Fleytman | } |
580 | 644c9858 | Dmitry Fleytman | |
581 | 644c9858 | Dmitry Fleytman | n->curr_guest_offloads = offloads; |
582 | 644c9858 | Dmitry Fleytman | virtio_net_apply_guest_offloads(n); |
583 | 644c9858 | Dmitry Fleytman | |
584 | 644c9858 | Dmitry Fleytman | return VIRTIO_NET_OK;
|
585 | 644c9858 | Dmitry Fleytman | } else {
|
586 | 644c9858 | Dmitry Fleytman | return VIRTIO_NET_ERR;
|
587 | 644c9858 | Dmitry Fleytman | } |
588 | 644c9858 | Dmitry Fleytman | } |
589 | 644c9858 | Dmitry Fleytman | |
590 | b6503ed9 | aliguori | static int virtio_net_handle_mac(VirtIONet *n, uint8_t cmd, |
591 | 921ac5d0 | Michael S. Tsirkin | struct iovec *iov, unsigned int iov_cnt) |
592 | b6503ed9 | aliguori | { |
593 | b6503ed9 | aliguori | struct virtio_net_ctrl_mac mac_data;
|
594 | 921ac5d0 | Michael S. Tsirkin | size_t s; |
595 | b1be4280 | Amos Kong | NetClientState *nc = qemu_get_queue(n->nic); |
596 | b6503ed9 | aliguori | |
597 | c1943a3f | Amos Kong | if (cmd == VIRTIO_NET_CTRL_MAC_ADDR_SET) {
|
598 | c1943a3f | Amos Kong | if (iov_size(iov, iov_cnt) != sizeof(n->mac)) { |
599 | c1943a3f | Amos Kong | return VIRTIO_NET_ERR;
|
600 | c1943a3f | Amos Kong | } |
601 | c1943a3f | Amos Kong | s = iov_to_buf(iov, iov_cnt, 0, &n->mac, sizeof(n->mac)); |
602 | c1943a3f | Amos Kong | assert(s == sizeof(n->mac));
|
603 | b356f76d | Jason Wang | qemu_format_nic_info_str(qemu_get_queue(n->nic), n->mac); |
604 | b1be4280 | Amos Kong | rxfilter_notify(nc); |
605 | b1be4280 | Amos Kong | |
606 | c1943a3f | Amos Kong | return VIRTIO_NET_OK;
|
607 | c1943a3f | Amos Kong | } |
608 | c1943a3f | Amos Kong | |
609 | 921ac5d0 | Michael S. Tsirkin | if (cmd != VIRTIO_NET_CTRL_MAC_TABLE_SET) {
|
610 | b6503ed9 | aliguori | return VIRTIO_NET_ERR;
|
611 | 921ac5d0 | Michael S. Tsirkin | } |
612 | b6503ed9 | aliguori | |
613 | cae2e556 | Amos Kong | int in_use = 0; |
614 | cae2e556 | Amos Kong | int first_multi = 0; |
615 | cae2e556 | Amos Kong | uint8_t uni_overflow = 0;
|
616 | cae2e556 | Amos Kong | uint8_t multi_overflow = 0;
|
617 | cae2e556 | Amos Kong | uint8_t *macs = g_malloc0(MAC_TABLE_ENTRIES * ETH_ALEN); |
618 | b6503ed9 | aliguori | |
619 | 921ac5d0 | Michael S. Tsirkin | s = iov_to_buf(iov, iov_cnt, 0, &mac_data.entries,
|
620 | 921ac5d0 | Michael S. Tsirkin | sizeof(mac_data.entries));
|
621 | 921ac5d0 | Michael S. Tsirkin | mac_data.entries = ldl_p(&mac_data.entries); |
622 | 921ac5d0 | Michael S. Tsirkin | if (s != sizeof(mac_data.entries)) { |
623 | b1be4280 | Amos Kong | goto error;
|
624 | 921ac5d0 | Michael S. Tsirkin | } |
625 | 921ac5d0 | Michael S. Tsirkin | iov_discard_front(&iov, &iov_cnt, s); |
626 | b6503ed9 | aliguori | |
627 | 921ac5d0 | Michael S. Tsirkin | if (mac_data.entries * ETH_ALEN > iov_size(iov, iov_cnt)) {
|
628 | b1be4280 | Amos Kong | goto error;
|
629 | 921ac5d0 | Michael S. Tsirkin | } |
630 | b6503ed9 | aliguori | |
631 | b6503ed9 | aliguori | if (mac_data.entries <= MAC_TABLE_ENTRIES) {
|
632 | cae2e556 | Amos Kong | s = iov_to_buf(iov, iov_cnt, 0, macs,
|
633 | 921ac5d0 | Michael S. Tsirkin | mac_data.entries * ETH_ALEN); |
634 | 921ac5d0 | Michael S. Tsirkin | if (s != mac_data.entries * ETH_ALEN) {
|
635 | b1be4280 | Amos Kong | goto error;
|
636 | 921ac5d0 | Michael S. Tsirkin | } |
637 | cae2e556 | Amos Kong | in_use += mac_data.entries; |
638 | b6503ed9 | aliguori | } else {
|
639 | cae2e556 | Amos Kong | uni_overflow = 1;
|
640 | b6503ed9 | aliguori | } |
641 | b6503ed9 | aliguori | |
642 | 921ac5d0 | Michael S. Tsirkin | iov_discard_front(&iov, &iov_cnt, mac_data.entries * ETH_ALEN); |
643 | 921ac5d0 | Michael S. Tsirkin | |
644 | cae2e556 | Amos Kong | first_multi = in_use; |
645 | 2d9aba39 | Alex Williamson | |
646 | 921ac5d0 | Michael S. Tsirkin | s = iov_to_buf(iov, iov_cnt, 0, &mac_data.entries,
|
647 | 921ac5d0 | Michael S. Tsirkin | sizeof(mac_data.entries));
|
648 | 921ac5d0 | Michael S. Tsirkin | mac_data.entries = ldl_p(&mac_data.entries); |
649 | 921ac5d0 | Michael S. Tsirkin | if (s != sizeof(mac_data.entries)) { |
650 | b1be4280 | Amos Kong | goto error;
|
651 | 921ac5d0 | Michael S. Tsirkin | } |
652 | 921ac5d0 | Michael S. Tsirkin | |
653 | 921ac5d0 | Michael S. Tsirkin | iov_discard_front(&iov, &iov_cnt, s); |
654 | b6503ed9 | aliguori | |
655 | 921ac5d0 | Michael S. Tsirkin | if (mac_data.entries * ETH_ALEN != iov_size(iov, iov_cnt)) {
|
656 | b1be4280 | Amos Kong | goto error;
|
657 | 921ac5d0 | Michael S. Tsirkin | } |
658 | b6503ed9 | aliguori | |
659 | cae2e556 | Amos Kong | if (in_use + mac_data.entries <= MAC_TABLE_ENTRIES) {
|
660 | cae2e556 | Amos Kong | s = iov_to_buf(iov, iov_cnt, 0, &macs[in_use * ETH_ALEN],
|
661 | 921ac5d0 | Michael S. Tsirkin | mac_data.entries * ETH_ALEN); |
662 | 921ac5d0 | Michael S. Tsirkin | if (s != mac_data.entries * ETH_ALEN) {
|
663 | b1be4280 | Amos Kong | goto error;
|
664 | 8fd2a2f1 | Alex Williamson | } |
665 | cae2e556 | Amos Kong | in_use += mac_data.entries; |
666 | 921ac5d0 | Michael S. Tsirkin | } else {
|
667 | cae2e556 | Amos Kong | multi_overflow = 1;
|
668 | b6503ed9 | aliguori | } |
669 | b6503ed9 | aliguori | |
670 | cae2e556 | Amos Kong | n->mac_table.in_use = in_use; |
671 | cae2e556 | Amos Kong | n->mac_table.first_multi = first_multi; |
672 | cae2e556 | Amos Kong | n->mac_table.uni_overflow = uni_overflow; |
673 | cae2e556 | Amos Kong | n->mac_table.multi_overflow = multi_overflow; |
674 | cae2e556 | Amos Kong | memcpy(n->mac_table.macs, macs, MAC_TABLE_ENTRIES * ETH_ALEN); |
675 | cae2e556 | Amos Kong | g_free(macs); |
676 | b1be4280 | Amos Kong | rxfilter_notify(nc); |
677 | b1be4280 | Amos Kong | |
678 | b6503ed9 | aliguori | return VIRTIO_NET_OK;
|
679 | b1be4280 | Amos Kong | |
680 | b1be4280 | Amos Kong | error:
|
681 | cae2e556 | Amos Kong | g_free(macs); |
682 | b1be4280 | Amos Kong | return VIRTIO_NET_ERR;
|
683 | b6503ed9 | aliguori | } |
684 | b6503ed9 | aliguori | |
685 | f21c0ed9 | aliguori | static int virtio_net_handle_vlan_table(VirtIONet *n, uint8_t cmd, |
686 | 921ac5d0 | Michael S. Tsirkin | struct iovec *iov, unsigned int iov_cnt) |
687 | f21c0ed9 | aliguori | { |
688 | f21c0ed9 | aliguori | uint16_t vid; |
689 | 921ac5d0 | Michael S. Tsirkin | size_t s; |
690 | b1be4280 | Amos Kong | NetClientState *nc = qemu_get_queue(n->nic); |
691 | f21c0ed9 | aliguori | |
692 | 921ac5d0 | Michael S. Tsirkin | s = iov_to_buf(iov, iov_cnt, 0, &vid, sizeof(vid)); |
693 | 921ac5d0 | Michael S. Tsirkin | vid = lduw_p(&vid); |
694 | 921ac5d0 | Michael S. Tsirkin | if (s != sizeof(vid)) { |
695 | f21c0ed9 | aliguori | return VIRTIO_NET_ERR;
|
696 | f21c0ed9 | aliguori | } |
697 | f21c0ed9 | aliguori | |
698 | f21c0ed9 | aliguori | if (vid >= MAX_VLAN)
|
699 | f21c0ed9 | aliguori | return VIRTIO_NET_ERR;
|
700 | f21c0ed9 | aliguori | |
701 | f21c0ed9 | aliguori | if (cmd == VIRTIO_NET_CTRL_VLAN_ADD)
|
702 | f21c0ed9 | aliguori | n->vlans[vid >> 5] |= (1U << (vid & 0x1f)); |
703 | f21c0ed9 | aliguori | else if (cmd == VIRTIO_NET_CTRL_VLAN_DEL) |
704 | f21c0ed9 | aliguori | n->vlans[vid >> 5] &= ~(1U << (vid & 0x1f)); |
705 | f21c0ed9 | aliguori | else
|
706 | f21c0ed9 | aliguori | return VIRTIO_NET_ERR;
|
707 | f21c0ed9 | aliguori | |
708 | b1be4280 | Amos Kong | rxfilter_notify(nc); |
709 | b1be4280 | Amos Kong | |
710 | f21c0ed9 | aliguori | return VIRTIO_NET_OK;
|
711 | f21c0ed9 | aliguori | } |
712 | f21c0ed9 | aliguori | |
713 | fed699f9 | Jason Wang | static int virtio_net_handle_mq(VirtIONet *n, uint8_t cmd, |
714 | f8f7c533 | Jason Wang | struct iovec *iov, unsigned int iov_cnt) |
715 | fed699f9 | Jason Wang | { |
716 | 17a0ca55 | KONRAD Frederic | VirtIODevice *vdev = VIRTIO_DEVICE(n); |
717 | f8f7c533 | Jason Wang | struct virtio_net_ctrl_mq mq;
|
718 | f8f7c533 | Jason Wang | size_t s; |
719 | f8f7c533 | Jason Wang | uint16_t queues; |
720 | fed699f9 | Jason Wang | |
721 | f8f7c533 | Jason Wang | s = iov_to_buf(iov, iov_cnt, 0, &mq, sizeof(mq)); |
722 | f8f7c533 | Jason Wang | if (s != sizeof(mq)) { |
723 | fed699f9 | Jason Wang | return VIRTIO_NET_ERR;
|
724 | fed699f9 | Jason Wang | } |
725 | fed699f9 | Jason Wang | |
726 | fed699f9 | Jason Wang | if (cmd != VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET) {
|
727 | fed699f9 | Jason Wang | return VIRTIO_NET_ERR;
|
728 | fed699f9 | Jason Wang | } |
729 | fed699f9 | Jason Wang | |
730 | f8f7c533 | Jason Wang | queues = lduw_p(&mq.virtqueue_pairs); |
731 | fed699f9 | Jason Wang | |
732 | f8f7c533 | Jason Wang | if (queues < VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MIN ||
|
733 | f8f7c533 | Jason Wang | queues > VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MAX || |
734 | f8f7c533 | Jason Wang | queues > n->max_queues || |
735 | fed699f9 | Jason Wang | !n->multiqueue) { |
736 | fed699f9 | Jason Wang | return VIRTIO_NET_ERR;
|
737 | fed699f9 | Jason Wang | } |
738 | fed699f9 | Jason Wang | |
739 | f8f7c533 | Jason Wang | n->curr_queues = queues; |
740 | fed699f9 | Jason Wang | /* stop the backend before changing the number of queues to avoid handling a
|
741 | fed699f9 | Jason Wang | * disabled queue */
|
742 | 17a0ca55 | KONRAD Frederic | virtio_net_set_status(vdev, vdev->status); |
743 | fed699f9 | Jason Wang | virtio_net_set_queues(n); |
744 | fed699f9 | Jason Wang | |
745 | fed699f9 | Jason Wang | return VIRTIO_NET_OK;
|
746 | fed699f9 | Jason Wang | } |
747 | 3d11d36c | aliguori | static void virtio_net_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq) |
748 | 3d11d36c | aliguori | { |
749 | 17a0ca55 | KONRAD Frederic | VirtIONet *n = VIRTIO_NET(vdev); |
750 | 3d11d36c | aliguori | struct virtio_net_ctrl_hdr ctrl;
|
751 | 3d11d36c | aliguori | virtio_net_ctrl_ack status = VIRTIO_NET_ERR; |
752 | 3d11d36c | aliguori | VirtQueueElement elem; |
753 | 921ac5d0 | Michael S. Tsirkin | size_t s; |
754 | 921ac5d0 | Michael S. Tsirkin | struct iovec *iov;
|
755 | 921ac5d0 | Michael S. Tsirkin | unsigned int iov_cnt; |
756 | 3d11d36c | aliguori | |
757 | 3d11d36c | aliguori | while (virtqueue_pop(vq, &elem)) {
|
758 | 921ac5d0 | Michael S. Tsirkin | if (iov_size(elem.in_sg, elem.in_num) < sizeof(status) || |
759 | 921ac5d0 | Michael S. Tsirkin | iov_size(elem.out_sg, elem.out_num) < sizeof(ctrl)) {
|
760 | e7b43f7e | Stefan Hajnoczi | error_report("virtio-net ctrl missing headers");
|
761 | 3d11d36c | aliguori | exit(1);
|
762 | 3d11d36c | aliguori | } |
763 | 3d11d36c | aliguori | |
764 | 921ac5d0 | Michael S. Tsirkin | iov = elem.out_sg; |
765 | 921ac5d0 | Michael S. Tsirkin | iov_cnt = elem.out_num; |
766 | 921ac5d0 | Michael S. Tsirkin | s = iov_to_buf(iov, iov_cnt, 0, &ctrl, sizeof(ctrl)); |
767 | 921ac5d0 | Michael S. Tsirkin | iov_discard_front(&iov, &iov_cnt, sizeof(ctrl));
|
768 | 921ac5d0 | Michael S. Tsirkin | if (s != sizeof(ctrl)) { |
769 | 921ac5d0 | Michael S. Tsirkin | status = VIRTIO_NET_ERR; |
770 | dd23454b | Amos Kong | } else if (ctrl.class == VIRTIO_NET_CTRL_RX) { |
771 | 921ac5d0 | Michael S. Tsirkin | status = virtio_net_handle_rx_mode(n, ctrl.cmd, iov, iov_cnt); |
772 | 921ac5d0 | Michael S. Tsirkin | } else if (ctrl.class == VIRTIO_NET_CTRL_MAC) { |
773 | 921ac5d0 | Michael S. Tsirkin | status = virtio_net_handle_mac(n, ctrl.cmd, iov, iov_cnt); |
774 | 921ac5d0 | Michael S. Tsirkin | } else if (ctrl.class == VIRTIO_NET_CTRL_VLAN) { |
775 | 921ac5d0 | Michael S. Tsirkin | status = virtio_net_handle_vlan_table(n, ctrl.cmd, iov, iov_cnt); |
776 | fed699f9 | Jason Wang | } else if (ctrl.class == VIRTIO_NET_CTRL_MQ) { |
777 | f8f7c533 | Jason Wang | status = virtio_net_handle_mq(n, ctrl.cmd, iov, iov_cnt); |
778 | 644c9858 | Dmitry Fleytman | } else if (ctrl.class == VIRTIO_NET_CTRL_GUEST_OFFLOADS) { |
779 | 644c9858 | Dmitry Fleytman | status = virtio_net_handle_offloads(n, ctrl.cmd, iov, iov_cnt); |
780 | 3d11d36c | aliguori | } |
781 | 3d11d36c | aliguori | |
782 | 921ac5d0 | Michael S. Tsirkin | s = iov_from_buf(elem.in_sg, elem.in_num, 0, &status, sizeof(status)); |
783 | 921ac5d0 | Michael S. Tsirkin | assert(s == sizeof(status));
|
784 | 3d11d36c | aliguori | |
785 | 3d11d36c | aliguori | virtqueue_push(vq, &elem, sizeof(status));
|
786 | 3d11d36c | aliguori | virtio_notify(vdev, vq); |
787 | 3d11d36c | aliguori | } |
788 | 3d11d36c | aliguori | } |
789 | 3d11d36c | aliguori | |
790 | fbe78f4f | aliguori | /* RX */
|
791 | fbe78f4f | aliguori | |
792 | fbe78f4f | aliguori | static void virtio_net_handle_rx(VirtIODevice *vdev, VirtQueue *vq) |
793 | fbe78f4f | aliguori | { |
794 | 17a0ca55 | KONRAD Frederic | VirtIONet *n = VIRTIO_NET(vdev); |
795 | fed699f9 | Jason Wang | int queue_index = vq2q(virtio_get_queue_index(vq));
|
796 | 8aeff62d | Mark McLoughlin | |
797 | fed699f9 | Jason Wang | qemu_flush_queued_packets(qemu_get_subqueue(n->nic, queue_index)); |
798 | fbe78f4f | aliguori | } |
799 | fbe78f4f | aliguori | |
800 | 4e68f7a0 | Stefan Hajnoczi | static int virtio_net_can_receive(NetClientState *nc) |
801 | fbe78f4f | aliguori | { |
802 | cc1f0f45 | Jason Wang | VirtIONet *n = qemu_get_nic_opaque(nc); |
803 | 17a0ca55 | KONRAD Frederic | VirtIODevice *vdev = VIRTIO_DEVICE(n); |
804 | fed699f9 | Jason Wang | VirtIONetQueue *q = virtio_net_get_subqueue(nc); |
805 | 0c87e93e | Jason Wang | |
806 | 17a0ca55 | KONRAD Frederic | if (!vdev->vm_running) {
|
807 | 95477323 | Michael S. Tsirkin | return 0; |
808 | 95477323 | Michael S. Tsirkin | } |
809 | cdd5cc12 | Mark McLoughlin | |
810 | fed699f9 | Jason Wang | if (nc->queue_index >= n->curr_queues) {
|
811 | fed699f9 | Jason Wang | return 0; |
812 | fed699f9 | Jason Wang | } |
813 | fed699f9 | Jason Wang | |
814 | 0c87e93e | Jason Wang | if (!virtio_queue_ready(q->rx_vq) ||
|
815 | 17a0ca55 | KONRAD Frederic | !(vdev->status & VIRTIO_CONFIG_S_DRIVER_OK)) { |
816 | fbe78f4f | aliguori | return 0; |
817 | 0c87e93e | Jason Wang | } |
818 | fbe78f4f | aliguori | |
819 | cdd5cc12 | Mark McLoughlin | return 1; |
820 | cdd5cc12 | Mark McLoughlin | } |
821 | cdd5cc12 | Mark McLoughlin | |
822 | 0c87e93e | Jason Wang | static int virtio_net_has_buffers(VirtIONetQueue *q, int bufsize) |
823 | cdd5cc12 | Mark McLoughlin | { |
824 | 0c87e93e | Jason Wang | VirtIONet *n = q->n; |
825 | 0c87e93e | Jason Wang | if (virtio_queue_empty(q->rx_vq) ||
|
826 | fbe78f4f | aliguori | (n->mergeable_rx_bufs && |
827 | 0c87e93e | Jason Wang | !virtqueue_avail_bytes(q->rx_vq, bufsize, 0))) {
|
828 | 0c87e93e | Jason Wang | virtio_queue_set_notification(q->rx_vq, 1);
|
829 | 06b12970 | Tom Lendacky | |
830 | 06b12970 | Tom Lendacky | /* To avoid a race condition where the guest has made some buffers
|
831 | 06b12970 | Tom Lendacky | * available after the above check but before notification was
|
832 | 06b12970 | Tom Lendacky | * enabled, check for available buffers again.
|
833 | 06b12970 | Tom Lendacky | */
|
834 | 0c87e93e | Jason Wang | if (virtio_queue_empty(q->rx_vq) ||
|
835 | 06b12970 | Tom Lendacky | (n->mergeable_rx_bufs && |
836 | 0c87e93e | Jason Wang | !virtqueue_avail_bytes(q->rx_vq, bufsize, 0))) {
|
837 | 06b12970 | Tom Lendacky | return 0; |
838 | 0c87e93e | Jason Wang | } |
839 | fbe78f4f | aliguori | } |
840 | fbe78f4f | aliguori | |
841 | 0c87e93e | Jason Wang | virtio_queue_set_notification(q->rx_vq, 0);
|
842 | fbe78f4f | aliguori | return 1; |
843 | fbe78f4f | aliguori | } |
844 | fbe78f4f | aliguori | |
845 | 1d41b0c1 | Anthony Liguori | /* dhclient uses AF_PACKET but doesn't pass auxdata to the kernel so
|
846 | 1d41b0c1 | Anthony Liguori | * it never finds out that the packets don't have valid checksums. This
|
847 | 1d41b0c1 | Anthony Liguori | * causes dhclient to get upset. Fedora's carried a patch for ages to
|
848 | 1d41b0c1 | Anthony Liguori | * fix this with Xen but it hasn't appeared in an upstream release of
|
849 | 1d41b0c1 | Anthony Liguori | * dhclient yet.
|
850 | 1d41b0c1 | Anthony Liguori | *
|
851 | 1d41b0c1 | Anthony Liguori | * To avoid breaking existing guests, we catch udp packets and add
|
852 | 1d41b0c1 | Anthony Liguori | * checksums. This is terrible but it's better than hacking the guest
|
853 | 1d41b0c1 | Anthony Liguori | * kernels.
|
854 | 1d41b0c1 | Anthony Liguori | *
|
855 | 1d41b0c1 | Anthony Liguori | * N.B. if we introduce a zero-copy API, this operation is no longer free so
|
856 | 1d41b0c1 | Anthony Liguori | * we should provide a mechanism to disable it to avoid polluting the host
|
857 | 1d41b0c1 | Anthony Liguori | * cache.
|
858 | 1d41b0c1 | Anthony Liguori | */
|
859 | 1d41b0c1 | Anthony Liguori | static void work_around_broken_dhclient(struct virtio_net_hdr *hdr, |
860 | 22cc84db | Michael S. Tsirkin | uint8_t *buf, size_t size) |
861 | 1d41b0c1 | Anthony Liguori | { |
862 | 1d41b0c1 | Anthony Liguori | if ((hdr->flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) && /* missing csum */ |
863 | 1d41b0c1 | Anthony Liguori | (size > 27 && size < 1500) && /* normal sized MTU */ |
864 | 1d41b0c1 | Anthony Liguori | (buf[12] == 0x08 && buf[13] == 0x00) && /* ethertype == IPv4 */ |
865 | 1d41b0c1 | Anthony Liguori | (buf[23] == 17) && /* ip.protocol == UDP */ |
866 | 1d41b0c1 | Anthony Liguori | (buf[34] == 0 && buf[35] == 67)) { /* udp.srcport == bootps */ |
867 | 22cc84db | Michael S. Tsirkin | net_checksum_calculate(buf, size); |
868 | 1d41b0c1 | Anthony Liguori | hdr->flags &= ~VIRTIO_NET_HDR_F_NEEDS_CSUM; |
869 | 1d41b0c1 | Anthony Liguori | } |
870 | 1d41b0c1 | Anthony Liguori | } |
871 | 1d41b0c1 | Anthony Liguori | |
872 | 280598b7 | Michael S. Tsirkin | static void receive_header(VirtIONet *n, const struct iovec *iov, int iov_cnt, |
873 | 280598b7 | Michael S. Tsirkin | const void *buf, size_t size) |
874 | fbe78f4f | aliguori | { |
875 | 3a330134 | Mark McLoughlin | if (n->has_vnet_hdr) {
|
876 | 22cc84db | Michael S. Tsirkin | /* FIXME this cast is evil */
|
877 | 22cc84db | Michael S. Tsirkin | void *wbuf = (void *)buf; |
878 | 280598b7 | Michael S. Tsirkin | work_around_broken_dhclient(wbuf, wbuf + n->host_hdr_len, |
879 | 280598b7 | Michael S. Tsirkin | size - n->host_hdr_len); |
880 | 280598b7 | Michael S. Tsirkin | iov_from_buf(iov, iov_cnt, 0, buf, sizeof(struct virtio_net_hdr)); |
881 | 22cc84db | Michael S. Tsirkin | } else {
|
882 | 22cc84db | Michael S. Tsirkin | struct virtio_net_hdr hdr = {
|
883 | 22cc84db | Michael S. Tsirkin | .flags = 0,
|
884 | 22cc84db | Michael S. Tsirkin | .gso_type = VIRTIO_NET_HDR_GSO_NONE |
885 | 22cc84db | Michael S. Tsirkin | }; |
886 | 22cc84db | Michael S. Tsirkin | iov_from_buf(iov, iov_cnt, 0, &hdr, sizeof hdr); |
887 | 3a330134 | Mark McLoughlin | } |
888 | fbe78f4f | aliguori | } |
889 | fbe78f4f | aliguori | |
890 | 3831ab20 | aliguori | static int receive_filter(VirtIONet *n, const uint8_t *buf, int size) |
891 | 3831ab20 | aliguori | { |
892 | 3831ab20 | aliguori | static const uint8_t bcast[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; |
893 | f21c0ed9 | aliguori | static const uint8_t vlan[] = {0x81, 0x00}; |
894 | 3831ab20 | aliguori | uint8_t *ptr = (uint8_t *)buf; |
895 | b6503ed9 | aliguori | int i;
|
896 | 3831ab20 | aliguori | |
897 | 3831ab20 | aliguori | if (n->promisc)
|
898 | 3831ab20 | aliguori | return 1; |
899 | 3831ab20 | aliguori | |
900 | e043ebc6 | Michael S. Tsirkin | ptr += n->host_hdr_len; |
901 | 3a330134 | Mark McLoughlin | |
902 | f21c0ed9 | aliguori | if (!memcmp(&ptr[12], vlan, sizeof(vlan))) { |
903 | f21c0ed9 | aliguori | int vid = be16_to_cpup((uint16_t *)(ptr + 14)) & 0xfff; |
904 | f21c0ed9 | aliguori | if (!(n->vlans[vid >> 5] & (1U << (vid & 0x1f)))) |
905 | f21c0ed9 | aliguori | return 0; |
906 | f21c0ed9 | aliguori | } |
907 | f21c0ed9 | aliguori | |
908 | bbe2f399 | Alex Williamson | if (ptr[0] & 1) { // multicast |
909 | bbe2f399 | Alex Williamson | if (!memcmp(ptr, bcast, sizeof(bcast))) { |
910 | 015cb166 | Alex Williamson | return !n->nobcast;
|
911 | 015cb166 | Alex Williamson | } else if (n->nomulti) { |
912 | 015cb166 | Alex Williamson | return 0; |
913 | 8fd2a2f1 | Alex Williamson | } else if (n->allmulti || n->mac_table.multi_overflow) { |
914 | bbe2f399 | Alex Williamson | return 1; |
915 | bbe2f399 | Alex Williamson | } |
916 | 2d9aba39 | Alex Williamson | |
917 | 2d9aba39 | Alex Williamson | for (i = n->mac_table.first_multi; i < n->mac_table.in_use; i++) {
|
918 | 2d9aba39 | Alex Williamson | if (!memcmp(ptr, &n->mac_table.macs[i * ETH_ALEN], ETH_ALEN)) {
|
919 | 2d9aba39 | Alex Williamson | return 1; |
920 | 2d9aba39 | Alex Williamson | } |
921 | 2d9aba39 | Alex Williamson | } |
922 | bbe2f399 | Alex Williamson | } else { // unicast |
923 | 015cb166 | Alex Williamson | if (n->nouni) {
|
924 | 015cb166 | Alex Williamson | return 0; |
925 | 015cb166 | Alex Williamson | } else if (n->alluni || n->mac_table.uni_overflow) { |
926 | 8fd2a2f1 | Alex Williamson | return 1; |
927 | 8fd2a2f1 | Alex Williamson | } else if (!memcmp(ptr, n->mac, ETH_ALEN)) { |
928 | bbe2f399 | Alex Williamson | return 1; |
929 | bbe2f399 | Alex Williamson | } |
930 | 3831ab20 | aliguori | |
931 | 2d9aba39 | Alex Williamson | for (i = 0; i < n->mac_table.first_multi; i++) { |
932 | 2d9aba39 | Alex Williamson | if (!memcmp(ptr, &n->mac_table.macs[i * ETH_ALEN], ETH_ALEN)) {
|
933 | 2d9aba39 | Alex Williamson | return 1; |
934 | 2d9aba39 | Alex Williamson | } |
935 | 2d9aba39 | Alex Williamson | } |
936 | b6503ed9 | aliguori | } |
937 | b6503ed9 | aliguori | |
938 | 3831ab20 | aliguori | return 0; |
939 | 3831ab20 | aliguori | } |
940 | 3831ab20 | aliguori | |
941 | 4e68f7a0 | Stefan Hajnoczi | static ssize_t virtio_net_receive(NetClientState *nc, const uint8_t *buf, size_t size) |
942 | fbe78f4f | aliguori | { |
943 | cc1f0f45 | Jason Wang | VirtIONet *n = qemu_get_nic_opaque(nc); |
944 | fed699f9 | Jason Wang | VirtIONetQueue *q = virtio_net_get_subqueue(nc); |
945 | 17a0ca55 | KONRAD Frederic | VirtIODevice *vdev = VIRTIO_DEVICE(n); |
946 | 63c58728 | Michael S. Tsirkin | struct iovec mhdr_sg[VIRTQUEUE_MAX_SIZE];
|
947 | 63c58728 | Michael S. Tsirkin | struct virtio_net_hdr_mrg_rxbuf mhdr;
|
948 | 63c58728 | Michael S. Tsirkin | unsigned mhdr_cnt = 0; |
949 | 22cc84db | Michael S. Tsirkin | size_t offset, i, guest_offset; |
950 | fbe78f4f | aliguori | |
951 | fed699f9 | Jason Wang | if (!virtio_net_can_receive(nc)) {
|
952 | cdd5cc12 | Mark McLoughlin | return -1; |
953 | b356f76d | Jason Wang | } |
954 | cdd5cc12 | Mark McLoughlin | |
955 | 940cda94 | Michael S. Tsirkin | /* hdr_len refers to the header we supply to the guest */
|
956 | 0c87e93e | Jason Wang | if (!virtio_net_has_buffers(q, size + n->guest_hdr_len - n->host_hdr_len)) {
|
957 | 8aeff62d | Mark McLoughlin | return 0; |
958 | 0c87e93e | Jason Wang | } |
959 | fbe78f4f | aliguori | |
960 | 3831ab20 | aliguori | if (!receive_filter(n, buf, size))
|
961 | 4f1c942b | Mark McLoughlin | return size;
|
962 | 3831ab20 | aliguori | |
963 | fbe78f4f | aliguori | offset = i = 0;
|
964 | fbe78f4f | aliguori | |
965 | fbe78f4f | aliguori | while (offset < size) {
|
966 | fbe78f4f | aliguori | VirtQueueElement elem; |
967 | fbe78f4f | aliguori | int len, total;
|
968 | 22cc84db | Michael S. Tsirkin | const struct iovec *sg = elem.in_sg; |
969 | fbe78f4f | aliguori | |
970 | 22c253d9 | Amit Shah | total = 0;
|
971 | fbe78f4f | aliguori | |
972 | 0c87e93e | Jason Wang | if (virtqueue_pop(q->rx_vq, &elem) == 0) { |
973 | fbe78f4f | aliguori | if (i == 0) |
974 | 4f1c942b | Mark McLoughlin | return -1; |
975 | e7b43f7e | Stefan Hajnoczi | error_report("virtio-net unexpected empty queue: "
|
976 | 279a4253 | Michael S. Tsirkin | "i %zd mergeable %d offset %zd, size %zd, "
|
977 | e7b43f7e | Stefan Hajnoczi | "guest hdr len %zd, host hdr len %zd guest features 0x%x",
|
978 | 279a4253 | Michael S. Tsirkin | i, n->mergeable_rx_bufs, offset, size, |
979 | 17a0ca55 | KONRAD Frederic | n->guest_hdr_len, n->host_hdr_len, vdev->guest_features); |
980 | fbe78f4f | aliguori | exit(1);
|
981 | fbe78f4f | aliguori | } |
982 | fbe78f4f | aliguori | |
983 | fbe78f4f | aliguori | if (elem.in_num < 1) { |
984 | e7b43f7e | Stefan Hajnoczi | error_report("virtio-net receive queue contains no in buffers");
|
985 | fbe78f4f | aliguori | exit(1);
|
986 | fbe78f4f | aliguori | } |
987 | fbe78f4f | aliguori | |
988 | fbe78f4f | aliguori | if (i == 0) { |
989 | c8d28e7e | Michael S. Tsirkin | assert(offset == 0);
|
990 | 63c58728 | Michael S. Tsirkin | if (n->mergeable_rx_bufs) {
|
991 | 63c58728 | Michael S. Tsirkin | mhdr_cnt = iov_copy(mhdr_sg, ARRAY_SIZE(mhdr_sg), |
992 | 63c58728 | Michael S. Tsirkin | sg, elem.in_num, |
993 | 63c58728 | Michael S. Tsirkin | offsetof(typeof(mhdr), num_buffers), |
994 | 63c58728 | Michael S. Tsirkin | sizeof(mhdr.num_buffers));
|
995 | 63c58728 | Michael S. Tsirkin | } |
996 | fbe78f4f | aliguori | |
997 | c8d28e7e | Michael S. Tsirkin | receive_header(n, sg, elem.in_num, buf, size); |
998 | c8d28e7e | Michael S. Tsirkin | offset = n->host_hdr_len; |
999 | e35e23f6 | Michael S. Tsirkin | total += n->guest_hdr_len; |
1000 | 22cc84db | Michael S. Tsirkin | guest_offset = n->guest_hdr_len; |
1001 | 22cc84db | Michael S. Tsirkin | } else {
|
1002 | 22cc84db | Michael S. Tsirkin | guest_offset = 0;
|
1003 | fbe78f4f | aliguori | } |
1004 | fbe78f4f | aliguori | |
1005 | fbe78f4f | aliguori | /* copy in packet. ugh */
|
1006 | 22cc84db | Michael S. Tsirkin | len = iov_from_buf(sg, elem.in_num, guest_offset, |
1007 | dcf6f5e1 | Michael Tokarev | buf + offset, size - offset); |
1008 | fbe78f4f | aliguori | total += len; |
1009 | 279a4253 | Michael S. Tsirkin | offset += len; |
1010 | 279a4253 | Michael S. Tsirkin | /* If buffers can't be merged, at this point we
|
1011 | 279a4253 | Michael S. Tsirkin | * must have consumed the complete packet.
|
1012 | 279a4253 | Michael S. Tsirkin | * Otherwise, drop it. */
|
1013 | 279a4253 | Michael S. Tsirkin | if (!n->mergeable_rx_bufs && offset < size) {
|
1014 | 279a4253 | Michael S. Tsirkin | #if 0
|
1015 | e7b43f7e | Stefan Hajnoczi | error_report("virtio-net truncated non-mergeable packet: "
|
1016 | e7b43f7e | Stefan Hajnoczi | "i %zd mergeable %d offset %zd, size %zd, "
|
1017 | e7b43f7e | Stefan Hajnoczi | "guest hdr len %zd, host hdr len %zd",
|
1018 | e7b43f7e | Stefan Hajnoczi | i, n->mergeable_rx_bufs,
|
1019 | e35e23f6 | Michael S. Tsirkin | offset, size, n->guest_hdr_len, n->host_hdr_len);
|
1020 | 279a4253 | Michael S. Tsirkin | #endif
|
1021 | 279a4253 | Michael S. Tsirkin | return size;
|
1022 | 279a4253 | Michael S. Tsirkin | } |
1023 | fbe78f4f | aliguori | |
1024 | fbe78f4f | aliguori | /* signal other side */
|
1025 | 0c87e93e | Jason Wang | virtqueue_fill(q->rx_vq, &elem, total, i++); |
1026 | fbe78f4f | aliguori | } |
1027 | fbe78f4f | aliguori | |
1028 | 63c58728 | Michael S. Tsirkin | if (mhdr_cnt) {
|
1029 | 63c58728 | Michael S. Tsirkin | stw_p(&mhdr.num_buffers, i); |
1030 | 63c58728 | Michael S. Tsirkin | iov_from_buf(mhdr_sg, mhdr_cnt, |
1031 | 63c58728 | Michael S. Tsirkin | 0,
|
1032 | 63c58728 | Michael S. Tsirkin | &mhdr.num_buffers, sizeof mhdr.num_buffers);
|
1033 | 44b15bc5 | Aurelien Jarno | } |
1034 | fbe78f4f | aliguori | |
1035 | 0c87e93e | Jason Wang | virtqueue_flush(q->rx_vq, i); |
1036 | 17a0ca55 | KONRAD Frederic | virtio_notify(vdev, q->rx_vq); |
1037 | 4f1c942b | Mark McLoughlin | |
1038 | 4f1c942b | Mark McLoughlin | return size;
|
1039 | fbe78f4f | aliguori | } |
1040 | fbe78f4f | aliguori | |
1041 | 0c87e93e | Jason Wang | static int32_t virtio_net_flush_tx(VirtIONetQueue *q);
|
1042 | 6243375f | Mark McLoughlin | |
1043 | 4e68f7a0 | Stefan Hajnoczi | static void virtio_net_tx_complete(NetClientState *nc, ssize_t len) |
1044 | 6243375f | Mark McLoughlin | { |
1045 | cc1f0f45 | Jason Wang | VirtIONet *n = qemu_get_nic_opaque(nc); |
1046 | fed699f9 | Jason Wang | VirtIONetQueue *q = virtio_net_get_subqueue(nc); |
1047 | 17a0ca55 | KONRAD Frederic | VirtIODevice *vdev = VIRTIO_DEVICE(n); |
1048 | 6243375f | Mark McLoughlin | |
1049 | 0c87e93e | Jason Wang | virtqueue_push(q->tx_vq, &q->async_tx.elem, 0);
|
1050 | 17a0ca55 | KONRAD Frederic | virtio_notify(vdev, q->tx_vq); |
1051 | 6243375f | Mark McLoughlin | |
1052 | 0c87e93e | Jason Wang | q->async_tx.elem.out_num = q->async_tx.len = 0;
|
1053 | 6243375f | Mark McLoughlin | |
1054 | 0c87e93e | Jason Wang | virtio_queue_set_notification(q->tx_vq, 1);
|
1055 | 0c87e93e | Jason Wang | virtio_net_flush_tx(q); |
1056 | 6243375f | Mark McLoughlin | } |
1057 | 6243375f | Mark McLoughlin | |
1058 | fbe78f4f | aliguori | /* TX */
|
1059 | 0c87e93e | Jason Wang | static int32_t virtio_net_flush_tx(VirtIONetQueue *q)
|
1060 | fbe78f4f | aliguori | { |
1061 | 0c87e93e | Jason Wang | VirtIONet *n = q->n; |
1062 | 17a0ca55 | KONRAD Frederic | VirtIODevice *vdev = VIRTIO_DEVICE(n); |
1063 | fbe78f4f | aliguori | VirtQueueElement elem; |
1064 | e3f30488 | Alex Williamson | int32_t num_packets = 0;
|
1065 | fed699f9 | Jason Wang | int queue_index = vq2q(virtio_get_queue_index(q->tx_vq));
|
1066 | 17a0ca55 | KONRAD Frederic | if (!(vdev->status & VIRTIO_CONFIG_S_DRIVER_OK)) {
|
1067 | e3f30488 | Alex Williamson | return num_packets;
|
1068 | e3f30488 | Alex Williamson | } |
1069 | fbe78f4f | aliguori | |
1070 | 17a0ca55 | KONRAD Frederic | assert(vdev->vm_running); |
1071 | 783e7706 | Michael S. Tsirkin | |
1072 | 0c87e93e | Jason Wang | if (q->async_tx.elem.out_num) {
|
1073 | 0c87e93e | Jason Wang | virtio_queue_set_notification(q->tx_vq, 0);
|
1074 | e3f30488 | Alex Williamson | return num_packets;
|
1075 | 6243375f | Mark McLoughlin | } |
1076 | 6243375f | Mark McLoughlin | |
1077 | 0c87e93e | Jason Wang | while (virtqueue_pop(q->tx_vq, &elem)) {
|
1078 | 14761f9c | Michael S. Tsirkin | ssize_t ret, len; |
1079 | fbe78f4f | aliguori | unsigned int out_num = elem.out_num; |
1080 | fbe78f4f | aliguori | struct iovec *out_sg = &elem.out_sg[0]; |
1081 | 14761f9c | Michael S. Tsirkin | struct iovec sg[VIRTQUEUE_MAX_SIZE];
|
1082 | fbe78f4f | aliguori | |
1083 | 7b80d08e | Michael S. Tsirkin | if (out_num < 1) { |
1084 | e7b43f7e | Stefan Hajnoczi | error_report("virtio-net header not in first element");
|
1085 | fbe78f4f | aliguori | exit(1);
|
1086 | fbe78f4f | aliguori | } |
1087 | fbe78f4f | aliguori | |
1088 | 14761f9c | Michael S. Tsirkin | /*
|
1089 | 14761f9c | Michael S. Tsirkin | * If host wants to see the guest header as is, we can
|
1090 | 14761f9c | Michael S. Tsirkin | * pass it on unchanged. Otherwise, copy just the parts
|
1091 | 14761f9c | Michael S. Tsirkin | * that host is interested in.
|
1092 | 14761f9c | Michael S. Tsirkin | */
|
1093 | 14761f9c | Michael S. Tsirkin | assert(n->host_hdr_len <= n->guest_hdr_len); |
1094 | 14761f9c | Michael S. Tsirkin | if (n->host_hdr_len != n->guest_hdr_len) {
|
1095 | 14761f9c | Michael S. Tsirkin | unsigned sg_num = iov_copy(sg, ARRAY_SIZE(sg),
|
1096 | 14761f9c | Michael S. Tsirkin | out_sg, out_num, |
1097 | 14761f9c | Michael S. Tsirkin | 0, n->host_hdr_len);
|
1098 | 14761f9c | Michael S. Tsirkin | sg_num += iov_copy(sg + sg_num, ARRAY_SIZE(sg) - sg_num, |
1099 | 14761f9c | Michael S. Tsirkin | out_sg, out_num, |
1100 | 14761f9c | Michael S. Tsirkin | n->guest_hdr_len, -1);
|
1101 | 14761f9c | Michael S. Tsirkin | out_num = sg_num; |
1102 | 14761f9c | Michael S. Tsirkin | out_sg = sg; |
1103 | fbe78f4f | aliguori | } |
1104 | fbe78f4f | aliguori | |
1105 | 7b80d08e | Michael S. Tsirkin | len = n->guest_hdr_len; |
1106 | 14761f9c | Michael S. Tsirkin | |
1107 | fed699f9 | Jason Wang | ret = qemu_sendv_packet_async(qemu_get_subqueue(n->nic, queue_index), |
1108 | fed699f9 | Jason Wang | out_sg, out_num, virtio_net_tx_complete); |
1109 | 6243375f | Mark McLoughlin | if (ret == 0) { |
1110 | 0c87e93e | Jason Wang | virtio_queue_set_notification(q->tx_vq, 0);
|
1111 | 0c87e93e | Jason Wang | q->async_tx.elem = elem; |
1112 | 0c87e93e | Jason Wang | q->async_tx.len = len; |
1113 | e3f30488 | Alex Williamson | return -EBUSY;
|
1114 | 6243375f | Mark McLoughlin | } |
1115 | 6243375f | Mark McLoughlin | |
1116 | 6243375f | Mark McLoughlin | len += ret; |
1117 | fbe78f4f | aliguori | |
1118 | 0c87e93e | Jason Wang | virtqueue_push(q->tx_vq, &elem, 0);
|
1119 | 17a0ca55 | KONRAD Frederic | virtio_notify(vdev, q->tx_vq); |
1120 | e3f30488 | Alex Williamson | |
1121 | e3f30488 | Alex Williamson | if (++num_packets >= n->tx_burst) {
|
1122 | e3f30488 | Alex Williamson | break;
|
1123 | e3f30488 | Alex Williamson | } |
1124 | fbe78f4f | aliguori | } |
1125 | e3f30488 | Alex Williamson | return num_packets;
|
1126 | fbe78f4f | aliguori | } |
1127 | fbe78f4f | aliguori | |
1128 | a697a334 | Alex Williamson | static void virtio_net_handle_tx_timer(VirtIODevice *vdev, VirtQueue *vq) |
1129 | fbe78f4f | aliguori | { |
1130 | 17a0ca55 | KONRAD Frederic | VirtIONet *n = VIRTIO_NET(vdev); |
1131 | fed699f9 | Jason Wang | VirtIONetQueue *q = &n->vqs[vq2q(virtio_get_queue_index(vq))]; |
1132 | fbe78f4f | aliguori | |
1133 | 783e7706 | Michael S. Tsirkin | /* This happens when device was stopped but VCPU wasn't. */
|
1134 | 17a0ca55 | KONRAD Frederic | if (!vdev->vm_running) {
|
1135 | 0c87e93e | Jason Wang | q->tx_waiting = 1;
|
1136 | 783e7706 | Michael S. Tsirkin | return;
|
1137 | 783e7706 | Michael S. Tsirkin | } |
1138 | 783e7706 | Michael S. Tsirkin | |
1139 | 0c87e93e | Jason Wang | if (q->tx_waiting) {
|
1140 | fbe78f4f | aliguori | virtio_queue_set_notification(vq, 1);
|
1141 | bc72ad67 | Alex Bligh | timer_del(q->tx_timer); |
1142 | 0c87e93e | Jason Wang | q->tx_waiting = 0;
|
1143 | 0c87e93e | Jason Wang | virtio_net_flush_tx(q); |
1144 | fbe78f4f | aliguori | } else {
|
1145 | bc72ad67 | Alex Bligh | timer_mod(q->tx_timer, |
1146 | bc72ad67 | Alex Bligh | qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + n->tx_timeout); |
1147 | 0c87e93e | Jason Wang | q->tx_waiting = 1;
|
1148 | fbe78f4f | aliguori | virtio_queue_set_notification(vq, 0);
|
1149 | fbe78f4f | aliguori | } |
1150 | fbe78f4f | aliguori | } |
1151 | fbe78f4f | aliguori | |
1152 | a697a334 | Alex Williamson | static void virtio_net_handle_tx_bh(VirtIODevice *vdev, VirtQueue *vq) |
1153 | a697a334 | Alex Williamson | { |
1154 | 17a0ca55 | KONRAD Frederic | VirtIONet *n = VIRTIO_NET(vdev); |
1155 | fed699f9 | Jason Wang | VirtIONetQueue *q = &n->vqs[vq2q(virtio_get_queue_index(vq))]; |
1156 | a697a334 | Alex Williamson | |
1157 | 0c87e93e | Jason Wang | if (unlikely(q->tx_waiting)) {
|
1158 | a697a334 | Alex Williamson | return;
|
1159 | a697a334 | Alex Williamson | } |
1160 | 0c87e93e | Jason Wang | q->tx_waiting = 1;
|
1161 | 783e7706 | Michael S. Tsirkin | /* This happens when device was stopped but VCPU wasn't. */
|
1162 | 17a0ca55 | KONRAD Frederic | if (!vdev->vm_running) {
|
1163 | 783e7706 | Michael S. Tsirkin | return;
|
1164 | 783e7706 | Michael S. Tsirkin | } |
1165 | a697a334 | Alex Williamson | virtio_queue_set_notification(vq, 0);
|
1166 | 0c87e93e | Jason Wang | qemu_bh_schedule(q->tx_bh); |
1167 | a697a334 | Alex Williamson | } |
1168 | a697a334 | Alex Williamson | |
1169 | fbe78f4f | aliguori | static void virtio_net_tx_timer(void *opaque) |
1170 | fbe78f4f | aliguori | { |
1171 | 0c87e93e | Jason Wang | VirtIONetQueue *q = opaque; |
1172 | 0c87e93e | Jason Wang | VirtIONet *n = q->n; |
1173 | 17a0ca55 | KONRAD Frederic | VirtIODevice *vdev = VIRTIO_DEVICE(n); |
1174 | 17a0ca55 | KONRAD Frederic | assert(vdev->vm_running); |
1175 | fbe78f4f | aliguori | |
1176 | 0c87e93e | Jason Wang | q->tx_waiting = 0;
|
1177 | fbe78f4f | aliguori | |
1178 | fbe78f4f | aliguori | /* Just in case the driver is not ready on more */
|
1179 | 17a0ca55 | KONRAD Frederic | if (!(vdev->status & VIRTIO_CONFIG_S_DRIVER_OK)) {
|
1180 | fbe78f4f | aliguori | return;
|
1181 | 17a0ca55 | KONRAD Frederic | } |
1182 | fbe78f4f | aliguori | |
1183 | 0c87e93e | Jason Wang | virtio_queue_set_notification(q->tx_vq, 1);
|
1184 | 0c87e93e | Jason Wang | virtio_net_flush_tx(q); |
1185 | fbe78f4f | aliguori | } |
1186 | fbe78f4f | aliguori | |
1187 | a697a334 | Alex Williamson | static void virtio_net_tx_bh(void *opaque) |
1188 | a697a334 | Alex Williamson | { |
1189 | 0c87e93e | Jason Wang | VirtIONetQueue *q = opaque; |
1190 | 0c87e93e | Jason Wang | VirtIONet *n = q->n; |
1191 | 17a0ca55 | KONRAD Frederic | VirtIODevice *vdev = VIRTIO_DEVICE(n); |
1192 | a697a334 | Alex Williamson | int32_t ret; |
1193 | a697a334 | Alex Williamson | |
1194 | 17a0ca55 | KONRAD Frederic | assert(vdev->vm_running); |
1195 | 783e7706 | Michael S. Tsirkin | |
1196 | 0c87e93e | Jason Wang | q->tx_waiting = 0;
|
1197 | a697a334 | Alex Williamson | |
1198 | a697a334 | Alex Williamson | /* Just in case the driver is not ready on more */
|
1199 | 17a0ca55 | KONRAD Frederic | if (unlikely(!(vdev->status & VIRTIO_CONFIG_S_DRIVER_OK))) {
|
1200 | a697a334 | Alex Williamson | return;
|
1201 | 17a0ca55 | KONRAD Frederic | } |
1202 | a697a334 | Alex Williamson | |
1203 | 0c87e93e | Jason Wang | ret = virtio_net_flush_tx(q); |
1204 | a697a334 | Alex Williamson | if (ret == -EBUSY) {
|
1205 | a697a334 | Alex Williamson | return; /* Notification re-enable handled by tx_complete */ |
1206 | a697a334 | Alex Williamson | } |
1207 | a697a334 | Alex Williamson | |
1208 | a697a334 | Alex Williamson | /* If we flush a full burst of packets, assume there are
|
1209 | a697a334 | Alex Williamson | * more coming and immediately reschedule */
|
1210 | a697a334 | Alex Williamson | if (ret >= n->tx_burst) {
|
1211 | 0c87e93e | Jason Wang | qemu_bh_schedule(q->tx_bh); |
1212 | 0c87e93e | Jason Wang | q->tx_waiting = 1;
|
1213 | a697a334 | Alex Williamson | return;
|
1214 | a697a334 | Alex Williamson | } |
1215 | a697a334 | Alex Williamson | |
1216 | a697a334 | Alex Williamson | /* If less than a full burst, re-enable notification and flush
|
1217 | a697a334 | Alex Williamson | * anything that may have come in while we weren't looking. If
|
1218 | a697a334 | Alex Williamson | * we find something, assume the guest is still active and reschedule */
|
1219 | 0c87e93e | Jason Wang | virtio_queue_set_notification(q->tx_vq, 1);
|
1220 | 0c87e93e | Jason Wang | if (virtio_net_flush_tx(q) > 0) { |
1221 | 0c87e93e | Jason Wang | virtio_queue_set_notification(q->tx_vq, 0);
|
1222 | 0c87e93e | Jason Wang | qemu_bh_schedule(q->tx_bh); |
1223 | 0c87e93e | Jason Wang | q->tx_waiting = 1;
|
1224 | a697a334 | Alex Williamson | } |
1225 | a697a334 | Alex Williamson | } |
1226 | a697a334 | Alex Williamson | |
1227 | ec57db16 | Jason Wang | static void virtio_net_set_multiqueue(VirtIONet *n, int multiqueue) |
1228 | fed699f9 | Jason Wang | { |
1229 | 17a0ca55 | KONRAD Frederic | VirtIODevice *vdev = VIRTIO_DEVICE(n); |
1230 | fed699f9 | Jason Wang | int i, max = multiqueue ? n->max_queues : 1; |
1231 | fed699f9 | Jason Wang | |
1232 | fed699f9 | Jason Wang | n->multiqueue = multiqueue; |
1233 | fed699f9 | Jason Wang | |
1234 | fed699f9 | Jason Wang | for (i = 2; i <= n->max_queues * 2 + 1; i++) { |
1235 | fed699f9 | Jason Wang | virtio_del_queue(vdev, i); |
1236 | fed699f9 | Jason Wang | } |
1237 | fed699f9 | Jason Wang | |
1238 | fed699f9 | Jason Wang | for (i = 1; i < max; i++) { |
1239 | fed699f9 | Jason Wang | n->vqs[i].rx_vq = virtio_add_queue(vdev, 256, virtio_net_handle_rx);
|
1240 | fed699f9 | Jason Wang | if (n->vqs[i].tx_timer) {
|
1241 | fed699f9 | Jason Wang | n->vqs[i].tx_vq = |
1242 | fed699f9 | Jason Wang | virtio_add_queue(vdev, 256, virtio_net_handle_tx_timer);
|
1243 | bc72ad67 | Alex Bligh | n->vqs[i].tx_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, |
1244 | fed699f9 | Jason Wang | virtio_net_tx_timer, |
1245 | fed699f9 | Jason Wang | &n->vqs[i]); |
1246 | fed699f9 | Jason Wang | } else {
|
1247 | fed699f9 | Jason Wang | n->vqs[i].tx_vq = |
1248 | fed699f9 | Jason Wang | virtio_add_queue(vdev, 256, virtio_net_handle_tx_bh);
|
1249 | fed699f9 | Jason Wang | n->vqs[i].tx_bh = qemu_bh_new(virtio_net_tx_bh, &n->vqs[i]); |
1250 | fed699f9 | Jason Wang | } |
1251 | fed699f9 | Jason Wang | |
1252 | fed699f9 | Jason Wang | n->vqs[i].tx_waiting = 0;
|
1253 | fed699f9 | Jason Wang | n->vqs[i].n = n; |
1254 | fed699f9 | Jason Wang | } |
1255 | fed699f9 | Jason Wang | |
1256 | ec57db16 | Jason Wang | /* Note: Minux Guests (version 3.2.1) use ctrl vq but don't ack
|
1257 | ec57db16 | Jason Wang | * VIRTIO_NET_F_CTRL_VQ. Create ctrl vq unconditionally to avoid
|
1258 | ec57db16 | Jason Wang | * breaking them.
|
1259 | ec57db16 | Jason Wang | */
|
1260 | ec57db16 | Jason Wang | n->ctrl_vq = virtio_add_queue(vdev, 64, virtio_net_handle_ctrl);
|
1261 | fed699f9 | Jason Wang | |
1262 | fed699f9 | Jason Wang | virtio_net_set_queues(n); |
1263 | fed699f9 | Jason Wang | } |
1264 | fed699f9 | Jason Wang | |
1265 | fbe78f4f | aliguori | static void virtio_net_save(QEMUFile *f, void *opaque) |
1266 | fbe78f4f | aliguori | { |
1267 | 5f800801 | Jason Wang | int i;
|
1268 | fbe78f4f | aliguori | VirtIONet *n = opaque; |
1269 | 17a0ca55 | KONRAD Frederic | VirtIODevice *vdev = VIRTIO_DEVICE(n); |
1270 | fbe78f4f | aliguori | |
1271 | afbaa7b4 | Michael S. Tsirkin | /* At this point, backend must be stopped, otherwise
|
1272 | afbaa7b4 | Michael S. Tsirkin | * it might keep writing to memory. */
|
1273 | afbaa7b4 | Michael S. Tsirkin | assert(!n->vhost_started); |
1274 | 17a0ca55 | KONRAD Frederic | virtio_save(vdev, f); |
1275 | fbe78f4f | aliguori | |
1276 | 79674068 | aliguori | qemu_put_buffer(f, n->mac, ETH_ALEN); |
1277 | 5f800801 | Jason Wang | qemu_put_be32(f, n->vqs[0].tx_waiting);
|
1278 | e46cb38f | aliguori | qemu_put_be32(f, n->mergeable_rx_bufs); |
1279 | 9d6271b8 | aliguori | qemu_put_be16(f, n->status); |
1280 | f10c592e | Alex Williamson | qemu_put_byte(f, n->promisc); |
1281 | f10c592e | Alex Williamson | qemu_put_byte(f, n->allmulti); |
1282 | b6503ed9 | aliguori | qemu_put_be32(f, n->mac_table.in_use); |
1283 | b6503ed9 | aliguori | qemu_put_buffer(f, n->mac_table.macs, n->mac_table.in_use * ETH_ALEN); |
1284 | f21c0ed9 | aliguori | qemu_put_buffer(f, (uint8_t *)n->vlans, MAX_VLAN >> 3);
|
1285 | 3a330134 | Mark McLoughlin | qemu_put_be32(f, n->has_vnet_hdr); |
1286 | 8fd2a2f1 | Alex Williamson | qemu_put_byte(f, n->mac_table.multi_overflow); |
1287 | 8fd2a2f1 | Alex Williamson | qemu_put_byte(f, n->mac_table.uni_overflow); |
1288 | 015cb166 | Alex Williamson | qemu_put_byte(f, n->alluni); |
1289 | 015cb166 | Alex Williamson | qemu_put_byte(f, n->nomulti); |
1290 | 015cb166 | Alex Williamson | qemu_put_byte(f, n->nouni); |
1291 | 015cb166 | Alex Williamson | qemu_put_byte(f, n->nobcast); |
1292 | 0ce0e8f4 | Mark McLoughlin | qemu_put_byte(f, n->has_ufo); |
1293 | 5f800801 | Jason Wang | if (n->max_queues > 1) { |
1294 | 5f800801 | Jason Wang | qemu_put_be16(f, n->max_queues); |
1295 | 5f800801 | Jason Wang | qemu_put_be16(f, n->curr_queues); |
1296 | 5f800801 | Jason Wang | for (i = 1; i < n->curr_queues; i++) { |
1297 | 5f800801 | Jason Wang | qemu_put_be32(f, n->vqs[i].tx_waiting); |
1298 | 5f800801 | Jason Wang | } |
1299 | 5f800801 | Jason Wang | } |
1300 | 644c9858 | Dmitry Fleytman | |
1301 | 644c9858 | Dmitry Fleytman | if ((1 << VIRTIO_NET_F_CTRL_GUEST_OFFLOADS) & vdev->guest_features) { |
1302 | 644c9858 | Dmitry Fleytman | qemu_put_be64(f, n->curr_guest_offloads); |
1303 | 644c9858 | Dmitry Fleytman | } |
1304 | fbe78f4f | aliguori | } |
1305 | fbe78f4f | aliguori | |
1306 | fbe78f4f | aliguori | static int virtio_net_load(QEMUFile *f, void *opaque, int version_id) |
1307 | fbe78f4f | aliguori | { |
1308 | fbe78f4f | aliguori | VirtIONet *n = opaque; |
1309 | 17a0ca55 | KONRAD Frederic | VirtIODevice *vdev = VIRTIO_DEVICE(n); |
1310 | 5f800801 | Jason Wang | int ret, i, link_down;
|
1311 | fbe78f4f | aliguori | |
1312 | 9d6271b8 | aliguori | if (version_id < 2 || version_id > VIRTIO_NET_VM_VERSION) |
1313 | fbe78f4f | aliguori | return -EINVAL;
|
1314 | fbe78f4f | aliguori | |
1315 | 17a0ca55 | KONRAD Frederic | ret = virtio_load(vdev, f); |
1316 | 2a633c46 | Orit Wassermann | if (ret) {
|
1317 | 2a633c46 | Orit Wassermann | return ret;
|
1318 | 2a633c46 | Orit Wassermann | } |
1319 | fbe78f4f | aliguori | |
1320 | 79674068 | aliguori | qemu_get_buffer(f, n->mac, ETH_ALEN); |
1321 | 5f800801 | Jason Wang | n->vqs[0].tx_waiting = qemu_get_be32(f);
|
1322 | ff3a8066 | Michael S. Tsirkin | |
1323 | ff3a8066 | Michael S. Tsirkin | virtio_net_set_mrg_rx_bufs(n, qemu_get_be32(f)); |
1324 | fbe78f4f | aliguori | |
1325 | 9d6271b8 | aliguori | if (version_id >= 3) |
1326 | 9d6271b8 | aliguori | n->status = qemu_get_be16(f); |
1327 | 9d6271b8 | aliguori | |
1328 | 002437cd | aliguori | if (version_id >= 4) { |
1329 | f10c592e | Alex Williamson | if (version_id < 8) { |
1330 | f10c592e | Alex Williamson | n->promisc = qemu_get_be32(f); |
1331 | f10c592e | Alex Williamson | n->allmulti = qemu_get_be32(f); |
1332 | f10c592e | Alex Williamson | } else {
|
1333 | f10c592e | Alex Williamson | n->promisc = qemu_get_byte(f); |
1334 | f10c592e | Alex Williamson | n->allmulti = qemu_get_byte(f); |
1335 | f10c592e | Alex Williamson | } |
1336 | 002437cd | aliguori | } |
1337 | 002437cd | aliguori | |
1338 | b6503ed9 | aliguori | if (version_id >= 5) { |
1339 | b6503ed9 | aliguori | n->mac_table.in_use = qemu_get_be32(f); |
1340 | b6503ed9 | aliguori | /* MAC_TABLE_ENTRIES may be different from the saved image */
|
1341 | b6503ed9 | aliguori | if (n->mac_table.in_use <= MAC_TABLE_ENTRIES) {
|
1342 | b6503ed9 | aliguori | qemu_get_buffer(f, n->mac_table.macs, |
1343 | b6503ed9 | aliguori | n->mac_table.in_use * ETH_ALEN); |
1344 | b6503ed9 | aliguori | } else if (n->mac_table.in_use) { |
1345 | e398d61b | Juan Quintela | uint8_t *buf = g_malloc0(n->mac_table.in_use); |
1346 | e398d61b | Juan Quintela | qemu_get_buffer(f, buf, n->mac_table.in_use * ETH_ALEN); |
1347 | e398d61b | Juan Quintela | g_free(buf); |
1348 | 8fd2a2f1 | Alex Williamson | n->mac_table.multi_overflow = n->mac_table.uni_overflow = 1;
|
1349 | b6503ed9 | aliguori | n->mac_table.in_use = 0;
|
1350 | b6503ed9 | aliguori | } |
1351 | b6503ed9 | aliguori | } |
1352 | b6503ed9 | aliguori | |
1353 | f21c0ed9 | aliguori | if (version_id >= 6) |
1354 | f21c0ed9 | aliguori | qemu_get_buffer(f, (uint8_t *)n->vlans, MAX_VLAN >> 3);
|
1355 | f21c0ed9 | aliguori | |
1356 | 3a330134 | Mark McLoughlin | if (version_id >= 7) { |
1357 | 3a330134 | Mark McLoughlin | if (qemu_get_be32(f) && !peer_has_vnet_hdr(n)) {
|
1358 | 1ecda02b | Markus Armbruster | error_report("virtio-net: saved image requires vnet_hdr=on");
|
1359 | 3a330134 | Mark McLoughlin | return -1; |
1360 | 3a330134 | Mark McLoughlin | } |
1361 | 6c042c16 | Alex Williamson | } |
1362 | 6c042c16 | Alex Williamson | |
1363 | 8fd2a2f1 | Alex Williamson | if (version_id >= 9) { |
1364 | 8fd2a2f1 | Alex Williamson | n->mac_table.multi_overflow = qemu_get_byte(f); |
1365 | 8fd2a2f1 | Alex Williamson | n->mac_table.uni_overflow = qemu_get_byte(f); |
1366 | 8fd2a2f1 | Alex Williamson | } |
1367 | 8fd2a2f1 | Alex Williamson | |
1368 | 015cb166 | Alex Williamson | if (version_id >= 10) { |
1369 | 015cb166 | Alex Williamson | n->alluni = qemu_get_byte(f); |
1370 | 015cb166 | Alex Williamson | n->nomulti = qemu_get_byte(f); |
1371 | 015cb166 | Alex Williamson | n->nouni = qemu_get_byte(f); |
1372 | 015cb166 | Alex Williamson | n->nobcast = qemu_get_byte(f); |
1373 | 015cb166 | Alex Williamson | } |
1374 | 015cb166 | Alex Williamson | |
1375 | 0ce0e8f4 | Mark McLoughlin | if (version_id >= 11) { |
1376 | 0ce0e8f4 | Mark McLoughlin | if (qemu_get_byte(f) && !peer_has_ufo(n)) {
|
1377 | 1ecda02b | Markus Armbruster | error_report("virtio-net: saved image requires TUN_F_UFO support");
|
1378 | 0ce0e8f4 | Mark McLoughlin | return -1; |
1379 | 0ce0e8f4 | Mark McLoughlin | } |
1380 | 0ce0e8f4 | Mark McLoughlin | } |
1381 | 0ce0e8f4 | Mark McLoughlin | |
1382 | 5f800801 | Jason Wang | if (n->max_queues > 1) { |
1383 | 5f800801 | Jason Wang | if (n->max_queues != qemu_get_be16(f)) {
|
1384 | 5f800801 | Jason Wang | error_report("virtio-net: different max_queues ");
|
1385 | 5f800801 | Jason Wang | return -1; |
1386 | 5f800801 | Jason Wang | } |
1387 | 5f800801 | Jason Wang | |
1388 | 5f800801 | Jason Wang | n->curr_queues = qemu_get_be16(f); |
1389 | 5f800801 | Jason Wang | for (i = 1; i < n->curr_queues; i++) { |
1390 | 5f800801 | Jason Wang | n->vqs[i].tx_waiting = qemu_get_be32(f); |
1391 | 5f800801 | Jason Wang | } |
1392 | 5f800801 | Jason Wang | } |
1393 | 5f800801 | Jason Wang | |
1394 | 644c9858 | Dmitry Fleytman | if ((1 << VIRTIO_NET_F_CTRL_GUEST_OFFLOADS) & vdev->guest_features) { |
1395 | 644c9858 | Dmitry Fleytman | n->curr_guest_offloads = qemu_get_be64(f); |
1396 | 644c9858 | Dmitry Fleytman | } else {
|
1397 | 644c9858 | Dmitry Fleytman | n->curr_guest_offloads = virtio_net_supported_guest_offloads(n); |
1398 | 644c9858 | Dmitry Fleytman | } |
1399 | 644c9858 | Dmitry Fleytman | |
1400 | 644c9858 | Dmitry Fleytman | if (peer_has_vnet_hdr(n)) {
|
1401 | 644c9858 | Dmitry Fleytman | virtio_net_apply_guest_offloads(n); |
1402 | 644c9858 | Dmitry Fleytman | } |
1403 | 644c9858 | Dmitry Fleytman | |
1404 | 5f800801 | Jason Wang | virtio_net_set_queues(n); |
1405 | 5f800801 | Jason Wang | |
1406 | 2d9aba39 | Alex Williamson | /* Find the first multicast entry in the saved MAC filter */
|
1407 | 2d9aba39 | Alex Williamson | for (i = 0; i < n->mac_table.in_use; i++) { |
1408 | 2d9aba39 | Alex Williamson | if (n->mac_table.macs[i * ETH_ALEN] & 1) { |
1409 | 2d9aba39 | Alex Williamson | break;
|
1410 | 2d9aba39 | Alex Williamson | } |
1411 | 2d9aba39 | Alex Williamson | } |
1412 | 2d9aba39 | Alex Williamson | n->mac_table.first_multi = i; |
1413 | 98991481 | Amos Kong | |
1414 | 98991481 | Amos Kong | /* nc.link_down can't be migrated, so infer link_down according
|
1415 | 98991481 | Amos Kong | * to link status bit in n->status */
|
1416 | 5f800801 | Jason Wang | link_down = (n->status & VIRTIO_NET_S_LINK_UP) == 0;
|
1417 | 5f800801 | Jason Wang | for (i = 0; i < n->max_queues; i++) { |
1418 | 5f800801 | Jason Wang | qemu_get_subqueue(n->nic, i)->link_down = link_down; |
1419 | 5f800801 | Jason Wang | } |
1420 | 98991481 | Amos Kong | |
1421 | fbe78f4f | aliguori | return 0; |
1422 | fbe78f4f | aliguori | } |
1423 | fbe78f4f | aliguori | |
1424 | 4e68f7a0 | Stefan Hajnoczi | static void virtio_net_cleanup(NetClientState *nc) |
1425 | b946a153 | aliguori | { |
1426 | cc1f0f45 | Jason Wang | VirtIONet *n = qemu_get_nic_opaque(nc); |
1427 | b946a153 | aliguori | |
1428 | eb6b6c12 | Mark McLoughlin | n->nic = NULL;
|
1429 | b946a153 | aliguori | } |
1430 | b946a153 | aliguori | |
1431 | eb6b6c12 | Mark McLoughlin | static NetClientInfo net_virtio_info = {
|
1432 | 2be64a68 | Laszlo Ersek | .type = NET_CLIENT_OPTIONS_KIND_NIC, |
1433 | eb6b6c12 | Mark McLoughlin | .size = sizeof(NICState),
|
1434 | eb6b6c12 | Mark McLoughlin | .can_receive = virtio_net_can_receive, |
1435 | eb6b6c12 | Mark McLoughlin | .receive = virtio_net_receive, |
1436 | cb77e358 | Zhi Yong Wu | .cleanup = virtio_net_cleanup, |
1437 | eb6b6c12 | Mark McLoughlin | .link_status_changed = virtio_net_set_link_status, |
1438 | b1be4280 | Amos Kong | .query_rx_filter = virtio_net_query_rxfilter, |
1439 | eb6b6c12 | Mark McLoughlin | }; |
1440 | eb6b6c12 | Mark McLoughlin | |
1441 | f56a1247 | Michael S. Tsirkin | static bool virtio_net_guest_notifier_pending(VirtIODevice *vdev, int idx) |
1442 | f56a1247 | Michael S. Tsirkin | { |
1443 | 17a0ca55 | KONRAD Frederic | VirtIONet *n = VIRTIO_NET(vdev); |
1444 | fed699f9 | Jason Wang | NetClientState *nc = qemu_get_subqueue(n->nic, vq2q(idx)); |
1445 | f56a1247 | Michael S. Tsirkin | assert(n->vhost_started); |
1446 | b356f76d | Jason Wang | return vhost_net_virtqueue_pending(tap_get_vhost_net(nc->peer), idx);
|
1447 | f56a1247 | Michael S. Tsirkin | } |
1448 | f56a1247 | Michael S. Tsirkin | |
1449 | f56a1247 | Michael S. Tsirkin | static void virtio_net_guest_notifier_mask(VirtIODevice *vdev, int idx, |
1450 | f56a1247 | Michael S. Tsirkin | bool mask)
|
1451 | f56a1247 | Michael S. Tsirkin | { |
1452 | 17a0ca55 | KONRAD Frederic | VirtIONet *n = VIRTIO_NET(vdev); |
1453 | fed699f9 | Jason Wang | NetClientState *nc = qemu_get_subqueue(n->nic, vq2q(idx)); |
1454 | f56a1247 | Michael S. Tsirkin | assert(n->vhost_started); |
1455 | b356f76d | Jason Wang | vhost_net_virtqueue_mask(tap_get_vhost_net(nc->peer), |
1456 | f56a1247 | Michael S. Tsirkin | vdev, idx, mask); |
1457 | f56a1247 | Michael S. Tsirkin | } |
1458 | f56a1247 | Michael S. Tsirkin | |
1459 | 17ec5a86 | KONRAD Frederic | void virtio_net_set_config_size(VirtIONet *n, uint32_t host_features)
|
1460 | fbe78f4f | aliguori | { |
1461 | 14f9b664 | Jesse Larrew | int i, config_size = 0; |
1462 | e9016ee2 | Jason Wang | host_features |= (1 << VIRTIO_NET_F_MAC);
|
1463 | 14f9b664 | Jesse Larrew | for (i = 0; feature_sizes[i].flags != 0; i++) { |
1464 | 14f9b664 | Jesse Larrew | if (host_features & feature_sizes[i].flags) {
|
1465 | 14f9b664 | Jesse Larrew | config_size = MAX(feature_sizes[i].end, config_size); |
1466 | 14f9b664 | Jesse Larrew | } |
1467 | 14f9b664 | Jesse Larrew | } |
1468 | 17ec5a86 | KONRAD Frederic | n->config_size = config_size; |
1469 | 17ec5a86 | KONRAD Frederic | } |
1470 | 17ec5a86 | KONRAD Frederic | |
1471 | 8a253ec2 | KONRAD Frederic | void virtio_net_set_netclient_name(VirtIONet *n, const char *name, |
1472 | 8a253ec2 | KONRAD Frederic | const char *type) |
1473 | 8a253ec2 | KONRAD Frederic | { |
1474 | 8a253ec2 | KONRAD Frederic | /*
|
1475 | 8a253ec2 | KONRAD Frederic | * The name can be NULL, the netclient name will be type.x.
|
1476 | 8a253ec2 | KONRAD Frederic | */
|
1477 | 8a253ec2 | KONRAD Frederic | assert(type != NULL);
|
1478 | 8a253ec2 | KONRAD Frederic | |
1479 | 8a253ec2 | KONRAD Frederic | if (n->netclient_name) {
|
1480 | 8a253ec2 | KONRAD Frederic | g_free(n->netclient_name); |
1481 | 8a253ec2 | KONRAD Frederic | n->netclient_name = NULL;
|
1482 | 8a253ec2 | KONRAD Frederic | } |
1483 | 8a253ec2 | KONRAD Frederic | if (n->netclient_type) {
|
1484 | 8a253ec2 | KONRAD Frederic | g_free(n->netclient_type); |
1485 | 8a253ec2 | KONRAD Frederic | n->netclient_type = NULL;
|
1486 | 8a253ec2 | KONRAD Frederic | } |
1487 | 8a253ec2 | KONRAD Frederic | |
1488 | 8a253ec2 | KONRAD Frederic | if (name != NULL) { |
1489 | 8a253ec2 | KONRAD Frederic | n->netclient_name = g_strdup(name); |
1490 | 8a253ec2 | KONRAD Frederic | } |
1491 | 8a253ec2 | KONRAD Frederic | n->netclient_type = g_strdup(type); |
1492 | 8a253ec2 | KONRAD Frederic | } |
1493 | 8a253ec2 | KONRAD Frederic | |
1494 | e6f746b3 | Andreas Färber | static void virtio_net_device_realize(DeviceState *dev, Error **errp) |
1495 | 17ec5a86 | KONRAD Frederic | { |
1496 | e6f746b3 | Andreas Färber | VirtIODevice *vdev = VIRTIO_DEVICE(dev); |
1497 | 284a32f0 | Andreas Färber | VirtIONet *n = VIRTIO_NET(dev); |
1498 | b1be4280 | Amos Kong | NetClientState *nc; |
1499 | 284a32f0 | Andreas Färber | int i;
|
1500 | 1773d9ee | KONRAD Frederic | |
1501 | 284a32f0 | Andreas Färber | virtio_init(vdev, "virtio-net", VIRTIO_ID_NET, n->config_size);
|
1502 | fbe78f4f | aliguori | |
1503 | 1773d9ee | KONRAD Frederic | n->max_queues = MAX(n->nic_conf.queues, 1);
|
1504 | f6b26cf2 | Jason Wang | n->vqs = g_malloc0(sizeof(VirtIONetQueue) * n->max_queues);
|
1505 | 17a0ca55 | KONRAD Frederic | n->vqs[0].rx_vq = virtio_add_queue(vdev, 256, virtio_net_handle_rx); |
1506 | fed699f9 | Jason Wang | n->curr_queues = 1;
|
1507 | fed699f9 | Jason Wang | n->vqs[0].n = n;
|
1508 | 1773d9ee | KONRAD Frederic | n->tx_timeout = n->net_conf.txtimer; |
1509 | a697a334 | Alex Williamson | |
1510 | 1773d9ee | KONRAD Frederic | if (n->net_conf.tx && strcmp(n->net_conf.tx, "timer") |
1511 | 1773d9ee | KONRAD Frederic | && strcmp(n->net_conf.tx, "bh")) {
|
1512 | e7b43f7e | Stefan Hajnoczi | error_report("virtio-net: "
|
1513 | e7b43f7e | Stefan Hajnoczi | "Unknown option tx=%s, valid options: \"timer\" \"bh\"",
|
1514 | 1773d9ee | KONRAD Frederic | n->net_conf.tx); |
1515 | e7b43f7e | Stefan Hajnoczi | error_report("Defaulting to \"bh\"");
|
1516 | a697a334 | Alex Williamson | } |
1517 | a697a334 | Alex Williamson | |
1518 | 1773d9ee | KONRAD Frederic | if (n->net_conf.tx && !strcmp(n->net_conf.tx, "timer")) { |
1519 | 17a0ca55 | KONRAD Frederic | n->vqs[0].tx_vq = virtio_add_queue(vdev, 256, |
1520 | fed699f9 | Jason Wang | virtio_net_handle_tx_timer); |
1521 | bc72ad67 | Alex Bligh | n->vqs[0].tx_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, virtio_net_tx_timer,
|
1522 | fed699f9 | Jason Wang | &n->vqs[0]);
|
1523 | a697a334 | Alex Williamson | } else {
|
1524 | 17a0ca55 | KONRAD Frederic | n->vqs[0].tx_vq = virtio_add_queue(vdev, 256, |
1525 | fed699f9 | Jason Wang | virtio_net_handle_tx_bh); |
1526 | fed699f9 | Jason Wang | n->vqs[0].tx_bh = qemu_bh_new(virtio_net_tx_bh, &n->vqs[0]); |
1527 | a697a334 | Alex Williamson | } |
1528 | 17a0ca55 | KONRAD Frederic | n->ctrl_vq = virtio_add_queue(vdev, 64, virtio_net_handle_ctrl);
|
1529 | 1773d9ee | KONRAD Frederic | qemu_macaddr_default_if_unset(&n->nic_conf.macaddr); |
1530 | 1773d9ee | KONRAD Frederic | memcpy(&n->mac[0], &n->nic_conf.macaddr, sizeof(n->mac)); |
1531 | 554c97dd | aliguori | n->status = VIRTIO_NET_S_LINK_UP; |
1532 | fbe78f4f | aliguori | |
1533 | 8a253ec2 | KONRAD Frederic | if (n->netclient_type) {
|
1534 | 8a253ec2 | KONRAD Frederic | /*
|
1535 | 8a253ec2 | KONRAD Frederic | * Happen when virtio_net_set_netclient_name has been called.
|
1536 | 8a253ec2 | KONRAD Frederic | */
|
1537 | 8a253ec2 | KONRAD Frederic | n->nic = qemu_new_nic(&net_virtio_info, &n->nic_conf, |
1538 | 8a253ec2 | KONRAD Frederic | n->netclient_type, n->netclient_name, n); |
1539 | 8a253ec2 | KONRAD Frederic | } else {
|
1540 | 8a253ec2 | KONRAD Frederic | n->nic = qemu_new_nic(&net_virtio_info, &n->nic_conf, |
1541 | 284a32f0 | Andreas Färber | object_get_typename(OBJECT(dev)), dev->id, n); |
1542 | 8a253ec2 | KONRAD Frederic | } |
1543 | 8a253ec2 | KONRAD Frederic | |
1544 | 6e371ab8 | Michael S. Tsirkin | peer_test_vnet_hdr(n); |
1545 | 6e371ab8 | Michael S. Tsirkin | if (peer_has_vnet_hdr(n)) {
|
1546 | fed699f9 | Jason Wang | for (i = 0; i < n->max_queues; i++) { |
1547 | fed699f9 | Jason Wang | tap_using_vnet_hdr(qemu_get_subqueue(n->nic, i)->peer, true);
|
1548 | fed699f9 | Jason Wang | } |
1549 | 6e371ab8 | Michael S. Tsirkin | n->host_hdr_len = sizeof(struct virtio_net_hdr); |
1550 | 6e371ab8 | Michael S. Tsirkin | } else {
|
1551 | 6e371ab8 | Michael S. Tsirkin | n->host_hdr_len = 0;
|
1552 | 6e371ab8 | Michael S. Tsirkin | } |
1553 | eb6b6c12 | Mark McLoughlin | |
1554 | 1773d9ee | KONRAD Frederic | qemu_format_nic_info_str(qemu_get_queue(n->nic), n->nic_conf.macaddr.a); |
1555 | 96d5e201 | aliguori | |
1556 | fed699f9 | Jason Wang | n->vqs[0].tx_waiting = 0; |
1557 | 1773d9ee | KONRAD Frederic | n->tx_burst = n->net_conf.txburst; |
1558 | ff3a8066 | Michael S. Tsirkin | virtio_net_set_mrg_rx_bufs(n, 0);
|
1559 | 002437cd | aliguori | n->promisc = 1; /* for compatibility */ |
1560 | fbe78f4f | aliguori | |
1561 | 7267c094 | Anthony Liguori | n->mac_table.macs = g_malloc0(MAC_TABLE_ENTRIES * ETH_ALEN); |
1562 | b6503ed9 | aliguori | |
1563 | 7267c094 | Anthony Liguori | n->vlans = g_malloc0(MAX_VLAN >> 3);
|
1564 | f21c0ed9 | aliguori | |
1565 | b1be4280 | Amos Kong | nc = qemu_get_queue(n->nic); |
1566 | b1be4280 | Amos Kong | nc->rxfilter_notify_enabled = 1;
|
1567 | b1be4280 | Amos Kong | |
1568 | 284a32f0 | Andreas Färber | n->qdev = dev; |
1569 | 284a32f0 | Andreas Färber | register_savevm(dev, "virtio-net", -1, VIRTIO_NET_VM_VERSION, |
1570 | fbe78f4f | aliguori | virtio_net_save, virtio_net_load, n); |
1571 | cf21e106 | Paul Brook | |
1572 | 284a32f0 | Andreas Färber | add_boot_device_path(n->nic_conf.bootindex, dev, "/ethernet-phy@0");
|
1573 | 17ec5a86 | KONRAD Frederic | } |
1574 | 17ec5a86 | KONRAD Frederic | |
1575 | 306ec6c3 | Andreas Färber | static void virtio_net_device_unrealize(DeviceState *dev, Error **errp) |
1576 | 17ec5a86 | KONRAD Frederic | { |
1577 | 306ec6c3 | Andreas Färber | VirtIODevice *vdev = VIRTIO_DEVICE(dev); |
1578 | 306ec6c3 | Andreas Färber | VirtIONet *n = VIRTIO_NET(dev); |
1579 | 17ec5a86 | KONRAD Frederic | int i;
|
1580 | 17ec5a86 | KONRAD Frederic | |
1581 | 17ec5a86 | KONRAD Frederic | /* This will stop vhost backend if appropriate. */
|
1582 | 17ec5a86 | KONRAD Frederic | virtio_net_set_status(vdev, 0);
|
1583 | 17ec5a86 | KONRAD Frederic | |
1584 | 306ec6c3 | Andreas Färber | unregister_savevm(dev, "virtio-net", n);
|
1585 | 17ec5a86 | KONRAD Frederic | |
1586 | 8a253ec2 | KONRAD Frederic | if (n->netclient_name) {
|
1587 | 8a253ec2 | KONRAD Frederic | g_free(n->netclient_name); |
1588 | 8a253ec2 | KONRAD Frederic | n->netclient_name = NULL;
|
1589 | 8a253ec2 | KONRAD Frederic | } |
1590 | 8a253ec2 | KONRAD Frederic | if (n->netclient_type) {
|
1591 | 8a253ec2 | KONRAD Frederic | g_free(n->netclient_type); |
1592 | 8a253ec2 | KONRAD Frederic | n->netclient_type = NULL;
|
1593 | 8a253ec2 | KONRAD Frederic | } |
1594 | 8a253ec2 | KONRAD Frederic | |
1595 | 17ec5a86 | KONRAD Frederic | g_free(n->mac_table.macs); |
1596 | 17ec5a86 | KONRAD Frederic | g_free(n->vlans); |
1597 | 17ec5a86 | KONRAD Frederic | |
1598 | 17ec5a86 | KONRAD Frederic | for (i = 0; i < n->max_queues; i++) { |
1599 | 17ec5a86 | KONRAD Frederic | VirtIONetQueue *q = &n->vqs[i]; |
1600 | 17ec5a86 | KONRAD Frederic | NetClientState *nc = qemu_get_subqueue(n->nic, i); |
1601 | 17ec5a86 | KONRAD Frederic | |
1602 | 17ec5a86 | KONRAD Frederic | qemu_purge_queued_packets(nc); |
1603 | 17ec5a86 | KONRAD Frederic | |
1604 | 17ec5a86 | KONRAD Frederic | if (q->tx_timer) {
|
1605 | bc72ad67 | Alex Bligh | timer_del(q->tx_timer); |
1606 | bc72ad67 | Alex Bligh | timer_free(q->tx_timer); |
1607 | fe2dafa0 | Jason Wang | } else if (q->tx_bh) { |
1608 | 17ec5a86 | KONRAD Frederic | qemu_bh_delete(q->tx_bh); |
1609 | 17ec5a86 | KONRAD Frederic | } |
1610 | 17ec5a86 | KONRAD Frederic | } |
1611 | 17ec5a86 | KONRAD Frederic | |
1612 | 17ec5a86 | KONRAD Frederic | g_free(n->vqs); |
1613 | 17ec5a86 | KONRAD Frederic | qemu_del_nic(n->nic); |
1614 | 6a1a8cc7 | KONRAD Frederic | virtio_cleanup(vdev); |
1615 | 17ec5a86 | KONRAD Frederic | } |
1616 | 17ec5a86 | KONRAD Frederic | |
1617 | 17ec5a86 | KONRAD Frederic | static void virtio_net_instance_init(Object *obj) |
1618 | 17ec5a86 | KONRAD Frederic | { |
1619 | 17ec5a86 | KONRAD Frederic | VirtIONet *n = VIRTIO_NET(obj); |
1620 | 17ec5a86 | KONRAD Frederic | |
1621 | 17ec5a86 | KONRAD Frederic | /*
|
1622 | 17ec5a86 | KONRAD Frederic | * The default config_size is sizeof(struct virtio_net_config).
|
1623 | 17ec5a86 | KONRAD Frederic | * Can be overriden with virtio_net_set_config_size.
|
1624 | 17ec5a86 | KONRAD Frederic | */
|
1625 | 17ec5a86 | KONRAD Frederic | n->config_size = sizeof(struct virtio_net_config); |
1626 | 17ec5a86 | KONRAD Frederic | } |
1627 | 17ec5a86 | KONRAD Frederic | |
1628 | 17ec5a86 | KONRAD Frederic | static Property virtio_net_properties[] = {
|
1629 | 17ec5a86 | KONRAD Frederic | DEFINE_NIC_PROPERTIES(VirtIONet, nic_conf), |
1630 | 17ec5a86 | KONRAD Frederic | DEFINE_PROP_UINT32("x-txtimer", VirtIONet, net_conf.txtimer,
|
1631 | 17ec5a86 | KONRAD Frederic | TX_TIMER_INTERVAL), |
1632 | 17ec5a86 | KONRAD Frederic | DEFINE_PROP_INT32("x-txburst", VirtIONet, net_conf.txburst, TX_BURST),
|
1633 | 17ec5a86 | KONRAD Frederic | DEFINE_PROP_STRING("tx", VirtIONet, net_conf.tx),
|
1634 | 17ec5a86 | KONRAD Frederic | DEFINE_PROP_END_OF_LIST(), |
1635 | 17ec5a86 | KONRAD Frederic | }; |
1636 | 17ec5a86 | KONRAD Frederic | |
1637 | 17ec5a86 | KONRAD Frederic | static void virtio_net_class_init(ObjectClass *klass, void *data) |
1638 | 17ec5a86 | KONRAD Frederic | { |
1639 | 17ec5a86 | KONRAD Frederic | DeviceClass *dc = DEVICE_CLASS(klass); |
1640 | 17ec5a86 | KONRAD Frederic | VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); |
1641 | e6f746b3 | Andreas Färber | |
1642 | 17ec5a86 | KONRAD Frederic | dc->props = virtio_net_properties; |
1643 | 125ee0ed | Marcel Apfelbaum | set_bit(DEVICE_CATEGORY_NETWORK, dc->categories); |
1644 | e6f746b3 | Andreas Färber | vdc->realize = virtio_net_device_realize; |
1645 | 306ec6c3 | Andreas Färber | vdc->unrealize = virtio_net_device_unrealize; |
1646 | 17ec5a86 | KONRAD Frederic | vdc->get_config = virtio_net_get_config; |
1647 | 17ec5a86 | KONRAD Frederic | vdc->set_config = virtio_net_set_config; |
1648 | 17ec5a86 | KONRAD Frederic | vdc->get_features = virtio_net_get_features; |
1649 | 17ec5a86 | KONRAD Frederic | vdc->set_features = virtio_net_set_features; |
1650 | 17ec5a86 | KONRAD Frederic | vdc->bad_features = virtio_net_bad_features; |
1651 | 17ec5a86 | KONRAD Frederic | vdc->reset = virtio_net_reset; |
1652 | 17ec5a86 | KONRAD Frederic | vdc->set_status = virtio_net_set_status; |
1653 | 17ec5a86 | KONRAD Frederic | vdc->guest_notifier_mask = virtio_net_guest_notifier_mask; |
1654 | 17ec5a86 | KONRAD Frederic | vdc->guest_notifier_pending = virtio_net_guest_notifier_pending; |
1655 | 17ec5a86 | KONRAD Frederic | } |
1656 | 17ec5a86 | KONRAD Frederic | |
1657 | 17ec5a86 | KONRAD Frederic | static const TypeInfo virtio_net_info = { |
1658 | 17ec5a86 | KONRAD Frederic | .name = TYPE_VIRTIO_NET, |
1659 | 17ec5a86 | KONRAD Frederic | .parent = TYPE_VIRTIO_DEVICE, |
1660 | 17ec5a86 | KONRAD Frederic | .instance_size = sizeof(VirtIONet),
|
1661 | 17ec5a86 | KONRAD Frederic | .instance_init = virtio_net_instance_init, |
1662 | 17ec5a86 | KONRAD Frederic | .class_init = virtio_net_class_init, |
1663 | 17ec5a86 | KONRAD Frederic | }; |
1664 | 17ec5a86 | KONRAD Frederic | |
1665 | 17ec5a86 | KONRAD Frederic | static void virtio_register_types(void) |
1666 | 17ec5a86 | KONRAD Frederic | { |
1667 | 17ec5a86 | KONRAD Frederic | type_register_static(&virtio_net_info); |
1668 | 17ec5a86 | KONRAD Frederic | } |
1669 | 17ec5a86 | KONRAD Frederic | |
1670 | 17ec5a86 | KONRAD Frederic | type_init(virtio_register_types) |