enable VIR_DOMAIN_NET_TYPE_ETHERNET network support for ch guests. Tested with following interface config: <interface type='ethernet'> <target dev='chtap0' managed="yes"/> <model type='virtio'/> <driver queues='2'/> <interface> Signed-off-by: Praveen K Paladugu <prapal@xxxxxxxxxxxxxxxxxxx> --- po/POTFILES | 1 + src/ch/ch_conf.h | 4 + src/ch/ch_domain.c | 41 +++++++++ src/ch/ch_domain.h | 3 + src/ch/ch_interface.c | 104 +++++++++++++++++++++ src/ch/ch_interface.h | 35 ++++++++ src/ch/ch_monitor.c | 205 +++++++++++++++--------------------------- src/ch/ch_monitor.h | 7 +- src/ch/ch_process.c | 160 ++++++++++++++++++++++++++++++++- src/ch/meson.build | 2 + 10 files changed, 424 insertions(+), 138 deletions(-) create mode 100644 src/ch/ch_interface.c create mode 100644 src/ch/ch_interface.h diff --git a/po/POTFILES b/po/POTFILES index b594a8dd39..e48b9023e2 100644 --- a/po/POTFILES +++ b/po/POTFILES @@ -21,6 +21,7 @@ src/bhyve/bhyve_process.c src/ch/ch_conf.c src/ch/ch_domain.c src/ch/ch_driver.c +src/ch/ch_interface.c src/ch/ch_monitor.c src/ch/ch_process.c src/conf/backup_conf.c diff --git a/src/ch/ch_conf.h b/src/ch/ch_conf.h index 5b9b42540d..579eca894e 100644 --- a/src/ch/ch_conf.h +++ b/src/ch/ch_conf.h @@ -23,6 +23,7 @@ #include "virdomainobjlist.h" #include "virthread.h" #include "ch_capabilities.h" +#include "virebtables.h" #define CH_DRIVER_NAME "CH" #define CH_CMD "cloud-hypervisor" @@ -75,6 +76,9 @@ struct _virCHDriver /* pid file FD, ensures two copies of the driver can't use the same root */ int lockFD; + + /* Immutable pointer, lockless APIs. Pointless abstraction */ + ebtablesContext *ebtables; }; virCaps *virCHDriverCapsInit(void); diff --git a/src/ch/ch_domain.c b/src/ch/ch_domain.c index c0d6c75b1d..2bf29d9f0a 100644 --- a/src/ch/ch_domain.c +++ b/src/ch/ch_domain.c @@ -22,6 +22,7 @@ #include "ch_domain.h" #include "domain_driver.h" +#include "domain_validate.h" #include "virchrdev.h" #include "virlog.h" #include "virtime.h" @@ -355,3 +356,43 @@ virCHDomainObjFromDomain(virDomainPtr domain) return vm; } + +int +virCHDomainValidateActualNetDef(virDomainNetDef *net) +{ + virDomainNetType actualType = virDomainNetGetActualType(net); + + /* hypervisor-agnostic validation */ + if (virDomainActualNetDefValidate(net) < 0) + return -1; + + /* ch specific validation */ + switch (actualType) { + case VIR_DOMAIN_NET_TYPE_ETHERNET: + if (net->guestIP.nips > 1) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("ethernet type supports a single guest ip")); + return -1; + } + break; + case VIR_DOMAIN_NET_TYPE_VHOSTUSER: + case VIR_DOMAIN_NET_TYPE_BRIDGE: + case VIR_DOMAIN_NET_TYPE_NETWORK: + case VIR_DOMAIN_NET_TYPE_DIRECT: + case VIR_DOMAIN_NET_TYPE_USER: + case VIR_DOMAIN_NET_TYPE_SERVER: + case VIR_DOMAIN_NET_TYPE_CLIENT: + case VIR_DOMAIN_NET_TYPE_MCAST: + case VIR_DOMAIN_NET_TYPE_INTERNAL: + case VIR_DOMAIN_NET_TYPE_HOSTDEV: + case VIR_DOMAIN_NET_TYPE_UDP: + case VIR_DOMAIN_NET_TYPE_VDPA: + case VIR_DOMAIN_NET_TYPE_NULL: + case VIR_DOMAIN_NET_TYPE_VDS: + case VIR_DOMAIN_NET_TYPE_LAST: + default: + break; + } + + return 0; +} diff --git a/src/ch/ch_domain.h b/src/ch/ch_domain.h index 4990914e9f..8dea2b2123 100644 --- a/src/ch/ch_domain.h +++ b/src/ch/ch_domain.h @@ -75,3 +75,6 @@ virCHDomainGetMachineName(virDomainObj *vm); virDomainObj * virCHDomainObjFromDomain(virDomainPtr domain); + +int +virCHDomainValidateActualNetDef(virDomainNetDef *net); diff --git a/src/ch/ch_interface.c b/src/ch/ch_interface.c new file mode 100644 index 0000000000..61976b073f --- /dev/null +++ b/src/ch/ch_interface.c @@ -0,0 +1,104 @@ +/* + * Copyright Microsoft Corp. 2023 + * + * ch_interface.c: methods to connect guest interfaces to appropriate host + * backends + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * <http://www.gnu.org/licenses/>. + */ + +#include <config.h> + +#include "domain_conf.h" +#include "domain_interface.h" +#include "virebtables.h" +#include "viralloc.h" +#include "ch_interface.h" +#include "virjson.h" +#include "virlog.h" + + +#define VIR_FROM_THIS VIR_FROM_CH + +VIR_LOG_INIT("ch.ch_interface"); + +/** + * virCHConnetNetworkInterfaces: + * @driver: pointer to ch driver object + * @vm: pointer to domain definition + * @net: pointer to a guest net + * @nicindexes: returned array of FDs of guest interfaces + * @nnicindexes: returned number of guest interfaces + * + * + * Returns 0 on success, -1 on error. + */ + +int +virCHConnetNetworkInterfaces(virCHDriver *driver, + virDomainDef *vm, + virDomainNetDef *net, + int *tapfds, + int **nicindexes, + size_t *nnicindexes) +{ + + virDomainNetType actualType = virDomainNetGetActualType(net); + + + switch (actualType) { + case VIR_DOMAIN_NET_TYPE_ETHERNET: + + if (virDomainInterfaceEthernetConnect(vm, net, driver->ebtables, false, + driver->privileged, tapfds, + net->driver.virtio.queues) < 0) + return -1; + + G_GNUC_FALLTHROUGH; + case VIR_DOMAIN_NET_TYPE_NETWORK: + case VIR_DOMAIN_NET_TYPE_BRIDGE: + case VIR_DOMAIN_NET_TYPE_DIRECT: + { + if (nicindexes && nnicindexes && net->ifname) { + int nicindex = 0; + + if (virNetDevGetIndex(net->ifname, &nicindex) < 0) + return -1; + + VIR_APPEND_ELEMENT(*nicindexes, *nnicindexes, nicindex); + } + + break; + } + case VIR_DOMAIN_NET_TYPE_USER: + case VIR_DOMAIN_NET_TYPE_SERVER: + case VIR_DOMAIN_NET_TYPE_CLIENT: + case VIR_DOMAIN_NET_TYPE_MCAST: + case VIR_DOMAIN_NET_TYPE_VHOSTUSER: + case VIR_DOMAIN_NET_TYPE_INTERNAL: + case VIR_DOMAIN_NET_TYPE_HOSTDEV: + case VIR_DOMAIN_NET_TYPE_UDP: + case VIR_DOMAIN_NET_TYPE_VDPA: + case VIR_DOMAIN_NET_TYPE_NULL: + case VIR_DOMAIN_NET_TYPE_VDS: + case VIR_DOMAIN_NET_TYPE_LAST: + default: + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("Unsupported Network type %1$d"), actualType); + return -1; + } + + return 0; +} diff --git a/src/ch/ch_interface.h b/src/ch/ch_interface.h new file mode 100644 index 0000000000..21d4b52c93 --- /dev/null +++ b/src/ch/ch_interface.h @@ -0,0 +1,35 @@ +/* + * Copyright Microsoft Corp. 2023 + * + * ch_interface.c: methods to connect guest interfaces to appropriate host + * backends + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * <http://www.gnu.org/licenses/>. + */ + +#pragma once + + +#include "ch_conf.h" +#include "virconftypes.h" + + +int +virCHConnetNetworkInterfaces( virCHDriver *driver, + virDomainDef *vmdef, + virDomainNetDef *netdef, + int *tapfds, + int **nicindexes, + size_t *nnicindexes); diff --git a/src/ch/ch_monitor.c b/src/ch/ch_monitor.c index 6f960c3a51..03470bf50f 100644 --- a/src/ch/ch_monitor.c +++ b/src/ch/ch_monitor.c @@ -24,7 +24,11 @@ #include <unistd.h> #include <curl/curl.h> +#include "datatypes.h" +#include "ch_conf.h" +#include "ch_interface.h" #include "ch_monitor.h" +#include "domain_interface.h" #include "viralloc.h" #include "vircommand.h" #include "virerror.h" @@ -258,148 +262,98 @@ virCHMonitorBuildDisksJson(virJSONValue *content, virDomainDef *vmdef) return 0; } -static int -virCHMonitorBuildNetJson(virJSONValue *nets, - virDomainNetDef *netdef, - size_t *nnicindexes, - int **nicindexes) -{ - virDomainNetType netType = virDomainNetGetActualType(netdef); - char macaddr[VIR_MAC_STRING_BUFLEN]; - g_autoptr(virJSONValue) net = NULL; - // check net type at first - net = virJSONValueNewObject(); - - switch (netType) { - case VIR_DOMAIN_NET_TYPE_ETHERNET: - if (netdef->guestIP.nips == 1) { - const virNetDevIPAddr *ip = netdef->guestIP.ips[0]; - g_autofree char *addr = NULL; - virSocketAddr netmask; - g_autofree char *netmaskStr = NULL; - - if (!(addr = virSocketAddrFormat(&ip->address))) - return -1; - if (virJSONValueObjectAppendString(net, "ip", addr) < 0) - return -1; - if (virSocketAddrPrefixToNetmask(ip->prefix, &netmask, AF_INET) < 0) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Failed to translate net prefix %1$d to netmask"), - ip->prefix); - return -1; - } - if (!(netmaskStr = virSocketAddrFormat(&netmask))) - return -1; - if (virJSONValueObjectAppendString(net, "mask", netmaskStr) < 0) - return -1; - } else if (netdef->guestIP.nips > 1) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("ethernet type supports a single guest ip")); - } - /* network and bridge use a tap device, and direct uses a - * macvtap device - */ - if (nicindexes && nnicindexes && netdef->ifname) { - int nicindex = 0; +/** + * virCHMonitorBuildNetJson: + * @net: pointer to a guest network definition + * @jsonstr: returned network json + * + * Build net json to send to ch + * Returns 0 on success or -1 in case of error + */ +int +virCHMonitorBuildNetJson(virDomainNetDef *net, char **jsonstr) +{ + char macaddr[VIR_MAC_STRING_BUFLEN]; + g_autoptr(virJSONValue) net_json = virJSONValueNewObject(); + + virDomainNetType actualType = virDomainNetGetActualType(net); + + if (actualType == VIR_DOMAIN_NET_TYPE_ETHERNET) { + + /* + * else case for below is already checked in + * virCHDomainValidateActualNetDef. No need to check again. + */ + if (net->guestIP.nips == 1) { + const virNetDevIPAddr *ip = net->guestIP.ips[0]; + g_autofree char *addr = NULL; + virSocketAddr netmask; + g_autofree char *netmaskStr = NULL; + if (!(addr = virSocketAddrFormat(&ip->address))) + return -1; - if (virNetDevGetIndex(netdef->ifname, &nicindex) < 0) + if (virJSONValueObjectAppendString(net_json, "ip", addr) < 0) return -1; - - VIR_APPEND_ELEMENT(*nicindexes, *nnicindexes, nicindex); + if (virSocketAddrPrefixToNetmask(ip->prefix, &netmask, + AF_INET) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to translate net prefix %1$d to netmask"), + ip->prefix); + return -1; } - break; - case VIR_DOMAIN_NET_TYPE_VHOSTUSER: - if ((virDomainChrType)netdef->data.vhostuser->type != VIR_DOMAIN_CHR_TYPE_UNIX) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("vhost_user type support UNIX socket in this CH")); + if (!(netmaskStr = virSocketAddrFormat(&netmask))) return -1; - } else { - if (virJSONValueObjectAppendString(net, "vhost_socket", netdef->data.vhostuser->data.nix.path) < 0) - return -1; - if (virJSONValueObjectAppendBoolean(net, "vhost_user", true) < 0) + if (virJSONValueObjectAppendString(net_json, "mask", netmaskStr) < 0) return -1; - } - break; - case VIR_DOMAIN_NET_TYPE_BRIDGE: - case VIR_DOMAIN_NET_TYPE_NETWORK: - case VIR_DOMAIN_NET_TYPE_DIRECT: - case VIR_DOMAIN_NET_TYPE_USER: - case VIR_DOMAIN_NET_TYPE_SERVER: - case VIR_DOMAIN_NET_TYPE_CLIENT: - case VIR_DOMAIN_NET_TYPE_MCAST: - case VIR_DOMAIN_NET_TYPE_INTERNAL: - case VIR_DOMAIN_NET_TYPE_HOSTDEV: - case VIR_DOMAIN_NET_TYPE_UDP: - case VIR_DOMAIN_NET_TYPE_VDPA: - case VIR_DOMAIN_NET_TYPE_NULL: - case VIR_DOMAIN_NET_TYPE_VDS: - case VIR_DOMAIN_NET_TYPE_LAST: - default: - virReportEnumRangeError(virDomainNetType, netType); - return -1; - } - - if (netdef->ifname != NULL) { - if (virJSONValueObjectAppendString(net, "tap", netdef->ifname) < 0) - return -1; - } - if (virJSONValueObjectAppendString(net, "mac", virMacAddrFormat(&netdef->mac, macaddr)) < 0) - return -1; + } + + } + if (virJSONValueObjectAppendString(net_json, "mac", + virMacAddrFormat(&net->mac, macaddr)) < 0) + return -1; - if (netdef->virtio != NULL) { - if (netdef->virtio->iommu == VIR_TRISTATE_SWITCH_ON) { - if (virJSONValueObjectAppendBoolean(net, "iommu", true) < 0) + if (net->virtio != NULL) { + if (net->virtio->iommu == VIR_TRISTATE_SWITCH_ON) { + if (virJSONValueObjectAppendBoolean(net_json, "iommu", true) < 0) return -1; } } - if (netdef->driver.virtio.queues) { - if (virJSONValueObjectAppendNumberInt(net, "num_queues", netdef->driver.virtio.queues) < 0) + + /* Cloud-Hypervisor expects number of queues. 1 for rx and 1 for tx. + * Multiply queue pairs by 2 to provide total number of queues to CH + */ + if (net->driver.virtio.queues) { + if (virJSONValueObjectAppendNumberInt(net_json, "num_queues", + 2 * net->driver.virtio.queues) < 0) return -1; } - if (netdef->driver.virtio.rx_queue_size || netdef->driver.virtio.tx_queue_size) { - if (netdef->driver.virtio.rx_queue_size != netdef->driver.virtio.tx_queue_size) { + if (net->driver.virtio.rx_queue_size || net->driver.virtio.tx_queue_size) { + if (net->driver.virtio.rx_queue_size != + net->driver.virtio.tx_queue_size) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("virtio rx_queue_size option %1$d is not same with tx_queue_size %2$d"), - netdef->driver.virtio.rx_queue_size, - netdef->driver.virtio.tx_queue_size); + net->driver.virtio.rx_queue_size, + net->driver.virtio.tx_queue_size); return -1; } - if (virJSONValueObjectAppendNumberInt(net, "queue_size", netdef->driver.virtio.rx_queue_size) < 0) + if (virJSONValueObjectAppendNumberInt(net_json, + "queue_size", net->driver.virtio.rx_queue_size) < 0) return -1; } - if (virJSONValueArrayAppend(nets, &net) < 0) - return -1; - - return 0; -} - -static int -virCHMonitorBuildNetsJson(virJSONValue *content, - virDomainDef *vmdef, - size_t *nnicindexes, - int **nicindexes) -{ - g_autoptr(virJSONValue) nets = NULL; - size_t i; - - if (vmdef->nnets > 0) { - nets = virJSONValueNewArray(); - - for (i = 0; i < vmdef->nnets; i++) { - if (virCHMonitorBuildNetJson(nets, vmdef->nets[i], - nnicindexes, nicindexes) < 0) - return -1; - } - if (virJSONValueObjectAppend(content, "net", &nets) < 0) + if (net->mtu) { + if (virJSONValueObjectAppendNumberInt(net_json, "mtu", net->mtu) < 0) return -1; } + if (!(*jsonstr = virJSONValueToString(net_json, false))) + return -1; + return 0; } @@ -456,11 +410,8 @@ virCHMonitorBuildDevicesJson(virJSONValue *content, } static int -virCHMonitorBuildVMJson(virCHDriver *driver, - virDomainDef *vmdef, - char **jsonstr, - size_t *nnicindexes, - int **nicindexes) +virCHMonitorBuildVMJson(virCHDriver *driver, virDomainDef *vmdef, + char **jsonstr) { g_autoptr(virJSONValue) content = virJSONValueNewObject(); @@ -490,10 +441,6 @@ virCHMonitorBuildVMJson(virCHDriver *driver, if (virCHMonitorBuildDisksJson(content, vmdef) < 0) return -1; - - if (virCHMonitorBuildNetsJson(content, vmdef, nnicindexes, nicindexes) < 0) - return -1; - if (virCHMonitorBuildDevicesJson(content, vmdef) < 0) return -1; @@ -877,10 +824,7 @@ virCHMonitorShutdownVMM(virCHMonitor *mon) } int -virCHMonitorCreateVM(virCHDriver *driver, - virCHMonitor *mon, - size_t *nnicindexes, - int **nicindexes) +virCHMonitorCreateVM(virCHDriver *driver, virCHMonitor *mon) { g_autofree char *url = NULL; int responseCode = 0; @@ -892,8 +836,7 @@ virCHMonitorCreateVM(virCHDriver *driver, headers = curl_slist_append(headers, "Accept: application/json"); headers = curl_slist_append(headers, "Content-Type: application/json"); - if (virCHMonitorBuildVMJson(driver, mon->vm->def, &payload, - nnicindexes, nicindexes) != 0) + if (virCHMonitorBuildVMJson(driver, mon->vm->def, &payload) != 0) return -1; VIR_WITH_OBJECT_LOCK_GUARD(mon) { diff --git a/src/ch/ch_monitor.h b/src/ch/ch_monitor.h index bbfa77cdff..47b4e7abbd 100644 --- a/src/ch/ch_monitor.h +++ b/src/ch/ch_monitor.h @@ -104,10 +104,7 @@ void virCHMonitorClose(virCHMonitor *mon); G_DEFINE_AUTOPTR_CLEANUP_FUNC(virCHMonitor, virCHMonitorClose); -int virCHMonitorCreateVM(virCHDriver *driver, - virCHMonitor *mon, - size_t *nnicindexes, - int **nicindexes); +int virCHMonitorCreateVM(virCHDriver *driver, virCHMonitor *mon); int virCHMonitorBootVM(virCHMonitor *mon); int virCHMonitorShutdownVM(virCHMonitor *mon); int virCHMonitorRebootVM(virCHMonitor *mon); @@ -123,3 +120,5 @@ size_t virCHMonitorGetThreadInfo(virCHMonitor *mon, bool refresh, virCHMonitorThreadInfo **threads); int virCHMonitorGetIOThreads(virCHMonitor *mon, virDomainIOThreadInfo ***iothreads); +int +virCHMonitorBuildNetJson(virDomainNetDef *netdef, char **jsonstr); diff --git a/src/ch/ch_process.c b/src/ch/ch_process.c index f3bb4a7280..c734d164a1 100644 --- a/src/ch/ch_process.c +++ b/src/ch/ch_process.c @@ -27,9 +27,13 @@ #include "ch_monitor.h" #include "ch_process.h" #include "domain_cgroup.h" +#include "domain_interface.h" #include "virerror.h" +#include "virfile.h" #include "virjson.h" #include "virlog.h" +#include "virstring.h" +#include "ch_interface.h" #define VIR_FROM_THIS VIR_FROM_CH @@ -448,13 +452,142 @@ virCHProcessSetupVcpus(virDomainObj *vm) 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, j, tapfd_len; + int mon_sockfd, http_res; + g_autofree int *tapfds = NULL; + g_autoptr(virJSONValue) net = NULL; + struct sockaddr_un server_addr; + g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER; + g_auto(virBuffer) http_headers = VIR_BUFFER_INITIALIZER; + int ret; + + if (!virBitmapIsBitSet(driver->chCaps, CH_MULTIFD_IN_ADDNET)) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Guest networking is not supported by this version of ch")); + return -1; + } + + mon_sockfd = socket(AF_UNIX, SOCK_STREAM, 0); + if (mon_sockfd < 0) { + virReportSystemError(errno, "%s", _("Failed to open a UNIX socket")); + return -1; + } + + memset(&server_addr, 0, sizeof(server_addr)); + server_addr.sun_family = AF_UNIX; + if (virStrcpyStatic(server_addr.sun_path, mon->socketpath) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("UNIX socket path '%1$s' too long"), mon->socketpath); + goto err; + } + + if (connect(mon_sockfd, (struct sockaddr *)&server_addr, + sizeof(server_addr)) == -1) { + virReportSystemError(errno, "%s", _("Failed to connect to mon socket")); + goto err; + } + + 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 char *payload = NULL; + 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")); + goto err; + } + + tapfds = g_new0(int, tapfd_len); + memset(tapfds, -1, (tapfd_len) * sizeof(*tapfds)); + + /* Connect Guest interfaces */ + if (virCHConnetNetworkInterfaces(driver, vmdef, vmdef->nets[i], tapfds, + nicindexes, nnicindexes) < 0) { + goto err; + } + + if (virCHMonitorBuildNetJson(vmdef->nets[i], &payload) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Failed to build net json")); + goto err; + } + + VIR_DEBUG("payload sent with net-add request to CH = %s", payload); + + virBufferAsprintf(&buf, "%s", virBufferCurrentContent(&http_headers)); + virBufferAsprintf(&buf, "Content-Length: %ld\r\n\r\n", strlen(payload)); + virBufferAsprintf(&buf, "%s", payload); + payload = virBufferContentAndReset(&buf); + + ret = virSocketSendMsgWithFDs(mon_sockfd, payload, tapfds, tapfd_len); + if (ret < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Failed to send net-add request to CH")); + goto err; + } + + /* Close sent tap fds in Libvirt, as they have been dup()ed in ch */ + for (j = 0; j < tapfd_len; j++) { + VIR_FORCE_CLOSE(tapfds[j]); + } + + /* Process the response from CH */ + http_res = virSocketRecvHttpResponse(mon_sockfd); + if (http_res < 0) { + VIR_ERROR(_("Failed while receiving response from CH")); + goto err; + } + if (http_res != 204 && http_res != 200) { + VIR_ERROR(_("Unexpected response from CH: %1$d"), http_res); + goto err; + } + } + + VIR_FORCE_CLOSE(mon_sockfd); + return 0; + + err: + VIR_FORCE_CLOSE(mon_sockfd); + return -1; +} + /** * virCHProcessStart: * @driver: pointer to driver structure * @vm: pointer to virtual machine structure * @reason: reason for switching vm to running state * - * Starts Cloud-Hypervisor listen on a local socket + * Starts Cloud-Hypervisor listening on a local socket * * Returns 0 on success or -1 in case of error */ @@ -483,8 +616,7 @@ virCHProcessStart(virCHDriver *driver, goto cleanup; } - if (virCHMonitorCreateVM(driver, priv->monitor, - &nnicindexes, &nicindexes) < 0) { + if (virCHMonitorCreateVM(driver, priv->monitor) < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("failed to create guest VM")); goto cleanup; @@ -495,6 +627,13 @@ virCHProcessStart(virCHDriver *driver, vm->def->id = vm->pid; priv->machineName = virCHDomainGetMachineName(vm); + if (chProcessAddNetworkDevices(driver, priv->monitor, vm->def, + &nicindexes, &nnicindexes) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Failed while adding guest interfaces")); + goto cleanup; + } + if (virDomainCgroupSetupCgroup("ch", vm, nnicindexes, nicindexes, &priv->cgroup, @@ -507,6 +646,10 @@ virCHProcessStart(virCHDriver *driver, if (virCHProcessInitCpuAffinity(vm) < 0) goto cleanup; + /* Bring up netdevs before starting CPUs */ + if (virDomainInterfaceStartDevices(vm->def) < 0) + return -1; + if (virCHMonitorBootVM(priv->monitor) < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("failed to boot guest VM")); @@ -552,6 +695,9 @@ virCHProcessStop(virCHDriver *driver G_GNUC_UNUSED, int ret; int retries = 0; virCHDomainObjPrivate *priv = vm->privateData; + virCHDriverConfig *cfg = virCHDriverGetConfig(driver); + virDomainDef *def = vm->def; + size_t i; VIR_DEBUG("Stopping VM name=%s pid=%d reason=%d", vm->def->name, (int)vm->pid, (int)reason); @@ -560,6 +706,14 @@ virCHProcessStop(virCHDriver *driver G_GNUC_UNUSED, g_clear_pointer(&priv->monitor, virCHMonitorClose); } + /* de-activate netdevs after stopping vm */ + ignore_value(virDomainInterfaceStopDevices(vm->def)); + + for (i = 0; i < def->nnets; i++) { + virDomainNetDef *net = def->nets[i]; + virDomainInterfaceDeleteDevice(def, net, false, cfg->stateDir); + } + retry: if ((ret = virDomainCgroupRemoveCgroup(vm, priv->cgroup, diff --git a/src/ch/meson.build b/src/ch/meson.build index 6c8bf9c43f..633966aac7 100644 --- a/src/ch/meson.build +++ b/src/ch/meson.build @@ -7,6 +7,8 @@ ch_driver_sources = [ 'ch_domain.h', 'ch_driver.c', 'ch_driver.h', + 'ch_interface.c', + 'ch_interface.h', 'ch_monitor.c', 'ch_monitor.h', 'ch_process.c', -- 2.41.0 _______________________________________________ Devel mailing list -- devel@xxxxxxxxxxxxxxxxx To unsubscribe send an email to devel-leave@xxxxxxxxxxxxxxxxx