16e790746SPaolo Bonzini /* 26e790746SPaolo Bonzini * Virtio Network Device 36e790746SPaolo Bonzini * 46e790746SPaolo Bonzini * Copyright IBM, Corp. 2007 56e790746SPaolo Bonzini * 66e790746SPaolo Bonzini * Authors: 76e790746SPaolo Bonzini * Anthony Liguori <aliguori@us.ibm.com> 86e790746SPaolo Bonzini * 96e790746SPaolo Bonzini * This work is licensed under the terms of the GNU GPL, version 2. See 106e790746SPaolo Bonzini * the COPYING file in the top-level directory. 116e790746SPaolo Bonzini * 126e790746SPaolo Bonzini */ 136e790746SPaolo Bonzini 149b8bfe21SPeter Maydell #include "qemu/osdep.h" 159711cd0dSJens Freimann #include "qemu/atomic.h" 166e790746SPaolo Bonzini #include "qemu/iov.h" 17db725815SMarkus Armbruster #include "qemu/main-loop.h" 180b8fa32fSMarkus Armbruster #include "qemu/module.h" 196e790746SPaolo Bonzini #include "hw/virtio/virtio.h" 206e790746SPaolo Bonzini #include "net/net.h" 216e790746SPaolo Bonzini #include "net/checksum.h" 226e790746SPaolo Bonzini #include "net/tap.h" 236e790746SPaolo Bonzini #include "qemu/error-report.h" 246e790746SPaolo Bonzini #include "qemu/timer.h" 259711cd0dSJens Freimann #include "qemu/option.h" 269711cd0dSJens Freimann #include "qemu/option_int.h" 279711cd0dSJens Freimann #include "qemu/config-file.h" 289711cd0dSJens Freimann #include "qapi/qmp/qdict.h" 296e790746SPaolo Bonzini #include "hw/virtio/virtio-net.h" 306e790746SPaolo Bonzini #include "net/vhost_net.h" 319d8c6a25SDr. David Alan Gilbert #include "net/announce.h" 3217ec5a86SKONRAD Frederic #include "hw/virtio/virtio-bus.h" 33e688df6bSMarkus Armbruster #include "qapi/error.h" 349af23989SMarkus Armbruster #include "qapi/qapi-events-net.h" 35a27bd6c7SMarkus Armbruster #include "hw/qdev-properties.h" 369711cd0dSJens Freimann #include "qapi/qapi-types-migration.h" 379711cd0dSJens Freimann #include "qapi/qapi-events-migration.h" 381399c60dSRusty Russell #include "hw/virtio/virtio-access.h" 39f8d806c9SJuan Quintela #include "migration/misc.h" 409473939eSJason Baron #include "standard-headers/linux/ethtool.h" 412f780b6aSMarkus Armbruster #include "sysemu/sysemu.h" 429d8c6a25SDr. David Alan Gilbert #include "trace.h" 439711cd0dSJens Freimann #include "monitor/qdev.h" 449711cd0dSJens Freimann #include "hw/pci/pci.h" 456e790746SPaolo Bonzini 466e790746SPaolo Bonzini #define VIRTIO_NET_VM_VERSION 11 476e790746SPaolo Bonzini 486e790746SPaolo Bonzini #define MAC_TABLE_ENTRIES 64 496e790746SPaolo Bonzini #define MAX_VLAN (1 << 12) /* Per 802.1Q definition */ 506e790746SPaolo Bonzini 511c0fbfa3SMichael S. Tsirkin /* previously fixed value */ 521c0fbfa3SMichael S. Tsirkin #define VIRTIO_NET_RX_QUEUE_DEFAULT_SIZE 256 539b02e161SWei Wang #define VIRTIO_NET_TX_QUEUE_DEFAULT_SIZE 256 549b02e161SWei Wang 551c0fbfa3SMichael S. Tsirkin /* for now, only allow larger queues; with virtio-1, guest can downsize */ 561c0fbfa3SMichael S. Tsirkin #define VIRTIO_NET_RX_QUEUE_MIN_SIZE VIRTIO_NET_RX_QUEUE_DEFAULT_SIZE 579b02e161SWei Wang #define VIRTIO_NET_TX_QUEUE_MIN_SIZE VIRTIO_NET_TX_QUEUE_DEFAULT_SIZE 581c0fbfa3SMichael S. Tsirkin 592974e916SYuri Benditovich #define VIRTIO_NET_IP4_ADDR_SIZE 8 /* ipv4 saddr + daddr */ 602974e916SYuri Benditovich 612974e916SYuri Benditovich #define VIRTIO_NET_TCP_FLAG 0x3F 622974e916SYuri Benditovich #define VIRTIO_NET_TCP_HDR_LENGTH 0xF000 632974e916SYuri Benditovich 642974e916SYuri Benditovich /* IPv4 max payload, 16 bits in the header */ 652974e916SYuri Benditovich #define VIRTIO_NET_MAX_IP4_PAYLOAD (65535 - sizeof(struct ip_header)) 662974e916SYuri Benditovich #define VIRTIO_NET_MAX_TCP_PAYLOAD 65535 672974e916SYuri Benditovich 682974e916SYuri Benditovich /* header length value in ip header without option */ 692974e916SYuri Benditovich #define VIRTIO_NET_IP4_HEADER_LENGTH 5 702974e916SYuri Benditovich 712974e916SYuri Benditovich #define VIRTIO_NET_IP6_ADDR_SIZE 32 /* ipv6 saddr + daddr */ 722974e916SYuri Benditovich #define VIRTIO_NET_MAX_IP6_PAYLOAD VIRTIO_NET_MAX_TCP_PAYLOAD 732974e916SYuri Benditovich 742974e916SYuri Benditovich /* Purge coalesced packets timer interval, This value affects the performance 752974e916SYuri Benditovich a lot, and should be tuned carefully, '300000'(300us) is the recommended 762974e916SYuri Benditovich value to pass the WHQL test, '50000' can gain 2x netperf throughput with 772974e916SYuri Benditovich tso/gso/gro 'off'. */ 782974e916SYuri Benditovich #define VIRTIO_NET_RSC_DEFAULT_INTERVAL 300000 792974e916SYuri Benditovich 802974e916SYuri Benditovich /* temporary until standard header include it */ 812974e916SYuri Benditovich #if !defined(VIRTIO_NET_HDR_F_RSC_INFO) 822974e916SYuri Benditovich 832974e916SYuri Benditovich #define VIRTIO_NET_HDR_F_RSC_INFO 4 /* rsc_ext data in csum_ fields */ 84d47e5e31SYuri Benditovich #define VIRTIO_NET_F_RSC_EXT 61 852974e916SYuri Benditovich 862974e916SYuri Benditovich static inline __virtio16 *virtio_net_rsc_ext_num_packets( 872974e916SYuri Benditovich struct virtio_net_hdr *hdr) 882974e916SYuri Benditovich { 892974e916SYuri Benditovich return &hdr->csum_start; 902974e916SYuri Benditovich } 912974e916SYuri Benditovich 922974e916SYuri Benditovich static inline __virtio16 *virtio_net_rsc_ext_num_dupacks( 932974e916SYuri Benditovich struct virtio_net_hdr *hdr) 942974e916SYuri Benditovich { 952974e916SYuri Benditovich return &hdr->csum_offset; 962974e916SYuri Benditovich } 972974e916SYuri Benditovich 982974e916SYuri Benditovich #endif 992974e916SYuri Benditovich 1006e790746SPaolo Bonzini static VirtIOFeature feature_sizes[] = { 101127833eeSJason Baron {.flags = 1ULL << VIRTIO_NET_F_MAC, 1025d5b33c0SMax Reitz .end = endof(struct virtio_net_config, mac)}, 103127833eeSJason Baron {.flags = 1ULL << VIRTIO_NET_F_STATUS, 1045d5b33c0SMax Reitz .end = endof(struct virtio_net_config, status)}, 105127833eeSJason Baron {.flags = 1ULL << VIRTIO_NET_F_MQ, 1065d5b33c0SMax Reitz .end = endof(struct virtio_net_config, max_virtqueue_pairs)}, 107127833eeSJason Baron {.flags = 1ULL << VIRTIO_NET_F_MTU, 1085d5b33c0SMax Reitz .end = endof(struct virtio_net_config, mtu)}, 1099473939eSJason Baron {.flags = 1ULL << VIRTIO_NET_F_SPEED_DUPLEX, 1105d5b33c0SMax Reitz .end = endof(struct virtio_net_config, duplex)}, 1116e790746SPaolo Bonzini {} 1126e790746SPaolo Bonzini }; 1136e790746SPaolo Bonzini 1146e790746SPaolo Bonzini static VirtIONetQueue *virtio_net_get_subqueue(NetClientState *nc) 1156e790746SPaolo Bonzini { 1166e790746SPaolo Bonzini VirtIONet *n = qemu_get_nic_opaque(nc); 1176e790746SPaolo Bonzini 1186e790746SPaolo Bonzini return &n->vqs[nc->queue_index]; 1196e790746SPaolo Bonzini } 1206e790746SPaolo Bonzini 1216e790746SPaolo Bonzini static int vq2q(int queue_index) 1226e790746SPaolo Bonzini { 1236e790746SPaolo Bonzini return queue_index / 2; 1246e790746SPaolo Bonzini } 1256e790746SPaolo Bonzini 1266e790746SPaolo Bonzini /* TODO 1276e790746SPaolo Bonzini * - we could suppress RX interrupt if we were so inclined. 1286e790746SPaolo Bonzini */ 1296e790746SPaolo Bonzini 1306e790746SPaolo Bonzini static void virtio_net_get_config(VirtIODevice *vdev, uint8_t *config) 1316e790746SPaolo Bonzini { 13217a0ca55SKONRAD Frederic VirtIONet *n = VIRTIO_NET(vdev); 1336e790746SPaolo Bonzini struct virtio_net_config netcfg; 1346e790746SPaolo Bonzini 1351399c60dSRusty Russell virtio_stw_p(vdev, &netcfg.status, n->status); 1361399c60dSRusty Russell virtio_stw_p(vdev, &netcfg.max_virtqueue_pairs, n->max_queues); 137a93e599dSMaxime Coquelin virtio_stw_p(vdev, &netcfg.mtu, n->net_conf.mtu); 1386e790746SPaolo Bonzini memcpy(netcfg.mac, n->mac, ETH_ALEN); 1399473939eSJason Baron virtio_stl_p(vdev, &netcfg.speed, n->net_conf.speed); 1409473939eSJason Baron netcfg.duplex = n->net_conf.duplex; 1416e790746SPaolo Bonzini memcpy(config, &netcfg, n->config_size); 1426e790746SPaolo Bonzini } 1436e790746SPaolo Bonzini 1446e790746SPaolo Bonzini static void virtio_net_set_config(VirtIODevice *vdev, const uint8_t *config) 1456e790746SPaolo Bonzini { 14617a0ca55SKONRAD Frederic VirtIONet *n = VIRTIO_NET(vdev); 1476e790746SPaolo Bonzini struct virtio_net_config netcfg = {}; 1486e790746SPaolo Bonzini 1496e790746SPaolo Bonzini memcpy(&netcfg, config, n->config_size); 1506e790746SPaolo Bonzini 15195129d6fSCornelia Huck if (!virtio_vdev_has_feature(vdev, VIRTIO_NET_F_CTRL_MAC_ADDR) && 15295129d6fSCornelia Huck !virtio_vdev_has_feature(vdev, VIRTIO_F_VERSION_1) && 1536e790746SPaolo Bonzini memcmp(netcfg.mac, n->mac, ETH_ALEN)) { 1546e790746SPaolo Bonzini memcpy(n->mac, netcfg.mac, ETH_ALEN); 1556e790746SPaolo Bonzini qemu_format_nic_info_str(qemu_get_queue(n->nic), n->mac); 1566e790746SPaolo Bonzini } 1576e790746SPaolo Bonzini } 1586e790746SPaolo Bonzini 1596e790746SPaolo Bonzini static bool virtio_net_started(VirtIONet *n, uint8_t status) 1606e790746SPaolo Bonzini { 16117a0ca55SKONRAD Frederic VirtIODevice *vdev = VIRTIO_DEVICE(n); 1626e790746SPaolo Bonzini return (status & VIRTIO_CONFIG_S_DRIVER_OK) && 16317a0ca55SKONRAD Frederic (n->status & VIRTIO_NET_S_LINK_UP) && vdev->vm_running; 1646e790746SPaolo Bonzini } 1656e790746SPaolo Bonzini 166b2c929f0SDr. David Alan Gilbert static void virtio_net_announce_notify(VirtIONet *net) 167b2c929f0SDr. David Alan Gilbert { 168b2c929f0SDr. David Alan Gilbert VirtIODevice *vdev = VIRTIO_DEVICE(net); 169b2c929f0SDr. David Alan Gilbert trace_virtio_net_announce_notify(); 170b2c929f0SDr. David Alan Gilbert 171b2c929f0SDr. David Alan Gilbert net->status |= VIRTIO_NET_S_ANNOUNCE; 172b2c929f0SDr. David Alan Gilbert virtio_notify_config(vdev); 173b2c929f0SDr. David Alan Gilbert } 174b2c929f0SDr. David Alan Gilbert 175f57fcf70SJason Wang static void virtio_net_announce_timer(void *opaque) 176f57fcf70SJason Wang { 177f57fcf70SJason Wang VirtIONet *n = opaque; 1789d8c6a25SDr. David Alan Gilbert trace_virtio_net_announce_timer(n->announce_timer.round); 179f57fcf70SJason Wang 1809d8c6a25SDr. David Alan Gilbert n->announce_timer.round--; 181b2c929f0SDr. David Alan Gilbert virtio_net_announce_notify(n); 182b2c929f0SDr. David Alan Gilbert } 183b2c929f0SDr. David Alan Gilbert 184b2c929f0SDr. David Alan Gilbert static void virtio_net_announce(NetClientState *nc) 185b2c929f0SDr. David Alan Gilbert { 186b2c929f0SDr. David Alan Gilbert VirtIONet *n = qemu_get_nic_opaque(nc); 187b2c929f0SDr. David Alan Gilbert VirtIODevice *vdev = VIRTIO_DEVICE(n); 188b2c929f0SDr. David Alan Gilbert 189b2c929f0SDr. David Alan Gilbert /* 190b2c929f0SDr. David Alan Gilbert * Make sure the virtio migration announcement timer isn't running 191b2c929f0SDr. David Alan Gilbert * If it is, let it trigger announcement so that we do not cause 192b2c929f0SDr. David Alan Gilbert * confusion. 193b2c929f0SDr. David Alan Gilbert */ 194b2c929f0SDr. David Alan Gilbert if (n->announce_timer.round) { 195b2c929f0SDr. David Alan Gilbert return; 196b2c929f0SDr. David Alan Gilbert } 197b2c929f0SDr. David Alan Gilbert 198b2c929f0SDr. David Alan Gilbert if (virtio_vdev_has_feature(vdev, VIRTIO_NET_F_GUEST_ANNOUNCE) && 199b2c929f0SDr. David Alan Gilbert virtio_vdev_has_feature(vdev, VIRTIO_NET_F_CTRL_VQ)) { 200b2c929f0SDr. David Alan Gilbert virtio_net_announce_notify(n); 201b2c929f0SDr. David Alan Gilbert } 202f57fcf70SJason Wang } 203f57fcf70SJason Wang 2046e790746SPaolo Bonzini static void virtio_net_vhost_status(VirtIONet *n, uint8_t status) 2056e790746SPaolo Bonzini { 20617a0ca55SKONRAD Frederic VirtIODevice *vdev = VIRTIO_DEVICE(n); 2076e790746SPaolo Bonzini NetClientState *nc = qemu_get_queue(n->nic); 2086e790746SPaolo Bonzini int queues = n->multiqueue ? n->max_queues : 1; 2096e790746SPaolo Bonzini 210ed8b4afeSNikolay Nikolaev if (!get_vhost_net(nc->peer)) { 2116e790746SPaolo Bonzini return; 2126e790746SPaolo Bonzini } 2136e790746SPaolo Bonzini 2148c1ac475SRadim Krčmář if ((virtio_net_started(n, status) && !nc->peer->link_down) == 2158c1ac475SRadim Krčmář !!n->vhost_started) { 2166e790746SPaolo Bonzini return; 2176e790746SPaolo Bonzini } 2186e790746SPaolo Bonzini if (!n->vhost_started) { 219086abc1cSMichael S. Tsirkin int r, i; 220086abc1cSMichael S. Tsirkin 2211bfa316cSGreg Kurz if (n->needs_vnet_hdr_swap) { 2221bfa316cSGreg Kurz error_report("backend does not support %s vnet headers; " 2231bfa316cSGreg Kurz "falling back on userspace virtio", 2241bfa316cSGreg Kurz virtio_is_big_endian(vdev) ? "BE" : "LE"); 2251bfa316cSGreg Kurz return; 2261bfa316cSGreg Kurz } 2271bfa316cSGreg Kurz 228086abc1cSMichael S. Tsirkin /* Any packets outstanding? Purge them to avoid touching rings 229086abc1cSMichael S. Tsirkin * when vhost is running. 230086abc1cSMichael S. Tsirkin */ 231086abc1cSMichael S. Tsirkin for (i = 0; i < queues; i++) { 232086abc1cSMichael S. Tsirkin NetClientState *qnc = qemu_get_subqueue(n->nic, i); 233086abc1cSMichael S. Tsirkin 234086abc1cSMichael S. Tsirkin /* Purge both directions: TX and RX. */ 235086abc1cSMichael S. Tsirkin qemu_net_queue_purge(qnc->peer->incoming_queue, qnc); 236086abc1cSMichael S. Tsirkin qemu_net_queue_purge(qnc->incoming_queue, qnc->peer); 237086abc1cSMichael S. Tsirkin } 238086abc1cSMichael S. Tsirkin 239a93e599dSMaxime Coquelin if (virtio_has_feature(vdev->guest_features, VIRTIO_NET_F_MTU)) { 240a93e599dSMaxime Coquelin r = vhost_net_set_mtu(get_vhost_net(nc->peer), n->net_conf.mtu); 241a93e599dSMaxime Coquelin if (r < 0) { 242a93e599dSMaxime Coquelin error_report("%uBytes MTU not supported by the backend", 243a93e599dSMaxime Coquelin n->net_conf.mtu); 244a93e599dSMaxime Coquelin 245a93e599dSMaxime Coquelin return; 246a93e599dSMaxime Coquelin } 247a93e599dSMaxime Coquelin } 248a93e599dSMaxime Coquelin 2496e790746SPaolo Bonzini n->vhost_started = 1; 25017a0ca55SKONRAD Frederic r = vhost_net_start(vdev, n->nic->ncs, queues); 2516e790746SPaolo Bonzini if (r < 0) { 2526e790746SPaolo Bonzini error_report("unable to start vhost net: %d: " 2536e790746SPaolo Bonzini "falling back on userspace virtio", -r); 2546e790746SPaolo Bonzini n->vhost_started = 0; 2556e790746SPaolo Bonzini } 2566e790746SPaolo Bonzini } else { 25717a0ca55SKONRAD Frederic vhost_net_stop(vdev, n->nic->ncs, queues); 2586e790746SPaolo Bonzini n->vhost_started = 0; 2596e790746SPaolo Bonzini } 2606e790746SPaolo Bonzini } 2616e790746SPaolo Bonzini 2621bfa316cSGreg Kurz static int virtio_net_set_vnet_endian_one(VirtIODevice *vdev, 2631bfa316cSGreg Kurz NetClientState *peer, 2641bfa316cSGreg Kurz bool enable) 2651bfa316cSGreg Kurz { 2661bfa316cSGreg Kurz if (virtio_is_big_endian(vdev)) { 2671bfa316cSGreg Kurz return qemu_set_vnet_be(peer, enable); 2681bfa316cSGreg Kurz } else { 2691bfa316cSGreg Kurz return qemu_set_vnet_le(peer, enable); 2701bfa316cSGreg Kurz } 2711bfa316cSGreg Kurz } 2721bfa316cSGreg Kurz 2731bfa316cSGreg Kurz static bool virtio_net_set_vnet_endian(VirtIODevice *vdev, NetClientState *ncs, 2741bfa316cSGreg Kurz int queues, bool enable) 2751bfa316cSGreg Kurz { 2761bfa316cSGreg Kurz int i; 2771bfa316cSGreg Kurz 2781bfa316cSGreg Kurz for (i = 0; i < queues; i++) { 2791bfa316cSGreg Kurz if (virtio_net_set_vnet_endian_one(vdev, ncs[i].peer, enable) < 0 && 2801bfa316cSGreg Kurz enable) { 2811bfa316cSGreg Kurz while (--i >= 0) { 2821bfa316cSGreg Kurz virtio_net_set_vnet_endian_one(vdev, ncs[i].peer, false); 2831bfa316cSGreg Kurz } 2841bfa316cSGreg Kurz 2851bfa316cSGreg Kurz return true; 2861bfa316cSGreg Kurz } 2871bfa316cSGreg Kurz } 2881bfa316cSGreg Kurz 2891bfa316cSGreg Kurz return false; 2901bfa316cSGreg Kurz } 2911bfa316cSGreg Kurz 2921bfa316cSGreg Kurz static void virtio_net_vnet_endian_status(VirtIONet *n, uint8_t status) 2931bfa316cSGreg Kurz { 2941bfa316cSGreg Kurz VirtIODevice *vdev = VIRTIO_DEVICE(n); 2951bfa316cSGreg Kurz int queues = n->multiqueue ? n->max_queues : 1; 2961bfa316cSGreg Kurz 2971bfa316cSGreg Kurz if (virtio_net_started(n, status)) { 2981bfa316cSGreg Kurz /* Before using the device, we tell the network backend about the 2991bfa316cSGreg Kurz * endianness to use when parsing vnet headers. If the backend 3001bfa316cSGreg Kurz * can't do it, we fallback onto fixing the headers in the core 3011bfa316cSGreg Kurz * virtio-net code. 3021bfa316cSGreg Kurz */ 3031bfa316cSGreg Kurz n->needs_vnet_hdr_swap = virtio_net_set_vnet_endian(vdev, n->nic->ncs, 3041bfa316cSGreg Kurz queues, true); 3051bfa316cSGreg Kurz } else if (virtio_net_started(n, vdev->status)) { 3061bfa316cSGreg Kurz /* After using the device, we need to reset the network backend to 3071bfa316cSGreg Kurz * the default (guest native endianness), otherwise the guest may 3081bfa316cSGreg Kurz * lose network connectivity if it is rebooted into a different 3091bfa316cSGreg Kurz * endianness. 3101bfa316cSGreg Kurz */ 3111bfa316cSGreg Kurz virtio_net_set_vnet_endian(vdev, n->nic->ncs, queues, false); 3121bfa316cSGreg Kurz } 3131bfa316cSGreg Kurz } 3141bfa316cSGreg Kurz 315283e2c2aSYuri Benditovich static void virtio_net_drop_tx_queue_data(VirtIODevice *vdev, VirtQueue *vq) 316283e2c2aSYuri Benditovich { 317283e2c2aSYuri Benditovich unsigned int dropped = virtqueue_drop_all(vq); 318283e2c2aSYuri Benditovich if (dropped) { 319283e2c2aSYuri Benditovich virtio_notify(vdev, vq); 320283e2c2aSYuri Benditovich } 321283e2c2aSYuri Benditovich } 322283e2c2aSYuri Benditovich 3236e790746SPaolo Bonzini static void virtio_net_set_status(struct VirtIODevice *vdev, uint8_t status) 3246e790746SPaolo Bonzini { 32517a0ca55SKONRAD Frederic VirtIONet *n = VIRTIO_NET(vdev); 3266e790746SPaolo Bonzini VirtIONetQueue *q; 3276e790746SPaolo Bonzini int i; 3286e790746SPaolo Bonzini uint8_t queue_status; 3296e790746SPaolo Bonzini 3301bfa316cSGreg Kurz virtio_net_vnet_endian_status(n, status); 3316e790746SPaolo Bonzini virtio_net_vhost_status(n, status); 3326e790746SPaolo Bonzini 3336e790746SPaolo Bonzini for (i = 0; i < n->max_queues; i++) { 33438705bb5SFam Zheng NetClientState *ncs = qemu_get_subqueue(n->nic, i); 33538705bb5SFam Zheng bool queue_started; 3366e790746SPaolo Bonzini q = &n->vqs[i]; 3376e790746SPaolo Bonzini 3386e790746SPaolo Bonzini if ((!n->multiqueue && i != 0) || i >= n->curr_queues) { 3396e790746SPaolo Bonzini queue_status = 0; 3406e790746SPaolo Bonzini } else { 3416e790746SPaolo Bonzini queue_status = status; 3426e790746SPaolo Bonzini } 34338705bb5SFam Zheng queue_started = 34438705bb5SFam Zheng virtio_net_started(n, queue_status) && !n->vhost_started; 34538705bb5SFam Zheng 34638705bb5SFam Zheng if (queue_started) { 34738705bb5SFam Zheng qemu_flush_queued_packets(ncs); 34838705bb5SFam Zheng } 3496e790746SPaolo Bonzini 3506e790746SPaolo Bonzini if (!q->tx_waiting) { 3516e790746SPaolo Bonzini continue; 3526e790746SPaolo Bonzini } 3536e790746SPaolo Bonzini 35438705bb5SFam Zheng if (queue_started) { 3556e790746SPaolo Bonzini if (q->tx_timer) { 356bc72ad67SAlex Bligh timer_mod(q->tx_timer, 357bc72ad67SAlex Bligh qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + n->tx_timeout); 3586e790746SPaolo Bonzini } else { 3596e790746SPaolo Bonzini qemu_bh_schedule(q->tx_bh); 3606e790746SPaolo Bonzini } 3616e790746SPaolo Bonzini } else { 3626e790746SPaolo Bonzini if (q->tx_timer) { 363bc72ad67SAlex Bligh timer_del(q->tx_timer); 3646e790746SPaolo Bonzini } else { 3656e790746SPaolo Bonzini qemu_bh_cancel(q->tx_bh); 3666e790746SPaolo Bonzini } 367283e2c2aSYuri Benditovich if ((n->status & VIRTIO_NET_S_LINK_UP) == 0 && 36870e53e6eSJason Wang (queue_status & VIRTIO_CONFIG_S_DRIVER_OK) && 36970e53e6eSJason Wang vdev->vm_running) { 370283e2c2aSYuri Benditovich /* if tx is waiting we are likely have some packets in tx queue 371283e2c2aSYuri Benditovich * and disabled notification */ 372283e2c2aSYuri Benditovich q->tx_waiting = 0; 373283e2c2aSYuri Benditovich virtio_queue_set_notification(q->tx_vq, 1); 374283e2c2aSYuri Benditovich virtio_net_drop_tx_queue_data(vdev, q->tx_vq); 375283e2c2aSYuri Benditovich } 3766e790746SPaolo Bonzini } 3776e790746SPaolo Bonzini } 3786e790746SPaolo Bonzini } 3796e790746SPaolo Bonzini 3806e790746SPaolo Bonzini static void virtio_net_set_link_status(NetClientState *nc) 3816e790746SPaolo Bonzini { 3826e790746SPaolo Bonzini VirtIONet *n = qemu_get_nic_opaque(nc); 38317a0ca55SKONRAD Frederic VirtIODevice *vdev = VIRTIO_DEVICE(n); 3846e790746SPaolo Bonzini uint16_t old_status = n->status; 3856e790746SPaolo Bonzini 3866e790746SPaolo Bonzini if (nc->link_down) 3876e790746SPaolo Bonzini n->status &= ~VIRTIO_NET_S_LINK_UP; 3886e790746SPaolo Bonzini else 3896e790746SPaolo Bonzini n->status |= VIRTIO_NET_S_LINK_UP; 3906e790746SPaolo Bonzini 3916e790746SPaolo Bonzini if (n->status != old_status) 39217a0ca55SKONRAD Frederic virtio_notify_config(vdev); 3936e790746SPaolo Bonzini 39417a0ca55SKONRAD Frederic virtio_net_set_status(vdev, vdev->status); 3956e790746SPaolo Bonzini } 3966e790746SPaolo Bonzini 397b1be4280SAmos Kong static void rxfilter_notify(NetClientState *nc) 398b1be4280SAmos Kong { 399b1be4280SAmos Kong VirtIONet *n = qemu_get_nic_opaque(nc); 400b1be4280SAmos Kong 401b1be4280SAmos Kong if (nc->rxfilter_notify_enabled) { 40296e35046SAmos Kong gchar *path = object_get_canonical_path(OBJECT(n->qdev)); 40306150279SWenchao Xia qapi_event_send_nic_rx_filter_changed(!!n->netclient_name, 4043ab72385SPeter Xu n->netclient_name, path); 40596e35046SAmos Kong g_free(path); 406b1be4280SAmos Kong 407b1be4280SAmos Kong /* disable event notification to avoid events flooding */ 408b1be4280SAmos Kong nc->rxfilter_notify_enabled = 0; 409b1be4280SAmos Kong } 410b1be4280SAmos Kong } 411b1be4280SAmos Kong 412f7bc8ef8SAmos Kong static intList *get_vlan_table(VirtIONet *n) 413f7bc8ef8SAmos Kong { 414f7bc8ef8SAmos Kong intList *list, *entry; 415f7bc8ef8SAmos Kong int i, j; 416f7bc8ef8SAmos Kong 417f7bc8ef8SAmos Kong list = NULL; 418f7bc8ef8SAmos Kong for (i = 0; i < MAX_VLAN >> 5; i++) { 419f7bc8ef8SAmos Kong for (j = 0; n->vlans[i] && j <= 0x1f; j++) { 420f7bc8ef8SAmos Kong if (n->vlans[i] & (1U << j)) { 421f7bc8ef8SAmos Kong entry = g_malloc0(sizeof(*entry)); 422f7bc8ef8SAmos Kong entry->value = (i << 5) + j; 423f7bc8ef8SAmos Kong entry->next = list; 424f7bc8ef8SAmos Kong list = entry; 425f7bc8ef8SAmos Kong } 426f7bc8ef8SAmos Kong } 427f7bc8ef8SAmos Kong } 428f7bc8ef8SAmos Kong 429f7bc8ef8SAmos Kong return list; 430f7bc8ef8SAmos Kong } 431f7bc8ef8SAmos Kong 432b1be4280SAmos Kong static RxFilterInfo *virtio_net_query_rxfilter(NetClientState *nc) 433b1be4280SAmos Kong { 434b1be4280SAmos Kong VirtIONet *n = qemu_get_nic_opaque(nc); 435f7bc8ef8SAmos Kong VirtIODevice *vdev = VIRTIO_DEVICE(n); 436b1be4280SAmos Kong RxFilterInfo *info; 437b1be4280SAmos Kong strList *str_list, *entry; 438f7bc8ef8SAmos Kong int i; 439b1be4280SAmos Kong 440b1be4280SAmos Kong info = g_malloc0(sizeof(*info)); 441b1be4280SAmos Kong info->name = g_strdup(nc->name); 442b1be4280SAmos Kong info->promiscuous = n->promisc; 443b1be4280SAmos Kong 444b1be4280SAmos Kong if (n->nouni) { 445b1be4280SAmos Kong info->unicast = RX_STATE_NONE; 446b1be4280SAmos Kong } else if (n->alluni) { 447b1be4280SAmos Kong info->unicast = RX_STATE_ALL; 448b1be4280SAmos Kong } else { 449b1be4280SAmos Kong info->unicast = RX_STATE_NORMAL; 450b1be4280SAmos Kong } 451b1be4280SAmos Kong 452b1be4280SAmos Kong if (n->nomulti) { 453b1be4280SAmos Kong info->multicast = RX_STATE_NONE; 454b1be4280SAmos Kong } else if (n->allmulti) { 455b1be4280SAmos Kong info->multicast = RX_STATE_ALL; 456b1be4280SAmos Kong } else { 457b1be4280SAmos Kong info->multicast = RX_STATE_NORMAL; 458b1be4280SAmos Kong } 459b1be4280SAmos Kong 460b1be4280SAmos Kong info->broadcast_allowed = n->nobcast; 461b1be4280SAmos Kong info->multicast_overflow = n->mac_table.multi_overflow; 462b1be4280SAmos Kong info->unicast_overflow = n->mac_table.uni_overflow; 463b1be4280SAmos Kong 464b0575ba4SScott Feldman info->main_mac = qemu_mac_strdup_printf(n->mac); 465b1be4280SAmos Kong 466b1be4280SAmos Kong str_list = NULL; 467b1be4280SAmos Kong for (i = 0; i < n->mac_table.first_multi; i++) { 468b1be4280SAmos Kong entry = g_malloc0(sizeof(*entry)); 469b0575ba4SScott Feldman entry->value = qemu_mac_strdup_printf(n->mac_table.macs + i * ETH_ALEN); 470b1be4280SAmos Kong entry->next = str_list; 471b1be4280SAmos Kong str_list = entry; 472b1be4280SAmos Kong } 473b1be4280SAmos Kong info->unicast_table = str_list; 474b1be4280SAmos Kong 475b1be4280SAmos Kong str_list = NULL; 476b1be4280SAmos Kong for (i = n->mac_table.first_multi; i < n->mac_table.in_use; i++) { 477b1be4280SAmos Kong entry = g_malloc0(sizeof(*entry)); 478b0575ba4SScott Feldman entry->value = qemu_mac_strdup_printf(n->mac_table.macs + i * ETH_ALEN); 479b1be4280SAmos Kong entry->next = str_list; 480b1be4280SAmos Kong str_list = entry; 481b1be4280SAmos Kong } 482b1be4280SAmos Kong info->multicast_table = str_list; 483f7bc8ef8SAmos Kong info->vlan_table = get_vlan_table(n); 484b1be4280SAmos Kong 48595129d6fSCornelia Huck if (!virtio_vdev_has_feature(vdev, VIRTIO_NET_F_CTRL_VLAN)) { 486f7bc8ef8SAmos Kong info->vlan = RX_STATE_ALL; 487f7bc8ef8SAmos Kong } else if (!info->vlan_table) { 488f7bc8ef8SAmos Kong info->vlan = RX_STATE_NONE; 489f7bc8ef8SAmos Kong } else { 490f7bc8ef8SAmos Kong info->vlan = RX_STATE_NORMAL; 491b1be4280SAmos Kong } 492b1be4280SAmos Kong 493b1be4280SAmos Kong /* enable event notification after query */ 494b1be4280SAmos Kong nc->rxfilter_notify_enabled = 1; 495b1be4280SAmos Kong 496b1be4280SAmos Kong return info; 497b1be4280SAmos Kong } 498b1be4280SAmos Kong 4996e790746SPaolo Bonzini static void virtio_net_reset(VirtIODevice *vdev) 5006e790746SPaolo Bonzini { 50117a0ca55SKONRAD Frederic VirtIONet *n = VIRTIO_NET(vdev); 50294b52958SGreg Kurz int i; 5036e790746SPaolo Bonzini 5046e790746SPaolo Bonzini /* Reset back to compatibility mode */ 5056e790746SPaolo Bonzini n->promisc = 1; 5066e790746SPaolo Bonzini n->allmulti = 0; 5076e790746SPaolo Bonzini n->alluni = 0; 5086e790746SPaolo Bonzini n->nomulti = 0; 5096e790746SPaolo Bonzini n->nouni = 0; 5106e790746SPaolo Bonzini n->nobcast = 0; 5116e790746SPaolo Bonzini /* multiqueue is disabled by default */ 5126e790746SPaolo Bonzini n->curr_queues = 1; 5139d8c6a25SDr. David Alan Gilbert timer_del(n->announce_timer.tm); 5149d8c6a25SDr. David Alan Gilbert n->announce_timer.round = 0; 515f57fcf70SJason Wang n->status &= ~VIRTIO_NET_S_ANNOUNCE; 5166e790746SPaolo Bonzini 5176e790746SPaolo Bonzini /* Flush any MAC and VLAN filter table state */ 5186e790746SPaolo Bonzini n->mac_table.in_use = 0; 5196e790746SPaolo Bonzini n->mac_table.first_multi = 0; 5206e790746SPaolo Bonzini n->mac_table.multi_overflow = 0; 5216e790746SPaolo Bonzini n->mac_table.uni_overflow = 0; 5226e790746SPaolo Bonzini memset(n->mac_table.macs, 0, MAC_TABLE_ENTRIES * ETH_ALEN); 5236e790746SPaolo Bonzini memcpy(&n->mac[0], &n->nic->conf->macaddr, sizeof(n->mac)); 524702d66a8SMichael S. Tsirkin qemu_format_nic_info_str(qemu_get_queue(n->nic), n->mac); 5256e790746SPaolo Bonzini memset(n->vlans, 0, MAX_VLAN >> 3); 52694b52958SGreg Kurz 52794b52958SGreg Kurz /* Flush any async TX */ 52894b52958SGreg Kurz for (i = 0; i < n->max_queues; i++) { 52994b52958SGreg Kurz NetClientState *nc = qemu_get_subqueue(n->nic, i); 53094b52958SGreg Kurz 53194b52958SGreg Kurz if (nc->peer) { 53294b52958SGreg Kurz qemu_flush_or_purge_queued_packets(nc->peer, true); 53394b52958SGreg Kurz assert(!virtio_net_get_subqueue(nc)->async_tx.elem); 53494b52958SGreg Kurz } 53594b52958SGreg Kurz } 5366e790746SPaolo Bonzini } 5376e790746SPaolo Bonzini 5386e790746SPaolo Bonzini static void peer_test_vnet_hdr(VirtIONet *n) 5396e790746SPaolo Bonzini { 5406e790746SPaolo Bonzini NetClientState *nc = qemu_get_queue(n->nic); 5416e790746SPaolo Bonzini if (!nc->peer) { 5426e790746SPaolo Bonzini return; 5436e790746SPaolo Bonzini } 5446e790746SPaolo Bonzini 545d6085e3aSStefan Hajnoczi n->has_vnet_hdr = qemu_has_vnet_hdr(nc->peer); 5466e790746SPaolo Bonzini } 5476e790746SPaolo Bonzini 5486e790746SPaolo Bonzini static int peer_has_vnet_hdr(VirtIONet *n) 5496e790746SPaolo Bonzini { 5506e790746SPaolo Bonzini return n->has_vnet_hdr; 5516e790746SPaolo Bonzini } 5526e790746SPaolo Bonzini 5536e790746SPaolo Bonzini static int peer_has_ufo(VirtIONet *n) 5546e790746SPaolo Bonzini { 5556e790746SPaolo Bonzini if (!peer_has_vnet_hdr(n)) 5566e790746SPaolo Bonzini return 0; 5576e790746SPaolo Bonzini 558d6085e3aSStefan Hajnoczi n->has_ufo = qemu_has_ufo(qemu_get_queue(n->nic)->peer); 5596e790746SPaolo Bonzini 5606e790746SPaolo Bonzini return n->has_ufo; 5616e790746SPaolo Bonzini } 5626e790746SPaolo Bonzini 563bb9d17f8SCornelia Huck static void virtio_net_set_mrg_rx_bufs(VirtIONet *n, int mergeable_rx_bufs, 564bb9d17f8SCornelia Huck int version_1) 5656e790746SPaolo Bonzini { 5666e790746SPaolo Bonzini int i; 5676e790746SPaolo Bonzini NetClientState *nc; 5686e790746SPaolo Bonzini 5696e790746SPaolo Bonzini n->mergeable_rx_bufs = mergeable_rx_bufs; 5706e790746SPaolo Bonzini 571bb9d17f8SCornelia Huck if (version_1) { 572bb9d17f8SCornelia Huck n->guest_hdr_len = sizeof(struct virtio_net_hdr_mrg_rxbuf); 573bb9d17f8SCornelia Huck } else { 5746e790746SPaolo Bonzini n->guest_hdr_len = n->mergeable_rx_bufs ? 575bb9d17f8SCornelia Huck sizeof(struct virtio_net_hdr_mrg_rxbuf) : 576bb9d17f8SCornelia Huck sizeof(struct virtio_net_hdr); 577bb9d17f8SCornelia Huck } 5786e790746SPaolo Bonzini 5796e790746SPaolo Bonzini for (i = 0; i < n->max_queues; i++) { 5806e790746SPaolo Bonzini nc = qemu_get_subqueue(n->nic, i); 5816e790746SPaolo Bonzini 5826e790746SPaolo Bonzini if (peer_has_vnet_hdr(n) && 583d6085e3aSStefan Hajnoczi qemu_has_vnet_hdr_len(nc->peer, n->guest_hdr_len)) { 584d6085e3aSStefan Hajnoczi qemu_set_vnet_hdr_len(nc->peer, n->guest_hdr_len); 5856e790746SPaolo Bonzini n->host_hdr_len = n->guest_hdr_len; 5866e790746SPaolo Bonzini } 5876e790746SPaolo Bonzini } 5886e790746SPaolo Bonzini } 5896e790746SPaolo Bonzini 5902eef278bSMichael S. Tsirkin static int virtio_net_max_tx_queue_size(VirtIONet *n) 5912eef278bSMichael S. Tsirkin { 5922eef278bSMichael S. Tsirkin NetClientState *peer = n->nic_conf.peers.ncs[0]; 5932eef278bSMichael S. Tsirkin 5942eef278bSMichael S. Tsirkin /* 5952eef278bSMichael S. Tsirkin * Backends other than vhost-user don't support max queue size. 5962eef278bSMichael S. Tsirkin */ 5972eef278bSMichael S. Tsirkin if (!peer) { 5982eef278bSMichael S. Tsirkin return VIRTIO_NET_TX_QUEUE_DEFAULT_SIZE; 5992eef278bSMichael S. Tsirkin } 6002eef278bSMichael S. Tsirkin 6012eef278bSMichael S. Tsirkin if (peer->info->type != NET_CLIENT_DRIVER_VHOST_USER) { 6022eef278bSMichael S. Tsirkin return VIRTIO_NET_TX_QUEUE_DEFAULT_SIZE; 6032eef278bSMichael S. Tsirkin } 6042eef278bSMichael S. Tsirkin 6052eef278bSMichael S. Tsirkin return VIRTQUEUE_MAX_SIZE; 6062eef278bSMichael S. Tsirkin } 6072eef278bSMichael S. Tsirkin 6086e790746SPaolo Bonzini static int peer_attach(VirtIONet *n, int index) 6096e790746SPaolo Bonzini { 6106e790746SPaolo Bonzini NetClientState *nc = qemu_get_subqueue(n->nic, index); 6116e790746SPaolo Bonzini 6126e790746SPaolo Bonzini if (!nc->peer) { 6136e790746SPaolo Bonzini return 0; 6146e790746SPaolo Bonzini } 6156e790746SPaolo Bonzini 616f394b2e2SEric Blake if (nc->peer->info->type == NET_CLIENT_DRIVER_VHOST_USER) { 6177263a0adSChangchun Ouyang vhost_set_vring_enable(nc->peer, 1); 6187263a0adSChangchun Ouyang } 6197263a0adSChangchun Ouyang 620f394b2e2SEric Blake if (nc->peer->info->type != NET_CLIENT_DRIVER_TAP) { 6216e790746SPaolo Bonzini return 0; 6226e790746SPaolo Bonzini } 6236e790746SPaolo Bonzini 6241074b879SJason Wang if (n->max_queues == 1) { 6251074b879SJason Wang return 0; 6261074b879SJason Wang } 6271074b879SJason Wang 6286e790746SPaolo Bonzini return tap_enable(nc->peer); 6296e790746SPaolo Bonzini } 6306e790746SPaolo Bonzini 6316e790746SPaolo Bonzini static int peer_detach(VirtIONet *n, int index) 6326e790746SPaolo Bonzini { 6336e790746SPaolo Bonzini NetClientState *nc = qemu_get_subqueue(n->nic, index); 6346e790746SPaolo Bonzini 6356e790746SPaolo Bonzini if (!nc->peer) { 6366e790746SPaolo Bonzini return 0; 6376e790746SPaolo Bonzini } 6386e790746SPaolo Bonzini 639f394b2e2SEric Blake if (nc->peer->info->type == NET_CLIENT_DRIVER_VHOST_USER) { 6407263a0adSChangchun Ouyang vhost_set_vring_enable(nc->peer, 0); 6417263a0adSChangchun Ouyang } 6427263a0adSChangchun Ouyang 643f394b2e2SEric Blake if (nc->peer->info->type != NET_CLIENT_DRIVER_TAP) { 6446e790746SPaolo Bonzini return 0; 6456e790746SPaolo Bonzini } 6466e790746SPaolo Bonzini 6476e790746SPaolo Bonzini return tap_disable(nc->peer); 6486e790746SPaolo Bonzini } 6496e790746SPaolo Bonzini 6506e790746SPaolo Bonzini static void virtio_net_set_queues(VirtIONet *n) 6516e790746SPaolo Bonzini { 6526e790746SPaolo Bonzini int i; 653ddfa83eaSJoel Stanley int r; 6546e790746SPaolo Bonzini 65568b5f314SYuri Benditovich if (n->nic->peer_deleted) { 65668b5f314SYuri Benditovich return; 65768b5f314SYuri Benditovich } 65868b5f314SYuri Benditovich 6596e790746SPaolo Bonzini for (i = 0; i < n->max_queues; i++) { 6606e790746SPaolo Bonzini if (i < n->curr_queues) { 661ddfa83eaSJoel Stanley r = peer_attach(n, i); 662ddfa83eaSJoel Stanley assert(!r); 6636e790746SPaolo Bonzini } else { 664ddfa83eaSJoel Stanley r = peer_detach(n, i); 665ddfa83eaSJoel Stanley assert(!r); 6666e790746SPaolo Bonzini } 6676e790746SPaolo Bonzini } 6686e790746SPaolo Bonzini } 6696e790746SPaolo Bonzini 670ec57db16SJason Wang static void virtio_net_set_multiqueue(VirtIONet *n, int multiqueue); 6716e790746SPaolo Bonzini 6729d5b731dSJason Wang static uint64_t virtio_net_get_features(VirtIODevice *vdev, uint64_t features, 6739d5b731dSJason Wang Error **errp) 6746e790746SPaolo Bonzini { 67517a0ca55SKONRAD Frederic VirtIONet *n = VIRTIO_NET(vdev); 6766e790746SPaolo Bonzini NetClientState *nc = qemu_get_queue(n->nic); 6776e790746SPaolo Bonzini 678da3e8a23SShannon Zhao /* Firstly sync all virtio-net possible supported features */ 679da3e8a23SShannon Zhao features |= n->host_features; 680da3e8a23SShannon Zhao 6810cd09c3aSCornelia Huck virtio_add_feature(&features, VIRTIO_NET_F_MAC); 6826e790746SPaolo Bonzini 6836e790746SPaolo Bonzini if (!peer_has_vnet_hdr(n)) { 6840cd09c3aSCornelia Huck virtio_clear_feature(&features, VIRTIO_NET_F_CSUM); 6850cd09c3aSCornelia Huck virtio_clear_feature(&features, VIRTIO_NET_F_HOST_TSO4); 6860cd09c3aSCornelia Huck virtio_clear_feature(&features, VIRTIO_NET_F_HOST_TSO6); 6870cd09c3aSCornelia Huck virtio_clear_feature(&features, VIRTIO_NET_F_HOST_ECN); 6886e790746SPaolo Bonzini 6890cd09c3aSCornelia Huck virtio_clear_feature(&features, VIRTIO_NET_F_GUEST_CSUM); 6900cd09c3aSCornelia Huck virtio_clear_feature(&features, VIRTIO_NET_F_GUEST_TSO4); 6910cd09c3aSCornelia Huck virtio_clear_feature(&features, VIRTIO_NET_F_GUEST_TSO6); 6920cd09c3aSCornelia Huck virtio_clear_feature(&features, VIRTIO_NET_F_GUEST_ECN); 6936e790746SPaolo Bonzini } 6946e790746SPaolo Bonzini 6956e790746SPaolo Bonzini if (!peer_has_vnet_hdr(n) || !peer_has_ufo(n)) { 6960cd09c3aSCornelia Huck virtio_clear_feature(&features, VIRTIO_NET_F_GUEST_UFO); 6970cd09c3aSCornelia Huck virtio_clear_feature(&features, VIRTIO_NET_F_HOST_UFO); 6986e790746SPaolo Bonzini } 6996e790746SPaolo Bonzini 700ed8b4afeSNikolay Nikolaev if (!get_vhost_net(nc->peer)) { 7016e790746SPaolo Bonzini return features; 7026e790746SPaolo Bonzini } 7032974e916SYuri Benditovich 70475ebec11SMaxime Coquelin features = vhost_net_get_features(get_vhost_net(nc->peer), features); 70575ebec11SMaxime Coquelin vdev->backend_features = features; 70675ebec11SMaxime Coquelin 70775ebec11SMaxime Coquelin if (n->mtu_bypass_backend && 70875ebec11SMaxime Coquelin (n->host_features & 1ULL << VIRTIO_NET_F_MTU)) { 70975ebec11SMaxime Coquelin features |= (1ULL << VIRTIO_NET_F_MTU); 71075ebec11SMaxime Coquelin } 71175ebec11SMaxime Coquelin 71275ebec11SMaxime Coquelin return features; 7136e790746SPaolo Bonzini } 7146e790746SPaolo Bonzini 715019a3edbSGerd Hoffmann static uint64_t virtio_net_bad_features(VirtIODevice *vdev) 7166e790746SPaolo Bonzini { 717019a3edbSGerd Hoffmann uint64_t features = 0; 7186e790746SPaolo Bonzini 7196e790746SPaolo Bonzini /* Linux kernel 2.6.25. It understood MAC (as everyone must), 7206e790746SPaolo Bonzini * but also these: */ 7210cd09c3aSCornelia Huck virtio_add_feature(&features, VIRTIO_NET_F_MAC); 7220cd09c3aSCornelia Huck virtio_add_feature(&features, VIRTIO_NET_F_CSUM); 7230cd09c3aSCornelia Huck virtio_add_feature(&features, VIRTIO_NET_F_HOST_TSO4); 7240cd09c3aSCornelia Huck virtio_add_feature(&features, VIRTIO_NET_F_HOST_TSO6); 7250cd09c3aSCornelia Huck virtio_add_feature(&features, VIRTIO_NET_F_HOST_ECN); 7266e790746SPaolo Bonzini 7276e790746SPaolo Bonzini return features; 7286e790746SPaolo Bonzini } 7296e790746SPaolo Bonzini 730644c9858SDmitry Fleytman static void virtio_net_apply_guest_offloads(VirtIONet *n) 731644c9858SDmitry Fleytman { 732ad37bb3bSStefan Hajnoczi qemu_set_offload(qemu_get_queue(n->nic)->peer, 733644c9858SDmitry Fleytman !!(n->curr_guest_offloads & (1ULL << VIRTIO_NET_F_GUEST_CSUM)), 734644c9858SDmitry Fleytman !!(n->curr_guest_offloads & (1ULL << VIRTIO_NET_F_GUEST_TSO4)), 735644c9858SDmitry Fleytman !!(n->curr_guest_offloads & (1ULL << VIRTIO_NET_F_GUEST_TSO6)), 736644c9858SDmitry Fleytman !!(n->curr_guest_offloads & (1ULL << VIRTIO_NET_F_GUEST_ECN)), 737644c9858SDmitry Fleytman !!(n->curr_guest_offloads & (1ULL << VIRTIO_NET_F_GUEST_UFO))); 738644c9858SDmitry Fleytman } 739644c9858SDmitry Fleytman 740644c9858SDmitry Fleytman static uint64_t virtio_net_guest_offloads_by_features(uint32_t features) 741644c9858SDmitry Fleytman { 742644c9858SDmitry Fleytman static const uint64_t guest_offloads_mask = 743644c9858SDmitry Fleytman (1ULL << VIRTIO_NET_F_GUEST_CSUM) | 744644c9858SDmitry Fleytman (1ULL << VIRTIO_NET_F_GUEST_TSO4) | 745644c9858SDmitry Fleytman (1ULL << VIRTIO_NET_F_GUEST_TSO6) | 746644c9858SDmitry Fleytman (1ULL << VIRTIO_NET_F_GUEST_ECN) | 747644c9858SDmitry Fleytman (1ULL << VIRTIO_NET_F_GUEST_UFO); 748644c9858SDmitry Fleytman 749644c9858SDmitry Fleytman return guest_offloads_mask & features; 750644c9858SDmitry Fleytman } 751644c9858SDmitry Fleytman 752644c9858SDmitry Fleytman static inline uint64_t virtio_net_supported_guest_offloads(VirtIONet *n) 753644c9858SDmitry Fleytman { 754644c9858SDmitry Fleytman VirtIODevice *vdev = VIRTIO_DEVICE(n); 755644c9858SDmitry Fleytman return virtio_net_guest_offloads_by_features(vdev->guest_features); 756644c9858SDmitry Fleytman } 757644c9858SDmitry Fleytman 7589711cd0dSJens Freimann static void failover_add_primary(VirtIONet *n, Error **errp) 7599711cd0dSJens Freimann { 7609711cd0dSJens Freimann Error *err = NULL; 7619711cd0dSJens Freimann 762117378bfSJens Freimann if (n->primary_dev) { 763117378bfSJens Freimann return; 764117378bfSJens Freimann } 765117378bfSJens Freimann 7669711cd0dSJens Freimann n->primary_device_opts = qemu_opts_find(qemu_find_opts("device"), 7679711cd0dSJens Freimann n->primary_device_id); 7689711cd0dSJens Freimann if (n->primary_device_opts) { 7699711cd0dSJens Freimann n->primary_dev = qdev_device_add(n->primary_device_opts, &err); 7709711cd0dSJens Freimann if (err) { 7719711cd0dSJens Freimann qemu_opts_del(n->primary_device_opts); 7729711cd0dSJens Freimann } 7739711cd0dSJens Freimann if (n->primary_dev) { 7749711cd0dSJens Freimann n->primary_bus = n->primary_dev->parent_bus; 7759711cd0dSJens Freimann if (err) { 7769711cd0dSJens Freimann qdev_unplug(n->primary_dev, &err); 7779711cd0dSJens Freimann qdev_set_id(n->primary_dev, ""); 7789711cd0dSJens Freimann 7799711cd0dSJens Freimann } 7809711cd0dSJens Freimann } 7819711cd0dSJens Freimann } else { 7829711cd0dSJens Freimann error_setg(errp, "Primary device not found"); 7839711cd0dSJens Freimann error_append_hint(errp, "Virtio-net failover will not work. Make " 7849711cd0dSJens Freimann "sure primary device has parameter" 7859711cd0dSJens Freimann " failover_pair_id=<virtio-net-id>\n"); 7869711cd0dSJens Freimann } 7879711cd0dSJens Freimann if (err) { 7889711cd0dSJens Freimann error_propagate(errp, err); 7899711cd0dSJens Freimann } 7909711cd0dSJens Freimann } 7919711cd0dSJens Freimann 7929711cd0dSJens Freimann static int is_my_primary(void *opaque, QemuOpts *opts, Error **errp) 7939711cd0dSJens Freimann { 7949711cd0dSJens Freimann VirtIONet *n = opaque; 7959711cd0dSJens Freimann int ret = 0; 7969711cd0dSJens Freimann 7979711cd0dSJens Freimann const char *standby_id = qemu_opt_get(opts, "failover_pair_id"); 7989711cd0dSJens Freimann 7999711cd0dSJens Freimann if (standby_id != NULL && (g_strcmp0(standby_id, n->netclient_name) == 0)) { 8009711cd0dSJens Freimann n->primary_device_id = g_strdup(opts->id); 8019711cd0dSJens Freimann ret = 1; 8029711cd0dSJens Freimann } 8039711cd0dSJens Freimann 8049711cd0dSJens Freimann return ret; 8059711cd0dSJens Freimann } 8069711cd0dSJens Freimann 8079711cd0dSJens Freimann static DeviceState *virtio_net_find_primary(VirtIONet *n, Error **errp) 8089711cd0dSJens Freimann { 8099711cd0dSJens Freimann DeviceState *dev = NULL; 8109711cd0dSJens Freimann Error *err = NULL; 8119711cd0dSJens Freimann 8129711cd0dSJens Freimann if (qemu_opts_foreach(qemu_find_opts("device"), 8139711cd0dSJens Freimann is_my_primary, n, &err)) { 8149711cd0dSJens Freimann if (err) { 8159711cd0dSJens Freimann error_propagate(errp, err); 8169711cd0dSJens Freimann return NULL; 8179711cd0dSJens Freimann } 8189711cd0dSJens Freimann if (n->primary_device_id) { 8199711cd0dSJens Freimann dev = qdev_find_recursive(sysbus_get_default(), 8209711cd0dSJens Freimann n->primary_device_id); 8219711cd0dSJens Freimann } else { 8229711cd0dSJens Freimann error_setg(errp, "Primary device id not found"); 8239711cd0dSJens Freimann return NULL; 8249711cd0dSJens Freimann } 8259711cd0dSJens Freimann } 8269711cd0dSJens Freimann return dev; 8279711cd0dSJens Freimann } 8289711cd0dSJens Freimann 8299711cd0dSJens Freimann 8309711cd0dSJens Freimann 8319711cd0dSJens Freimann static DeviceState *virtio_connect_failover_devices(VirtIONet *n, 8329711cd0dSJens Freimann DeviceState *dev, 8339711cd0dSJens Freimann Error **errp) 8349711cd0dSJens Freimann { 8359711cd0dSJens Freimann DeviceState *prim_dev = NULL; 8369711cd0dSJens Freimann Error *err = NULL; 8379711cd0dSJens Freimann 8389711cd0dSJens Freimann prim_dev = virtio_net_find_primary(n, &err); 8399711cd0dSJens Freimann if (prim_dev) { 8409711cd0dSJens Freimann n->primary_device_id = g_strdup(prim_dev->id); 8419711cd0dSJens Freimann n->primary_device_opts = prim_dev->opts; 8429711cd0dSJens Freimann } else { 8439711cd0dSJens Freimann if (err) { 8449711cd0dSJens Freimann error_propagate(errp, err); 8459711cd0dSJens Freimann } 8469711cd0dSJens Freimann } 8479711cd0dSJens Freimann 8489711cd0dSJens Freimann return prim_dev; 8499711cd0dSJens Freimann } 8509711cd0dSJens Freimann 851d5aaa1b0SGerd Hoffmann static void virtio_net_set_features(VirtIODevice *vdev, uint64_t features) 8526e790746SPaolo Bonzini { 85317a0ca55SKONRAD Frederic VirtIONet *n = VIRTIO_NET(vdev); 8549711cd0dSJens Freimann Error *err = NULL; 8556e790746SPaolo Bonzini int i; 8566e790746SPaolo Bonzini 85775ebec11SMaxime Coquelin if (n->mtu_bypass_backend && 85875ebec11SMaxime Coquelin !virtio_has_feature(vdev->backend_features, VIRTIO_NET_F_MTU)) { 85975ebec11SMaxime Coquelin features &= ~(1ULL << VIRTIO_NET_F_MTU); 86075ebec11SMaxime Coquelin } 86175ebec11SMaxime Coquelin 862ef546f12SCornelia Huck virtio_net_set_multiqueue(n, 86395129d6fSCornelia Huck virtio_has_feature(features, VIRTIO_NET_F_MQ)); 8646e790746SPaolo Bonzini 865ef546f12SCornelia Huck virtio_net_set_mrg_rx_bufs(n, 86695129d6fSCornelia Huck virtio_has_feature(features, 867bb9d17f8SCornelia Huck VIRTIO_NET_F_MRG_RXBUF), 86895129d6fSCornelia Huck virtio_has_feature(features, 869bb9d17f8SCornelia Huck VIRTIO_F_VERSION_1)); 8706e790746SPaolo Bonzini 8712974e916SYuri Benditovich n->rsc4_enabled = virtio_has_feature(features, VIRTIO_NET_F_RSC_EXT) && 8722974e916SYuri Benditovich virtio_has_feature(features, VIRTIO_NET_F_GUEST_TSO4); 8732974e916SYuri Benditovich n->rsc6_enabled = virtio_has_feature(features, VIRTIO_NET_F_RSC_EXT) && 8742974e916SYuri Benditovich virtio_has_feature(features, VIRTIO_NET_F_GUEST_TSO6); 8752974e916SYuri Benditovich 8766e790746SPaolo Bonzini if (n->has_vnet_hdr) { 877644c9858SDmitry Fleytman n->curr_guest_offloads = 878644c9858SDmitry Fleytman virtio_net_guest_offloads_by_features(features); 879644c9858SDmitry Fleytman virtio_net_apply_guest_offloads(n); 8806e790746SPaolo Bonzini } 8816e790746SPaolo Bonzini 8826e790746SPaolo Bonzini for (i = 0; i < n->max_queues; i++) { 8836e790746SPaolo Bonzini NetClientState *nc = qemu_get_subqueue(n->nic, i); 8846e790746SPaolo Bonzini 885ed8b4afeSNikolay Nikolaev if (!get_vhost_net(nc->peer)) { 8866e790746SPaolo Bonzini continue; 8876e790746SPaolo Bonzini } 888ed8b4afeSNikolay Nikolaev vhost_net_ack_features(get_vhost_net(nc->peer), features); 8896e790746SPaolo Bonzini } 8900b1eaa88SStefan Fritsch 89195129d6fSCornelia Huck if (virtio_has_feature(features, VIRTIO_NET_F_CTRL_VLAN)) { 8920b1eaa88SStefan Fritsch memset(n->vlans, 0, MAX_VLAN >> 3); 8930b1eaa88SStefan Fritsch } else { 8940b1eaa88SStefan Fritsch memset(n->vlans, 0xff, MAX_VLAN >> 3); 8950b1eaa88SStefan Fritsch } 8969711cd0dSJens Freimann 8979711cd0dSJens Freimann if (virtio_has_feature(features, VIRTIO_NET_F_STANDBY)) { 8989711cd0dSJens Freimann qapi_event_send_failover_negotiated(n->netclient_name); 8999711cd0dSJens Freimann atomic_set(&n->primary_should_be_hidden, false); 9009711cd0dSJens Freimann failover_add_primary(n, &err); 9019711cd0dSJens Freimann if (err) { 9029711cd0dSJens Freimann n->primary_dev = virtio_connect_failover_devices(n, n->qdev, &err); 9039711cd0dSJens Freimann if (err) { 9049711cd0dSJens Freimann goto out_err; 9059711cd0dSJens Freimann } 9069711cd0dSJens Freimann failover_add_primary(n, &err); 9079711cd0dSJens Freimann if (err) { 9089711cd0dSJens Freimann goto out_err; 9099711cd0dSJens Freimann } 9109711cd0dSJens Freimann } 9119711cd0dSJens Freimann } 9129711cd0dSJens Freimann return; 9139711cd0dSJens Freimann 9149711cd0dSJens Freimann out_err: 9159711cd0dSJens Freimann if (err) { 9169711cd0dSJens Freimann warn_report_err(err); 9179711cd0dSJens Freimann } 9186e790746SPaolo Bonzini } 9196e790746SPaolo Bonzini 9206e790746SPaolo Bonzini static int virtio_net_handle_rx_mode(VirtIONet *n, uint8_t cmd, 9216e790746SPaolo Bonzini struct iovec *iov, unsigned int iov_cnt) 9226e790746SPaolo Bonzini { 9236e790746SPaolo Bonzini uint8_t on; 9246e790746SPaolo Bonzini size_t s; 925b1be4280SAmos Kong NetClientState *nc = qemu_get_queue(n->nic); 9266e790746SPaolo Bonzini 9276e790746SPaolo Bonzini s = iov_to_buf(iov, iov_cnt, 0, &on, sizeof(on)); 9286e790746SPaolo Bonzini if (s != sizeof(on)) { 9296e790746SPaolo Bonzini return VIRTIO_NET_ERR; 9306e790746SPaolo Bonzini } 9316e790746SPaolo Bonzini 9326e790746SPaolo Bonzini if (cmd == VIRTIO_NET_CTRL_RX_PROMISC) { 9336e790746SPaolo Bonzini n->promisc = on; 9346e790746SPaolo Bonzini } else if (cmd == VIRTIO_NET_CTRL_RX_ALLMULTI) { 9356e790746SPaolo Bonzini n->allmulti = on; 9366e790746SPaolo Bonzini } else if (cmd == VIRTIO_NET_CTRL_RX_ALLUNI) { 9376e790746SPaolo Bonzini n->alluni = on; 9386e790746SPaolo Bonzini } else if (cmd == VIRTIO_NET_CTRL_RX_NOMULTI) { 9396e790746SPaolo Bonzini n->nomulti = on; 9406e790746SPaolo Bonzini } else if (cmd == VIRTIO_NET_CTRL_RX_NOUNI) { 9416e790746SPaolo Bonzini n->nouni = on; 9426e790746SPaolo Bonzini } else if (cmd == VIRTIO_NET_CTRL_RX_NOBCAST) { 9436e790746SPaolo Bonzini n->nobcast = on; 9446e790746SPaolo Bonzini } else { 9456e790746SPaolo Bonzini return VIRTIO_NET_ERR; 9466e790746SPaolo Bonzini } 9476e790746SPaolo Bonzini 948b1be4280SAmos Kong rxfilter_notify(nc); 949b1be4280SAmos Kong 9506e790746SPaolo Bonzini return VIRTIO_NET_OK; 9516e790746SPaolo Bonzini } 9526e790746SPaolo Bonzini 953644c9858SDmitry Fleytman static int virtio_net_handle_offloads(VirtIONet *n, uint8_t cmd, 954644c9858SDmitry Fleytman struct iovec *iov, unsigned int iov_cnt) 955644c9858SDmitry Fleytman { 956644c9858SDmitry Fleytman VirtIODevice *vdev = VIRTIO_DEVICE(n); 957644c9858SDmitry Fleytman uint64_t offloads; 958644c9858SDmitry Fleytman size_t s; 959644c9858SDmitry Fleytman 96095129d6fSCornelia Huck if (!virtio_vdev_has_feature(vdev, VIRTIO_NET_F_CTRL_GUEST_OFFLOADS)) { 961644c9858SDmitry Fleytman return VIRTIO_NET_ERR; 962644c9858SDmitry Fleytman } 963644c9858SDmitry Fleytman 964644c9858SDmitry Fleytman s = iov_to_buf(iov, iov_cnt, 0, &offloads, sizeof(offloads)); 965644c9858SDmitry Fleytman if (s != sizeof(offloads)) { 966644c9858SDmitry Fleytman return VIRTIO_NET_ERR; 967644c9858SDmitry Fleytman } 968644c9858SDmitry Fleytman 969644c9858SDmitry Fleytman if (cmd == VIRTIO_NET_CTRL_GUEST_OFFLOADS_SET) { 970644c9858SDmitry Fleytman uint64_t supported_offloads; 971644c9858SDmitry Fleytman 972189ae6bbSJason Wang offloads = virtio_ldq_p(vdev, &offloads); 973189ae6bbSJason Wang 974644c9858SDmitry Fleytman if (!n->has_vnet_hdr) { 975644c9858SDmitry Fleytman return VIRTIO_NET_ERR; 976644c9858SDmitry Fleytman } 977644c9858SDmitry Fleytman 9782974e916SYuri Benditovich n->rsc4_enabled = virtio_has_feature(offloads, VIRTIO_NET_F_RSC_EXT) && 9792974e916SYuri Benditovich virtio_has_feature(offloads, VIRTIO_NET_F_GUEST_TSO4); 9802974e916SYuri Benditovich n->rsc6_enabled = virtio_has_feature(offloads, VIRTIO_NET_F_RSC_EXT) && 9812974e916SYuri Benditovich virtio_has_feature(offloads, VIRTIO_NET_F_GUEST_TSO6); 9822974e916SYuri Benditovich virtio_clear_feature(&offloads, VIRTIO_NET_F_RSC_EXT); 9832974e916SYuri Benditovich 984644c9858SDmitry Fleytman supported_offloads = virtio_net_supported_guest_offloads(n); 985644c9858SDmitry Fleytman if (offloads & ~supported_offloads) { 986644c9858SDmitry Fleytman return VIRTIO_NET_ERR; 987644c9858SDmitry Fleytman } 988644c9858SDmitry Fleytman 989644c9858SDmitry Fleytman n->curr_guest_offloads = offloads; 990644c9858SDmitry Fleytman virtio_net_apply_guest_offloads(n); 991644c9858SDmitry Fleytman 992644c9858SDmitry Fleytman return VIRTIO_NET_OK; 993644c9858SDmitry Fleytman } else { 994644c9858SDmitry Fleytman return VIRTIO_NET_ERR; 995644c9858SDmitry Fleytman } 996644c9858SDmitry Fleytman } 997644c9858SDmitry Fleytman 9986e790746SPaolo Bonzini static int virtio_net_handle_mac(VirtIONet *n, uint8_t cmd, 9996e790746SPaolo Bonzini struct iovec *iov, unsigned int iov_cnt) 10006e790746SPaolo Bonzini { 10011399c60dSRusty Russell VirtIODevice *vdev = VIRTIO_DEVICE(n); 10026e790746SPaolo Bonzini struct virtio_net_ctrl_mac mac_data; 10036e790746SPaolo Bonzini size_t s; 1004b1be4280SAmos Kong NetClientState *nc = qemu_get_queue(n->nic); 10056e790746SPaolo Bonzini 10066e790746SPaolo Bonzini if (cmd == VIRTIO_NET_CTRL_MAC_ADDR_SET) { 10076e790746SPaolo Bonzini if (iov_size(iov, iov_cnt) != sizeof(n->mac)) { 10086e790746SPaolo Bonzini return VIRTIO_NET_ERR; 10096e790746SPaolo Bonzini } 10106e790746SPaolo Bonzini s = iov_to_buf(iov, iov_cnt, 0, &n->mac, sizeof(n->mac)); 10116e790746SPaolo Bonzini assert(s == sizeof(n->mac)); 10126e790746SPaolo Bonzini qemu_format_nic_info_str(qemu_get_queue(n->nic), n->mac); 1013b1be4280SAmos Kong rxfilter_notify(nc); 1014b1be4280SAmos Kong 10156e790746SPaolo Bonzini return VIRTIO_NET_OK; 10166e790746SPaolo Bonzini } 10176e790746SPaolo Bonzini 10186e790746SPaolo Bonzini if (cmd != VIRTIO_NET_CTRL_MAC_TABLE_SET) { 10196e790746SPaolo Bonzini return VIRTIO_NET_ERR; 10206e790746SPaolo Bonzini } 10216e790746SPaolo Bonzini 1022cae2e556SAmos Kong int in_use = 0; 1023cae2e556SAmos Kong int first_multi = 0; 1024cae2e556SAmos Kong uint8_t uni_overflow = 0; 1025cae2e556SAmos Kong uint8_t multi_overflow = 0; 1026cae2e556SAmos Kong uint8_t *macs = g_malloc0(MAC_TABLE_ENTRIES * ETH_ALEN); 10276e790746SPaolo Bonzini 10286e790746SPaolo Bonzini s = iov_to_buf(iov, iov_cnt, 0, &mac_data.entries, 10296e790746SPaolo Bonzini sizeof(mac_data.entries)); 10301399c60dSRusty Russell mac_data.entries = virtio_ldl_p(vdev, &mac_data.entries); 10316e790746SPaolo Bonzini if (s != sizeof(mac_data.entries)) { 1032b1be4280SAmos Kong goto error; 10336e790746SPaolo Bonzini } 10346e790746SPaolo Bonzini iov_discard_front(&iov, &iov_cnt, s); 10356e790746SPaolo Bonzini 10366e790746SPaolo Bonzini if (mac_data.entries * ETH_ALEN > iov_size(iov, iov_cnt)) { 1037b1be4280SAmos Kong goto error; 10386e790746SPaolo Bonzini } 10396e790746SPaolo Bonzini 10406e790746SPaolo Bonzini if (mac_data.entries <= MAC_TABLE_ENTRIES) { 1041cae2e556SAmos Kong s = iov_to_buf(iov, iov_cnt, 0, macs, 10426e790746SPaolo Bonzini mac_data.entries * ETH_ALEN); 10436e790746SPaolo Bonzini if (s != mac_data.entries * ETH_ALEN) { 1044b1be4280SAmos Kong goto error; 10456e790746SPaolo Bonzini } 1046cae2e556SAmos Kong in_use += mac_data.entries; 10476e790746SPaolo Bonzini } else { 1048cae2e556SAmos Kong uni_overflow = 1; 10496e790746SPaolo Bonzini } 10506e790746SPaolo Bonzini 10516e790746SPaolo Bonzini iov_discard_front(&iov, &iov_cnt, mac_data.entries * ETH_ALEN); 10526e790746SPaolo Bonzini 1053cae2e556SAmos Kong first_multi = in_use; 10546e790746SPaolo Bonzini 10556e790746SPaolo Bonzini s = iov_to_buf(iov, iov_cnt, 0, &mac_data.entries, 10566e790746SPaolo Bonzini sizeof(mac_data.entries)); 10571399c60dSRusty Russell mac_data.entries = virtio_ldl_p(vdev, &mac_data.entries); 10586e790746SPaolo Bonzini if (s != sizeof(mac_data.entries)) { 1059b1be4280SAmos Kong goto error; 10606e790746SPaolo Bonzini } 10616e790746SPaolo Bonzini 10626e790746SPaolo Bonzini iov_discard_front(&iov, &iov_cnt, s); 10636e790746SPaolo Bonzini 10646e790746SPaolo Bonzini if (mac_data.entries * ETH_ALEN != iov_size(iov, iov_cnt)) { 1065b1be4280SAmos Kong goto error; 10666e790746SPaolo Bonzini } 10676e790746SPaolo Bonzini 1068edc24385SMichael S. Tsirkin if (mac_data.entries <= MAC_TABLE_ENTRIES - in_use) { 1069cae2e556SAmos Kong s = iov_to_buf(iov, iov_cnt, 0, &macs[in_use * ETH_ALEN], 10706e790746SPaolo Bonzini mac_data.entries * ETH_ALEN); 10716e790746SPaolo Bonzini if (s != mac_data.entries * ETH_ALEN) { 1072b1be4280SAmos Kong goto error; 10736e790746SPaolo Bonzini } 1074cae2e556SAmos Kong in_use += mac_data.entries; 10756e790746SPaolo Bonzini } else { 1076cae2e556SAmos Kong multi_overflow = 1; 10776e790746SPaolo Bonzini } 10786e790746SPaolo Bonzini 1079cae2e556SAmos Kong n->mac_table.in_use = in_use; 1080cae2e556SAmos Kong n->mac_table.first_multi = first_multi; 1081cae2e556SAmos Kong n->mac_table.uni_overflow = uni_overflow; 1082cae2e556SAmos Kong n->mac_table.multi_overflow = multi_overflow; 1083cae2e556SAmos Kong memcpy(n->mac_table.macs, macs, MAC_TABLE_ENTRIES * ETH_ALEN); 1084cae2e556SAmos Kong g_free(macs); 1085b1be4280SAmos Kong rxfilter_notify(nc); 1086b1be4280SAmos Kong 10876e790746SPaolo Bonzini return VIRTIO_NET_OK; 1088b1be4280SAmos Kong 1089b1be4280SAmos Kong error: 1090cae2e556SAmos Kong g_free(macs); 1091b1be4280SAmos Kong return VIRTIO_NET_ERR; 10926e790746SPaolo Bonzini } 10936e790746SPaolo Bonzini 10946e790746SPaolo Bonzini static int virtio_net_handle_vlan_table(VirtIONet *n, uint8_t cmd, 10956e790746SPaolo Bonzini struct iovec *iov, unsigned int iov_cnt) 10966e790746SPaolo Bonzini { 10971399c60dSRusty Russell VirtIODevice *vdev = VIRTIO_DEVICE(n); 10986e790746SPaolo Bonzini uint16_t vid; 10996e790746SPaolo Bonzini size_t s; 1100b1be4280SAmos Kong NetClientState *nc = qemu_get_queue(n->nic); 11016e790746SPaolo Bonzini 11026e790746SPaolo Bonzini s = iov_to_buf(iov, iov_cnt, 0, &vid, sizeof(vid)); 11031399c60dSRusty Russell vid = virtio_lduw_p(vdev, &vid); 11046e790746SPaolo Bonzini if (s != sizeof(vid)) { 11056e790746SPaolo Bonzini return VIRTIO_NET_ERR; 11066e790746SPaolo Bonzini } 11076e790746SPaolo Bonzini 11086e790746SPaolo Bonzini if (vid >= MAX_VLAN) 11096e790746SPaolo Bonzini return VIRTIO_NET_ERR; 11106e790746SPaolo Bonzini 11116e790746SPaolo Bonzini if (cmd == VIRTIO_NET_CTRL_VLAN_ADD) 11126e790746SPaolo Bonzini n->vlans[vid >> 5] |= (1U << (vid & 0x1f)); 11136e790746SPaolo Bonzini else if (cmd == VIRTIO_NET_CTRL_VLAN_DEL) 11146e790746SPaolo Bonzini n->vlans[vid >> 5] &= ~(1U << (vid & 0x1f)); 11156e790746SPaolo Bonzini else 11166e790746SPaolo Bonzini return VIRTIO_NET_ERR; 11176e790746SPaolo Bonzini 1118b1be4280SAmos Kong rxfilter_notify(nc); 1119b1be4280SAmos Kong 11206e790746SPaolo Bonzini return VIRTIO_NET_OK; 11216e790746SPaolo Bonzini } 11226e790746SPaolo Bonzini 1123f57fcf70SJason Wang static int virtio_net_handle_announce(VirtIONet *n, uint8_t cmd, 1124f57fcf70SJason Wang struct iovec *iov, unsigned int iov_cnt) 1125f57fcf70SJason Wang { 11269d8c6a25SDr. David Alan Gilbert trace_virtio_net_handle_announce(n->announce_timer.round); 1127f57fcf70SJason Wang if (cmd == VIRTIO_NET_CTRL_ANNOUNCE_ACK && 1128f57fcf70SJason Wang n->status & VIRTIO_NET_S_ANNOUNCE) { 1129f57fcf70SJason Wang n->status &= ~VIRTIO_NET_S_ANNOUNCE; 11309d8c6a25SDr. David Alan Gilbert if (n->announce_timer.round) { 11319d8c6a25SDr. David Alan Gilbert qemu_announce_timer_step(&n->announce_timer); 1132f57fcf70SJason Wang } 1133f57fcf70SJason Wang return VIRTIO_NET_OK; 1134f57fcf70SJason Wang } else { 1135f57fcf70SJason Wang return VIRTIO_NET_ERR; 1136f57fcf70SJason Wang } 1137f57fcf70SJason Wang } 1138f57fcf70SJason Wang 11396e790746SPaolo Bonzini static int virtio_net_handle_mq(VirtIONet *n, uint8_t cmd, 11406e790746SPaolo Bonzini struct iovec *iov, unsigned int iov_cnt) 11416e790746SPaolo Bonzini { 114217a0ca55SKONRAD Frederic VirtIODevice *vdev = VIRTIO_DEVICE(n); 11436e790746SPaolo Bonzini struct virtio_net_ctrl_mq mq; 11446e790746SPaolo Bonzini size_t s; 11456e790746SPaolo Bonzini uint16_t queues; 11466e790746SPaolo Bonzini 11476e790746SPaolo Bonzini s = iov_to_buf(iov, iov_cnt, 0, &mq, sizeof(mq)); 11486e790746SPaolo Bonzini if (s != sizeof(mq)) { 11496e790746SPaolo Bonzini return VIRTIO_NET_ERR; 11506e790746SPaolo Bonzini } 11516e790746SPaolo Bonzini 11526e790746SPaolo Bonzini if (cmd != VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET) { 11536e790746SPaolo Bonzini return VIRTIO_NET_ERR; 11546e790746SPaolo Bonzini } 11556e790746SPaolo Bonzini 11561399c60dSRusty Russell queues = virtio_lduw_p(vdev, &mq.virtqueue_pairs); 11576e790746SPaolo Bonzini 11586e790746SPaolo Bonzini if (queues < VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MIN || 11596e790746SPaolo Bonzini queues > VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MAX || 11606e790746SPaolo Bonzini queues > n->max_queues || 11616e790746SPaolo Bonzini !n->multiqueue) { 11626e790746SPaolo Bonzini return VIRTIO_NET_ERR; 11636e790746SPaolo Bonzini } 11646e790746SPaolo Bonzini 11656e790746SPaolo Bonzini n->curr_queues = queues; 11666e790746SPaolo Bonzini /* stop the backend before changing the number of queues to avoid handling a 11676e790746SPaolo Bonzini * disabled queue */ 116817a0ca55SKONRAD Frederic virtio_net_set_status(vdev, vdev->status); 11696e790746SPaolo Bonzini virtio_net_set_queues(n); 11706e790746SPaolo Bonzini 11716e790746SPaolo Bonzini return VIRTIO_NET_OK; 11726e790746SPaolo Bonzini } 1173ba7eadb5SGreg Kurz 11746e790746SPaolo Bonzini static void virtio_net_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq) 11756e790746SPaolo Bonzini { 117617a0ca55SKONRAD Frederic VirtIONet *n = VIRTIO_NET(vdev); 11776e790746SPaolo Bonzini struct virtio_net_ctrl_hdr ctrl; 11786e790746SPaolo Bonzini virtio_net_ctrl_ack status = VIRTIO_NET_ERR; 117951b19ebeSPaolo Bonzini VirtQueueElement *elem; 11806e790746SPaolo Bonzini size_t s; 1181771b6ed3SJason Wang struct iovec *iov, *iov2; 11826e790746SPaolo Bonzini unsigned int iov_cnt; 11836e790746SPaolo Bonzini 118451b19ebeSPaolo Bonzini for (;;) { 118551b19ebeSPaolo Bonzini elem = virtqueue_pop(vq, sizeof(VirtQueueElement)); 118651b19ebeSPaolo Bonzini if (!elem) { 118751b19ebeSPaolo Bonzini break; 118851b19ebeSPaolo Bonzini } 118951b19ebeSPaolo Bonzini if (iov_size(elem->in_sg, elem->in_num) < sizeof(status) || 119051b19ebeSPaolo Bonzini iov_size(elem->out_sg, elem->out_num) < sizeof(ctrl)) { 1191ba7eadb5SGreg Kurz virtio_error(vdev, "virtio-net ctrl missing headers"); 1192ba7eadb5SGreg Kurz virtqueue_detach_element(vq, elem, 0); 1193ba7eadb5SGreg Kurz g_free(elem); 1194ba7eadb5SGreg Kurz break; 11956e790746SPaolo Bonzini } 11966e790746SPaolo Bonzini 119751b19ebeSPaolo Bonzini iov_cnt = elem->out_num; 119851b19ebeSPaolo Bonzini iov2 = iov = g_memdup(elem->out_sg, sizeof(struct iovec) * elem->out_num); 11996e790746SPaolo Bonzini s = iov_to_buf(iov, iov_cnt, 0, &ctrl, sizeof(ctrl)); 12006e790746SPaolo Bonzini iov_discard_front(&iov, &iov_cnt, sizeof(ctrl)); 12016e790746SPaolo Bonzini if (s != sizeof(ctrl)) { 12026e790746SPaolo Bonzini status = VIRTIO_NET_ERR; 12036e790746SPaolo Bonzini } else if (ctrl.class == VIRTIO_NET_CTRL_RX) { 12046e790746SPaolo Bonzini status = virtio_net_handle_rx_mode(n, ctrl.cmd, iov, iov_cnt); 12056e790746SPaolo Bonzini } else if (ctrl.class == VIRTIO_NET_CTRL_MAC) { 12066e790746SPaolo Bonzini status = virtio_net_handle_mac(n, ctrl.cmd, iov, iov_cnt); 12076e790746SPaolo Bonzini } else if (ctrl.class == VIRTIO_NET_CTRL_VLAN) { 12086e790746SPaolo Bonzini status = virtio_net_handle_vlan_table(n, ctrl.cmd, iov, iov_cnt); 1209f57fcf70SJason Wang } else if (ctrl.class == VIRTIO_NET_CTRL_ANNOUNCE) { 1210f57fcf70SJason Wang status = virtio_net_handle_announce(n, ctrl.cmd, iov, iov_cnt); 12116e790746SPaolo Bonzini } else if (ctrl.class == VIRTIO_NET_CTRL_MQ) { 12126e790746SPaolo Bonzini status = virtio_net_handle_mq(n, ctrl.cmd, iov, iov_cnt); 1213644c9858SDmitry Fleytman } else if (ctrl.class == VIRTIO_NET_CTRL_GUEST_OFFLOADS) { 1214644c9858SDmitry Fleytman status = virtio_net_handle_offloads(n, ctrl.cmd, iov, iov_cnt); 12156e790746SPaolo Bonzini } 12166e790746SPaolo Bonzini 121751b19ebeSPaolo Bonzini s = iov_from_buf(elem->in_sg, elem->in_num, 0, &status, sizeof(status)); 12186e790746SPaolo Bonzini assert(s == sizeof(status)); 12196e790746SPaolo Bonzini 122051b19ebeSPaolo Bonzini virtqueue_push(vq, elem, sizeof(status)); 12216e790746SPaolo Bonzini virtio_notify(vdev, vq); 1222771b6ed3SJason Wang g_free(iov2); 122351b19ebeSPaolo Bonzini g_free(elem); 12246e790746SPaolo Bonzini } 12256e790746SPaolo Bonzini } 12266e790746SPaolo Bonzini 12276e790746SPaolo Bonzini /* RX */ 12286e790746SPaolo Bonzini 12296e790746SPaolo Bonzini static void virtio_net_handle_rx(VirtIODevice *vdev, VirtQueue *vq) 12306e790746SPaolo Bonzini { 123117a0ca55SKONRAD Frederic VirtIONet *n = VIRTIO_NET(vdev); 12326e790746SPaolo Bonzini int queue_index = vq2q(virtio_get_queue_index(vq)); 12336e790746SPaolo Bonzini 12346e790746SPaolo Bonzini qemu_flush_queued_packets(qemu_get_subqueue(n->nic, queue_index)); 12356e790746SPaolo Bonzini } 12366e790746SPaolo Bonzini 12376e790746SPaolo Bonzini static int virtio_net_can_receive(NetClientState *nc) 12386e790746SPaolo Bonzini { 12396e790746SPaolo Bonzini VirtIONet *n = qemu_get_nic_opaque(nc); 124017a0ca55SKONRAD Frederic VirtIODevice *vdev = VIRTIO_DEVICE(n); 12416e790746SPaolo Bonzini VirtIONetQueue *q = virtio_net_get_subqueue(nc); 12426e790746SPaolo Bonzini 124317a0ca55SKONRAD Frederic if (!vdev->vm_running) { 12446e790746SPaolo Bonzini return 0; 12456e790746SPaolo Bonzini } 12466e790746SPaolo Bonzini 12476e790746SPaolo Bonzini if (nc->queue_index >= n->curr_queues) { 12486e790746SPaolo Bonzini return 0; 12496e790746SPaolo Bonzini } 12506e790746SPaolo Bonzini 12516e790746SPaolo Bonzini if (!virtio_queue_ready(q->rx_vq) || 125217a0ca55SKONRAD Frederic !(vdev->status & VIRTIO_CONFIG_S_DRIVER_OK)) { 12536e790746SPaolo Bonzini return 0; 12546e790746SPaolo Bonzini } 12556e790746SPaolo Bonzini 12566e790746SPaolo Bonzini return 1; 12576e790746SPaolo Bonzini } 12586e790746SPaolo Bonzini 12596e790746SPaolo Bonzini static int virtio_net_has_buffers(VirtIONetQueue *q, int bufsize) 12606e790746SPaolo Bonzini { 12616e790746SPaolo Bonzini VirtIONet *n = q->n; 12626e790746SPaolo Bonzini if (virtio_queue_empty(q->rx_vq) || 12636e790746SPaolo Bonzini (n->mergeable_rx_bufs && 12646e790746SPaolo Bonzini !virtqueue_avail_bytes(q->rx_vq, bufsize, 0))) { 12656e790746SPaolo Bonzini virtio_queue_set_notification(q->rx_vq, 1); 12666e790746SPaolo Bonzini 12676e790746SPaolo Bonzini /* To avoid a race condition where the guest has made some buffers 12686e790746SPaolo Bonzini * available after the above check but before notification was 12696e790746SPaolo Bonzini * enabled, check for available buffers again. 12706e790746SPaolo Bonzini */ 12716e790746SPaolo Bonzini if (virtio_queue_empty(q->rx_vq) || 12726e790746SPaolo Bonzini (n->mergeable_rx_bufs && 12736e790746SPaolo Bonzini !virtqueue_avail_bytes(q->rx_vq, bufsize, 0))) { 12746e790746SPaolo Bonzini return 0; 12756e790746SPaolo Bonzini } 12766e790746SPaolo Bonzini } 12776e790746SPaolo Bonzini 12786e790746SPaolo Bonzini virtio_queue_set_notification(q->rx_vq, 0); 12796e790746SPaolo Bonzini return 1; 12806e790746SPaolo Bonzini } 12816e790746SPaolo Bonzini 12821399c60dSRusty Russell static void virtio_net_hdr_swap(VirtIODevice *vdev, struct virtio_net_hdr *hdr) 1283032a74a1SCédric Le Goater { 12841399c60dSRusty Russell virtio_tswap16s(vdev, &hdr->hdr_len); 12851399c60dSRusty Russell virtio_tswap16s(vdev, &hdr->gso_size); 12861399c60dSRusty Russell virtio_tswap16s(vdev, &hdr->csum_start); 12871399c60dSRusty Russell virtio_tswap16s(vdev, &hdr->csum_offset); 1288032a74a1SCédric Le Goater } 1289032a74a1SCédric Le Goater 12906e790746SPaolo Bonzini /* dhclient uses AF_PACKET but doesn't pass auxdata to the kernel so 12916e790746SPaolo Bonzini * it never finds out that the packets don't have valid checksums. This 12926e790746SPaolo Bonzini * causes dhclient to get upset. Fedora's carried a patch for ages to 12936e790746SPaolo Bonzini * fix this with Xen but it hasn't appeared in an upstream release of 12946e790746SPaolo Bonzini * dhclient yet. 12956e790746SPaolo Bonzini * 12966e790746SPaolo Bonzini * To avoid breaking existing guests, we catch udp packets and add 12976e790746SPaolo Bonzini * checksums. This is terrible but it's better than hacking the guest 12986e790746SPaolo Bonzini * kernels. 12996e790746SPaolo Bonzini * 13006e790746SPaolo Bonzini * N.B. if we introduce a zero-copy API, this operation is no longer free so 13016e790746SPaolo Bonzini * we should provide a mechanism to disable it to avoid polluting the host 13026e790746SPaolo Bonzini * cache. 13036e790746SPaolo Bonzini */ 13046e790746SPaolo Bonzini static void work_around_broken_dhclient(struct virtio_net_hdr *hdr, 13056e790746SPaolo Bonzini uint8_t *buf, size_t size) 13066e790746SPaolo Bonzini { 13076e790746SPaolo Bonzini if ((hdr->flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) && /* missing csum */ 13086e790746SPaolo Bonzini (size > 27 && size < 1500) && /* normal sized MTU */ 13096e790746SPaolo Bonzini (buf[12] == 0x08 && buf[13] == 0x00) && /* ethertype == IPv4 */ 13106e790746SPaolo Bonzini (buf[23] == 17) && /* ip.protocol == UDP */ 13116e790746SPaolo Bonzini (buf[34] == 0 && buf[35] == 67)) { /* udp.srcport == bootps */ 13126e790746SPaolo Bonzini net_checksum_calculate(buf, size); 13136e790746SPaolo Bonzini hdr->flags &= ~VIRTIO_NET_HDR_F_NEEDS_CSUM; 13146e790746SPaolo Bonzini } 13156e790746SPaolo Bonzini } 13166e790746SPaolo Bonzini 13176e790746SPaolo Bonzini static void receive_header(VirtIONet *n, const struct iovec *iov, int iov_cnt, 13186e790746SPaolo Bonzini const void *buf, size_t size) 13196e790746SPaolo Bonzini { 13206e790746SPaolo Bonzini if (n->has_vnet_hdr) { 13216e790746SPaolo Bonzini /* FIXME this cast is evil */ 13226e790746SPaolo Bonzini void *wbuf = (void *)buf; 13236e790746SPaolo Bonzini work_around_broken_dhclient(wbuf, wbuf + n->host_hdr_len, 13246e790746SPaolo Bonzini size - n->host_hdr_len); 13251bfa316cSGreg Kurz 13261bfa316cSGreg Kurz if (n->needs_vnet_hdr_swap) { 13271399c60dSRusty Russell virtio_net_hdr_swap(VIRTIO_DEVICE(n), wbuf); 13281bfa316cSGreg Kurz } 13296e790746SPaolo Bonzini iov_from_buf(iov, iov_cnt, 0, buf, sizeof(struct virtio_net_hdr)); 13306e790746SPaolo Bonzini } else { 13316e790746SPaolo Bonzini struct virtio_net_hdr hdr = { 13326e790746SPaolo Bonzini .flags = 0, 13336e790746SPaolo Bonzini .gso_type = VIRTIO_NET_HDR_GSO_NONE 13346e790746SPaolo Bonzini }; 13356e790746SPaolo Bonzini iov_from_buf(iov, iov_cnt, 0, &hdr, sizeof hdr); 13366e790746SPaolo Bonzini } 13376e790746SPaolo Bonzini } 13386e790746SPaolo Bonzini 13396e790746SPaolo Bonzini static int receive_filter(VirtIONet *n, const uint8_t *buf, int size) 13406e790746SPaolo Bonzini { 13416e790746SPaolo Bonzini static const uint8_t bcast[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; 13426e790746SPaolo Bonzini static const uint8_t vlan[] = {0x81, 0x00}; 13436e790746SPaolo Bonzini uint8_t *ptr = (uint8_t *)buf; 13446e790746SPaolo Bonzini int i; 13456e790746SPaolo Bonzini 13466e790746SPaolo Bonzini if (n->promisc) 13476e790746SPaolo Bonzini return 1; 13486e790746SPaolo Bonzini 13496e790746SPaolo Bonzini ptr += n->host_hdr_len; 13506e790746SPaolo Bonzini 13516e790746SPaolo Bonzini if (!memcmp(&ptr[12], vlan, sizeof(vlan))) { 13527542d3e7SPeter Maydell int vid = lduw_be_p(ptr + 14) & 0xfff; 13536e790746SPaolo Bonzini if (!(n->vlans[vid >> 5] & (1U << (vid & 0x1f)))) 13546e790746SPaolo Bonzini return 0; 13556e790746SPaolo Bonzini } 13566e790746SPaolo Bonzini 13576e790746SPaolo Bonzini if (ptr[0] & 1) { // multicast 13586e790746SPaolo Bonzini if (!memcmp(ptr, bcast, sizeof(bcast))) { 13596e790746SPaolo Bonzini return !n->nobcast; 13606e790746SPaolo Bonzini } else if (n->nomulti) { 13616e790746SPaolo Bonzini return 0; 13626e790746SPaolo Bonzini } else if (n->allmulti || n->mac_table.multi_overflow) { 13636e790746SPaolo Bonzini return 1; 13646e790746SPaolo Bonzini } 13656e790746SPaolo Bonzini 13666e790746SPaolo Bonzini for (i = n->mac_table.first_multi; i < n->mac_table.in_use; i++) { 13676e790746SPaolo Bonzini if (!memcmp(ptr, &n->mac_table.macs[i * ETH_ALEN], ETH_ALEN)) { 13686e790746SPaolo Bonzini return 1; 13696e790746SPaolo Bonzini } 13706e790746SPaolo Bonzini } 13716e790746SPaolo Bonzini } else { // unicast 13726e790746SPaolo Bonzini if (n->nouni) { 13736e790746SPaolo Bonzini return 0; 13746e790746SPaolo Bonzini } else if (n->alluni || n->mac_table.uni_overflow) { 13756e790746SPaolo Bonzini return 1; 13766e790746SPaolo Bonzini } else if (!memcmp(ptr, n->mac, ETH_ALEN)) { 13776e790746SPaolo Bonzini return 1; 13786e790746SPaolo Bonzini } 13796e790746SPaolo Bonzini 13806e790746SPaolo Bonzini for (i = 0; i < n->mac_table.first_multi; i++) { 13816e790746SPaolo Bonzini if (!memcmp(ptr, &n->mac_table.macs[i * ETH_ALEN], ETH_ALEN)) { 13826e790746SPaolo Bonzini return 1; 13836e790746SPaolo Bonzini } 13846e790746SPaolo Bonzini } 13856e790746SPaolo Bonzini } 13866e790746SPaolo Bonzini 13876e790746SPaolo Bonzini return 0; 13886e790746SPaolo Bonzini } 13896e790746SPaolo Bonzini 139097cd965cSPaolo Bonzini static ssize_t virtio_net_receive_rcu(NetClientState *nc, const uint8_t *buf, 139197cd965cSPaolo Bonzini size_t size) 13926e790746SPaolo Bonzini { 13936e790746SPaolo Bonzini VirtIONet *n = qemu_get_nic_opaque(nc); 13946e790746SPaolo Bonzini VirtIONetQueue *q = virtio_net_get_subqueue(nc); 139517a0ca55SKONRAD Frederic VirtIODevice *vdev = VIRTIO_DEVICE(n); 13966e790746SPaolo Bonzini struct iovec mhdr_sg[VIRTQUEUE_MAX_SIZE]; 13976e790746SPaolo Bonzini struct virtio_net_hdr_mrg_rxbuf mhdr; 13986e790746SPaolo Bonzini unsigned mhdr_cnt = 0; 13996e790746SPaolo Bonzini size_t offset, i, guest_offset; 14006e790746SPaolo Bonzini 14016e790746SPaolo Bonzini if (!virtio_net_can_receive(nc)) { 14026e790746SPaolo Bonzini return -1; 14036e790746SPaolo Bonzini } 14046e790746SPaolo Bonzini 14056e790746SPaolo Bonzini /* hdr_len refers to the header we supply to the guest */ 14066e790746SPaolo Bonzini if (!virtio_net_has_buffers(q, size + n->guest_hdr_len - n->host_hdr_len)) { 14076e790746SPaolo Bonzini return 0; 14086e790746SPaolo Bonzini } 14096e790746SPaolo Bonzini 14106e790746SPaolo Bonzini if (!receive_filter(n, buf, size)) 14116e790746SPaolo Bonzini return size; 14126e790746SPaolo Bonzini 14136e790746SPaolo Bonzini offset = i = 0; 14146e790746SPaolo Bonzini 14156e790746SPaolo Bonzini while (offset < size) { 141651b19ebeSPaolo Bonzini VirtQueueElement *elem; 14176e790746SPaolo Bonzini int len, total; 141851b19ebeSPaolo Bonzini const struct iovec *sg; 14196e790746SPaolo Bonzini 14206e790746SPaolo Bonzini total = 0; 14216e790746SPaolo Bonzini 142251b19ebeSPaolo Bonzini elem = virtqueue_pop(q->rx_vq, sizeof(VirtQueueElement)); 142351b19ebeSPaolo Bonzini if (!elem) { 1424ba10b9c0SGreg Kurz if (i) { 1425ba10b9c0SGreg Kurz virtio_error(vdev, "virtio-net unexpected empty queue: " 14266e790746SPaolo Bonzini "i %zd mergeable %d offset %zd, size %zd, " 1427019a3edbSGerd Hoffmann "guest hdr len %zd, host hdr len %zd " 1428019a3edbSGerd Hoffmann "guest features 0x%" PRIx64, 14296e790746SPaolo Bonzini i, n->mergeable_rx_bufs, offset, size, 1430019a3edbSGerd Hoffmann n->guest_hdr_len, n->host_hdr_len, 1431019a3edbSGerd Hoffmann vdev->guest_features); 1432ba10b9c0SGreg Kurz } 1433ba10b9c0SGreg Kurz return -1; 14346e790746SPaolo Bonzini } 14356e790746SPaolo Bonzini 143651b19ebeSPaolo Bonzini if (elem->in_num < 1) { 1437ba10b9c0SGreg Kurz virtio_error(vdev, 1438ba10b9c0SGreg Kurz "virtio-net receive queue contains no in buffers"); 1439ba10b9c0SGreg Kurz virtqueue_detach_element(q->rx_vq, elem, 0); 1440ba10b9c0SGreg Kurz g_free(elem); 1441ba10b9c0SGreg Kurz return -1; 14426e790746SPaolo Bonzini } 14436e790746SPaolo Bonzini 144451b19ebeSPaolo Bonzini sg = elem->in_sg; 14456e790746SPaolo Bonzini if (i == 0) { 14466e790746SPaolo Bonzini assert(offset == 0); 14476e790746SPaolo Bonzini if (n->mergeable_rx_bufs) { 14486e790746SPaolo Bonzini mhdr_cnt = iov_copy(mhdr_sg, ARRAY_SIZE(mhdr_sg), 144951b19ebeSPaolo Bonzini sg, elem->in_num, 14506e790746SPaolo Bonzini offsetof(typeof(mhdr), num_buffers), 14516e790746SPaolo Bonzini sizeof(mhdr.num_buffers)); 14526e790746SPaolo Bonzini } 14536e790746SPaolo Bonzini 145451b19ebeSPaolo Bonzini receive_header(n, sg, elem->in_num, buf, size); 14556e790746SPaolo Bonzini offset = n->host_hdr_len; 14566e790746SPaolo Bonzini total += n->guest_hdr_len; 14576e790746SPaolo Bonzini guest_offset = n->guest_hdr_len; 14586e790746SPaolo Bonzini } else { 14596e790746SPaolo Bonzini guest_offset = 0; 14606e790746SPaolo Bonzini } 14616e790746SPaolo Bonzini 14626e790746SPaolo Bonzini /* copy in packet. ugh */ 146351b19ebeSPaolo Bonzini len = iov_from_buf(sg, elem->in_num, guest_offset, 14646e790746SPaolo Bonzini buf + offset, size - offset); 14656e790746SPaolo Bonzini total += len; 14666e790746SPaolo Bonzini offset += len; 14676e790746SPaolo Bonzini /* If buffers can't be merged, at this point we 14686e790746SPaolo Bonzini * must have consumed the complete packet. 14696e790746SPaolo Bonzini * Otherwise, drop it. */ 14706e790746SPaolo Bonzini if (!n->mergeable_rx_bufs && offset < size) { 147127e57efeSLadi Prosek virtqueue_unpop(q->rx_vq, elem, total); 147251b19ebeSPaolo Bonzini g_free(elem); 14736e790746SPaolo Bonzini return size; 14746e790746SPaolo Bonzini } 14756e790746SPaolo Bonzini 14766e790746SPaolo Bonzini /* signal other side */ 147751b19ebeSPaolo Bonzini virtqueue_fill(q->rx_vq, elem, total, i++); 147851b19ebeSPaolo Bonzini g_free(elem); 14796e790746SPaolo Bonzini } 14806e790746SPaolo Bonzini 14816e790746SPaolo Bonzini if (mhdr_cnt) { 14821399c60dSRusty Russell virtio_stw_p(vdev, &mhdr.num_buffers, i); 14836e790746SPaolo Bonzini iov_from_buf(mhdr_sg, mhdr_cnt, 14846e790746SPaolo Bonzini 0, 14856e790746SPaolo Bonzini &mhdr.num_buffers, sizeof mhdr.num_buffers); 14866e790746SPaolo Bonzini } 14876e790746SPaolo Bonzini 14886e790746SPaolo Bonzini virtqueue_flush(q->rx_vq, i); 148917a0ca55SKONRAD Frederic virtio_notify(vdev, q->rx_vq); 14906e790746SPaolo Bonzini 14916e790746SPaolo Bonzini return size; 14926e790746SPaolo Bonzini } 14936e790746SPaolo Bonzini 14942974e916SYuri Benditovich static ssize_t virtio_net_do_receive(NetClientState *nc, const uint8_t *buf, 149597cd965cSPaolo Bonzini size_t size) 149697cd965cSPaolo Bonzini { 1497068ddfa9SDr. David Alan Gilbert RCU_READ_LOCK_GUARD(); 149897cd965cSPaolo Bonzini 1499068ddfa9SDr. David Alan Gilbert return virtio_net_receive_rcu(nc, buf, size); 150097cd965cSPaolo Bonzini } 150197cd965cSPaolo Bonzini 15022974e916SYuri Benditovich static void virtio_net_rsc_extract_unit4(VirtioNetRscChain *chain, 15032974e916SYuri Benditovich const uint8_t *buf, 15042974e916SYuri Benditovich VirtioNetRscUnit *unit) 15052974e916SYuri Benditovich { 15062974e916SYuri Benditovich uint16_t ip_hdrlen; 15072974e916SYuri Benditovich struct ip_header *ip; 15082974e916SYuri Benditovich 15092974e916SYuri Benditovich ip = (struct ip_header *)(buf + chain->n->guest_hdr_len 15102974e916SYuri Benditovich + sizeof(struct eth_header)); 15112974e916SYuri Benditovich unit->ip = (void *)ip; 15122974e916SYuri Benditovich ip_hdrlen = (ip->ip_ver_len & 0xF) << 2; 15132974e916SYuri Benditovich unit->ip_plen = &ip->ip_len; 15142974e916SYuri Benditovich unit->tcp = (struct tcp_header *)(((uint8_t *)unit->ip) + ip_hdrlen); 15152974e916SYuri Benditovich unit->tcp_hdrlen = (htons(unit->tcp->th_offset_flags) & 0xF000) >> 10; 15162974e916SYuri Benditovich unit->payload = htons(*unit->ip_plen) - ip_hdrlen - unit->tcp_hdrlen; 15172974e916SYuri Benditovich } 15182974e916SYuri Benditovich 15192974e916SYuri Benditovich static void virtio_net_rsc_extract_unit6(VirtioNetRscChain *chain, 15202974e916SYuri Benditovich const uint8_t *buf, 15212974e916SYuri Benditovich VirtioNetRscUnit *unit) 15222974e916SYuri Benditovich { 15232974e916SYuri Benditovich struct ip6_header *ip6; 15242974e916SYuri Benditovich 15252974e916SYuri Benditovich ip6 = (struct ip6_header *)(buf + chain->n->guest_hdr_len 15262974e916SYuri Benditovich + sizeof(struct eth_header)); 15272974e916SYuri Benditovich unit->ip = ip6; 15282974e916SYuri Benditovich unit->ip_plen = &(ip6->ip6_ctlun.ip6_un1.ip6_un1_plen); 15292974e916SYuri Benditovich unit->tcp = (struct tcp_header *)(((uint8_t *)unit->ip)\ 15302974e916SYuri Benditovich + sizeof(struct ip6_header)); 15312974e916SYuri Benditovich unit->tcp_hdrlen = (htons(unit->tcp->th_offset_flags) & 0xF000) >> 10; 15322974e916SYuri Benditovich 15332974e916SYuri Benditovich /* There is a difference between payload lenght in ipv4 and v6, 15342974e916SYuri Benditovich ip header is excluded in ipv6 */ 15352974e916SYuri Benditovich unit->payload = htons(*unit->ip_plen) - unit->tcp_hdrlen; 15362974e916SYuri Benditovich } 15372974e916SYuri Benditovich 15382974e916SYuri Benditovich static size_t virtio_net_rsc_drain_seg(VirtioNetRscChain *chain, 15392974e916SYuri Benditovich VirtioNetRscSeg *seg) 15402974e916SYuri Benditovich { 15412974e916SYuri Benditovich int ret; 15422974e916SYuri Benditovich struct virtio_net_hdr *h; 15432974e916SYuri Benditovich 15442974e916SYuri Benditovich h = (struct virtio_net_hdr *)seg->buf; 15452974e916SYuri Benditovich h->flags = 0; 15462974e916SYuri Benditovich h->gso_type = VIRTIO_NET_HDR_GSO_NONE; 15472974e916SYuri Benditovich 15482974e916SYuri Benditovich if (seg->is_coalesced) { 15492974e916SYuri Benditovich *virtio_net_rsc_ext_num_packets(h) = seg->packets; 15502974e916SYuri Benditovich *virtio_net_rsc_ext_num_dupacks(h) = seg->dup_ack; 15512974e916SYuri Benditovich h->flags = VIRTIO_NET_HDR_F_RSC_INFO; 15522974e916SYuri Benditovich if (chain->proto == ETH_P_IP) { 15532974e916SYuri Benditovich h->gso_type = VIRTIO_NET_HDR_GSO_TCPV4; 15542974e916SYuri Benditovich } else { 15552974e916SYuri Benditovich h->gso_type = VIRTIO_NET_HDR_GSO_TCPV6; 15562974e916SYuri Benditovich } 15572974e916SYuri Benditovich } 15582974e916SYuri Benditovich 15592974e916SYuri Benditovich ret = virtio_net_do_receive(seg->nc, seg->buf, seg->size); 15602974e916SYuri Benditovich QTAILQ_REMOVE(&chain->buffers, seg, next); 15612974e916SYuri Benditovich g_free(seg->buf); 15622974e916SYuri Benditovich g_free(seg); 15632974e916SYuri Benditovich 15642974e916SYuri Benditovich return ret; 15652974e916SYuri Benditovich } 15662974e916SYuri Benditovich 15672974e916SYuri Benditovich static void virtio_net_rsc_purge(void *opq) 15682974e916SYuri Benditovich { 15692974e916SYuri Benditovich VirtioNetRscSeg *seg, *rn; 15702974e916SYuri Benditovich VirtioNetRscChain *chain = (VirtioNetRscChain *)opq; 15712974e916SYuri Benditovich 15722974e916SYuri Benditovich QTAILQ_FOREACH_SAFE(seg, &chain->buffers, next, rn) { 15732974e916SYuri Benditovich if (virtio_net_rsc_drain_seg(chain, seg) == 0) { 15742974e916SYuri Benditovich chain->stat.purge_failed++; 15752974e916SYuri Benditovich continue; 15762974e916SYuri Benditovich } 15772974e916SYuri Benditovich } 15782974e916SYuri Benditovich 15792974e916SYuri Benditovich chain->stat.timer++; 15802974e916SYuri Benditovich if (!QTAILQ_EMPTY(&chain->buffers)) { 15812974e916SYuri Benditovich timer_mod(chain->drain_timer, 15822974e916SYuri Benditovich qemu_clock_get_ns(QEMU_CLOCK_HOST) + chain->n->rsc_timeout); 15832974e916SYuri Benditovich } 15842974e916SYuri Benditovich } 15852974e916SYuri Benditovich 15862974e916SYuri Benditovich static void virtio_net_rsc_cleanup(VirtIONet *n) 15872974e916SYuri Benditovich { 15882974e916SYuri Benditovich VirtioNetRscChain *chain, *rn_chain; 15892974e916SYuri Benditovich VirtioNetRscSeg *seg, *rn_seg; 15902974e916SYuri Benditovich 15912974e916SYuri Benditovich QTAILQ_FOREACH_SAFE(chain, &n->rsc_chains, next, rn_chain) { 15922974e916SYuri Benditovich QTAILQ_FOREACH_SAFE(seg, &chain->buffers, next, rn_seg) { 15932974e916SYuri Benditovich QTAILQ_REMOVE(&chain->buffers, seg, next); 15942974e916SYuri Benditovich g_free(seg->buf); 15952974e916SYuri Benditovich g_free(seg); 15962974e916SYuri Benditovich } 15972974e916SYuri Benditovich 15982974e916SYuri Benditovich timer_del(chain->drain_timer); 15992974e916SYuri Benditovich timer_free(chain->drain_timer); 16002974e916SYuri Benditovich QTAILQ_REMOVE(&n->rsc_chains, chain, next); 16012974e916SYuri Benditovich g_free(chain); 16022974e916SYuri Benditovich } 16032974e916SYuri Benditovich } 16042974e916SYuri Benditovich 16052974e916SYuri Benditovich static void virtio_net_rsc_cache_buf(VirtioNetRscChain *chain, 16062974e916SYuri Benditovich NetClientState *nc, 16072974e916SYuri Benditovich const uint8_t *buf, size_t size) 16082974e916SYuri Benditovich { 16092974e916SYuri Benditovich uint16_t hdr_len; 16102974e916SYuri Benditovich VirtioNetRscSeg *seg; 16112974e916SYuri Benditovich 16122974e916SYuri Benditovich hdr_len = chain->n->guest_hdr_len; 16132974e916SYuri Benditovich seg = g_malloc(sizeof(VirtioNetRscSeg)); 16142974e916SYuri Benditovich seg->buf = g_malloc(hdr_len + sizeof(struct eth_header) 16152974e916SYuri Benditovich + sizeof(struct ip6_header) + VIRTIO_NET_MAX_TCP_PAYLOAD); 16162974e916SYuri Benditovich memcpy(seg->buf, buf, size); 16172974e916SYuri Benditovich seg->size = size; 16182974e916SYuri Benditovich seg->packets = 1; 16192974e916SYuri Benditovich seg->dup_ack = 0; 16202974e916SYuri Benditovich seg->is_coalesced = 0; 16212974e916SYuri Benditovich seg->nc = nc; 16222974e916SYuri Benditovich 16232974e916SYuri Benditovich QTAILQ_INSERT_TAIL(&chain->buffers, seg, next); 16242974e916SYuri Benditovich chain->stat.cache++; 16252974e916SYuri Benditovich 16262974e916SYuri Benditovich switch (chain->proto) { 16272974e916SYuri Benditovich case ETH_P_IP: 16282974e916SYuri Benditovich virtio_net_rsc_extract_unit4(chain, seg->buf, &seg->unit); 16292974e916SYuri Benditovich break; 16302974e916SYuri Benditovich case ETH_P_IPV6: 16312974e916SYuri Benditovich virtio_net_rsc_extract_unit6(chain, seg->buf, &seg->unit); 16322974e916SYuri Benditovich break; 16332974e916SYuri Benditovich default: 16342974e916SYuri Benditovich g_assert_not_reached(); 16352974e916SYuri Benditovich } 16362974e916SYuri Benditovich } 16372974e916SYuri Benditovich 16382974e916SYuri Benditovich static int32_t virtio_net_rsc_handle_ack(VirtioNetRscChain *chain, 16392974e916SYuri Benditovich VirtioNetRscSeg *seg, 16402974e916SYuri Benditovich const uint8_t *buf, 16412974e916SYuri Benditovich struct tcp_header *n_tcp, 16422974e916SYuri Benditovich struct tcp_header *o_tcp) 16432974e916SYuri Benditovich { 16442974e916SYuri Benditovich uint32_t nack, oack; 16452974e916SYuri Benditovich uint16_t nwin, owin; 16462974e916SYuri Benditovich 16472974e916SYuri Benditovich nack = htonl(n_tcp->th_ack); 16482974e916SYuri Benditovich nwin = htons(n_tcp->th_win); 16492974e916SYuri Benditovich oack = htonl(o_tcp->th_ack); 16502974e916SYuri Benditovich owin = htons(o_tcp->th_win); 16512974e916SYuri Benditovich 16522974e916SYuri Benditovich if ((nack - oack) >= VIRTIO_NET_MAX_TCP_PAYLOAD) { 16532974e916SYuri Benditovich chain->stat.ack_out_of_win++; 16542974e916SYuri Benditovich return RSC_FINAL; 16552974e916SYuri Benditovich } else if (nack == oack) { 16562974e916SYuri Benditovich /* duplicated ack or window probe */ 16572974e916SYuri Benditovich if (nwin == owin) { 16582974e916SYuri Benditovich /* duplicated ack, add dup ack count due to whql test up to 1 */ 16592974e916SYuri Benditovich chain->stat.dup_ack++; 16602974e916SYuri Benditovich return RSC_FINAL; 16612974e916SYuri Benditovich } else { 16622974e916SYuri Benditovich /* Coalesce window update */ 16632974e916SYuri Benditovich o_tcp->th_win = n_tcp->th_win; 16642974e916SYuri Benditovich chain->stat.win_update++; 16652974e916SYuri Benditovich return RSC_COALESCE; 16662974e916SYuri Benditovich } 16672974e916SYuri Benditovich } else { 16682974e916SYuri Benditovich /* pure ack, go to 'C', finalize*/ 16692974e916SYuri Benditovich chain->stat.pure_ack++; 16702974e916SYuri Benditovich return RSC_FINAL; 16712974e916SYuri Benditovich } 16722974e916SYuri Benditovich } 16732974e916SYuri Benditovich 16742974e916SYuri Benditovich static int32_t virtio_net_rsc_coalesce_data(VirtioNetRscChain *chain, 16752974e916SYuri Benditovich VirtioNetRscSeg *seg, 16762974e916SYuri Benditovich const uint8_t *buf, 16772974e916SYuri Benditovich VirtioNetRscUnit *n_unit) 16782974e916SYuri Benditovich { 16792974e916SYuri Benditovich void *data; 16802974e916SYuri Benditovich uint16_t o_ip_len; 16812974e916SYuri Benditovich uint32_t nseq, oseq; 16822974e916SYuri Benditovich VirtioNetRscUnit *o_unit; 16832974e916SYuri Benditovich 16842974e916SYuri Benditovich o_unit = &seg->unit; 16852974e916SYuri Benditovich o_ip_len = htons(*o_unit->ip_plen); 16862974e916SYuri Benditovich nseq = htonl(n_unit->tcp->th_seq); 16872974e916SYuri Benditovich oseq = htonl(o_unit->tcp->th_seq); 16882974e916SYuri Benditovich 16892974e916SYuri Benditovich /* out of order or retransmitted. */ 16902974e916SYuri Benditovich if ((nseq - oseq) > VIRTIO_NET_MAX_TCP_PAYLOAD) { 16912974e916SYuri Benditovich chain->stat.data_out_of_win++; 16922974e916SYuri Benditovich return RSC_FINAL; 16932974e916SYuri Benditovich } 16942974e916SYuri Benditovich 16952974e916SYuri Benditovich data = ((uint8_t *)n_unit->tcp) + n_unit->tcp_hdrlen; 16962974e916SYuri Benditovich if (nseq == oseq) { 16972974e916SYuri Benditovich if ((o_unit->payload == 0) && n_unit->payload) { 16982974e916SYuri Benditovich /* From no payload to payload, normal case, not a dup ack or etc */ 16992974e916SYuri Benditovich chain->stat.data_after_pure_ack++; 17002974e916SYuri Benditovich goto coalesce; 17012974e916SYuri Benditovich } else { 17022974e916SYuri Benditovich return virtio_net_rsc_handle_ack(chain, seg, buf, 17032974e916SYuri Benditovich n_unit->tcp, o_unit->tcp); 17042974e916SYuri Benditovich } 17052974e916SYuri Benditovich } else if ((nseq - oseq) != o_unit->payload) { 17062974e916SYuri Benditovich /* Not a consistent packet, out of order */ 17072974e916SYuri Benditovich chain->stat.data_out_of_order++; 17082974e916SYuri Benditovich return RSC_FINAL; 17092974e916SYuri Benditovich } else { 17102974e916SYuri Benditovich coalesce: 17112974e916SYuri Benditovich if ((o_ip_len + n_unit->payload) > chain->max_payload) { 17122974e916SYuri Benditovich chain->stat.over_size++; 17132974e916SYuri Benditovich return RSC_FINAL; 17142974e916SYuri Benditovich } 17152974e916SYuri Benditovich 17162974e916SYuri Benditovich /* Here comes the right data, the payload length in v4/v6 is different, 17172974e916SYuri Benditovich so use the field value to update and record the new data len */ 17182974e916SYuri Benditovich o_unit->payload += n_unit->payload; /* update new data len */ 17192974e916SYuri Benditovich 17202974e916SYuri Benditovich /* update field in ip header */ 17212974e916SYuri Benditovich *o_unit->ip_plen = htons(o_ip_len + n_unit->payload); 17222974e916SYuri Benditovich 17232974e916SYuri Benditovich /* Bring 'PUSH' big, the whql test guide says 'PUSH' can be coalesced 17242974e916SYuri Benditovich for windows guest, while this may change the behavior for linux 17252974e916SYuri Benditovich guest (only if it uses RSC feature). */ 17262974e916SYuri Benditovich o_unit->tcp->th_offset_flags = n_unit->tcp->th_offset_flags; 17272974e916SYuri Benditovich 17282974e916SYuri Benditovich o_unit->tcp->th_ack = n_unit->tcp->th_ack; 17292974e916SYuri Benditovich o_unit->tcp->th_win = n_unit->tcp->th_win; 17302974e916SYuri Benditovich 17312974e916SYuri Benditovich memmove(seg->buf + seg->size, data, n_unit->payload); 17322974e916SYuri Benditovich seg->size += n_unit->payload; 17332974e916SYuri Benditovich seg->packets++; 17342974e916SYuri Benditovich chain->stat.coalesced++; 17352974e916SYuri Benditovich return RSC_COALESCE; 17362974e916SYuri Benditovich } 17372974e916SYuri Benditovich } 17382974e916SYuri Benditovich 17392974e916SYuri Benditovich static int32_t virtio_net_rsc_coalesce4(VirtioNetRscChain *chain, 17402974e916SYuri Benditovich VirtioNetRscSeg *seg, 17412974e916SYuri Benditovich const uint8_t *buf, size_t size, 17422974e916SYuri Benditovich VirtioNetRscUnit *unit) 17432974e916SYuri Benditovich { 17442974e916SYuri Benditovich struct ip_header *ip1, *ip2; 17452974e916SYuri Benditovich 17462974e916SYuri Benditovich ip1 = (struct ip_header *)(unit->ip); 17472974e916SYuri Benditovich ip2 = (struct ip_header *)(seg->unit.ip); 17482974e916SYuri Benditovich if ((ip1->ip_src ^ ip2->ip_src) || (ip1->ip_dst ^ ip2->ip_dst) 17492974e916SYuri Benditovich || (unit->tcp->th_sport ^ seg->unit.tcp->th_sport) 17502974e916SYuri Benditovich || (unit->tcp->th_dport ^ seg->unit.tcp->th_dport)) { 17512974e916SYuri Benditovich chain->stat.no_match++; 17522974e916SYuri Benditovich return RSC_NO_MATCH; 17532974e916SYuri Benditovich } 17542974e916SYuri Benditovich 17552974e916SYuri Benditovich return virtio_net_rsc_coalesce_data(chain, seg, buf, unit); 17562974e916SYuri Benditovich } 17572974e916SYuri Benditovich 17582974e916SYuri Benditovich static int32_t virtio_net_rsc_coalesce6(VirtioNetRscChain *chain, 17592974e916SYuri Benditovich VirtioNetRscSeg *seg, 17602974e916SYuri Benditovich const uint8_t *buf, size_t size, 17612974e916SYuri Benditovich VirtioNetRscUnit *unit) 17622974e916SYuri Benditovich { 17632974e916SYuri Benditovich struct ip6_header *ip1, *ip2; 17642974e916SYuri Benditovich 17652974e916SYuri Benditovich ip1 = (struct ip6_header *)(unit->ip); 17662974e916SYuri Benditovich ip2 = (struct ip6_header *)(seg->unit.ip); 17672974e916SYuri Benditovich if (memcmp(&ip1->ip6_src, &ip2->ip6_src, sizeof(struct in6_address)) 17682974e916SYuri Benditovich || memcmp(&ip1->ip6_dst, &ip2->ip6_dst, sizeof(struct in6_address)) 17692974e916SYuri Benditovich || (unit->tcp->th_sport ^ seg->unit.tcp->th_sport) 17702974e916SYuri Benditovich || (unit->tcp->th_dport ^ seg->unit.tcp->th_dport)) { 17712974e916SYuri Benditovich chain->stat.no_match++; 17722974e916SYuri Benditovich return RSC_NO_MATCH; 17732974e916SYuri Benditovich } 17742974e916SYuri Benditovich 17752974e916SYuri Benditovich return virtio_net_rsc_coalesce_data(chain, seg, buf, unit); 17762974e916SYuri Benditovich } 17772974e916SYuri Benditovich 17782974e916SYuri Benditovich /* Packets with 'SYN' should bypass, other flag should be sent after drain 17792974e916SYuri Benditovich * to prevent out of order */ 17802974e916SYuri Benditovich static int virtio_net_rsc_tcp_ctrl_check(VirtioNetRscChain *chain, 17812974e916SYuri Benditovich struct tcp_header *tcp) 17822974e916SYuri Benditovich { 17832974e916SYuri Benditovich uint16_t tcp_hdr; 17842974e916SYuri Benditovich uint16_t tcp_flag; 17852974e916SYuri Benditovich 17862974e916SYuri Benditovich tcp_flag = htons(tcp->th_offset_flags); 17872974e916SYuri Benditovich tcp_hdr = (tcp_flag & VIRTIO_NET_TCP_HDR_LENGTH) >> 10; 17882974e916SYuri Benditovich tcp_flag &= VIRTIO_NET_TCP_FLAG; 17892974e916SYuri Benditovich tcp_flag = htons(tcp->th_offset_flags) & 0x3F; 17902974e916SYuri Benditovich if (tcp_flag & TH_SYN) { 17912974e916SYuri Benditovich chain->stat.tcp_syn++; 17922974e916SYuri Benditovich return RSC_BYPASS; 17932974e916SYuri Benditovich } 17942974e916SYuri Benditovich 17952974e916SYuri Benditovich if (tcp_flag & (TH_FIN | TH_URG | TH_RST | TH_ECE | TH_CWR)) { 17962974e916SYuri Benditovich chain->stat.tcp_ctrl_drain++; 17972974e916SYuri Benditovich return RSC_FINAL; 17982974e916SYuri Benditovich } 17992974e916SYuri Benditovich 18002974e916SYuri Benditovich if (tcp_hdr > sizeof(struct tcp_header)) { 18012974e916SYuri Benditovich chain->stat.tcp_all_opt++; 18022974e916SYuri Benditovich return RSC_FINAL; 18032974e916SYuri Benditovich } 18042974e916SYuri Benditovich 18052974e916SYuri Benditovich return RSC_CANDIDATE; 18062974e916SYuri Benditovich } 18072974e916SYuri Benditovich 18082974e916SYuri Benditovich static size_t virtio_net_rsc_do_coalesce(VirtioNetRscChain *chain, 18092974e916SYuri Benditovich NetClientState *nc, 18102974e916SYuri Benditovich const uint8_t *buf, size_t size, 18112974e916SYuri Benditovich VirtioNetRscUnit *unit) 18122974e916SYuri Benditovich { 18132974e916SYuri Benditovich int ret; 18142974e916SYuri Benditovich VirtioNetRscSeg *seg, *nseg; 18152974e916SYuri Benditovich 18162974e916SYuri Benditovich if (QTAILQ_EMPTY(&chain->buffers)) { 18172974e916SYuri Benditovich chain->stat.empty_cache++; 18182974e916SYuri Benditovich virtio_net_rsc_cache_buf(chain, nc, buf, size); 18192974e916SYuri Benditovich timer_mod(chain->drain_timer, 18202974e916SYuri Benditovich qemu_clock_get_ns(QEMU_CLOCK_HOST) + chain->n->rsc_timeout); 18212974e916SYuri Benditovich return size; 18222974e916SYuri Benditovich } 18232974e916SYuri Benditovich 18242974e916SYuri Benditovich QTAILQ_FOREACH_SAFE(seg, &chain->buffers, next, nseg) { 18252974e916SYuri Benditovich if (chain->proto == ETH_P_IP) { 18262974e916SYuri Benditovich ret = virtio_net_rsc_coalesce4(chain, seg, buf, size, unit); 18272974e916SYuri Benditovich } else { 18282974e916SYuri Benditovich ret = virtio_net_rsc_coalesce6(chain, seg, buf, size, unit); 18292974e916SYuri Benditovich } 18302974e916SYuri Benditovich 18312974e916SYuri Benditovich if (ret == RSC_FINAL) { 18322974e916SYuri Benditovich if (virtio_net_rsc_drain_seg(chain, seg) == 0) { 18332974e916SYuri Benditovich /* Send failed */ 18342974e916SYuri Benditovich chain->stat.final_failed++; 18352974e916SYuri Benditovich return 0; 18362974e916SYuri Benditovich } 18372974e916SYuri Benditovich 18382974e916SYuri Benditovich /* Send current packet */ 18392974e916SYuri Benditovich return virtio_net_do_receive(nc, buf, size); 18402974e916SYuri Benditovich } else if (ret == RSC_NO_MATCH) { 18412974e916SYuri Benditovich continue; 18422974e916SYuri Benditovich } else { 18432974e916SYuri Benditovich /* Coalesced, mark coalesced flag to tell calc cksum for ipv4 */ 18442974e916SYuri Benditovich seg->is_coalesced = 1; 18452974e916SYuri Benditovich return size; 18462974e916SYuri Benditovich } 18472974e916SYuri Benditovich } 18482974e916SYuri Benditovich 18492974e916SYuri Benditovich chain->stat.no_match_cache++; 18502974e916SYuri Benditovich virtio_net_rsc_cache_buf(chain, nc, buf, size); 18512974e916SYuri Benditovich return size; 18522974e916SYuri Benditovich } 18532974e916SYuri Benditovich 18542974e916SYuri Benditovich /* Drain a connection data, this is to avoid out of order segments */ 18552974e916SYuri Benditovich static size_t virtio_net_rsc_drain_flow(VirtioNetRscChain *chain, 18562974e916SYuri Benditovich NetClientState *nc, 18572974e916SYuri Benditovich const uint8_t *buf, size_t size, 18582974e916SYuri Benditovich uint16_t ip_start, uint16_t ip_size, 18592974e916SYuri Benditovich uint16_t tcp_port) 18602974e916SYuri Benditovich { 18612974e916SYuri Benditovich VirtioNetRscSeg *seg, *nseg; 18622974e916SYuri Benditovich uint32_t ppair1, ppair2; 18632974e916SYuri Benditovich 18642974e916SYuri Benditovich ppair1 = *(uint32_t *)(buf + tcp_port); 18652974e916SYuri Benditovich QTAILQ_FOREACH_SAFE(seg, &chain->buffers, next, nseg) { 18662974e916SYuri Benditovich ppair2 = *(uint32_t *)(seg->buf + tcp_port); 18672974e916SYuri Benditovich if (memcmp(buf + ip_start, seg->buf + ip_start, ip_size) 18682974e916SYuri Benditovich || (ppair1 != ppair2)) { 18692974e916SYuri Benditovich continue; 18702974e916SYuri Benditovich } 18712974e916SYuri Benditovich if (virtio_net_rsc_drain_seg(chain, seg) == 0) { 18722974e916SYuri Benditovich chain->stat.drain_failed++; 18732974e916SYuri Benditovich } 18742974e916SYuri Benditovich 18752974e916SYuri Benditovich break; 18762974e916SYuri Benditovich } 18772974e916SYuri Benditovich 18782974e916SYuri Benditovich return virtio_net_do_receive(nc, buf, size); 18792974e916SYuri Benditovich } 18802974e916SYuri Benditovich 18812974e916SYuri Benditovich static int32_t virtio_net_rsc_sanity_check4(VirtioNetRscChain *chain, 18822974e916SYuri Benditovich struct ip_header *ip, 18832974e916SYuri Benditovich const uint8_t *buf, size_t size) 18842974e916SYuri Benditovich { 18852974e916SYuri Benditovich uint16_t ip_len; 18862974e916SYuri Benditovich 18872974e916SYuri Benditovich /* Not an ipv4 packet */ 18882974e916SYuri Benditovich if (((ip->ip_ver_len & 0xF0) >> 4) != IP_HEADER_VERSION_4) { 18892974e916SYuri Benditovich chain->stat.ip_option++; 18902974e916SYuri Benditovich return RSC_BYPASS; 18912974e916SYuri Benditovich } 18922974e916SYuri Benditovich 18932974e916SYuri Benditovich /* Don't handle packets with ip option */ 18942974e916SYuri Benditovich if ((ip->ip_ver_len & 0xF) != VIRTIO_NET_IP4_HEADER_LENGTH) { 18952974e916SYuri Benditovich chain->stat.ip_option++; 18962974e916SYuri Benditovich return RSC_BYPASS; 18972974e916SYuri Benditovich } 18982974e916SYuri Benditovich 18992974e916SYuri Benditovich if (ip->ip_p != IPPROTO_TCP) { 19002974e916SYuri Benditovich chain->stat.bypass_not_tcp++; 19012974e916SYuri Benditovich return RSC_BYPASS; 19022974e916SYuri Benditovich } 19032974e916SYuri Benditovich 19042974e916SYuri Benditovich /* Don't handle packets with ip fragment */ 19052974e916SYuri Benditovich if (!(htons(ip->ip_off) & IP_DF)) { 19062974e916SYuri Benditovich chain->stat.ip_frag++; 19072974e916SYuri Benditovich return RSC_BYPASS; 19082974e916SYuri Benditovich } 19092974e916SYuri Benditovich 19102974e916SYuri Benditovich /* Don't handle packets with ecn flag */ 19112974e916SYuri Benditovich if (IPTOS_ECN(ip->ip_tos)) { 19122974e916SYuri Benditovich chain->stat.ip_ecn++; 19132974e916SYuri Benditovich return RSC_BYPASS; 19142974e916SYuri Benditovich } 19152974e916SYuri Benditovich 19162974e916SYuri Benditovich ip_len = htons(ip->ip_len); 19172974e916SYuri Benditovich if (ip_len < (sizeof(struct ip_header) + sizeof(struct tcp_header)) 19182974e916SYuri Benditovich || ip_len > (size - chain->n->guest_hdr_len - 19192974e916SYuri Benditovich sizeof(struct eth_header))) { 19202974e916SYuri Benditovich chain->stat.ip_hacked++; 19212974e916SYuri Benditovich return RSC_BYPASS; 19222974e916SYuri Benditovich } 19232974e916SYuri Benditovich 19242974e916SYuri Benditovich return RSC_CANDIDATE; 19252974e916SYuri Benditovich } 19262974e916SYuri Benditovich 19272974e916SYuri Benditovich static size_t virtio_net_rsc_receive4(VirtioNetRscChain *chain, 19282974e916SYuri Benditovich NetClientState *nc, 19292974e916SYuri Benditovich const uint8_t *buf, size_t size) 19302974e916SYuri Benditovich { 19312974e916SYuri Benditovich int32_t ret; 19322974e916SYuri Benditovich uint16_t hdr_len; 19332974e916SYuri Benditovich VirtioNetRscUnit unit; 19342974e916SYuri Benditovich 19352974e916SYuri Benditovich hdr_len = ((VirtIONet *)(chain->n))->guest_hdr_len; 19362974e916SYuri Benditovich 19372974e916SYuri Benditovich if (size < (hdr_len + sizeof(struct eth_header) + sizeof(struct ip_header) 19382974e916SYuri Benditovich + sizeof(struct tcp_header))) { 19392974e916SYuri Benditovich chain->stat.bypass_not_tcp++; 19402974e916SYuri Benditovich return virtio_net_do_receive(nc, buf, size); 19412974e916SYuri Benditovich } 19422974e916SYuri Benditovich 19432974e916SYuri Benditovich virtio_net_rsc_extract_unit4(chain, buf, &unit); 19442974e916SYuri Benditovich if (virtio_net_rsc_sanity_check4(chain, unit.ip, buf, size) 19452974e916SYuri Benditovich != RSC_CANDIDATE) { 19462974e916SYuri Benditovich return virtio_net_do_receive(nc, buf, size); 19472974e916SYuri Benditovich } 19482974e916SYuri Benditovich 19492974e916SYuri Benditovich ret = virtio_net_rsc_tcp_ctrl_check(chain, unit.tcp); 19502974e916SYuri Benditovich if (ret == RSC_BYPASS) { 19512974e916SYuri Benditovich return virtio_net_do_receive(nc, buf, size); 19522974e916SYuri Benditovich } else if (ret == RSC_FINAL) { 19532974e916SYuri Benditovich return virtio_net_rsc_drain_flow(chain, nc, buf, size, 19542974e916SYuri Benditovich ((hdr_len + sizeof(struct eth_header)) + 12), 19552974e916SYuri Benditovich VIRTIO_NET_IP4_ADDR_SIZE, 19562974e916SYuri Benditovich hdr_len + sizeof(struct eth_header) + sizeof(struct ip_header)); 19572974e916SYuri Benditovich } 19582974e916SYuri Benditovich 19592974e916SYuri Benditovich return virtio_net_rsc_do_coalesce(chain, nc, buf, size, &unit); 19602974e916SYuri Benditovich } 19612974e916SYuri Benditovich 19622974e916SYuri Benditovich static int32_t virtio_net_rsc_sanity_check6(VirtioNetRscChain *chain, 19632974e916SYuri Benditovich struct ip6_header *ip6, 19642974e916SYuri Benditovich const uint8_t *buf, size_t size) 19652974e916SYuri Benditovich { 19662974e916SYuri Benditovich uint16_t ip_len; 19672974e916SYuri Benditovich 19682974e916SYuri Benditovich if (((ip6->ip6_ctlun.ip6_un1.ip6_un1_flow & 0xF0) >> 4) 19692974e916SYuri Benditovich != IP_HEADER_VERSION_6) { 19702974e916SYuri Benditovich return RSC_BYPASS; 19712974e916SYuri Benditovich } 19722974e916SYuri Benditovich 19732974e916SYuri Benditovich /* Both option and protocol is checked in this */ 19742974e916SYuri Benditovich if (ip6->ip6_ctlun.ip6_un1.ip6_un1_nxt != IPPROTO_TCP) { 19752974e916SYuri Benditovich chain->stat.bypass_not_tcp++; 19762974e916SYuri Benditovich return RSC_BYPASS; 19772974e916SYuri Benditovich } 19782974e916SYuri Benditovich 19792974e916SYuri Benditovich ip_len = htons(ip6->ip6_ctlun.ip6_un1.ip6_un1_plen); 19802974e916SYuri Benditovich if (ip_len < sizeof(struct tcp_header) || 19812974e916SYuri Benditovich ip_len > (size - chain->n->guest_hdr_len - sizeof(struct eth_header) 19822974e916SYuri Benditovich - sizeof(struct ip6_header))) { 19832974e916SYuri Benditovich chain->stat.ip_hacked++; 19842974e916SYuri Benditovich return RSC_BYPASS; 19852974e916SYuri Benditovich } 19862974e916SYuri Benditovich 19872974e916SYuri Benditovich /* Don't handle packets with ecn flag */ 19882974e916SYuri Benditovich if (IP6_ECN(ip6->ip6_ctlun.ip6_un3.ip6_un3_ecn)) { 19892974e916SYuri Benditovich chain->stat.ip_ecn++; 19902974e916SYuri Benditovich return RSC_BYPASS; 19912974e916SYuri Benditovich } 19922974e916SYuri Benditovich 19932974e916SYuri Benditovich return RSC_CANDIDATE; 19942974e916SYuri Benditovich } 19952974e916SYuri Benditovich 19962974e916SYuri Benditovich static size_t virtio_net_rsc_receive6(void *opq, NetClientState *nc, 19972974e916SYuri Benditovich const uint8_t *buf, size_t size) 19982974e916SYuri Benditovich { 19992974e916SYuri Benditovich int32_t ret; 20002974e916SYuri Benditovich uint16_t hdr_len; 20012974e916SYuri Benditovich VirtioNetRscChain *chain; 20022974e916SYuri Benditovich VirtioNetRscUnit unit; 20032974e916SYuri Benditovich 20042974e916SYuri Benditovich chain = (VirtioNetRscChain *)opq; 20052974e916SYuri Benditovich hdr_len = ((VirtIONet *)(chain->n))->guest_hdr_len; 20062974e916SYuri Benditovich 20072974e916SYuri Benditovich if (size < (hdr_len + sizeof(struct eth_header) + sizeof(struct ip6_header) 20082974e916SYuri Benditovich + sizeof(tcp_header))) { 20092974e916SYuri Benditovich return virtio_net_do_receive(nc, buf, size); 20102974e916SYuri Benditovich } 20112974e916SYuri Benditovich 20122974e916SYuri Benditovich virtio_net_rsc_extract_unit6(chain, buf, &unit); 20132974e916SYuri Benditovich if (RSC_CANDIDATE != virtio_net_rsc_sanity_check6(chain, 20142974e916SYuri Benditovich unit.ip, buf, size)) { 20152974e916SYuri Benditovich return virtio_net_do_receive(nc, buf, size); 20162974e916SYuri Benditovich } 20172974e916SYuri Benditovich 20182974e916SYuri Benditovich ret = virtio_net_rsc_tcp_ctrl_check(chain, unit.tcp); 20192974e916SYuri Benditovich if (ret == RSC_BYPASS) { 20202974e916SYuri Benditovich return virtio_net_do_receive(nc, buf, size); 20212974e916SYuri Benditovich } else if (ret == RSC_FINAL) { 20222974e916SYuri Benditovich return virtio_net_rsc_drain_flow(chain, nc, buf, size, 20232974e916SYuri Benditovich ((hdr_len + sizeof(struct eth_header)) + 8), 20242974e916SYuri Benditovich VIRTIO_NET_IP6_ADDR_SIZE, 20252974e916SYuri Benditovich hdr_len + sizeof(struct eth_header) 20262974e916SYuri Benditovich + sizeof(struct ip6_header)); 20272974e916SYuri Benditovich } 20282974e916SYuri Benditovich 20292974e916SYuri Benditovich return virtio_net_rsc_do_coalesce(chain, nc, buf, size, &unit); 20302974e916SYuri Benditovich } 20312974e916SYuri Benditovich 20322974e916SYuri Benditovich static VirtioNetRscChain *virtio_net_rsc_lookup_chain(VirtIONet *n, 20332974e916SYuri Benditovich NetClientState *nc, 20342974e916SYuri Benditovich uint16_t proto) 20352974e916SYuri Benditovich { 20362974e916SYuri Benditovich VirtioNetRscChain *chain; 20372974e916SYuri Benditovich 20382974e916SYuri Benditovich if ((proto != (uint16_t)ETH_P_IP) && (proto != (uint16_t)ETH_P_IPV6)) { 20392974e916SYuri Benditovich return NULL; 20402974e916SYuri Benditovich } 20412974e916SYuri Benditovich 20422974e916SYuri Benditovich QTAILQ_FOREACH(chain, &n->rsc_chains, next) { 20432974e916SYuri Benditovich if (chain->proto == proto) { 20442974e916SYuri Benditovich return chain; 20452974e916SYuri Benditovich } 20462974e916SYuri Benditovich } 20472974e916SYuri Benditovich 20482974e916SYuri Benditovich chain = g_malloc(sizeof(*chain)); 20492974e916SYuri Benditovich chain->n = n; 20502974e916SYuri Benditovich chain->proto = proto; 20512974e916SYuri Benditovich if (proto == (uint16_t)ETH_P_IP) { 20522974e916SYuri Benditovich chain->max_payload = VIRTIO_NET_MAX_IP4_PAYLOAD; 20532974e916SYuri Benditovich chain->gso_type = VIRTIO_NET_HDR_GSO_TCPV4; 20542974e916SYuri Benditovich } else { 20552974e916SYuri Benditovich chain->max_payload = VIRTIO_NET_MAX_IP6_PAYLOAD; 20562974e916SYuri Benditovich chain->gso_type = VIRTIO_NET_HDR_GSO_TCPV6; 20572974e916SYuri Benditovich } 20582974e916SYuri Benditovich chain->drain_timer = timer_new_ns(QEMU_CLOCK_HOST, 20592974e916SYuri Benditovich virtio_net_rsc_purge, chain); 20602974e916SYuri Benditovich memset(&chain->stat, 0, sizeof(chain->stat)); 20612974e916SYuri Benditovich 20622974e916SYuri Benditovich QTAILQ_INIT(&chain->buffers); 20632974e916SYuri Benditovich QTAILQ_INSERT_TAIL(&n->rsc_chains, chain, next); 20642974e916SYuri Benditovich 20652974e916SYuri Benditovich return chain; 20662974e916SYuri Benditovich } 20672974e916SYuri Benditovich 20682974e916SYuri Benditovich static ssize_t virtio_net_rsc_receive(NetClientState *nc, 20692974e916SYuri Benditovich const uint8_t *buf, 20702974e916SYuri Benditovich size_t size) 20712974e916SYuri Benditovich { 20722974e916SYuri Benditovich uint16_t proto; 20732974e916SYuri Benditovich VirtioNetRscChain *chain; 20742974e916SYuri Benditovich struct eth_header *eth; 20752974e916SYuri Benditovich VirtIONet *n; 20762974e916SYuri Benditovich 20772974e916SYuri Benditovich n = qemu_get_nic_opaque(nc); 20782974e916SYuri Benditovich if (size < (n->host_hdr_len + sizeof(struct eth_header))) { 20792974e916SYuri Benditovich return virtio_net_do_receive(nc, buf, size); 20802974e916SYuri Benditovich } 20812974e916SYuri Benditovich 20822974e916SYuri Benditovich eth = (struct eth_header *)(buf + n->guest_hdr_len); 20832974e916SYuri Benditovich proto = htons(eth->h_proto); 20842974e916SYuri Benditovich 20852974e916SYuri Benditovich chain = virtio_net_rsc_lookup_chain(n, nc, proto); 20862974e916SYuri Benditovich if (chain) { 20872974e916SYuri Benditovich chain->stat.received++; 20882974e916SYuri Benditovich if (proto == (uint16_t)ETH_P_IP && n->rsc4_enabled) { 20892974e916SYuri Benditovich return virtio_net_rsc_receive4(chain, nc, buf, size); 20902974e916SYuri Benditovich } else if (proto == (uint16_t)ETH_P_IPV6 && n->rsc6_enabled) { 20912974e916SYuri Benditovich return virtio_net_rsc_receive6(chain, nc, buf, size); 20922974e916SYuri Benditovich } 20932974e916SYuri Benditovich } 20942974e916SYuri Benditovich return virtio_net_do_receive(nc, buf, size); 20952974e916SYuri Benditovich } 20962974e916SYuri Benditovich 20972974e916SYuri Benditovich static ssize_t virtio_net_receive(NetClientState *nc, const uint8_t *buf, 20982974e916SYuri Benditovich size_t size) 20992974e916SYuri Benditovich { 21002974e916SYuri Benditovich VirtIONet *n = qemu_get_nic_opaque(nc); 21012974e916SYuri Benditovich if ((n->rsc4_enabled || n->rsc6_enabled)) { 21022974e916SYuri Benditovich return virtio_net_rsc_receive(nc, buf, size); 21032974e916SYuri Benditovich } else { 21042974e916SYuri Benditovich return virtio_net_do_receive(nc, buf, size); 21052974e916SYuri Benditovich } 21062974e916SYuri Benditovich } 21072974e916SYuri Benditovich 21086e790746SPaolo Bonzini static int32_t virtio_net_flush_tx(VirtIONetQueue *q); 21096e790746SPaolo Bonzini 21106e790746SPaolo Bonzini static void virtio_net_tx_complete(NetClientState *nc, ssize_t len) 21116e790746SPaolo Bonzini { 21126e790746SPaolo Bonzini VirtIONet *n = qemu_get_nic_opaque(nc); 21136e790746SPaolo Bonzini VirtIONetQueue *q = virtio_net_get_subqueue(nc); 211417a0ca55SKONRAD Frederic VirtIODevice *vdev = VIRTIO_DEVICE(n); 21156e790746SPaolo Bonzini 211651b19ebeSPaolo Bonzini virtqueue_push(q->tx_vq, q->async_tx.elem, 0); 211717a0ca55SKONRAD Frederic virtio_notify(vdev, q->tx_vq); 21186e790746SPaolo Bonzini 211951b19ebeSPaolo Bonzini g_free(q->async_tx.elem); 212051b19ebeSPaolo Bonzini q->async_tx.elem = NULL; 21216e790746SPaolo Bonzini 21226e790746SPaolo Bonzini virtio_queue_set_notification(q->tx_vq, 1); 21236e790746SPaolo Bonzini virtio_net_flush_tx(q); 21246e790746SPaolo Bonzini } 21256e790746SPaolo Bonzini 21266e790746SPaolo Bonzini /* TX */ 21276e790746SPaolo Bonzini static int32_t virtio_net_flush_tx(VirtIONetQueue *q) 21286e790746SPaolo Bonzini { 21296e790746SPaolo Bonzini VirtIONet *n = q->n; 213017a0ca55SKONRAD Frederic VirtIODevice *vdev = VIRTIO_DEVICE(n); 213151b19ebeSPaolo Bonzini VirtQueueElement *elem; 21326e790746SPaolo Bonzini int32_t num_packets = 0; 21336e790746SPaolo Bonzini int queue_index = vq2q(virtio_get_queue_index(q->tx_vq)); 213417a0ca55SKONRAD Frederic if (!(vdev->status & VIRTIO_CONFIG_S_DRIVER_OK)) { 21356e790746SPaolo Bonzini return num_packets; 21366e790746SPaolo Bonzini } 21376e790746SPaolo Bonzini 213851b19ebeSPaolo Bonzini if (q->async_tx.elem) { 21396e790746SPaolo Bonzini virtio_queue_set_notification(q->tx_vq, 0); 21406e790746SPaolo Bonzini return num_packets; 21416e790746SPaolo Bonzini } 21426e790746SPaolo Bonzini 214351b19ebeSPaolo Bonzini for (;;) { 2144bd89dd98SJason Wang ssize_t ret; 214551b19ebeSPaolo Bonzini unsigned int out_num; 214651b19ebeSPaolo Bonzini struct iovec sg[VIRTQUEUE_MAX_SIZE], sg2[VIRTQUEUE_MAX_SIZE + 1], *out_sg; 2147feb93f36SJason Wang struct virtio_net_hdr_mrg_rxbuf mhdr; 21486e790746SPaolo Bonzini 214951b19ebeSPaolo Bonzini elem = virtqueue_pop(q->tx_vq, sizeof(VirtQueueElement)); 215051b19ebeSPaolo Bonzini if (!elem) { 215151b19ebeSPaolo Bonzini break; 215251b19ebeSPaolo Bonzini } 215351b19ebeSPaolo Bonzini 215451b19ebeSPaolo Bonzini out_num = elem->out_num; 215551b19ebeSPaolo Bonzini out_sg = elem->out_sg; 21566e790746SPaolo Bonzini if (out_num < 1) { 2157fa5e56c2SGreg Kurz virtio_error(vdev, "virtio-net header not in first element"); 2158fa5e56c2SGreg Kurz virtqueue_detach_element(q->tx_vq, elem, 0); 2159fa5e56c2SGreg Kurz g_free(elem); 2160fa5e56c2SGreg Kurz return -EINVAL; 21616e790746SPaolo Bonzini } 21626e790746SPaolo Bonzini 2163032a74a1SCédric Le Goater if (n->has_vnet_hdr) { 2164feb93f36SJason Wang if (iov_to_buf(out_sg, out_num, 0, &mhdr, n->guest_hdr_len) < 2165feb93f36SJason Wang n->guest_hdr_len) { 2166fa5e56c2SGreg Kurz virtio_error(vdev, "virtio-net header incorrect"); 2167fa5e56c2SGreg Kurz virtqueue_detach_element(q->tx_vq, elem, 0); 2168fa5e56c2SGreg Kurz g_free(elem); 2169fa5e56c2SGreg Kurz return -EINVAL; 2170032a74a1SCédric Le Goater } 21711bfa316cSGreg Kurz if (n->needs_vnet_hdr_swap) { 2172feb93f36SJason Wang virtio_net_hdr_swap(vdev, (void *) &mhdr); 2173feb93f36SJason Wang sg2[0].iov_base = &mhdr; 2174feb93f36SJason Wang sg2[0].iov_len = n->guest_hdr_len; 2175feb93f36SJason Wang out_num = iov_copy(&sg2[1], ARRAY_SIZE(sg2) - 1, 2176feb93f36SJason Wang out_sg, out_num, 2177feb93f36SJason Wang n->guest_hdr_len, -1); 2178feb93f36SJason Wang if (out_num == VIRTQUEUE_MAX_SIZE) { 2179feb93f36SJason Wang goto drop; 2180032a74a1SCédric Le Goater } 2181feb93f36SJason Wang out_num += 1; 2182feb93f36SJason Wang out_sg = sg2; 2183feb93f36SJason Wang } 2184feb93f36SJason Wang } 21856e790746SPaolo Bonzini /* 21866e790746SPaolo Bonzini * If host wants to see the guest header as is, we can 21876e790746SPaolo Bonzini * pass it on unchanged. Otherwise, copy just the parts 21886e790746SPaolo Bonzini * that host is interested in. 21896e790746SPaolo Bonzini */ 21906e790746SPaolo Bonzini assert(n->host_hdr_len <= n->guest_hdr_len); 21916e790746SPaolo Bonzini if (n->host_hdr_len != n->guest_hdr_len) { 21926e790746SPaolo Bonzini unsigned sg_num = iov_copy(sg, ARRAY_SIZE(sg), 21936e790746SPaolo Bonzini out_sg, out_num, 21946e790746SPaolo Bonzini 0, n->host_hdr_len); 21956e790746SPaolo Bonzini sg_num += iov_copy(sg + sg_num, ARRAY_SIZE(sg) - sg_num, 21966e790746SPaolo Bonzini out_sg, out_num, 21976e790746SPaolo Bonzini n->guest_hdr_len, -1); 21986e790746SPaolo Bonzini out_num = sg_num; 21996e790746SPaolo Bonzini out_sg = sg; 22006e790746SPaolo Bonzini } 22016e790746SPaolo Bonzini 22026e790746SPaolo Bonzini ret = qemu_sendv_packet_async(qemu_get_subqueue(n->nic, queue_index), 22036e790746SPaolo Bonzini out_sg, out_num, virtio_net_tx_complete); 22046e790746SPaolo Bonzini if (ret == 0) { 22056e790746SPaolo Bonzini virtio_queue_set_notification(q->tx_vq, 0); 22066e790746SPaolo Bonzini q->async_tx.elem = elem; 22076e790746SPaolo Bonzini return -EBUSY; 22086e790746SPaolo Bonzini } 22096e790746SPaolo Bonzini 2210feb93f36SJason Wang drop: 221151b19ebeSPaolo Bonzini virtqueue_push(q->tx_vq, elem, 0); 221217a0ca55SKONRAD Frederic virtio_notify(vdev, q->tx_vq); 221351b19ebeSPaolo Bonzini g_free(elem); 22146e790746SPaolo Bonzini 22156e790746SPaolo Bonzini if (++num_packets >= n->tx_burst) { 22166e790746SPaolo Bonzini break; 22176e790746SPaolo Bonzini } 22186e790746SPaolo Bonzini } 22196e790746SPaolo Bonzini return num_packets; 22206e790746SPaolo Bonzini } 22216e790746SPaolo Bonzini 22226e790746SPaolo Bonzini static void virtio_net_handle_tx_timer(VirtIODevice *vdev, VirtQueue *vq) 22236e790746SPaolo Bonzini { 222417a0ca55SKONRAD Frederic VirtIONet *n = VIRTIO_NET(vdev); 22256e790746SPaolo Bonzini VirtIONetQueue *q = &n->vqs[vq2q(virtio_get_queue_index(vq))]; 22266e790746SPaolo Bonzini 2227283e2c2aSYuri Benditovich if (unlikely((n->status & VIRTIO_NET_S_LINK_UP) == 0)) { 2228283e2c2aSYuri Benditovich virtio_net_drop_tx_queue_data(vdev, vq); 2229283e2c2aSYuri Benditovich return; 2230283e2c2aSYuri Benditovich } 2231283e2c2aSYuri Benditovich 22326e790746SPaolo Bonzini /* This happens when device was stopped but VCPU wasn't. */ 223317a0ca55SKONRAD Frederic if (!vdev->vm_running) { 22346e790746SPaolo Bonzini q->tx_waiting = 1; 22356e790746SPaolo Bonzini return; 22366e790746SPaolo Bonzini } 22376e790746SPaolo Bonzini 22386e790746SPaolo Bonzini if (q->tx_waiting) { 22396e790746SPaolo Bonzini virtio_queue_set_notification(vq, 1); 2240bc72ad67SAlex Bligh timer_del(q->tx_timer); 22416e790746SPaolo Bonzini q->tx_waiting = 0; 2242fa5e56c2SGreg Kurz if (virtio_net_flush_tx(q) == -EINVAL) { 2243fa5e56c2SGreg Kurz return; 2244fa5e56c2SGreg Kurz } 22456e790746SPaolo Bonzini } else { 2246bc72ad67SAlex Bligh timer_mod(q->tx_timer, 2247bc72ad67SAlex Bligh qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + n->tx_timeout); 22486e790746SPaolo Bonzini q->tx_waiting = 1; 22496e790746SPaolo Bonzini virtio_queue_set_notification(vq, 0); 22506e790746SPaolo Bonzini } 22516e790746SPaolo Bonzini } 22526e790746SPaolo Bonzini 22536e790746SPaolo Bonzini static void virtio_net_handle_tx_bh(VirtIODevice *vdev, VirtQueue *vq) 22546e790746SPaolo Bonzini { 225517a0ca55SKONRAD Frederic VirtIONet *n = VIRTIO_NET(vdev); 22566e790746SPaolo Bonzini VirtIONetQueue *q = &n->vqs[vq2q(virtio_get_queue_index(vq))]; 22576e790746SPaolo Bonzini 2258283e2c2aSYuri Benditovich if (unlikely((n->status & VIRTIO_NET_S_LINK_UP) == 0)) { 2259283e2c2aSYuri Benditovich virtio_net_drop_tx_queue_data(vdev, vq); 2260283e2c2aSYuri Benditovich return; 2261283e2c2aSYuri Benditovich } 2262283e2c2aSYuri Benditovich 22636e790746SPaolo Bonzini if (unlikely(q->tx_waiting)) { 22646e790746SPaolo Bonzini return; 22656e790746SPaolo Bonzini } 22666e790746SPaolo Bonzini q->tx_waiting = 1; 22676e790746SPaolo Bonzini /* This happens when device was stopped but VCPU wasn't. */ 226817a0ca55SKONRAD Frederic if (!vdev->vm_running) { 22696e790746SPaolo Bonzini return; 22706e790746SPaolo Bonzini } 22716e790746SPaolo Bonzini virtio_queue_set_notification(vq, 0); 22726e790746SPaolo Bonzini qemu_bh_schedule(q->tx_bh); 22736e790746SPaolo Bonzini } 22746e790746SPaolo Bonzini 22756e790746SPaolo Bonzini static void virtio_net_tx_timer(void *opaque) 22766e790746SPaolo Bonzini { 22776e790746SPaolo Bonzini VirtIONetQueue *q = opaque; 22786e790746SPaolo Bonzini VirtIONet *n = q->n; 227917a0ca55SKONRAD Frederic VirtIODevice *vdev = VIRTIO_DEVICE(n); 2280e8bcf842SMichael S. Tsirkin /* This happens when device was stopped but BH wasn't. */ 2281e8bcf842SMichael S. Tsirkin if (!vdev->vm_running) { 2282e8bcf842SMichael S. Tsirkin /* Make sure tx waiting is set, so we'll run when restarted. */ 2283e8bcf842SMichael S. Tsirkin assert(q->tx_waiting); 2284e8bcf842SMichael S. Tsirkin return; 2285e8bcf842SMichael S. Tsirkin } 22866e790746SPaolo Bonzini 22876e790746SPaolo Bonzini q->tx_waiting = 0; 22886e790746SPaolo Bonzini 22896e790746SPaolo Bonzini /* Just in case the driver is not ready on more */ 229017a0ca55SKONRAD Frederic if (!(vdev->status & VIRTIO_CONFIG_S_DRIVER_OK)) { 22916e790746SPaolo Bonzini return; 229217a0ca55SKONRAD Frederic } 22936e790746SPaolo Bonzini 22946e790746SPaolo Bonzini virtio_queue_set_notification(q->tx_vq, 1); 22956e790746SPaolo Bonzini virtio_net_flush_tx(q); 22966e790746SPaolo Bonzini } 22976e790746SPaolo Bonzini 22986e790746SPaolo Bonzini static void virtio_net_tx_bh(void *opaque) 22996e790746SPaolo Bonzini { 23006e790746SPaolo Bonzini VirtIONetQueue *q = opaque; 23016e790746SPaolo Bonzini VirtIONet *n = q->n; 230217a0ca55SKONRAD Frederic VirtIODevice *vdev = VIRTIO_DEVICE(n); 23036e790746SPaolo Bonzini int32_t ret; 23046e790746SPaolo Bonzini 2305e8bcf842SMichael S. Tsirkin /* This happens when device was stopped but BH wasn't. */ 2306e8bcf842SMichael S. Tsirkin if (!vdev->vm_running) { 2307e8bcf842SMichael S. Tsirkin /* Make sure tx waiting is set, so we'll run when restarted. */ 2308e8bcf842SMichael S. Tsirkin assert(q->tx_waiting); 2309e8bcf842SMichael S. Tsirkin return; 2310e8bcf842SMichael S. Tsirkin } 23116e790746SPaolo Bonzini 23126e790746SPaolo Bonzini q->tx_waiting = 0; 23136e790746SPaolo Bonzini 23146e790746SPaolo Bonzini /* Just in case the driver is not ready on more */ 231517a0ca55SKONRAD Frederic if (unlikely(!(vdev->status & VIRTIO_CONFIG_S_DRIVER_OK))) { 23166e790746SPaolo Bonzini return; 231717a0ca55SKONRAD Frederic } 23186e790746SPaolo Bonzini 23196e790746SPaolo Bonzini ret = virtio_net_flush_tx(q); 2320fa5e56c2SGreg Kurz if (ret == -EBUSY || ret == -EINVAL) { 2321fa5e56c2SGreg Kurz return; /* Notification re-enable handled by tx_complete or device 2322fa5e56c2SGreg Kurz * broken */ 23236e790746SPaolo Bonzini } 23246e790746SPaolo Bonzini 23256e790746SPaolo Bonzini /* If we flush a full burst of packets, assume there are 23266e790746SPaolo Bonzini * more coming and immediately reschedule */ 23276e790746SPaolo Bonzini if (ret >= n->tx_burst) { 23286e790746SPaolo Bonzini qemu_bh_schedule(q->tx_bh); 23296e790746SPaolo Bonzini q->tx_waiting = 1; 23306e790746SPaolo Bonzini return; 23316e790746SPaolo Bonzini } 23326e790746SPaolo Bonzini 23336e790746SPaolo Bonzini /* If less than a full burst, re-enable notification and flush 23346e790746SPaolo Bonzini * anything that may have come in while we weren't looking. If 23356e790746SPaolo Bonzini * we find something, assume the guest is still active and reschedule */ 23366e790746SPaolo Bonzini virtio_queue_set_notification(q->tx_vq, 1); 2337fa5e56c2SGreg Kurz ret = virtio_net_flush_tx(q); 2338fa5e56c2SGreg Kurz if (ret == -EINVAL) { 2339fa5e56c2SGreg Kurz return; 2340fa5e56c2SGreg Kurz } else if (ret > 0) { 23416e790746SPaolo Bonzini virtio_queue_set_notification(q->tx_vq, 0); 23426e790746SPaolo Bonzini qemu_bh_schedule(q->tx_bh); 23436e790746SPaolo Bonzini q->tx_waiting = 1; 23446e790746SPaolo Bonzini } 23456e790746SPaolo Bonzini } 23466e790746SPaolo Bonzini 2347f9d6dbf0SWen Congyang static void virtio_net_add_queue(VirtIONet *n, int index) 2348f9d6dbf0SWen Congyang { 2349f9d6dbf0SWen Congyang VirtIODevice *vdev = VIRTIO_DEVICE(n); 2350f9d6dbf0SWen Congyang 23511c0fbfa3SMichael S. Tsirkin n->vqs[index].rx_vq = virtio_add_queue(vdev, n->net_conf.rx_queue_size, 23521c0fbfa3SMichael S. Tsirkin virtio_net_handle_rx); 23539b02e161SWei Wang 2354f9d6dbf0SWen Congyang if (n->net_conf.tx && !strcmp(n->net_conf.tx, "timer")) { 2355f9d6dbf0SWen Congyang n->vqs[index].tx_vq = 23569b02e161SWei Wang virtio_add_queue(vdev, n->net_conf.tx_queue_size, 23579b02e161SWei Wang virtio_net_handle_tx_timer); 2358f9d6dbf0SWen Congyang n->vqs[index].tx_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, 2359f9d6dbf0SWen Congyang virtio_net_tx_timer, 2360f9d6dbf0SWen Congyang &n->vqs[index]); 2361f9d6dbf0SWen Congyang } else { 2362f9d6dbf0SWen Congyang n->vqs[index].tx_vq = 23639b02e161SWei Wang virtio_add_queue(vdev, n->net_conf.tx_queue_size, 23649b02e161SWei Wang virtio_net_handle_tx_bh); 2365f9d6dbf0SWen Congyang n->vqs[index].tx_bh = qemu_bh_new(virtio_net_tx_bh, &n->vqs[index]); 2366f9d6dbf0SWen Congyang } 2367f9d6dbf0SWen Congyang 2368f9d6dbf0SWen Congyang n->vqs[index].tx_waiting = 0; 2369f9d6dbf0SWen Congyang n->vqs[index].n = n; 2370f9d6dbf0SWen Congyang } 2371f9d6dbf0SWen Congyang 2372f9d6dbf0SWen Congyang static void virtio_net_del_queue(VirtIONet *n, int index) 2373f9d6dbf0SWen Congyang { 2374f9d6dbf0SWen Congyang VirtIODevice *vdev = VIRTIO_DEVICE(n); 2375f9d6dbf0SWen Congyang VirtIONetQueue *q = &n->vqs[index]; 2376f9d6dbf0SWen Congyang NetClientState *nc = qemu_get_subqueue(n->nic, index); 2377f9d6dbf0SWen Congyang 2378f9d6dbf0SWen Congyang qemu_purge_queued_packets(nc); 2379f9d6dbf0SWen Congyang 2380f9d6dbf0SWen Congyang virtio_del_queue(vdev, index * 2); 2381f9d6dbf0SWen Congyang if (q->tx_timer) { 2382f9d6dbf0SWen Congyang timer_del(q->tx_timer); 2383f9d6dbf0SWen Congyang timer_free(q->tx_timer); 2384f989c30cSYunjian Wang q->tx_timer = NULL; 2385f9d6dbf0SWen Congyang } else { 2386f9d6dbf0SWen Congyang qemu_bh_delete(q->tx_bh); 2387f989c30cSYunjian Wang q->tx_bh = NULL; 2388f9d6dbf0SWen Congyang } 2389f989c30cSYunjian Wang q->tx_waiting = 0; 2390f9d6dbf0SWen Congyang virtio_del_queue(vdev, index * 2 + 1); 2391f9d6dbf0SWen Congyang } 2392f9d6dbf0SWen Congyang 2393f9d6dbf0SWen Congyang static void virtio_net_change_num_queues(VirtIONet *n, int new_max_queues) 2394f9d6dbf0SWen Congyang { 2395f9d6dbf0SWen Congyang VirtIODevice *vdev = VIRTIO_DEVICE(n); 2396f9d6dbf0SWen Congyang int old_num_queues = virtio_get_num_queues(vdev); 2397f9d6dbf0SWen Congyang int new_num_queues = new_max_queues * 2 + 1; 2398f9d6dbf0SWen Congyang int i; 2399f9d6dbf0SWen Congyang 2400f9d6dbf0SWen Congyang assert(old_num_queues >= 3); 2401f9d6dbf0SWen Congyang assert(old_num_queues % 2 == 1); 2402f9d6dbf0SWen Congyang 2403f9d6dbf0SWen Congyang if (old_num_queues == new_num_queues) { 2404f9d6dbf0SWen Congyang return; 2405f9d6dbf0SWen Congyang } 2406f9d6dbf0SWen Congyang 2407f9d6dbf0SWen Congyang /* 2408f9d6dbf0SWen Congyang * We always need to remove and add ctrl vq if 2409f9d6dbf0SWen Congyang * old_num_queues != new_num_queues. Remove ctrl_vq first, 241020f86a75SYuval Shaia * and then we only enter one of the following two loops. 2411f9d6dbf0SWen Congyang */ 2412f9d6dbf0SWen Congyang virtio_del_queue(vdev, old_num_queues - 1); 2413f9d6dbf0SWen Congyang 2414f9d6dbf0SWen Congyang for (i = new_num_queues - 1; i < old_num_queues - 1; i += 2) { 2415f9d6dbf0SWen Congyang /* new_num_queues < old_num_queues */ 2416f9d6dbf0SWen Congyang virtio_net_del_queue(n, i / 2); 2417f9d6dbf0SWen Congyang } 2418f9d6dbf0SWen Congyang 2419f9d6dbf0SWen Congyang for (i = old_num_queues - 1; i < new_num_queues - 1; i += 2) { 2420f9d6dbf0SWen Congyang /* new_num_queues > old_num_queues */ 2421f9d6dbf0SWen Congyang virtio_net_add_queue(n, i / 2); 2422f9d6dbf0SWen Congyang } 2423f9d6dbf0SWen Congyang 2424f9d6dbf0SWen Congyang /* add ctrl_vq last */ 2425f9d6dbf0SWen Congyang n->ctrl_vq = virtio_add_queue(vdev, 64, virtio_net_handle_ctrl); 2426f9d6dbf0SWen Congyang } 2427f9d6dbf0SWen Congyang 2428ec57db16SJason Wang static void virtio_net_set_multiqueue(VirtIONet *n, int multiqueue) 24296e790746SPaolo Bonzini { 2430f9d6dbf0SWen Congyang int max = multiqueue ? n->max_queues : 1; 2431f9d6dbf0SWen Congyang 24326e790746SPaolo Bonzini n->multiqueue = multiqueue; 2433f9d6dbf0SWen Congyang virtio_net_change_num_queues(n, max); 24346e790746SPaolo Bonzini 24356e790746SPaolo Bonzini virtio_net_set_queues(n); 24366e790746SPaolo Bonzini } 24376e790746SPaolo Bonzini 2438982b78c5SDr. David Alan Gilbert static int virtio_net_post_load_device(void *opaque, int version_id) 2439037dab2fSGreg Kurz { 2440982b78c5SDr. David Alan Gilbert VirtIONet *n = opaque; 2441982b78c5SDr. David Alan Gilbert VirtIODevice *vdev = VIRTIO_DEVICE(n); 2442037dab2fSGreg Kurz int i, link_down; 2443037dab2fSGreg Kurz 24449d8c6a25SDr. David Alan Gilbert trace_virtio_net_post_load_device(); 2445982b78c5SDr. David Alan Gilbert virtio_net_set_mrg_rx_bufs(n, n->mergeable_rx_bufs, 244695129d6fSCornelia Huck virtio_vdev_has_feature(vdev, 244795129d6fSCornelia Huck VIRTIO_F_VERSION_1)); 24486e790746SPaolo Bonzini 24496e790746SPaolo Bonzini /* MAC_TABLE_ENTRIES may be different from the saved image */ 2450982b78c5SDr. David Alan Gilbert if (n->mac_table.in_use > MAC_TABLE_ENTRIES) { 24516e790746SPaolo Bonzini n->mac_table.in_use = 0; 24526e790746SPaolo Bonzini } 24536e790746SPaolo Bonzini 2454982b78c5SDr. David Alan Gilbert if (!virtio_vdev_has_feature(vdev, VIRTIO_NET_F_CTRL_GUEST_OFFLOADS)) { 24556c666823SMichael S. Tsirkin n->curr_guest_offloads = virtio_net_supported_guest_offloads(n); 24566c666823SMichael S. Tsirkin } 24576c666823SMichael S. Tsirkin 24587788c3f2SMikhail Sennikovsky /* 24597788c3f2SMikhail Sennikovsky * curr_guest_offloads will be later overwritten by the 24607788c3f2SMikhail Sennikovsky * virtio_set_features_nocheck call done from the virtio_load. 24617788c3f2SMikhail Sennikovsky * Here we make sure it is preserved and restored accordingly 24627788c3f2SMikhail Sennikovsky * in the virtio_net_post_load_virtio callback. 24637788c3f2SMikhail Sennikovsky */ 24647788c3f2SMikhail Sennikovsky n->saved_guest_offloads = n->curr_guest_offloads; 24656c666823SMichael S. Tsirkin 24666e790746SPaolo Bonzini virtio_net_set_queues(n); 24676e790746SPaolo Bonzini 24686e790746SPaolo Bonzini /* Find the first multicast entry in the saved MAC filter */ 24696e790746SPaolo Bonzini for (i = 0; i < n->mac_table.in_use; i++) { 24706e790746SPaolo Bonzini if (n->mac_table.macs[i * ETH_ALEN] & 1) { 24716e790746SPaolo Bonzini break; 24726e790746SPaolo Bonzini } 24736e790746SPaolo Bonzini } 24746e790746SPaolo Bonzini n->mac_table.first_multi = i; 24756e790746SPaolo Bonzini 24766e790746SPaolo Bonzini /* nc.link_down can't be migrated, so infer link_down according 24776e790746SPaolo Bonzini * to link status bit in n->status */ 24786e790746SPaolo Bonzini link_down = (n->status & VIRTIO_NET_S_LINK_UP) == 0; 24796e790746SPaolo Bonzini for (i = 0; i < n->max_queues; i++) { 24806e790746SPaolo Bonzini qemu_get_subqueue(n->nic, i)->link_down = link_down; 24816e790746SPaolo Bonzini } 24826e790746SPaolo Bonzini 24836c666823SMichael S. Tsirkin if (virtio_vdev_has_feature(vdev, VIRTIO_NET_F_GUEST_ANNOUNCE) && 24846c666823SMichael S. Tsirkin virtio_vdev_has_feature(vdev, VIRTIO_NET_F_CTRL_VQ)) { 24859d8c6a25SDr. David Alan Gilbert qemu_announce_timer_reset(&n->announce_timer, migrate_announce_params(), 24869d8c6a25SDr. David Alan Gilbert QEMU_CLOCK_VIRTUAL, 24879d8c6a25SDr. David Alan Gilbert virtio_net_announce_timer, n); 24889d8c6a25SDr. David Alan Gilbert if (n->announce_timer.round) { 24899d8c6a25SDr. David Alan Gilbert timer_mod(n->announce_timer.tm, 24909d8c6a25SDr. David Alan Gilbert qemu_clock_get_ms(n->announce_timer.type)); 24919d8c6a25SDr. David Alan Gilbert } else { 2492944458b6SDr. David Alan Gilbert qemu_announce_timer_del(&n->announce_timer, false); 24939d8c6a25SDr. David Alan Gilbert } 24946c666823SMichael S. Tsirkin } 24956c666823SMichael S. Tsirkin 24966e790746SPaolo Bonzini return 0; 24976e790746SPaolo Bonzini } 24986e790746SPaolo Bonzini 24997788c3f2SMikhail Sennikovsky static int virtio_net_post_load_virtio(VirtIODevice *vdev) 25007788c3f2SMikhail Sennikovsky { 25017788c3f2SMikhail Sennikovsky VirtIONet *n = VIRTIO_NET(vdev); 25027788c3f2SMikhail Sennikovsky /* 25037788c3f2SMikhail Sennikovsky * The actual needed state is now in saved_guest_offloads, 25047788c3f2SMikhail Sennikovsky * see virtio_net_post_load_device for detail. 25057788c3f2SMikhail Sennikovsky * Restore it back and apply the desired offloads. 25067788c3f2SMikhail Sennikovsky */ 25077788c3f2SMikhail Sennikovsky n->curr_guest_offloads = n->saved_guest_offloads; 25087788c3f2SMikhail Sennikovsky if (peer_has_vnet_hdr(n)) { 25097788c3f2SMikhail Sennikovsky virtio_net_apply_guest_offloads(n); 25107788c3f2SMikhail Sennikovsky } 25117788c3f2SMikhail Sennikovsky 25127788c3f2SMikhail Sennikovsky return 0; 25137788c3f2SMikhail Sennikovsky } 25147788c3f2SMikhail Sennikovsky 2515982b78c5SDr. David Alan Gilbert /* tx_waiting field of a VirtIONetQueue */ 2516982b78c5SDr. David Alan Gilbert static const VMStateDescription vmstate_virtio_net_queue_tx_waiting = { 2517982b78c5SDr. David Alan Gilbert .name = "virtio-net-queue-tx_waiting", 2518982b78c5SDr. David Alan Gilbert .fields = (VMStateField[]) { 2519982b78c5SDr. David Alan Gilbert VMSTATE_UINT32(tx_waiting, VirtIONetQueue), 2520982b78c5SDr. David Alan Gilbert VMSTATE_END_OF_LIST() 2521982b78c5SDr. David Alan Gilbert }, 2522982b78c5SDr. David Alan Gilbert }; 2523982b78c5SDr. David Alan Gilbert 2524982b78c5SDr. David Alan Gilbert static bool max_queues_gt_1(void *opaque, int version_id) 2525982b78c5SDr. David Alan Gilbert { 2526982b78c5SDr. David Alan Gilbert return VIRTIO_NET(opaque)->max_queues > 1; 2527982b78c5SDr. David Alan Gilbert } 2528982b78c5SDr. David Alan Gilbert 2529982b78c5SDr. David Alan Gilbert static bool has_ctrl_guest_offloads(void *opaque, int version_id) 2530982b78c5SDr. David Alan Gilbert { 2531982b78c5SDr. David Alan Gilbert return virtio_vdev_has_feature(VIRTIO_DEVICE(opaque), 2532982b78c5SDr. David Alan Gilbert VIRTIO_NET_F_CTRL_GUEST_OFFLOADS); 2533982b78c5SDr. David Alan Gilbert } 2534982b78c5SDr. David Alan Gilbert 2535982b78c5SDr. David Alan Gilbert static bool mac_table_fits(void *opaque, int version_id) 2536982b78c5SDr. David Alan Gilbert { 2537982b78c5SDr. David Alan Gilbert return VIRTIO_NET(opaque)->mac_table.in_use <= MAC_TABLE_ENTRIES; 2538982b78c5SDr. David Alan Gilbert } 2539982b78c5SDr. David Alan Gilbert 2540982b78c5SDr. David Alan Gilbert static bool mac_table_doesnt_fit(void *opaque, int version_id) 2541982b78c5SDr. David Alan Gilbert { 2542982b78c5SDr. David Alan Gilbert return !mac_table_fits(opaque, version_id); 2543982b78c5SDr. David Alan Gilbert } 2544982b78c5SDr. David Alan Gilbert 2545982b78c5SDr. David Alan Gilbert /* This temporary type is shared by all the WITH_TMP methods 2546982b78c5SDr. David Alan Gilbert * although only some fields are used by each. 2547982b78c5SDr. David Alan Gilbert */ 2548982b78c5SDr. David Alan Gilbert struct VirtIONetMigTmp { 2549982b78c5SDr. David Alan Gilbert VirtIONet *parent; 2550982b78c5SDr. David Alan Gilbert VirtIONetQueue *vqs_1; 2551982b78c5SDr. David Alan Gilbert uint16_t curr_queues_1; 2552982b78c5SDr. David Alan Gilbert uint8_t has_ufo; 2553982b78c5SDr. David Alan Gilbert uint32_t has_vnet_hdr; 2554982b78c5SDr. David Alan Gilbert }; 2555982b78c5SDr. David Alan Gilbert 2556982b78c5SDr. David Alan Gilbert /* The 2nd and subsequent tx_waiting flags are loaded later than 2557982b78c5SDr. David Alan Gilbert * the 1st entry in the queues and only if there's more than one 2558982b78c5SDr. David Alan Gilbert * entry. We use the tmp mechanism to calculate a temporary 2559982b78c5SDr. David Alan Gilbert * pointer and count and also validate the count. 2560982b78c5SDr. David Alan Gilbert */ 2561982b78c5SDr. David Alan Gilbert 256244b1ff31SDr. David Alan Gilbert static int virtio_net_tx_waiting_pre_save(void *opaque) 2563982b78c5SDr. David Alan Gilbert { 2564982b78c5SDr. David Alan Gilbert struct VirtIONetMigTmp *tmp = opaque; 2565982b78c5SDr. David Alan Gilbert 2566982b78c5SDr. David Alan Gilbert tmp->vqs_1 = tmp->parent->vqs + 1; 2567982b78c5SDr. David Alan Gilbert tmp->curr_queues_1 = tmp->parent->curr_queues - 1; 2568982b78c5SDr. David Alan Gilbert if (tmp->parent->curr_queues == 0) { 2569982b78c5SDr. David Alan Gilbert tmp->curr_queues_1 = 0; 2570982b78c5SDr. David Alan Gilbert } 257144b1ff31SDr. David Alan Gilbert 257244b1ff31SDr. David Alan Gilbert return 0; 2573982b78c5SDr. David Alan Gilbert } 2574982b78c5SDr. David Alan Gilbert 2575982b78c5SDr. David Alan Gilbert static int virtio_net_tx_waiting_pre_load(void *opaque) 2576982b78c5SDr. David Alan Gilbert { 2577982b78c5SDr. David Alan Gilbert struct VirtIONetMigTmp *tmp = opaque; 2578982b78c5SDr. David Alan Gilbert 2579982b78c5SDr. David Alan Gilbert /* Reuse the pointer setup from save */ 2580982b78c5SDr. David Alan Gilbert virtio_net_tx_waiting_pre_save(opaque); 2581982b78c5SDr. David Alan Gilbert 2582982b78c5SDr. David Alan Gilbert if (tmp->parent->curr_queues > tmp->parent->max_queues) { 2583982b78c5SDr. David Alan Gilbert error_report("virtio-net: curr_queues %x > max_queues %x", 2584982b78c5SDr. David Alan Gilbert tmp->parent->curr_queues, tmp->parent->max_queues); 2585982b78c5SDr. David Alan Gilbert 2586982b78c5SDr. David Alan Gilbert return -EINVAL; 2587982b78c5SDr. David Alan Gilbert } 2588982b78c5SDr. David Alan Gilbert 2589982b78c5SDr. David Alan Gilbert return 0; /* all good */ 2590982b78c5SDr. David Alan Gilbert } 2591982b78c5SDr. David Alan Gilbert 2592982b78c5SDr. David Alan Gilbert static const VMStateDescription vmstate_virtio_net_tx_waiting = { 2593982b78c5SDr. David Alan Gilbert .name = "virtio-net-tx_waiting", 2594982b78c5SDr. David Alan Gilbert .pre_load = virtio_net_tx_waiting_pre_load, 2595982b78c5SDr. David Alan Gilbert .pre_save = virtio_net_tx_waiting_pre_save, 2596982b78c5SDr. David Alan Gilbert .fields = (VMStateField[]) { 2597982b78c5SDr. David Alan Gilbert VMSTATE_STRUCT_VARRAY_POINTER_UINT16(vqs_1, struct VirtIONetMigTmp, 2598982b78c5SDr. David Alan Gilbert curr_queues_1, 2599982b78c5SDr. David Alan Gilbert vmstate_virtio_net_queue_tx_waiting, 2600982b78c5SDr. David Alan Gilbert struct VirtIONetQueue), 2601982b78c5SDr. David Alan Gilbert VMSTATE_END_OF_LIST() 2602982b78c5SDr. David Alan Gilbert }, 2603982b78c5SDr. David Alan Gilbert }; 2604982b78c5SDr. David Alan Gilbert 2605982b78c5SDr. David Alan Gilbert /* the 'has_ufo' flag is just tested; if the incoming stream has the 2606982b78c5SDr. David Alan Gilbert * flag set we need to check that we have it 2607982b78c5SDr. David Alan Gilbert */ 2608982b78c5SDr. David Alan Gilbert static int virtio_net_ufo_post_load(void *opaque, int version_id) 2609982b78c5SDr. David Alan Gilbert { 2610982b78c5SDr. David Alan Gilbert struct VirtIONetMigTmp *tmp = opaque; 2611982b78c5SDr. David Alan Gilbert 2612982b78c5SDr. David Alan Gilbert if (tmp->has_ufo && !peer_has_ufo(tmp->parent)) { 2613982b78c5SDr. David Alan Gilbert error_report("virtio-net: saved image requires TUN_F_UFO support"); 2614982b78c5SDr. David Alan Gilbert return -EINVAL; 2615982b78c5SDr. David Alan Gilbert } 2616982b78c5SDr. David Alan Gilbert 2617982b78c5SDr. David Alan Gilbert return 0; 2618982b78c5SDr. David Alan Gilbert } 2619982b78c5SDr. David Alan Gilbert 262044b1ff31SDr. David Alan Gilbert static int virtio_net_ufo_pre_save(void *opaque) 2621982b78c5SDr. David Alan Gilbert { 2622982b78c5SDr. David Alan Gilbert struct VirtIONetMigTmp *tmp = opaque; 2623982b78c5SDr. David Alan Gilbert 2624982b78c5SDr. David Alan Gilbert tmp->has_ufo = tmp->parent->has_ufo; 262544b1ff31SDr. David Alan Gilbert 262644b1ff31SDr. David Alan Gilbert return 0; 2627982b78c5SDr. David Alan Gilbert } 2628982b78c5SDr. David Alan Gilbert 2629982b78c5SDr. David Alan Gilbert static const VMStateDescription vmstate_virtio_net_has_ufo = { 2630982b78c5SDr. David Alan Gilbert .name = "virtio-net-ufo", 2631982b78c5SDr. David Alan Gilbert .post_load = virtio_net_ufo_post_load, 2632982b78c5SDr. David Alan Gilbert .pre_save = virtio_net_ufo_pre_save, 2633982b78c5SDr. David Alan Gilbert .fields = (VMStateField[]) { 2634982b78c5SDr. David Alan Gilbert VMSTATE_UINT8(has_ufo, struct VirtIONetMigTmp), 2635982b78c5SDr. David Alan Gilbert VMSTATE_END_OF_LIST() 2636982b78c5SDr. David Alan Gilbert }, 2637982b78c5SDr. David Alan Gilbert }; 2638982b78c5SDr. David Alan Gilbert 2639982b78c5SDr. David Alan Gilbert /* the 'has_vnet_hdr' flag is just tested; if the incoming stream has the 2640982b78c5SDr. David Alan Gilbert * flag set we need to check that we have it 2641982b78c5SDr. David Alan Gilbert */ 2642982b78c5SDr. David Alan Gilbert static int virtio_net_vnet_post_load(void *opaque, int version_id) 2643982b78c5SDr. David Alan Gilbert { 2644982b78c5SDr. David Alan Gilbert struct VirtIONetMigTmp *tmp = opaque; 2645982b78c5SDr. David Alan Gilbert 2646982b78c5SDr. David Alan Gilbert if (tmp->has_vnet_hdr && !peer_has_vnet_hdr(tmp->parent)) { 2647982b78c5SDr. David Alan Gilbert error_report("virtio-net: saved image requires vnet_hdr=on"); 2648982b78c5SDr. David Alan Gilbert return -EINVAL; 2649982b78c5SDr. David Alan Gilbert } 2650982b78c5SDr. David Alan Gilbert 2651982b78c5SDr. David Alan Gilbert return 0; 2652982b78c5SDr. David Alan Gilbert } 2653982b78c5SDr. David Alan Gilbert 265444b1ff31SDr. David Alan Gilbert static int virtio_net_vnet_pre_save(void *opaque) 2655982b78c5SDr. David Alan Gilbert { 2656982b78c5SDr. David Alan Gilbert struct VirtIONetMigTmp *tmp = opaque; 2657982b78c5SDr. David Alan Gilbert 2658982b78c5SDr. David Alan Gilbert tmp->has_vnet_hdr = tmp->parent->has_vnet_hdr; 265944b1ff31SDr. David Alan Gilbert 266044b1ff31SDr. David Alan Gilbert return 0; 2661982b78c5SDr. David Alan Gilbert } 2662982b78c5SDr. David Alan Gilbert 2663982b78c5SDr. David Alan Gilbert static const VMStateDescription vmstate_virtio_net_has_vnet = { 2664982b78c5SDr. David Alan Gilbert .name = "virtio-net-vnet", 2665982b78c5SDr. David Alan Gilbert .post_load = virtio_net_vnet_post_load, 2666982b78c5SDr. David Alan Gilbert .pre_save = virtio_net_vnet_pre_save, 2667982b78c5SDr. David Alan Gilbert .fields = (VMStateField[]) { 2668982b78c5SDr. David Alan Gilbert VMSTATE_UINT32(has_vnet_hdr, struct VirtIONetMigTmp), 2669982b78c5SDr. David Alan Gilbert VMSTATE_END_OF_LIST() 2670982b78c5SDr. David Alan Gilbert }, 2671982b78c5SDr. David Alan Gilbert }; 2672982b78c5SDr. David Alan Gilbert 2673982b78c5SDr. David Alan Gilbert static const VMStateDescription vmstate_virtio_net_device = { 2674982b78c5SDr. David Alan Gilbert .name = "virtio-net-device", 2675982b78c5SDr. David Alan Gilbert .version_id = VIRTIO_NET_VM_VERSION, 2676982b78c5SDr. David Alan Gilbert .minimum_version_id = VIRTIO_NET_VM_VERSION, 2677982b78c5SDr. David Alan Gilbert .post_load = virtio_net_post_load_device, 2678982b78c5SDr. David Alan Gilbert .fields = (VMStateField[]) { 2679982b78c5SDr. David Alan Gilbert VMSTATE_UINT8_ARRAY(mac, VirtIONet, ETH_ALEN), 2680982b78c5SDr. David Alan Gilbert VMSTATE_STRUCT_POINTER(vqs, VirtIONet, 2681982b78c5SDr. David Alan Gilbert vmstate_virtio_net_queue_tx_waiting, 2682982b78c5SDr. David Alan Gilbert VirtIONetQueue), 2683982b78c5SDr. David Alan Gilbert VMSTATE_UINT32(mergeable_rx_bufs, VirtIONet), 2684982b78c5SDr. David Alan Gilbert VMSTATE_UINT16(status, VirtIONet), 2685982b78c5SDr. David Alan Gilbert VMSTATE_UINT8(promisc, VirtIONet), 2686982b78c5SDr. David Alan Gilbert VMSTATE_UINT8(allmulti, VirtIONet), 2687982b78c5SDr. David Alan Gilbert VMSTATE_UINT32(mac_table.in_use, VirtIONet), 2688982b78c5SDr. David Alan Gilbert 2689982b78c5SDr. David Alan Gilbert /* Guarded pair: If it fits we load it, else we throw it away 2690982b78c5SDr. David Alan Gilbert * - can happen if source has a larger MAC table.; post-load 2691982b78c5SDr. David Alan Gilbert * sets flags in this case. 2692982b78c5SDr. David Alan Gilbert */ 2693982b78c5SDr. David Alan Gilbert VMSTATE_VBUFFER_MULTIPLY(mac_table.macs, VirtIONet, 2694982b78c5SDr. David Alan Gilbert 0, mac_table_fits, mac_table.in_use, 2695982b78c5SDr. David Alan Gilbert ETH_ALEN), 2696982b78c5SDr. David Alan Gilbert VMSTATE_UNUSED_VARRAY_UINT32(VirtIONet, mac_table_doesnt_fit, 0, 2697982b78c5SDr. David Alan Gilbert mac_table.in_use, ETH_ALEN), 2698982b78c5SDr. David Alan Gilbert 2699982b78c5SDr. David Alan Gilbert /* Note: This is an array of uint32's that's always been saved as a 2700982b78c5SDr. David Alan Gilbert * buffer; hold onto your endiannesses; it's actually used as a bitmap 2701982b78c5SDr. David Alan Gilbert * but based on the uint. 2702982b78c5SDr. David Alan Gilbert */ 2703982b78c5SDr. David Alan Gilbert VMSTATE_BUFFER_POINTER_UNSAFE(vlans, VirtIONet, 0, MAX_VLAN >> 3), 2704982b78c5SDr. David Alan Gilbert VMSTATE_WITH_TMP(VirtIONet, struct VirtIONetMigTmp, 2705982b78c5SDr. David Alan Gilbert vmstate_virtio_net_has_vnet), 2706982b78c5SDr. David Alan Gilbert VMSTATE_UINT8(mac_table.multi_overflow, VirtIONet), 2707982b78c5SDr. David Alan Gilbert VMSTATE_UINT8(mac_table.uni_overflow, VirtIONet), 2708982b78c5SDr. David Alan Gilbert VMSTATE_UINT8(alluni, VirtIONet), 2709982b78c5SDr. David Alan Gilbert VMSTATE_UINT8(nomulti, VirtIONet), 2710982b78c5SDr. David Alan Gilbert VMSTATE_UINT8(nouni, VirtIONet), 2711982b78c5SDr. David Alan Gilbert VMSTATE_UINT8(nobcast, VirtIONet), 2712982b78c5SDr. David Alan Gilbert VMSTATE_WITH_TMP(VirtIONet, struct VirtIONetMigTmp, 2713982b78c5SDr. David Alan Gilbert vmstate_virtio_net_has_ufo), 2714982b78c5SDr. David Alan Gilbert VMSTATE_SINGLE_TEST(max_queues, VirtIONet, max_queues_gt_1, 0, 2715982b78c5SDr. David Alan Gilbert vmstate_info_uint16_equal, uint16_t), 2716982b78c5SDr. David Alan Gilbert VMSTATE_UINT16_TEST(curr_queues, VirtIONet, max_queues_gt_1), 2717982b78c5SDr. David Alan Gilbert VMSTATE_WITH_TMP(VirtIONet, struct VirtIONetMigTmp, 2718982b78c5SDr. David Alan Gilbert vmstate_virtio_net_tx_waiting), 2719982b78c5SDr. David Alan Gilbert VMSTATE_UINT64_TEST(curr_guest_offloads, VirtIONet, 2720982b78c5SDr. David Alan Gilbert has_ctrl_guest_offloads), 2721982b78c5SDr. David Alan Gilbert VMSTATE_END_OF_LIST() 2722982b78c5SDr. David Alan Gilbert }, 2723982b78c5SDr. David Alan Gilbert }; 2724982b78c5SDr. David Alan Gilbert 27256e790746SPaolo Bonzini static NetClientInfo net_virtio_info = { 2726f394b2e2SEric Blake .type = NET_CLIENT_DRIVER_NIC, 27276e790746SPaolo Bonzini .size = sizeof(NICState), 27286e790746SPaolo Bonzini .can_receive = virtio_net_can_receive, 27296e790746SPaolo Bonzini .receive = virtio_net_receive, 27306e790746SPaolo Bonzini .link_status_changed = virtio_net_set_link_status, 2731b1be4280SAmos Kong .query_rx_filter = virtio_net_query_rxfilter, 2732b2c929f0SDr. David Alan Gilbert .announce = virtio_net_announce, 27336e790746SPaolo Bonzini }; 27346e790746SPaolo Bonzini 27356e790746SPaolo Bonzini static bool virtio_net_guest_notifier_pending(VirtIODevice *vdev, int idx) 27366e790746SPaolo Bonzini { 273717a0ca55SKONRAD Frederic VirtIONet *n = VIRTIO_NET(vdev); 27386e790746SPaolo Bonzini NetClientState *nc = qemu_get_subqueue(n->nic, vq2q(idx)); 27396e790746SPaolo Bonzini assert(n->vhost_started); 2740ed8b4afeSNikolay Nikolaev return vhost_net_virtqueue_pending(get_vhost_net(nc->peer), idx); 27416e790746SPaolo Bonzini } 27426e790746SPaolo Bonzini 27436e790746SPaolo Bonzini static void virtio_net_guest_notifier_mask(VirtIODevice *vdev, int idx, 27446e790746SPaolo Bonzini bool mask) 27456e790746SPaolo Bonzini { 274617a0ca55SKONRAD Frederic VirtIONet *n = VIRTIO_NET(vdev); 27476e790746SPaolo Bonzini NetClientState *nc = qemu_get_subqueue(n->nic, vq2q(idx)); 27486e790746SPaolo Bonzini assert(n->vhost_started); 2749ed8b4afeSNikolay Nikolaev vhost_net_virtqueue_mask(get_vhost_net(nc->peer), 27506e790746SPaolo Bonzini vdev, idx, mask); 27516e790746SPaolo Bonzini } 27526e790746SPaolo Bonzini 2753019a3edbSGerd Hoffmann static void virtio_net_set_config_size(VirtIONet *n, uint64_t host_features) 27546e790746SPaolo Bonzini { 27550cd09c3aSCornelia Huck virtio_add_feature(&host_features, VIRTIO_NET_F_MAC); 2756a93e599dSMaxime Coquelin 2757ba550851SStefano Garzarella n->config_size = virtio_feature_get_config_size(feature_sizes, 2758ba550851SStefano Garzarella host_features); 275917ec5a86SKONRAD Frederic } 27606e790746SPaolo Bonzini 27618a253ec2SKONRAD Frederic void virtio_net_set_netclient_name(VirtIONet *n, const char *name, 27628a253ec2SKONRAD Frederic const char *type) 27638a253ec2SKONRAD Frederic { 27648a253ec2SKONRAD Frederic /* 27658a253ec2SKONRAD Frederic * The name can be NULL, the netclient name will be type.x. 27668a253ec2SKONRAD Frederic */ 27678a253ec2SKONRAD Frederic assert(type != NULL); 27688a253ec2SKONRAD Frederic 27698a253ec2SKONRAD Frederic g_free(n->netclient_name); 27708a253ec2SKONRAD Frederic g_free(n->netclient_type); 27718a253ec2SKONRAD Frederic n->netclient_name = g_strdup(name); 27728a253ec2SKONRAD Frederic n->netclient_type = g_strdup(type); 27738a253ec2SKONRAD Frederic } 27748a253ec2SKONRAD Frederic 27759711cd0dSJens Freimann static bool failover_unplug_primary(VirtIONet *n) 27769711cd0dSJens Freimann { 27779711cd0dSJens Freimann HotplugHandler *hotplug_ctrl; 27789711cd0dSJens Freimann PCIDevice *pci_dev; 27799711cd0dSJens Freimann Error *err = NULL; 27809711cd0dSJens Freimann 27819711cd0dSJens Freimann hotplug_ctrl = qdev_get_hotplug_handler(n->primary_dev); 27829711cd0dSJens Freimann if (hotplug_ctrl) { 27839711cd0dSJens Freimann pci_dev = PCI_DEVICE(n->primary_dev); 27849711cd0dSJens Freimann pci_dev->partially_hotplugged = true; 27859711cd0dSJens Freimann hotplug_handler_unplug_request(hotplug_ctrl, n->primary_dev, &err); 27869711cd0dSJens Freimann if (err) { 27879711cd0dSJens Freimann error_report_err(err); 27889711cd0dSJens Freimann return false; 27899711cd0dSJens Freimann } 27909711cd0dSJens Freimann } else { 27919711cd0dSJens Freimann return false; 27929711cd0dSJens Freimann } 27939711cd0dSJens Freimann return true; 27949711cd0dSJens Freimann } 27959711cd0dSJens Freimann 27969711cd0dSJens Freimann static bool failover_replug_primary(VirtIONet *n, Error **errp) 27979711cd0dSJens Freimann { 2798*5a0948d3SMarkus Armbruster Error *err = NULL; 27999711cd0dSJens Freimann HotplugHandler *hotplug_ctrl; 28009711cd0dSJens Freimann PCIDevice *pdev = PCI_DEVICE(n->primary_dev); 28019711cd0dSJens Freimann 28029711cd0dSJens Freimann if (!pdev->partially_hotplugged) { 28039711cd0dSJens Freimann return true; 28049711cd0dSJens Freimann } 28059711cd0dSJens Freimann if (!n->primary_device_opts) { 28069711cd0dSJens Freimann n->primary_device_opts = qemu_opts_from_qdict( 28079711cd0dSJens Freimann qemu_find_opts("device"), 28089711cd0dSJens Freimann n->primary_device_dict, errp); 2809150ab54aSJens Freimann if (!n->primary_device_opts) { 2810*5a0948d3SMarkus Armbruster return false; 28119711cd0dSJens Freimann } 2812150ab54aSJens Freimann } 28139711cd0dSJens Freimann n->primary_bus = n->primary_dev->parent_bus; 2814150ab54aSJens Freimann if (!n->primary_bus) { 2815150ab54aSJens Freimann error_setg(errp, "virtio_net: couldn't find primary bus"); 2816*5a0948d3SMarkus Armbruster return false; 28179711cd0dSJens Freimann } 28189711cd0dSJens Freimann qdev_set_parent_bus(n->primary_dev, n->primary_bus); 28199711cd0dSJens Freimann n->primary_should_be_hidden = false; 28209711cd0dSJens Freimann qemu_opt_set_bool(n->primary_device_opts, 2821*5a0948d3SMarkus Armbruster "partially_hotplugged", true, &err); 2822*5a0948d3SMarkus Armbruster if (err) { 2823*5a0948d3SMarkus Armbruster goto out; 2824*5a0948d3SMarkus Armbruster } 28259711cd0dSJens Freimann hotplug_ctrl = qdev_get_hotplug_handler(n->primary_dev); 28269711cd0dSJens Freimann if (hotplug_ctrl) { 2827*5a0948d3SMarkus Armbruster hotplug_handler_pre_plug(hotplug_ctrl, n->primary_dev, &err); 2828*5a0948d3SMarkus Armbruster if (err) { 2829*5a0948d3SMarkus Armbruster goto out; 2830*5a0948d3SMarkus Armbruster } 28319711cd0dSJens Freimann hotplug_handler_plug(hotplug_ctrl, n->primary_dev, errp); 28329711cd0dSJens Freimann } 2833150ab54aSJens Freimann 2834150ab54aSJens Freimann out: 2835*5a0948d3SMarkus Armbruster error_propagate(errp, err); 2836*5a0948d3SMarkus Armbruster return !err; 28379711cd0dSJens Freimann } 28389711cd0dSJens Freimann 28399711cd0dSJens Freimann static void virtio_net_handle_migration_primary(VirtIONet *n, 28409711cd0dSJens Freimann MigrationState *s) 28419711cd0dSJens Freimann { 28429711cd0dSJens Freimann bool should_be_hidden; 28439711cd0dSJens Freimann Error *err = NULL; 28449711cd0dSJens Freimann 28459711cd0dSJens Freimann should_be_hidden = atomic_read(&n->primary_should_be_hidden); 28469711cd0dSJens Freimann 28479711cd0dSJens Freimann if (!n->primary_dev) { 28489711cd0dSJens Freimann n->primary_dev = virtio_connect_failover_devices(n, n->qdev, &err); 28499711cd0dSJens Freimann if (!n->primary_dev) { 28509711cd0dSJens Freimann return; 28519711cd0dSJens Freimann } 28529711cd0dSJens Freimann } 28539711cd0dSJens Freimann 28544dbac1aeSMarkus Armbruster if (migration_in_setup(s) && !should_be_hidden) { 28559711cd0dSJens Freimann if (failover_unplug_primary(n)) { 28569711cd0dSJens Freimann vmstate_unregister(n->primary_dev, qdev_get_vmsd(n->primary_dev), 28579711cd0dSJens Freimann n->primary_dev); 28589711cd0dSJens Freimann qapi_event_send_unplug_primary(n->primary_device_id); 28599711cd0dSJens Freimann atomic_set(&n->primary_should_be_hidden, true); 28609711cd0dSJens Freimann } else { 28619711cd0dSJens Freimann warn_report("couldn't unplug primary device"); 28629711cd0dSJens Freimann } 28639711cd0dSJens Freimann } else if (migration_has_failed(s)) { 2864150ab54aSJens Freimann /* We already unplugged the device let's plug it back */ 28659711cd0dSJens Freimann if (!failover_replug_primary(n, &err)) { 28669711cd0dSJens Freimann if (err) { 28679711cd0dSJens Freimann error_report_err(err); 28689711cd0dSJens Freimann } 28699711cd0dSJens Freimann } 28709711cd0dSJens Freimann } 28719711cd0dSJens Freimann } 28729711cd0dSJens Freimann 28739711cd0dSJens Freimann static void virtio_net_migration_state_notifier(Notifier *notifier, void *data) 28749711cd0dSJens Freimann { 28759711cd0dSJens Freimann MigrationState *s = data; 28769711cd0dSJens Freimann VirtIONet *n = container_of(notifier, VirtIONet, migration_state); 28779711cd0dSJens Freimann virtio_net_handle_migration_primary(n, s); 28789711cd0dSJens Freimann } 28799711cd0dSJens Freimann 28809711cd0dSJens Freimann static int virtio_net_primary_should_be_hidden(DeviceListener *listener, 28819711cd0dSJens Freimann QemuOpts *device_opts) 28829711cd0dSJens Freimann { 28839711cd0dSJens Freimann VirtIONet *n = container_of(listener, VirtIONet, primary_listener); 28844d0e59acSJens Freimann bool match_found = false; 28854d0e59acSJens Freimann bool hide = false; 28869711cd0dSJens Freimann 28874d0e59acSJens Freimann if (!device_opts) { 28884d0e59acSJens Freimann return -1; 28894d0e59acSJens Freimann } 28909711cd0dSJens Freimann n->primary_device_dict = qemu_opts_to_qdict(device_opts, 28919711cd0dSJens Freimann n->primary_device_dict); 28929711cd0dSJens Freimann if (n->primary_device_dict) { 28939711cd0dSJens Freimann g_free(n->standby_id); 28949711cd0dSJens Freimann n->standby_id = g_strdup(qdict_get_try_str(n->primary_device_dict, 28959711cd0dSJens Freimann "failover_pair_id")); 28969711cd0dSJens Freimann } 28974d0e59acSJens Freimann if (g_strcmp0(n->standby_id, n->netclient_name) == 0) { 28989711cd0dSJens Freimann match_found = true; 28999711cd0dSJens Freimann } else { 29009711cd0dSJens Freimann match_found = false; 29019711cd0dSJens Freimann hide = false; 29029711cd0dSJens Freimann g_free(n->standby_id); 29039711cd0dSJens Freimann n->primary_device_dict = NULL; 29049711cd0dSJens Freimann goto out; 29059711cd0dSJens Freimann } 29069711cd0dSJens Freimann 29079711cd0dSJens Freimann n->primary_device_opts = device_opts; 29089711cd0dSJens Freimann 29099711cd0dSJens Freimann /* primary_should_be_hidden is set during feature negotiation */ 29109711cd0dSJens Freimann hide = atomic_read(&n->primary_should_be_hidden); 29119711cd0dSJens Freimann 29129711cd0dSJens Freimann if (n->primary_device_dict) { 29139711cd0dSJens Freimann g_free(n->primary_device_id); 29149711cd0dSJens Freimann n->primary_device_id = g_strdup(qdict_get_try_str( 29159711cd0dSJens Freimann n->primary_device_dict, "id")); 29169711cd0dSJens Freimann if (!n->primary_device_id) { 29179711cd0dSJens Freimann warn_report("primary_device_id not set"); 29189711cd0dSJens Freimann } 29199711cd0dSJens Freimann } 29209711cd0dSJens Freimann 29219711cd0dSJens Freimann out: 29229711cd0dSJens Freimann if (match_found && hide) { 29239711cd0dSJens Freimann return 1; 29249711cd0dSJens Freimann } else if (match_found && !hide) { 29259711cd0dSJens Freimann return 0; 29269711cd0dSJens Freimann } else { 29279711cd0dSJens Freimann return -1; 29289711cd0dSJens Freimann } 29299711cd0dSJens Freimann } 29309711cd0dSJens Freimann 2931e6f746b3SAndreas Färber static void virtio_net_device_realize(DeviceState *dev, Error **errp) 293217ec5a86SKONRAD Frederic { 2933e6f746b3SAndreas Färber VirtIODevice *vdev = VIRTIO_DEVICE(dev); 2934284a32f0SAndreas Färber VirtIONet *n = VIRTIO_NET(dev); 2935284a32f0SAndreas Färber NetClientState *nc; 29361773d9eeSKONRAD Frederic int i; 293717ec5a86SKONRAD Frederic 2938a93e599dSMaxime Coquelin if (n->net_conf.mtu) { 2939127833eeSJason Baron n->host_features |= (1ULL << VIRTIO_NET_F_MTU); 2940a93e599dSMaxime Coquelin } 2941a93e599dSMaxime Coquelin 29429473939eSJason Baron if (n->net_conf.duplex_str) { 29439473939eSJason Baron if (strncmp(n->net_conf.duplex_str, "half", 5) == 0) { 29449473939eSJason Baron n->net_conf.duplex = DUPLEX_HALF; 29459473939eSJason Baron } else if (strncmp(n->net_conf.duplex_str, "full", 5) == 0) { 29469473939eSJason Baron n->net_conf.duplex = DUPLEX_FULL; 29479473939eSJason Baron } else { 29489473939eSJason Baron error_setg(errp, "'duplex' must be 'half' or 'full'"); 29499473939eSJason Baron } 29509473939eSJason Baron n->host_features |= (1ULL << VIRTIO_NET_F_SPEED_DUPLEX); 29519473939eSJason Baron } else { 29529473939eSJason Baron n->net_conf.duplex = DUPLEX_UNKNOWN; 29539473939eSJason Baron } 29549473939eSJason Baron 29559473939eSJason Baron if (n->net_conf.speed < SPEED_UNKNOWN) { 29569473939eSJason Baron error_setg(errp, "'speed' must be between 0 and INT_MAX"); 29579473939eSJason Baron } else if (n->net_conf.speed >= 0) { 29589473939eSJason Baron n->host_features |= (1ULL << VIRTIO_NET_F_SPEED_DUPLEX); 29599473939eSJason Baron } 29609473939eSJason Baron 29619711cd0dSJens Freimann if (n->failover) { 29629711cd0dSJens Freimann n->primary_listener.should_be_hidden = 29639711cd0dSJens Freimann virtio_net_primary_should_be_hidden; 29649711cd0dSJens Freimann atomic_set(&n->primary_should_be_hidden, true); 29659711cd0dSJens Freimann device_listener_register(&n->primary_listener); 29669711cd0dSJens Freimann n->migration_state.notify = virtio_net_migration_state_notifier; 29679711cd0dSJens Freimann add_migration_state_change_notifier(&n->migration_state); 29689711cd0dSJens Freimann n->host_features |= (1ULL << VIRTIO_NET_F_STANDBY); 29699711cd0dSJens Freimann } 29709711cd0dSJens Freimann 2971da3e8a23SShannon Zhao virtio_net_set_config_size(n, n->host_features); 2972284a32f0SAndreas Färber virtio_init(vdev, "virtio-net", VIRTIO_ID_NET, n->config_size); 297317ec5a86SKONRAD Frederic 29741c0fbfa3SMichael S. Tsirkin /* 29751c0fbfa3SMichael S. Tsirkin * We set a lower limit on RX queue size to what it always was. 29761c0fbfa3SMichael S. Tsirkin * Guests that want a smaller ring can always resize it without 29771c0fbfa3SMichael S. Tsirkin * help from us (using virtio 1 and up). 29781c0fbfa3SMichael S. Tsirkin */ 29791c0fbfa3SMichael S. Tsirkin if (n->net_conf.rx_queue_size < VIRTIO_NET_RX_QUEUE_MIN_SIZE || 29801c0fbfa3SMichael S. Tsirkin n->net_conf.rx_queue_size > VIRTQUEUE_MAX_SIZE || 29815f997fd1SMichal Privoznik !is_power_of_2(n->net_conf.rx_queue_size)) { 29821c0fbfa3SMichael S. Tsirkin error_setg(errp, "Invalid rx_queue_size (= %" PRIu16 "), " 29831c0fbfa3SMichael S. Tsirkin "must be a power of 2 between %d and %d.", 29841c0fbfa3SMichael S. Tsirkin n->net_conf.rx_queue_size, VIRTIO_NET_RX_QUEUE_MIN_SIZE, 29851c0fbfa3SMichael S. Tsirkin VIRTQUEUE_MAX_SIZE); 29861c0fbfa3SMichael S. Tsirkin virtio_cleanup(vdev); 29871c0fbfa3SMichael S. Tsirkin return; 29881c0fbfa3SMichael S. Tsirkin } 29891c0fbfa3SMichael S. Tsirkin 29909b02e161SWei Wang if (n->net_conf.tx_queue_size < VIRTIO_NET_TX_QUEUE_MIN_SIZE || 29919b02e161SWei Wang n->net_conf.tx_queue_size > VIRTQUEUE_MAX_SIZE || 29929b02e161SWei Wang !is_power_of_2(n->net_conf.tx_queue_size)) { 29939b02e161SWei Wang error_setg(errp, "Invalid tx_queue_size (= %" PRIu16 "), " 29949b02e161SWei Wang "must be a power of 2 between %d and %d", 29959b02e161SWei Wang n->net_conf.tx_queue_size, VIRTIO_NET_TX_QUEUE_MIN_SIZE, 29969b02e161SWei Wang VIRTQUEUE_MAX_SIZE); 29979b02e161SWei Wang virtio_cleanup(vdev); 29989b02e161SWei Wang return; 29999b02e161SWei Wang } 30009b02e161SWei Wang 3001575a1c0eSJiri Pirko n->max_queues = MAX(n->nic_conf.peers.queues, 1); 300287b3bd1cSJason Wang if (n->max_queues * 2 + 1 > VIRTIO_QUEUE_MAX) { 30037e0e736eSJason Wang error_setg(errp, "Invalid number of queues (= %" PRIu32 "), " 3004631b22eaSStefan Weil "must be a positive integer less than %d.", 300587b3bd1cSJason Wang n->max_queues, (VIRTIO_QUEUE_MAX - 1) / 2); 30067e0e736eSJason Wang virtio_cleanup(vdev); 30077e0e736eSJason Wang return; 30087e0e736eSJason Wang } 30096e790746SPaolo Bonzini n->vqs = g_malloc0(sizeof(VirtIONetQueue) * n->max_queues); 30106e790746SPaolo Bonzini n->curr_queues = 1; 30111773d9eeSKONRAD Frederic n->tx_timeout = n->net_conf.txtimer; 30126e790746SPaolo Bonzini 30131773d9eeSKONRAD Frederic if (n->net_conf.tx && strcmp(n->net_conf.tx, "timer") 30141773d9eeSKONRAD Frederic && strcmp(n->net_conf.tx, "bh")) { 30150765691eSMarkus Armbruster warn_report("virtio-net: " 30166e790746SPaolo Bonzini "Unknown option tx=%s, valid options: \"timer\" \"bh\"", 30171773d9eeSKONRAD Frederic n->net_conf.tx); 30180765691eSMarkus Armbruster error_printf("Defaulting to \"bh\""); 30196e790746SPaolo Bonzini } 30206e790746SPaolo Bonzini 30212eef278bSMichael S. Tsirkin n->net_conf.tx_queue_size = MIN(virtio_net_max_tx_queue_size(n), 30222eef278bSMichael S. Tsirkin n->net_conf.tx_queue_size); 30239b02e161SWei Wang 3024da51a335SJason Wang for (i = 0; i < n->max_queues; i++) { 3025f9d6dbf0SWen Congyang virtio_net_add_queue(n, i); 3026da51a335SJason Wang } 3027da51a335SJason Wang 302817a0ca55SKONRAD Frederic n->ctrl_vq = virtio_add_queue(vdev, 64, virtio_net_handle_ctrl); 30291773d9eeSKONRAD Frederic qemu_macaddr_default_if_unset(&n->nic_conf.macaddr); 30301773d9eeSKONRAD Frederic memcpy(&n->mac[0], &n->nic_conf.macaddr, sizeof(n->mac)); 30316e790746SPaolo Bonzini n->status = VIRTIO_NET_S_LINK_UP; 30329d8c6a25SDr. David Alan Gilbert qemu_announce_timer_reset(&n->announce_timer, migrate_announce_params(), 30339d8c6a25SDr. David Alan Gilbert QEMU_CLOCK_VIRTUAL, 3034f57fcf70SJason Wang virtio_net_announce_timer, n); 3035b2c929f0SDr. David Alan Gilbert n->announce_timer.round = 0; 30366e790746SPaolo Bonzini 30378a253ec2SKONRAD Frederic if (n->netclient_type) { 30388a253ec2SKONRAD Frederic /* 30398a253ec2SKONRAD Frederic * Happen when virtio_net_set_netclient_name has been called. 30408a253ec2SKONRAD Frederic */ 30418a253ec2SKONRAD Frederic n->nic = qemu_new_nic(&net_virtio_info, &n->nic_conf, 30428a253ec2SKONRAD Frederic n->netclient_type, n->netclient_name, n); 30438a253ec2SKONRAD Frederic } else { 30441773d9eeSKONRAD Frederic n->nic = qemu_new_nic(&net_virtio_info, &n->nic_conf, 3045284a32f0SAndreas Färber object_get_typename(OBJECT(dev)), dev->id, n); 30468a253ec2SKONRAD Frederic } 30478a253ec2SKONRAD Frederic 30486e790746SPaolo Bonzini peer_test_vnet_hdr(n); 30496e790746SPaolo Bonzini if (peer_has_vnet_hdr(n)) { 30506e790746SPaolo Bonzini for (i = 0; i < n->max_queues; i++) { 3051d6085e3aSStefan Hajnoczi qemu_using_vnet_hdr(qemu_get_subqueue(n->nic, i)->peer, true); 30526e790746SPaolo Bonzini } 30536e790746SPaolo Bonzini n->host_hdr_len = sizeof(struct virtio_net_hdr); 30546e790746SPaolo Bonzini } else { 30556e790746SPaolo Bonzini n->host_hdr_len = 0; 30566e790746SPaolo Bonzini } 30576e790746SPaolo Bonzini 30581773d9eeSKONRAD Frederic qemu_format_nic_info_str(qemu_get_queue(n->nic), n->nic_conf.macaddr.a); 30596e790746SPaolo Bonzini 30606e790746SPaolo Bonzini n->vqs[0].tx_waiting = 0; 30611773d9eeSKONRAD Frederic n->tx_burst = n->net_conf.txburst; 3062bb9d17f8SCornelia Huck virtio_net_set_mrg_rx_bufs(n, 0, 0); 30636e790746SPaolo Bonzini n->promisc = 1; /* for compatibility */ 30646e790746SPaolo Bonzini 30656e790746SPaolo Bonzini n->mac_table.macs = g_malloc0(MAC_TABLE_ENTRIES * ETH_ALEN); 30666e790746SPaolo Bonzini 30676e790746SPaolo Bonzini n->vlans = g_malloc0(MAX_VLAN >> 3); 30686e790746SPaolo Bonzini 3069b1be4280SAmos Kong nc = qemu_get_queue(n->nic); 3070b1be4280SAmos Kong nc->rxfilter_notify_enabled = 1; 3071b1be4280SAmos Kong 30722974e916SYuri Benditovich QTAILQ_INIT(&n->rsc_chains); 3073284a32f0SAndreas Färber n->qdev = dev; 307417ec5a86SKONRAD Frederic } 307517ec5a86SKONRAD Frederic 3076306ec6c3SAndreas Färber static void virtio_net_device_unrealize(DeviceState *dev, Error **errp) 307717ec5a86SKONRAD Frederic { 3078306ec6c3SAndreas Färber VirtIODevice *vdev = VIRTIO_DEVICE(dev); 3079306ec6c3SAndreas Färber VirtIONet *n = VIRTIO_NET(dev); 3080f9d6dbf0SWen Congyang int i, max_queues; 308117ec5a86SKONRAD Frederic 308217ec5a86SKONRAD Frederic /* This will stop vhost backend if appropriate. */ 308317ec5a86SKONRAD Frederic virtio_net_set_status(vdev, 0); 308417ec5a86SKONRAD Frederic 30858a253ec2SKONRAD Frederic g_free(n->netclient_name); 30868a253ec2SKONRAD Frederic n->netclient_name = NULL; 30878a253ec2SKONRAD Frederic g_free(n->netclient_type); 30888a253ec2SKONRAD Frederic n->netclient_type = NULL; 30898a253ec2SKONRAD Frederic 309017ec5a86SKONRAD Frederic g_free(n->mac_table.macs); 309117ec5a86SKONRAD Frederic g_free(n->vlans); 309217ec5a86SKONRAD Frederic 30939711cd0dSJens Freimann if (n->failover) { 30949711cd0dSJens Freimann g_free(n->primary_device_id); 30959711cd0dSJens Freimann g_free(n->standby_id); 30969711cd0dSJens Freimann qobject_unref(n->primary_device_dict); 30979711cd0dSJens Freimann n->primary_device_dict = NULL; 30989711cd0dSJens Freimann } 30999711cd0dSJens Freimann 3100f9d6dbf0SWen Congyang max_queues = n->multiqueue ? n->max_queues : 1; 3101f9d6dbf0SWen Congyang for (i = 0; i < max_queues; i++) { 3102f9d6dbf0SWen Congyang virtio_net_del_queue(n, i); 310317ec5a86SKONRAD Frederic } 310417ec5a86SKONRAD Frederic 3105944458b6SDr. David Alan Gilbert qemu_announce_timer_del(&n->announce_timer, false); 310617ec5a86SKONRAD Frederic g_free(n->vqs); 310717ec5a86SKONRAD Frederic qemu_del_nic(n->nic); 31082974e916SYuri Benditovich virtio_net_rsc_cleanup(n); 31096a1a8cc7SKONRAD Frederic virtio_cleanup(vdev); 311017ec5a86SKONRAD Frederic } 311117ec5a86SKONRAD Frederic 311217ec5a86SKONRAD Frederic static void virtio_net_instance_init(Object *obj) 311317ec5a86SKONRAD Frederic { 311417ec5a86SKONRAD Frederic VirtIONet *n = VIRTIO_NET(obj); 311517ec5a86SKONRAD Frederic 311617ec5a86SKONRAD Frederic /* 311717ec5a86SKONRAD Frederic * The default config_size is sizeof(struct virtio_net_config). 311817ec5a86SKONRAD Frederic * Can be overriden with virtio_net_set_config_size. 311917ec5a86SKONRAD Frederic */ 312017ec5a86SKONRAD Frederic n->config_size = sizeof(struct virtio_net_config); 3121aa4197c3SGonglei device_add_bootindex_property(obj, &n->nic_conf.bootindex, 3122aa4197c3SGonglei "bootindex", "/ethernet-phy@0", 3123aa4197c3SGonglei DEVICE(n), NULL); 312417ec5a86SKONRAD Frederic } 312517ec5a86SKONRAD Frederic 312644b1ff31SDr. David Alan Gilbert static int virtio_net_pre_save(void *opaque) 31274d45dcfbSHalil Pasic { 31284d45dcfbSHalil Pasic VirtIONet *n = opaque; 31294d45dcfbSHalil Pasic 31304d45dcfbSHalil Pasic /* At this point, backend must be stopped, otherwise 31314d45dcfbSHalil Pasic * it might keep writing to memory. */ 31324d45dcfbSHalil Pasic assert(!n->vhost_started); 313344b1ff31SDr. David Alan Gilbert 313444b1ff31SDr. David Alan Gilbert return 0; 31354d45dcfbSHalil Pasic } 31364d45dcfbSHalil Pasic 31379711cd0dSJens Freimann static bool primary_unplug_pending(void *opaque) 31389711cd0dSJens Freimann { 31399711cd0dSJens Freimann DeviceState *dev = opaque; 31409711cd0dSJens Freimann VirtIODevice *vdev = VIRTIO_DEVICE(dev); 31419711cd0dSJens Freimann VirtIONet *n = VIRTIO_NET(vdev); 31429711cd0dSJens Freimann 3143284f42a5SJens Freimann if (!virtio_vdev_has_feature(vdev, VIRTIO_NET_F_STANDBY)) { 3144284f42a5SJens Freimann return false; 3145284f42a5SJens Freimann } 31469711cd0dSJens Freimann return n->primary_dev ? n->primary_dev->pending_deleted_event : false; 31479711cd0dSJens Freimann } 31489711cd0dSJens Freimann 31499711cd0dSJens Freimann static bool dev_unplug_pending(void *opaque) 31509711cd0dSJens Freimann { 31519711cd0dSJens Freimann DeviceState *dev = opaque; 31529711cd0dSJens Freimann VirtioDeviceClass *vdc = VIRTIO_DEVICE_GET_CLASS(dev); 31539711cd0dSJens Freimann 31549711cd0dSJens Freimann return vdc->primary_unplug_pending(dev); 31559711cd0dSJens Freimann } 31569711cd0dSJens Freimann 31574d45dcfbSHalil Pasic static const VMStateDescription vmstate_virtio_net = { 31584d45dcfbSHalil Pasic .name = "virtio-net", 31594d45dcfbSHalil Pasic .minimum_version_id = VIRTIO_NET_VM_VERSION, 31604d45dcfbSHalil Pasic .version_id = VIRTIO_NET_VM_VERSION, 31614d45dcfbSHalil Pasic .fields = (VMStateField[]) { 31624d45dcfbSHalil Pasic VMSTATE_VIRTIO_DEVICE, 31634d45dcfbSHalil Pasic VMSTATE_END_OF_LIST() 31644d45dcfbSHalil Pasic }, 31654d45dcfbSHalil Pasic .pre_save = virtio_net_pre_save, 31669711cd0dSJens Freimann .dev_unplug_pending = dev_unplug_pending, 31674d45dcfbSHalil Pasic }; 3168290c2428SDr. David Alan Gilbert 316917ec5a86SKONRAD Frederic static Property virtio_net_properties[] = { 3170127833eeSJason Baron DEFINE_PROP_BIT64("csum", VirtIONet, host_features, 3171127833eeSJason Baron VIRTIO_NET_F_CSUM, true), 3172127833eeSJason Baron DEFINE_PROP_BIT64("guest_csum", VirtIONet, host_features, 317387108bb2SShannon Zhao VIRTIO_NET_F_GUEST_CSUM, true), 3174127833eeSJason Baron DEFINE_PROP_BIT64("gso", VirtIONet, host_features, VIRTIO_NET_F_GSO, true), 3175127833eeSJason Baron DEFINE_PROP_BIT64("guest_tso4", VirtIONet, host_features, 317687108bb2SShannon Zhao VIRTIO_NET_F_GUEST_TSO4, true), 3177127833eeSJason Baron DEFINE_PROP_BIT64("guest_tso6", VirtIONet, host_features, 317887108bb2SShannon Zhao VIRTIO_NET_F_GUEST_TSO6, true), 3179127833eeSJason Baron DEFINE_PROP_BIT64("guest_ecn", VirtIONet, host_features, 318087108bb2SShannon Zhao VIRTIO_NET_F_GUEST_ECN, true), 3181127833eeSJason Baron DEFINE_PROP_BIT64("guest_ufo", VirtIONet, host_features, 318287108bb2SShannon Zhao VIRTIO_NET_F_GUEST_UFO, true), 3183127833eeSJason Baron DEFINE_PROP_BIT64("guest_announce", VirtIONet, host_features, 318487108bb2SShannon Zhao VIRTIO_NET_F_GUEST_ANNOUNCE, true), 3185127833eeSJason Baron DEFINE_PROP_BIT64("host_tso4", VirtIONet, host_features, 318687108bb2SShannon Zhao VIRTIO_NET_F_HOST_TSO4, true), 3187127833eeSJason Baron DEFINE_PROP_BIT64("host_tso6", VirtIONet, host_features, 318887108bb2SShannon Zhao VIRTIO_NET_F_HOST_TSO6, true), 3189127833eeSJason Baron DEFINE_PROP_BIT64("host_ecn", VirtIONet, host_features, 319087108bb2SShannon Zhao VIRTIO_NET_F_HOST_ECN, true), 3191127833eeSJason Baron DEFINE_PROP_BIT64("host_ufo", VirtIONet, host_features, 319287108bb2SShannon Zhao VIRTIO_NET_F_HOST_UFO, true), 3193127833eeSJason Baron DEFINE_PROP_BIT64("mrg_rxbuf", VirtIONet, host_features, 319487108bb2SShannon Zhao VIRTIO_NET_F_MRG_RXBUF, true), 3195127833eeSJason Baron DEFINE_PROP_BIT64("status", VirtIONet, host_features, 319687108bb2SShannon Zhao VIRTIO_NET_F_STATUS, true), 3197127833eeSJason Baron DEFINE_PROP_BIT64("ctrl_vq", VirtIONet, host_features, 319887108bb2SShannon Zhao VIRTIO_NET_F_CTRL_VQ, true), 3199127833eeSJason Baron DEFINE_PROP_BIT64("ctrl_rx", VirtIONet, host_features, 320087108bb2SShannon Zhao VIRTIO_NET_F_CTRL_RX, true), 3201127833eeSJason Baron DEFINE_PROP_BIT64("ctrl_vlan", VirtIONet, host_features, 320287108bb2SShannon Zhao VIRTIO_NET_F_CTRL_VLAN, true), 3203127833eeSJason Baron DEFINE_PROP_BIT64("ctrl_rx_extra", VirtIONet, host_features, 320487108bb2SShannon Zhao VIRTIO_NET_F_CTRL_RX_EXTRA, true), 3205127833eeSJason Baron DEFINE_PROP_BIT64("ctrl_mac_addr", VirtIONet, host_features, 320687108bb2SShannon Zhao VIRTIO_NET_F_CTRL_MAC_ADDR, true), 3207127833eeSJason Baron DEFINE_PROP_BIT64("ctrl_guest_offloads", VirtIONet, host_features, 320887108bb2SShannon Zhao VIRTIO_NET_F_CTRL_GUEST_OFFLOADS, true), 3209127833eeSJason Baron DEFINE_PROP_BIT64("mq", VirtIONet, host_features, VIRTIO_NET_F_MQ, false), 32102974e916SYuri Benditovich DEFINE_PROP_BIT64("guest_rsc_ext", VirtIONet, host_features, 32112974e916SYuri Benditovich VIRTIO_NET_F_RSC_EXT, false), 32122974e916SYuri Benditovich DEFINE_PROP_UINT32("rsc_interval", VirtIONet, rsc_timeout, 32132974e916SYuri Benditovich VIRTIO_NET_RSC_DEFAULT_INTERVAL), 321417ec5a86SKONRAD Frederic DEFINE_NIC_PROPERTIES(VirtIONet, nic_conf), 321517ec5a86SKONRAD Frederic DEFINE_PROP_UINT32("x-txtimer", VirtIONet, net_conf.txtimer, 321617ec5a86SKONRAD Frederic TX_TIMER_INTERVAL), 321717ec5a86SKONRAD Frederic DEFINE_PROP_INT32("x-txburst", VirtIONet, net_conf.txburst, TX_BURST), 321817ec5a86SKONRAD Frederic DEFINE_PROP_STRING("tx", VirtIONet, net_conf.tx), 32191c0fbfa3SMichael S. Tsirkin DEFINE_PROP_UINT16("rx_queue_size", VirtIONet, net_conf.rx_queue_size, 32201c0fbfa3SMichael S. Tsirkin VIRTIO_NET_RX_QUEUE_DEFAULT_SIZE), 32219b02e161SWei Wang DEFINE_PROP_UINT16("tx_queue_size", VirtIONet, net_conf.tx_queue_size, 32229b02e161SWei Wang VIRTIO_NET_TX_QUEUE_DEFAULT_SIZE), 3223a93e599dSMaxime Coquelin DEFINE_PROP_UINT16("host_mtu", VirtIONet, net_conf.mtu, 0), 322475ebec11SMaxime Coquelin DEFINE_PROP_BOOL("x-mtu-bypass-backend", VirtIONet, mtu_bypass_backend, 322575ebec11SMaxime Coquelin true), 32269473939eSJason Baron DEFINE_PROP_INT32("speed", VirtIONet, net_conf.speed, SPEED_UNKNOWN), 32279473939eSJason Baron DEFINE_PROP_STRING("duplex", VirtIONet, net_conf.duplex_str), 32289711cd0dSJens Freimann DEFINE_PROP_BOOL("failover", VirtIONet, failover, false), 322917ec5a86SKONRAD Frederic DEFINE_PROP_END_OF_LIST(), 323017ec5a86SKONRAD Frederic }; 323117ec5a86SKONRAD Frederic 323217ec5a86SKONRAD Frederic static void virtio_net_class_init(ObjectClass *klass, void *data) 323317ec5a86SKONRAD Frederic { 323417ec5a86SKONRAD Frederic DeviceClass *dc = DEVICE_CLASS(klass); 323517ec5a86SKONRAD Frederic VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); 3236e6f746b3SAndreas Färber 323717ec5a86SKONRAD Frederic dc->props = virtio_net_properties; 3238290c2428SDr. David Alan Gilbert dc->vmsd = &vmstate_virtio_net; 3239125ee0edSMarcel Apfelbaum set_bit(DEVICE_CATEGORY_NETWORK, dc->categories); 3240e6f746b3SAndreas Färber vdc->realize = virtio_net_device_realize; 3241306ec6c3SAndreas Färber vdc->unrealize = virtio_net_device_unrealize; 324217ec5a86SKONRAD Frederic vdc->get_config = virtio_net_get_config; 324317ec5a86SKONRAD Frederic vdc->set_config = virtio_net_set_config; 324417ec5a86SKONRAD Frederic vdc->get_features = virtio_net_get_features; 324517ec5a86SKONRAD Frederic vdc->set_features = virtio_net_set_features; 324617ec5a86SKONRAD Frederic vdc->bad_features = virtio_net_bad_features; 324717ec5a86SKONRAD Frederic vdc->reset = virtio_net_reset; 324817ec5a86SKONRAD Frederic vdc->set_status = virtio_net_set_status; 324917ec5a86SKONRAD Frederic vdc->guest_notifier_mask = virtio_net_guest_notifier_mask; 325017ec5a86SKONRAD Frederic vdc->guest_notifier_pending = virtio_net_guest_notifier_pending; 32512a083ffdSMichael S. Tsirkin vdc->legacy_features |= (0x1 << VIRTIO_NET_F_GSO); 32527788c3f2SMikhail Sennikovsky vdc->post_load = virtio_net_post_load_virtio; 3253982b78c5SDr. David Alan Gilbert vdc->vmsd = &vmstate_virtio_net_device; 32549711cd0dSJens Freimann vdc->primary_unplug_pending = primary_unplug_pending; 325517ec5a86SKONRAD Frederic } 325617ec5a86SKONRAD Frederic 325717ec5a86SKONRAD Frederic static const TypeInfo virtio_net_info = { 325817ec5a86SKONRAD Frederic .name = TYPE_VIRTIO_NET, 325917ec5a86SKONRAD Frederic .parent = TYPE_VIRTIO_DEVICE, 326017ec5a86SKONRAD Frederic .instance_size = sizeof(VirtIONet), 326117ec5a86SKONRAD Frederic .instance_init = virtio_net_instance_init, 326217ec5a86SKONRAD Frederic .class_init = virtio_net_class_init, 326317ec5a86SKONRAD Frederic }; 326417ec5a86SKONRAD Frederic 326517ec5a86SKONRAD Frederic static void virtio_register_types(void) 326617ec5a86SKONRAD Frederic { 326717ec5a86SKONRAD Frederic type_register_static(&virtio_net_info); 326817ec5a86SKONRAD Frederic } 326917ec5a86SKONRAD Frederic 327017ec5a86SKONRAD Frederic type_init(virtio_register_types) 3271