Re: [PATCH 2/5] virtio-net: Added property to load eBPF RSS with fds.

2023-05-07 Thread Andrew Melnichenko
Hi all,

Thank you for your comments. I'll update it in the next patch version.

On Wed, May 3, 2023 at 2:03 PM Daniel P. Berrangé  wrote:
>
> On Mon, May 01, 2023 at 10:20:58AM +0300, Andrew Melnychenko wrote:
> > eBPF RSS program and maps may now be passed during initialization.
> > Initially was implemented for libvirt to launch qemu without permissions,
> > and initialized eBPF program through the helper.
> >
> > Signed-off-by: Andrew Melnychenko 
> > ---
> >  hw/net/virtio-net.c| 96 +++---
> >  include/hw/virtio/virtio-net.h |  1 +
> >  2 files changed, 91 insertions(+), 6 deletions(-)
> >
> > diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
> > index 53e1c326433..9b3a997d872 100644
> > --- a/hw/net/virtio-net.c
> > +++ b/hw/net/virtio-net.c
> > @@ -42,6 +42,7 @@
> >  #include "sysemu/sysemu.h"
> >  #include "trace.h"
> >  #include "monitor/qdev.h"
> > +#include "monitor/monitor.h"
> >  #include "hw/pci/pci_device.h"
> >  #include "net_rx_pkt.h"
> >  #include "hw/virtio/vhost.h"
> > @@ -1305,14 +1306,96 @@ static void virtio_net_detach_epbf_rss(VirtIONet *n)
> >  virtio_net_attach_ebpf_to_backend(n->nic, -1);
> >  }
> >
> > -static bool virtio_net_load_ebpf(VirtIONet *n)
> > +static int virtio_net_get_ebpf_rss_fds(char *str, char *fds[], int nfds,
> > +   Error **errp)
> >  {
> > -if (!virtio_net_attach_ebpf_to_backend(n->nic, -1)) {
> > -/* backend does't support steering ebpf */
> > -return false;
> > +char *ptr = str;
> > +char *cur = NULL;
> > +size_t len = strlen(str);
> > +int i = 0;
> > +
> > +for (; i < nfds && ptr < str + len;) {
> > +cur = strchr(ptr, ':');
> > +
> > +if (cur == NULL) {
> > +fds[i] = g_strdup(ptr);
> > +} else {
> > +fds[i] = g_strndup(ptr, cur - ptr);
> > +}
> > +
> > +i++;
> > +if (cur == NULL) {
> > +break;
> > +} else {
> > +ptr = cur + 1;
> > +}
> > +}
> > +
> > +if (cur != NULL) {
> > +/* the string contains more arguments */
> > +error_setg(errp,
> > +   "Too many eBPF file descriptors for RSS provided.");
> > +} else if (i < nfds) {
> > +error_setg(errp,
> > +   "Not enough eBPF file descriptors for RSS were 
> > provided.");
> > +}
> > +
> > +return i;
> > +}
>
> This whole method could be replaced by a call to g_strsplit in
> the caller
>
>
> > +
> > +static bool virtio_net_load_ebpf_fds(VirtIONet *n, Error **errp)
> > +{
> > +char *fds_strs[EBPF_RSS_MAX_FDS];
>
>g_autoptr(GStrv) fds_strs = g_strsplit(n->ebpf_rss_fds, ",", 0);
>
> > +int fds[EBPF_RSS_MAX_FDS];
>
> Left as uninitialized stack memory.
>
> > +int nfds;
> > +int ret = true;
> > +int i = 0;
> > +
> > +ERRP_GUARD();
> > +
> > +nfds = virtio_net_get_ebpf_rss_fds(n->ebpf_rss_fds,
> > +   fds_strs, EBPF_RSS_MAX_FDS, errp);
> > +if (*errp) {
> > +ret = false;
> > +goto exit;
> >  }
>
> Replace with
>
>if (g_strv_length(fds_strs) != EBPF_RSS_MAX_FDS) {
>error_setg(errp,
>   "Expected %d file descriptors but got %d",
>   EBPF_RSS_MAX_FDS, g_strv_length(fds_strs));
>return false;
>}
>
> >
> > -return ebpf_rss_load(>ebpf_rss);
> > +for (i = 0; i < nfds; i++) {
> > +fds[i] = monitor_fd_param(monitor_cur(), fds_strs[i], errp);
> > +if (*errp) {
> > +ret = false;
> > +goto exit;
>
> This can break out of the loop before all elements in 'fds' are
> initialized.
>
> > +}
> > +}
> > +
> > +ret = ebpf_rss_load_fds(>ebpf_rss, fds[0], fds[1], fds[2], fds[3]);
> > +
> > +exit:
> > +if (!ret || *errp) {
> > +for (i = 0; i < nfds; i++) {
> > +close(fds[i]);
> > +}
> > +}
>
> This now calls close() on uninitialized memory, killing
> arbitary FDs QEMU has open elsewhere.
>
> > +
> > +for (i = 0; i < nfds; i++) {
> > +g_free(fds_strs[i]);
> > +}
>
> Not required if we use g_autoptr(GStrv)
>
> > +
> > +return ret;
> > +}
> > +
> > +static bool virtio_net_load_ebpf(VirtIONet *n, Error **errp)
> > +{
> > +bool ret = false;
> > +
> > +if (virtio_net_attach_ebpf_to_backend(n->nic, -1)) {
> > +if (!(n->ebpf_rss_fds
> > +&& virtio_net_load_ebpf_fds(n, errp))) {
> > +ret = ebpf_rss_load(>ebpf_rss);
> > +}
> > +}
> > +
> > +return ret;
> >  }
> >
> >  static void virtio_net_unload_ebpf(VirtIONet *n)
> > @@ -3738,7 +3821,7 @@ static void virtio_net_device_realize(DeviceState 
> > *dev, Error **errp)
> >  net_rx_pkt_init(>rx_pkt);
> >
> >  if (virtio_has_feature(n->host_features, VIRTIO_NET_F_RSS)) {
> > -virtio_net_load_ebpf(n);
> > +virtio_net_load_ebpf(n, errp);
> >  }
> > 

Re: [PATCH 2/5] virtio-net: Added property to load eBPF RSS with fds.

2023-05-03 Thread Daniel P . Berrangé
On Mon, May 01, 2023 at 10:20:58AM +0300, Andrew Melnychenko wrote:
> eBPF RSS program and maps may now be passed during initialization.
> Initially was implemented for libvirt to launch qemu without permissions,
> and initialized eBPF program through the helper.
> 
> Signed-off-by: Andrew Melnychenko 
> ---
>  hw/net/virtio-net.c| 96 +++---
>  include/hw/virtio/virtio-net.h |  1 +
>  2 files changed, 91 insertions(+), 6 deletions(-)
> 
> diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
> index 53e1c326433..9b3a997d872 100644
> --- a/hw/net/virtio-net.c
> +++ b/hw/net/virtio-net.c
> @@ -42,6 +42,7 @@
>  #include "sysemu/sysemu.h"
>  #include "trace.h"
>  #include "monitor/qdev.h"
> +#include "monitor/monitor.h"
>  #include "hw/pci/pci_device.h"
>  #include "net_rx_pkt.h"
>  #include "hw/virtio/vhost.h"
> @@ -1305,14 +1306,96 @@ static void virtio_net_detach_epbf_rss(VirtIONet *n)
>  virtio_net_attach_ebpf_to_backend(n->nic, -1);
>  }
>  
> -static bool virtio_net_load_ebpf(VirtIONet *n)
> +static int virtio_net_get_ebpf_rss_fds(char *str, char *fds[], int nfds,
> +   Error **errp)
>  {
> -if (!virtio_net_attach_ebpf_to_backend(n->nic, -1)) {
> -/* backend does't support steering ebpf */
> -return false;
> +char *ptr = str;
> +char *cur = NULL;
> +size_t len = strlen(str);
> +int i = 0;
> +
> +for (; i < nfds && ptr < str + len;) {
> +cur = strchr(ptr, ':');
> +
> +if (cur == NULL) {
> +fds[i] = g_strdup(ptr);
> +} else {
> +fds[i] = g_strndup(ptr, cur - ptr);
> +}
> +
> +i++;
> +if (cur == NULL) {
> +break;
> +} else {
> +ptr = cur + 1;
> +}
> +}
> +
> +if (cur != NULL) {
> +/* the string contains more arguments */
> +error_setg(errp,
> +   "Too many eBPF file descriptors for RSS provided.");
> +} else if (i < nfds) {
> +error_setg(errp,
> +   "Not enough eBPF file descriptors for RSS were 
> provided.");
> +}
> +
> +return i;
> +}

This whole method could be replaced by a call to g_strsplit in
the caller
 

> +
> +static bool virtio_net_load_ebpf_fds(VirtIONet *n, Error **errp)
> +{
> +char *fds_strs[EBPF_RSS_MAX_FDS];

   g_autoptr(GStrv) fds_strs = g_strsplit(n->ebpf_rss_fds, ",", 0);

> +int fds[EBPF_RSS_MAX_FDS];

Left as uninitialized stack memory.

> +int nfds;
> +int ret = true;
> +int i = 0;
> +
> +ERRP_GUARD();
> +
> +nfds = virtio_net_get_ebpf_rss_fds(n->ebpf_rss_fds,
> +   fds_strs, EBPF_RSS_MAX_FDS, errp);
> +if (*errp) {
> +ret = false;
> +goto exit;
>  }

Replace with 

   if (g_strv_length(fds_strs) != EBPF_RSS_MAX_FDS) {
   error_setg(errp,
  "Expected %d file descriptors but got %d",
  EBPF_RSS_MAX_FDS, g_strv_length(fds_strs));
   return false;
   }

>  
> -return ebpf_rss_load(>ebpf_rss);
> +for (i = 0; i < nfds; i++) {
> +fds[i] = monitor_fd_param(monitor_cur(), fds_strs[i], errp);
> +if (*errp) {
> +ret = false;
> +goto exit;

This can break out of the loop before all elements in 'fds' are
initialized.

> +}
> +}
> +
> +ret = ebpf_rss_load_fds(>ebpf_rss, fds[0], fds[1], fds[2], fds[3]);
> +
> +exit:
> +if (!ret || *errp) {
> +for (i = 0; i < nfds; i++) {
> +close(fds[i]);
> +}
> +}

This now calls close() on uninitialized memory, killing
arbitary FDs QEMU has open elsewhere.

> +
> +for (i = 0; i < nfds; i++) {
> +g_free(fds_strs[i]);
> +}

Not required if we use g_autoptr(GStrv)

> +
> +return ret;
> +}
> +
> +static bool virtio_net_load_ebpf(VirtIONet *n, Error **errp)
> +{
> +bool ret = false;
> +
> +if (virtio_net_attach_ebpf_to_backend(n->nic, -1)) {
> +if (!(n->ebpf_rss_fds
> +&& virtio_net_load_ebpf_fds(n, errp))) {
> +ret = ebpf_rss_load(>ebpf_rss);
> +}
> +}
> +
> +return ret;
>  }
>  
>  static void virtio_net_unload_ebpf(VirtIONet *n)
> @@ -3738,7 +3821,7 @@ static void virtio_net_device_realize(DeviceState *dev, 
> Error **errp)
>  net_rx_pkt_init(>rx_pkt);
>  
>  if (virtio_has_feature(n->host_features, VIRTIO_NET_F_RSS)) {
> -virtio_net_load_ebpf(n);
> +virtio_net_load_ebpf(n, errp);
>  }
>  }
>  
> @@ -3900,6 +3983,7 @@ static Property virtio_net_properties[] = {
>  VIRTIO_NET_F_RSS, false),
>  DEFINE_PROP_BIT64("hash", VirtIONet, host_features,
>  VIRTIO_NET_F_HASH_REPORT, false),
> +DEFINE_PROP_STRING("ebpf_rss_fds", VirtIONet, ebpf_rss_fds),
>  DEFINE_PROP_BIT64("guest_rsc_ext", VirtIONet, host_features,
>  VIRTIO_NET_F_RSC_EXT, false),
>  

[PATCH 2/5] virtio-net: Added property to load eBPF RSS with fds.

2023-05-01 Thread Andrew Melnychenko
eBPF RSS program and maps may now be passed during initialization.
Initially was implemented for libvirt to launch qemu without permissions,
and initialized eBPF program through the helper.

Signed-off-by: Andrew Melnychenko 
---
 hw/net/virtio-net.c| 96 +++---
 include/hw/virtio/virtio-net.h |  1 +
 2 files changed, 91 insertions(+), 6 deletions(-)

diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
index 53e1c326433..9b3a997d872 100644
--- a/hw/net/virtio-net.c
+++ b/hw/net/virtio-net.c
@@ -42,6 +42,7 @@
 #include "sysemu/sysemu.h"
 #include "trace.h"
 #include "monitor/qdev.h"
+#include "monitor/monitor.h"
 #include "hw/pci/pci_device.h"
 #include "net_rx_pkt.h"
 #include "hw/virtio/vhost.h"
@@ -1305,14 +1306,96 @@ static void virtio_net_detach_epbf_rss(VirtIONet *n)
 virtio_net_attach_ebpf_to_backend(n->nic, -1);
 }
 
-static bool virtio_net_load_ebpf(VirtIONet *n)
+static int virtio_net_get_ebpf_rss_fds(char *str, char *fds[], int nfds,
+   Error **errp)
 {
-if (!virtio_net_attach_ebpf_to_backend(n->nic, -1)) {
-/* backend does't support steering ebpf */
-return false;
+char *ptr = str;
+char *cur = NULL;
+size_t len = strlen(str);
+int i = 0;
+
+for (; i < nfds && ptr < str + len;) {
+cur = strchr(ptr, ':');
+
+if (cur == NULL) {
+fds[i] = g_strdup(ptr);
+} else {
+fds[i] = g_strndup(ptr, cur - ptr);
+}
+
+i++;
+if (cur == NULL) {
+break;
+} else {
+ptr = cur + 1;
+}
+}
+
+if (cur != NULL) {
+/* the string contains more arguments */
+error_setg(errp,
+   "Too many eBPF file descriptors for RSS provided.");
+} else if (i < nfds) {
+error_setg(errp,
+   "Not enough eBPF file descriptors for RSS were provided.");
+}
+
+return i;
+}
+
+static bool virtio_net_load_ebpf_fds(VirtIONet *n, Error **errp)
+{
+char *fds_strs[EBPF_RSS_MAX_FDS];
+int fds[EBPF_RSS_MAX_FDS];
+int nfds;
+int ret = true;
+int i = 0;
+
+ERRP_GUARD();
+
+nfds = virtio_net_get_ebpf_rss_fds(n->ebpf_rss_fds,
+   fds_strs, EBPF_RSS_MAX_FDS, errp);
+if (*errp) {
+ret = false;
+goto exit;
 }
 
-return ebpf_rss_load(>ebpf_rss);
+for (i = 0; i < nfds; i++) {
+fds[i] = monitor_fd_param(monitor_cur(), fds_strs[i], errp);
+if (*errp) {
+ret = false;
+goto exit;
+}
+}
+
+ret = ebpf_rss_load_fds(>ebpf_rss, fds[0], fds[1], fds[2], fds[3]);
+
+exit:
+if (!ret || *errp) {
+for (i = 0; i < nfds; i++) {
+close(fds[i]);
+}
+}
+
+for (i = 0; i < nfds; i++) {
+g_free(fds_strs[i]);
+}
+
+return ret;
+}
+
+static bool virtio_net_load_ebpf(VirtIONet *n, Error **errp)
+{
+bool ret = false;
+
+if (virtio_net_attach_ebpf_to_backend(n->nic, -1)) {
+if (!(n->ebpf_rss_fds
+&& virtio_net_load_ebpf_fds(n, errp))) {
+ret = ebpf_rss_load(>ebpf_rss);
+}
+}
+
+return ret;
 }
 
 static void virtio_net_unload_ebpf(VirtIONet *n)
@@ -3738,7 +3821,7 @@ static void virtio_net_device_realize(DeviceState *dev, 
Error **errp)
 net_rx_pkt_init(>rx_pkt);
 
 if (virtio_has_feature(n->host_features, VIRTIO_NET_F_RSS)) {
-virtio_net_load_ebpf(n);
+virtio_net_load_ebpf(n, errp);
 }
 }
 
@@ -3900,6 +3983,7 @@ static Property virtio_net_properties[] = {
 VIRTIO_NET_F_RSS, false),
 DEFINE_PROP_BIT64("hash", VirtIONet, host_features,
 VIRTIO_NET_F_HASH_REPORT, false),
+DEFINE_PROP_STRING("ebpf_rss_fds", VirtIONet, ebpf_rss_fds),
 DEFINE_PROP_BIT64("guest_rsc_ext", VirtIONet, host_features,
 VIRTIO_NET_F_RSC_EXT, false),
 DEFINE_PROP_UINT32("rsc_interval", VirtIONet, rsc_timeout,
diff --git a/include/hw/virtio/virtio-net.h b/include/hw/virtio/virtio-net.h
index ef234ffe7ef..e10ce88f918 100644
--- a/include/hw/virtio/virtio-net.h
+++ b/include/hw/virtio/virtio-net.h
@@ -219,6 +219,7 @@ struct VirtIONet {
 VirtioNetRssData rss_data;
 struct NetRxPkt *rx_pkt;
 struct EBPFRSSContext ebpf_rss;
+char *ebpf_rss_fds;
 };
 
 size_t virtio_net_handle_ctrl_iov(VirtIODevice *vdev,
-- 
2.39.1




Re: [RFC PATCH 2/5] virtio-net: Added property to load eBPF RSS with fds.

2023-03-30 Thread Daniel P . Berrangé
On Thu, Mar 30, 2023 at 03:15:19AM +0300, Andrew Melnychenko wrote:
> eBPF RSS program and maps may now be passed during initialization.
> Initially was implemented for libvirt to launch qemu without permissions,
> and initialized eBPF program through the helper.
> 
> Signed-off-by: Andrew Melnychenko 
> ---
>  hw/net/virtio-net.c| 77 --
>  include/hw/virtio/virtio-net.h |  1 +
>  2 files changed, 74 insertions(+), 4 deletions(-)
> 
> diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
> index 53e1c32643..45d448a83d 100644
> --- a/hw/net/virtio-net.c
> +++ b/hw/net/virtio-net.c
> @@ -42,6 +42,7 @@
>  #include "sysemu/sysemu.h"
>  #include "trace.h"
>  #include "monitor/qdev.h"
> +#include "monitor/monitor.h"
>  #include "hw/pci/pci_device.h"
>  #include "net_rx_pkt.h"
>  #include "hw/virtio/vhost.h"
> @@ -1305,14 +1306,81 @@ static void virtio_net_detach_epbf_rss(VirtIONet *n)
>  virtio_net_attach_ebpf_to_backend(n->nic, -1);
>  }
>  
> -static bool virtio_net_load_ebpf(VirtIONet *n)
> +static int virtio_net_get_ebpf_rss_fds(char *str, char *fds[], int nfds)

Needs to have an 'Error **errp' parameter

> +{
> +char *ptr = str;
> +char *cur = NULL;
> +size_t len = strlen(str);
> +int i = 0;
> +
> +for (; i < nfds && ptr < str + len;) {
> +cur = strchr(ptr, ':');
> +
> +if (cur == NULL) {
> +fds[i] = g_strdup(ptr);
> +} else {
> +fds[i] = g_strndup(ptr, cur - ptr);
> +}
> +
> +i++;
> +if (cur == NULL) {
> +break;
> +} else {
> +ptr = cur + 1;
> +}
> +}

...and here needs to error_setg(...) if the string being parsed has
more FDs present than 'nfds', and return error.

It should also report error if less than 'nfds' were present.

> +
> +return i;
> +}
> +
> +static bool virtio_net_load_ebpf_fds(VirtIONet *n)
>  {
> -if (!virtio_net_attach_ebpf_to_backend(n->nic, -1)) {
> -/* backend does't support steering ebpf */
> +char *fds_strs[EBPF_RSS_MAX_FDS];
> +int fds[EBPF_RSS_MAX_FDS];
> +int nfds;
> +int ret = false;
> +Error *errp;

This method should be having 'Error **errp' passed into it
instead

> +int i = 0;
> +
> +if (n == NULL || !n->ebpf_rss_fds) {
>  return false;
>  }

The only caller has already de-referenced 'n' so n == NULL is
impossible. The caller has also chck ebpf_rss_fds != NULL.
IOW, this is redundant

> -return ebpf_rss_load(>ebpf_rss);
> +nfds = virtio_net_get_ebpf_rss_fds(n->ebpf_rss_fds,
> +   fds_strs, EBPF_RSS_MAX_FDS);

Needs to pass in 'errp' and check for the error condition on return

  if (nfds != EBPF_RSS_MAX_FDS)
  return false;

> +for (i = 0; i < nfds; i++) {
> +fds[i] = monitor_fd_param(monitor_cur(), fds_strs[i], );

if (fds[i] < 0)
   close all FDs so far and return error...


> +}
> +
> +if (nfds == EBPF_RSS_MAX_FDS) {
> +ret = ebpf_rss_load_fds(>ebpf_rss, fds[0], fds[1], fds[2], 
> fds[3]);
> +}

This condition is not required, since we should have check
it immediately after the virtio_net_get_ebpf_rss_fds() call


> +
> +if (!ret) {
> +for (i = 0; i < nfds; i++) {
> +close(fds[i]);
> +}
> +}
> +
> +for (i = 0; i < nfds; i++) {
> +g_free(fds_strs[i]);
> +}
> +
> +return ret;
> +}
> +
> +static bool virtio_net_load_ebpf(VirtIONet *n)

This needs to have "Error **errp' added to it and return an
error on failure. The caller already has an 'errp' available
to pass in.

> +{
> +bool ret = true;
> +
> +if (virtio_net_attach_ebpf_to_backend(n->nic, -1)) {
> +if (!(n->ebpf_rss_fds
> +&& virtio_net_load_ebpf_fds(n))) {
> +ret = ebpf_rss_load(>ebpf_rss);
> +}
> +}
> +
> +return ret;
>  }
>  
>  static void virtio_net_unload_ebpf(VirtIONet *n)
> @@ -3900,6 +3968,7 @@ static Property virtio_net_properties[] = {
>  VIRTIO_NET_F_RSS, false),
>  DEFINE_PROP_BIT64("hash", VirtIONet, host_features,
>  VIRTIO_NET_F_HASH_REPORT, false),
> +DEFINE_PROP_STRING("ebpf_rss_fds", VirtIONet, ebpf_rss_fds),
>  DEFINE_PROP_BIT64("guest_rsc_ext", VirtIONet, host_features,
>  VIRTIO_NET_F_RSC_EXT, false),
>  DEFINE_PROP_UINT32("rsc_interval", VirtIONet, rsc_timeout,
> diff --git a/include/hw/virtio/virtio-net.h b/include/hw/virtio/virtio-net.h
> index ef234ffe7e..e10ce88f91 100644
> --- a/include/hw/virtio/virtio-net.h
> +++ b/include/hw/virtio/virtio-net.h
> @@ -219,6 +219,7 @@ struct VirtIONet {
>  VirtioNetRssData rss_data;
>  struct NetRxPkt *rx_pkt;
>  struct EBPFRSSContext ebpf_rss;
> +char *ebpf_rss_fds;
>  };
>  
>  size_t virtio_net_handle_ctrl_iov(VirtIODevice *vdev,
> -- 
> 2.39.1
> 

With regards,
Daniel
-- 
|: https://berrange.com  -o-

[RFC PATCH 2/5] virtio-net: Added property to load eBPF RSS with fds.

2023-03-29 Thread Andrew Melnychenko
eBPF RSS program and maps may now be passed during initialization.
Initially was implemented for libvirt to launch qemu without permissions,
and initialized eBPF program through the helper.

Signed-off-by: Andrew Melnychenko 
---
 hw/net/virtio-net.c| 77 --
 include/hw/virtio/virtio-net.h |  1 +
 2 files changed, 74 insertions(+), 4 deletions(-)

diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
index 53e1c32643..45d448a83d 100644
--- a/hw/net/virtio-net.c
+++ b/hw/net/virtio-net.c
@@ -42,6 +42,7 @@
 #include "sysemu/sysemu.h"
 #include "trace.h"
 #include "monitor/qdev.h"
+#include "monitor/monitor.h"
 #include "hw/pci/pci_device.h"
 #include "net_rx_pkt.h"
 #include "hw/virtio/vhost.h"
@@ -1305,14 +1306,81 @@ static void virtio_net_detach_epbf_rss(VirtIONet *n)
 virtio_net_attach_ebpf_to_backend(n->nic, -1);
 }
 
-static bool virtio_net_load_ebpf(VirtIONet *n)
+static int virtio_net_get_ebpf_rss_fds(char *str, char *fds[], int nfds)
+{
+char *ptr = str;
+char *cur = NULL;
+size_t len = strlen(str);
+int i = 0;
+
+for (; i < nfds && ptr < str + len;) {
+cur = strchr(ptr, ':');
+
+if (cur == NULL) {
+fds[i] = g_strdup(ptr);
+} else {
+fds[i] = g_strndup(ptr, cur - ptr);
+}
+
+i++;
+if (cur == NULL) {
+break;
+} else {
+ptr = cur + 1;
+}
+}
+
+return i;
+}
+
+static bool virtio_net_load_ebpf_fds(VirtIONet *n)
 {
-if (!virtio_net_attach_ebpf_to_backend(n->nic, -1)) {
-/* backend does't support steering ebpf */
+char *fds_strs[EBPF_RSS_MAX_FDS];
+int fds[EBPF_RSS_MAX_FDS];
+int nfds;
+int ret = false;
+Error *errp;
+int i = 0;
+
+if (n == NULL || !n->ebpf_rss_fds) {
 return false;
 }
 
-return ebpf_rss_load(>ebpf_rss);
+nfds = virtio_net_get_ebpf_rss_fds(n->ebpf_rss_fds,
+   fds_strs, EBPF_RSS_MAX_FDS);
+for (i = 0; i < nfds; i++) {
+fds[i] = monitor_fd_param(monitor_cur(), fds_strs[i], );
+}
+
+if (nfds == EBPF_RSS_MAX_FDS) {
+ret = ebpf_rss_load_fds(>ebpf_rss, fds[0], fds[1], fds[2], fds[3]);
+}
+
+if (!ret) {
+for (i = 0; i < nfds; i++) {
+close(fds[i]);
+}
+}
+
+for (i = 0; i < nfds; i++) {
+g_free(fds_strs[i]);
+}
+
+return ret;
+}
+
+static bool virtio_net_load_ebpf(VirtIONet *n)
+{
+bool ret = true;
+
+if (virtio_net_attach_ebpf_to_backend(n->nic, -1)) {
+if (!(n->ebpf_rss_fds
+&& virtio_net_load_ebpf_fds(n))) {
+ret = ebpf_rss_load(>ebpf_rss);
+}
+}
+
+return ret;
 }
 
 static void virtio_net_unload_ebpf(VirtIONet *n)
@@ -3900,6 +3968,7 @@ static Property virtio_net_properties[] = {
 VIRTIO_NET_F_RSS, false),
 DEFINE_PROP_BIT64("hash", VirtIONet, host_features,
 VIRTIO_NET_F_HASH_REPORT, false),
+DEFINE_PROP_STRING("ebpf_rss_fds", VirtIONet, ebpf_rss_fds),
 DEFINE_PROP_BIT64("guest_rsc_ext", VirtIONet, host_features,
 VIRTIO_NET_F_RSC_EXT, false),
 DEFINE_PROP_UINT32("rsc_interval", VirtIONet, rsc_timeout,
diff --git a/include/hw/virtio/virtio-net.h b/include/hw/virtio/virtio-net.h
index ef234ffe7e..e10ce88f91 100644
--- a/include/hw/virtio/virtio-net.h
+++ b/include/hw/virtio/virtio-net.h
@@ -219,6 +219,7 @@ struct VirtIONet {
 VirtioNetRssData rss_data;
 struct NetRxPkt *rx_pkt;
 struct EBPFRSSContext ebpf_rss;
+char *ebpf_rss_fds;
 };
 
 size_t virtio_net_handle_ctrl_iov(VirtIODevice *vdev,
-- 
2.39.1




[PATCH 2/5] virtio-net: Added property to load eBPF RSS with fds.

2023-02-19 Thread Andrew Melnychenko
eBPF RSS program and maps may now be passed during initialization.
Initially was implemented for libvirt to launch qemu without permissions,
and initialized eBPF program through the helper.

Signed-off-by: Andrew Melnychenko 
---
 hw/net/virtio-net.c| 77 --
 include/hw/virtio/virtio-net.h |  1 +
 2 files changed, 74 insertions(+), 4 deletions(-)

diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
index 3ae909041a..0ab2cf33f9 100644
--- a/hw/net/virtio-net.c
+++ b/hw/net/virtio-net.c
@@ -42,6 +42,7 @@
 #include "sysemu/sysemu.h"
 #include "trace.h"
 #include "monitor/qdev.h"
+#include "monitor/monitor.h"
 #include "hw/pci/pci_device.h"
 #include "net_rx_pkt.h"
 #include "hw/virtio/vhost.h"
@@ -1290,14 +1291,81 @@ static void virtio_net_detach_epbf_rss(VirtIONet *n)
 virtio_net_attach_ebpf_to_backend(n->nic, -1);
 }
 
-static bool virtio_net_load_ebpf(VirtIONet *n)
+static int virtio_net_get_ebpf_rss_fds(char *str, char *fds[], int nfds)
+{
+char *ptr = str;
+char *cur = NULL;
+size_t len = strlen(str);
+int i = 0;
+
+for (; i < nfds && ptr < str + len;) {
+cur = strchr(ptr, ':');
+
+if (cur == NULL) {
+fds[i] = g_strdup(ptr);
+} else {
+fds[i] = g_strndup(ptr, cur - ptr);
+}
+
+i++;
+if (cur == NULL) {
+break;
+} else {
+ptr = cur + 1;
+}
+}
+
+return i;
+}
+
+static bool virtio_net_load_ebpf_fds(VirtIONet *n)
 {
-if (!virtio_net_attach_ebpf_to_backend(n->nic, -1)) {
-/* backend does't support steering ebpf */
+char *fds_strs[EBPF_RSS_MAX_FDS];
+int fds[EBPF_RSS_MAX_FDS];
+int nfds;
+int ret = false;
+Error *errp;
+int i = 0;
+
+if (n == NULL || !n->ebpf_rss_fds) {
 return false;
 }
 
-return ebpf_rss_load(>ebpf_rss);
+nfds = virtio_net_get_ebpf_rss_fds(n->ebpf_rss_fds,
+   fds_strs, EBPF_RSS_MAX_FDS);
+for (i = 0; i < nfds; i++) {
+fds[i] = monitor_fd_param(monitor_cur(), fds_strs[i], );
+}
+
+if (nfds == EBPF_RSS_MAX_FDS) {
+ret = ebpf_rss_load_fds(>ebpf_rss, fds[0], fds[1], fds[2], fds[3]);
+}
+
+if (!ret) {
+for (i = 0; i < nfds; i++) {
+close(fds[i]);
+}
+}
+
+for (i = 0; i < nfds; i++) {
+g_free(fds_strs[i]);
+}
+
+return ret;
+}
+
+static bool virtio_net_load_ebpf(VirtIONet *n)
+{
+bool ret = true;
+
+if (virtio_net_attach_ebpf_to_backend(n->nic, -1)) {
+if (!(n->ebpf_rss_fds
+&& virtio_net_load_ebpf_fds(n))) {
+ret = ebpf_rss_load(>ebpf_rss);
+}
+}
+
+return ret;
 }
 
 static void virtio_net_unload_ebpf(VirtIONet *n)
@@ -3868,6 +3936,7 @@ static Property virtio_net_properties[] = {
 VIRTIO_NET_F_RSS, false),
 DEFINE_PROP_BIT64("hash", VirtIONet, host_features,
 VIRTIO_NET_F_HASH_REPORT, false),
+DEFINE_PROP_STRING("ebpf_rss_fds", VirtIONet, ebpf_rss_fds),
 DEFINE_PROP_BIT64("guest_rsc_ext", VirtIONet, host_features,
 VIRTIO_NET_F_RSC_EXT, false),
 DEFINE_PROP_UINT32("rsc_interval", VirtIONet, rsc_timeout,
diff --git a/include/hw/virtio/virtio-net.h b/include/hw/virtio/virtio-net.h
index ef234ffe7e..e10ce88f91 100644
--- a/include/hw/virtio/virtio-net.h
+++ b/include/hw/virtio/virtio-net.h
@@ -219,6 +219,7 @@ struct VirtIONet {
 VirtioNetRssData rss_data;
 struct NetRxPkt *rx_pkt;
 struct EBPFRSSContext ebpf_rss;
+char *ebpf_rss_fds;
 };
 
 size_t virtio_net_handle_ctrl_iov(VirtIODevice *vdev,
-- 
2.39.1




Re: [PATCH 2/5] virtio-net: Added property to load eBPF RSS with fds.

2021-08-25 Thread Andrew Melnichenko
Hi,

> I wonder if it's better to use separated properties instead of implying
> an order here?
>
Not really, technically RSS BPF interface may be changed (it's already
changed after RFC).
And libvirt should use something unified, so it's better to use fd array.
If any changes occur - those changes will be applied only for qemu and the
helper.
Also, now all maps are combined in one configuration map.

On Fri, Aug 20, 2021 at 6:36 AM Jason Wang  wrote:

>
> 在 2021/7/13 下午11:37, Andrew Melnychenko 写道:
> > eBPF RSS program and maps now may be passed during initialization.
> > Initially was implemented for libvirt to launch qemu without permissions.
> >
> > Signed-off-by: Andrew Melnychenko 
> > ---
> >   hw/net/virtio-net.c| 77 --
> >   include/hw/virtio/virtio-net.h |  1 +
> >   2 files changed, 74 insertions(+), 4 deletions(-)
> >
> > diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
> > index bd7958b9f0..0602b1772e 100644
> > --- a/hw/net/virtio-net.c
> > +++ b/hw/net/virtio-net.c
> > @@ -41,6 +41,7 @@
> >   #include "sysemu/sysemu.h"
> >   #include "trace.h"
> >   #include "monitor/qdev.h"
> > +#include "monitor/monitor.h"
> >   #include "hw/pci/pci.h"
> >   #include "net_rx_pkt.h"
> >   #include "hw/virtio/vhost.h"
> > @@ -1223,14 +1224,81 @@ static void virtio_net_detach_epbf_rss(VirtIONet
> *n)
> >   virtio_net_attach_ebpf_to_backend(n->nic, -1);
> >   }
> >
> > -static bool virtio_net_load_ebpf(VirtIONet *n)
> > +static int virtio_net_get_ebpf_rss_fds(char *str, char *fds[], int nfds)
> >   {
> > -if (!virtio_net_attach_ebpf_to_backend(n->nic, -1)) {
> > -/* backend does't support steering ebpf */
> > +char *ptr = str;
> > +char *cur = NULL;
> > +size_t len = strlen(str);
> > +int i = 0;
> > +
> > +for (; i < nfds && ptr < str + len;) {
> > +cur = strchr(ptr, ':');
> > +
> > +if (cur == NULL) {
> > +fds[i] = g_strdup(ptr);
> > +} else {
> > +fds[i] = g_strndup(ptr, cur - ptr);
> > +}
> > +
> > +i++;
> > +if (cur == NULL) {
> > +break;
> > +} else {
> > +ptr = cur + 1;
> > +}
> > +}
> > +
> > +return i;
> > +}
> > +
> > +static bool virtio_net_load_ebpf_fds(VirtIONet *n)
> > +{
> > +char *fds_strs[EBPF_RSS_MAX_FDS];
> > +int fds[EBPF_RSS_MAX_FDS];
> > +int nfds;
> > +int ret = false;
> > +Error *errp;
> > +int i = 0;
> > +
> > +if (n == NULL || !n->ebpf_rss_fds) {
> >   return false;
> >   }
> >
> > -return ebpf_rss_load(>ebpf_rss);
> > +nfds = virtio_net_get_ebpf_rss_fds(n->ebpf_rss_fds,
> > +   fds_strs, EBPF_RSS_MAX_FDS);
> > +for (i = 0; i < nfds; i++) {
> > +fds[i] = monitor_fd_param(monitor_cur(), fds_strs[i], );
> > +}
> > +
> > +if (nfds == EBPF_RSS_MAX_FDS) {
> > +ret = ebpf_rss_load_fds(>ebpf_rss, fds[0], fds[1], fds[2],
> fds[3]);
> > +}
> > +
> > +if (!ret) {
> > +for (i = 0; i < nfds; i++) {
> > +close(fds[i]);
> > +}
> > +}
> > +
> > +for (i = 0; i < nfds; i++) {
> > +g_free(fds_strs[i]);
> > +}
> > +
> > +return ret;
> > +}
> > +
> > +static bool virtio_net_load_ebpf(VirtIONet *n)
> > +{
> > +bool ret = true;
> > +
> > +if (virtio_net_attach_ebpf_to_backend(n->nic, -1)) {
> > +if (!(n->ebpf_rss_fds
> > +&& virtio_net_load_ebpf_fds(n))) {
> > +ret = ebpf_rss_load(>ebpf_rss);
> > +}
> > +}
> > +
> > +return ret;
> >   }
> >
> >   static void virtio_net_unload_ebpf(VirtIONet *n)
> > @@ -3605,6 +3673,7 @@ static Property virtio_net_properties[] = {
> >   VIRTIO_NET_F_RSS, false),
> >   DEFINE_PROP_BIT64("hash", VirtIONet, host_features,
> >   VIRTIO_NET_F_HASH_REPORT, false),
> > +DEFINE_PROP_STRING("ebpf_rss_fds", VirtIONet, ebpf_rss_fds),
> >   DEFINE_PROP_BIT64("guest_rsc_ext", VirtIONet, host_features,
> >   VIRTIO_NET_F_RSC_EXT, false),
> >   DEFINE_PROP_UINT32("rsc_interval", VirtIONet, rsc_timeout,
> > diff --git a/include/hw/virtio/virtio-net.h
> b/include/hw/virtio/virtio-net.h
> > index 824a69c23f..993f2f3036 100644
> > --- a/include/hw/virtio/virtio-net.h
> > +++ b/include/hw/virtio/virtio-net.h
> > @@ -213,6 +213,7 @@ struct VirtIONet {
> >   VirtioNetRssData rss_data;
> >   struct NetRxPkt *rx_pkt;
> >   struct EBPFRSSContext ebpf_rss;
> > +char *ebpf_rss_fds;
>
>
> I wonder if it's better to use separated properties instead of implying
> an order here?
>
> E.g "program_fd", "key_map_fd", "indirection_table_map_fd" etc.
>
> Thanks
>
>
> >   };
> >
> >   void virtio_net_set_netclient_name(VirtIONet *n, const char *name,
>
>


Re: [PATCH 2/5] virtio-net: Added property to load eBPF RSS with fds.

2021-08-19 Thread Jason Wang



在 2021/7/13 下午11:37, Andrew Melnychenko 写道:

eBPF RSS program and maps now may be passed during initialization.
Initially was implemented for libvirt to launch qemu without permissions.

Signed-off-by: Andrew Melnychenko 
---
  hw/net/virtio-net.c| 77 --
  include/hw/virtio/virtio-net.h |  1 +
  2 files changed, 74 insertions(+), 4 deletions(-)

diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
index bd7958b9f0..0602b1772e 100644
--- a/hw/net/virtio-net.c
+++ b/hw/net/virtio-net.c
@@ -41,6 +41,7 @@
  #include "sysemu/sysemu.h"
  #include "trace.h"
  #include "monitor/qdev.h"
+#include "monitor/monitor.h"
  #include "hw/pci/pci.h"
  #include "net_rx_pkt.h"
  #include "hw/virtio/vhost.h"
@@ -1223,14 +1224,81 @@ static void virtio_net_detach_epbf_rss(VirtIONet *n)
  virtio_net_attach_ebpf_to_backend(n->nic, -1);
  }
  
-static bool virtio_net_load_ebpf(VirtIONet *n)

+static int virtio_net_get_ebpf_rss_fds(char *str, char *fds[], int nfds)
  {
-if (!virtio_net_attach_ebpf_to_backend(n->nic, -1)) {
-/* backend does't support steering ebpf */
+char *ptr = str;
+char *cur = NULL;
+size_t len = strlen(str);
+int i = 0;
+
+for (; i < nfds && ptr < str + len;) {
+cur = strchr(ptr, ':');
+
+if (cur == NULL) {
+fds[i] = g_strdup(ptr);
+} else {
+fds[i] = g_strndup(ptr, cur - ptr);
+}
+
+i++;
+if (cur == NULL) {
+break;
+} else {
+ptr = cur + 1;
+}
+}
+
+return i;
+}
+
+static bool virtio_net_load_ebpf_fds(VirtIONet *n)
+{
+char *fds_strs[EBPF_RSS_MAX_FDS];
+int fds[EBPF_RSS_MAX_FDS];
+int nfds;
+int ret = false;
+Error *errp;
+int i = 0;
+
+if (n == NULL || !n->ebpf_rss_fds) {
  return false;
  }
  
-return ebpf_rss_load(>ebpf_rss);

+nfds = virtio_net_get_ebpf_rss_fds(n->ebpf_rss_fds,
+   fds_strs, EBPF_RSS_MAX_FDS);
+for (i = 0; i < nfds; i++) {
+fds[i] = monitor_fd_param(monitor_cur(), fds_strs[i], );
+}
+
+if (nfds == EBPF_RSS_MAX_FDS) {
+ret = ebpf_rss_load_fds(>ebpf_rss, fds[0], fds[1], fds[2], fds[3]);
+}
+
+if (!ret) {
+for (i = 0; i < nfds; i++) {
+close(fds[i]);
+}
+}
+
+for (i = 0; i < nfds; i++) {
+g_free(fds_strs[i]);
+}
+
+return ret;
+}
+
+static bool virtio_net_load_ebpf(VirtIONet *n)
+{
+bool ret = true;
+
+if (virtio_net_attach_ebpf_to_backend(n->nic, -1)) {
+if (!(n->ebpf_rss_fds
+&& virtio_net_load_ebpf_fds(n))) {
+ret = ebpf_rss_load(>ebpf_rss);
+}
+}
+
+return ret;
  }
  
  static void virtio_net_unload_ebpf(VirtIONet *n)

@@ -3605,6 +3673,7 @@ static Property virtio_net_properties[] = {
  VIRTIO_NET_F_RSS, false),
  DEFINE_PROP_BIT64("hash", VirtIONet, host_features,
  VIRTIO_NET_F_HASH_REPORT, false),
+DEFINE_PROP_STRING("ebpf_rss_fds", VirtIONet, ebpf_rss_fds),
  DEFINE_PROP_BIT64("guest_rsc_ext", VirtIONet, host_features,
  VIRTIO_NET_F_RSC_EXT, false),
  DEFINE_PROP_UINT32("rsc_interval", VirtIONet, rsc_timeout,
diff --git a/include/hw/virtio/virtio-net.h b/include/hw/virtio/virtio-net.h
index 824a69c23f..993f2f3036 100644
--- a/include/hw/virtio/virtio-net.h
+++ b/include/hw/virtio/virtio-net.h
@@ -213,6 +213,7 @@ struct VirtIONet {
  VirtioNetRssData rss_data;
  struct NetRxPkt *rx_pkt;
  struct EBPFRSSContext ebpf_rss;
+char *ebpf_rss_fds;



I wonder if it's better to use separated properties instead of implying 
an order here?


E.g "program_fd", "key_map_fd", "indirection_table_map_fd" etc.

Thanks



  };
  
  void virtio_net_set_netclient_name(VirtIONet *n, const char *name,





[PATCH 2/5] virtio-net: Added property to load eBPF RSS with fds.

2021-07-13 Thread Andrew Melnychenko
eBPF RSS program and maps now may be passed during initialization.
Initially was implemented for libvirt to launch qemu without permissions.

Signed-off-by: Andrew Melnychenko 
---
 hw/net/virtio-net.c| 77 --
 include/hw/virtio/virtio-net.h |  1 +
 2 files changed, 74 insertions(+), 4 deletions(-)

diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
index bd7958b9f0..0602b1772e 100644
--- a/hw/net/virtio-net.c
+++ b/hw/net/virtio-net.c
@@ -41,6 +41,7 @@
 #include "sysemu/sysemu.h"
 #include "trace.h"
 #include "monitor/qdev.h"
+#include "monitor/monitor.h"
 #include "hw/pci/pci.h"
 #include "net_rx_pkt.h"
 #include "hw/virtio/vhost.h"
@@ -1223,14 +1224,81 @@ static void virtio_net_detach_epbf_rss(VirtIONet *n)
 virtio_net_attach_ebpf_to_backend(n->nic, -1);
 }
 
-static bool virtio_net_load_ebpf(VirtIONet *n)
+static int virtio_net_get_ebpf_rss_fds(char *str, char *fds[], int nfds)
 {
-if (!virtio_net_attach_ebpf_to_backend(n->nic, -1)) {
-/* backend does't support steering ebpf */
+char *ptr = str;
+char *cur = NULL;
+size_t len = strlen(str);
+int i = 0;
+
+for (; i < nfds && ptr < str + len;) {
+cur = strchr(ptr, ':');
+
+if (cur == NULL) {
+fds[i] = g_strdup(ptr);
+} else {
+fds[i] = g_strndup(ptr, cur - ptr);
+}
+
+i++;
+if (cur == NULL) {
+break;
+} else {
+ptr = cur + 1;
+}
+}
+
+return i;
+}
+
+static bool virtio_net_load_ebpf_fds(VirtIONet *n)
+{
+char *fds_strs[EBPF_RSS_MAX_FDS];
+int fds[EBPF_RSS_MAX_FDS];
+int nfds;
+int ret = false;
+Error *errp;
+int i = 0;
+
+if (n == NULL || !n->ebpf_rss_fds) {
 return false;
 }
 
-return ebpf_rss_load(>ebpf_rss);
+nfds = virtio_net_get_ebpf_rss_fds(n->ebpf_rss_fds,
+   fds_strs, EBPF_RSS_MAX_FDS);
+for (i = 0; i < nfds; i++) {
+fds[i] = monitor_fd_param(monitor_cur(), fds_strs[i], );
+}
+
+if (nfds == EBPF_RSS_MAX_FDS) {
+ret = ebpf_rss_load_fds(>ebpf_rss, fds[0], fds[1], fds[2], fds[3]);
+}
+
+if (!ret) {
+for (i = 0; i < nfds; i++) {
+close(fds[i]);
+}
+}
+
+for (i = 0; i < nfds; i++) {
+g_free(fds_strs[i]);
+}
+
+return ret;
+}
+
+static bool virtio_net_load_ebpf(VirtIONet *n)
+{
+bool ret = true;
+
+if (virtio_net_attach_ebpf_to_backend(n->nic, -1)) {
+if (!(n->ebpf_rss_fds
+&& virtio_net_load_ebpf_fds(n))) {
+ret = ebpf_rss_load(>ebpf_rss);
+}
+}
+
+return ret;
 }
 
 static void virtio_net_unload_ebpf(VirtIONet *n)
@@ -3605,6 +3673,7 @@ static Property virtio_net_properties[] = {
 VIRTIO_NET_F_RSS, false),
 DEFINE_PROP_BIT64("hash", VirtIONet, host_features,
 VIRTIO_NET_F_HASH_REPORT, false),
+DEFINE_PROP_STRING("ebpf_rss_fds", VirtIONet, ebpf_rss_fds),
 DEFINE_PROP_BIT64("guest_rsc_ext", VirtIONet, host_features,
 VIRTIO_NET_F_RSC_EXT, false),
 DEFINE_PROP_UINT32("rsc_interval", VirtIONet, rsc_timeout,
diff --git a/include/hw/virtio/virtio-net.h b/include/hw/virtio/virtio-net.h
index 824a69c23f..993f2f3036 100644
--- a/include/hw/virtio/virtio-net.h
+++ b/include/hw/virtio/virtio-net.h
@@ -213,6 +213,7 @@ struct VirtIONet {
 VirtioNetRssData rss_data;
 struct NetRxPkt *rx_pkt;
 struct EBPFRSSContext ebpf_rss;
+char *ebpf_rss_fds;
 };
 
 void virtio_net_set_netclient_name(VirtIONet *n, const char *name,
-- 
2.31.1




[RFC PATCH 2/5] virtio-net: Added property to load eBPF RSS with fds.

2021-06-09 Thread Andrew Melnychenko
eBPF RSS program and maps now may be passed during initialization.
Initially was implemented for libvirt to launch qemu without permissions.

Signed-off-by: Andrew Melnychenko 
---
 hw/net/virtio-net.c| 77 --
 include/hw/virtio/virtio-net.h |  1 +
 2 files changed, 74 insertions(+), 4 deletions(-)

diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
index bd7958b9f0..0602b1772e 100644
--- a/hw/net/virtio-net.c
+++ b/hw/net/virtio-net.c
@@ -41,6 +41,7 @@
 #include "sysemu/sysemu.h"
 #include "trace.h"
 #include "monitor/qdev.h"
+#include "monitor/monitor.h"
 #include "hw/pci/pci.h"
 #include "net_rx_pkt.h"
 #include "hw/virtio/vhost.h"
@@ -1223,14 +1224,81 @@ static void virtio_net_detach_epbf_rss(VirtIONet *n)
 virtio_net_attach_ebpf_to_backend(n->nic, -1);
 }
 
-static bool virtio_net_load_ebpf(VirtIONet *n)
+static int virtio_net_get_ebpf_rss_fds(char *str, char *fds[], int nfds)
 {
-if (!virtio_net_attach_ebpf_to_backend(n->nic, -1)) {
-/* backend does't support steering ebpf */
+char *ptr = str;
+char *cur = NULL;
+size_t len = strlen(str);
+int i = 0;
+
+for (; i < nfds && ptr < str + len;) {
+cur = strchr(ptr, ':');
+
+if (cur == NULL) {
+fds[i] = g_strdup(ptr);
+} else {
+fds[i] = g_strndup(ptr, cur - ptr);
+}
+
+i++;
+if (cur == NULL) {
+break;
+} else {
+ptr = cur + 1;
+}
+}
+
+return i;
+}
+
+static bool virtio_net_load_ebpf_fds(VirtIONet *n)
+{
+char *fds_strs[EBPF_RSS_MAX_FDS];
+int fds[EBPF_RSS_MAX_FDS];
+int nfds;
+int ret = false;
+Error *errp;
+int i = 0;
+
+if (n == NULL || !n->ebpf_rss_fds) {
 return false;
 }
 
-return ebpf_rss_load(>ebpf_rss);
+nfds = virtio_net_get_ebpf_rss_fds(n->ebpf_rss_fds,
+   fds_strs, EBPF_RSS_MAX_FDS);
+for (i = 0; i < nfds; i++) {
+fds[i] = monitor_fd_param(monitor_cur(), fds_strs[i], );
+}
+
+if (nfds == EBPF_RSS_MAX_FDS) {
+ret = ebpf_rss_load_fds(>ebpf_rss, fds[0], fds[1], fds[2], fds[3]);
+}
+
+if (!ret) {
+for (i = 0; i < nfds; i++) {
+close(fds[i]);
+}
+}
+
+for (i = 0; i < nfds; i++) {
+g_free(fds_strs[i]);
+}
+
+return ret;
+}
+
+static bool virtio_net_load_ebpf(VirtIONet *n)
+{
+bool ret = true;
+
+if (virtio_net_attach_ebpf_to_backend(n->nic, -1)) {
+if (!(n->ebpf_rss_fds
+&& virtio_net_load_ebpf_fds(n))) {
+ret = ebpf_rss_load(>ebpf_rss);
+}
+}
+
+return ret;
 }
 
 static void virtio_net_unload_ebpf(VirtIONet *n)
@@ -3605,6 +3673,7 @@ static Property virtio_net_properties[] = {
 VIRTIO_NET_F_RSS, false),
 DEFINE_PROP_BIT64("hash", VirtIONet, host_features,
 VIRTIO_NET_F_HASH_REPORT, false),
+DEFINE_PROP_STRING("ebpf_rss_fds", VirtIONet, ebpf_rss_fds),
 DEFINE_PROP_BIT64("guest_rsc_ext", VirtIONet, host_features,
 VIRTIO_NET_F_RSC_EXT, false),
 DEFINE_PROP_UINT32("rsc_interval", VirtIONet, rsc_timeout,
diff --git a/include/hw/virtio/virtio-net.h b/include/hw/virtio/virtio-net.h
index 824a69c23f..993f2f3036 100644
--- a/include/hw/virtio/virtio-net.h
+++ b/include/hw/virtio/virtio-net.h
@@ -213,6 +213,7 @@ struct VirtIONet {
 VirtioNetRssData rss_data;
 struct NetRxPkt *rx_pkt;
 struct EBPFRSSContext ebpf_rss;
+char *ebpf_rss_fds;
 };
 
 void virtio_net_set_netclient_name(VirtIONet *n, const char *name,
-- 
2.31.1