On 7/28/21 10:17 AM, Andrew Melnychenko wrote: > New function to call "qemu-ebpf-rss-helper". > The helper passes few fds through unix socket. > Technically libvirt should not be aware how many and what those fds. > The helper should return fds that should be passed to the qemu as is and in same order. > > Signed-off-by: Andrew Melnychenko <andrew@xxxxxxxxxx> > --- > src/qemu/qemu_interface.c | 54 +++++++++++++++++++++++++++++++++++++++ > src/qemu/qemu_interface.h | 2 ++ > 2 files changed, 56 insertions(+) > > diff --git a/src/qemu/qemu_interface.c b/src/qemu/qemu_interface.c > index ac0168c80d..76435af94e 100644 > --- a/src/qemu/qemu_interface.c > +++ b/src/qemu/qemu_interface.c > @@ -777,3 +777,57 @@ qemuInterfaceOpenVhostNet(virDomainDef *def, > > return -1; > } > + > + > +int qemuEbpfRssHelper(const char *helper, int *fds, int nfds) > +{ > + int ret = 0; > + int err = 0; > + int unix_fds[2] = { -1, -1 }; > + virCommand *cmd = NULL; If you'd use: g_autoptr(virCommand) cmd = NULL; then you can ditch that explicit virCommandFree() call below. > + > + if (!helper || !fds || !nfds) { > + return -1; > + } > + > + ret = socketpair(AF_UNIX, SOCK_STREAM, 0, unix_fds); > + if (ret) { > + virReportSystemError(errno, "%s", _("failed to create socket")); > + return -1; > + } > + > + cmd = virCommandNew(helper); > + if (cmd == NULL) { This can't really happen. Also, all virCommand* APIs are prepared for this situation so that we can write simpler code: cmd = virCommandNew(); virCommandSomething(cmd); virCommandSomethingElse(cmd); if (virCommandRunAsync(cmd) < 0) /* This is the point where we learn about any previous error */ > + VIR_FORCE_CLOSE(unix_fds[1]); > + ret = -1; > + goto cleanup; > + } > + virCommandAddArgFormat(cmd, "--fd=%d", unix_fds[1]); > + virCommandPassFD(cmd, unix_fds[1], VIR_COMMAND_PASS_FD_CLOSE_PARENT); > + virCommandDoAsyncIO(cmd); > + > + if (virCommandRunAsync(cmd, NULL) < 0) { > + VIR_FORCE_CLOSE(unix_fds[1]); This doesn't look right. Even in case of failure virCommandRun* should have closed all CLOSE_PARENT FDs. So this is effectively a double close. > + ret = -1; > + goto cleanup; > + } > + > + memset(fds, 0, sizeof(*fds) * nfds); > + > + ret = virSocketRecvMultipleFDs(unix_fds[0], fds, nfds, 0); > + > + if (virCommandWait(cmd, &err) < 0) { > + int i = 0; > + for (; i < ret; ++i) { > + if (fds[i]) { This check seems needless. After successful return from virSocketRecvMultipleFDs() the @fds array must be filled with only valid FDs. > + VIR_FORCE_CLOSE(fds[i]); > + } > + } > + ret = -1; > + } > + > +cleanup: > + VIR_FORCE_CLOSE(unix_fds[0]); > + virCommandFree(cmd); > + return ret; > +} > diff --git a/src/qemu/qemu_interface.h b/src/qemu/qemu_interface.h > index 438d548065..63d7590035 100644 > --- a/src/qemu/qemu_interface.h > +++ b/src/qemu/qemu_interface.h > @@ -61,3 +61,5 @@ int qemuInterfacePrepareSlirp(virQEMUDriver *driver, > qemuSlirp **slirp); > > int qemuInterfaceVDPAConnect(virDomainNetDef *net) G_GNUC_NO_INLINE; > + > +int qemuEbpfRssHelper(const char *helper, int *fds, int nfds); > Michal