|
@@ -104,8 +104,8 @@ struct virtnet_nic {
|
104
|
104
|
/** Pending rx packet count */
|
105
|
105
|
unsigned int rx_num_iobufs;
|
106
|
106
|
|
107
|
|
- /** Virtio net packet header, we only need one */
|
108
|
|
- struct virtio_net_hdr_modern empty_header;
|
|
107
|
+ /** Virtio net dummy packet headers */
|
|
108
|
+ struct virtio_net_hdr_modern empty_header[QUEUE_NB];
|
109
|
109
|
};
|
110
|
110
|
|
111
|
111
|
/** Add an iobuf to a virtqueue
|
|
@@ -120,19 +120,24 @@ static void virtnet_enqueue_iob ( struct net_device *netdev,
|
120
|
120
|
int vq_idx, struct io_buffer *iobuf ) {
|
121
|
121
|
struct virtnet_nic *virtnet = netdev->priv;
|
122
|
122
|
struct vring_virtqueue *vq = &virtnet->virtqueue[vq_idx];
|
|
123
|
+ struct virtio_net_hdr_modern *header = &virtnet->empty_header[vq_idx];
|
123
|
124
|
unsigned int out = ( vq_idx == TX_INDEX ) ? 2 : 0;
|
124
|
125
|
unsigned int in = ( vq_idx == TX_INDEX ) ? 0 : 2;
|
125
|
|
- size_t header_len = virtnet->virtio_version
|
126
|
|
- ? sizeof ( virtnet->empty_header )
|
127
|
|
- : sizeof ( virtnet->empty_header.legacy );
|
|
126
|
+ size_t header_len = ( virtnet->virtio_version ?
|
|
127
|
+ sizeof ( *header ) : sizeof ( header->legacy ) );
|
128
|
128
|
struct vring_list list[] = {
|
129
|
129
|
{
|
130
|
130
|
/* Share a single zeroed virtio net header between all
|
131
|
|
- * rx and tx packets. This works because this driver
|
|
131
|
+ * packets in a ring. This works because this driver
|
132
|
132
|
* does not use any advanced features so none of the
|
133
|
133
|
* header fields get used.
|
|
134
|
+ *
|
|
135
|
+ * Some host implementations (notably Google Compute
|
|
136
|
+ * Platform) are known to unconditionally write back
|
|
137
|
+ * to header->flags for received packets. Work around
|
|
138
|
+ * this by using separate RX and TX headers.
|
134
|
139
|
*/
|
135
|
|
- .addr = ( char* ) &virtnet->empty_header,
|
|
140
|
+ .addr = ( char* ) header,
|
136
|
141
|
.length = header_len,
|
137
|
142
|
},
|
138
|
143
|
{
|