From nobody Sun Feb 8 07:52:46 2026 Delivered-To: importer@patchew.org Received-SPF: none (zohomail.com: 8.43.85.245 is neither permitted nor denied by domain of lists.libvirt.org) client-ip=8.43.85.245; envelope-from=devel-bounces@lists.libvirt.org; helo=lists.libvirt.org; Authentication-Results: mx.zohomail.com; spf=none (zohomail.com: 8.43.85.245 is neither permitted nor denied by domain of lists.libvirt.org) smtp.mailfrom=devel-bounces@lists.libvirt.org; dmarc=fail(p=none dis=none) header.from=linux.microsoft.com Return-Path: Received: from lists.libvirt.org (lists.libvirt.org [8.43.85.245]) by mx.zohomail.com with SMTPS id 1701300488556990.6063587945433; Wed, 29 Nov 2023 15:28:08 -0800 (PST) Received: by lists.libvirt.org (Postfix, from userid 996) id DB1281ADE; Wed, 29 Nov 2023 18:28:07 -0500 (EST) Received: from lists.libvirt.org (localhost [IPv6:::1]) by lists.libvirt.org (Postfix) with ESMTP id 566511AFE; Wed, 29 Nov 2023 18:12:10 -0500 (EST) Received: by lists.libvirt.org (Postfix, from userid 996) id A1BAB1ACC; Wed, 29 Nov 2023 18:11:25 -0500 (EST) Received: from linux.microsoft.com (linux.microsoft.com [13.77.154.182]) by lists.libvirt.org (Postfix) with ESMTP id 2B63D1AA3 for ; Wed, 29 Nov 2023 18:11:17 -0500 (EST) Received: from home-fedora.. (072-191-074-189.res.spectrum.com [72.191.74.189]) by linux.microsoft.com (Postfix) with ESMTPSA id 1341220B74C1; Wed, 29 Nov 2023 15:11:16 -0800 (PST) X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on lists.libvirt.org X-Spam-Level: X-Spam-Status: No, score=-0.8 required=5.0 tests=HEADER_FROM_DIFFERENT_DOMAINS, MAILING_LIST_MULTI,SPF_HELO_PASS,T_SCC_BODY_TEXT_LINE autolearn=unavailable autolearn_force=no version=3.4.4 DKIM-Filter: OpenDKIM Filter v2.11.0 linux.microsoft.com 1341220B74C1 From: Praveen K Paladugu To: devel@lists.libvirt.org Subject: [libvirt PATCH 5/5] ch: Enable ETHERNET Network mode support Date: Wed, 29 Nov 2023 17:11:06 -0600 Message-ID: <20231129231106.73443-6-prapal@linux.microsoft.com> X-Mailer: git-send-email 2.41.0 In-Reply-To: <20231129231106.73443-1-prapal@linux.microsoft.com> References: <20231129231106.73443-1-prapal@linux.microsoft.com> MIME-Version: 1.0 Message-ID-Hash: N7EARAHM44TUFAB5CIHUMGY2MSKHUETS X-Message-ID-Hash: N7EARAHM44TUFAB5CIHUMGY2MSKHUETS X-MailFrom: prapal@linux.microsoft.com X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; emergency; loop; banned-address; member-moderation; header-match-config-1; header-match-config-2; header-match-config-3; header-match-devel.lists.libvirt.org-0; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; suspicious-header CC: liuwe@microsoft.com X-Mailman-Version: 3.2.2 Precedence: list List-Id: Development discussions about the libvirt library & tools Archived-At: List-Archive: List-Help: List-Post: List-Subscribe: List-Unsubscribe: Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable X-ZM-MESSAGEID: 1701300490509000001 enable VIR_DOMAIN_NET_TYPE_ETHERNET network support for ch guests. Tested with following interface config: Signed-off-by: Praveen K Paladugu --- 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" =20 #define CH_DRIVER_NAME "CH" #define CH_CMD "cloud-hypervisor" @@ -75,6 +76,9 @@ struct _virCHDriver =20 /* pid file FD, ensures two copies of the driver can't use the same ro= ot */ int lockFD; + + /* Immutable pointer, lockless APIs. Pointless abstraction */ + ebtablesContext *ebtables; }; =20 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 @@ =20 #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) =20 return vm; } + +int +virCHDomainValidateActualNetDef(virDomainNetDef *net) +{ + virDomainNetType actualType =3D 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); =20 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 + * . + */ + +#include + +#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 =3D virDomainNetGetActualType(net); + + + switch (actualType) { + case VIR_DOMAIN_NET_TYPE_ETHERNET: + + if (virDomainInterfaceEthernetConnect(vm, net, driver->ebtables, f= alse, + 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 =3D 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 + * . + */ + +#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 #include =20 +#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, vi= rDomainDef *vmdef) return 0; } =20 -static int -virCHMonitorBuildNetJson(virJSONValue *nets, - virDomainNetDef *netdef, - size_t *nnicindexes, - int **nicindexes) -{ - virDomainNetType netType =3D virDomainNetGetActualType(netdef); - char macaddr[VIR_MAC_STRING_BUFLEN]; - g_autoptr(virJSONValue) net =3D NULL; =20 - // check net type at first - net =3D virJSONValueNewObject(); - - switch (netType) { - case VIR_DOMAIN_NET_TYPE_ETHERNET: - if (netdef->guestIP.nips =3D=3D 1) { - const virNetDevIPAddr *ip =3D netdef->guestIP.ips[0]; - g_autofree char *addr =3D NULL; - virSocketAddr netmask; - g_autofree char *netmaskStr =3D NULL; - - if (!(addr =3D virSocketAddrFormat(&ip->address))) - return -1; - if (virJSONValueObjectAppendString(net, "ip", addr) < 0) - return -1; =20 - 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 =3D 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= ")); - } =20 - /* network and bridge use a tap device, and direct uses a - * macvtap device - */ - if (nicindexes && nnicindexes && netdef->ifname) { - int nicindex =3D 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 =3D virJSONValueNewObject(); + + virDomainNetType actualType =3D virDomainNetGetActualType(net); + + if (actualType =3D=3D VIR_DOMAIN_NET_TYPE_ETHERNET) { + + /* + * else case for below is already checked in + * virCHDomainValidateActualNetDef. No need to check again. + */ + if (net->guestIP.nips =3D=3D 1) { + const virNetDevIPAddr *ip =3D net->guestIP.ips[0]; + g_autofree char *addr =3D NULL; + virSocketAddr netmask; + g_autofree char *netmaskStr =3D NULL; + if (!(addr =3D virSocketAddrFormat(&ip->address))) + return -1; =20 - 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 netm= ask"), + ip->prefix); + return -1; } - break; - case VIR_DOMAIN_NET_TYPE_VHOSTUSER: - if ((virDomainChrType)netdef->data.vhostuser->type !=3D VIR_DO= MAIN_CHR_TYPE_UNIX) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("vhost_user type support UNIX socket in this = CH")); + if (!(netmaskStr =3D virSocketAddrFormat(&netmask))) return -1; - } else { - if (virJSONValueObjectAppendString(net, "vhost_socket", ne= tdef->data.vhostuser->data.nix.path) < 0) - return -1; - if (virJSONValueObjectAppendBoolean(net, "vhost_user", tru= e) < 0) + if (virJSONValueObjectAppendString(net_json, "mask", netmaskSt= r) < 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 !=3D NULL) { - if (virJSONValueObjectAppendString(net, "tap", netdef->ifname) < 0) - return -1; - } - if (virJSONValueObjectAppendString(net, "mac", virMacAddrFormat(&netde= f->mac, macaddr)) < 0) - return -1; + } + + } =20 + if (virJSONValueObjectAppendString(net_json, "mac", + virMacAddrFormat(&net->mac, macaddr)) < 0) + return -1; =20 - if (netdef->virtio !=3D NULL) { - if (netdef->virtio->iommu =3D=3D VIR_TRISTATE_SWITCH_ON) { - if (virJSONValueObjectAppendBoolean(net, "iommu", true) < 0) + if (net->virtio !=3D NULL) { + if (net->virtio->iommu =3D=3D VIR_TRISTATE_SWITCH_ON) { + if (virJSONValueObjectAppendBoolean(net_json, "iommu", true) <= 0) return -1; } } - if (netdef->driver.virtio.queues) { - if (virJSONValueObjectAppendNumberInt(net, "num_queues", netdef->d= river.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; } =20 - if (netdef->driver.virtio.rx_queue_size || netdef->driver.virtio.tx_qu= eue_size) { - if (netdef->driver.virtio.rx_queue_size !=3D netdef->driver.virtio= .tx_queue_size) { + if (net->driver.virtio.rx_queue_size || net->driver.virtio.tx_queue_si= ze) { + if (net->driver.virtio.rx_queue_size !=3D + net->driver.virtio.tx_queue_size) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("virtio rx_queue_size option %1$d is not same with tx_que= ue_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->d= river.virtio.rx_queue_size) < 0) + if (virJSONValueObjectAppendNumberInt(net_json, + "queue_size", net->driver.virtio.rx_queue_size= ) < 0) return -1; } =20 - 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 =3D NULL; - size_t i; - - if (vmdef->nnets > 0) { - nets =3D virJSONValueNewArray(); - - for (i =3D 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; } =20 + if (!(*jsonstr =3D virJSONValueToString(net_json, false))) + return -1; + return 0; } =20 @@ -456,11 +410,8 @@ virCHMonitorBuildDevicesJson(virJSONValue *content, } =20 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 =3D virJSONValueNewObject(); =20 @@ -490,10 +441,6 @@ virCHMonitorBuildVMJson(virCHDriver *driver, if (virCHMonitorBuildDisksJson(content, vmdef) < 0) return -1; =20 - - if (virCHMonitorBuildNetsJson(content, vmdef, nnicindexes, nicindexes)= < 0) - return -1; - if (virCHMonitorBuildDevicesJson(content, vmdef) < 0) return -1; =20 @@ -877,10 +824,7 @@ virCHMonitorShutdownVMM(virCHMonitor *mon) } =20 int -virCHMonitorCreateVM(virCHDriver *driver, - virCHMonitor *mon, - size_t *nnicindexes, - int **nicindexes) +virCHMonitorCreateVM(virCHDriver *driver, virCHMonitor *mon) { g_autofree char *url =3D NULL; int responseCode =3D 0; @@ -892,8 +836,7 @@ virCHMonitorCreateVM(virCHDriver *driver, headers =3D curl_slist_append(headers, "Accept: application/json"); headers =3D curl_slist_append(headers, "Content-Type: application/json= "); =20 - if (virCHMonitorBuildVMJson(driver, mon->vm->def, &payload, - nnicindexes, nicindexes) !=3D 0) + if (virCHMonitorBuildVMJson(driver, mon->vm->def, &payload) !=3D 0) return -1; =20 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); =20 =20 -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, boo= l 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" =20 #define VIR_FROM_THIS VIR_FROM_CH =20 @@ -448,13 +452,142 @@ virCHProcessSetupVcpus(virDomainObj *vm) return 0; } =20 +/** + * 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 =3D NULL; + g_autoptr(virJSONValue) net =3D NULL; + struct sockaddr_un server_addr; + g_auto(virBuffer) buf =3D VIR_BUFFER_INITIALIZER; + g_auto(virBuffer) http_headers =3D 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 =3D 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 =3D AF_UNIX; + if (virStrcpyStatic(server_addr.sun_path, mon->socketpath) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("UNIX socket path '%1$s' too long"), mon->socketp= ath); + goto err; + } + + if (connect(mon_sockfd, (struct sockaddr *)&server_addr, + sizeof(server_addr)) =3D=3D -1) { + virReportSystemError(errno, "%s", _("Failed to connect to mon sock= et")); + 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 =3D 0; i < vmdef->nnets; i++) { + g_autofree char *payload =3D NULL; + if (vmdef->nets[i]->driver.virtio.queues =3D=3D 0) { + /* "queues" here refers to queue pairs. When 0, initialize + * queue pairs to 1. + */ + vmdef->nets[i]->driver.virtio.queues =3D 1; + } + tapfd_len =3D 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 =3D g_new0(int, tapfd_len); + memset(tapfds, -1, (tapfd_len) * sizeof(*tapfds)); + + /* Connect Guest interfaces */ + if (virCHConnetNetworkInterfaces(driver, vmdef, vmdef->nets[i], ta= pfds, + 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 =3D %s", payloa= d); + + virBufferAsprintf(&buf, "%s", virBufferCurrentContent(&http_header= s)); + virBufferAsprintf(&buf, "Content-Length: %ld\r\n\r\n", strlen(payl= oad)); + virBufferAsprintf(&buf, "%s", payload); + payload =3D virBufferContentAndReset(&buf); + + ret =3D 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 =3D 0; j < tapfd_len; j++) { + VIR_FORCE_CLOSE(tapfds[j]); + } + + /* Process the response from CH */ + http_res =3D virSocketRecvHttpResponse(mon_sockfd); + if (http_res < 0) { + VIR_ERROR(_("Failed while receiving response from CH")); + goto err; + } + if (http_res !=3D 204 && http_res !=3D 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; } =20 - 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 =3D vm->pid; priv->machineName =3D virCHDomainGetMachineName(vm); =20 + 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; =20 + /* 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 =3D 0; virCHDomainObjPrivate *priv =3D vm->privateData; + virCHDriverConfig *cfg =3D virCHDriverGetConfig(driver); + virDomainDef *def =3D vm->def; + size_t i; =20 VIR_DEBUG("Stopping VM name=3D%s pid=3D%d reason=3D%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); } =20 + /* de-activate netdevs after stopping vm */ + ignore_value(virDomainInterfaceStopDevices(vm->def)); + + for (i =3D 0; i < def->nnets; i++) { + virDomainNetDef *net =3D def->nets[i]; + virDomainInterfaceDeleteDevice(def, net, false, cfg->stateDir); + } + retry: if ((ret =3D 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 =3D [ 'ch_domain.h', 'ch_driver.c', 'ch_driver.h', + 'ch_interface.c', + 'ch_interface.h', 'ch_monitor.c', 'ch_monitor.h', 'ch_process.c', --=20 2.41.0 _______________________________________________ Devel mailing list -- devel@lists.libvirt.org To unsubscribe send an email to devel-leave@lists.libvirt.org