@@ -1630,6 +1630,18 @@ static int virtio_net_load_device(VirtIODevice *vdev, QEMUFile *f,
return 0;
}
+static void virtio_net_rsc_ipv4_checksum(NetRscSeg *seg)
+{
+ uint32_t sum;
+ struct ip_header *ip;
+
+ ip = (struct ip_header *)(seg->buf + IP_OFFSET);
+
+ ip->ip_sum = 0;
+ sum = net_checksum_add_cont(sizeof(struct ip_header), (uint8_t *)ip, 0);
+ ip->ip_sum = cpu_to_be16(net_checksum_finish(sum));
+}
+
static void virtio_net_rsc_purge(void *opq)
{
int ret = 0;
@@ -1643,6 +1655,10 @@ static void virtio_net_rsc_purge(void *opq)
continue;
}
+ if ((chain->proto == ETH_P_IP) && seg->is_coalesced) {
+ virtio_net_rsc_ipv4_checksum(seg);
+ }
+
ret = virtio_net_do_receive(seg->nc, seg->buf, seg->size);
QTAILQ_REMOVE(&chain->buffers, seg, next);
g_free(seg->buf);
@@ -1853,6 +1869,9 @@ static size_t virtio_net_rsc_callback(NetRscChain *chain, NetClientState *nc,
QTAILQ_FOREACH_SAFE(seg, &chain->buffers, next, nseg) {
ret = coalesce(chain, seg, buf, size);
if (RSC_FINAL == ret) {
+ if ((chain->proto == ETH_P_IP) && seg->is_coalesced) {
+ virtio_net_rsc_ipv4_checksum(seg);
+ }
ret = virtio_net_do_receive(seg->nc, seg->buf, seg->size);
QTAILQ_REMOVE(&chain->buffers, seg, next);
g_free(seg->buf);
Signed-off-by: Wei Xu <wexu@redhat.com> --- hw/net/virtio-net.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+)