Files
libvirt/src/qemu/qemu_interface.c
Praveen K Paladugu af87ee7927 hypervisor: Move domain interface mgmt methods
From: Praveen K Paladugu <prapal@linux.microsoft.com>

Move methods to connect domain interfaces to host bridges to hypervisor.
This is to allow reuse between qemu and ch drivers.

Signed-off-by: Praveen K Paladugu <praveenkpaladugu@gmail.com>
Signed-off-by: Praveen K Paladugu <prapal@linux.microsoft.com>
Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
Reviewed-by: Michal Privoznik <mprivozn@redhat.com>
2024-08-26 16:10:04 +02:00

218 lines
7.2 KiB
C

/*
* qemu_interface.c: QEMU interface management
*
* Copyright (C) 2015-2016 Red Hat, Inc.
* Copyright IBM Corp. 2014
*
* 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 "network_conf.h"
#include "domain_audit.h"
#include "domain_nwfilter.h"
#include "domain_interface.h"
#include "qemu_interface.h"
#include "viralloc.h"
#include "virlog.h"
#include "virnetdev.h"
#include "virnetdevtap.h"
#include "virnetdevmacvlan.h"
#include "virnetdevbridge.h"
#include "virnetdevvportprofile.h"
#include "virsocket.h"
#include "vircommand.h"
#include <sys/stat.h>
#include <fcntl.h>
#define VIR_FROM_THIS VIR_FROM_QEMU
VIR_LOG_INIT("qemu.qemu_interface");
/**
* qemuInterfaceDirectConnect:
* @def: the definition of the VM (needed by 802.1Qbh and audit)
* @driver: pointer to the driver instance
* @net: pointer to the VM's interface description with direct device type
* @tapfd: array of file descriptor return value for the new device
* @tapfdSize: number of file descriptors in @tapfd
* @vmop: VM operation type
*
* Returns 0 on success or -1 in case of error.
*/
int
qemuInterfaceDirectConnect(virDomainDef *def,
virQEMUDriver *driver,
virDomainNetDef *net,
int *tapfd,
size_t tapfdSize,
virNetDevVPortProfileOp vmop)
{
int ret = -1;
char *res_ifname = NULL;
g_autoptr(virQEMUDriverConfig) cfg = virQEMUDriverGetConfig(driver);
unsigned int macvlan_create_flags = VIR_NETDEV_MACVLAN_CREATE_WITH_TAP;
qemuDomainNetworkPrivate *netpriv = QEMU_DOMAIN_NETWORK_PRIVATE(net);
if (virDomainInterfaceIsVnetCompatModel(net))
macvlan_create_flags |= VIR_NETDEV_MACVLAN_VNET_HDR;
if (virNetDevMacVLanCreateWithVPortProfile(net->ifname,
&net->mac,
virDomainNetGetActualDirectDev(net),
virDomainNetGetActualDirectMode(net),
virDomainNetGetActualVlan(net),
def->uuid,
virDomainNetGetActualVirtPortProfile(net),
&res_ifname,
vmop, cfg->stateDir,
tapfd, tapfdSize,
macvlan_create_flags) < 0)
goto cleanup;
netpriv->created = true;
virDomainAuditNetDevice(def, net, res_ifname, true);
VIR_FREE(net->ifname);
net->ifname = res_ifname;
ret = 0;
cleanup:
if (ret < 0) {
while (tapfdSize--)
VIR_FORCE_CLOSE(tapfd[tapfdSize]);
}
return ret;
}
/*
* Returns: -1 on error, 0 on success. Populates net->privateData->slirp if
* the slirp helper is needed.
*/
int
qemuInterfacePrepareSlirp(virQEMUDriver *driver,
virDomainNetDef *net)
{
g_autoptr(virQEMUDriverConfig) cfg = virQEMUDriverGetConfig(driver);
g_autoptr(qemuSlirp) slirp = NULL;
size_t i;
if (!cfg->slirpHelperName ||
!virFileExists(cfg->slirpHelperName))
return 0; /* fallback to builtin slirp impl */
if (!(slirp = qemuSlirpNewForHelper(cfg->slirpHelperName)))
return -1;
for (i = 0; i < net->guestIP.nips; i++) {
const virNetDevIPAddr *ip = net->guestIP.ips[i];
if (VIR_SOCKET_ADDR_IS_FAMILY(&ip->address, AF_INET) &&
!qemuSlirpHasFeature(slirp, QEMU_SLIRP_FEATURE_IPV4))
return 0;
if (VIR_SOCKET_ADDR_IS_FAMILY(&ip->address, AF_INET6) &&
!qemuSlirpHasFeature(slirp, QEMU_SLIRP_FEATURE_IPV6))
return 0;
}
QEMU_DOMAIN_NETWORK_PRIVATE(net)->slirp = g_steal_pointer(&slirp);
return 0;
}
/**
* qemuInterfaceOpenVhostNet:
* @vm: domain object
* @net: network definition
*
* Open vhost-net, multiple times - if requested.
*
* Returns: 0 on success
* -1 on failure
*/
int
qemuInterfaceOpenVhostNet(virDomainObj *vm,
virDomainNetDef *net)
{
qemuDomainNetworkPrivate *netpriv = QEMU_DOMAIN_NETWORK_PRIVATE(net);
size_t i;
const char *vhostnet_path = net->backend.vhost;
size_t vhostfdSize = net->driver.virtio.queues;
if (!vhostfdSize)
vhostfdSize = 1;
if (!vhostnet_path)
vhostnet_path = "/dev/vhost-net";
/* If running a plain QEMU guest, or
* if the config says explicitly to not use vhost, return now */
if (vm->def->virtType != VIR_DOMAIN_VIRT_KVM ||
net->driver.virtio.name == VIR_DOMAIN_NET_DRIVER_TYPE_QEMU)
return 0;
/* If qemu doesn't support vhost-net mode (including the -netdev and
* -device command options), don't try to open the device.
*/
if (!qemuDomainSupportsNicdev(vm->def, net)) {
if (net->driver.virtio.name == VIR_DOMAIN_NET_DRIVER_TYPE_VHOST) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("vhost-net is not supported with this QEMU binary"));
return -1;
}
return 0;
}
/* If the nic model isn't virtio, don't try to open. */
if (!virDomainNetIsVirtioModel(net)) {
if (net->driver.virtio.name == VIR_DOMAIN_NET_DRIVER_TYPE_VHOST) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("vhost-net is only supported for virtio network interfaces"));
return -1;
}
return 0;
}
for (i = 0; i < vhostfdSize; i++) {
VIR_AUTOCLOSE fd = open(vhostnet_path, O_RDWR);
g_autofree char *name = g_strdup_printf("vhostfd-%s%zu", net->info.alias, i);
/* If the config says explicitly to use vhost and we couldn't open it,
* report an error.
*/
if (fd < 0) {
virDomainAuditNetDevice(vm->def, net, vhostnet_path, false);
if (net->driver.virtio.name == VIR_DOMAIN_NET_DRIVER_TYPE_VHOST) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("vhost-net was requested for an interface, but is unavailable"));
return -1;
}
VIR_WARN("Unable to open vhost-net. Opened so far %zu, requested %zu",
i, vhostfdSize);
break;
}
netpriv->vhostfds = g_slist_prepend(netpriv->vhostfds, qemuFDPassDirectNew(name, &fd));
}
netpriv->vhostfds = g_slist_reverse(netpriv->vhostfds);
virDomainAuditNetDevice(vm->def, net, vhostnet_path, vhostfdSize);
return 0;
}