qemu with hax to log dma reads & writes jcs.org/2018/11/12/vfio

virtio-net: implement RX RSS processing

If VIRTIO_NET_F_RSS negotiated and RSS is enabled, process
incoming packets, calculate packet's hash and place the
packet into respective RX virtqueue.

Signed-off-by: Yuri Benditovich <yuri.benditovich@daynix.com>
Signed-off-by: Jason Wang <jasowang@redhat.com>

authored by

Yuri Benditovich and committed by
Jason Wang
4474e37a 59079029

+88 -2
+1
hw/net/Makefile.objs
··· 41 41 obj-$(CONFIG_PSERIES) += spapr_llan.o 42 42 obj-$(CONFIG_XILINX_ETHLITE) += xilinx_ethlite.o 43 43 44 + common-obj-$(CONFIG_VIRTIO_NET) += net_rx_pkt.o 44 45 obj-$(CONFIG_VIRTIO_NET) += virtio-net.o 45 46 common-obj-$(call land,$(CONFIG_VIRTIO_NET),$(CONFIG_VHOST_NET)) += vhost_net.o 46 47 common-obj-$(call lnot,$(call land,$(CONFIG_VIRTIO_NET),$(CONFIG_VHOST_NET))) += vhost_net-stub.o
+86 -2
hw/net/virtio-net.c
··· 42 42 #include "trace.h" 43 43 #include "monitor/qdev.h" 44 44 #include "hw/pci/pci.h" 45 + #include "net_rx_pkt.h" 45 46 46 47 #define VIRTIO_NET_VM_VERSION 11 47 48 ··· 1533 1534 return 0; 1534 1535 } 1535 1536 1537 + static uint8_t virtio_net_get_hash_type(bool isip4, 1538 + bool isip6, 1539 + bool isudp, 1540 + bool istcp, 1541 + uint32_t types) 1542 + { 1543 + if (isip4) { 1544 + if (istcp && (types & VIRTIO_NET_RSS_HASH_TYPE_TCPv4)) { 1545 + return NetPktRssIpV4Tcp; 1546 + } 1547 + if (isudp && (types & VIRTIO_NET_RSS_HASH_TYPE_UDPv4)) { 1548 + return NetPktRssIpV4Udp; 1549 + } 1550 + if (types & VIRTIO_NET_RSS_HASH_TYPE_IPv4) { 1551 + return NetPktRssIpV4; 1552 + } 1553 + } else if (isip6) { 1554 + uint32_t mask = VIRTIO_NET_RSS_HASH_TYPE_TCP_EX | 1555 + VIRTIO_NET_RSS_HASH_TYPE_TCPv6; 1556 + 1557 + if (istcp && (types & mask)) { 1558 + return (types & VIRTIO_NET_RSS_HASH_TYPE_TCP_EX) ? 1559 + NetPktRssIpV6TcpEx : NetPktRssIpV6Tcp; 1560 + } 1561 + mask = VIRTIO_NET_RSS_HASH_TYPE_UDP_EX | VIRTIO_NET_RSS_HASH_TYPE_UDPv6; 1562 + if (isudp && (types & mask)) { 1563 + return (types & VIRTIO_NET_RSS_HASH_TYPE_UDP_EX) ? 1564 + NetPktRssIpV6UdpEx : NetPktRssIpV6Udp; 1565 + } 1566 + mask = VIRTIO_NET_RSS_HASH_TYPE_IP_EX | VIRTIO_NET_RSS_HASH_TYPE_IPv6; 1567 + if (types & mask) { 1568 + return (types & VIRTIO_NET_RSS_HASH_TYPE_IP_EX) ? 1569 + NetPktRssIpV6Ex : NetPktRssIpV6; 1570 + } 1571 + } 1572 + return 0xff; 1573 + } 1574 + 1575 + static int virtio_net_process_rss(NetClientState *nc, const uint8_t *buf, 1576 + size_t size) 1577 + { 1578 + VirtIONet *n = qemu_get_nic_opaque(nc); 1579 + unsigned int index = nc->queue_index, new_index; 1580 + struct NetRxPkt *pkt = n->rx_pkt; 1581 + uint8_t net_hash_type; 1582 + uint32_t hash; 1583 + bool isip4, isip6, isudp, istcp; 1584 + 1585 + net_rx_pkt_set_protocols(pkt, buf + n->host_hdr_len, 1586 + size - n->host_hdr_len); 1587 + net_rx_pkt_get_protocols(pkt, &isip4, &isip6, &isudp, &istcp); 1588 + if (isip4 && (net_rx_pkt_get_ip4_info(pkt)->fragment)) { 1589 + istcp = isudp = false; 1590 + } 1591 + if (isip6 && (net_rx_pkt_get_ip6_info(pkt)->fragment)) { 1592 + istcp = isudp = false; 1593 + } 1594 + net_hash_type = virtio_net_get_hash_type(isip4, isip6, isudp, istcp, 1595 + n->rss_data.hash_types); 1596 + if (net_hash_type > NetPktRssIpV6UdpEx) { 1597 + return n->rss_data.default_queue; 1598 + } 1599 + 1600 + hash = net_rx_pkt_calc_rss_hash(pkt, net_hash_type, n->rss_data.key); 1601 + new_index = hash & (n->rss_data.indirections_len - 1); 1602 + new_index = n->rss_data.indirections_table[new_index]; 1603 + if (index == new_index) { 1604 + return -1; 1605 + } 1606 + return new_index; 1607 + } 1608 + 1536 1609 static ssize_t virtio_net_receive_rcu(NetClientState *nc, const uint8_t *buf, 1537 - size_t size) 1610 + size_t size, bool no_rss) 1538 1611 { 1539 1612 VirtIONet *n = qemu_get_nic_opaque(nc); 1540 1613 VirtIONetQueue *q = virtio_net_get_subqueue(nc); ··· 1546 1619 1547 1620 if (!virtio_net_can_receive(nc)) { 1548 1621 return -1; 1622 + } 1623 + 1624 + if (!no_rss && n->rss_data.enabled) { 1625 + int index = virtio_net_process_rss(nc, buf, size); 1626 + if (index >= 0) { 1627 + NetClientState *nc2 = qemu_get_subqueue(n->nic, index); 1628 + return virtio_net_receive_rcu(nc2, buf, size, true); 1629 + } 1549 1630 } 1550 1631 1551 1632 /* hdr_len refers to the header we supply to the guest */ ··· 1642 1723 { 1643 1724 RCU_READ_LOCK_GUARD(); 1644 1725 1645 - return virtio_net_receive_rcu(nc, buf, size); 1726 + return virtio_net_receive_rcu(nc, buf, size, false); 1646 1727 } 1647 1728 1648 1729 static void virtio_net_rsc_extract_unit4(VirtioNetRscChain *chain, ··· 3221 3302 3222 3303 QTAILQ_INIT(&n->rsc_chains); 3223 3304 n->qdev = dev; 3305 + 3306 + net_rx_pkt_init(&n->rx_pkt, false); 3224 3307 } 3225 3308 3226 3309 static void virtio_net_device_unrealize(DeviceState *dev) ··· 3258 3341 qemu_del_nic(n->nic); 3259 3342 virtio_net_rsc_cleanup(n); 3260 3343 g_free(n->rss_data.indirections_table); 3344 + net_rx_pkt_uninit(n->rx_pkt); 3261 3345 virtio_cleanup(vdev); 3262 3346 } 3263 3347
+1
include/hw/virtio/virtio-net.h
··· 212 212 DeviceListener primary_listener; 213 213 Notifier migration_state; 214 214 VirtioNetRssData rss_data; 215 + struct NetRxPkt *rx_pkt; 215 216 }; 216 217 217 218 void virtio_net_set_netclient_name(VirtIONet *n, const char *name,