From 92441ba35ac95fb296f0209a2eafdd0fc9a312d7 Mon Sep 17 00:00:00 2001 From: Stefan Kober Date: Mon, 6 Oct 2025 17:18:09 +0200 Subject: [PATCH] ch: implement network device hot attach On-behalf-of: SAP stefan.kober@sap.com Signed-off-by: Stefan Kober Signed-off-by: Michal Privoznik Reviewed-by: Michal Privoznik --- src/ch/ch_hotplug.c | 12 ++++ src/ch/ch_monitor.c | 5 +- src/ch/ch_monitor.h | 1 - src/ch/ch_process.c | 163 +++++++++++++++++++++++++------------------- src/ch/ch_process.h | 8 +++ 5 files changed, 113 insertions(+), 76 deletions(-) diff --git a/src/ch/ch_hotplug.c b/src/ch/ch_hotplug.c index b953fe4c6c..2494652561 100644 --- a/src/ch/ch_hotplug.c +++ b/src/ch/ch_hotplug.c @@ -21,6 +21,7 @@ #include "ch_hotplug.h" #include "ch_alias.h" #include "ch_domain.h" +#include "ch_process.h" #include "domain_event.h" #include "domain_validate.h" #include "virlog.h" @@ -73,6 +74,17 @@ chDomainAttachDeviceLive(virCHDriver *driver, break; case VIR_DOMAIN_DEVICE_NET: + if (chProcessAddNetworkDevice(driver, mon, vm->def, dev->data.net, + NULL, NULL) < 0) { + break; + } + + virDomainNetInsert(vm->def, dev->data.net); + alias = dev->data.net->info.alias; + dev->data.net = NULL; + ret = 0; + break; + case VIR_DOMAIN_DEVICE_LEASE: case VIR_DOMAIN_DEVICE_FS: case VIR_DOMAIN_DEVICE_INPUT: diff --git a/src/ch/ch_monitor.c b/src/ch/ch_monitor.c index 65dc89cfd1..46b31acc76 100644 --- a/src/ch/ch_monitor.c +++ b/src/ch/ch_monitor.c @@ -379,7 +379,6 @@ virCHMonitorBuildRngJson(virJSONValue *content, virDomainDef *vmdef) /** * virCHMonitorBuildNetJson: * @net: pointer to a guest network definition - * @netindex: index of the guest network definition * @jsonstr: returned network json * * Build net json to send to CH @@ -387,15 +386,13 @@ virCHMonitorBuildRngJson(virJSONValue *content, virDomainDef *vmdef) */ int virCHMonitorBuildNetJson(virDomainNetDef *net, - int netindex, char **jsonstr) { char macaddr[VIR_MAC_STRING_BUFLEN]; g_autoptr(virJSONValue) net_json = virJSONValueNewObject(); virDomainNetType actualType = virDomainNetGetActualType(net); - g_autofree char *id = g_strdup_printf("%s_%d", CH_NET_ID_PREFIX, netindex); - if (virJSONValueObjectAppendString(net_json, "id", id) < 0) + if (virJSONValueObjectAppendString(net_json, "id", net->info.alias) < 0) return -1; if (actualType == VIR_DOMAIN_NET_TYPE_ETHERNET && diff --git a/src/ch/ch_monitor.h b/src/ch/ch_monitor.h index e3fde06f88..a462630be0 100644 --- a/src/ch/ch_monitor.h +++ b/src/ch/ch_monitor.h @@ -138,7 +138,6 @@ int virCHMonitorGetIOThreads(virCHMonitor *mon, virDomainIOThreadInfo ***iothreads); int virCHMonitorBuildNetJson(virDomainNetDef *netdef, - int netindex, char **jsonstr); int virCHMonitorAddDisk(virCHMonitor* mon, diff --git a/src/ch/ch_process.c b/src/ch/ch_process.c index 54b21b0baf..a1f30f09e1 100644 --- a/src/ch/ch_process.c +++ b/src/ch/ch_process.c @@ -624,30 +624,24 @@ chCloseFDs(int *fds, size_t nfds) return 0; } -/** - * chProcessAddNetworkDevices: - * @driver: pointer to ch driver object - * @mon: pointer to the monitor object - * @vmdef: pointer to domain definition - * @nicindexes: returned array of FDs of guest interfaces - * @nnicindexes: returned number of network indexes - * - * Send tap fds to CH process via AddNet api. Capture the network indexes of - * guest interfaces in nicindexes. - * - * Returns 0 on success, -1 on error. - */ -static int -chProcessAddNetworkDevices(virCHDriver *driver, - virCHMonitor *mon, - virDomainDef *vmdef, - int **nicindexes, - size_t *nnicindexes) +int +chProcessAddNetworkDevice(virCHDriver *driver, + virCHMonitor *mon, + virDomainDef *vmdef, + virDomainNetDef *net, + int **nicindexes, + size_t *nnicindexes) { - size_t i; VIR_AUTOCLOSE mon_sockfd = -1; g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER; g_auto(virBuffer) http_headers = VIR_BUFFER_INITIALIZER; + g_autofree int *tapfds = NULL; + g_autofree char *payload = NULL; + g_autofree char *response = NULL; + size_t tapfd_len; + size_t payload_len; + int saved_errno; + int rc; if (!virBitmapIsBitSet(driver->chCaps, CH_MULTIFD_IN_ADDNET)) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", @@ -655,73 +649,100 @@ chProcessAddNetworkDevices(virCHDriver *driver, return -1; } - if ((mon_sockfd = chMonitorSocketConnect(mon)) < 0) + if ((mon_sockfd = chMonitorSocketConnect(mon)) < 0) { + VIR_WARN("chProcessAddNetworkDevices failed"); return -1; + } virBufferAddLit(&http_headers, "PUT /api/v1/vm.add-net HTTP/1.1\r\n"); virBufferAddLit(&http_headers, "Host: localhost\r\n"); virBufferAddLit(&http_headers, "Content-Type: application/json\r\n"); - for (i = 0; i < vmdef->nnets; i++) { - g_autofree int *tapfds = NULL; - g_autofree char *payload = NULL; - g_autofree char *response = NULL; - size_t tapfd_len; - size_t payload_len; - int saved_errno; - int rc; - - if (vmdef->nets[i]->driver.virtio.queues == 0) { - /* "queues" here refers to queue pairs. When 0, initialize - * queue pairs to 1. - */ - vmdef->nets[i]->driver.virtio.queues = 1; - } - tapfd_len = vmdef->nets[i]->driver.virtio.queues; - if (virCHDomainValidateActualNetDef(vmdef->nets[i]) < 0) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("net definition failed validation")); - return -1; - } + if (net->driver.virtio.queues == 0) { + /* "queues" here refers to queue pairs. When 0, initialize + * queue pairs to 1. + */ + net->driver.virtio.queues = 1; + } + tapfd_len = net->driver.virtio.queues; - tapfds = g_new0(int, tapfd_len); - memset(tapfds, -1, (tapfd_len) * sizeof(int)); + if (virCHDomainValidateActualNetDef(net) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("net definition failed validation")); + return -1; + } - /* Connect Guest interfaces */ - if (virCHConnetNetworkInterfaces(driver, vmdef, vmdef->nets[i], tapfds, - nicindexes, nnicindexes) < 0) - return -1; + tapfds = g_new0(int, tapfd_len); + memset(tapfds, -1, (tapfd_len) * sizeof(int)); - if (virCHMonitorBuildNetJson(vmdef->nets[i], i, &payload) < 0) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("Failed to build net json")); - return -1; - } + /* Connect Guest interfaces */ + if (virCHConnetNetworkInterfaces(driver, vmdef, net, tapfds, + nicindexes, nnicindexes) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Failed to connect network interfaces")); + return -1; + } - VIR_DEBUG("payload sent with net-add request to CH = %s", payload); + chAssignDeviceNetAlias(vmdef, net); + if (virCHMonitorBuildNetJson(net, &payload) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Failed to build net json")); + return -1; + } - virBufferAsprintf(&buf, "%s", virBufferCurrentContent(&http_headers)); - virBufferAsprintf(&buf, "Content-Length: %zu\r\n\r\n", strlen(payload)); - virBufferAsprintf(&buf, "%s", payload); - payload_len = virBufferUse(&buf); - payload = virBufferContentAndReset(&buf); + virBufferAsprintf(&buf, "%s", virBufferCurrentContent(&http_headers)); + virBufferAsprintf(&buf, "Content-Length: %zu\r\n\r\n", strlen(payload)); + virBufferAsprintf(&buf, "%s", payload); + payload_len = virBufferUse(&buf); + payload = virBufferContentAndReset(&buf); - rc = virSocketSendMsgWithFDs(mon_sockfd, payload, payload_len, - tapfds, tapfd_len); - saved_errno = errno; + rc = virSocketSendMsgWithFDs(mon_sockfd, payload, payload_len, + tapfds, tapfd_len); + saved_errno = errno; - /* Close sent tap fds in Libvirt, as they have been dup()ed in CH */ - chCloseFDs(tapfds, tapfd_len); + /* Close sent tap fds in Libvirt, as they have been dup()ed in CH */ + chCloseFDs(tapfds, tapfd_len); - if (rc < 0) { - virReportSystemError(saved_errno, "%s", - _("Failed to send net-add request to CH")); - return -1; - } + if (rc < 0) { + virReportSystemError(saved_errno, "%s", + _("Failed to send net-add request to CH")); + return -1; + } - if (chSocketProcessHttpResponse(mon_sockfd, true) < 0) - return -1; + if (chSocketProcessHttpResponse(mon_sockfd, true) < 0) + return -1; + + return 0; +} + +/** + * chProcessAddNetworkDevices: + * @driver: pointer to ch driver object + * @mon: pointer to the monitor object + * @vmdef: pointer to domain definition + * @nicindexes: returned array of FDs of guest interfaces + * @nnicindexes: returned number of network indexes + * + * Send tap fds to CH process via AddNet api. Capture the network indexes of + * guest interfaces in nicindexes. + * + * Returns 0 on success, -1 on error. + */ +static int +chProcessAddNetworkDevices(virCHDriver *driver, + virCHMonitor *mon, + virDomainDef *vmdef, + int **nicindexes, + size_t *nnicindexes) +{ + size_t i = 0; + + for (i = 0; i < vmdef->nnets; i++) { + if (chProcessAddNetworkDevice(driver, mon, vmdef, vmdef->nets[i], + nicindexes, nnicindexes) < 0) { + return -1; + } } return 0; diff --git a/src/ch/ch_process.h b/src/ch/ch_process.h index a22790bb5c..e9b1f559d9 100644 --- a/src/ch/ch_process.h +++ b/src/ch/ch_process.h @@ -41,3 +41,11 @@ int virCHProcessStartRestore(virCHDriver *driver, const char *from); int virCHProcessUpdateInfo(virDomainObj *vm); + +int +chProcessAddNetworkDevice(virCHDriver *driver, + virCHMonitor *mon, + virDomainDef *vmdef, + virDomainNetDef *net, + int **nicindexes, + size_t *nnicindexes); -- 2.47.3