Message ID | 20200309083438.2389-4-yuri.benditovich@daynix.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | reference implementation of RSS | expand |
On 2020/3/9 下午4:34, Yuri Benditovich wrote: > 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> > --- > hw/net/virtio-net.c | 86 +++++++++++++++++++++++++++++++++- > include/hw/virtio/virtio-net.h | 1 + > 2 files changed, 85 insertions(+), 2 deletions(-) > > diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c > index 27071eccd2..abc41fdb16 100644 > --- a/hw/net/virtio-net.c > +++ b/hw/net/virtio-net.c > @@ -42,6 +42,7 @@ > #include "trace.h" > #include "monitor/qdev.h" > #include "hw/pci/pci.h" > +#include "net_rx_pkt.h" > > #define VIRTIO_NET_VM_VERSION 11 > > @@ -1610,8 +1611,78 @@ static int receive_filter(VirtIONet *n, const uint8_t *buf, int size) > return 0; > } > > +static uint8_t virtio_net_get_hash_type(bool isip4, > + bool isip6, > + bool isudp, > + bool istcp, > + uint32_t types) > +{ > + uint32_t mask; > + if (isip4) { > + if (istcp && (types & VIRTIO_NET_RSS_HASH_TYPE_TCPv4)) { > + return NetPktRssIpV4Tcp; > + } > + if (isudp && (types & VIRTIO_NET_RSS_HASH_TYPE_UDPv4)) { > + return NetPktRssIpV4Udp; > + } > + if (types & VIRTIO_NET_RSS_HASH_TYPE_IPv4) { > + return NetPktRssIpV4; > + } > + } else if (isip6) { > + mask = VIRTIO_NET_RSS_HASH_TYPE_TCP_EX | VIRTIO_NET_RSS_HASH_TYPE_TCPv6; > + if (istcp && (types & mask)) { > + return (types & VIRTIO_NET_RSS_HASH_TYPE_TCP_EX) ? > + NetPktRssIpV6TcpEx : NetPktRssIpV6Tcp; > + } > + mask = VIRTIO_NET_RSS_HASH_TYPE_UDP_EX | VIRTIO_NET_RSS_HASH_TYPE_UDPv6; > + if (isudp && (types & mask)) { > + return (types & VIRTIO_NET_RSS_HASH_TYPE_UDP_EX) ? > + NetPktRssIpV6UdpEx : NetPktRssIpV6Udp; > + } > + mask = VIRTIO_NET_RSS_HASH_TYPE_IP_EX | VIRTIO_NET_RSS_HASH_TYPE_IPv6; > + if (types & mask) { > + return (types & VIRTIO_NET_RSS_HASH_TYPE_IP_EX) ? > + NetPktRssIpV6Ex : NetPktRssIpV6; > + } > + } > + return 0xff; > +} > + > +static int virtio_net_process_rss(NetClientState *nc, const uint8_t *buf, > + size_t size) > +{ > + VirtIONet *n = qemu_get_nic_opaque(nc); > + unsigned int index = nc->queue_index, new_index; > + struct NetRxPkt *pkt = n->rss_data.pkt; > + uint8_t net_hash_type; > + uint32_t hash; > + bool isip4, isip6, isudp, istcp; > + net_rx_pkt_set_protocols(pkt, buf + n->host_hdr_len, > + size - n->host_hdr_len); > + net_rx_pkt_get_protocols(pkt, &isip4, &isip6, &isudp, &istcp); > + if (isip4 && (net_rx_pkt_get_ip4_info(pkt)->fragment)) { > + istcp = isudp = false; > + } > + if (isip6 && (net_rx_pkt_get_ip6_info(pkt)->fragment)) { > + istcp = isudp = false; > + } > + net_hash_type = virtio_net_get_hash_type(isip4, isip6, isudp, istcp, > + n->rss_data.hash_types); > + if (net_hash_type > NetPktRssIpV6UdpEx) { > + return n->rss_data.default_queue; > + } > + > + hash = net_rx_pkt_calc_rss_hash(pkt, net_hash_type, n->rss_data.key); > + new_index = hash & (n->rss_data.indirections_len - 1); > + new_index = n->rss_data.indirections[new_index]; > + if (index == new_index) { > + return -1; > + } > + return new_index; > +} > + > static ssize_t virtio_net_receive_rcu(NetClientState *nc, const uint8_t *buf, > - size_t size) > + size_t size, bool no_rss) > { > VirtIONet *n = qemu_get_nic_opaque(nc); > VirtIONetQueue *q = virtio_net_get_subqueue(nc); > @@ -1625,6 +1696,14 @@ static ssize_t virtio_net_receive_rcu(NetClientState *nc, const uint8_t *buf, > return -1; > } > > + if (!no_rss && n->rss_data.enabled) { > + int index = virtio_net_process_rss(nc, buf, size); > + if (index >= 0) { > + NetClientState *nc2 = qemu_get_subqueue(n->nic, index); > + return virtio_net_receive_rcu(nc2, buf, size, true); > + } > + } In the long run, we need to implement steering ops and allow device model to implement their own policy instead of doing hack like this. Thanks > + > /* hdr_len refers to the header we supply to the guest */ > if (!virtio_net_has_buffers(q, size + n->guest_hdr_len - n->host_hdr_len)) { > return 0; > @@ -1719,7 +1798,7 @@ static ssize_t virtio_net_do_receive(NetClientState *nc, const uint8_t *buf, > { > RCU_READ_LOCK_GUARD(); > > - return virtio_net_receive_rcu(nc, buf, size); > + return virtio_net_receive_rcu(nc, buf, size, false); > } > > static void virtio_net_rsc_extract_unit4(VirtioNetRscChain *chain, > @@ -3295,6 +3374,8 @@ static void virtio_net_device_realize(DeviceState *dev, Error **errp) > > QTAILQ_INIT(&n->rsc_chains); > n->qdev = dev; > + > + net_rx_pkt_init(&n->rss_data.pkt, false); > } > > static void virtio_net_device_unrealize(DeviceState *dev, Error **errp) > @@ -3331,6 +3412,7 @@ static void virtio_net_device_unrealize(DeviceState *dev, Error **errp) > g_free(n->vqs); > qemu_del_nic(n->nic); > virtio_net_rsc_cleanup(n); > + net_rx_pkt_uninit(n->rss_data.pkt); > virtio_cleanup(vdev); > } > > diff --git a/include/hw/virtio/virtio-net.h b/include/hw/virtio/virtio-net.h > index cf16f5192e..45670dd054 100644 > --- a/include/hw/virtio/virtio-net.h > +++ b/include/hw/virtio/virtio-net.h > @@ -209,6 +209,7 @@ struct VirtIONet { > uint16_t indirections[VIRTIO_NET_RSS_MAX_TABLE_LEN]; > uint16_t indirections_len; > uint16_t default_queue; > + struct NetRxPkt *pkt; > } rss_data; > }; >
On Mon, Mar 09, 2020 at 10:34:37AM +0200, Yuri Benditovich wrote: > 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> > --- > hw/net/virtio-net.c | 86 +++++++++++++++++++++++++++++++++- > include/hw/virtio/virtio-net.h | 1 + > 2 files changed, 85 insertions(+), 2 deletions(-) > > diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c > index 27071eccd2..abc41fdb16 100644 > --- a/hw/net/virtio-net.c > +++ b/hw/net/virtio-net.c > @@ -42,6 +42,7 @@ > #include "trace.h" > #include "monitor/qdev.h" > #include "hw/pci/pci.h" > +#include "net_rx_pkt.h" > > #define VIRTIO_NET_VM_VERSION 11 > > @@ -1610,8 +1611,78 @@ static int receive_filter(VirtIONet *n, const uint8_t *buf, int size) > return 0; > } > > +static uint8_t virtio_net_get_hash_type(bool isip4, > + bool isip6, > + bool isudp, > + bool istcp, > + uint32_t types) > +{ > + uint32_t mask; > + if (isip4) { An empty line after a declaration won't hurt, here and elsewhere. > + if (istcp && (types & VIRTIO_NET_RSS_HASH_TYPE_TCPv4)) { > + return NetPktRssIpV4Tcp; > + } > + if (isudp && (types & VIRTIO_NET_RSS_HASH_TYPE_UDPv4)) { > + return NetPktRssIpV4Udp; > + } > + if (types & VIRTIO_NET_RSS_HASH_TYPE_IPv4) { > + return NetPktRssIpV4; > + } > + } else if (isip6) { > + mask = VIRTIO_NET_RSS_HASH_TYPE_TCP_EX | VIRTIO_NET_RSS_HASH_TYPE_TCPv6; Mask is only used on this path, move declaration within if ()? > + if (istcp && (types & mask)) { > + return (types & VIRTIO_NET_RSS_HASH_TYPE_TCP_EX) ? > + NetPktRssIpV6TcpEx : NetPktRssIpV6Tcp; > + } > + mask = VIRTIO_NET_RSS_HASH_TYPE_UDP_EX | VIRTIO_NET_RSS_HASH_TYPE_UDPv6; > + if (isudp && (types & mask)) { > + return (types & VIRTIO_NET_RSS_HASH_TYPE_UDP_EX) ? > + NetPktRssIpV6UdpEx : NetPktRssIpV6Udp; > + } > + mask = VIRTIO_NET_RSS_HASH_TYPE_IP_EX | VIRTIO_NET_RSS_HASH_TYPE_IPv6; > + if (types & mask) { > + return (types & VIRTIO_NET_RSS_HASH_TYPE_IP_EX) ? > + NetPktRssIpV6Ex : NetPktRssIpV6; > + } > + } > + return 0xff; > +} > + > +static int virtio_net_process_rss(NetClientState *nc, const uint8_t *buf, > + size_t size) > +{ > + VirtIONet *n = qemu_get_nic_opaque(nc); > + unsigned int index = nc->queue_index, new_index; > + struct NetRxPkt *pkt = n->rss_data.pkt; > + uint8_t net_hash_type; > + uint32_t hash; > + bool isip4, isip6, isudp, istcp; > + net_rx_pkt_set_protocols(pkt, buf + n->host_hdr_len, > + size - n->host_hdr_len); > + net_rx_pkt_get_protocols(pkt, &isip4, &isip6, &isudp, &istcp); > + if (isip4 && (net_rx_pkt_get_ip4_info(pkt)->fragment)) { > + istcp = isudp = false; > + } > + if (isip6 && (net_rx_pkt_get_ip6_info(pkt)->fragment)) { > + istcp = isudp = false; > + } > + net_hash_type = virtio_net_get_hash_type(isip4, isip6, isudp, istcp, > + n->rss_data.hash_types); > + if (net_hash_type > NetPktRssIpV6UdpEx) { > + return n->rss_data.default_queue; > + } > + > + hash = net_rx_pkt_calc_rss_hash(pkt, net_hash_type, n->rss_data.key); > + new_index = hash & (n->rss_data.indirections_len - 1); > + new_index = n->rss_data.indirections[new_index]; > + if (index == new_index) { > + return -1; > + } > + return new_index; > +} > + > static ssize_t virtio_net_receive_rcu(NetClientState *nc, const uint8_t *buf, > - size_t size) > + size_t size, bool no_rss) > { > VirtIONet *n = qemu_get_nic_opaque(nc); > VirtIONetQueue *q = virtio_net_get_subqueue(nc); > @@ -1625,6 +1696,14 @@ static ssize_t virtio_net_receive_rcu(NetClientState *nc, const uint8_t *buf, > return -1; > } > > + if (!no_rss && n->rss_data.enabled) { > + int index = virtio_net_process_rss(nc, buf, size); > + if (index >= 0) { > + NetClientState *nc2 = qemu_get_subqueue(n->nic, index); > + return virtio_net_receive_rcu(nc2, buf, size, true); > + } > + } > + > /* hdr_len refers to the header we supply to the guest */ > if (!virtio_net_has_buffers(q, size + n->guest_hdr_len - n->host_hdr_len)) { > return 0; > @@ -1719,7 +1798,7 @@ static ssize_t virtio_net_do_receive(NetClientState *nc, const uint8_t *buf, > { > RCU_READ_LOCK_GUARD(); > > - return virtio_net_receive_rcu(nc, buf, size); > + return virtio_net_receive_rcu(nc, buf, size, false); > } > > static void virtio_net_rsc_extract_unit4(VirtioNetRscChain *chain, > @@ -3295,6 +3374,8 @@ static void virtio_net_device_realize(DeviceState *dev, Error **errp) > > QTAILQ_INIT(&n->rsc_chains); > n->qdev = dev; > + > + net_rx_pkt_init(&n->rss_data.pkt, false); > } > > static void virtio_net_device_unrealize(DeviceState *dev, Error **errp) > @@ -3331,6 +3412,7 @@ static void virtio_net_device_unrealize(DeviceState *dev, Error **errp) > g_free(n->vqs); > qemu_del_nic(n->nic); > virtio_net_rsc_cleanup(n); > + net_rx_pkt_uninit(n->rss_data.pkt); > virtio_cleanup(vdev); > } > > diff --git a/include/hw/virtio/virtio-net.h b/include/hw/virtio/virtio-net.h > index cf16f5192e..45670dd054 100644 > --- a/include/hw/virtio/virtio-net.h > +++ b/include/hw/virtio/virtio-net.h > @@ -209,6 +209,7 @@ struct VirtIONet { > uint16_t indirections[VIRTIO_NET_RSS_MAX_TABLE_LEN]; > uint16_t indirections_len; > uint16_t default_queue; > + struct NetRxPkt *pkt; > } rss_data; > }; > > -- > 2.17.1
On Tue, Mar 10, 2020 at 5:10 AM Jason Wang <jasowang@redhat.com> wrote: > > > On 2020/3/9 下午4:34, Yuri Benditovich wrote: > > 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> > > --- > > hw/net/virtio-net.c | 86 +++++++++++++++++++++++++++++++++- > > include/hw/virtio/virtio-net.h | 1 + > > 2 files changed, 85 insertions(+), 2 deletions(-) > > > > diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c > > index 27071eccd2..abc41fdb16 100644 > > --- a/hw/net/virtio-net.c > > +++ b/hw/net/virtio-net.c > > @@ -42,6 +42,7 @@ > > #include "trace.h" > > #include "monitor/qdev.h" > > #include "hw/pci/pci.h" > > +#include "net_rx_pkt.h" > > > > #define VIRTIO_NET_VM_VERSION 11 > > > > @@ -1610,8 +1611,78 @@ static int receive_filter(VirtIONet *n, const uint8_t *buf, int size) > > return 0; > > } > > > > +static uint8_t virtio_net_get_hash_type(bool isip4, > > + bool isip6, > > + bool isudp, > > + bool istcp, > > + uint32_t types) > > +{ > > + uint32_t mask; > > + if (isip4) { > > + if (istcp && (types & VIRTIO_NET_RSS_HASH_TYPE_TCPv4)) { > > + return NetPktRssIpV4Tcp; > > + } > > + if (isudp && (types & VIRTIO_NET_RSS_HASH_TYPE_UDPv4)) { > > + return NetPktRssIpV4Udp; > > + } > > + if (types & VIRTIO_NET_RSS_HASH_TYPE_IPv4) { > > + return NetPktRssIpV4; > > + } > > + } else if (isip6) { > > + mask = VIRTIO_NET_RSS_HASH_TYPE_TCP_EX | VIRTIO_NET_RSS_HASH_TYPE_TCPv6; > > + if (istcp && (types & mask)) { > > + return (types & VIRTIO_NET_RSS_HASH_TYPE_TCP_EX) ? > > + NetPktRssIpV6TcpEx : NetPktRssIpV6Tcp; > > + } > > + mask = VIRTIO_NET_RSS_HASH_TYPE_UDP_EX | VIRTIO_NET_RSS_HASH_TYPE_UDPv6; > > + if (isudp && (types & mask)) { > > + return (types & VIRTIO_NET_RSS_HASH_TYPE_UDP_EX) ? > > + NetPktRssIpV6UdpEx : NetPktRssIpV6Udp; > > + } > > + mask = VIRTIO_NET_RSS_HASH_TYPE_IP_EX | VIRTIO_NET_RSS_HASH_TYPE_IPv6; > > + if (types & mask) { > > + return (types & VIRTIO_NET_RSS_HASH_TYPE_IP_EX) ? > > + NetPktRssIpV6Ex : NetPktRssIpV6; > > + } > > + } > > + return 0xff; > > +} > > + > > +static int virtio_net_process_rss(NetClientState *nc, const uint8_t *buf, > > + size_t size) > > +{ > > + VirtIONet *n = qemu_get_nic_opaque(nc); > > + unsigned int index = nc->queue_index, new_index; > > + struct NetRxPkt *pkt = n->rss_data.pkt; > > + uint8_t net_hash_type; > > + uint32_t hash; > > + bool isip4, isip6, isudp, istcp; > > + net_rx_pkt_set_protocols(pkt, buf + n->host_hdr_len, > > + size - n->host_hdr_len); > > + net_rx_pkt_get_protocols(pkt, &isip4, &isip6, &isudp, &istcp); > > + if (isip4 && (net_rx_pkt_get_ip4_info(pkt)->fragment)) { > > + istcp = isudp = false; > > + } > > + if (isip6 && (net_rx_pkt_get_ip6_info(pkt)->fragment)) { > > + istcp = isudp = false; > > + } > > + net_hash_type = virtio_net_get_hash_type(isip4, isip6, isudp, istcp, > > + n->rss_data.hash_types); > > + if (net_hash_type > NetPktRssIpV6UdpEx) { > > + return n->rss_data.default_queue; > > + } > > + > > + hash = net_rx_pkt_calc_rss_hash(pkt, net_hash_type, n->rss_data.key); > > + new_index = hash & (n->rss_data.indirections_len - 1); > > + new_index = n->rss_data.indirections[new_index]; > > + if (index == new_index) { > > + return -1; > > + } > > + return new_index; > > +} > > + > > static ssize_t virtio_net_receive_rcu(NetClientState *nc, const uint8_t *buf, > > - size_t size) > > + size_t size, bool no_rss) > > { > > VirtIONet *n = qemu_get_nic_opaque(nc); > > VirtIONetQueue *q = virtio_net_get_subqueue(nc); > > @@ -1625,6 +1696,14 @@ static ssize_t virtio_net_receive_rcu(NetClientState *nc, const uint8_t *buf, > > return -1; > > } > > > > + if (!no_rss && n->rss_data.enabled) { > > + int index = virtio_net_process_rss(nc, buf, size); > > + if (index >= 0) { > > + NetClientState *nc2 = qemu_get_subqueue(n->nic, index); > > + return virtio_net_receive_rcu(nc2, buf, size, true); > > + } > > + } > > > In the long run, we need to implement steering ops and allow device > model to implement their own policy instead of doing hack like this. > Are you talking about support for RSS in tap driver or about something different? > Thanks > > > > + > > /* hdr_len refers to the header we supply to the guest */ > > if (!virtio_net_has_buffers(q, size + n->guest_hdr_len - n->host_hdr_len)) { > > return 0; > > @@ -1719,7 +1798,7 @@ static ssize_t virtio_net_do_receive(NetClientState *nc, const uint8_t *buf, > > { > > RCU_READ_LOCK_GUARD(); > > > > - return virtio_net_receive_rcu(nc, buf, size); > > + return virtio_net_receive_rcu(nc, buf, size, false); > > } > > > > static void virtio_net_rsc_extract_unit4(VirtioNetRscChain *chain, > > @@ -3295,6 +3374,8 @@ static void virtio_net_device_realize(DeviceState *dev, Error **errp) > > > > QTAILQ_INIT(&n->rsc_chains); > > n->qdev = dev; > > + > > + net_rx_pkt_init(&n->rss_data.pkt, false); > > } > > > > static void virtio_net_device_unrealize(DeviceState *dev, Error **errp) > > @@ -3331,6 +3412,7 @@ static void virtio_net_device_unrealize(DeviceState *dev, Error **errp) > > g_free(n->vqs); > > qemu_del_nic(n->nic); > > virtio_net_rsc_cleanup(n); > > + net_rx_pkt_uninit(n->rss_data.pkt); > > virtio_cleanup(vdev); > > } > > > > diff --git a/include/hw/virtio/virtio-net.h b/include/hw/virtio/virtio-net.h > > index cf16f5192e..45670dd054 100644 > > --- a/include/hw/virtio/virtio-net.h > > +++ b/include/hw/virtio/virtio-net.h > > @@ -209,6 +209,7 @@ struct VirtIONet { > > uint16_t indirections[VIRTIO_NET_RSS_MAX_TABLE_LEN]; > > uint16_t indirections_len; > > uint16_t default_queue; > > + struct NetRxPkt *pkt; > > } rss_data; > > }; > > >
diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c index 27071eccd2..abc41fdb16 100644 --- a/hw/net/virtio-net.c +++ b/hw/net/virtio-net.c @@ -42,6 +42,7 @@ #include "trace.h" #include "monitor/qdev.h" #include "hw/pci/pci.h" +#include "net_rx_pkt.h" #define VIRTIO_NET_VM_VERSION 11 @@ -1610,8 +1611,78 @@ static int receive_filter(VirtIONet *n, const uint8_t *buf, int size) return 0; } +static uint8_t virtio_net_get_hash_type(bool isip4, + bool isip6, + bool isudp, + bool istcp, + uint32_t types) +{ + uint32_t mask; + if (isip4) { + if (istcp && (types & VIRTIO_NET_RSS_HASH_TYPE_TCPv4)) { + return NetPktRssIpV4Tcp; + } + if (isudp && (types & VIRTIO_NET_RSS_HASH_TYPE_UDPv4)) { + return NetPktRssIpV4Udp; + } + if (types & VIRTIO_NET_RSS_HASH_TYPE_IPv4) { + return NetPktRssIpV4; + } + } else if (isip6) { + mask = VIRTIO_NET_RSS_HASH_TYPE_TCP_EX | VIRTIO_NET_RSS_HASH_TYPE_TCPv6; + if (istcp && (types & mask)) { + return (types & VIRTIO_NET_RSS_HASH_TYPE_TCP_EX) ? + NetPktRssIpV6TcpEx : NetPktRssIpV6Tcp; + } + mask = VIRTIO_NET_RSS_HASH_TYPE_UDP_EX | VIRTIO_NET_RSS_HASH_TYPE_UDPv6; + if (isudp && (types & mask)) { + return (types & VIRTIO_NET_RSS_HASH_TYPE_UDP_EX) ? + NetPktRssIpV6UdpEx : NetPktRssIpV6Udp; + } + mask = VIRTIO_NET_RSS_HASH_TYPE_IP_EX | VIRTIO_NET_RSS_HASH_TYPE_IPv6; + if (types & mask) { + return (types & VIRTIO_NET_RSS_HASH_TYPE_IP_EX) ? + NetPktRssIpV6Ex : NetPktRssIpV6; + } + } + return 0xff; +} + +static int virtio_net_process_rss(NetClientState *nc, const uint8_t *buf, + size_t size) +{ + VirtIONet *n = qemu_get_nic_opaque(nc); + unsigned int index = nc->queue_index, new_index; + struct NetRxPkt *pkt = n->rss_data.pkt; + uint8_t net_hash_type; + uint32_t hash; + bool isip4, isip6, isudp, istcp; + net_rx_pkt_set_protocols(pkt, buf + n->host_hdr_len, + size - n->host_hdr_len); + net_rx_pkt_get_protocols(pkt, &isip4, &isip6, &isudp, &istcp); + if (isip4 && (net_rx_pkt_get_ip4_info(pkt)->fragment)) { + istcp = isudp = false; + } + if (isip6 && (net_rx_pkt_get_ip6_info(pkt)->fragment)) { + istcp = isudp = false; + } + net_hash_type = virtio_net_get_hash_type(isip4, isip6, isudp, istcp, + n->rss_data.hash_types); + if (net_hash_type > NetPktRssIpV6UdpEx) { + return n->rss_data.default_queue; + } + + hash = net_rx_pkt_calc_rss_hash(pkt, net_hash_type, n->rss_data.key); + new_index = hash & (n->rss_data.indirections_len - 1); + new_index = n->rss_data.indirections[new_index]; + if (index == new_index) { + return -1; + } + return new_index; +} + static ssize_t virtio_net_receive_rcu(NetClientState *nc, const uint8_t *buf, - size_t size) + size_t size, bool no_rss) { VirtIONet *n = qemu_get_nic_opaque(nc); VirtIONetQueue *q = virtio_net_get_subqueue(nc); @@ -1625,6 +1696,14 @@ static ssize_t virtio_net_receive_rcu(NetClientState *nc, const uint8_t *buf, return -1; } + if (!no_rss && n->rss_data.enabled) { + int index = virtio_net_process_rss(nc, buf, size); + if (index >= 0) { + NetClientState *nc2 = qemu_get_subqueue(n->nic, index); + return virtio_net_receive_rcu(nc2, buf, size, true); + } + } + /* hdr_len refers to the header we supply to the guest */ if (!virtio_net_has_buffers(q, size + n->guest_hdr_len - n->host_hdr_len)) { return 0; @@ -1719,7 +1798,7 @@ static ssize_t virtio_net_do_receive(NetClientState *nc, const uint8_t *buf, { RCU_READ_LOCK_GUARD(); - return virtio_net_receive_rcu(nc, buf, size); + return virtio_net_receive_rcu(nc, buf, size, false); } static void virtio_net_rsc_extract_unit4(VirtioNetRscChain *chain, @@ -3295,6 +3374,8 @@ static void virtio_net_device_realize(DeviceState *dev, Error **errp) QTAILQ_INIT(&n->rsc_chains); n->qdev = dev; + + net_rx_pkt_init(&n->rss_data.pkt, false); } static void virtio_net_device_unrealize(DeviceState *dev, Error **errp) @@ -3331,6 +3412,7 @@ static void virtio_net_device_unrealize(DeviceState *dev, Error **errp) g_free(n->vqs); qemu_del_nic(n->nic); virtio_net_rsc_cleanup(n); + net_rx_pkt_uninit(n->rss_data.pkt); virtio_cleanup(vdev); } diff --git a/include/hw/virtio/virtio-net.h b/include/hw/virtio/virtio-net.h index cf16f5192e..45670dd054 100644 --- a/include/hw/virtio/virtio-net.h +++ b/include/hw/virtio/virtio-net.h @@ -209,6 +209,7 @@ struct VirtIONet { uint16_t indirections[VIRTIO_NET_RSS_MAX_TABLE_LEN]; uint16_t indirections_len; uint16_t default_queue; + struct NetRxPkt *pkt; } rss_data; };
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> --- hw/net/virtio-net.c | 86 +++++++++++++++++++++++++++++++++- include/hw/virtio/virtio-net.h | 1 + 2 files changed, 85 insertions(+), 2 deletions(-)