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 7629711cd0dSJens Freimann n->primary_device_opts = qemu_opts_find(qemu_find_opts("device"), 7639711cd0dSJens Freimann n->primary_device_id); 7649711cd0dSJens Freimann if (n->primary_device_opts) { 7659711cd0dSJens Freimann n->primary_dev = qdev_device_add(n->primary_device_opts, &err); 7669711cd0dSJens Freimann if (err) { 7679711cd0dSJens Freimann qemu_opts_del(n->primary_device_opts); 7689711cd0dSJens Freimann } 7699711cd0dSJens Freimann if (n->primary_dev) { 7709711cd0dSJens Freimann n->primary_bus = n->primary_dev->parent_bus; 7719711cd0dSJens Freimann if (err) { 7729711cd0dSJens Freimann qdev_unplug(n->primary_dev, &err); 7739711cd0dSJens Freimann qdev_set_id(n->primary_dev, ""); 7749711cd0dSJens Freimann 7759711cd0dSJens Freimann } 7769711cd0dSJens Freimann } 7779711cd0dSJens Freimann } else { 7789711cd0dSJens Freimann error_setg(errp, "Primary device not found"); 7799711cd0dSJens Freimann error_append_hint(errp, "Virtio-net failover will not work. Make " 7809711cd0dSJens Freimann "sure primary device has parameter" 7819711cd0dSJens Freimann " failover_pair_id=<virtio-net-id>\n"); 7829711cd0dSJens Freimann } 7839711cd0dSJens Freimann if (err) { 7849711cd0dSJens Freimann error_propagate(errp, err); 7859711cd0dSJens Freimann } 7869711cd0dSJens Freimann } 7879711cd0dSJens Freimann 7889711cd0dSJens Freimann static int is_my_primary(void *opaque, QemuOpts *opts, Error **errp) 7899711cd0dSJens Freimann { 7909711cd0dSJens Freimann VirtIONet *n = opaque; 7919711cd0dSJens Freimann int ret = 0; 7929711cd0dSJens Freimann 7939711cd0dSJens Freimann const char *standby_id = qemu_opt_get(opts, "failover_pair_id"); 7949711cd0dSJens Freimann 7959711cd0dSJens Freimann if (standby_id != NULL && (g_strcmp0(standby_id, n->netclient_name) == 0)) { 7969711cd0dSJens Freimann n->primary_device_id = g_strdup(opts->id); 7979711cd0dSJens Freimann ret = 1; 7989711cd0dSJens Freimann } 7999711cd0dSJens Freimann 8009711cd0dSJens Freimann return ret; 8019711cd0dSJens Freimann } 8029711cd0dSJens Freimann 8039711cd0dSJens Freimann static DeviceState *virtio_net_find_primary(VirtIONet *n, Error **errp) 8049711cd0dSJens Freimann { 8059711cd0dSJens Freimann DeviceState *dev = NULL; 8069711cd0dSJens Freimann Error *err = NULL; 8079711cd0dSJens Freimann 8089711cd0dSJens Freimann if (qemu_opts_foreach(qemu_find_opts("device"), 8099711cd0dSJens Freimann is_my_primary, n, &err)) { 8109711cd0dSJens Freimann if (err) { 8119711cd0dSJens Freimann error_propagate(errp, err); 8129711cd0dSJens Freimann return NULL; 8139711cd0dSJens Freimann } 8149711cd0dSJens Freimann if (n->primary_device_id) { 8159711cd0dSJens Freimann dev = qdev_find_recursive(sysbus_get_default(), 8169711cd0dSJens Freimann n->primary_device_id); 8179711cd0dSJens Freimann } else { 8189711cd0dSJens Freimann error_setg(errp, "Primary device id not found"); 8199711cd0dSJens Freimann return NULL; 8209711cd0dSJens Freimann } 8219711cd0dSJens Freimann } 8229711cd0dSJens Freimann return dev; 8239711cd0dSJens Freimann } 8249711cd0dSJens Freimann 8259711cd0dSJens Freimann 8269711cd0dSJens Freimann 8279711cd0dSJens Freimann static DeviceState *virtio_connect_failover_devices(VirtIONet *n, 8289711cd0dSJens Freimann DeviceState *dev, 8299711cd0dSJens Freimann Error **errp) 8309711cd0dSJens Freimann { 8319711cd0dSJens Freimann DeviceState *prim_dev = NULL; 8329711cd0dSJens Freimann Error *err = NULL; 8339711cd0dSJens Freimann 8349711cd0dSJens Freimann prim_dev = virtio_net_find_primary(n, &err); 8359711cd0dSJens Freimann if (prim_dev) { 8369711cd0dSJens Freimann n->primary_device_id = g_strdup(prim_dev->id); 8379711cd0dSJens Freimann n->primary_device_opts = prim_dev->opts; 8389711cd0dSJens Freimann } else { 8399711cd0dSJens Freimann if (err) { 8409711cd0dSJens Freimann error_propagate(errp, err); 8419711cd0dSJens Freimann } 8429711cd0dSJens Freimann } 8439711cd0dSJens Freimann 8449711cd0dSJens Freimann return prim_dev; 8459711cd0dSJens Freimann } 8469711cd0dSJens Freimann 847d5aaa1b0SGerd Hoffmann static void virtio_net_set_features(VirtIODevice *vdev, uint64_t features) 8486e790746SPaolo Bonzini { 84917a0ca55SKONRAD Frederic VirtIONet *n = VIRTIO_NET(vdev); 8509711cd0dSJens Freimann Error *err = NULL; 8516e790746SPaolo Bonzini int i; 8526e790746SPaolo Bonzini 85375ebec11SMaxime Coquelin if (n->mtu_bypass_backend && 85475ebec11SMaxime Coquelin !virtio_has_feature(vdev->backend_features, VIRTIO_NET_F_MTU)) { 85575ebec11SMaxime Coquelin features &= ~(1ULL << VIRTIO_NET_F_MTU); 85675ebec11SMaxime Coquelin } 85775ebec11SMaxime Coquelin 858ef546f12SCornelia Huck virtio_net_set_multiqueue(n, 85995129d6fSCornelia Huck virtio_has_feature(features, VIRTIO_NET_F_MQ)); 8606e790746SPaolo Bonzini 861ef546f12SCornelia Huck virtio_net_set_mrg_rx_bufs(n, 86295129d6fSCornelia Huck virtio_has_feature(features, 863bb9d17f8SCornelia Huck VIRTIO_NET_F_MRG_RXBUF), 86495129d6fSCornelia Huck virtio_has_feature(features, 865bb9d17f8SCornelia Huck VIRTIO_F_VERSION_1)); 8666e790746SPaolo Bonzini 8672974e916SYuri Benditovich n->rsc4_enabled = virtio_has_feature(features, VIRTIO_NET_F_RSC_EXT) && 8682974e916SYuri Benditovich virtio_has_feature(features, VIRTIO_NET_F_GUEST_TSO4); 8692974e916SYuri Benditovich n->rsc6_enabled = virtio_has_feature(features, VIRTIO_NET_F_RSC_EXT) && 8702974e916SYuri Benditovich virtio_has_feature(features, VIRTIO_NET_F_GUEST_TSO6); 8712974e916SYuri Benditovich 8726e790746SPaolo Bonzini if (n->has_vnet_hdr) { 873644c9858SDmitry Fleytman n->curr_guest_offloads = 874644c9858SDmitry Fleytman virtio_net_guest_offloads_by_features(features); 875644c9858SDmitry Fleytman virtio_net_apply_guest_offloads(n); 8766e790746SPaolo Bonzini } 8776e790746SPaolo Bonzini 8786e790746SPaolo Bonzini for (i = 0; i < n->max_queues; i++) { 8796e790746SPaolo Bonzini NetClientState *nc = qemu_get_subqueue(n->nic, i); 8806e790746SPaolo Bonzini 881ed8b4afeSNikolay Nikolaev if (!get_vhost_net(nc->peer)) { 8826e790746SPaolo Bonzini continue; 8836e790746SPaolo Bonzini } 884ed8b4afeSNikolay Nikolaev vhost_net_ack_features(get_vhost_net(nc->peer), features); 8856e790746SPaolo Bonzini } 8860b1eaa88SStefan Fritsch 88795129d6fSCornelia Huck if (virtio_has_feature(features, VIRTIO_NET_F_CTRL_VLAN)) { 8880b1eaa88SStefan Fritsch memset(n->vlans, 0, MAX_VLAN >> 3); 8890b1eaa88SStefan Fritsch } else { 8900b1eaa88SStefan Fritsch memset(n->vlans, 0xff, MAX_VLAN >> 3); 8910b1eaa88SStefan Fritsch } 8929711cd0dSJens Freimann 8939711cd0dSJens Freimann if (virtio_has_feature(features, VIRTIO_NET_F_STANDBY)) { 8949711cd0dSJens Freimann qapi_event_send_failover_negotiated(n->netclient_name); 8959711cd0dSJens Freimann atomic_set(&n->primary_should_be_hidden, false); 8969711cd0dSJens Freimann failover_add_primary(n, &err); 8979711cd0dSJens Freimann if (err) { 8989711cd0dSJens Freimann n->primary_dev = virtio_connect_failover_devices(n, n->qdev, &err); 8999711cd0dSJens Freimann if (err) { 9009711cd0dSJens Freimann goto out_err; 9019711cd0dSJens Freimann } 9029711cd0dSJens Freimann failover_add_primary(n, &err); 9039711cd0dSJens Freimann if (err) { 9049711cd0dSJens Freimann goto out_err; 9059711cd0dSJens Freimann } 9069711cd0dSJens Freimann } 9079711cd0dSJens Freimann } 9089711cd0dSJens Freimann return; 9099711cd0dSJens Freimann 9109711cd0dSJens Freimann out_err: 9119711cd0dSJens Freimann if (err) { 9129711cd0dSJens Freimann warn_report_err(err); 9139711cd0dSJens Freimann } 9146e790746SPaolo Bonzini } 9156e790746SPaolo Bonzini 9166e790746SPaolo Bonzini static int virtio_net_handle_rx_mode(VirtIONet *n, uint8_t cmd, 9176e790746SPaolo Bonzini struct iovec *iov, unsigned int iov_cnt) 9186e790746SPaolo Bonzini { 9196e790746SPaolo Bonzini uint8_t on; 9206e790746SPaolo Bonzini size_t s; 921b1be4280SAmos Kong NetClientState *nc = qemu_get_queue(n->nic); 9226e790746SPaolo Bonzini 9236e790746SPaolo Bonzini s = iov_to_buf(iov, iov_cnt, 0, &on, sizeof(on)); 9246e790746SPaolo Bonzini if (s != sizeof(on)) { 9256e790746SPaolo Bonzini return VIRTIO_NET_ERR; 9266e790746SPaolo Bonzini } 9276e790746SPaolo Bonzini 9286e790746SPaolo Bonzini if (cmd == VIRTIO_NET_CTRL_RX_PROMISC) { 9296e790746SPaolo Bonzini n->promisc = on; 9306e790746SPaolo Bonzini } else if (cmd == VIRTIO_NET_CTRL_RX_ALLMULTI) { 9316e790746SPaolo Bonzini n->allmulti = on; 9326e790746SPaolo Bonzini } else if (cmd == VIRTIO_NET_CTRL_RX_ALLUNI) { 9336e790746SPaolo Bonzini n->alluni = on; 9346e790746SPaolo Bonzini } else if (cmd == VIRTIO_NET_CTRL_RX_NOMULTI) { 9356e790746SPaolo Bonzini n->nomulti = on; 9366e790746SPaolo Bonzini } else if (cmd == VIRTIO_NET_CTRL_RX_NOUNI) { 9376e790746SPaolo Bonzini n->nouni = on; 9386e790746SPaolo Bonzini } else if (cmd == VIRTIO_NET_CTRL_RX_NOBCAST) { 9396e790746SPaolo Bonzini n->nobcast = on; 9406e790746SPaolo Bonzini } else { 9416e790746SPaolo Bonzini return VIRTIO_NET_ERR; 9426e790746SPaolo Bonzini } 9436e790746SPaolo Bonzini 944b1be4280SAmos Kong rxfilter_notify(nc); 945b1be4280SAmos Kong 9466e790746SPaolo Bonzini return VIRTIO_NET_OK; 9476e790746SPaolo Bonzini } 9486e790746SPaolo Bonzini 949644c9858SDmitry Fleytman static int virtio_net_handle_offloads(VirtIONet *n, uint8_t cmd, 950644c9858SDmitry Fleytman struct iovec *iov, unsigned int iov_cnt) 951644c9858SDmitry Fleytman { 952644c9858SDmitry Fleytman VirtIODevice *vdev = VIRTIO_DEVICE(n); 953644c9858SDmitry Fleytman uint64_t offloads; 954644c9858SDmitry Fleytman size_t s; 955644c9858SDmitry Fleytman 95695129d6fSCornelia Huck if (!virtio_vdev_has_feature(vdev, VIRTIO_NET_F_CTRL_GUEST_OFFLOADS)) { 957644c9858SDmitry Fleytman return VIRTIO_NET_ERR; 958644c9858SDmitry Fleytman } 959644c9858SDmitry Fleytman 960644c9858SDmitry Fleytman s = iov_to_buf(iov, iov_cnt, 0, &offloads, sizeof(offloads)); 961644c9858SDmitry Fleytman if (s != sizeof(offloads)) { 962644c9858SDmitry Fleytman return VIRTIO_NET_ERR; 963644c9858SDmitry Fleytman } 964644c9858SDmitry Fleytman 965644c9858SDmitry Fleytman if (cmd == VIRTIO_NET_CTRL_GUEST_OFFLOADS_SET) { 966644c9858SDmitry Fleytman uint64_t supported_offloads; 967644c9858SDmitry Fleytman 968189ae6bbSJason Wang offloads = virtio_ldq_p(vdev, &offloads); 969189ae6bbSJason Wang 970644c9858SDmitry Fleytman if (!n->has_vnet_hdr) { 971644c9858SDmitry Fleytman return VIRTIO_NET_ERR; 972644c9858SDmitry Fleytman } 973644c9858SDmitry Fleytman 9742974e916SYuri Benditovich n->rsc4_enabled = virtio_has_feature(offloads, VIRTIO_NET_F_RSC_EXT) && 9752974e916SYuri Benditovich virtio_has_feature(offloads, VIRTIO_NET_F_GUEST_TSO4); 9762974e916SYuri Benditovich n->rsc6_enabled = virtio_has_feature(offloads, VIRTIO_NET_F_RSC_EXT) && 9772974e916SYuri Benditovich virtio_has_feature(offloads, VIRTIO_NET_F_GUEST_TSO6); 9782974e916SYuri Benditovich virtio_clear_feature(&offloads, VIRTIO_NET_F_RSC_EXT); 9792974e916SYuri Benditovich 980644c9858SDmitry Fleytman supported_offloads = virtio_net_supported_guest_offloads(n); 981644c9858SDmitry Fleytman if (offloads & ~supported_offloads) { 982644c9858SDmitry Fleytman return VIRTIO_NET_ERR; 983644c9858SDmitry Fleytman } 984644c9858SDmitry Fleytman 985644c9858SDmitry Fleytman n->curr_guest_offloads = offloads; 986644c9858SDmitry Fleytman virtio_net_apply_guest_offloads(n); 987644c9858SDmitry Fleytman 988644c9858SDmitry Fleytman return VIRTIO_NET_OK; 989644c9858SDmitry Fleytman } else { 990644c9858SDmitry Fleytman return VIRTIO_NET_ERR; 991644c9858SDmitry Fleytman } 992644c9858SDmitry Fleytman } 993644c9858SDmitry Fleytman 9946e790746SPaolo Bonzini static int virtio_net_handle_mac(VirtIONet *n, uint8_t cmd, 9956e790746SPaolo Bonzini struct iovec *iov, unsigned int iov_cnt) 9966e790746SPaolo Bonzini { 9971399c60dSRusty Russell VirtIODevice *vdev = VIRTIO_DEVICE(n); 9986e790746SPaolo Bonzini struct virtio_net_ctrl_mac mac_data; 9996e790746SPaolo Bonzini size_t s; 1000b1be4280SAmos Kong NetClientState *nc = qemu_get_queue(n->nic); 10016e790746SPaolo Bonzini 10026e790746SPaolo Bonzini if (cmd == VIRTIO_NET_CTRL_MAC_ADDR_SET) { 10036e790746SPaolo Bonzini if (iov_size(iov, iov_cnt) != sizeof(n->mac)) { 10046e790746SPaolo Bonzini return VIRTIO_NET_ERR; 10056e790746SPaolo Bonzini } 10066e790746SPaolo Bonzini s = iov_to_buf(iov, iov_cnt, 0, &n->mac, sizeof(n->mac)); 10076e790746SPaolo Bonzini assert(s == sizeof(n->mac)); 10086e790746SPaolo Bonzini qemu_format_nic_info_str(qemu_get_queue(n->nic), n->mac); 1009b1be4280SAmos Kong rxfilter_notify(nc); 1010b1be4280SAmos Kong 10116e790746SPaolo Bonzini return VIRTIO_NET_OK; 10126e790746SPaolo Bonzini } 10136e790746SPaolo Bonzini 10146e790746SPaolo Bonzini if (cmd != VIRTIO_NET_CTRL_MAC_TABLE_SET) { 10156e790746SPaolo Bonzini return VIRTIO_NET_ERR; 10166e790746SPaolo Bonzini } 10176e790746SPaolo Bonzini 1018cae2e556SAmos Kong int in_use = 0; 1019cae2e556SAmos Kong int first_multi = 0; 1020cae2e556SAmos Kong uint8_t uni_overflow = 0; 1021cae2e556SAmos Kong uint8_t multi_overflow = 0; 1022cae2e556SAmos Kong uint8_t *macs = g_malloc0(MAC_TABLE_ENTRIES * ETH_ALEN); 10236e790746SPaolo Bonzini 10246e790746SPaolo Bonzini s = iov_to_buf(iov, iov_cnt, 0, &mac_data.entries, 10256e790746SPaolo Bonzini sizeof(mac_data.entries)); 10261399c60dSRusty Russell mac_data.entries = virtio_ldl_p(vdev, &mac_data.entries); 10276e790746SPaolo Bonzini if (s != sizeof(mac_data.entries)) { 1028b1be4280SAmos Kong goto error; 10296e790746SPaolo Bonzini } 10306e790746SPaolo Bonzini iov_discard_front(&iov, &iov_cnt, s); 10316e790746SPaolo Bonzini 10326e790746SPaolo Bonzini if (mac_data.entries * ETH_ALEN > iov_size(iov, iov_cnt)) { 1033b1be4280SAmos Kong goto error; 10346e790746SPaolo Bonzini } 10356e790746SPaolo Bonzini 10366e790746SPaolo Bonzini if (mac_data.entries <= MAC_TABLE_ENTRIES) { 1037cae2e556SAmos Kong s = iov_to_buf(iov, iov_cnt, 0, macs, 10386e790746SPaolo Bonzini mac_data.entries * ETH_ALEN); 10396e790746SPaolo Bonzini if (s != mac_data.entries * ETH_ALEN) { 1040b1be4280SAmos Kong goto error; 10416e790746SPaolo Bonzini } 1042cae2e556SAmos Kong in_use += mac_data.entries; 10436e790746SPaolo Bonzini } else { 1044cae2e556SAmos Kong uni_overflow = 1; 10456e790746SPaolo Bonzini } 10466e790746SPaolo Bonzini 10476e790746SPaolo Bonzini iov_discard_front(&iov, &iov_cnt, mac_data.entries * ETH_ALEN); 10486e790746SPaolo Bonzini 1049cae2e556SAmos Kong first_multi = in_use; 10506e790746SPaolo Bonzini 10516e790746SPaolo Bonzini s = iov_to_buf(iov, iov_cnt, 0, &mac_data.entries, 10526e790746SPaolo Bonzini sizeof(mac_data.entries)); 10531399c60dSRusty Russell mac_data.entries = virtio_ldl_p(vdev, &mac_data.entries); 10546e790746SPaolo Bonzini if (s != sizeof(mac_data.entries)) { 1055b1be4280SAmos Kong goto error; 10566e790746SPaolo Bonzini } 10576e790746SPaolo Bonzini 10586e790746SPaolo Bonzini iov_discard_front(&iov, &iov_cnt, s); 10596e790746SPaolo Bonzini 10606e790746SPaolo Bonzini if (mac_data.entries * ETH_ALEN != iov_size(iov, iov_cnt)) { 1061b1be4280SAmos Kong goto error; 10626e790746SPaolo Bonzini } 10636e790746SPaolo Bonzini 1064edc24385SMichael S. Tsirkin if (mac_data.entries <= MAC_TABLE_ENTRIES - in_use) { 1065cae2e556SAmos Kong s = iov_to_buf(iov, iov_cnt, 0, &macs[in_use * ETH_ALEN], 10666e790746SPaolo Bonzini mac_data.entries * ETH_ALEN); 10676e790746SPaolo Bonzini if (s != mac_data.entries * ETH_ALEN) { 1068b1be4280SAmos Kong goto error; 10696e790746SPaolo Bonzini } 1070cae2e556SAmos Kong in_use += mac_data.entries; 10716e790746SPaolo Bonzini } else { 1072cae2e556SAmos Kong multi_overflow = 1; 10736e790746SPaolo Bonzini } 10746e790746SPaolo Bonzini 1075cae2e556SAmos Kong n->mac_table.in_use = in_use; 1076cae2e556SAmos Kong n->mac_table.first_multi = first_multi; 1077cae2e556SAmos Kong n->mac_table.uni_overflow = uni_overflow; 1078cae2e556SAmos Kong n->mac_table.multi_overflow = multi_overflow; 1079cae2e556SAmos Kong memcpy(n->mac_table.macs, macs, MAC_TABLE_ENTRIES * ETH_ALEN); 1080cae2e556SAmos Kong g_free(macs); 1081b1be4280SAmos Kong rxfilter_notify(nc); 1082b1be4280SAmos Kong 10836e790746SPaolo Bonzini return VIRTIO_NET_OK; 1084b1be4280SAmos Kong 1085b1be4280SAmos Kong error: 1086cae2e556SAmos Kong g_free(macs); 1087b1be4280SAmos Kong return VIRTIO_NET_ERR; 10886e790746SPaolo Bonzini } 10896e790746SPaolo Bonzini 10906e790746SPaolo Bonzini static int virtio_net_handle_vlan_table(VirtIONet *n, uint8_t cmd, 10916e790746SPaolo Bonzini struct iovec *iov, unsigned int iov_cnt) 10926e790746SPaolo Bonzini { 10931399c60dSRusty Russell VirtIODevice *vdev = VIRTIO_DEVICE(n); 10946e790746SPaolo Bonzini uint16_t vid; 10956e790746SPaolo Bonzini size_t s; 1096b1be4280SAmos Kong NetClientState *nc = qemu_get_queue(n->nic); 10976e790746SPaolo Bonzini 10986e790746SPaolo Bonzini s = iov_to_buf(iov, iov_cnt, 0, &vid, sizeof(vid)); 10991399c60dSRusty Russell vid = virtio_lduw_p(vdev, &vid); 11006e790746SPaolo Bonzini if (s != sizeof(vid)) { 11016e790746SPaolo Bonzini return VIRTIO_NET_ERR; 11026e790746SPaolo Bonzini } 11036e790746SPaolo Bonzini 11046e790746SPaolo Bonzini if (vid >= MAX_VLAN) 11056e790746SPaolo Bonzini return VIRTIO_NET_ERR; 11066e790746SPaolo Bonzini 11076e790746SPaolo Bonzini if (cmd == VIRTIO_NET_CTRL_VLAN_ADD) 11086e790746SPaolo Bonzini n->vlans[vid >> 5] |= (1U << (vid & 0x1f)); 11096e790746SPaolo Bonzini else if (cmd == VIRTIO_NET_CTRL_VLAN_DEL) 11106e790746SPaolo Bonzini n->vlans[vid >> 5] &= ~(1U << (vid & 0x1f)); 11116e790746SPaolo Bonzini else 11126e790746SPaolo Bonzini return VIRTIO_NET_ERR; 11136e790746SPaolo Bonzini 1114b1be4280SAmos Kong rxfilter_notify(nc); 1115b1be4280SAmos Kong 11166e790746SPaolo Bonzini return VIRTIO_NET_OK; 11176e790746SPaolo Bonzini } 11186e790746SPaolo Bonzini 1119f57fcf70SJason Wang static int virtio_net_handle_announce(VirtIONet *n, uint8_t cmd, 1120f57fcf70SJason Wang struct iovec *iov, unsigned int iov_cnt) 1121f57fcf70SJason Wang { 11229d8c6a25SDr. David Alan Gilbert trace_virtio_net_handle_announce(n->announce_timer.round); 1123f57fcf70SJason Wang if (cmd == VIRTIO_NET_CTRL_ANNOUNCE_ACK && 1124f57fcf70SJason Wang n->status & VIRTIO_NET_S_ANNOUNCE) { 1125f57fcf70SJason Wang n->status &= ~VIRTIO_NET_S_ANNOUNCE; 11269d8c6a25SDr. David Alan Gilbert if (n->announce_timer.round) { 11279d8c6a25SDr. David Alan Gilbert qemu_announce_timer_step(&n->announce_timer); 1128f57fcf70SJason Wang } 1129f57fcf70SJason Wang return VIRTIO_NET_OK; 1130f57fcf70SJason Wang } else { 1131f57fcf70SJason Wang return VIRTIO_NET_ERR; 1132f57fcf70SJason Wang } 1133f57fcf70SJason Wang } 1134f57fcf70SJason Wang 11356e790746SPaolo Bonzini static int virtio_net_handle_mq(VirtIONet *n, uint8_t cmd, 11366e790746SPaolo Bonzini struct iovec *iov, unsigned int iov_cnt) 11376e790746SPaolo Bonzini { 113817a0ca55SKONRAD Frederic VirtIODevice *vdev = VIRTIO_DEVICE(n); 11396e790746SPaolo Bonzini struct virtio_net_ctrl_mq mq; 11406e790746SPaolo Bonzini size_t s; 11416e790746SPaolo Bonzini uint16_t queues; 11426e790746SPaolo Bonzini 11436e790746SPaolo Bonzini s = iov_to_buf(iov, iov_cnt, 0, &mq, sizeof(mq)); 11446e790746SPaolo Bonzini if (s != sizeof(mq)) { 11456e790746SPaolo Bonzini return VIRTIO_NET_ERR; 11466e790746SPaolo Bonzini } 11476e790746SPaolo Bonzini 11486e790746SPaolo Bonzini if (cmd != VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET) { 11496e790746SPaolo Bonzini return VIRTIO_NET_ERR; 11506e790746SPaolo Bonzini } 11516e790746SPaolo Bonzini 11521399c60dSRusty Russell queues = virtio_lduw_p(vdev, &mq.virtqueue_pairs); 11536e790746SPaolo Bonzini 11546e790746SPaolo Bonzini if (queues < VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MIN || 11556e790746SPaolo Bonzini queues > VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MAX || 11566e790746SPaolo Bonzini queues > n->max_queues || 11576e790746SPaolo Bonzini !n->multiqueue) { 11586e790746SPaolo Bonzini return VIRTIO_NET_ERR; 11596e790746SPaolo Bonzini } 11606e790746SPaolo Bonzini 11616e790746SPaolo Bonzini n->curr_queues = queues; 11626e790746SPaolo Bonzini /* stop the backend before changing the number of queues to avoid handling a 11636e790746SPaolo Bonzini * disabled queue */ 116417a0ca55SKONRAD Frederic virtio_net_set_status(vdev, vdev->status); 11656e790746SPaolo Bonzini virtio_net_set_queues(n); 11666e790746SPaolo Bonzini 11676e790746SPaolo Bonzini return VIRTIO_NET_OK; 11686e790746SPaolo Bonzini } 1169ba7eadb5SGreg Kurz 11706e790746SPaolo Bonzini static void virtio_net_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq) 11716e790746SPaolo Bonzini { 117217a0ca55SKONRAD Frederic VirtIONet *n = VIRTIO_NET(vdev); 11736e790746SPaolo Bonzini struct virtio_net_ctrl_hdr ctrl; 11746e790746SPaolo Bonzini virtio_net_ctrl_ack status = VIRTIO_NET_ERR; 117551b19ebeSPaolo Bonzini VirtQueueElement *elem; 11766e790746SPaolo Bonzini size_t s; 1177771b6ed3SJason Wang struct iovec *iov, *iov2; 11786e790746SPaolo Bonzini unsigned int iov_cnt; 11796e790746SPaolo Bonzini 118051b19ebeSPaolo Bonzini for (;;) { 118151b19ebeSPaolo Bonzini elem = virtqueue_pop(vq, sizeof(VirtQueueElement)); 118251b19ebeSPaolo Bonzini if (!elem) { 118351b19ebeSPaolo Bonzini break; 118451b19ebeSPaolo Bonzini } 118551b19ebeSPaolo Bonzini if (iov_size(elem->in_sg, elem->in_num) < sizeof(status) || 118651b19ebeSPaolo Bonzini iov_size(elem->out_sg, elem->out_num) < sizeof(ctrl)) { 1187ba7eadb5SGreg Kurz virtio_error(vdev, "virtio-net ctrl missing headers"); 1188ba7eadb5SGreg Kurz virtqueue_detach_element(vq, elem, 0); 1189ba7eadb5SGreg Kurz g_free(elem); 1190ba7eadb5SGreg Kurz break; 11916e790746SPaolo Bonzini } 11926e790746SPaolo Bonzini 119351b19ebeSPaolo Bonzini iov_cnt = elem->out_num; 119451b19ebeSPaolo Bonzini iov2 = iov = g_memdup(elem->out_sg, sizeof(struct iovec) * elem->out_num); 11956e790746SPaolo Bonzini s = iov_to_buf(iov, iov_cnt, 0, &ctrl, sizeof(ctrl)); 11966e790746SPaolo Bonzini iov_discard_front(&iov, &iov_cnt, sizeof(ctrl)); 11976e790746SPaolo Bonzini if (s != sizeof(ctrl)) { 11986e790746SPaolo Bonzini status = VIRTIO_NET_ERR; 11996e790746SPaolo Bonzini } else if (ctrl.class == VIRTIO_NET_CTRL_RX) { 12006e790746SPaolo Bonzini status = virtio_net_handle_rx_mode(n, ctrl.cmd, iov, iov_cnt); 12016e790746SPaolo Bonzini } else if (ctrl.class == VIRTIO_NET_CTRL_MAC) { 12026e790746SPaolo Bonzini status = virtio_net_handle_mac(n, ctrl.cmd, iov, iov_cnt); 12036e790746SPaolo Bonzini } else if (ctrl.class == VIRTIO_NET_CTRL_VLAN) { 12046e790746SPaolo Bonzini status = virtio_net_handle_vlan_table(n, ctrl.cmd, iov, iov_cnt); 1205f57fcf70SJason Wang } else if (ctrl.class == VIRTIO_NET_CTRL_ANNOUNCE) { 1206f57fcf70SJason Wang status = virtio_net_handle_announce(n, ctrl.cmd, iov, iov_cnt); 12076e790746SPaolo Bonzini } else if (ctrl.class == VIRTIO_NET_CTRL_MQ) { 12086e790746SPaolo Bonzini status = virtio_net_handle_mq(n, ctrl.cmd, iov, iov_cnt); 1209644c9858SDmitry Fleytman } else if (ctrl.class == VIRTIO_NET_CTRL_GUEST_OFFLOADS) { 1210644c9858SDmitry Fleytman status = virtio_net_handle_offloads(n, ctrl.cmd, iov, iov_cnt); 12116e790746SPaolo Bonzini } 12126e790746SPaolo Bonzini 121351b19ebeSPaolo Bonzini s = iov_from_buf(elem->in_sg, elem->in_num, 0, &status, sizeof(status)); 12146e790746SPaolo Bonzini assert(s == sizeof(status)); 12156e790746SPaolo Bonzini 121651b19ebeSPaolo Bonzini virtqueue_push(vq, elem, sizeof(status)); 12176e790746SPaolo Bonzini virtio_notify(vdev, vq); 1218771b6ed3SJason Wang g_free(iov2); 121951b19ebeSPaolo Bonzini g_free(elem); 12206e790746SPaolo Bonzini } 12216e790746SPaolo Bonzini } 12226e790746SPaolo Bonzini 12236e790746SPaolo Bonzini /* RX */ 12246e790746SPaolo Bonzini 12256e790746SPaolo Bonzini static void virtio_net_handle_rx(VirtIODevice *vdev, VirtQueue *vq) 12266e790746SPaolo Bonzini { 122717a0ca55SKONRAD Frederic VirtIONet *n = VIRTIO_NET(vdev); 12286e790746SPaolo Bonzini int queue_index = vq2q(virtio_get_queue_index(vq)); 12296e790746SPaolo Bonzini 12306e790746SPaolo Bonzini qemu_flush_queued_packets(qemu_get_subqueue(n->nic, queue_index)); 12316e790746SPaolo Bonzini } 12326e790746SPaolo Bonzini 12336e790746SPaolo Bonzini static int virtio_net_can_receive(NetClientState *nc) 12346e790746SPaolo Bonzini { 12356e790746SPaolo Bonzini VirtIONet *n = qemu_get_nic_opaque(nc); 123617a0ca55SKONRAD Frederic VirtIODevice *vdev = VIRTIO_DEVICE(n); 12376e790746SPaolo Bonzini VirtIONetQueue *q = virtio_net_get_subqueue(nc); 12386e790746SPaolo Bonzini 123917a0ca55SKONRAD Frederic if (!vdev->vm_running) { 12406e790746SPaolo Bonzini return 0; 12416e790746SPaolo Bonzini } 12426e790746SPaolo Bonzini 12436e790746SPaolo Bonzini if (nc->queue_index >= n->curr_queues) { 12446e790746SPaolo Bonzini return 0; 12456e790746SPaolo Bonzini } 12466e790746SPaolo Bonzini 12476e790746SPaolo Bonzini if (!virtio_queue_ready(q->rx_vq) || 124817a0ca55SKONRAD Frederic !(vdev->status & VIRTIO_CONFIG_S_DRIVER_OK)) { 12496e790746SPaolo Bonzini return 0; 12506e790746SPaolo Bonzini } 12516e790746SPaolo Bonzini 12526e790746SPaolo Bonzini return 1; 12536e790746SPaolo Bonzini } 12546e790746SPaolo Bonzini 12556e790746SPaolo Bonzini static int virtio_net_has_buffers(VirtIONetQueue *q, int bufsize) 12566e790746SPaolo Bonzini { 12576e790746SPaolo Bonzini VirtIONet *n = q->n; 12586e790746SPaolo Bonzini if (virtio_queue_empty(q->rx_vq) || 12596e790746SPaolo Bonzini (n->mergeable_rx_bufs && 12606e790746SPaolo Bonzini !virtqueue_avail_bytes(q->rx_vq, bufsize, 0))) { 12616e790746SPaolo Bonzini virtio_queue_set_notification(q->rx_vq, 1); 12626e790746SPaolo Bonzini 12636e790746SPaolo Bonzini /* To avoid a race condition where the guest has made some buffers 12646e790746SPaolo Bonzini * available after the above check but before notification was 12656e790746SPaolo Bonzini * enabled, check for available buffers again. 12666e790746SPaolo Bonzini */ 12676e790746SPaolo Bonzini if (virtio_queue_empty(q->rx_vq) || 12686e790746SPaolo Bonzini (n->mergeable_rx_bufs && 12696e790746SPaolo Bonzini !virtqueue_avail_bytes(q->rx_vq, bufsize, 0))) { 12706e790746SPaolo Bonzini return 0; 12716e790746SPaolo Bonzini } 12726e790746SPaolo Bonzini } 12736e790746SPaolo Bonzini 12746e790746SPaolo Bonzini virtio_queue_set_notification(q->rx_vq, 0); 12756e790746SPaolo Bonzini return 1; 12766e790746SPaolo Bonzini } 12776e790746SPaolo Bonzini 12781399c60dSRusty Russell static void virtio_net_hdr_swap(VirtIODevice *vdev, struct virtio_net_hdr *hdr) 1279032a74a1SCédric Le Goater { 12801399c60dSRusty Russell virtio_tswap16s(vdev, &hdr->hdr_len); 12811399c60dSRusty Russell virtio_tswap16s(vdev, &hdr->gso_size); 12821399c60dSRusty Russell virtio_tswap16s(vdev, &hdr->csum_start); 12831399c60dSRusty Russell virtio_tswap16s(vdev, &hdr->csum_offset); 1284032a74a1SCédric Le Goater } 1285032a74a1SCédric Le Goater 12866e790746SPaolo Bonzini /* dhclient uses AF_PACKET but doesn't pass auxdata to the kernel so 12876e790746SPaolo Bonzini * it never finds out that the packets don't have valid checksums. This 12886e790746SPaolo Bonzini * causes dhclient to get upset. Fedora's carried a patch for ages to 12896e790746SPaolo Bonzini * fix this with Xen but it hasn't appeared in an upstream release of 12906e790746SPaolo Bonzini * dhclient yet. 12916e790746SPaolo Bonzini * 12926e790746SPaolo Bonzini * To avoid breaking existing guests, we catch udp packets and add 12936e790746SPaolo Bonzini * checksums. This is terrible but it's better than hacking the guest 12946e790746SPaolo Bonzini * kernels. 12956e790746SPaolo Bonzini * 12966e790746SPaolo Bonzini * N.B. if we introduce a zero-copy API, this operation is no longer free so 12976e790746SPaolo Bonzini * we should provide a mechanism to disable it to avoid polluting the host 12986e790746SPaolo Bonzini * cache. 12996e790746SPaolo Bonzini */ 13006e790746SPaolo Bonzini static void work_around_broken_dhclient(struct virtio_net_hdr *hdr, 13016e790746SPaolo Bonzini uint8_t *buf, size_t size) 13026e790746SPaolo Bonzini { 13036e790746SPaolo Bonzini if ((hdr->flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) && /* missing csum */ 13046e790746SPaolo Bonzini (size > 27 && size < 1500) && /* normal sized MTU */ 13056e790746SPaolo Bonzini (buf[12] == 0x08 && buf[13] == 0x00) && /* ethertype == IPv4 */ 13066e790746SPaolo Bonzini (buf[23] == 17) && /* ip.protocol == UDP */ 13076e790746SPaolo Bonzini (buf[34] == 0 && buf[35] == 67)) { /* udp.srcport == bootps */ 13086e790746SPaolo Bonzini net_checksum_calculate(buf, size); 13096e790746SPaolo Bonzini hdr->flags &= ~VIRTIO_NET_HDR_F_NEEDS_CSUM; 13106e790746SPaolo Bonzini } 13116e790746SPaolo Bonzini } 13126e790746SPaolo Bonzini 13136e790746SPaolo Bonzini static void receive_header(VirtIONet *n, const struct iovec *iov, int iov_cnt, 13146e790746SPaolo Bonzini const void *buf, size_t size) 13156e790746SPaolo Bonzini { 13166e790746SPaolo Bonzini if (n->has_vnet_hdr) { 13176e790746SPaolo Bonzini /* FIXME this cast is evil */ 13186e790746SPaolo Bonzini void *wbuf = (void *)buf; 13196e790746SPaolo Bonzini work_around_broken_dhclient(wbuf, wbuf + n->host_hdr_len, 13206e790746SPaolo Bonzini size - n->host_hdr_len); 13211bfa316cSGreg Kurz 13221bfa316cSGreg Kurz if (n->needs_vnet_hdr_swap) { 13231399c60dSRusty Russell virtio_net_hdr_swap(VIRTIO_DEVICE(n), wbuf); 13241bfa316cSGreg Kurz } 13256e790746SPaolo Bonzini iov_from_buf(iov, iov_cnt, 0, buf, sizeof(struct virtio_net_hdr)); 13266e790746SPaolo Bonzini } else { 13276e790746SPaolo Bonzini struct virtio_net_hdr hdr = { 13286e790746SPaolo Bonzini .flags = 0, 13296e790746SPaolo Bonzini .gso_type = VIRTIO_NET_HDR_GSO_NONE 13306e790746SPaolo Bonzini }; 13316e790746SPaolo Bonzini iov_from_buf(iov, iov_cnt, 0, &hdr, sizeof hdr); 13326e790746SPaolo Bonzini } 13336e790746SPaolo Bonzini } 13346e790746SPaolo Bonzini 13356e790746SPaolo Bonzini static int receive_filter(VirtIONet *n, const uint8_t *buf, int size) 13366e790746SPaolo Bonzini { 13376e790746SPaolo Bonzini static const uint8_t bcast[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; 13386e790746SPaolo Bonzini static const uint8_t vlan[] = {0x81, 0x00}; 13396e790746SPaolo Bonzini uint8_t *ptr = (uint8_t *)buf; 13406e790746SPaolo Bonzini int i; 13416e790746SPaolo Bonzini 13426e790746SPaolo Bonzini if (n->promisc) 13436e790746SPaolo Bonzini return 1; 13446e790746SPaolo Bonzini 13456e790746SPaolo Bonzini ptr += n->host_hdr_len; 13466e790746SPaolo Bonzini 13476e790746SPaolo Bonzini if (!memcmp(&ptr[12], vlan, sizeof(vlan))) { 13487542d3e7SPeter Maydell int vid = lduw_be_p(ptr + 14) & 0xfff; 13496e790746SPaolo Bonzini if (!(n->vlans[vid >> 5] & (1U << (vid & 0x1f)))) 13506e790746SPaolo Bonzini return 0; 13516e790746SPaolo Bonzini } 13526e790746SPaolo Bonzini 13536e790746SPaolo Bonzini if (ptr[0] & 1) { // multicast 13546e790746SPaolo Bonzini if (!memcmp(ptr, bcast, sizeof(bcast))) { 13556e790746SPaolo Bonzini return !n->nobcast; 13566e790746SPaolo Bonzini } else if (n->nomulti) { 13576e790746SPaolo Bonzini return 0; 13586e790746SPaolo Bonzini } else if (n->allmulti || n->mac_table.multi_overflow) { 13596e790746SPaolo Bonzini return 1; 13606e790746SPaolo Bonzini } 13616e790746SPaolo Bonzini 13626e790746SPaolo Bonzini for (i = n->mac_table.first_multi; i < n->mac_table.in_use; i++) { 13636e790746SPaolo Bonzini if (!memcmp(ptr, &n->mac_table.macs[i * ETH_ALEN], ETH_ALEN)) { 13646e790746SPaolo Bonzini return 1; 13656e790746SPaolo Bonzini } 13666e790746SPaolo Bonzini } 13676e790746SPaolo Bonzini } else { // unicast 13686e790746SPaolo Bonzini if (n->nouni) { 13696e790746SPaolo Bonzini return 0; 13706e790746SPaolo Bonzini } else if (n->alluni || n->mac_table.uni_overflow) { 13716e790746SPaolo Bonzini return 1; 13726e790746SPaolo Bonzini } else if (!memcmp(ptr, n->mac, ETH_ALEN)) { 13736e790746SPaolo Bonzini return 1; 13746e790746SPaolo Bonzini } 13756e790746SPaolo Bonzini 13766e790746SPaolo Bonzini for (i = 0; i < n->mac_table.first_multi; i++) { 13776e790746SPaolo Bonzini if (!memcmp(ptr, &n->mac_table.macs[i * ETH_ALEN], ETH_ALEN)) { 13786e790746SPaolo Bonzini return 1; 13796e790746SPaolo Bonzini } 13806e790746SPaolo Bonzini } 13816e790746SPaolo Bonzini } 13826e790746SPaolo Bonzini 13836e790746SPaolo Bonzini return 0; 13846e790746SPaolo Bonzini } 13856e790746SPaolo Bonzini 138697cd965cSPaolo Bonzini static ssize_t virtio_net_receive_rcu(NetClientState *nc, const uint8_t *buf, 138797cd965cSPaolo Bonzini size_t size) 13886e790746SPaolo Bonzini { 13896e790746SPaolo Bonzini VirtIONet *n = qemu_get_nic_opaque(nc); 13906e790746SPaolo Bonzini VirtIONetQueue *q = virtio_net_get_subqueue(nc); 139117a0ca55SKONRAD Frederic VirtIODevice *vdev = VIRTIO_DEVICE(n); 13926e790746SPaolo Bonzini struct iovec mhdr_sg[VIRTQUEUE_MAX_SIZE]; 13936e790746SPaolo Bonzini struct virtio_net_hdr_mrg_rxbuf mhdr; 13946e790746SPaolo Bonzini unsigned mhdr_cnt = 0; 13956e790746SPaolo Bonzini size_t offset, i, guest_offset; 13966e790746SPaolo Bonzini 13976e790746SPaolo Bonzini if (!virtio_net_can_receive(nc)) { 13986e790746SPaolo Bonzini return -1; 13996e790746SPaolo Bonzini } 14006e790746SPaolo Bonzini 14016e790746SPaolo Bonzini /* hdr_len refers to the header we supply to the guest */ 14026e790746SPaolo Bonzini if (!virtio_net_has_buffers(q, size + n->guest_hdr_len - n->host_hdr_len)) { 14036e790746SPaolo Bonzini return 0; 14046e790746SPaolo Bonzini } 14056e790746SPaolo Bonzini 14066e790746SPaolo Bonzini if (!receive_filter(n, buf, size)) 14076e790746SPaolo Bonzini return size; 14086e790746SPaolo Bonzini 14096e790746SPaolo Bonzini offset = i = 0; 14106e790746SPaolo Bonzini 14116e790746SPaolo Bonzini while (offset < size) { 141251b19ebeSPaolo Bonzini VirtQueueElement *elem; 14136e790746SPaolo Bonzini int len, total; 141451b19ebeSPaolo Bonzini const struct iovec *sg; 14156e790746SPaolo Bonzini 14166e790746SPaolo Bonzini total = 0; 14176e790746SPaolo Bonzini 141851b19ebeSPaolo Bonzini elem = virtqueue_pop(q->rx_vq, sizeof(VirtQueueElement)); 141951b19ebeSPaolo Bonzini if (!elem) { 1420ba10b9c0SGreg Kurz if (i) { 1421ba10b9c0SGreg Kurz virtio_error(vdev, "virtio-net unexpected empty queue: " 14226e790746SPaolo Bonzini "i %zd mergeable %d offset %zd, size %zd, " 1423019a3edbSGerd Hoffmann "guest hdr len %zd, host hdr len %zd " 1424019a3edbSGerd Hoffmann "guest features 0x%" PRIx64, 14256e790746SPaolo Bonzini i, n->mergeable_rx_bufs, offset, size, 1426019a3edbSGerd Hoffmann n->guest_hdr_len, n->host_hdr_len, 1427019a3edbSGerd Hoffmann vdev->guest_features); 1428ba10b9c0SGreg Kurz } 1429ba10b9c0SGreg Kurz return -1; 14306e790746SPaolo Bonzini } 14316e790746SPaolo Bonzini 143251b19ebeSPaolo Bonzini if (elem->in_num < 1) { 1433ba10b9c0SGreg Kurz virtio_error(vdev, 1434ba10b9c0SGreg Kurz "virtio-net receive queue contains no in buffers"); 1435ba10b9c0SGreg Kurz virtqueue_detach_element(q->rx_vq, elem, 0); 1436ba10b9c0SGreg Kurz g_free(elem); 1437ba10b9c0SGreg Kurz return -1; 14386e790746SPaolo Bonzini } 14396e790746SPaolo Bonzini 144051b19ebeSPaolo Bonzini sg = elem->in_sg; 14416e790746SPaolo Bonzini if (i == 0) { 14426e790746SPaolo Bonzini assert(offset == 0); 14436e790746SPaolo Bonzini if (n->mergeable_rx_bufs) { 14446e790746SPaolo Bonzini mhdr_cnt = iov_copy(mhdr_sg, ARRAY_SIZE(mhdr_sg), 144551b19ebeSPaolo Bonzini sg, elem->in_num, 14466e790746SPaolo Bonzini offsetof(typeof(mhdr), num_buffers), 14476e790746SPaolo Bonzini sizeof(mhdr.num_buffers)); 14486e790746SPaolo Bonzini } 14496e790746SPaolo Bonzini 145051b19ebeSPaolo Bonzini receive_header(n, sg, elem->in_num, buf, size); 14516e790746SPaolo Bonzini offset = n->host_hdr_len; 14526e790746SPaolo Bonzini total += n->guest_hdr_len; 14536e790746SPaolo Bonzini guest_offset = n->guest_hdr_len; 14546e790746SPaolo Bonzini } else { 14556e790746SPaolo Bonzini guest_offset = 0; 14566e790746SPaolo Bonzini } 14576e790746SPaolo Bonzini 14586e790746SPaolo Bonzini /* copy in packet. ugh */ 145951b19ebeSPaolo Bonzini len = iov_from_buf(sg, elem->in_num, guest_offset, 14606e790746SPaolo Bonzini buf + offset, size - offset); 14616e790746SPaolo Bonzini total += len; 14626e790746SPaolo Bonzini offset += len; 14636e790746SPaolo Bonzini /* If buffers can't be merged, at this point we 14646e790746SPaolo Bonzini * must have consumed the complete packet. 14656e790746SPaolo Bonzini * Otherwise, drop it. */ 14666e790746SPaolo Bonzini if (!n->mergeable_rx_bufs && offset < size) { 146727e57efeSLadi Prosek virtqueue_unpop(q->rx_vq, elem, total); 146851b19ebeSPaolo Bonzini g_free(elem); 14696e790746SPaolo Bonzini return size; 14706e790746SPaolo Bonzini } 14716e790746SPaolo Bonzini 14726e790746SPaolo Bonzini /* signal other side */ 147351b19ebeSPaolo Bonzini virtqueue_fill(q->rx_vq, elem, total, i++); 147451b19ebeSPaolo Bonzini g_free(elem); 14756e790746SPaolo Bonzini } 14766e790746SPaolo Bonzini 14776e790746SPaolo Bonzini if (mhdr_cnt) { 14781399c60dSRusty Russell virtio_stw_p(vdev, &mhdr.num_buffers, i); 14796e790746SPaolo Bonzini iov_from_buf(mhdr_sg, mhdr_cnt, 14806e790746SPaolo Bonzini 0, 14816e790746SPaolo Bonzini &mhdr.num_buffers, sizeof mhdr.num_buffers); 14826e790746SPaolo Bonzini } 14836e790746SPaolo Bonzini 14846e790746SPaolo Bonzini virtqueue_flush(q->rx_vq, i); 148517a0ca55SKONRAD Frederic virtio_notify(vdev, q->rx_vq); 14866e790746SPaolo Bonzini 14876e790746SPaolo Bonzini return size; 14886e790746SPaolo Bonzini } 14896e790746SPaolo Bonzini 14902974e916SYuri Benditovich static ssize_t virtio_net_do_receive(NetClientState *nc, const uint8_t *buf, 149197cd965cSPaolo Bonzini size_t size) 149297cd965cSPaolo Bonzini { 1493*068ddfa9SDr. David Alan Gilbert RCU_READ_LOCK_GUARD(); 149497cd965cSPaolo Bonzini 1495*068ddfa9SDr. David Alan Gilbert return virtio_net_receive_rcu(nc, buf, size); 149697cd965cSPaolo Bonzini } 149797cd965cSPaolo Bonzini 14982974e916SYuri Benditovich static void virtio_net_rsc_extract_unit4(VirtioNetRscChain *chain, 14992974e916SYuri Benditovich const uint8_t *buf, 15002974e916SYuri Benditovich VirtioNetRscUnit *unit) 15012974e916SYuri Benditovich { 15022974e916SYuri Benditovich uint16_t ip_hdrlen; 15032974e916SYuri Benditovich struct ip_header *ip; 15042974e916SYuri Benditovich 15052974e916SYuri Benditovich ip = (struct ip_header *)(buf + chain->n->guest_hdr_len 15062974e916SYuri Benditovich + sizeof(struct eth_header)); 15072974e916SYuri Benditovich unit->ip = (void *)ip; 15082974e916SYuri Benditovich ip_hdrlen = (ip->ip_ver_len & 0xF) << 2; 15092974e916SYuri Benditovich unit->ip_plen = &ip->ip_len; 15102974e916SYuri Benditovich unit->tcp = (struct tcp_header *)(((uint8_t *)unit->ip) + ip_hdrlen); 15112974e916SYuri Benditovich unit->tcp_hdrlen = (htons(unit->tcp->th_offset_flags) & 0xF000) >> 10; 15122974e916SYuri Benditovich unit->payload = htons(*unit->ip_plen) - ip_hdrlen - unit->tcp_hdrlen; 15132974e916SYuri Benditovich } 15142974e916SYuri Benditovich 15152974e916SYuri Benditovich static void virtio_net_rsc_extract_unit6(VirtioNetRscChain *chain, 15162974e916SYuri Benditovich const uint8_t *buf, 15172974e916SYuri Benditovich VirtioNetRscUnit *unit) 15182974e916SYuri Benditovich { 15192974e916SYuri Benditovich struct ip6_header *ip6; 15202974e916SYuri Benditovich 15212974e916SYuri Benditovich ip6 = (struct ip6_header *)(buf + chain->n->guest_hdr_len 15222974e916SYuri Benditovich + sizeof(struct eth_header)); 15232974e916SYuri Benditovich unit->ip = ip6; 15242974e916SYuri Benditovich unit->ip_plen = &(ip6->ip6_ctlun.ip6_un1.ip6_un1_plen); 15252974e916SYuri Benditovich unit->tcp = (struct tcp_header *)(((uint8_t *)unit->ip)\ 15262974e916SYuri Benditovich + sizeof(struct ip6_header)); 15272974e916SYuri Benditovich unit->tcp_hdrlen = (htons(unit->tcp->th_offset_flags) & 0xF000) >> 10; 15282974e916SYuri Benditovich 15292974e916SYuri Benditovich /* There is a difference between payload lenght in ipv4 and v6, 15302974e916SYuri Benditovich ip header is excluded in ipv6 */ 15312974e916SYuri Benditovich unit->payload = htons(*unit->ip_plen) - unit->tcp_hdrlen; 15322974e916SYuri Benditovich } 15332974e916SYuri Benditovich 15342974e916SYuri Benditovich static size_t virtio_net_rsc_drain_seg(VirtioNetRscChain *chain, 15352974e916SYuri Benditovich VirtioNetRscSeg *seg) 15362974e916SYuri Benditovich { 15372974e916SYuri Benditovich int ret; 15382974e916SYuri Benditovich struct virtio_net_hdr *h; 15392974e916SYuri Benditovich 15402974e916SYuri Benditovich h = (struct virtio_net_hdr *)seg->buf; 15412974e916SYuri Benditovich h->flags = 0; 15422974e916SYuri Benditovich h->gso_type = VIRTIO_NET_HDR_GSO_NONE; 15432974e916SYuri Benditovich 15442974e916SYuri Benditovich if (seg->is_coalesced) { 15452974e916SYuri Benditovich *virtio_net_rsc_ext_num_packets(h) = seg->packets; 15462974e916SYuri Benditovich *virtio_net_rsc_ext_num_dupacks(h) = seg->dup_ack; 15472974e916SYuri Benditovich h->flags = VIRTIO_NET_HDR_F_RSC_INFO; 15482974e916SYuri Benditovich if (chain->proto == ETH_P_IP) { 15492974e916SYuri Benditovich h->gso_type = VIRTIO_NET_HDR_GSO_TCPV4; 15502974e916SYuri Benditovich } else { 15512974e916SYuri Benditovich h->gso_type = VIRTIO_NET_HDR_GSO_TCPV6; 15522974e916SYuri Benditovich } 15532974e916SYuri Benditovich } 15542974e916SYuri Benditovich 15552974e916SYuri Benditovich ret = virtio_net_do_receive(seg->nc, seg->buf, seg->size); 15562974e916SYuri Benditovich QTAILQ_REMOVE(&chain->buffers, seg, next); 15572974e916SYuri Benditovich g_free(seg->buf); 15582974e916SYuri Benditovich g_free(seg); 15592974e916SYuri Benditovich 15602974e916SYuri Benditovich return ret; 15612974e916SYuri Benditovich } 15622974e916SYuri Benditovich 15632974e916SYuri Benditovich static void virtio_net_rsc_purge(void *opq) 15642974e916SYuri Benditovich { 15652974e916SYuri Benditovich VirtioNetRscSeg *seg, *rn; 15662974e916SYuri Benditovich VirtioNetRscChain *chain = (VirtioNetRscChain *)opq; 15672974e916SYuri Benditovich 15682974e916SYuri Benditovich QTAILQ_FOREACH_SAFE(seg, &chain->buffers, next, rn) { 15692974e916SYuri Benditovich if (virtio_net_rsc_drain_seg(chain, seg) == 0) { 15702974e916SYuri Benditovich chain->stat.purge_failed++; 15712974e916SYuri Benditovich continue; 15722974e916SYuri Benditovich } 15732974e916SYuri Benditovich } 15742974e916SYuri Benditovich 15752974e916SYuri Benditovich chain->stat.timer++; 15762974e916SYuri Benditovich if (!QTAILQ_EMPTY(&chain->buffers)) { 15772974e916SYuri Benditovich timer_mod(chain->drain_timer, 15782974e916SYuri Benditovich qemu_clock_get_ns(QEMU_CLOCK_HOST) + chain->n->rsc_timeout); 15792974e916SYuri Benditovich } 15802974e916SYuri Benditovich } 15812974e916SYuri Benditovich 15822974e916SYuri Benditovich static void virtio_net_rsc_cleanup(VirtIONet *n) 15832974e916SYuri Benditovich { 15842974e916SYuri Benditovich VirtioNetRscChain *chain, *rn_chain; 15852974e916SYuri Benditovich VirtioNetRscSeg *seg, *rn_seg; 15862974e916SYuri Benditovich 15872974e916SYuri Benditovich QTAILQ_FOREACH_SAFE(chain, &n->rsc_chains, next, rn_chain) { 15882974e916SYuri Benditovich QTAILQ_FOREACH_SAFE(seg, &chain->buffers, next, rn_seg) { 15892974e916SYuri Benditovich QTAILQ_REMOVE(&chain->buffers, seg, next); 15902974e916SYuri Benditovich g_free(seg->buf); 15912974e916SYuri Benditovich g_free(seg); 15922974e916SYuri Benditovich } 15932974e916SYuri Benditovich 15942974e916SYuri Benditovich timer_del(chain->drain_timer); 15952974e916SYuri Benditovich timer_free(chain->drain_timer); 15962974e916SYuri Benditovich QTAILQ_REMOVE(&n->rsc_chains, chain, next); 15972974e916SYuri Benditovich g_free(chain); 15982974e916SYuri Benditovich } 15992974e916SYuri Benditovich } 16002974e916SYuri Benditovich 16012974e916SYuri Benditovich static void virtio_net_rsc_cache_buf(VirtioNetRscChain *chain, 16022974e916SYuri Benditovich NetClientState *nc, 16032974e916SYuri Benditovich const uint8_t *buf, size_t size) 16042974e916SYuri Benditovich { 16052974e916SYuri Benditovich uint16_t hdr_len; 16062974e916SYuri Benditovich VirtioNetRscSeg *seg; 16072974e916SYuri Benditovich 16082974e916SYuri Benditovich hdr_len = chain->n->guest_hdr_len; 16092974e916SYuri Benditovich seg = g_malloc(sizeof(VirtioNetRscSeg)); 16102974e916SYuri Benditovich seg->buf = g_malloc(hdr_len + sizeof(struct eth_header) 16112974e916SYuri Benditovich + sizeof(struct ip6_header) + VIRTIO_NET_MAX_TCP_PAYLOAD); 16122974e916SYuri Benditovich memcpy(seg->buf, buf, size); 16132974e916SYuri Benditovich seg->size = size; 16142974e916SYuri Benditovich seg->packets = 1; 16152974e916SYuri Benditovich seg->dup_ack = 0; 16162974e916SYuri Benditovich seg->is_coalesced = 0; 16172974e916SYuri Benditovich seg->nc = nc; 16182974e916SYuri Benditovich 16192974e916SYuri Benditovich QTAILQ_INSERT_TAIL(&chain->buffers, seg, next); 16202974e916SYuri Benditovich chain->stat.cache++; 16212974e916SYuri Benditovich 16222974e916SYuri Benditovich switch (chain->proto) { 16232974e916SYuri Benditovich case ETH_P_IP: 16242974e916SYuri Benditovich virtio_net_rsc_extract_unit4(chain, seg->buf, &seg->unit); 16252974e916SYuri Benditovich break; 16262974e916SYuri Benditovich case ETH_P_IPV6: 16272974e916SYuri Benditovich virtio_net_rsc_extract_unit6(chain, seg->buf, &seg->unit); 16282974e916SYuri Benditovich break; 16292974e916SYuri Benditovich default: 16302974e916SYuri Benditovich g_assert_not_reached(); 16312974e916SYuri Benditovich } 16322974e916SYuri Benditovich } 16332974e916SYuri Benditovich 16342974e916SYuri Benditovich static int32_t virtio_net_rsc_handle_ack(VirtioNetRscChain *chain, 16352974e916SYuri Benditovich VirtioNetRscSeg *seg, 16362974e916SYuri Benditovich const uint8_t *buf, 16372974e916SYuri Benditovich struct tcp_header *n_tcp, 16382974e916SYuri Benditovich struct tcp_header *o_tcp) 16392974e916SYuri Benditovich { 16402974e916SYuri Benditovich uint32_t nack, oack; 16412974e916SYuri Benditovich uint16_t nwin, owin; 16422974e916SYuri Benditovich 16432974e916SYuri Benditovich nack = htonl(n_tcp->th_ack); 16442974e916SYuri Benditovich nwin = htons(n_tcp->th_win); 16452974e916SYuri Benditovich oack = htonl(o_tcp->th_ack); 16462974e916SYuri Benditovich owin = htons(o_tcp->th_win); 16472974e916SYuri Benditovich 16482974e916SYuri Benditovich if ((nack - oack) >= VIRTIO_NET_MAX_TCP_PAYLOAD) { 16492974e916SYuri Benditovich chain->stat.ack_out_of_win++; 16502974e916SYuri Benditovich return RSC_FINAL; 16512974e916SYuri Benditovich } else if (nack == oack) { 16522974e916SYuri Benditovich /* duplicated ack or window probe */ 16532974e916SYuri Benditovich if (nwin == owin) { 16542974e916SYuri Benditovich /* duplicated ack, add dup ack count due to whql test up to 1 */ 16552974e916SYuri Benditovich chain->stat.dup_ack++; 16562974e916SYuri Benditovich return RSC_FINAL; 16572974e916SYuri Benditovich } else { 16582974e916SYuri Benditovich /* Coalesce window update */ 16592974e916SYuri Benditovich o_tcp->th_win = n_tcp->th_win; 16602974e916SYuri Benditovich chain->stat.win_update++; 16612974e916SYuri Benditovich return RSC_COALESCE; 16622974e916SYuri Benditovich } 16632974e916SYuri Benditovich } else { 16642974e916SYuri Benditovich /* pure ack, go to 'C', finalize*/ 16652974e916SYuri Benditovich chain->stat.pure_ack++; 16662974e916SYuri Benditovich return RSC_FINAL; 16672974e916SYuri Benditovich } 16682974e916SYuri Benditovich } 16692974e916SYuri Benditovich 16702974e916SYuri Benditovich static int32_t virtio_net_rsc_coalesce_data(VirtioNetRscChain *chain, 16712974e916SYuri Benditovich VirtioNetRscSeg *seg, 16722974e916SYuri Benditovich const uint8_t *buf, 16732974e916SYuri Benditovich VirtioNetRscUnit *n_unit) 16742974e916SYuri Benditovich { 16752974e916SYuri Benditovich void *data; 16762974e916SYuri Benditovich uint16_t o_ip_len; 16772974e916SYuri Benditovich uint32_t nseq, oseq; 16782974e916SYuri Benditovich VirtioNetRscUnit *o_unit; 16792974e916SYuri Benditovich 16802974e916SYuri Benditovich o_unit = &seg->unit; 16812974e916SYuri Benditovich o_ip_len = htons(*o_unit->ip_plen); 16822974e916SYuri Benditovich nseq = htonl(n_unit->tcp->th_seq); 16832974e916SYuri Benditovich oseq = htonl(o_unit->tcp->th_seq); 16842974e916SYuri Benditovich 16852974e916SYuri Benditovich /* out of order or retransmitted. */ 16862974e916SYuri Benditovich if ((nseq - oseq) > VIRTIO_NET_MAX_TCP_PAYLOAD) { 16872974e916SYuri Benditovich chain->stat.data_out_of_win++; 16882974e916SYuri Benditovich return RSC_FINAL; 16892974e916SYuri Benditovich } 16902974e916SYuri Benditovich 16912974e916SYuri Benditovich data = ((uint8_t *)n_unit->tcp) + n_unit->tcp_hdrlen; 16922974e916SYuri Benditovich if (nseq == oseq) { 16932974e916SYuri Benditovich if ((o_unit->payload == 0) && n_unit->payload) { 16942974e916SYuri Benditovich /* From no payload to payload, normal case, not a dup ack or etc */ 16952974e916SYuri Benditovich chain->stat.data_after_pure_ack++; 16962974e916SYuri Benditovich goto coalesce; 16972974e916SYuri Benditovich } else { 16982974e916SYuri Benditovich return virtio_net_rsc_handle_ack(chain, seg, buf, 16992974e916SYuri Benditovich n_unit->tcp, o_unit->tcp); 17002974e916SYuri Benditovich } 17012974e916SYuri Benditovich } else if ((nseq - oseq) != o_unit->payload) { 17022974e916SYuri Benditovich /* Not a consistent packet, out of order */ 17032974e916SYuri Benditovich chain->stat.data_out_of_order++; 17042974e916SYuri Benditovich return RSC_FINAL; 17052974e916SYuri Benditovich } else { 17062974e916SYuri Benditovich coalesce: 17072974e916SYuri Benditovich if ((o_ip_len + n_unit->payload) > chain->max_payload) { 17082974e916SYuri Benditovich chain->stat.over_size++; 17092974e916SYuri Benditovich return RSC_FINAL; 17102974e916SYuri Benditovich } 17112974e916SYuri Benditovich 17122974e916SYuri Benditovich /* Here comes the right data, the payload length in v4/v6 is different, 17132974e916SYuri Benditovich so use the field value to update and record the new data len */ 17142974e916SYuri Benditovich o_unit->payload += n_unit->payload; /* update new data len */ 17152974e916SYuri Benditovich 17162974e916SYuri Benditovich /* update field in ip header */ 17172974e916SYuri Benditovich *o_unit->ip_plen = htons(o_ip_len + n_unit->payload); 17182974e916SYuri Benditovich 17192974e916SYuri Benditovich /* Bring 'PUSH' big, the whql test guide says 'PUSH' can be coalesced 17202974e916SYuri Benditovich for windows guest, while this may change the behavior for linux 17212974e916SYuri Benditovich guest (only if it uses RSC feature). */ 17222974e916SYuri Benditovich o_unit->tcp->th_offset_flags = n_unit->tcp->th_offset_flags; 17232974e916SYuri Benditovich 17242974e916SYuri Benditovich o_unit->tcp->th_ack = n_unit->tcp->th_ack; 17252974e916SYuri Benditovich o_unit->tcp->th_win = n_unit->tcp->th_win; 17262974e916SYuri Benditovich 17272974e916SYuri Benditovich memmove(seg->buf + seg->size, data, n_unit->payload); 17282974e916SYuri Benditovich seg->size += n_unit->payload; 17292974e916SYuri Benditovich seg->packets++; 17302974e916SYuri Benditovich chain->stat.coalesced++; 17312974e916SYuri Benditovich return RSC_COALESCE; 17322974e916SYuri Benditovich } 17332974e916SYuri Benditovich } 17342974e916SYuri Benditovich 17352974e916SYuri Benditovich static int32_t virtio_net_rsc_coalesce4(VirtioNetRscChain *chain, 17362974e916SYuri Benditovich VirtioNetRscSeg *seg, 17372974e916SYuri Benditovich const uint8_t *buf, size_t size, 17382974e916SYuri Benditovich VirtioNetRscUnit *unit) 17392974e916SYuri Benditovich { 17402974e916SYuri Benditovich struct ip_header *ip1, *ip2; 17412974e916SYuri Benditovich 17422974e916SYuri Benditovich ip1 = (struct ip_header *)(unit->ip); 17432974e916SYuri Benditovich ip2 = (struct ip_header *)(seg->unit.ip); 17442974e916SYuri Benditovich if ((ip1->ip_src ^ ip2->ip_src) || (ip1->ip_dst ^ ip2->ip_dst) 17452974e916SYuri Benditovich || (unit->tcp->th_sport ^ seg->unit.tcp->th_sport) 17462974e916SYuri Benditovich || (unit->tcp->th_dport ^ seg->unit.tcp->th_dport)) { 17472974e916SYuri Benditovich chain->stat.no_match++; 17482974e916SYuri Benditovich return RSC_NO_MATCH; 17492974e916SYuri Benditovich } 17502974e916SYuri Benditovich 17512974e916SYuri Benditovich return virtio_net_rsc_coalesce_data(chain, seg, buf, unit); 17522974e916SYuri Benditovich } 17532974e916SYuri Benditovich 17542974e916SYuri Benditovich static int32_t virtio_net_rsc_coalesce6(VirtioNetRscChain *chain, 17552974e916SYuri Benditovich VirtioNetRscSeg *seg, 17562974e916SYuri Benditovich const uint8_t *buf, size_t size, 17572974e916SYuri Benditovich VirtioNetRscUnit *unit) 17582974e916SYuri Benditovich { 17592974e916SYuri Benditovich struct ip6_header *ip1, *ip2; 17602974e916SYuri Benditovich 17612974e916SYuri Benditovich ip1 = (struct ip6_header *)(unit->ip); 17622974e916SYuri Benditovich ip2 = (struct ip6_header *)(seg->unit.ip); 17632974e916SYuri Benditovich if (memcmp(&ip1->ip6_src, &ip2->ip6_src, sizeof(struct in6_address)) 17642974e916SYuri Benditovich || memcmp(&ip1->ip6_dst, &ip2->ip6_dst, sizeof(struct in6_address)) 17652974e916SYuri Benditovich || (unit->tcp->th_sport ^ seg->unit.tcp->th_sport) 17662974e916SYuri Benditovich || (unit->tcp->th_dport ^ seg->unit.tcp->th_dport)) { 17672974e916SYuri Benditovich chain->stat.no_match++; 17682974e916SYuri Benditovich return RSC_NO_MATCH; 17692974e916SYuri Benditovich } 17702974e916SYuri Benditovich 17712974e916SYuri Benditovich return virtio_net_rsc_coalesce_data(chain, seg, buf, unit); 17722974e916SYuri Benditovich } 17732974e916SYuri Benditovich 17742974e916SYuri Benditovich /* Packets with 'SYN' should bypass, other flag should be sent after drain 17752974e916SYuri Benditovich * to prevent out of order */ 17762974e916SYuri Benditovich static int virtio_net_rsc_tcp_ctrl_check(VirtioNetRscChain *chain, 17772974e916SYuri Benditovich struct tcp_header *tcp) 17782974e916SYuri Benditovich { 17792974e916SYuri Benditovich uint16_t tcp_hdr; 17802974e916SYuri Benditovich uint16_t tcp_flag; 17812974e916SYuri Benditovich 17822974e916SYuri Benditovich tcp_flag = htons(tcp->th_offset_flags); 17832974e916SYuri Benditovich tcp_hdr = (tcp_flag & VIRTIO_NET_TCP_HDR_LENGTH) >> 10; 17842974e916SYuri Benditovich tcp_flag &= VIRTIO_NET_TCP_FLAG; 17852974e916SYuri Benditovich tcp_flag = htons(tcp->th_offset_flags) & 0x3F; 17862974e916SYuri Benditovich if (tcp_flag & TH_SYN) { 17872974e916SYuri Benditovich chain->stat.tcp_syn++; 17882974e916SYuri Benditovich return RSC_BYPASS; 17892974e916SYuri Benditovich } 17902974e916SYuri Benditovich 17912974e916SYuri Benditovich if (tcp_flag & (TH_FIN | TH_URG | TH_RST | TH_ECE | TH_CWR)) { 17922974e916SYuri Benditovich chain->stat.tcp_ctrl_drain++; 17932974e916SYuri Benditovich return RSC_FINAL; 17942974e916SYuri Benditovich } 17952974e916SYuri Benditovich 17962974e916SYuri Benditovich if (tcp_hdr > sizeof(struct tcp_header)) { 17972974e916SYuri Benditovich chain->stat.tcp_all_opt++; 17982974e916SYuri Benditovich return RSC_FINAL; 17992974e916SYuri Benditovich } 18002974e916SYuri Benditovich 18012974e916SYuri Benditovich return RSC_CANDIDATE; 18022974e916SYuri Benditovich } 18032974e916SYuri Benditovich 18042974e916SYuri Benditovich static size_t virtio_net_rsc_do_coalesce(VirtioNetRscChain *chain, 18052974e916SYuri Benditovich NetClientState *nc, 18062974e916SYuri Benditovich const uint8_t *buf, size_t size, 18072974e916SYuri Benditovich VirtioNetRscUnit *unit) 18082974e916SYuri Benditovich { 18092974e916SYuri Benditovich int ret; 18102974e916SYuri Benditovich VirtioNetRscSeg *seg, *nseg; 18112974e916SYuri Benditovich 18122974e916SYuri Benditovich if (QTAILQ_EMPTY(&chain->buffers)) { 18132974e916SYuri Benditovich chain->stat.empty_cache++; 18142974e916SYuri Benditovich virtio_net_rsc_cache_buf(chain, nc, buf, size); 18152974e916SYuri Benditovich timer_mod(chain->drain_timer, 18162974e916SYuri Benditovich qemu_clock_get_ns(QEMU_CLOCK_HOST) + chain->n->rsc_timeout); 18172974e916SYuri Benditovich return size; 18182974e916SYuri Benditovich } 18192974e916SYuri Benditovich 18202974e916SYuri Benditovich QTAILQ_FOREACH_SAFE(seg, &chain->buffers, next, nseg) { 18212974e916SYuri Benditovich if (chain->proto == ETH_P_IP) { 18222974e916SYuri Benditovich ret = virtio_net_rsc_coalesce4(chain, seg, buf, size, unit); 18232974e916SYuri Benditovich } else { 18242974e916SYuri Benditovich ret = virtio_net_rsc_coalesce6(chain, seg, buf, size, unit); 18252974e916SYuri Benditovich } 18262974e916SYuri Benditovich 18272974e916SYuri Benditovich if (ret == RSC_FINAL) { 18282974e916SYuri Benditovich if (virtio_net_rsc_drain_seg(chain, seg) == 0) { 18292974e916SYuri Benditovich /* Send failed */ 18302974e916SYuri Benditovich chain->stat.final_failed++; 18312974e916SYuri Benditovich return 0; 18322974e916SYuri Benditovich } 18332974e916SYuri Benditovich 18342974e916SYuri Benditovich /* Send current packet */ 18352974e916SYuri Benditovich return virtio_net_do_receive(nc, buf, size); 18362974e916SYuri Benditovich } else if (ret == RSC_NO_MATCH) { 18372974e916SYuri Benditovich continue; 18382974e916SYuri Benditovich } else { 18392974e916SYuri Benditovich /* Coalesced, mark coalesced flag to tell calc cksum for ipv4 */ 18402974e916SYuri Benditovich seg->is_coalesced = 1; 18412974e916SYuri Benditovich return size; 18422974e916SYuri Benditovich } 18432974e916SYuri Benditovich } 18442974e916SYuri Benditovich 18452974e916SYuri Benditovich chain->stat.no_match_cache++; 18462974e916SYuri Benditovich virtio_net_rsc_cache_buf(chain, nc, buf, size); 18472974e916SYuri Benditovich return size; 18482974e916SYuri Benditovich } 18492974e916SYuri Benditovich 18502974e916SYuri Benditovich /* Drain a connection data, this is to avoid out of order segments */ 18512974e916SYuri Benditovich static size_t virtio_net_rsc_drain_flow(VirtioNetRscChain *chain, 18522974e916SYuri Benditovich NetClientState *nc, 18532974e916SYuri Benditovich const uint8_t *buf, size_t size, 18542974e916SYuri Benditovich uint16_t ip_start, uint16_t ip_size, 18552974e916SYuri Benditovich uint16_t tcp_port) 18562974e916SYuri Benditovich { 18572974e916SYuri Benditovich VirtioNetRscSeg *seg, *nseg; 18582974e916SYuri Benditovich uint32_t ppair1, ppair2; 18592974e916SYuri Benditovich 18602974e916SYuri Benditovich ppair1 = *(uint32_t *)(buf + tcp_port); 18612974e916SYuri Benditovich QTAILQ_FOREACH_SAFE(seg, &chain->buffers, next, nseg) { 18622974e916SYuri Benditovich ppair2 = *(uint32_t *)(seg->buf + tcp_port); 18632974e916SYuri Benditovich if (memcmp(buf + ip_start, seg->buf + ip_start, ip_size) 18642974e916SYuri Benditovich || (ppair1 != ppair2)) { 18652974e916SYuri Benditovich continue; 18662974e916SYuri Benditovich } 18672974e916SYuri Benditovich if (virtio_net_rsc_drain_seg(chain, seg) == 0) { 18682974e916SYuri Benditovich chain->stat.drain_failed++; 18692974e916SYuri Benditovich } 18702974e916SYuri Benditovich 18712974e916SYuri Benditovich break; 18722974e916SYuri Benditovich } 18732974e916SYuri Benditovich 18742974e916SYuri Benditovich return virtio_net_do_receive(nc, buf, size); 18752974e916SYuri Benditovich } 18762974e916SYuri Benditovich 18772974e916SYuri Benditovich static int32_t virtio_net_rsc_sanity_check4(VirtioNetRscChain *chain, 18782974e916SYuri Benditovich struct ip_header *ip, 18792974e916SYuri Benditovich const uint8_t *buf, size_t size) 18802974e916SYuri Benditovich { 18812974e916SYuri Benditovich uint16_t ip_len; 18822974e916SYuri Benditovich 18832974e916SYuri Benditovich /* Not an ipv4 packet */ 18842974e916SYuri Benditovich if (((ip->ip_ver_len & 0xF0) >> 4) != IP_HEADER_VERSION_4) { 18852974e916SYuri Benditovich chain->stat.ip_option++; 18862974e916SYuri Benditovich return RSC_BYPASS; 18872974e916SYuri Benditovich } 18882974e916SYuri Benditovich 18892974e916SYuri Benditovich /* Don't handle packets with ip option */ 18902974e916SYuri Benditovich if ((ip->ip_ver_len & 0xF) != VIRTIO_NET_IP4_HEADER_LENGTH) { 18912974e916SYuri Benditovich chain->stat.ip_option++; 18922974e916SYuri Benditovich return RSC_BYPASS; 18932974e916SYuri Benditovich } 18942974e916SYuri Benditovich 18952974e916SYuri Benditovich if (ip->ip_p != IPPROTO_TCP) { 18962974e916SYuri Benditovich chain->stat.bypass_not_tcp++; 18972974e916SYuri Benditovich return RSC_BYPASS; 18982974e916SYuri Benditovich } 18992974e916SYuri Benditovich 19002974e916SYuri Benditovich /* Don't handle packets with ip fragment */ 19012974e916SYuri Benditovich if (!(htons(ip->ip_off) & IP_DF)) { 19022974e916SYuri Benditovich chain->stat.ip_frag++; 19032974e916SYuri Benditovich return RSC_BYPASS; 19042974e916SYuri Benditovich } 19052974e916SYuri Benditovich 19062974e916SYuri Benditovich /* Don't handle packets with ecn flag */ 19072974e916SYuri Benditovich if (IPTOS_ECN(ip->ip_tos)) { 19082974e916SYuri Benditovich chain->stat.ip_ecn++; 19092974e916SYuri Benditovich return RSC_BYPASS; 19102974e916SYuri Benditovich } 19112974e916SYuri Benditovich 19122974e916SYuri Benditovich ip_len = htons(ip->ip_len); 19132974e916SYuri Benditovich if (ip_len < (sizeof(struct ip_header) + sizeof(struct tcp_header)) 19142974e916SYuri Benditovich || ip_len > (size - chain->n->guest_hdr_len - 19152974e916SYuri Benditovich sizeof(struct eth_header))) { 19162974e916SYuri Benditovich chain->stat.ip_hacked++; 19172974e916SYuri Benditovich return RSC_BYPASS; 19182974e916SYuri Benditovich } 19192974e916SYuri Benditovich 19202974e916SYuri Benditovich return RSC_CANDIDATE; 19212974e916SYuri Benditovich } 19222974e916SYuri Benditovich 19232974e916SYuri Benditovich static size_t virtio_net_rsc_receive4(VirtioNetRscChain *chain, 19242974e916SYuri Benditovich NetClientState *nc, 19252974e916SYuri Benditovich const uint8_t *buf, size_t size) 19262974e916SYuri Benditovich { 19272974e916SYuri Benditovich int32_t ret; 19282974e916SYuri Benditovich uint16_t hdr_len; 19292974e916SYuri Benditovich VirtioNetRscUnit unit; 19302974e916SYuri Benditovich 19312974e916SYuri Benditovich hdr_len = ((VirtIONet *)(chain->n))->guest_hdr_len; 19322974e916SYuri Benditovich 19332974e916SYuri Benditovich if (size < (hdr_len + sizeof(struct eth_header) + sizeof(struct ip_header) 19342974e916SYuri Benditovich + sizeof(struct tcp_header))) { 19352974e916SYuri Benditovich chain->stat.bypass_not_tcp++; 19362974e916SYuri Benditovich return virtio_net_do_receive(nc, buf, size); 19372974e916SYuri Benditovich } 19382974e916SYuri Benditovich 19392974e916SYuri Benditovich virtio_net_rsc_extract_unit4(chain, buf, &unit); 19402974e916SYuri Benditovich if (virtio_net_rsc_sanity_check4(chain, unit.ip, buf, size) 19412974e916SYuri Benditovich != RSC_CANDIDATE) { 19422974e916SYuri Benditovich return virtio_net_do_receive(nc, buf, size); 19432974e916SYuri Benditovich } 19442974e916SYuri Benditovich 19452974e916SYuri Benditovich ret = virtio_net_rsc_tcp_ctrl_check(chain, unit.tcp); 19462974e916SYuri Benditovich if (ret == RSC_BYPASS) { 19472974e916SYuri Benditovich return virtio_net_do_receive(nc, buf, size); 19482974e916SYuri Benditovich } else if (ret == RSC_FINAL) { 19492974e916SYuri Benditovich return virtio_net_rsc_drain_flow(chain, nc, buf, size, 19502974e916SYuri Benditovich ((hdr_len + sizeof(struct eth_header)) + 12), 19512974e916SYuri Benditovich VIRTIO_NET_IP4_ADDR_SIZE, 19522974e916SYuri Benditovich hdr_len + sizeof(struct eth_header) + sizeof(struct ip_header)); 19532974e916SYuri Benditovich } 19542974e916SYuri Benditovich 19552974e916SYuri Benditovich return virtio_net_rsc_do_coalesce(chain, nc, buf, size, &unit); 19562974e916SYuri Benditovich } 19572974e916SYuri Benditovich 19582974e916SYuri Benditovich static int32_t virtio_net_rsc_sanity_check6(VirtioNetRscChain *chain, 19592974e916SYuri Benditovich struct ip6_header *ip6, 19602974e916SYuri Benditovich const uint8_t *buf, size_t size) 19612974e916SYuri Benditovich { 19622974e916SYuri Benditovich uint16_t ip_len; 19632974e916SYuri Benditovich 19642974e916SYuri Benditovich if (((ip6->ip6_ctlun.ip6_un1.ip6_un1_flow & 0xF0) >> 4) 19652974e916SYuri Benditovich != IP_HEADER_VERSION_6) { 19662974e916SYuri Benditovich return RSC_BYPASS; 19672974e916SYuri Benditovich } 19682974e916SYuri Benditovich 19692974e916SYuri Benditovich /* Both option and protocol is checked in this */ 19702974e916SYuri Benditovich if (ip6->ip6_ctlun.ip6_un1.ip6_un1_nxt != IPPROTO_TCP) { 19712974e916SYuri Benditovich chain->stat.bypass_not_tcp++; 19722974e916SYuri Benditovich return RSC_BYPASS; 19732974e916SYuri Benditovich } 19742974e916SYuri Benditovich 19752974e916SYuri Benditovich ip_len = htons(ip6->ip6_ctlun.ip6_un1.ip6_un1_plen); 19762974e916SYuri Benditovich if (ip_len < sizeof(struct tcp_header) || 19772974e916SYuri Benditovich ip_len > (size - chain->n->guest_hdr_len - sizeof(struct eth_header) 19782974e916SYuri Benditovich - sizeof(struct ip6_header))) { 19792974e916SYuri Benditovich chain->stat.ip_hacked++; 19802974e916SYuri Benditovich return RSC_BYPASS; 19812974e916SYuri Benditovich } 19822974e916SYuri Benditovich 19832974e916SYuri Benditovich /* Don't handle packets with ecn flag */ 19842974e916SYuri Benditovich if (IP6_ECN(ip6->ip6_ctlun.ip6_un3.ip6_un3_ecn)) { 19852974e916SYuri Benditovich chain->stat.ip_ecn++; 19862974e916SYuri Benditovich return RSC_BYPASS; 19872974e916SYuri Benditovich } 19882974e916SYuri Benditovich 19892974e916SYuri Benditovich return RSC_CANDIDATE; 19902974e916SYuri Benditovich } 19912974e916SYuri Benditovich 19922974e916SYuri Benditovich static size_t virtio_net_rsc_receive6(void *opq, NetClientState *nc, 19932974e916SYuri Benditovich const uint8_t *buf, size_t size) 19942974e916SYuri Benditovich { 19952974e916SYuri Benditovich int32_t ret; 19962974e916SYuri Benditovich uint16_t hdr_len; 19972974e916SYuri Benditovich VirtioNetRscChain *chain; 19982974e916SYuri Benditovich VirtioNetRscUnit unit; 19992974e916SYuri Benditovich 20002974e916SYuri Benditovich chain = (VirtioNetRscChain *)opq; 20012974e916SYuri Benditovich hdr_len = ((VirtIONet *)(chain->n))->guest_hdr_len; 20022974e916SYuri Benditovich 20032974e916SYuri Benditovich if (size < (hdr_len + sizeof(struct eth_header) + sizeof(struct ip6_header) 20042974e916SYuri Benditovich + sizeof(tcp_header))) { 20052974e916SYuri Benditovich return virtio_net_do_receive(nc, buf, size); 20062974e916SYuri Benditovich } 20072974e916SYuri Benditovich 20082974e916SYuri Benditovich virtio_net_rsc_extract_unit6(chain, buf, &unit); 20092974e916SYuri Benditovich if (RSC_CANDIDATE != virtio_net_rsc_sanity_check6(chain, 20102974e916SYuri Benditovich unit.ip, buf, size)) { 20112974e916SYuri Benditovich return virtio_net_do_receive(nc, buf, size); 20122974e916SYuri Benditovich } 20132974e916SYuri Benditovich 20142974e916SYuri Benditovich ret = virtio_net_rsc_tcp_ctrl_check(chain, unit.tcp); 20152974e916SYuri Benditovich if (ret == RSC_BYPASS) { 20162974e916SYuri Benditovich return virtio_net_do_receive(nc, buf, size); 20172974e916SYuri Benditovich } else if (ret == RSC_FINAL) { 20182974e916SYuri Benditovich return virtio_net_rsc_drain_flow(chain, nc, buf, size, 20192974e916SYuri Benditovich ((hdr_len + sizeof(struct eth_header)) + 8), 20202974e916SYuri Benditovich VIRTIO_NET_IP6_ADDR_SIZE, 20212974e916SYuri Benditovich hdr_len + sizeof(struct eth_header) 20222974e916SYuri Benditovich + sizeof(struct ip6_header)); 20232974e916SYuri Benditovich } 20242974e916SYuri Benditovich 20252974e916SYuri Benditovich return virtio_net_rsc_do_coalesce(chain, nc, buf, size, &unit); 20262974e916SYuri Benditovich } 20272974e916SYuri Benditovich 20282974e916SYuri Benditovich static VirtioNetRscChain *virtio_net_rsc_lookup_chain(VirtIONet *n, 20292974e916SYuri Benditovich NetClientState *nc, 20302974e916SYuri Benditovich uint16_t proto) 20312974e916SYuri Benditovich { 20322974e916SYuri Benditovich VirtioNetRscChain *chain; 20332974e916SYuri Benditovich 20342974e916SYuri Benditovich if ((proto != (uint16_t)ETH_P_IP) && (proto != (uint16_t)ETH_P_IPV6)) { 20352974e916SYuri Benditovich return NULL; 20362974e916SYuri Benditovich } 20372974e916SYuri Benditovich 20382974e916SYuri Benditovich QTAILQ_FOREACH(chain, &n->rsc_chains, next) { 20392974e916SYuri Benditovich if (chain->proto == proto) { 20402974e916SYuri Benditovich return chain; 20412974e916SYuri Benditovich } 20422974e916SYuri Benditovich } 20432974e916SYuri Benditovich 20442974e916SYuri Benditovich chain = g_malloc(sizeof(*chain)); 20452974e916SYuri Benditovich chain->n = n; 20462974e916SYuri Benditovich chain->proto = proto; 20472974e916SYuri Benditovich if (proto == (uint16_t)ETH_P_IP) { 20482974e916SYuri Benditovich chain->max_payload = VIRTIO_NET_MAX_IP4_PAYLOAD; 20492974e916SYuri Benditovich chain->gso_type = VIRTIO_NET_HDR_GSO_TCPV4; 20502974e916SYuri Benditovich } else { 20512974e916SYuri Benditovich chain->max_payload = VIRTIO_NET_MAX_IP6_PAYLOAD; 20522974e916SYuri Benditovich chain->gso_type = VIRTIO_NET_HDR_GSO_TCPV6; 20532974e916SYuri Benditovich } 20542974e916SYuri Benditovich chain->drain_timer = timer_new_ns(QEMU_CLOCK_HOST, 20552974e916SYuri Benditovich virtio_net_rsc_purge, chain); 20562974e916SYuri Benditovich memset(&chain->stat, 0, sizeof(chain->stat)); 20572974e916SYuri Benditovich 20582974e916SYuri Benditovich QTAILQ_INIT(&chain->buffers); 20592974e916SYuri Benditovich QTAILQ_INSERT_TAIL(&n->rsc_chains, chain, next); 20602974e916SYuri Benditovich 20612974e916SYuri Benditovich return chain; 20622974e916SYuri Benditovich } 20632974e916SYuri Benditovich 20642974e916SYuri Benditovich static ssize_t virtio_net_rsc_receive(NetClientState *nc, 20652974e916SYuri Benditovich const uint8_t *buf, 20662974e916SYuri Benditovich size_t size) 20672974e916SYuri Benditovich { 20682974e916SYuri Benditovich uint16_t proto; 20692974e916SYuri Benditovich VirtioNetRscChain *chain; 20702974e916SYuri Benditovich struct eth_header *eth; 20712974e916SYuri Benditovich VirtIONet *n; 20722974e916SYuri Benditovich 20732974e916SYuri Benditovich n = qemu_get_nic_opaque(nc); 20742974e916SYuri Benditovich if (size < (n->host_hdr_len + sizeof(struct eth_header))) { 20752974e916SYuri Benditovich return virtio_net_do_receive(nc, buf, size); 20762974e916SYuri Benditovich } 20772974e916SYuri Benditovich 20782974e916SYuri Benditovich eth = (struct eth_header *)(buf + n->guest_hdr_len); 20792974e916SYuri Benditovich proto = htons(eth->h_proto); 20802974e916SYuri Benditovich 20812974e916SYuri Benditovich chain = virtio_net_rsc_lookup_chain(n, nc, proto); 20822974e916SYuri Benditovich if (chain) { 20832974e916SYuri Benditovich chain->stat.received++; 20842974e916SYuri Benditovich if (proto == (uint16_t)ETH_P_IP && n->rsc4_enabled) { 20852974e916SYuri Benditovich return virtio_net_rsc_receive4(chain, nc, buf, size); 20862974e916SYuri Benditovich } else if (proto == (uint16_t)ETH_P_IPV6 && n->rsc6_enabled) { 20872974e916SYuri Benditovich return virtio_net_rsc_receive6(chain, nc, buf, size); 20882974e916SYuri Benditovich } 20892974e916SYuri Benditovich } 20902974e916SYuri Benditovich return virtio_net_do_receive(nc, buf, size); 20912974e916SYuri Benditovich } 20922974e916SYuri Benditovich 20932974e916SYuri Benditovich static ssize_t virtio_net_receive(NetClientState *nc, const uint8_t *buf, 20942974e916SYuri Benditovich size_t size) 20952974e916SYuri Benditovich { 20962974e916SYuri Benditovich VirtIONet *n = qemu_get_nic_opaque(nc); 20972974e916SYuri Benditovich if ((n->rsc4_enabled || n->rsc6_enabled)) { 20982974e916SYuri Benditovich return virtio_net_rsc_receive(nc, buf, size); 20992974e916SYuri Benditovich } else { 21002974e916SYuri Benditovich return virtio_net_do_receive(nc, buf, size); 21012974e916SYuri Benditovich } 21022974e916SYuri Benditovich } 21032974e916SYuri Benditovich 21046e790746SPaolo Bonzini static int32_t virtio_net_flush_tx(VirtIONetQueue *q); 21056e790746SPaolo Bonzini 21066e790746SPaolo Bonzini static void virtio_net_tx_complete(NetClientState *nc, ssize_t len) 21076e790746SPaolo Bonzini { 21086e790746SPaolo Bonzini VirtIONet *n = qemu_get_nic_opaque(nc); 21096e790746SPaolo Bonzini VirtIONetQueue *q = virtio_net_get_subqueue(nc); 211017a0ca55SKONRAD Frederic VirtIODevice *vdev = VIRTIO_DEVICE(n); 21116e790746SPaolo Bonzini 211251b19ebeSPaolo Bonzini virtqueue_push(q->tx_vq, q->async_tx.elem, 0); 211317a0ca55SKONRAD Frederic virtio_notify(vdev, q->tx_vq); 21146e790746SPaolo Bonzini 211551b19ebeSPaolo Bonzini g_free(q->async_tx.elem); 211651b19ebeSPaolo Bonzini q->async_tx.elem = NULL; 21176e790746SPaolo Bonzini 21186e790746SPaolo Bonzini virtio_queue_set_notification(q->tx_vq, 1); 21196e790746SPaolo Bonzini virtio_net_flush_tx(q); 21206e790746SPaolo Bonzini } 21216e790746SPaolo Bonzini 21226e790746SPaolo Bonzini /* TX */ 21236e790746SPaolo Bonzini static int32_t virtio_net_flush_tx(VirtIONetQueue *q) 21246e790746SPaolo Bonzini { 21256e790746SPaolo Bonzini VirtIONet *n = q->n; 212617a0ca55SKONRAD Frederic VirtIODevice *vdev = VIRTIO_DEVICE(n); 212751b19ebeSPaolo Bonzini VirtQueueElement *elem; 21286e790746SPaolo Bonzini int32_t num_packets = 0; 21296e790746SPaolo Bonzini int queue_index = vq2q(virtio_get_queue_index(q->tx_vq)); 213017a0ca55SKONRAD Frederic if (!(vdev->status & VIRTIO_CONFIG_S_DRIVER_OK)) { 21316e790746SPaolo Bonzini return num_packets; 21326e790746SPaolo Bonzini } 21336e790746SPaolo Bonzini 213451b19ebeSPaolo Bonzini if (q->async_tx.elem) { 21356e790746SPaolo Bonzini virtio_queue_set_notification(q->tx_vq, 0); 21366e790746SPaolo Bonzini return num_packets; 21376e790746SPaolo Bonzini } 21386e790746SPaolo Bonzini 213951b19ebeSPaolo Bonzini for (;;) { 2140bd89dd98SJason Wang ssize_t ret; 214151b19ebeSPaolo Bonzini unsigned int out_num; 214251b19ebeSPaolo Bonzini struct iovec sg[VIRTQUEUE_MAX_SIZE], sg2[VIRTQUEUE_MAX_SIZE + 1], *out_sg; 2143feb93f36SJason Wang struct virtio_net_hdr_mrg_rxbuf mhdr; 21446e790746SPaolo Bonzini 214551b19ebeSPaolo Bonzini elem = virtqueue_pop(q->tx_vq, sizeof(VirtQueueElement)); 214651b19ebeSPaolo Bonzini if (!elem) { 214751b19ebeSPaolo Bonzini break; 214851b19ebeSPaolo Bonzini } 214951b19ebeSPaolo Bonzini 215051b19ebeSPaolo Bonzini out_num = elem->out_num; 215151b19ebeSPaolo Bonzini out_sg = elem->out_sg; 21526e790746SPaolo Bonzini if (out_num < 1) { 2153fa5e56c2SGreg Kurz virtio_error(vdev, "virtio-net header not in first element"); 2154fa5e56c2SGreg Kurz virtqueue_detach_element(q->tx_vq, elem, 0); 2155fa5e56c2SGreg Kurz g_free(elem); 2156fa5e56c2SGreg Kurz return -EINVAL; 21576e790746SPaolo Bonzini } 21586e790746SPaolo Bonzini 2159032a74a1SCédric Le Goater if (n->has_vnet_hdr) { 2160feb93f36SJason Wang if (iov_to_buf(out_sg, out_num, 0, &mhdr, n->guest_hdr_len) < 2161feb93f36SJason Wang n->guest_hdr_len) { 2162fa5e56c2SGreg Kurz virtio_error(vdev, "virtio-net header incorrect"); 2163fa5e56c2SGreg Kurz virtqueue_detach_element(q->tx_vq, elem, 0); 2164fa5e56c2SGreg Kurz g_free(elem); 2165fa5e56c2SGreg Kurz return -EINVAL; 2166032a74a1SCédric Le Goater } 21671bfa316cSGreg Kurz if (n->needs_vnet_hdr_swap) { 2168feb93f36SJason Wang virtio_net_hdr_swap(vdev, (void *) &mhdr); 2169feb93f36SJason Wang sg2[0].iov_base = &mhdr; 2170feb93f36SJason Wang sg2[0].iov_len = n->guest_hdr_len; 2171feb93f36SJason Wang out_num = iov_copy(&sg2[1], ARRAY_SIZE(sg2) - 1, 2172feb93f36SJason Wang out_sg, out_num, 2173feb93f36SJason Wang n->guest_hdr_len, -1); 2174feb93f36SJason Wang if (out_num == VIRTQUEUE_MAX_SIZE) { 2175feb93f36SJason Wang goto drop; 2176032a74a1SCédric Le Goater } 2177feb93f36SJason Wang out_num += 1; 2178feb93f36SJason Wang out_sg = sg2; 2179feb93f36SJason Wang } 2180feb93f36SJason Wang } 21816e790746SPaolo Bonzini /* 21826e790746SPaolo Bonzini * If host wants to see the guest header as is, we can 21836e790746SPaolo Bonzini * pass it on unchanged. Otherwise, copy just the parts 21846e790746SPaolo Bonzini * that host is interested in. 21856e790746SPaolo Bonzini */ 21866e790746SPaolo Bonzini assert(n->host_hdr_len <= n->guest_hdr_len); 21876e790746SPaolo Bonzini if (n->host_hdr_len != n->guest_hdr_len) { 21886e790746SPaolo Bonzini unsigned sg_num = iov_copy(sg, ARRAY_SIZE(sg), 21896e790746SPaolo Bonzini out_sg, out_num, 21906e790746SPaolo Bonzini 0, n->host_hdr_len); 21916e790746SPaolo Bonzini sg_num += iov_copy(sg + sg_num, ARRAY_SIZE(sg) - sg_num, 21926e790746SPaolo Bonzini out_sg, out_num, 21936e790746SPaolo Bonzini n->guest_hdr_len, -1); 21946e790746SPaolo Bonzini out_num = sg_num; 21956e790746SPaolo Bonzini out_sg = sg; 21966e790746SPaolo Bonzini } 21976e790746SPaolo Bonzini 21986e790746SPaolo Bonzini ret = qemu_sendv_packet_async(qemu_get_subqueue(n->nic, queue_index), 21996e790746SPaolo Bonzini out_sg, out_num, virtio_net_tx_complete); 22006e790746SPaolo Bonzini if (ret == 0) { 22016e790746SPaolo Bonzini virtio_queue_set_notification(q->tx_vq, 0); 22026e790746SPaolo Bonzini q->async_tx.elem = elem; 22036e790746SPaolo Bonzini return -EBUSY; 22046e790746SPaolo Bonzini } 22056e790746SPaolo Bonzini 2206feb93f36SJason Wang drop: 220751b19ebeSPaolo Bonzini virtqueue_push(q->tx_vq, elem, 0); 220817a0ca55SKONRAD Frederic virtio_notify(vdev, q->tx_vq); 220951b19ebeSPaolo Bonzini g_free(elem); 22106e790746SPaolo Bonzini 22116e790746SPaolo Bonzini if (++num_packets >= n->tx_burst) { 22126e790746SPaolo Bonzini break; 22136e790746SPaolo Bonzini } 22146e790746SPaolo Bonzini } 22156e790746SPaolo Bonzini return num_packets; 22166e790746SPaolo Bonzini } 22176e790746SPaolo Bonzini 22186e790746SPaolo Bonzini static void virtio_net_handle_tx_timer(VirtIODevice *vdev, VirtQueue *vq) 22196e790746SPaolo Bonzini { 222017a0ca55SKONRAD Frederic VirtIONet *n = VIRTIO_NET(vdev); 22216e790746SPaolo Bonzini VirtIONetQueue *q = &n->vqs[vq2q(virtio_get_queue_index(vq))]; 22226e790746SPaolo Bonzini 2223283e2c2aSYuri Benditovich if (unlikely((n->status & VIRTIO_NET_S_LINK_UP) == 0)) { 2224283e2c2aSYuri Benditovich virtio_net_drop_tx_queue_data(vdev, vq); 2225283e2c2aSYuri Benditovich return; 2226283e2c2aSYuri Benditovich } 2227283e2c2aSYuri Benditovich 22286e790746SPaolo Bonzini /* This happens when device was stopped but VCPU wasn't. */ 222917a0ca55SKONRAD Frederic if (!vdev->vm_running) { 22306e790746SPaolo Bonzini q->tx_waiting = 1; 22316e790746SPaolo Bonzini return; 22326e790746SPaolo Bonzini } 22336e790746SPaolo Bonzini 22346e790746SPaolo Bonzini if (q->tx_waiting) { 22356e790746SPaolo Bonzini virtio_queue_set_notification(vq, 1); 2236bc72ad67SAlex Bligh timer_del(q->tx_timer); 22376e790746SPaolo Bonzini q->tx_waiting = 0; 2238fa5e56c2SGreg Kurz if (virtio_net_flush_tx(q) == -EINVAL) { 2239fa5e56c2SGreg Kurz return; 2240fa5e56c2SGreg Kurz } 22416e790746SPaolo Bonzini } else { 2242bc72ad67SAlex Bligh timer_mod(q->tx_timer, 2243bc72ad67SAlex Bligh qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + n->tx_timeout); 22446e790746SPaolo Bonzini q->tx_waiting = 1; 22456e790746SPaolo Bonzini virtio_queue_set_notification(vq, 0); 22466e790746SPaolo Bonzini } 22476e790746SPaolo Bonzini } 22486e790746SPaolo Bonzini 22496e790746SPaolo Bonzini static void virtio_net_handle_tx_bh(VirtIODevice *vdev, VirtQueue *vq) 22506e790746SPaolo Bonzini { 225117a0ca55SKONRAD Frederic VirtIONet *n = VIRTIO_NET(vdev); 22526e790746SPaolo Bonzini VirtIONetQueue *q = &n->vqs[vq2q(virtio_get_queue_index(vq))]; 22536e790746SPaolo Bonzini 2254283e2c2aSYuri Benditovich if (unlikely((n->status & VIRTIO_NET_S_LINK_UP) == 0)) { 2255283e2c2aSYuri Benditovich virtio_net_drop_tx_queue_data(vdev, vq); 2256283e2c2aSYuri Benditovich return; 2257283e2c2aSYuri Benditovich } 2258283e2c2aSYuri Benditovich 22596e790746SPaolo Bonzini if (unlikely(q->tx_waiting)) { 22606e790746SPaolo Bonzini return; 22616e790746SPaolo Bonzini } 22626e790746SPaolo Bonzini q->tx_waiting = 1; 22636e790746SPaolo Bonzini /* This happens when device was stopped but VCPU wasn't. */ 226417a0ca55SKONRAD Frederic if (!vdev->vm_running) { 22656e790746SPaolo Bonzini return; 22666e790746SPaolo Bonzini } 22676e790746SPaolo Bonzini virtio_queue_set_notification(vq, 0); 22686e790746SPaolo Bonzini qemu_bh_schedule(q->tx_bh); 22696e790746SPaolo Bonzini } 22706e790746SPaolo Bonzini 22716e790746SPaolo Bonzini static void virtio_net_tx_timer(void *opaque) 22726e790746SPaolo Bonzini { 22736e790746SPaolo Bonzini VirtIONetQueue *q = opaque; 22746e790746SPaolo Bonzini VirtIONet *n = q->n; 227517a0ca55SKONRAD Frederic VirtIODevice *vdev = VIRTIO_DEVICE(n); 2276e8bcf842SMichael S. Tsirkin /* This happens when device was stopped but BH wasn't. */ 2277e8bcf842SMichael S. Tsirkin if (!vdev->vm_running) { 2278e8bcf842SMichael S. Tsirkin /* Make sure tx waiting is set, so we'll run when restarted. */ 2279e8bcf842SMichael S. Tsirkin assert(q->tx_waiting); 2280e8bcf842SMichael S. Tsirkin return; 2281e8bcf842SMichael S. Tsirkin } 22826e790746SPaolo Bonzini 22836e790746SPaolo Bonzini q->tx_waiting = 0; 22846e790746SPaolo Bonzini 22856e790746SPaolo Bonzini /* Just in case the driver is not ready on more */ 228617a0ca55SKONRAD Frederic if (!(vdev->status & VIRTIO_CONFIG_S_DRIVER_OK)) { 22876e790746SPaolo Bonzini return; 228817a0ca55SKONRAD Frederic } 22896e790746SPaolo Bonzini 22906e790746SPaolo Bonzini virtio_queue_set_notification(q->tx_vq, 1); 22916e790746SPaolo Bonzini virtio_net_flush_tx(q); 22926e790746SPaolo Bonzini } 22936e790746SPaolo Bonzini 22946e790746SPaolo Bonzini static void virtio_net_tx_bh(void *opaque) 22956e790746SPaolo Bonzini { 22966e790746SPaolo Bonzini VirtIONetQueue *q = opaque; 22976e790746SPaolo Bonzini VirtIONet *n = q->n; 229817a0ca55SKONRAD Frederic VirtIODevice *vdev = VIRTIO_DEVICE(n); 22996e790746SPaolo Bonzini int32_t ret; 23006e790746SPaolo Bonzini 2301e8bcf842SMichael S. Tsirkin /* This happens when device was stopped but BH wasn't. */ 2302e8bcf842SMichael S. Tsirkin if (!vdev->vm_running) { 2303e8bcf842SMichael S. Tsirkin /* Make sure tx waiting is set, so we'll run when restarted. */ 2304e8bcf842SMichael S. Tsirkin assert(q->tx_waiting); 2305e8bcf842SMichael S. Tsirkin return; 2306e8bcf842SMichael S. Tsirkin } 23076e790746SPaolo Bonzini 23086e790746SPaolo Bonzini q->tx_waiting = 0; 23096e790746SPaolo Bonzini 23106e790746SPaolo Bonzini /* Just in case the driver is not ready on more */ 231117a0ca55SKONRAD Frederic if (unlikely(!(vdev->status & VIRTIO_CONFIG_S_DRIVER_OK))) { 23126e790746SPaolo Bonzini return; 231317a0ca55SKONRAD Frederic } 23146e790746SPaolo Bonzini 23156e790746SPaolo Bonzini ret = virtio_net_flush_tx(q); 2316fa5e56c2SGreg Kurz if (ret == -EBUSY || ret == -EINVAL) { 2317fa5e56c2SGreg Kurz return; /* Notification re-enable handled by tx_complete or device 2318fa5e56c2SGreg Kurz * broken */ 23196e790746SPaolo Bonzini } 23206e790746SPaolo Bonzini 23216e790746SPaolo Bonzini /* If we flush a full burst of packets, assume there are 23226e790746SPaolo Bonzini * more coming and immediately reschedule */ 23236e790746SPaolo Bonzini if (ret >= n->tx_burst) { 23246e790746SPaolo Bonzini qemu_bh_schedule(q->tx_bh); 23256e790746SPaolo Bonzini q->tx_waiting = 1; 23266e790746SPaolo Bonzini return; 23276e790746SPaolo Bonzini } 23286e790746SPaolo Bonzini 23296e790746SPaolo Bonzini /* If less than a full burst, re-enable notification and flush 23306e790746SPaolo Bonzini * anything that may have come in while we weren't looking. If 23316e790746SPaolo Bonzini * we find something, assume the guest is still active and reschedule */ 23326e790746SPaolo Bonzini virtio_queue_set_notification(q->tx_vq, 1); 2333fa5e56c2SGreg Kurz ret = virtio_net_flush_tx(q); 2334fa5e56c2SGreg Kurz if (ret == -EINVAL) { 2335fa5e56c2SGreg Kurz return; 2336fa5e56c2SGreg Kurz } else if (ret > 0) { 23376e790746SPaolo Bonzini virtio_queue_set_notification(q->tx_vq, 0); 23386e790746SPaolo Bonzini qemu_bh_schedule(q->tx_bh); 23396e790746SPaolo Bonzini q->tx_waiting = 1; 23406e790746SPaolo Bonzini } 23416e790746SPaolo Bonzini } 23426e790746SPaolo Bonzini 2343f9d6dbf0SWen Congyang static void virtio_net_add_queue(VirtIONet *n, int index) 2344f9d6dbf0SWen Congyang { 2345f9d6dbf0SWen Congyang VirtIODevice *vdev = VIRTIO_DEVICE(n); 2346f9d6dbf0SWen Congyang 23471c0fbfa3SMichael S. Tsirkin n->vqs[index].rx_vq = virtio_add_queue(vdev, n->net_conf.rx_queue_size, 23481c0fbfa3SMichael S. Tsirkin virtio_net_handle_rx); 23499b02e161SWei Wang 2350f9d6dbf0SWen Congyang if (n->net_conf.tx && !strcmp(n->net_conf.tx, "timer")) { 2351f9d6dbf0SWen Congyang n->vqs[index].tx_vq = 23529b02e161SWei Wang virtio_add_queue(vdev, n->net_conf.tx_queue_size, 23539b02e161SWei Wang virtio_net_handle_tx_timer); 2354f9d6dbf0SWen Congyang n->vqs[index].tx_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, 2355f9d6dbf0SWen Congyang virtio_net_tx_timer, 2356f9d6dbf0SWen Congyang &n->vqs[index]); 2357f9d6dbf0SWen Congyang } else { 2358f9d6dbf0SWen Congyang n->vqs[index].tx_vq = 23599b02e161SWei Wang virtio_add_queue(vdev, n->net_conf.tx_queue_size, 23609b02e161SWei Wang virtio_net_handle_tx_bh); 2361f9d6dbf0SWen Congyang n->vqs[index].tx_bh = qemu_bh_new(virtio_net_tx_bh, &n->vqs[index]); 2362f9d6dbf0SWen Congyang } 2363f9d6dbf0SWen Congyang 2364f9d6dbf0SWen Congyang n->vqs[index].tx_waiting = 0; 2365f9d6dbf0SWen Congyang n->vqs[index].n = n; 2366f9d6dbf0SWen Congyang } 2367f9d6dbf0SWen Congyang 2368f9d6dbf0SWen Congyang static void virtio_net_del_queue(VirtIONet *n, int index) 2369f9d6dbf0SWen Congyang { 2370f9d6dbf0SWen Congyang VirtIODevice *vdev = VIRTIO_DEVICE(n); 2371f9d6dbf0SWen Congyang VirtIONetQueue *q = &n->vqs[index]; 2372f9d6dbf0SWen Congyang NetClientState *nc = qemu_get_subqueue(n->nic, index); 2373f9d6dbf0SWen Congyang 2374f9d6dbf0SWen Congyang qemu_purge_queued_packets(nc); 2375f9d6dbf0SWen Congyang 2376f9d6dbf0SWen Congyang virtio_del_queue(vdev, index * 2); 2377f9d6dbf0SWen Congyang if (q->tx_timer) { 2378f9d6dbf0SWen Congyang timer_del(q->tx_timer); 2379f9d6dbf0SWen Congyang timer_free(q->tx_timer); 2380f989c30cSYunjian Wang q->tx_timer = NULL; 2381f9d6dbf0SWen Congyang } else { 2382f9d6dbf0SWen Congyang qemu_bh_delete(q->tx_bh); 2383f989c30cSYunjian Wang q->tx_bh = NULL; 2384f9d6dbf0SWen Congyang } 2385f989c30cSYunjian Wang q->tx_waiting = 0; 2386f9d6dbf0SWen Congyang virtio_del_queue(vdev, index * 2 + 1); 2387f9d6dbf0SWen Congyang } 2388f9d6dbf0SWen Congyang 2389f9d6dbf0SWen Congyang static void virtio_net_change_num_queues(VirtIONet *n, int new_max_queues) 2390f9d6dbf0SWen Congyang { 2391f9d6dbf0SWen Congyang VirtIODevice *vdev = VIRTIO_DEVICE(n); 2392f9d6dbf0SWen Congyang int old_num_queues = virtio_get_num_queues(vdev); 2393f9d6dbf0SWen Congyang int new_num_queues = new_max_queues * 2 + 1; 2394f9d6dbf0SWen Congyang int i; 2395f9d6dbf0SWen Congyang 2396f9d6dbf0SWen Congyang assert(old_num_queues >= 3); 2397f9d6dbf0SWen Congyang assert(old_num_queues % 2 == 1); 2398f9d6dbf0SWen Congyang 2399f9d6dbf0SWen Congyang if (old_num_queues == new_num_queues) { 2400f9d6dbf0SWen Congyang return; 2401f9d6dbf0SWen Congyang } 2402f9d6dbf0SWen Congyang 2403f9d6dbf0SWen Congyang /* 2404f9d6dbf0SWen Congyang * We always need to remove and add ctrl vq if 2405f9d6dbf0SWen Congyang * old_num_queues != new_num_queues. Remove ctrl_vq first, 240620f86a75SYuval Shaia * and then we only enter one of the following two loops. 2407f9d6dbf0SWen Congyang */ 2408f9d6dbf0SWen Congyang virtio_del_queue(vdev, old_num_queues - 1); 2409f9d6dbf0SWen Congyang 2410f9d6dbf0SWen Congyang for (i = new_num_queues - 1; i < old_num_queues - 1; i += 2) { 2411f9d6dbf0SWen Congyang /* new_num_queues < old_num_queues */ 2412f9d6dbf0SWen Congyang virtio_net_del_queue(n, i / 2); 2413f9d6dbf0SWen Congyang } 2414f9d6dbf0SWen Congyang 2415f9d6dbf0SWen Congyang for (i = old_num_queues - 1; i < new_num_queues - 1; i += 2) { 2416f9d6dbf0SWen Congyang /* new_num_queues > old_num_queues */ 2417f9d6dbf0SWen Congyang virtio_net_add_queue(n, i / 2); 2418f9d6dbf0SWen Congyang } 2419f9d6dbf0SWen Congyang 2420f9d6dbf0SWen Congyang /* add ctrl_vq last */ 2421f9d6dbf0SWen Congyang n->ctrl_vq = virtio_add_queue(vdev, 64, virtio_net_handle_ctrl); 2422f9d6dbf0SWen Congyang } 2423f9d6dbf0SWen Congyang 2424ec57db16SJason Wang static void virtio_net_set_multiqueue(VirtIONet *n, int multiqueue) 24256e790746SPaolo Bonzini { 2426f9d6dbf0SWen Congyang int max = multiqueue ? n->max_queues : 1; 2427f9d6dbf0SWen Congyang 24286e790746SPaolo Bonzini n->multiqueue = multiqueue; 2429f9d6dbf0SWen Congyang virtio_net_change_num_queues(n, max); 24306e790746SPaolo Bonzini 24316e790746SPaolo Bonzini virtio_net_set_queues(n); 24326e790746SPaolo Bonzini } 24336e790746SPaolo Bonzini 2434982b78c5SDr. David Alan Gilbert static int virtio_net_post_load_device(void *opaque, int version_id) 2435037dab2fSGreg Kurz { 2436982b78c5SDr. David Alan Gilbert VirtIONet *n = opaque; 2437982b78c5SDr. David Alan Gilbert VirtIODevice *vdev = VIRTIO_DEVICE(n); 2438037dab2fSGreg Kurz int i, link_down; 2439037dab2fSGreg Kurz 24409d8c6a25SDr. David Alan Gilbert trace_virtio_net_post_load_device(); 2441982b78c5SDr. David Alan Gilbert virtio_net_set_mrg_rx_bufs(n, n->mergeable_rx_bufs, 244295129d6fSCornelia Huck virtio_vdev_has_feature(vdev, 244395129d6fSCornelia Huck VIRTIO_F_VERSION_1)); 24446e790746SPaolo Bonzini 24456e790746SPaolo Bonzini /* MAC_TABLE_ENTRIES may be different from the saved image */ 2446982b78c5SDr. David Alan Gilbert if (n->mac_table.in_use > MAC_TABLE_ENTRIES) { 24476e790746SPaolo Bonzini n->mac_table.in_use = 0; 24486e790746SPaolo Bonzini } 24496e790746SPaolo Bonzini 2450982b78c5SDr. David Alan Gilbert if (!virtio_vdev_has_feature(vdev, VIRTIO_NET_F_CTRL_GUEST_OFFLOADS)) { 24516c666823SMichael S. Tsirkin n->curr_guest_offloads = virtio_net_supported_guest_offloads(n); 24526c666823SMichael S. Tsirkin } 24536c666823SMichael S. Tsirkin 24547788c3f2SMikhail Sennikovsky /* 24557788c3f2SMikhail Sennikovsky * curr_guest_offloads will be later overwritten by the 24567788c3f2SMikhail Sennikovsky * virtio_set_features_nocheck call done from the virtio_load. 24577788c3f2SMikhail Sennikovsky * Here we make sure it is preserved and restored accordingly 24587788c3f2SMikhail Sennikovsky * in the virtio_net_post_load_virtio callback. 24597788c3f2SMikhail Sennikovsky */ 24607788c3f2SMikhail Sennikovsky n->saved_guest_offloads = n->curr_guest_offloads; 24616c666823SMichael S. Tsirkin 24626e790746SPaolo Bonzini virtio_net_set_queues(n); 24636e790746SPaolo Bonzini 24646e790746SPaolo Bonzini /* Find the first multicast entry in the saved MAC filter */ 24656e790746SPaolo Bonzini for (i = 0; i < n->mac_table.in_use; i++) { 24666e790746SPaolo Bonzini if (n->mac_table.macs[i * ETH_ALEN] & 1) { 24676e790746SPaolo Bonzini break; 24686e790746SPaolo Bonzini } 24696e790746SPaolo Bonzini } 24706e790746SPaolo Bonzini n->mac_table.first_multi = i; 24716e790746SPaolo Bonzini 24726e790746SPaolo Bonzini /* nc.link_down can't be migrated, so infer link_down according 24736e790746SPaolo Bonzini * to link status bit in n->status */ 24746e790746SPaolo Bonzini link_down = (n->status & VIRTIO_NET_S_LINK_UP) == 0; 24756e790746SPaolo Bonzini for (i = 0; i < n->max_queues; i++) { 24766e790746SPaolo Bonzini qemu_get_subqueue(n->nic, i)->link_down = link_down; 24776e790746SPaolo Bonzini } 24786e790746SPaolo Bonzini 24796c666823SMichael S. Tsirkin if (virtio_vdev_has_feature(vdev, VIRTIO_NET_F_GUEST_ANNOUNCE) && 24806c666823SMichael S. Tsirkin virtio_vdev_has_feature(vdev, VIRTIO_NET_F_CTRL_VQ)) { 24819d8c6a25SDr. David Alan Gilbert qemu_announce_timer_reset(&n->announce_timer, migrate_announce_params(), 24829d8c6a25SDr. David Alan Gilbert QEMU_CLOCK_VIRTUAL, 24839d8c6a25SDr. David Alan Gilbert virtio_net_announce_timer, n); 24849d8c6a25SDr. David Alan Gilbert if (n->announce_timer.round) { 24859d8c6a25SDr. David Alan Gilbert timer_mod(n->announce_timer.tm, 24869d8c6a25SDr. David Alan Gilbert qemu_clock_get_ms(n->announce_timer.type)); 24879d8c6a25SDr. David Alan Gilbert } else { 2488944458b6SDr. David Alan Gilbert qemu_announce_timer_del(&n->announce_timer, false); 24899d8c6a25SDr. David Alan Gilbert } 24906c666823SMichael S. Tsirkin } 24916c666823SMichael S. Tsirkin 24926e790746SPaolo Bonzini return 0; 24936e790746SPaolo Bonzini } 24946e790746SPaolo Bonzini 24957788c3f2SMikhail Sennikovsky static int virtio_net_post_load_virtio(VirtIODevice *vdev) 24967788c3f2SMikhail Sennikovsky { 24977788c3f2SMikhail Sennikovsky VirtIONet *n = VIRTIO_NET(vdev); 24987788c3f2SMikhail Sennikovsky /* 24997788c3f2SMikhail Sennikovsky * The actual needed state is now in saved_guest_offloads, 25007788c3f2SMikhail Sennikovsky * see virtio_net_post_load_device for detail. 25017788c3f2SMikhail Sennikovsky * Restore it back and apply the desired offloads. 25027788c3f2SMikhail Sennikovsky */ 25037788c3f2SMikhail Sennikovsky n->curr_guest_offloads = n->saved_guest_offloads; 25047788c3f2SMikhail Sennikovsky if (peer_has_vnet_hdr(n)) { 25057788c3f2SMikhail Sennikovsky virtio_net_apply_guest_offloads(n); 25067788c3f2SMikhail Sennikovsky } 25077788c3f2SMikhail Sennikovsky 25087788c3f2SMikhail Sennikovsky return 0; 25097788c3f2SMikhail Sennikovsky } 25107788c3f2SMikhail Sennikovsky 2511982b78c5SDr. David Alan Gilbert /* tx_waiting field of a VirtIONetQueue */ 2512982b78c5SDr. David Alan Gilbert static const VMStateDescription vmstate_virtio_net_queue_tx_waiting = { 2513982b78c5SDr. David Alan Gilbert .name = "virtio-net-queue-tx_waiting", 2514982b78c5SDr. David Alan Gilbert .fields = (VMStateField[]) { 2515982b78c5SDr. David Alan Gilbert VMSTATE_UINT32(tx_waiting, VirtIONetQueue), 2516982b78c5SDr. David Alan Gilbert VMSTATE_END_OF_LIST() 2517982b78c5SDr. David Alan Gilbert }, 2518982b78c5SDr. David Alan Gilbert }; 2519982b78c5SDr. David Alan Gilbert 2520982b78c5SDr. David Alan Gilbert static bool max_queues_gt_1(void *opaque, int version_id) 2521982b78c5SDr. David Alan Gilbert { 2522982b78c5SDr. David Alan Gilbert return VIRTIO_NET(opaque)->max_queues > 1; 2523982b78c5SDr. David Alan Gilbert } 2524982b78c5SDr. David Alan Gilbert 2525982b78c5SDr. David Alan Gilbert static bool has_ctrl_guest_offloads(void *opaque, int version_id) 2526982b78c5SDr. David Alan Gilbert { 2527982b78c5SDr. David Alan Gilbert return virtio_vdev_has_feature(VIRTIO_DEVICE(opaque), 2528982b78c5SDr. David Alan Gilbert VIRTIO_NET_F_CTRL_GUEST_OFFLOADS); 2529982b78c5SDr. David Alan Gilbert } 2530982b78c5SDr. David Alan Gilbert 2531982b78c5SDr. David Alan Gilbert static bool mac_table_fits(void *opaque, int version_id) 2532982b78c5SDr. David Alan Gilbert { 2533982b78c5SDr. David Alan Gilbert return VIRTIO_NET(opaque)->mac_table.in_use <= MAC_TABLE_ENTRIES; 2534982b78c5SDr. David Alan Gilbert } 2535982b78c5SDr. David Alan Gilbert 2536982b78c5SDr. David Alan Gilbert static bool mac_table_doesnt_fit(void *opaque, int version_id) 2537982b78c5SDr. David Alan Gilbert { 2538982b78c5SDr. David Alan Gilbert return !mac_table_fits(opaque, version_id); 2539982b78c5SDr. David Alan Gilbert } 2540982b78c5SDr. David Alan Gilbert 2541982b78c5SDr. David Alan Gilbert /* This temporary type is shared by all the WITH_TMP methods 2542982b78c5SDr. David Alan Gilbert * although only some fields are used by each. 2543982b78c5SDr. David Alan Gilbert */ 2544982b78c5SDr. David Alan Gilbert struct VirtIONetMigTmp { 2545982b78c5SDr. David Alan Gilbert VirtIONet *parent; 2546982b78c5SDr. David Alan Gilbert VirtIONetQueue *vqs_1; 2547982b78c5SDr. David Alan Gilbert uint16_t curr_queues_1; 2548982b78c5SDr. David Alan Gilbert uint8_t has_ufo; 2549982b78c5SDr. David Alan Gilbert uint32_t has_vnet_hdr; 2550982b78c5SDr. David Alan Gilbert }; 2551982b78c5SDr. David Alan Gilbert 2552982b78c5SDr. David Alan Gilbert /* The 2nd and subsequent tx_waiting flags are loaded later than 2553982b78c5SDr. David Alan Gilbert * the 1st entry in the queues and only if there's more than one 2554982b78c5SDr. David Alan Gilbert * entry. We use the tmp mechanism to calculate a temporary 2555982b78c5SDr. David Alan Gilbert * pointer and count and also validate the count. 2556982b78c5SDr. David Alan Gilbert */ 2557982b78c5SDr. David Alan Gilbert 255844b1ff31SDr. David Alan Gilbert static int virtio_net_tx_waiting_pre_save(void *opaque) 2559982b78c5SDr. David Alan Gilbert { 2560982b78c5SDr. David Alan Gilbert struct VirtIONetMigTmp *tmp = opaque; 2561982b78c5SDr. David Alan Gilbert 2562982b78c5SDr. David Alan Gilbert tmp->vqs_1 = tmp->parent->vqs + 1; 2563982b78c5SDr. David Alan Gilbert tmp->curr_queues_1 = tmp->parent->curr_queues - 1; 2564982b78c5SDr. David Alan Gilbert if (tmp->parent->curr_queues == 0) { 2565982b78c5SDr. David Alan Gilbert tmp->curr_queues_1 = 0; 2566982b78c5SDr. David Alan Gilbert } 256744b1ff31SDr. David Alan Gilbert 256844b1ff31SDr. David Alan Gilbert return 0; 2569982b78c5SDr. David Alan Gilbert } 2570982b78c5SDr. David Alan Gilbert 2571982b78c5SDr. David Alan Gilbert static int virtio_net_tx_waiting_pre_load(void *opaque) 2572982b78c5SDr. David Alan Gilbert { 2573982b78c5SDr. David Alan Gilbert struct VirtIONetMigTmp *tmp = opaque; 2574982b78c5SDr. David Alan Gilbert 2575982b78c5SDr. David Alan Gilbert /* Reuse the pointer setup from save */ 2576982b78c5SDr. David Alan Gilbert virtio_net_tx_waiting_pre_save(opaque); 2577982b78c5SDr. David Alan Gilbert 2578982b78c5SDr. David Alan Gilbert if (tmp->parent->curr_queues > tmp->parent->max_queues) { 2579982b78c5SDr. David Alan Gilbert error_report("virtio-net: curr_queues %x > max_queues %x", 2580982b78c5SDr. David Alan Gilbert tmp->parent->curr_queues, tmp->parent->max_queues); 2581982b78c5SDr. David Alan Gilbert 2582982b78c5SDr. David Alan Gilbert return -EINVAL; 2583982b78c5SDr. David Alan Gilbert } 2584982b78c5SDr. David Alan Gilbert 2585982b78c5SDr. David Alan Gilbert return 0; /* all good */ 2586982b78c5SDr. David Alan Gilbert } 2587982b78c5SDr. David Alan Gilbert 2588982b78c5SDr. David Alan Gilbert static const VMStateDescription vmstate_virtio_net_tx_waiting = { 2589982b78c5SDr. David Alan Gilbert .name = "virtio-net-tx_waiting", 2590982b78c5SDr. David Alan Gilbert .pre_load = virtio_net_tx_waiting_pre_load, 2591982b78c5SDr. David Alan Gilbert .pre_save = virtio_net_tx_waiting_pre_save, 2592982b78c5SDr. David Alan Gilbert .fields = (VMStateField[]) { 2593982b78c5SDr. David Alan Gilbert VMSTATE_STRUCT_VARRAY_POINTER_UINT16(vqs_1, struct VirtIONetMigTmp, 2594982b78c5SDr. David Alan Gilbert curr_queues_1, 2595982b78c5SDr. David Alan Gilbert vmstate_virtio_net_queue_tx_waiting, 2596982b78c5SDr. David Alan Gilbert struct VirtIONetQueue), 2597982b78c5SDr. David Alan Gilbert VMSTATE_END_OF_LIST() 2598982b78c5SDr. David Alan Gilbert }, 2599982b78c5SDr. David Alan Gilbert }; 2600982b78c5SDr. David Alan Gilbert 2601982b78c5SDr. David Alan Gilbert /* the 'has_ufo' flag is just tested; if the incoming stream has the 2602982b78c5SDr. David Alan Gilbert * flag set we need to check that we have it 2603982b78c5SDr. David Alan Gilbert */ 2604982b78c5SDr. David Alan Gilbert static int virtio_net_ufo_post_load(void *opaque, int version_id) 2605982b78c5SDr. David Alan Gilbert { 2606982b78c5SDr. David Alan Gilbert struct VirtIONetMigTmp *tmp = opaque; 2607982b78c5SDr. David Alan Gilbert 2608982b78c5SDr. David Alan Gilbert if (tmp->has_ufo && !peer_has_ufo(tmp->parent)) { 2609982b78c5SDr. David Alan Gilbert error_report("virtio-net: saved image requires TUN_F_UFO support"); 2610982b78c5SDr. David Alan Gilbert return -EINVAL; 2611982b78c5SDr. David Alan Gilbert } 2612982b78c5SDr. David Alan Gilbert 2613982b78c5SDr. David Alan Gilbert return 0; 2614982b78c5SDr. David Alan Gilbert } 2615982b78c5SDr. David Alan Gilbert 261644b1ff31SDr. David Alan Gilbert static int virtio_net_ufo_pre_save(void *opaque) 2617982b78c5SDr. David Alan Gilbert { 2618982b78c5SDr. David Alan Gilbert struct VirtIONetMigTmp *tmp = opaque; 2619982b78c5SDr. David Alan Gilbert 2620982b78c5SDr. David Alan Gilbert tmp->has_ufo = tmp->parent->has_ufo; 262144b1ff31SDr. David Alan Gilbert 262244b1ff31SDr. David Alan Gilbert return 0; 2623982b78c5SDr. David Alan Gilbert } 2624982b78c5SDr. David Alan Gilbert 2625982b78c5SDr. David Alan Gilbert static const VMStateDescription vmstate_virtio_net_has_ufo = { 2626982b78c5SDr. David Alan Gilbert .name = "virtio-net-ufo", 2627982b78c5SDr. David Alan Gilbert .post_load = virtio_net_ufo_post_load, 2628982b78c5SDr. David Alan Gilbert .pre_save = virtio_net_ufo_pre_save, 2629982b78c5SDr. David Alan Gilbert .fields = (VMStateField[]) { 2630982b78c5SDr. David Alan Gilbert VMSTATE_UINT8(has_ufo, struct VirtIONetMigTmp), 2631982b78c5SDr. David Alan Gilbert VMSTATE_END_OF_LIST() 2632982b78c5SDr. David Alan Gilbert }, 2633982b78c5SDr. David Alan Gilbert }; 2634982b78c5SDr. David Alan Gilbert 2635982b78c5SDr. David Alan Gilbert /* the 'has_vnet_hdr' flag is just tested; if the incoming stream has the 2636982b78c5SDr. David Alan Gilbert * flag set we need to check that we have it 2637982b78c5SDr. David Alan Gilbert */ 2638982b78c5SDr. David Alan Gilbert static int virtio_net_vnet_post_load(void *opaque, int version_id) 2639982b78c5SDr. David Alan Gilbert { 2640982b78c5SDr. David Alan Gilbert struct VirtIONetMigTmp *tmp = opaque; 2641982b78c5SDr. David Alan Gilbert 2642982b78c5SDr. David Alan Gilbert if (tmp->has_vnet_hdr && !peer_has_vnet_hdr(tmp->parent)) { 2643982b78c5SDr. David Alan Gilbert error_report("virtio-net: saved image requires vnet_hdr=on"); 2644982b78c5SDr. David Alan Gilbert return -EINVAL; 2645982b78c5SDr. David Alan Gilbert } 2646982b78c5SDr. David Alan Gilbert 2647982b78c5SDr. David Alan Gilbert return 0; 2648982b78c5SDr. David Alan Gilbert } 2649982b78c5SDr. David Alan Gilbert 265044b1ff31SDr. David Alan Gilbert static int virtio_net_vnet_pre_save(void *opaque) 2651982b78c5SDr. David Alan Gilbert { 2652982b78c5SDr. David Alan Gilbert struct VirtIONetMigTmp *tmp = opaque; 2653982b78c5SDr. David Alan Gilbert 2654982b78c5SDr. David Alan Gilbert tmp->has_vnet_hdr = tmp->parent->has_vnet_hdr; 265544b1ff31SDr. David Alan Gilbert 265644b1ff31SDr. David Alan Gilbert return 0; 2657982b78c5SDr. David Alan Gilbert } 2658982b78c5SDr. David Alan Gilbert 2659982b78c5SDr. David Alan Gilbert static const VMStateDescription vmstate_virtio_net_has_vnet = { 2660982b78c5SDr. David Alan Gilbert .name = "virtio-net-vnet", 2661982b78c5SDr. David Alan Gilbert .post_load = virtio_net_vnet_post_load, 2662982b78c5SDr. David Alan Gilbert .pre_save = virtio_net_vnet_pre_save, 2663982b78c5SDr. David Alan Gilbert .fields = (VMStateField[]) { 2664982b78c5SDr. David Alan Gilbert VMSTATE_UINT32(has_vnet_hdr, struct VirtIONetMigTmp), 2665982b78c5SDr. David Alan Gilbert VMSTATE_END_OF_LIST() 2666982b78c5SDr. David Alan Gilbert }, 2667982b78c5SDr. David Alan Gilbert }; 2668982b78c5SDr. David Alan Gilbert 2669982b78c5SDr. David Alan Gilbert static const VMStateDescription vmstate_virtio_net_device = { 2670982b78c5SDr. David Alan Gilbert .name = "virtio-net-device", 2671982b78c5SDr. David Alan Gilbert .version_id = VIRTIO_NET_VM_VERSION, 2672982b78c5SDr. David Alan Gilbert .minimum_version_id = VIRTIO_NET_VM_VERSION, 2673982b78c5SDr. David Alan Gilbert .post_load = virtio_net_post_load_device, 2674982b78c5SDr. David Alan Gilbert .fields = (VMStateField[]) { 2675982b78c5SDr. David Alan Gilbert VMSTATE_UINT8_ARRAY(mac, VirtIONet, ETH_ALEN), 2676982b78c5SDr. David Alan Gilbert VMSTATE_STRUCT_POINTER(vqs, VirtIONet, 2677982b78c5SDr. David Alan Gilbert vmstate_virtio_net_queue_tx_waiting, 2678982b78c5SDr. David Alan Gilbert VirtIONetQueue), 2679982b78c5SDr. David Alan Gilbert VMSTATE_UINT32(mergeable_rx_bufs, VirtIONet), 2680982b78c5SDr. David Alan Gilbert VMSTATE_UINT16(status, VirtIONet), 2681982b78c5SDr. David Alan Gilbert VMSTATE_UINT8(promisc, VirtIONet), 2682982b78c5SDr. David Alan Gilbert VMSTATE_UINT8(allmulti, VirtIONet), 2683982b78c5SDr. David Alan Gilbert VMSTATE_UINT32(mac_table.in_use, VirtIONet), 2684982b78c5SDr. David Alan Gilbert 2685982b78c5SDr. David Alan Gilbert /* Guarded pair: If it fits we load it, else we throw it away 2686982b78c5SDr. David Alan Gilbert * - can happen if source has a larger MAC table.; post-load 2687982b78c5SDr. David Alan Gilbert * sets flags in this case. 2688982b78c5SDr. David Alan Gilbert */ 2689982b78c5SDr. David Alan Gilbert VMSTATE_VBUFFER_MULTIPLY(mac_table.macs, VirtIONet, 2690982b78c5SDr. David Alan Gilbert 0, mac_table_fits, mac_table.in_use, 2691982b78c5SDr. David Alan Gilbert ETH_ALEN), 2692982b78c5SDr. David Alan Gilbert VMSTATE_UNUSED_VARRAY_UINT32(VirtIONet, mac_table_doesnt_fit, 0, 2693982b78c5SDr. David Alan Gilbert mac_table.in_use, ETH_ALEN), 2694982b78c5SDr. David Alan Gilbert 2695982b78c5SDr. David Alan Gilbert /* Note: This is an array of uint32's that's always been saved as a 2696982b78c5SDr. David Alan Gilbert * buffer; hold onto your endiannesses; it's actually used as a bitmap 2697982b78c5SDr. David Alan Gilbert * but based on the uint. 2698982b78c5SDr. David Alan Gilbert */ 2699982b78c5SDr. David Alan Gilbert VMSTATE_BUFFER_POINTER_UNSAFE(vlans, VirtIONet, 0, MAX_VLAN >> 3), 2700982b78c5SDr. David Alan Gilbert VMSTATE_WITH_TMP(VirtIONet, struct VirtIONetMigTmp, 2701982b78c5SDr. David Alan Gilbert vmstate_virtio_net_has_vnet), 2702982b78c5SDr. David Alan Gilbert VMSTATE_UINT8(mac_table.multi_overflow, VirtIONet), 2703982b78c5SDr. David Alan Gilbert VMSTATE_UINT8(mac_table.uni_overflow, VirtIONet), 2704982b78c5SDr. David Alan Gilbert VMSTATE_UINT8(alluni, VirtIONet), 2705982b78c5SDr. David Alan Gilbert VMSTATE_UINT8(nomulti, VirtIONet), 2706982b78c5SDr. David Alan Gilbert VMSTATE_UINT8(nouni, VirtIONet), 2707982b78c5SDr. David Alan Gilbert VMSTATE_UINT8(nobcast, VirtIONet), 2708982b78c5SDr. David Alan Gilbert VMSTATE_WITH_TMP(VirtIONet, struct VirtIONetMigTmp, 2709982b78c5SDr. David Alan Gilbert vmstate_virtio_net_has_ufo), 2710982b78c5SDr. David Alan Gilbert VMSTATE_SINGLE_TEST(max_queues, VirtIONet, max_queues_gt_1, 0, 2711982b78c5SDr. David Alan Gilbert vmstate_info_uint16_equal, uint16_t), 2712982b78c5SDr. David Alan Gilbert VMSTATE_UINT16_TEST(curr_queues, VirtIONet, max_queues_gt_1), 2713982b78c5SDr. David Alan Gilbert VMSTATE_WITH_TMP(VirtIONet, struct VirtIONetMigTmp, 2714982b78c5SDr. David Alan Gilbert vmstate_virtio_net_tx_waiting), 2715982b78c5SDr. David Alan Gilbert VMSTATE_UINT64_TEST(curr_guest_offloads, VirtIONet, 2716982b78c5SDr. David Alan Gilbert has_ctrl_guest_offloads), 2717982b78c5SDr. David Alan Gilbert VMSTATE_END_OF_LIST() 2718982b78c5SDr. David Alan Gilbert }, 2719982b78c5SDr. David Alan Gilbert }; 2720982b78c5SDr. David Alan Gilbert 27216e790746SPaolo Bonzini static NetClientInfo net_virtio_info = { 2722f394b2e2SEric Blake .type = NET_CLIENT_DRIVER_NIC, 27236e790746SPaolo Bonzini .size = sizeof(NICState), 27246e790746SPaolo Bonzini .can_receive = virtio_net_can_receive, 27256e790746SPaolo Bonzini .receive = virtio_net_receive, 27266e790746SPaolo Bonzini .link_status_changed = virtio_net_set_link_status, 2727b1be4280SAmos Kong .query_rx_filter = virtio_net_query_rxfilter, 2728b2c929f0SDr. David Alan Gilbert .announce = virtio_net_announce, 27296e790746SPaolo Bonzini }; 27306e790746SPaolo Bonzini 27316e790746SPaolo Bonzini static bool virtio_net_guest_notifier_pending(VirtIODevice *vdev, int idx) 27326e790746SPaolo Bonzini { 273317a0ca55SKONRAD Frederic VirtIONet *n = VIRTIO_NET(vdev); 27346e790746SPaolo Bonzini NetClientState *nc = qemu_get_subqueue(n->nic, vq2q(idx)); 27356e790746SPaolo Bonzini assert(n->vhost_started); 2736ed8b4afeSNikolay Nikolaev return vhost_net_virtqueue_pending(get_vhost_net(nc->peer), idx); 27376e790746SPaolo Bonzini } 27386e790746SPaolo Bonzini 27396e790746SPaolo Bonzini static void virtio_net_guest_notifier_mask(VirtIODevice *vdev, int idx, 27406e790746SPaolo Bonzini bool mask) 27416e790746SPaolo Bonzini { 274217a0ca55SKONRAD Frederic VirtIONet *n = VIRTIO_NET(vdev); 27436e790746SPaolo Bonzini NetClientState *nc = qemu_get_subqueue(n->nic, vq2q(idx)); 27446e790746SPaolo Bonzini assert(n->vhost_started); 2745ed8b4afeSNikolay Nikolaev vhost_net_virtqueue_mask(get_vhost_net(nc->peer), 27466e790746SPaolo Bonzini vdev, idx, mask); 27476e790746SPaolo Bonzini } 27486e790746SPaolo Bonzini 2749019a3edbSGerd Hoffmann static void virtio_net_set_config_size(VirtIONet *n, uint64_t host_features) 27506e790746SPaolo Bonzini { 27510cd09c3aSCornelia Huck virtio_add_feature(&host_features, VIRTIO_NET_F_MAC); 2752a93e599dSMaxime Coquelin 2753ba550851SStefano Garzarella n->config_size = virtio_feature_get_config_size(feature_sizes, 2754ba550851SStefano Garzarella host_features); 275517ec5a86SKONRAD Frederic } 27566e790746SPaolo Bonzini 27578a253ec2SKONRAD Frederic void virtio_net_set_netclient_name(VirtIONet *n, const char *name, 27588a253ec2SKONRAD Frederic const char *type) 27598a253ec2SKONRAD Frederic { 27608a253ec2SKONRAD Frederic /* 27618a253ec2SKONRAD Frederic * The name can be NULL, the netclient name will be type.x. 27628a253ec2SKONRAD Frederic */ 27638a253ec2SKONRAD Frederic assert(type != NULL); 27648a253ec2SKONRAD Frederic 27658a253ec2SKONRAD Frederic g_free(n->netclient_name); 27668a253ec2SKONRAD Frederic g_free(n->netclient_type); 27678a253ec2SKONRAD Frederic n->netclient_name = g_strdup(name); 27688a253ec2SKONRAD Frederic n->netclient_type = g_strdup(type); 27698a253ec2SKONRAD Frederic } 27708a253ec2SKONRAD Frederic 27719711cd0dSJens Freimann static bool failover_unplug_primary(VirtIONet *n) 27729711cd0dSJens Freimann { 27739711cd0dSJens Freimann HotplugHandler *hotplug_ctrl; 27749711cd0dSJens Freimann PCIDevice *pci_dev; 27759711cd0dSJens Freimann Error *err = NULL; 27769711cd0dSJens Freimann 27779711cd0dSJens Freimann hotplug_ctrl = qdev_get_hotplug_handler(n->primary_dev); 27789711cd0dSJens Freimann if (hotplug_ctrl) { 27799711cd0dSJens Freimann pci_dev = PCI_DEVICE(n->primary_dev); 27809711cd0dSJens Freimann pci_dev->partially_hotplugged = true; 27819711cd0dSJens Freimann hotplug_handler_unplug_request(hotplug_ctrl, n->primary_dev, &err); 27829711cd0dSJens Freimann if (err) { 27839711cd0dSJens Freimann error_report_err(err); 27849711cd0dSJens Freimann return false; 27859711cd0dSJens Freimann } 27869711cd0dSJens Freimann } else { 27879711cd0dSJens Freimann return false; 27889711cd0dSJens Freimann } 27899711cd0dSJens Freimann return true; 27909711cd0dSJens Freimann } 27919711cd0dSJens Freimann 27929711cd0dSJens Freimann static bool failover_replug_primary(VirtIONet *n, Error **errp) 27939711cd0dSJens Freimann { 27949711cd0dSJens Freimann HotplugHandler *hotplug_ctrl; 27959711cd0dSJens Freimann PCIDevice *pdev = PCI_DEVICE(n->primary_dev); 27969711cd0dSJens Freimann 27979711cd0dSJens Freimann if (!pdev->partially_hotplugged) { 27989711cd0dSJens Freimann return true; 27999711cd0dSJens Freimann } 28009711cd0dSJens Freimann if (!n->primary_device_opts) { 28019711cd0dSJens Freimann n->primary_device_opts = qemu_opts_from_qdict( 28029711cd0dSJens Freimann qemu_find_opts("device"), 28039711cd0dSJens Freimann n->primary_device_dict, errp); 28049711cd0dSJens Freimann } 28059711cd0dSJens Freimann if (n->primary_device_opts) { 28069711cd0dSJens Freimann if (n->primary_dev) { 28079711cd0dSJens Freimann n->primary_bus = n->primary_dev->parent_bus; 28089711cd0dSJens Freimann } 28099711cd0dSJens Freimann qdev_set_parent_bus(n->primary_dev, n->primary_bus); 28109711cd0dSJens Freimann n->primary_should_be_hidden = false; 28119711cd0dSJens Freimann qemu_opt_set_bool(n->primary_device_opts, 28129711cd0dSJens Freimann "partially_hotplugged", true, errp); 28139711cd0dSJens Freimann hotplug_ctrl = qdev_get_hotplug_handler(n->primary_dev); 28149711cd0dSJens Freimann if (hotplug_ctrl) { 28159711cd0dSJens Freimann hotplug_handler_pre_plug(hotplug_ctrl, n->primary_dev, errp); 28169711cd0dSJens Freimann hotplug_handler_plug(hotplug_ctrl, n->primary_dev, errp); 28179711cd0dSJens Freimann } 28189711cd0dSJens Freimann if (!n->primary_dev) { 28199711cd0dSJens Freimann error_setg(errp, "virtio_net: couldn't find primary device"); 28209711cd0dSJens Freimann } 28219711cd0dSJens Freimann } 28229711cd0dSJens Freimann return *errp != NULL; 28239711cd0dSJens Freimann } 28249711cd0dSJens Freimann 28259711cd0dSJens Freimann static void virtio_net_handle_migration_primary(VirtIONet *n, 28269711cd0dSJens Freimann MigrationState *s) 28279711cd0dSJens Freimann { 28289711cd0dSJens Freimann bool should_be_hidden; 28299711cd0dSJens Freimann Error *err = NULL; 28309711cd0dSJens Freimann 28319711cd0dSJens Freimann should_be_hidden = atomic_read(&n->primary_should_be_hidden); 28329711cd0dSJens Freimann 28339711cd0dSJens Freimann if (!n->primary_dev) { 28349711cd0dSJens Freimann n->primary_dev = virtio_connect_failover_devices(n, n->qdev, &err); 28359711cd0dSJens Freimann if (!n->primary_dev) { 28369711cd0dSJens Freimann return; 28379711cd0dSJens Freimann } 28389711cd0dSJens Freimann } 28399711cd0dSJens Freimann 28409711cd0dSJens Freimann if (migration_in_setup(s) && !should_be_hidden && 28419711cd0dSJens Freimann n->primary_dev) { 28429711cd0dSJens Freimann if (failover_unplug_primary(n)) { 28439711cd0dSJens Freimann vmstate_unregister(n->primary_dev, qdev_get_vmsd(n->primary_dev), 28449711cd0dSJens Freimann n->primary_dev); 28459711cd0dSJens Freimann qapi_event_send_unplug_primary(n->primary_device_id); 28469711cd0dSJens Freimann atomic_set(&n->primary_should_be_hidden, true); 28479711cd0dSJens Freimann } else { 28489711cd0dSJens Freimann warn_report("couldn't unplug primary device"); 28499711cd0dSJens Freimann } 28509711cd0dSJens Freimann } else if (migration_has_failed(s)) { 28519711cd0dSJens Freimann /* We already unplugged the device let's plugged it back */ 28529711cd0dSJens Freimann if (!failover_replug_primary(n, &err)) { 28539711cd0dSJens Freimann if (err) { 28549711cd0dSJens Freimann error_report_err(err); 28559711cd0dSJens Freimann } 28569711cd0dSJens Freimann } 28579711cd0dSJens Freimann } 28589711cd0dSJens Freimann } 28599711cd0dSJens Freimann 28609711cd0dSJens Freimann static void virtio_net_migration_state_notifier(Notifier *notifier, void *data) 28619711cd0dSJens Freimann { 28629711cd0dSJens Freimann MigrationState *s = data; 28639711cd0dSJens Freimann VirtIONet *n = container_of(notifier, VirtIONet, migration_state); 28649711cd0dSJens Freimann virtio_net_handle_migration_primary(n, s); 28659711cd0dSJens Freimann } 28669711cd0dSJens Freimann 28679711cd0dSJens Freimann static int virtio_net_primary_should_be_hidden(DeviceListener *listener, 28689711cd0dSJens Freimann QemuOpts *device_opts) 28699711cd0dSJens Freimann { 28709711cd0dSJens Freimann VirtIONet *n = container_of(listener, VirtIONet, primary_listener); 28719711cd0dSJens Freimann bool match_found; 28729711cd0dSJens Freimann bool hide; 28739711cd0dSJens Freimann 28749711cd0dSJens Freimann n->primary_device_dict = qemu_opts_to_qdict(device_opts, 28759711cd0dSJens Freimann n->primary_device_dict); 28769711cd0dSJens Freimann if (n->primary_device_dict) { 28779711cd0dSJens Freimann g_free(n->standby_id); 28789711cd0dSJens Freimann n->standby_id = g_strdup(qdict_get_try_str(n->primary_device_dict, 28799711cd0dSJens Freimann "failover_pair_id")); 28809711cd0dSJens Freimann } 28819711cd0dSJens Freimann if (device_opts && g_strcmp0(n->standby_id, n->netclient_name) == 0) { 28829711cd0dSJens Freimann match_found = true; 28839711cd0dSJens Freimann } else { 28849711cd0dSJens Freimann match_found = false; 28859711cd0dSJens Freimann hide = false; 28869711cd0dSJens Freimann g_free(n->standby_id); 28879711cd0dSJens Freimann n->primary_device_dict = NULL; 28889711cd0dSJens Freimann goto out; 28899711cd0dSJens Freimann } 28909711cd0dSJens Freimann 28919711cd0dSJens Freimann n->primary_device_opts = device_opts; 28929711cd0dSJens Freimann 28939711cd0dSJens Freimann /* primary_should_be_hidden is set during feature negotiation */ 28949711cd0dSJens Freimann hide = atomic_read(&n->primary_should_be_hidden); 28959711cd0dSJens Freimann 28969711cd0dSJens Freimann if (n->primary_device_dict) { 28979711cd0dSJens Freimann g_free(n->primary_device_id); 28989711cd0dSJens Freimann n->primary_device_id = g_strdup(qdict_get_try_str( 28999711cd0dSJens Freimann n->primary_device_dict, "id")); 29009711cd0dSJens Freimann if (!n->primary_device_id) { 29019711cd0dSJens Freimann warn_report("primary_device_id not set"); 29029711cd0dSJens Freimann } 29039711cd0dSJens Freimann } 29049711cd0dSJens Freimann 29059711cd0dSJens Freimann out: 29069711cd0dSJens Freimann if (match_found && hide) { 29079711cd0dSJens Freimann return 1; 29089711cd0dSJens Freimann } else if (match_found && !hide) { 29099711cd0dSJens Freimann return 0; 29109711cd0dSJens Freimann } else { 29119711cd0dSJens Freimann return -1; 29129711cd0dSJens Freimann } 29139711cd0dSJens Freimann } 29149711cd0dSJens Freimann 2915e6f746b3SAndreas Färber static void virtio_net_device_realize(DeviceState *dev, Error **errp) 291617ec5a86SKONRAD Frederic { 2917e6f746b3SAndreas Färber VirtIODevice *vdev = VIRTIO_DEVICE(dev); 2918284a32f0SAndreas Färber VirtIONet *n = VIRTIO_NET(dev); 2919284a32f0SAndreas Färber NetClientState *nc; 29201773d9eeSKONRAD Frederic int i; 292117ec5a86SKONRAD Frederic 2922a93e599dSMaxime Coquelin if (n->net_conf.mtu) { 2923127833eeSJason Baron n->host_features |= (1ULL << VIRTIO_NET_F_MTU); 2924a93e599dSMaxime Coquelin } 2925a93e599dSMaxime Coquelin 29269473939eSJason Baron if (n->net_conf.duplex_str) { 29279473939eSJason Baron if (strncmp(n->net_conf.duplex_str, "half", 5) == 0) { 29289473939eSJason Baron n->net_conf.duplex = DUPLEX_HALF; 29299473939eSJason Baron } else if (strncmp(n->net_conf.duplex_str, "full", 5) == 0) { 29309473939eSJason Baron n->net_conf.duplex = DUPLEX_FULL; 29319473939eSJason Baron } else { 29329473939eSJason Baron error_setg(errp, "'duplex' must be 'half' or 'full'"); 29339473939eSJason Baron } 29349473939eSJason Baron n->host_features |= (1ULL << VIRTIO_NET_F_SPEED_DUPLEX); 29359473939eSJason Baron } else { 29369473939eSJason Baron n->net_conf.duplex = DUPLEX_UNKNOWN; 29379473939eSJason Baron } 29389473939eSJason Baron 29399473939eSJason Baron if (n->net_conf.speed < SPEED_UNKNOWN) { 29409473939eSJason Baron error_setg(errp, "'speed' must be between 0 and INT_MAX"); 29419473939eSJason Baron } else if (n->net_conf.speed >= 0) { 29429473939eSJason Baron n->host_features |= (1ULL << VIRTIO_NET_F_SPEED_DUPLEX); 29439473939eSJason Baron } 29449473939eSJason Baron 29459711cd0dSJens Freimann if (n->failover) { 29469711cd0dSJens Freimann n->primary_listener.should_be_hidden = 29479711cd0dSJens Freimann virtio_net_primary_should_be_hidden; 29489711cd0dSJens Freimann atomic_set(&n->primary_should_be_hidden, true); 29499711cd0dSJens Freimann device_listener_register(&n->primary_listener); 29509711cd0dSJens Freimann n->migration_state.notify = virtio_net_migration_state_notifier; 29519711cd0dSJens Freimann add_migration_state_change_notifier(&n->migration_state); 29529711cd0dSJens Freimann n->host_features |= (1ULL << VIRTIO_NET_F_STANDBY); 29539711cd0dSJens Freimann } 29549711cd0dSJens Freimann 2955da3e8a23SShannon Zhao virtio_net_set_config_size(n, n->host_features); 2956284a32f0SAndreas Färber virtio_init(vdev, "virtio-net", VIRTIO_ID_NET, n->config_size); 295717ec5a86SKONRAD Frederic 29581c0fbfa3SMichael S. Tsirkin /* 29591c0fbfa3SMichael S. Tsirkin * We set a lower limit on RX queue size to what it always was. 29601c0fbfa3SMichael S. Tsirkin * Guests that want a smaller ring can always resize it without 29611c0fbfa3SMichael S. Tsirkin * help from us (using virtio 1 and up). 29621c0fbfa3SMichael S. Tsirkin */ 29631c0fbfa3SMichael S. Tsirkin if (n->net_conf.rx_queue_size < VIRTIO_NET_RX_QUEUE_MIN_SIZE || 29641c0fbfa3SMichael S. Tsirkin n->net_conf.rx_queue_size > VIRTQUEUE_MAX_SIZE || 29655f997fd1SMichal Privoznik !is_power_of_2(n->net_conf.rx_queue_size)) { 29661c0fbfa3SMichael S. Tsirkin error_setg(errp, "Invalid rx_queue_size (= %" PRIu16 "), " 29671c0fbfa3SMichael S. Tsirkin "must be a power of 2 between %d and %d.", 29681c0fbfa3SMichael S. Tsirkin n->net_conf.rx_queue_size, VIRTIO_NET_RX_QUEUE_MIN_SIZE, 29691c0fbfa3SMichael S. Tsirkin VIRTQUEUE_MAX_SIZE); 29701c0fbfa3SMichael S. Tsirkin virtio_cleanup(vdev); 29711c0fbfa3SMichael S. Tsirkin return; 29721c0fbfa3SMichael S. Tsirkin } 29731c0fbfa3SMichael S. Tsirkin 29749b02e161SWei Wang if (n->net_conf.tx_queue_size < VIRTIO_NET_TX_QUEUE_MIN_SIZE || 29759b02e161SWei Wang n->net_conf.tx_queue_size > VIRTQUEUE_MAX_SIZE || 29769b02e161SWei Wang !is_power_of_2(n->net_conf.tx_queue_size)) { 29779b02e161SWei Wang error_setg(errp, "Invalid tx_queue_size (= %" PRIu16 "), " 29789b02e161SWei Wang "must be a power of 2 between %d and %d", 29799b02e161SWei Wang n->net_conf.tx_queue_size, VIRTIO_NET_TX_QUEUE_MIN_SIZE, 29809b02e161SWei Wang VIRTQUEUE_MAX_SIZE); 29819b02e161SWei Wang virtio_cleanup(vdev); 29829b02e161SWei Wang return; 29839b02e161SWei Wang } 29849b02e161SWei Wang 2985575a1c0eSJiri Pirko n->max_queues = MAX(n->nic_conf.peers.queues, 1); 298687b3bd1cSJason Wang if (n->max_queues * 2 + 1 > VIRTIO_QUEUE_MAX) { 29877e0e736eSJason Wang error_setg(errp, "Invalid number of queues (= %" PRIu32 "), " 2988631b22eaSStefan Weil "must be a positive integer less than %d.", 298987b3bd1cSJason Wang n->max_queues, (VIRTIO_QUEUE_MAX - 1) / 2); 29907e0e736eSJason Wang virtio_cleanup(vdev); 29917e0e736eSJason Wang return; 29927e0e736eSJason Wang } 29936e790746SPaolo Bonzini n->vqs = g_malloc0(sizeof(VirtIONetQueue) * n->max_queues); 29946e790746SPaolo Bonzini n->curr_queues = 1; 29951773d9eeSKONRAD Frederic n->tx_timeout = n->net_conf.txtimer; 29966e790746SPaolo Bonzini 29971773d9eeSKONRAD Frederic if (n->net_conf.tx && strcmp(n->net_conf.tx, "timer") 29981773d9eeSKONRAD Frederic && strcmp(n->net_conf.tx, "bh")) { 29990765691eSMarkus Armbruster warn_report("virtio-net: " 30006e790746SPaolo Bonzini "Unknown option tx=%s, valid options: \"timer\" \"bh\"", 30011773d9eeSKONRAD Frederic n->net_conf.tx); 30020765691eSMarkus Armbruster error_printf("Defaulting to \"bh\""); 30036e790746SPaolo Bonzini } 30046e790746SPaolo Bonzini 30052eef278bSMichael S. Tsirkin n->net_conf.tx_queue_size = MIN(virtio_net_max_tx_queue_size(n), 30062eef278bSMichael S. Tsirkin n->net_conf.tx_queue_size); 30079b02e161SWei Wang 3008da51a335SJason Wang for (i = 0; i < n->max_queues; i++) { 3009f9d6dbf0SWen Congyang virtio_net_add_queue(n, i); 3010da51a335SJason Wang } 3011da51a335SJason Wang 301217a0ca55SKONRAD Frederic n->ctrl_vq = virtio_add_queue(vdev, 64, virtio_net_handle_ctrl); 30131773d9eeSKONRAD Frederic qemu_macaddr_default_if_unset(&n->nic_conf.macaddr); 30141773d9eeSKONRAD Frederic memcpy(&n->mac[0], &n->nic_conf.macaddr, sizeof(n->mac)); 30156e790746SPaolo Bonzini n->status = VIRTIO_NET_S_LINK_UP; 30169d8c6a25SDr. David Alan Gilbert qemu_announce_timer_reset(&n->announce_timer, migrate_announce_params(), 30179d8c6a25SDr. David Alan Gilbert QEMU_CLOCK_VIRTUAL, 3018f57fcf70SJason Wang virtio_net_announce_timer, n); 3019b2c929f0SDr. David Alan Gilbert n->announce_timer.round = 0; 30206e790746SPaolo Bonzini 30218a253ec2SKONRAD Frederic if (n->netclient_type) { 30228a253ec2SKONRAD Frederic /* 30238a253ec2SKONRAD Frederic * Happen when virtio_net_set_netclient_name has been called. 30248a253ec2SKONRAD Frederic */ 30258a253ec2SKONRAD Frederic n->nic = qemu_new_nic(&net_virtio_info, &n->nic_conf, 30268a253ec2SKONRAD Frederic n->netclient_type, n->netclient_name, n); 30278a253ec2SKONRAD Frederic } else { 30281773d9eeSKONRAD Frederic n->nic = qemu_new_nic(&net_virtio_info, &n->nic_conf, 3029284a32f0SAndreas Färber object_get_typename(OBJECT(dev)), dev->id, n); 30308a253ec2SKONRAD Frederic } 30318a253ec2SKONRAD Frederic 30326e790746SPaolo Bonzini peer_test_vnet_hdr(n); 30336e790746SPaolo Bonzini if (peer_has_vnet_hdr(n)) { 30346e790746SPaolo Bonzini for (i = 0; i < n->max_queues; i++) { 3035d6085e3aSStefan Hajnoczi qemu_using_vnet_hdr(qemu_get_subqueue(n->nic, i)->peer, true); 30366e790746SPaolo Bonzini } 30376e790746SPaolo Bonzini n->host_hdr_len = sizeof(struct virtio_net_hdr); 30386e790746SPaolo Bonzini } else { 30396e790746SPaolo Bonzini n->host_hdr_len = 0; 30406e790746SPaolo Bonzini } 30416e790746SPaolo Bonzini 30421773d9eeSKONRAD Frederic qemu_format_nic_info_str(qemu_get_queue(n->nic), n->nic_conf.macaddr.a); 30436e790746SPaolo Bonzini 30446e790746SPaolo Bonzini n->vqs[0].tx_waiting = 0; 30451773d9eeSKONRAD Frederic n->tx_burst = n->net_conf.txburst; 3046bb9d17f8SCornelia Huck virtio_net_set_mrg_rx_bufs(n, 0, 0); 30476e790746SPaolo Bonzini n->promisc = 1; /* for compatibility */ 30486e790746SPaolo Bonzini 30496e790746SPaolo Bonzini n->mac_table.macs = g_malloc0(MAC_TABLE_ENTRIES * ETH_ALEN); 30506e790746SPaolo Bonzini 30516e790746SPaolo Bonzini n->vlans = g_malloc0(MAX_VLAN >> 3); 30526e790746SPaolo Bonzini 3053b1be4280SAmos Kong nc = qemu_get_queue(n->nic); 3054b1be4280SAmos Kong nc->rxfilter_notify_enabled = 1; 3055b1be4280SAmos Kong 30562974e916SYuri Benditovich QTAILQ_INIT(&n->rsc_chains); 3057284a32f0SAndreas Färber n->qdev = dev; 305817ec5a86SKONRAD Frederic } 305917ec5a86SKONRAD Frederic 3060306ec6c3SAndreas Färber static void virtio_net_device_unrealize(DeviceState *dev, Error **errp) 306117ec5a86SKONRAD Frederic { 3062306ec6c3SAndreas Färber VirtIODevice *vdev = VIRTIO_DEVICE(dev); 3063306ec6c3SAndreas Färber VirtIONet *n = VIRTIO_NET(dev); 3064f9d6dbf0SWen Congyang int i, max_queues; 306517ec5a86SKONRAD Frederic 306617ec5a86SKONRAD Frederic /* This will stop vhost backend if appropriate. */ 306717ec5a86SKONRAD Frederic virtio_net_set_status(vdev, 0); 306817ec5a86SKONRAD Frederic 30698a253ec2SKONRAD Frederic g_free(n->netclient_name); 30708a253ec2SKONRAD Frederic n->netclient_name = NULL; 30718a253ec2SKONRAD Frederic g_free(n->netclient_type); 30728a253ec2SKONRAD Frederic n->netclient_type = NULL; 30738a253ec2SKONRAD Frederic 307417ec5a86SKONRAD Frederic g_free(n->mac_table.macs); 307517ec5a86SKONRAD Frederic g_free(n->vlans); 307617ec5a86SKONRAD Frederic 30779711cd0dSJens Freimann if (n->failover) { 30789711cd0dSJens Freimann g_free(n->primary_device_id); 30799711cd0dSJens Freimann g_free(n->standby_id); 30809711cd0dSJens Freimann qobject_unref(n->primary_device_dict); 30819711cd0dSJens Freimann n->primary_device_dict = NULL; 30829711cd0dSJens Freimann } 30839711cd0dSJens Freimann 3084f9d6dbf0SWen Congyang max_queues = n->multiqueue ? n->max_queues : 1; 3085f9d6dbf0SWen Congyang for (i = 0; i < max_queues; i++) { 3086f9d6dbf0SWen Congyang virtio_net_del_queue(n, i); 308717ec5a86SKONRAD Frederic } 308817ec5a86SKONRAD Frederic 3089944458b6SDr. David Alan Gilbert qemu_announce_timer_del(&n->announce_timer, false); 309017ec5a86SKONRAD Frederic g_free(n->vqs); 309117ec5a86SKONRAD Frederic qemu_del_nic(n->nic); 30922974e916SYuri Benditovich virtio_net_rsc_cleanup(n); 30936a1a8cc7SKONRAD Frederic virtio_cleanup(vdev); 309417ec5a86SKONRAD Frederic } 309517ec5a86SKONRAD Frederic 309617ec5a86SKONRAD Frederic static void virtio_net_instance_init(Object *obj) 309717ec5a86SKONRAD Frederic { 309817ec5a86SKONRAD Frederic VirtIONet *n = VIRTIO_NET(obj); 309917ec5a86SKONRAD Frederic 310017ec5a86SKONRAD Frederic /* 310117ec5a86SKONRAD Frederic * The default config_size is sizeof(struct virtio_net_config). 310217ec5a86SKONRAD Frederic * Can be overriden with virtio_net_set_config_size. 310317ec5a86SKONRAD Frederic */ 310417ec5a86SKONRAD Frederic n->config_size = sizeof(struct virtio_net_config); 3105aa4197c3SGonglei device_add_bootindex_property(obj, &n->nic_conf.bootindex, 3106aa4197c3SGonglei "bootindex", "/ethernet-phy@0", 3107aa4197c3SGonglei DEVICE(n), NULL); 310817ec5a86SKONRAD Frederic } 310917ec5a86SKONRAD Frederic 311044b1ff31SDr. David Alan Gilbert static int virtio_net_pre_save(void *opaque) 31114d45dcfbSHalil Pasic { 31124d45dcfbSHalil Pasic VirtIONet *n = opaque; 31134d45dcfbSHalil Pasic 31144d45dcfbSHalil Pasic /* At this point, backend must be stopped, otherwise 31154d45dcfbSHalil Pasic * it might keep writing to memory. */ 31164d45dcfbSHalil Pasic assert(!n->vhost_started); 311744b1ff31SDr. David Alan Gilbert 311844b1ff31SDr. David Alan Gilbert return 0; 31194d45dcfbSHalil Pasic } 31204d45dcfbSHalil Pasic 31219711cd0dSJens Freimann static bool primary_unplug_pending(void *opaque) 31229711cd0dSJens Freimann { 31239711cd0dSJens Freimann DeviceState *dev = opaque; 31249711cd0dSJens Freimann VirtIODevice *vdev = VIRTIO_DEVICE(dev); 31259711cd0dSJens Freimann VirtIONet *n = VIRTIO_NET(vdev); 31269711cd0dSJens Freimann 31279711cd0dSJens Freimann return n->primary_dev ? n->primary_dev->pending_deleted_event : false; 31289711cd0dSJens Freimann } 31299711cd0dSJens Freimann 31309711cd0dSJens Freimann static bool dev_unplug_pending(void *opaque) 31319711cd0dSJens Freimann { 31329711cd0dSJens Freimann DeviceState *dev = opaque; 31339711cd0dSJens Freimann VirtioDeviceClass *vdc = VIRTIO_DEVICE_GET_CLASS(dev); 31349711cd0dSJens Freimann 31359711cd0dSJens Freimann return vdc->primary_unplug_pending(dev); 31369711cd0dSJens Freimann } 31379711cd0dSJens Freimann 31384d45dcfbSHalil Pasic static const VMStateDescription vmstate_virtio_net = { 31394d45dcfbSHalil Pasic .name = "virtio-net", 31404d45dcfbSHalil Pasic .minimum_version_id = VIRTIO_NET_VM_VERSION, 31414d45dcfbSHalil Pasic .version_id = VIRTIO_NET_VM_VERSION, 31424d45dcfbSHalil Pasic .fields = (VMStateField[]) { 31434d45dcfbSHalil Pasic VMSTATE_VIRTIO_DEVICE, 31444d45dcfbSHalil Pasic VMSTATE_END_OF_LIST() 31454d45dcfbSHalil Pasic }, 31464d45dcfbSHalil Pasic .pre_save = virtio_net_pre_save, 31479711cd0dSJens Freimann .dev_unplug_pending = dev_unplug_pending, 31484d45dcfbSHalil Pasic }; 3149290c2428SDr. David Alan Gilbert 315017ec5a86SKONRAD Frederic static Property virtio_net_properties[] = { 3151127833eeSJason Baron DEFINE_PROP_BIT64("csum", VirtIONet, host_features, 3152127833eeSJason Baron VIRTIO_NET_F_CSUM, true), 3153127833eeSJason Baron DEFINE_PROP_BIT64("guest_csum", VirtIONet, host_features, 315487108bb2SShannon Zhao VIRTIO_NET_F_GUEST_CSUM, true), 3155127833eeSJason Baron DEFINE_PROP_BIT64("gso", VirtIONet, host_features, VIRTIO_NET_F_GSO, true), 3156127833eeSJason Baron DEFINE_PROP_BIT64("guest_tso4", VirtIONet, host_features, 315787108bb2SShannon Zhao VIRTIO_NET_F_GUEST_TSO4, true), 3158127833eeSJason Baron DEFINE_PROP_BIT64("guest_tso6", VirtIONet, host_features, 315987108bb2SShannon Zhao VIRTIO_NET_F_GUEST_TSO6, true), 3160127833eeSJason Baron DEFINE_PROP_BIT64("guest_ecn", VirtIONet, host_features, 316187108bb2SShannon Zhao VIRTIO_NET_F_GUEST_ECN, true), 3162127833eeSJason Baron DEFINE_PROP_BIT64("guest_ufo", VirtIONet, host_features, 316387108bb2SShannon Zhao VIRTIO_NET_F_GUEST_UFO, true), 3164127833eeSJason Baron DEFINE_PROP_BIT64("guest_announce", VirtIONet, host_features, 316587108bb2SShannon Zhao VIRTIO_NET_F_GUEST_ANNOUNCE, true), 3166127833eeSJason Baron DEFINE_PROP_BIT64("host_tso4", VirtIONet, host_features, 316787108bb2SShannon Zhao VIRTIO_NET_F_HOST_TSO4, true), 3168127833eeSJason Baron DEFINE_PROP_BIT64("host_tso6", VirtIONet, host_features, 316987108bb2SShannon Zhao VIRTIO_NET_F_HOST_TSO6, true), 3170127833eeSJason Baron DEFINE_PROP_BIT64("host_ecn", VirtIONet, host_features, 317187108bb2SShannon Zhao VIRTIO_NET_F_HOST_ECN, true), 3172127833eeSJason Baron DEFINE_PROP_BIT64("host_ufo", VirtIONet, host_features, 317387108bb2SShannon Zhao VIRTIO_NET_F_HOST_UFO, true), 3174127833eeSJason Baron DEFINE_PROP_BIT64("mrg_rxbuf", VirtIONet, host_features, 317587108bb2SShannon Zhao VIRTIO_NET_F_MRG_RXBUF, true), 3176127833eeSJason Baron DEFINE_PROP_BIT64("status", VirtIONet, host_features, 317787108bb2SShannon Zhao VIRTIO_NET_F_STATUS, true), 3178127833eeSJason Baron DEFINE_PROP_BIT64("ctrl_vq", VirtIONet, host_features, 317987108bb2SShannon Zhao VIRTIO_NET_F_CTRL_VQ, true), 3180127833eeSJason Baron DEFINE_PROP_BIT64("ctrl_rx", VirtIONet, host_features, 318187108bb2SShannon Zhao VIRTIO_NET_F_CTRL_RX, true), 3182127833eeSJason Baron DEFINE_PROP_BIT64("ctrl_vlan", VirtIONet, host_features, 318387108bb2SShannon Zhao VIRTIO_NET_F_CTRL_VLAN, true), 3184127833eeSJason Baron DEFINE_PROP_BIT64("ctrl_rx_extra", VirtIONet, host_features, 318587108bb2SShannon Zhao VIRTIO_NET_F_CTRL_RX_EXTRA, true), 3186127833eeSJason Baron DEFINE_PROP_BIT64("ctrl_mac_addr", VirtIONet, host_features, 318787108bb2SShannon Zhao VIRTIO_NET_F_CTRL_MAC_ADDR, true), 3188127833eeSJason Baron DEFINE_PROP_BIT64("ctrl_guest_offloads", VirtIONet, host_features, 318987108bb2SShannon Zhao VIRTIO_NET_F_CTRL_GUEST_OFFLOADS, true), 3190127833eeSJason Baron DEFINE_PROP_BIT64("mq", VirtIONet, host_features, VIRTIO_NET_F_MQ, false), 31912974e916SYuri Benditovich DEFINE_PROP_BIT64("guest_rsc_ext", VirtIONet, host_features, 31922974e916SYuri Benditovich VIRTIO_NET_F_RSC_EXT, false), 31932974e916SYuri Benditovich DEFINE_PROP_UINT32("rsc_interval", VirtIONet, rsc_timeout, 31942974e916SYuri Benditovich VIRTIO_NET_RSC_DEFAULT_INTERVAL), 319517ec5a86SKONRAD Frederic DEFINE_NIC_PROPERTIES(VirtIONet, nic_conf), 319617ec5a86SKONRAD Frederic DEFINE_PROP_UINT32("x-txtimer", VirtIONet, net_conf.txtimer, 319717ec5a86SKONRAD Frederic TX_TIMER_INTERVAL), 319817ec5a86SKONRAD Frederic DEFINE_PROP_INT32("x-txburst", VirtIONet, net_conf.txburst, TX_BURST), 319917ec5a86SKONRAD Frederic DEFINE_PROP_STRING("tx", VirtIONet, net_conf.tx), 32001c0fbfa3SMichael S. Tsirkin DEFINE_PROP_UINT16("rx_queue_size", VirtIONet, net_conf.rx_queue_size, 32011c0fbfa3SMichael S. Tsirkin VIRTIO_NET_RX_QUEUE_DEFAULT_SIZE), 32029b02e161SWei Wang DEFINE_PROP_UINT16("tx_queue_size", VirtIONet, net_conf.tx_queue_size, 32039b02e161SWei Wang VIRTIO_NET_TX_QUEUE_DEFAULT_SIZE), 3204a93e599dSMaxime Coquelin DEFINE_PROP_UINT16("host_mtu", VirtIONet, net_conf.mtu, 0), 320575ebec11SMaxime Coquelin DEFINE_PROP_BOOL("x-mtu-bypass-backend", VirtIONet, mtu_bypass_backend, 320675ebec11SMaxime Coquelin true), 32079473939eSJason Baron DEFINE_PROP_INT32("speed", VirtIONet, net_conf.speed, SPEED_UNKNOWN), 32089473939eSJason Baron DEFINE_PROP_STRING("duplex", VirtIONet, net_conf.duplex_str), 32099711cd0dSJens Freimann DEFINE_PROP_BOOL("failover", VirtIONet, failover, false), 321017ec5a86SKONRAD Frederic DEFINE_PROP_END_OF_LIST(), 321117ec5a86SKONRAD Frederic }; 321217ec5a86SKONRAD Frederic 321317ec5a86SKONRAD Frederic static void virtio_net_class_init(ObjectClass *klass, void *data) 321417ec5a86SKONRAD Frederic { 321517ec5a86SKONRAD Frederic DeviceClass *dc = DEVICE_CLASS(klass); 321617ec5a86SKONRAD Frederic VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); 3217e6f746b3SAndreas Färber 321817ec5a86SKONRAD Frederic dc->props = virtio_net_properties; 3219290c2428SDr. David Alan Gilbert dc->vmsd = &vmstate_virtio_net; 3220125ee0edSMarcel Apfelbaum set_bit(DEVICE_CATEGORY_NETWORK, dc->categories); 3221e6f746b3SAndreas Färber vdc->realize = virtio_net_device_realize; 3222306ec6c3SAndreas Färber vdc->unrealize = virtio_net_device_unrealize; 322317ec5a86SKONRAD Frederic vdc->get_config = virtio_net_get_config; 322417ec5a86SKONRAD Frederic vdc->set_config = virtio_net_set_config; 322517ec5a86SKONRAD Frederic vdc->get_features = virtio_net_get_features; 322617ec5a86SKONRAD Frederic vdc->set_features = virtio_net_set_features; 322717ec5a86SKONRAD Frederic vdc->bad_features = virtio_net_bad_features; 322817ec5a86SKONRAD Frederic vdc->reset = virtio_net_reset; 322917ec5a86SKONRAD Frederic vdc->set_status = virtio_net_set_status; 323017ec5a86SKONRAD Frederic vdc->guest_notifier_mask = virtio_net_guest_notifier_mask; 323117ec5a86SKONRAD Frederic vdc->guest_notifier_pending = virtio_net_guest_notifier_pending; 32322a083ffdSMichael S. Tsirkin vdc->legacy_features |= (0x1 << VIRTIO_NET_F_GSO); 32337788c3f2SMikhail Sennikovsky vdc->post_load = virtio_net_post_load_virtio; 3234982b78c5SDr. David Alan Gilbert vdc->vmsd = &vmstate_virtio_net_device; 32359711cd0dSJens Freimann vdc->primary_unplug_pending = primary_unplug_pending; 323617ec5a86SKONRAD Frederic } 323717ec5a86SKONRAD Frederic 323817ec5a86SKONRAD Frederic static const TypeInfo virtio_net_info = { 323917ec5a86SKONRAD Frederic .name = TYPE_VIRTIO_NET, 324017ec5a86SKONRAD Frederic .parent = TYPE_VIRTIO_DEVICE, 324117ec5a86SKONRAD Frederic .instance_size = sizeof(VirtIONet), 324217ec5a86SKONRAD Frederic .instance_init = virtio_net_instance_init, 324317ec5a86SKONRAD Frederic .class_init = virtio_net_class_init, 324417ec5a86SKONRAD Frederic }; 324517ec5a86SKONRAD Frederic 324617ec5a86SKONRAD Frederic static void virtio_register_types(void) 324717ec5a86SKONRAD Frederic { 324817ec5a86SKONRAD Frederic type_register_static(&virtio_net_info); 324917ec5a86SKONRAD Frederic } 325017ec5a86SKONRAD Frederic 325117ec5a86SKONRAD Frederic type_init(virtio_register_types) 3252