[libvirt PATCH 0/3] Introduce VIR_MIGRATE_ASSUME_SHARED_STORAGE
by Andrea Bolognani
This was initially motivated by a KubeVirt issue[1] concerning
integration with the Portworx storage provide, but it turns out to be
more generally applicable: since mounting an NFS share on the same
host that is exporting it is known to cause issues and is therefore
not recommended, we need a way to allow migration in such a
configuration while still not going quite as far as
VIR_MIGRATE_UNSAFE does and losing all handrails.
[1] https://issues.redhat.com/browse/CNV-34322
Andrea Bolognani (3):
include: Introduce VIR_MIGRATE_ASSUME_SHARED_STORAGE
qemu: Implement VIR_MIGRATE_ASSUME_SHARED_STORAGE support
virsh: Wire up VIR_MIGRATE_ASSUME_SHARED_STORAGE support
docs/manpages/virsh.rst | 5 ++++-
include/libvirt/libvirt-domain.h | 14 ++++++++++++++
src/qemu/qemu_migration.c | 5 +++++
src/qemu/qemu_migration.h | 1 +
tools/virsh-domain.c | 5 +++++
5 files changed, 29 insertions(+), 1 deletion(-)
--
2.41.0
5 months, 3 weeks
Versioned CPU types in libvirt
by Jonathon Jongsma
I'm currently looking at getting libvirt working with AMD's SEV-SNP
encrypted virtualization technology. I have access to a test machine
with an AMD EPYC 7713 processor which I can use to launch SNP guests
with qemu, but only when I specify one of the following versioned -cpu
values:
- EPYC-v4
- EPYC-Milan-v2
- EPYC-Rome-v3
From what I understand, the unversioned CPU models in qemu are supposed
to resolve to a specific versioned CPU model depending on the machine
type. But I'm not exactly sure how machine type influences it.
I've got some libvirt patches to launch an SEV-SNP guest working now
except for the CPU model specification. As far as I can tell, I can
currently only specify the un-versioned model in libvirt. Is there any
way to request a particular versioned CPU from qemu? I feel like I'm
missing something here.
I should perhaps also mention that I'm running a development version of
qemu from Cole's copr repo[1], which could still have some related bugs
[1] https://copr.fedorainfracloud.org/coprs/g/virtmaint-sig/sev-snp-coconut/
Thanks,
Jonathon
5 months, 4 weeks
[PATCH V3] support for hotplug/hotunplug in test hypervisor
by Thanos Makatos
Signed-off-by: Thanos Makatos <thanos.makatos(a)nutanix.com>
---
src/test/test_driver.c | 59 ++++++++++++++++++++++++++++++++++++++++++
1 file changed, 59 insertions(+)
diff --git a/src/test/test_driver.c b/src/test/test_driver.c
index e87d7cfd44..d605649262 100644
--- a/src/test/test_driver.c
+++ b/src/test/test_driver.c
@@ -10035,6 +10035,62 @@ testConnectGetDomainCapabilities(virConnectPtr conn G_GNUC_UNUSED,
return virDomainCapsFormat(domCaps);
}
+static int
+testVirDomainAttachDeviceFlags(virDomainPtr domain,
+ const char *xml,
+ unsigned int flags G_GNUC_UNUSED) {
+
+ int ret = -1;
+ virDomainObj *vm;
+ testDriver *driver;
+ virDomainDeviceDef *devConf;
+
+ if (!(vm = testDomObjFromDomain(domain)))
+ return -1;
+
+ driver = domain->conn->privateData;
+
+ if (!(devConf = virDomainDeviceDefParse(xml, vm->def, driver->xmlopt,
+ NULL, 0)))
+ goto out;
+
+ VIR_APPEND_ELEMENT(vm->def->hostdevs, vm->def->nhostdevs,
+ devConf->data.hostdev);
+ virDomainDeviceDefFree(devConf);
+ ret = 0;
+out:
+ virDomainObjEndAPI(&vm);
+ return ret;
+}
+
+static int
+testVirDomainAttachDevice(virDomainPtr domain, const char *xml)
+{
+ return testVirDomainAttachDeviceFlags(domain, xml, 0);
+}
+
+static int
+testVirDomainDetachDeviceAlias(virDomainPtr domain,
+ const char *alias,
+ unsigned int flags G_GNUC_UNUSED)
+{
+ virDomainObj *vm;
+ size_t i;
+ bool found = false;
+
+ if (!(vm = testDomObjFromDomain(domain)))
+ return -1;
+
+ for (i = 0; i < vm->def->nhostdevs && !found; i++) {
+ if (!strcmp(vm->def->hostdevs[i]->info->alias, alias)) {
+ virDomainHostdevDefFree(vm->def->hostdevs[i]);
+ VIR_DELETE_ELEMENT(vm->def->hostdevs, i, vm->def->nhostdevs);
+ found = true;
+ }
+ }
+ virDomainObjEndAPI(&vm);
+ return found ? 0 : -1;
+}
/*
* Test driver
@@ -10058,6 +10114,9 @@ static virHypervisorDriver testHypervisorDriver = {
.connectListDomains = testConnectListDomains, /* 0.1.1 */
.connectNumOfDomains = testConnectNumOfDomains, /* 0.1.1 */
.connectListAllDomains = testConnectListAllDomains, /* 0.9.13 */
+ .domainAttachDevice = testVirDomainAttachDevice, /* 9.9.0 */
+ .domainAttachDeviceFlags = testVirDomainAttachDeviceFlags, /* 9.9.0 */
+ .domainDetachDeviceAlias = testVirDomainDetachDeviceAlias, /* 9.9.0 */
.domainCreateXML = testDomainCreateXML, /* 0.1.4 */
.domainCreateXMLWithFiles = testDomainCreateXMLWithFiles, /* 5.7.0 */
.domainLookupByID = testDomainLookupByID, /* 0.1.1 */
--
2.27.0
6 months
[PATCH 00/16] Farewell rpcgen
by Daniel P. Berrangé
This series something I was hacking on a little while back in an
attempt to make our RPC layer more maintainable. There are many
aspects I'm unhappy about with current code
* When serializing a message we have no clue how big
it will be, but xdrmem_create wants a fixed size,
so we have to keep trying to serialize in a loop
making it bigger each time
* We don't control memory allocation/free'ing directly
so we can't do a virSecureErase on fields inside the
RPC message struct that handle secrets.
* The XDR API is generally unpleasant to use as it is
outside our virNetMessage object. Ideally we would
be reading/writing directly from/to the virNetMessage
buffer with APIs on virNetMessage,instead of indirectly
via a XDR object.
* We want more from XDR than it actually gives us. Our
XDR protocol files have annotations to express what
we want our code generator todo, or for ACLs. The
relationship between the structs and the message
numbers is implicit. Essentially we've defined our
own language indirectly via comments, and then
parse this with regexes which is horrid.
* The code rpcgen creates is poor quality which we have
to post-process to fix bugs/problems. It also lacks
support for modern features like g_auto.
Anyway, in a fit of rage I looked at the XDR RFC and thought..
This language is trivial, why do we need to outsource to
rpcgen and libtirpc instead of dealing with it directly.
This small series moves in that direction. It creates an
XDR language lexer and parser, and then a code generator
which emits code that is (nearly) identical to what rpcgen
would emit. This is sufficient to eliminate rpcgen usage
and support g_auto. Since we're still using libtirpc
at this stage we can be confident we're still doing the
same thing on the wire. I've got some unit tests too
with the rpcgen generation to validate stuff.
The next step is to change the code generator so that
instead of generating code for libtirpc APIs, it will
instead directly speak virNetMessage APIs. That would
give us full control over our RPC stack guaranteed to
be platform portable instead of fighting slight differences
in RPC libraries (eg xdr_quad vs xdr_int64 madness).
I was going to wait until I had written such code before
sending this series, but I've got diverted onto other more
important tasks. So here at least is what I have so far.
After that foundation is done, we are in a place where
we can actually do more innovative things. For example
we can directly extend the XDR protocol language if we
like, turning our magic comments into properly parsable
constructs.
With this, we would be in a position to replace our
Perl RPC client/server dispatch code generators with
something that is more supportable in Python. The python
code would work with properly represented objects and
formal parsers and not regexes and anonymous complex
perl data structures.
Daniel P. Berrangé (16):
rpcgen: drop type-puning workarounds
build-aux: skip E203 and W503 flake8 checks
build-aux: introduce 'black' tool for python formatting
rpcgen: add an XDR protocol lexer
rpcgen: add an XDR protocol abstract syntax tree
rpcgen: add an XDR protocol parser
rpcgen: define a visitor API for XDR protocol specs
rpcgen: add a C code generator for XDR protocol specs
rpcgen: add test case for XDR serialization
rpcgen: define entrypoint for running new rpcgen impl
build: switch over to new rpc generator code
rpcgen: add g_auto function support
rpc: use g_auto for client RPC return parameters
admin: use g_auto for client RPC return parameters
remote: use g_auto for client RPC return parameters
rpc: add helpers for XDR type serialization
build-aux/Makefile.in | 1 +
build-aux/meson.build | 5 +
build-aux/syntax-check.mk | 42 +-
libvirt.spec.in | 2 +-
meson.build | 13 +-
scripts/meson.build | 2 +
scripts/rpcgen/main.py | 90 ++
scripts/rpcgen/meson.build | 16 +
scripts/rpcgen/rpcgen/ast.py | 270 ++++++
scripts/rpcgen/rpcgen/generator.py | 509 ++++++++++++
scripts/rpcgen/rpcgen/lexer.py | 213 +++++
scripts/rpcgen/rpcgen/meson.build | 7 +
scripts/rpcgen/rpcgen/parser.py | 497 +++++++++++
scripts/rpcgen/rpcgen/visitor.py | 156 ++++
scripts/rpcgen/tests/demo.c | 495 +++++++++++
scripts/rpcgen/tests/demo.h | 264 ++++++
scripts/rpcgen/tests/demo.x | 127 +++
scripts/rpcgen/tests/meson.build | 20 +
scripts/rpcgen/tests/simple.x | 35 +
scripts/rpcgen/tests/test_demo.c | 782 ++++++++++++++++++
scripts/rpcgen/tests/test_demo_enum.bin | Bin 0 -> 4 bytes
.../tests/test_demo_enum_fixed_array.bin | Bin 0 -> 52 bytes
.../tests/test_demo_enum_pointer_null.bin | Bin 0 -> 4 bytes
.../tests/test_demo_enum_pointer_set.bin | Bin 0 -> 8 bytes
.../rpcgen/tests/test_demo_enum_scalar.bin | Bin 0 -> 4 bytes
.../test_demo_enum_variable_array_empty.bin | Bin 0 -> 4 bytes
.../test_demo_enum_variable_array_set.bin | Bin 0 -> 16 bytes
.../tests/test_demo_int_fixed_array.bin | Bin 0 -> 12 bytes
.../tests/test_demo_int_pointer_null.bin | Bin 0 -> 4 bytes
.../tests/test_demo_int_pointer_set.bin | Bin 0 -> 8 bytes
scripts/rpcgen/tests/test_demo_int_scalar.bin | Bin 0 -> 4 bytes
.../test_demo_int_variable_array_empty.bin | Bin 0 -> 4 bytes
.../test_demo_int_variable_array_set.bin | Bin 0 -> 16 bytes
.../tests/test_demo_opaque_fixed_array.bin | Bin 0 -> 12 bytes
.../test_demo_opaque_variable_array_empty.bin | Bin 0 -> 4 bytes
.../test_demo_opaque_variable_array_set.bin | Bin 0 -> 8 bytes
.../test_demo_string_variable_array_empty.bin | Bin 0 -> 4 bytes
.../test_demo_string_variable_array_set.bin | Bin 0 -> 12 bytes
scripts/rpcgen/tests/test_demo_struct.bin | Bin 0 -> 8 bytes
.../tests/test_demo_struct_fixed_array.bin | Bin 0 -> 136 bytes
.../tests/test_demo_struct_pointer_null.bin | Bin 0 -> 4 bytes
.../tests/test_demo_struct_pointer_set.bin | Bin 0 -> 12 bytes
.../rpcgen/tests/test_demo_struct_scalar.bin | 1 +
.../test_demo_struct_variable_array_empty.bin | Bin 0 -> 4 bytes
.../test_demo_struct_variable_array_set.bin | Bin 0 -> 28 bytes
.../tests/test_demo_test_struct_all_types.bin | Bin 0 -> 1752 bytes
scripts/rpcgen/tests/test_demo_union_case.bin | Bin 0 -> 8 bytes
.../rpcgen/tests/test_demo_union_default.bin | Bin 0 -> 8 bytes
.../tests/test_demo_union_fixed_array.bin | Bin 0 -> 168 bytes
.../tests/test_demo_union_no_default_case.bin | Bin 0 -> 8 bytes
.../tests/test_demo_union_pointer_null.bin | Bin 0 -> 4 bytes
.../tests/test_demo_union_pointer_set.bin | Bin 0 -> 12 bytes
.../rpcgen/tests/test_demo_union_scalar.bin | Bin 0 -> 8 bytes
.../test_demo_union_variable_array_empty.bin | Bin 0 -> 4 bytes
.../test_demo_union_variable_array_set.bin | Bin 0 -> 28 bytes
.../test_demo_union_void_default_case.bin | Bin 0 -> 8 bytes
.../test_demo_union_void_default_default.bin | 1 +
scripts/rpcgen/tests/test_generator.py | 60 ++
scripts/rpcgen/tests/test_lexer.py | 116 +++
scripts/rpcgen/tests/test_parser.py | 91 ++
src/admin/admin_remote.c | 50 +-
src/admin/meson.build | 8 +-
src/locking/meson.build | 8 +-
src/logging/meson.build | 8 +-
src/lxc/meson.build | 12 +-
src/remote/meson.build | 8 +-
src/remote/remote_driver.c | 754 ++++++-----------
src/rpc/gendispatch.pl | 60 +-
src/rpc/genprotocol.pl | 144 ----
src/rpc/meson.build | 9 +-
src/rpc/virnetmessage.c | 704 ++++++++++++++++
src/rpc/virnetmessage.h | 88 ++
72 files changed, 4897 insertions(+), 771 deletions(-)
create mode 100755 scripts/rpcgen/main.py
create mode 100644 scripts/rpcgen/meson.build
create mode 100644 scripts/rpcgen/rpcgen/ast.py
create mode 100644 scripts/rpcgen/rpcgen/generator.py
create mode 100644 scripts/rpcgen/rpcgen/lexer.py
create mode 100644 scripts/rpcgen/rpcgen/meson.build
create mode 100644 scripts/rpcgen/rpcgen/parser.py
create mode 100644 scripts/rpcgen/rpcgen/visitor.py
create mode 100644 scripts/rpcgen/tests/demo.c
create mode 100644 scripts/rpcgen/tests/demo.h
create mode 100644 scripts/rpcgen/tests/demo.x
create mode 100644 scripts/rpcgen/tests/meson.build
create mode 100644 scripts/rpcgen/tests/simple.x
create mode 100644 scripts/rpcgen/tests/test_demo.c
create mode 100644 scripts/rpcgen/tests/test_demo_enum.bin
create mode 100644 scripts/rpcgen/tests/test_demo_enum_fixed_array.bin
create mode 100644 scripts/rpcgen/tests/test_demo_enum_pointer_null.bin
create mode 100644 scripts/rpcgen/tests/test_demo_enum_pointer_set.bin
create mode 100644 scripts/rpcgen/tests/test_demo_enum_scalar.bin
create mode 100644 scripts/rpcgen/tests/test_demo_enum_variable_array_empty.bin
create mode 100644 scripts/rpcgen/tests/test_demo_enum_variable_array_set.bin
create mode 100644 scripts/rpcgen/tests/test_demo_int_fixed_array.bin
create mode 100644 scripts/rpcgen/tests/test_demo_int_pointer_null.bin
create mode 100644 scripts/rpcgen/tests/test_demo_int_pointer_set.bin
create mode 100644 scripts/rpcgen/tests/test_demo_int_scalar.bin
create mode 100644 scripts/rpcgen/tests/test_demo_int_variable_array_empty.bin
create mode 100644 scripts/rpcgen/tests/test_demo_int_variable_array_set.bin
create mode 100644 scripts/rpcgen/tests/test_demo_opaque_fixed_array.bin
create mode 100644 scripts/rpcgen/tests/test_demo_opaque_variable_array_empty.bin
create mode 100644 scripts/rpcgen/tests/test_demo_opaque_variable_array_set.bin
create mode 100644 scripts/rpcgen/tests/test_demo_string_variable_array_empty.bin
create mode 100644 scripts/rpcgen/tests/test_demo_string_variable_array_set.bin
create mode 100644 scripts/rpcgen/tests/test_demo_struct.bin
create mode 100644 scripts/rpcgen/tests/test_demo_struct_fixed_array.bin
create mode 100644 scripts/rpcgen/tests/test_demo_struct_pointer_null.bin
create mode 100644 scripts/rpcgen/tests/test_demo_struct_pointer_set.bin
create mode 100644 scripts/rpcgen/tests/test_demo_struct_scalar.bin
create mode 100644 scripts/rpcgen/tests/test_demo_struct_variable_array_empty.bin
create mode 100644 scripts/rpcgen/tests/test_demo_struct_variable_array_set.bin
create mode 100644 scripts/rpcgen/tests/test_demo_test_struct_all_types.bin
create mode 100644 scripts/rpcgen/tests/test_demo_union_case.bin
create mode 100644 scripts/rpcgen/tests/test_demo_union_default.bin
create mode 100644 scripts/rpcgen/tests/test_demo_union_fixed_array.bin
create mode 100644 scripts/rpcgen/tests/test_demo_union_no_default_case.bin
create mode 100644 scripts/rpcgen/tests/test_demo_union_pointer_null.bin
create mode 100644 scripts/rpcgen/tests/test_demo_union_pointer_set.bin
create mode 100644 scripts/rpcgen/tests/test_demo_union_scalar.bin
create mode 100644 scripts/rpcgen/tests/test_demo_union_variable_array_empty.bin
create mode 100644 scripts/rpcgen/tests/test_demo_union_variable_array_set.bin
create mode 100644 scripts/rpcgen/tests/test_demo_union_void_default_case.bin
create mode 100644 scripts/rpcgen/tests/test_demo_union_void_default_default.bin
create mode 100644 scripts/rpcgen/tests/test_generator.py
create mode 100644 scripts/rpcgen/tests/test_lexer.py
create mode 100644 scripts/rpcgen/tests/test_parser.py
delete mode 100755 src/rpc/genprotocol.pl
--
2.39.1
6 months
ANNOUNCE: Mailing list move complete
by Daniel P. Berrangé
This is an announcement to the effect that the mailing list move is now
complete. TL;DR the new list addresses are:
* announce(a)lists.libvirt.org (formerly libvirt-announce(a)redhat.com)
Low volume, announcements of releases and other important info
* users(a)lists.libvirt.org (formerly libvirt-users(a)redhat.com)
End user questions and discussions and collaboration
* devel(a)lists.libvirt.org (formerly libvir-list(a)redhat.com)
Patch submission for development of main project
* security(a)lists.libvirt.org (formerly libvir-security(a)redhat.com)
Submission of security sensitive bug reports
The online archive and membership mgmt interface is
https://lists.libvirt.org
In my original announcement[1] I mentioned that people would need to manually
re-subscribe. Due to a mixup in communications, our IT admins went ahead and
migrated across the existing entire subscriber base for all lists. Thus there
is NO need to re-subscribe to any of the lists. If you were doing filtering
of mail, you may need to update filters for the new list ID matches.
With the new list server, HyperKitty is providing the web interface. Thus
if you wish to interact with the lists entire via the browser this is now
possible. Note that it requires you to register for an account and set a
password, even if you are already a list subscriber.
If you mistakenly send to the old lists you should receive an auto-reply
about the moved destinations.
Note, we had some technical issues on Thursday/Friday, so if you sent
mails on those two days they probably will not have reached any lists,
and so you may wish to re-send them.
With regards,
Daniel
[1] https://listman.redhat.com/archives/libvirt-announce/2023-October/000650....
--
|: https://berrange.com -o- https://www.flickr.com/photos/dberrange :|
|: https://libvirt.org -o- https://fstop138.berrange.com :|
|: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|
6 months, 1 week
RFC: Switch to a date-based versioning scheme
by Andrea Bolognani
Since we're just a few months away from the 10.0.0 release, I thought
it would be a good time to bring up this idea.
Can we move to date-based version numbers? I suggest having
libvirt 24.01.0 instead of 10.0.0
24.03.0 10.1.0
24.04.0 10.2.0
...
24.11.0 10.9.0
24.12.0 10.10.0
The big advantage is that, once version numbers are obviously
date-based, any expectation of them being interpreted according to
semver[1] are immediately gone.
Of course semver doesn't make sense for us, given our extremely
strong backwards compatibility guarantees, and that's exactly why
we've left it behind with 2.0.0; however, that's something that's not
immediately obvious to someone who's not very involved with our
development process, and regarless of our intentions libvirt version
numbers *will* be mistakenly assumed to be semver-compliant on
occasion.
People are quite used to date-based version numbers thanks to Ubuntu
having used them for almost two decades, so I don't think anyone is
going to be confused by the move. And since our release schedule is
already date-based, having the versioning scheme match that just
makes perfect sense IMO.
Up until now, one could have argued in favor of the current
versioning scheme because of the single-digit major version
component, but that's going away next year regardless, which makes
this the perfect time to raise the topic :)
Thoughts?
[1] https://semver.org/
--
Andrea Bolognani / Red Hat / Virtualization
6 months, 1 week
[libvirt PATCH] src: Remove duplicated VIR_REQUIRE_FLAG_GOTO() call
by Andrea Bolognani
Signed-off-by: Andrea Bolognani <abologna(a)redhat.com>
---
src/libvirt-domain.c | 4 ----
1 file changed, 4 deletions(-)
diff --git a/src/libvirt-domain.c b/src/libvirt-domain.c
index 6616294fc1..58e1e5ea8d 100644
--- a/src/libvirt-domain.c
+++ b/src/libvirt-domain.c
@@ -4221,10 +4221,6 @@ virDomainMigrate3(virDomainPtr domain,
VIR_MIGRATE_NON_SHARED_DISK | VIR_MIGRATE_NON_SHARED_INC,
error);
- VIR_REQUIRE_FLAG_GOTO(VIR_MIGRATE_NON_SHARED_SYNCHRONOUS_WRITES,
- VIR_MIGRATE_NON_SHARED_DISK | VIR_MIGRATE_NON_SHARED_INC,
- error);
-
if (flags & VIR_MIGRATE_PEER2PEER) {
virReportInvalidArg(flags, "%s",
_("use virDomainMigrateToURI3 for peer-to-peer migration"));
--
2.41.0
6 months, 1 week
[libvirt PATCH v4] hypervisor: Move interface mgmt methods to hypervisor
by Praveen K Paladugu
Move guest interface management methods from qemu to hypervisor. These
methods will be shared by networking support in ch driver.
Signed-off-by: Praveen K Paladugu <prapal(a)linux.microsoft.com>
---
v4:
* logging and formatting fixes
v3:
* Moved qemuInterfaceStopDevice/s methods into hypervisor, to keep all the
related methods together.
Signed-off-by: Praveen K Paladugu <prapal(a)linux.microsoft.com>
---
po/POTFILES | 1 +
src/hypervisor/domain_interface.c | 370 ++++++++++++++++++++++++++++++
src/hypervisor/domain_interface.h | 41 ++++
src/hypervisor/meson.build | 1 +
src/libvirt_private.syms | 8 +
src/qemu/qemu_command.c | 6 +-
src/qemu/qemu_hotplug.c | 5 +-
src/qemu/qemu_interface.c | 339 +--------------------------
src/qemu/qemu_interface.h | 11 -
src/qemu/qemu_process.c | 5 +-
10 files changed, 436 insertions(+), 351 deletions(-)
create mode 100644 src/hypervisor/domain_interface.c
create mode 100644 src/hypervisor/domain_interface.h
diff --git a/po/POTFILES b/po/POTFILES
index 3a51aea5cb..023c041f61 100644
--- a/po/POTFILES
+++ b/po/POTFILES
@@ -92,6 +92,7 @@ src/hyperv/hyperv_util.c
src/hyperv/hyperv_wmi.c
src/hypervisor/domain_cgroup.c
src/hypervisor/domain_driver.c
+src/hypervisor/domain_interface.c
src/hypervisor/virhostdev.c
src/interface/interface_backend_netcf.c
src/interface/interface_backend_udev.c
diff --git a/src/hypervisor/domain_interface.c b/src/hypervisor/domain_interface.c
new file mode 100644
index 0000000000..07a83d2034
--- /dev/null
+++ b/src/hypervisor/domain_interface.c
@@ -0,0 +1,370 @@
+/*
+ * Copyright (C) 2015-2016 Red Hat, Inc.
+ * Copyright IBM Corp. 2014
+ *
+ * domain_interface.c: methods to manage guest/domain interfaces
+ *
+ * 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_audit.h"
+#include "domain_conf.h"
+#include "domain_interface.h"
+#include "domain_nwfilter.h"
+#include "network_conf.h"
+#include "viralloc.h"
+#include "virconftypes.h"
+#include "virebtables.h"
+#include "virfile.h"
+#include "virlog.h"
+#include "virmacaddr.h"
+#include "virnetdevbridge.h"
+#include "virnetdevtap.h"
+
+#define VIR_FROM_THIS VIR_FROM_DOMAIN
+
+VIR_LOG_INIT("domain.interface");
+
+bool
+virDomainInterfaceIsVnetCompatModel(const virDomainNetDef *net)
+{
+ return (virDomainNetIsVirtioModel(net) ||
+ net->model == VIR_DOMAIN_NET_MODEL_E1000E ||
+ net->model == VIR_DOMAIN_NET_MODEL_IGB ||
+ net->model == VIR_DOMAIN_NET_MODEL_VMXNET3);
+}
+
+/* virDomainInterfaceEthernetConnect:
+ * @def: the definition of the VM
+ * @net: a net definition in the VM
+ * @ebtables: ebtales context
+ * @macFilter: whether driver support mac Filtering
+ * @privileged: whether running as privileged user
+ * @tapfd: array of file descriptor return value for the new device
+ * @tapfdsize: number of file descriptors in @tapfd
+ *
+ * Called *only* called if actualType is VIR_DOMAIN_NET_TYPE_ETHERNET
+ * (i.e. if the connection is made with a tap device)
+ */
+int
+virDomainInterfaceEthernetConnect(virDomainDef *def,
+ virDomainNetDef *net,
+ ebtablesContext *ebtables,
+ bool macFilter,
+ bool privileged,
+ int *tapfd,
+ size_t tapfdSize)
+{
+ virMacAddr tapmac;
+ int ret = -1;
+ unsigned int tap_create_flags = VIR_NETDEV_TAP_CREATE_IFUP;
+ bool template_ifname = false;
+ const char *tunpath = "/dev/net/tun";
+ const char *auditdev = tunpath;
+
+ if (net->backend.tap) {
+ tunpath = net->backend.tap;
+ if (!privileged) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("cannot use custom tap device in session mode"));
+ goto cleanup;
+ }
+ }
+
+ if (virDomainInterfaceIsVnetCompatModel(net))
+ tap_create_flags |= VIR_NETDEV_TAP_CREATE_VNET_HDR;
+
+ if (net->managed_tap == VIR_TRISTATE_BOOL_NO) {
+ if (!net->ifname) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("target dev must be supplied when managed='no'"));
+ goto cleanup;
+ }
+ if (virNetDevExists(net->ifname) != 1) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("target managed='no' but specified dev doesn't exist"));
+ goto cleanup;
+ }
+
+ tap_create_flags |= VIR_NETDEV_TAP_CREATE_ALLOW_EXISTING;
+
+ if (virNetDevMacVLanIsMacvtap(net->ifname)) {
+ auditdev = net->ifname;
+ if (virNetDevMacVLanTapOpen(net->ifname, tapfd, tapfdSize) < 0)
+ goto cleanup;
+ if (virNetDevMacVLanTapSetup(tapfd, tapfdSize,
+ virDomainInterfaceIsVnetCompatModel(net)) < 0) {
+ goto cleanup;
+ }
+ } else {
+ if (virNetDevTapCreate(&net->ifname, tunpath, tapfd, tapfdSize,
+ tap_create_flags) < 0)
+ goto cleanup;
+ }
+ } else {
+
+ if (!net->ifname)
+ template_ifname = true;
+
+ if (virNetDevTapCreate(&net->ifname, tunpath, tapfd, tapfdSize,
+ tap_create_flags) < 0) {
+ goto cleanup;
+ }
+
+ /* The tap device's MAC address cannot match the MAC address
+ * used by the guest. This results in "received packet on
+ * vnetX with own address as source address" error logs from
+ * the kernel.
+ */
+ virMacAddrSet(&tapmac, &net->mac);
+ if (tapmac.addr[0] == 0xFE)
+ tapmac.addr[0] = 0xFA;
+ else
+ tapmac.addr[0] = 0xFE;
+
+ if (virNetDevSetMAC(net->ifname, &tapmac) < 0)
+ goto cleanup;
+
+ if (virNetDevSetOnline(net->ifname, true) < 0)
+ goto cleanup;
+ }
+
+ if (net->script &&
+ virNetDevRunEthernetScript(net->ifname, net->script) < 0)
+ goto cleanup;
+
+ if (macFilter &&
+ ebtablesAddForwardAllowIn(ebtables,
+ net->ifname,
+ &net->mac) < 0)
+ goto cleanup;
+
+ if (net->filter &&
+ virDomainConfNWFilterInstantiate(def->name, def->uuid, net, false) < 0) {
+ goto cleanup;
+ }
+
+ virDomainAuditNetDevice(def, net, auditdev, true);
+
+ ret = 0;
+
+ cleanup:
+ if (ret < 0) {
+ size_t i;
+
+ virDomainAuditNetDevice(def, net, auditdev, false);
+ for (i = 0; i < tapfdSize && tapfd[i] >= 0; i++)
+ VIR_FORCE_CLOSE(tapfd[i]);
+ if (template_ifname)
+ VIR_FREE(net->ifname);
+ }
+
+ return ret;
+}
+
+/**
+ * virDomainInterfaceStartDevice:
+ * @net: net device to start
+ *
+ * Based upon the type of device provided, perform the appropriate
+ * work to completely activate the device and make it reachable from
+ * the rest of the network.
+ */
+int
+virDomainInterfaceStartDevice(virDomainNetDef *net)
+{
+ virDomainNetType actualType = virDomainNetGetActualType(net);
+
+ switch (actualType) {
+ case VIR_DOMAIN_NET_TYPE_BRIDGE:
+ case VIR_DOMAIN_NET_TYPE_NETWORK:
+ if (virDomainNetGetActualBridgeMACTableManager(net)
+ == VIR_NETWORK_BRIDGE_MAC_TABLE_MANAGER_LIBVIRT) {
+ /* libvirt is managing the FDB of the bridge this device
+ * is attaching to, so we have turned off learning and
+ * unicast_flood on the device to prevent the kernel from
+ * adding any FDB entries for it. This means we need to
+ * add an fdb entry ourselves, using the MAC address from
+ * the interface config.
+ */
+ if (virNetDevBridgeFDBAdd(&net->mac, net->ifname,
+ VIR_NETDEVBRIDGE_FDB_FLAG_MASTER |
+ VIR_NETDEVBRIDGE_FDB_FLAG_TEMP) < 0)
+ return -1;
+ }
+ break;
+
+ case VIR_DOMAIN_NET_TYPE_DIRECT: {
+ const char *physdev = virDomainNetGetActualDirectDev(net);
+ bool isOnline = true;
+
+ /* set the physdev online if necessary. It may already be up,
+ * in which case we shouldn't re-up it just in case that causes
+ * some sort of "blip" in the physdev's status.
+ */
+ if (physdev && virNetDevGetOnline(physdev, &isOnline) < 0)
+ return -1;
+ if (!isOnline && virNetDevSetOnline(physdev, true) < 0)
+ return -1;
+
+ /* macvtap devices share their MAC address with the guest
+ * domain, and if they are set online prior to the domain CPUs
+ * being started, the host may send out traffic from this
+ * device that could confuse other entities on the network (in
+ * particular, if this new domain is the destination of a
+ * migration, and the source domain is still running, another
+ * host may mistakenly direct traffic for the guest to the
+ * destination domain rather than source domain). To prevent
+ * this, we create the macvtap device with IFF_UP false
+ * (i.e. "offline") then wait to bring it online until just as
+ * we are starting the domain CPUs.
+ */
+ if (virNetDevSetOnline(net->ifname, true) < 0)
+ return -1;
+ break;
+ }
+
+ case VIR_DOMAIN_NET_TYPE_ETHERNET:
+ if (virNetDevIPInfoAddToDev(net->ifname, &net->hostIP) < 0)
+ return -1;
+
+ break;
+
+ case VIR_DOMAIN_NET_TYPE_USER:
+ case VIR_DOMAIN_NET_TYPE_VHOSTUSER:
+ case VIR_DOMAIN_NET_TYPE_SERVER:
+ case VIR_DOMAIN_NET_TYPE_CLIENT:
+ case VIR_DOMAIN_NET_TYPE_MCAST:
+ case VIR_DOMAIN_NET_TYPE_UDP:
+ case VIR_DOMAIN_NET_TYPE_INTERNAL:
+ case VIR_DOMAIN_NET_TYPE_HOSTDEV:
+ case VIR_DOMAIN_NET_TYPE_VDPA:
+ case VIR_DOMAIN_NET_TYPE_NULL:
+ case VIR_DOMAIN_NET_TYPE_VDS:
+ case VIR_DOMAIN_NET_TYPE_LAST:
+ /* these types all require no action */
+ break;
+ }
+
+ return 0;
+}
+
+/**
+ * virDomainInterfaceStartDevices:
+ * @def: domain definition
+ *
+ * Set all ifaces associated with this domain to the online state.
+ */
+int
+virDomainInterfaceStartDevices(virDomainDef *def)
+{
+ size_t i;
+
+ for (i = 0; i < def->nnets; i++) {
+ if (virDomainInterfaceStartDevice(def->nets[i]) < 0)
+ return -1;
+ }
+ return 0;
+}
+
+/**
+ * virDomainInterfaceStopDevice:
+ * @net: net device to stop
+ *
+ * Based upon the type of device provided, perform the appropriate
+ * work to deactivate the device so that packets aren't forwarded to
+ * it from the rest of the network.
+ */
+int
+virDomainInterfaceStopDevice(virDomainNetDef *net)
+{
+ virDomainNetType actualType = virDomainNetGetActualType(net);
+
+ switch (actualType) {
+ case VIR_DOMAIN_NET_TYPE_BRIDGE:
+ case VIR_DOMAIN_NET_TYPE_NETWORK:
+ if (virDomainNetGetActualBridgeMACTableManager(net)
+ == VIR_NETWORK_BRIDGE_MAC_TABLE_MANAGER_LIBVIRT) {
+ /* remove the FDB entries that were added during
+ * virDomainInterfaceStartDevices()
+ */
+ if (virNetDevBridgeFDBDel(&net->mac, net->ifname,
+ VIR_NETDEVBRIDGE_FDB_FLAG_MASTER |
+ VIR_NETDEVBRIDGE_FDB_FLAG_TEMP) < 0)
+ return -1;
+ }
+ break;
+
+ case VIR_DOMAIN_NET_TYPE_DIRECT: {
+ const char *physdev = virDomainNetGetActualDirectDev(net);
+
+ /* macvtap interfaces need to be marked !IFF_UP (ie "down") to
+ * prevent any host-generated traffic sent from this interface
+ * from putting bad info into the arp caches of other machines
+ * on this network.
+ */
+ if (virNetDevSetOnline(net->ifname, false) < 0)
+ return -1;
+
+ /* also mark the physdev down for passthrough macvtap, as the
+ * physdev has the same MAC address as the macvtap device.
+ */
+ if (virDomainNetGetActualDirectMode(net) ==
+ VIR_NETDEV_MACVLAN_MODE_PASSTHRU &&
+ physdev && virNetDevSetOnline(physdev, false) < 0)
+ return -1;
+ break;
+ }
+
+ case VIR_DOMAIN_NET_TYPE_ETHERNET:
+ case VIR_DOMAIN_NET_TYPE_USER:
+ case VIR_DOMAIN_NET_TYPE_VHOSTUSER:
+ case VIR_DOMAIN_NET_TYPE_SERVER:
+ case VIR_DOMAIN_NET_TYPE_CLIENT:
+ case VIR_DOMAIN_NET_TYPE_MCAST:
+ case VIR_DOMAIN_NET_TYPE_UDP:
+ case VIR_DOMAIN_NET_TYPE_INTERNAL:
+ case VIR_DOMAIN_NET_TYPE_HOSTDEV:
+ case VIR_DOMAIN_NET_TYPE_VDPA:
+ case VIR_DOMAIN_NET_TYPE_NULL:
+ case VIR_DOMAIN_NET_TYPE_VDS:
+ case VIR_DOMAIN_NET_TYPE_LAST:
+ /* these types all require no action */
+ break;
+ }
+
+ return 0;
+}
+
+/**
+ * virDomainInterfaceStopDevices:
+ * @def: domain definition
+ *
+ * Make all interfaces associated with this domain inaccessible from
+ * the rest of the network.
+ */
+int
+virDomainInterfaceStopDevices(virDomainDef *def)
+{
+ size_t i;
+
+ for (i = 0; i < def->nnets; i++) {
+ if (virDomainInterfaceStopDevice(def->nets[i]) < 0)
+ return -1;
+ }
+ return 0;
+}
diff --git a/src/hypervisor/domain_interface.h b/src/hypervisor/domain_interface.h
new file mode 100644
index 0000000000..68bf2ae51d
--- /dev/null
+++ b/src/hypervisor/domain_interface.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2015-2016 Red Hat, Inc.
+ * Copyright IBM Corp. 2014
+ *
+ * domain_interface.h: methods to manage guest/domain interfaces
+ *
+ * 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 "virebtables.h"
+
+int
+virDomainInterfaceEthernetConnect(virDomainDef *def,
+ virDomainNetDef *net,
+ ebtablesContext *ebtables,
+ bool macFilter,
+ bool privileged,
+ int *tapfd,
+ size_t tapfdSize);
+
+bool
+virDomainInterfaceIsVnetCompatModel(const virDomainNetDef *net);
+
+int virDomainInterfaceStartDevice(virDomainNetDef *net);
+int virDomainInterfaceStartDevices(virDomainDef *def);
+int virDomainInterfaceStopDevice(virDomainNetDef *net);
+int virDomainInterfaceStopDevices(virDomainDef *def);
diff --git a/src/hypervisor/meson.build b/src/hypervisor/meson.build
index f35565b16b..819a9a82a2 100644
--- a/src/hypervisor/meson.build
+++ b/src/hypervisor/meson.build
@@ -1,6 +1,7 @@
hypervisor_sources = [
'domain_cgroup.c',
'domain_driver.c',
+ 'domain_interface.c',
'virclosecallbacks.c',
'virhostdev.c',
]
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 553b01b8c0..b7f329be43 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -1630,6 +1630,14 @@ virDomainDriverNodeDeviceReset;
virDomainDriverParseBlkioDeviceStr;
virDomainDriverSetupPersistentDefBlkioParams;
+# hypervisor/domain_interface.h
+virDomainInterfaceEthernetConnect;
+virDomainInterfaceIsVnetCompatModel;
+virDomainInterfaceStartDevice;
+virDomainInterfaceStartDevices;
+virDomainInterfaceStopDevice;
+virDomainInterfaceStopDevices;
+
# hypervisor/virclosecallbacks.h
virCloseCallbacksDomainAdd;
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index fd0f12f304..036f6ba2e5 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -43,6 +43,7 @@
#include "domain_nwfilter.h"
#include "domain_addr.h"
#include "domain_conf.h"
+#include "domain_interface.h"
#include "netdev_bandwidth_conf.h"
#include "virnetdevopenvswitch.h"
#include "device_conf.h"
@@ -8505,7 +8506,10 @@ qemuBuildInterfaceConnect(virDomainObj *vm,
break;
case VIR_DOMAIN_NET_TYPE_ETHERNET:
- if (qemuInterfaceEthernetConnect(vm->def, priv->driver, net,
+ if (virDomainInterfaceEthernetConnect(vm->def, net,
+ priv->driver->ebtables,
+ priv->driver->config->macFilter,
+ priv->driver->privileged,
tapfd, tapfdSize) < 0)
return -1;
vhostfd = true;
diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c
index fec7c4be4e..63a130c201 100644
--- a/src/qemu/qemu_hotplug.c
+++ b/src/qemu/qemu_hotplug.c
@@ -39,6 +39,7 @@
#include "qemu_virtiofs.h"
#include "domain_audit.h"
#include "domain_cgroup.h"
+#include "domain_interface.h"
#include "netdev_bandwidth_conf.h"
#include "domain_nwfilter.h"
#include "virlog.h"
@@ -1272,7 +1273,7 @@ qemuDomainAttachNetDevice(virQEMUDriver *driver,
}
/* Set device online immediately */
- if (qemuInterfaceStartDevice(net) < 0)
+ if (virDomainInterfaceStartDevice(net) < 0)
goto cleanup;
qemuDomainInterfaceSetDefaultQDisc(driver, net);
@@ -4772,7 +4773,7 @@ qemuDomainRemoveNetDevice(virQEMUDriver *driver,
* affect the parent device (e.g. macvtap passthrough mode sets
* the parent device offline)
*/
- ignore_value(qemuInterfaceStopDevice(net));
+ ignore_value(virDomainInterfaceStopDevice(net));
qemuDomainObjEnterMonitor(vm);
if (qemuMonitorRemoveNetdev(priv->mon, hostnet_name) < 0) {
diff --git a/src/qemu/qemu_interface.c b/src/qemu/qemu_interface.c
index 8856bb95a8..c2007c7043 100644
--- a/src/qemu/qemu_interface.c
+++ b/src/qemu/qemu_interface.c
@@ -24,6 +24,7 @@
#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"
@@ -41,211 +42,6 @@
VIR_LOG_INIT("qemu.qemu_interface");
-/**
- * qemuInterfaceStartDevice:
- * @net: net device to start
- *
- * Based upon the type of device provided, perform the appropriate
- * work to completely activate the device and make it reachable from
- * the rest of the network.
- */
-int
-qemuInterfaceStartDevice(virDomainNetDef *net)
-{
- virDomainNetType actualType = virDomainNetGetActualType(net);
-
- switch (actualType) {
- case VIR_DOMAIN_NET_TYPE_BRIDGE:
- case VIR_DOMAIN_NET_TYPE_NETWORK:
- if (virDomainNetGetActualBridgeMACTableManager(net)
- == VIR_NETWORK_BRIDGE_MAC_TABLE_MANAGER_LIBVIRT) {
- /* libvirt is managing the FDB of the bridge this device
- * is attaching to, so we have turned off learning and
- * unicast_flood on the device to prevent the kernel from
- * adding any FDB entries for it. This means we need to
- * add an fdb entry ourselves, using the MAC address from
- * the interface config.
- */
- if (virNetDevBridgeFDBAdd(&net->mac, net->ifname,
- VIR_NETDEVBRIDGE_FDB_FLAG_MASTER |
- VIR_NETDEVBRIDGE_FDB_FLAG_TEMP) < 0)
- return -1;
- }
- break;
-
- case VIR_DOMAIN_NET_TYPE_DIRECT: {
- const char *physdev = virDomainNetGetActualDirectDev(net);
- bool isOnline = true;
-
- /* set the physdev online if necessary. It may already be up,
- * in which case we shouldn't re-up it just in case that causes
- * some sort of "blip" in the physdev's status.
- */
- if (physdev && virNetDevGetOnline(physdev, &isOnline) < 0)
- return -1;
- if (!isOnline && virNetDevSetOnline(physdev, true) < 0)
- return -1;
-
- /* macvtap devices share their MAC address with the guest
- * domain, and if they are set online prior to the domain CPUs
- * being started, the host may send out traffic from this
- * device that could confuse other entities on the network (in
- * particular, if this new domain is the destination of a
- * migration, and the source domain is still running, another
- * host may mistakenly direct traffic for the guest to the
- * destination domain rather than source domain). To prevent
- * this, we create the macvtap device with IFF_UP false
- * (i.e. "offline") then wait to bring it online until just as
- * we are starting the domain CPUs.
- */
- if (virNetDevSetOnline(net->ifname, true) < 0)
- return -1;
- break;
- }
-
- case VIR_DOMAIN_NET_TYPE_ETHERNET:
- if (virNetDevIPInfoAddToDev(net->ifname, &net->hostIP) < 0)
- return -1;
-
- break;
-
- case VIR_DOMAIN_NET_TYPE_USER:
- case VIR_DOMAIN_NET_TYPE_VHOSTUSER:
- case VIR_DOMAIN_NET_TYPE_SERVER:
- case VIR_DOMAIN_NET_TYPE_CLIENT:
- case VIR_DOMAIN_NET_TYPE_MCAST:
- case VIR_DOMAIN_NET_TYPE_UDP:
- case VIR_DOMAIN_NET_TYPE_INTERNAL:
- case VIR_DOMAIN_NET_TYPE_HOSTDEV:
- case VIR_DOMAIN_NET_TYPE_VDPA:
- case VIR_DOMAIN_NET_TYPE_NULL:
- case VIR_DOMAIN_NET_TYPE_VDS:
- case VIR_DOMAIN_NET_TYPE_LAST:
- /* these types all require no action */
- break;
- }
-
- return 0;
-}
-
-/**
- * qemuInterfaceStartDevices:
- * @def: domain definition
- *
- * Set all ifaces associated with this domain to the online state.
- */
-int
-qemuInterfaceStartDevices(virDomainDef *def)
-{
- size_t i;
-
- for (i = 0; i < def->nnets; i++) {
- if (qemuInterfaceStartDevice(def->nets[i]) < 0)
- return -1;
- }
- return 0;
-}
-
-
-/**
- * qemuInterfaceStopDevice:
- * @net: net device to stop
- *
- * Based upon the type of device provided, perform the appropriate
- * work to deactivate the device so that packets aren't forwarded to
- * it from the rest of the network.
- */
-int
-qemuInterfaceStopDevice(virDomainNetDef *net)
-{
- virDomainNetType actualType = virDomainNetGetActualType(net);
-
- switch (actualType) {
- case VIR_DOMAIN_NET_TYPE_BRIDGE:
- case VIR_DOMAIN_NET_TYPE_NETWORK:
- if (virDomainNetGetActualBridgeMACTableManager(net)
- == VIR_NETWORK_BRIDGE_MAC_TABLE_MANAGER_LIBVIRT) {
- /* remove the FDB entries that were added during
- * qemuInterfaceStartDevices()
- */
- if (virNetDevBridgeFDBDel(&net->mac, net->ifname,
- VIR_NETDEVBRIDGE_FDB_FLAG_MASTER |
- VIR_NETDEVBRIDGE_FDB_FLAG_TEMP) < 0)
- return -1;
- }
- break;
-
- case VIR_DOMAIN_NET_TYPE_DIRECT: {
- const char *physdev = virDomainNetGetActualDirectDev(net);
-
- /* macvtap interfaces need to be marked !IFF_UP (ie "down") to
- * prevent any host-generated traffic sent from this interface
- * from putting bad info into the arp caches of other machines
- * on this network.
- */
- if (virNetDevSetOnline(net->ifname, false) < 0)
- return -1;
-
- /* also mark the physdev down for passthrough macvtap, as the
- * physdev has the same MAC address as the macvtap device.
- */
- if (virDomainNetGetActualDirectMode(net) ==
- VIR_NETDEV_MACVLAN_MODE_PASSTHRU &&
- physdev && virNetDevSetOnline(physdev, false) < 0)
- return -1;
- break;
- }
-
- case VIR_DOMAIN_NET_TYPE_ETHERNET:
- case VIR_DOMAIN_NET_TYPE_USER:
- case VIR_DOMAIN_NET_TYPE_VHOSTUSER:
- case VIR_DOMAIN_NET_TYPE_SERVER:
- case VIR_DOMAIN_NET_TYPE_CLIENT:
- case VIR_DOMAIN_NET_TYPE_MCAST:
- case VIR_DOMAIN_NET_TYPE_UDP:
- case VIR_DOMAIN_NET_TYPE_INTERNAL:
- case VIR_DOMAIN_NET_TYPE_HOSTDEV:
- case VIR_DOMAIN_NET_TYPE_VDPA:
- case VIR_DOMAIN_NET_TYPE_NULL:
- case VIR_DOMAIN_NET_TYPE_VDS:
- case VIR_DOMAIN_NET_TYPE_LAST:
- /* these types all require no action */
- break;
- }
-
- return 0;
-}
-
-/**
- * qemuInterfaceStopDevices:
- * @def: domain definition
- *
- * Make all interfaces associated with this domain inaccessible from
- * the rest of the network.
- */
-int
-qemuInterfaceStopDevices(virDomainDef *def)
-{
- size_t i;
-
- for (i = 0; i < def->nnets; i++) {
- if (qemuInterfaceStopDevice(def->nets[i]) < 0)
- return -1;
- }
- return 0;
-}
-
-
-static bool
-qemuInterfaceIsVnetCompatModel(const virDomainNetDef *net)
-{
- return (virDomainNetIsVirtioModel(net) ||
- net->model == VIR_DOMAIN_NET_MODEL_E1000E ||
- net->model == VIR_DOMAIN_NET_MODEL_IGB ||
- net->model == VIR_DOMAIN_NET_MODEL_VMXNET3);
-}
-
-
/**
* qemuInterfaceDirectConnect:
* @def: the definition of the VM (needed by 802.1Qbh and audit)
@@ -271,7 +67,7 @@ qemuInterfaceDirectConnect(virDomainDef *def,
unsigned int macvlan_create_flags = VIR_NETDEV_MACVLAN_CREATE_WITH_TAP;
qemuDomainNetworkPrivate *netpriv = QEMU_DOMAIN_NETWORK_PRIVATE(net);
- if (qemuInterfaceIsVnetCompatModel(net))
+ if (virDomainInterfaceIsVnetCompatModel(net))
macvlan_create_flags |= VIR_NETDEV_MACVLAN_VNET_HDR;
if (virNetDevMacVLanCreateWithVPortProfile(net->ifname,
@@ -409,133 +205,6 @@ qemuCreateInBridgePortWithHelper(virQEMUDriverConfig *cfg,
return *tapfd < 0 ? -1 : 0;
}
-
-/* qemuInterfaceEthernetConnect:
- * @def: the definition of the VM
- * @driver: qemu driver data
- * @net: pointer to the VM's interface description
- * @tapfd: array of file descriptor return value for the new device
- * @tapfdsize: number of file descriptors in @tapfd
- *
- * Called *only* called if actualType is VIR_DOMAIN_NET_TYPE_ETHERNET
- * (i.e. if the connection is made with a tap device)
- */
-int
-qemuInterfaceEthernetConnect(virDomainDef *def,
- virQEMUDriver *driver,
- virDomainNetDef *net,
- int *tapfd,
- size_t tapfdSize)
-{
- virMacAddr tapmac;
- int ret = -1;
- unsigned int tap_create_flags = VIR_NETDEV_TAP_CREATE_IFUP;
- bool template_ifname = false;
- g_autoptr(virQEMUDriverConfig) cfg = virQEMUDriverGetConfig(driver);
- const char *tunpath = "/dev/net/tun";
- const char *auditdev = tunpath;
-
- if (net->backend.tap) {
- tunpath = net->backend.tap;
- if (!driver->privileged) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
- _("cannot use custom tap device in session mode"));
- goto cleanup;
- }
- }
-
- if (qemuInterfaceIsVnetCompatModel(net))
- tap_create_flags |= VIR_NETDEV_TAP_CREATE_VNET_HDR;
-
- if (net->managed_tap == VIR_TRISTATE_BOOL_NO) {
- if (!net->ifname) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
- _("target dev must be supplied when managed='no'"));
- goto cleanup;
- }
- if (virNetDevExists(net->ifname) != 1) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
- _("target managed='no' but specified dev doesn't exist"));
- goto cleanup;
- }
-
- tap_create_flags |= VIR_NETDEV_TAP_CREATE_ALLOW_EXISTING;
-
- if (virNetDevMacVLanIsMacvtap(net->ifname)) {
- auditdev = net->ifname;
- if (virNetDevMacVLanTapOpen(net->ifname, tapfd, tapfdSize) < 0)
- goto cleanup;
- if (virNetDevMacVLanTapSetup(tapfd, tapfdSize,
- qemuInterfaceIsVnetCompatModel(net)) < 0) {
- goto cleanup;
- }
- } else {
- if (virNetDevTapCreate(&net->ifname, tunpath, tapfd, tapfdSize,
- tap_create_flags) < 0)
- goto cleanup;
- }
- } else {
-
- if (!net->ifname)
- template_ifname = true;
-
- if (virNetDevTapCreate(&net->ifname, tunpath, tapfd, tapfdSize,
- tap_create_flags) < 0) {
- goto cleanup;
- }
-
- /* The tap device's MAC address cannot match the MAC address
- * used by the guest. This results in "received packet on
- * vnetX with own address as source address" error logs from
- * the kernel.
- */
- virMacAddrSet(&tapmac, &net->mac);
- if (tapmac.addr[0] == 0xFE)
- tapmac.addr[0] = 0xFA;
- else
- tapmac.addr[0] = 0xFE;
-
- if (virNetDevSetMAC(net->ifname, &tapmac) < 0)
- goto cleanup;
-
- if (virNetDevSetOnline(net->ifname, true) < 0)
- goto cleanup;
- }
-
- if (net->script &&
- virNetDevRunEthernetScript(net->ifname, net->script) < 0)
- goto cleanup;
-
- if (cfg->macFilter &&
- ebtablesAddForwardAllowIn(driver->ebtables,
- net->ifname,
- &net->mac) < 0)
- goto cleanup;
-
- if (net->filter &&
- virDomainConfNWFilterInstantiate(def->name, def->uuid, net, false) < 0) {
- goto cleanup;
- }
-
- virDomainAuditNetDevice(def, net, auditdev, true);
-
- ret = 0;
-
- cleanup:
- if (ret < 0) {
- size_t i;
-
- virDomainAuditNetDevice(def, net, auditdev, false);
- for (i = 0; i < tapfdSize && tapfd[i] >= 0; i++)
- VIR_FORCE_CLOSE(tapfd[i]);
- if (template_ifname)
- VIR_FREE(net->ifname);
- }
-
- return ret;
-}
-
-
/* qemuInterfaceBridgeConnect:
* @def: the definition of the VM
* @driver: qemu driver data
@@ -578,7 +247,7 @@ qemuInterfaceBridgeConnect(virDomainDef *def,
if (!net->ifname)
template_ifname = true;
- if (qemuInterfaceIsVnetCompatModel(net))
+ if (virDomainInterfaceIsVnetCompatModel(net))
tap_create_flags |= VIR_NETDEV_TAP_CREATE_VNET_HDR;
if (driver->privileged) {
@@ -598,7 +267,7 @@ qemuInterfaceBridgeConnect(virDomainDef *def,
* is attaching to, so we need to turn off learning and
* unicast_flood on the device to prevent the kernel from
* adding any FDB entries for it. We will add an fdb
- * entry ourselves (during qemuInterfaceStartDevices(),
+ * entry ourselves (during virDomainInterfaceStartDevices(),
* using the MAC address from the interface config.
*/
if (virNetDevBridgePortSetLearning(brname, net->ifname, false) < 0)
diff --git a/src/qemu/qemu_interface.h b/src/qemu/qemu_interface.h
index 6eed3e6bd7..47d7ec03fd 100644
--- a/src/qemu/qemu_interface.h
+++ b/src/qemu/qemu_interface.h
@@ -25,11 +25,6 @@
#include "qemu_domain.h"
#include "qemu_slirp.h"
-int qemuInterfaceStartDevice(virDomainNetDef *net);
-int qemuInterfaceStartDevices(virDomainDef *def);
-int qemuInterfaceStopDevice(virDomainNetDef *net);
-int qemuInterfaceStopDevices(virDomainDef *def);
-
int qemuInterfaceDirectConnect(virDomainDef *def,
virQEMUDriver *driver,
virDomainNetDef *net,
@@ -37,12 +32,6 @@ int qemuInterfaceDirectConnect(virDomainDef *def,
size_t tapfdSize,
virNetDevVPortProfileOp vmop);
-int qemuInterfaceEthernetConnect(virDomainDef *def,
- virQEMUDriver *driver,
- virDomainNetDef *net,
- int *tapfd,
- size_t tapfdSize);
-
int qemuInterfaceBridgeConnect(virDomainDef *def,
virQEMUDriver *driver,
virDomainNetDef *net,
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
index 1ef032dbd2..1626f368bd 100644
--- a/src/qemu/qemu_process.c
+++ b/src/qemu/qemu_process.c
@@ -74,6 +74,7 @@
#include "virhostcpu.h"
#include "domain_audit.h"
#include "domain_cgroup.h"
+#include "domain_interface.h"
#include "domain_nwfilter.h"
#include "domain_postparse.h"
#include "domain_validate.h"
@@ -3121,7 +3122,7 @@ qemuProcessStartCPUs(virQEMUDriver *driver, virDomainObj *vm,
g_autoptr(virQEMUDriverConfig) cfg = virQEMUDriverGetConfig(driver);
/* Bring up netdevs before starting CPUs */
- if (qemuInterfaceStartDevices(vm->def) < 0)
+ if (virDomainInterfaceStartDevices(vm->def) < 0)
return -1;
VIR_DEBUG("Using lock state '%s'", NULLSTR(priv->lockState));
@@ -3184,7 +3185,7 @@ int qemuProcessStopCPUs(virQEMUDriver *driver,
goto cleanup;
/* de-activate netdevs after stopping CPUs */
- ignore_value(qemuInterfaceStopDevices(vm->def));
+ ignore_value(virDomainInterfaceStopDevices(vm->def));
if (vm->job->current)
ignore_value(virTimeMillisNow(&vm->job->current->stopped));
--
2.41.0
6 months, 1 week
[PATCH V2] support for hotplug/hotunplug in test hypervisor
by Thanos Makatos
Signed-off-by: Thanos Makatos <thanos.makatos(a)nutanix.com>
---
src/test/test_driver.c | 59 ++++++++++++++++++++++++++++++++++++++++++
1 file changed, 59 insertions(+)
diff --git a/src/test/test_driver.c b/src/test/test_driver.c
index e87d7cfd44..80ef1b3cbb 100644
--- a/src/test/test_driver.c
+++ b/src/test/test_driver.c
@@ -10035,6 +10035,62 @@ testConnectGetDomainCapabilities(virConnectPtr conn G_GNUC_UNUSED,
return virDomainCapsFormat(domCaps);
}
+static int
+testVirDomainAttachDeviceFlags(virDomainPtr domain,
+ const char *xml,
+ unsigned int flags G_GNUC_UNUSED) {
+
+ int ret = -1;
+ virDomainObj *vm;
+ testDriver *driver;
+ virDomainDeviceDef *devConf;
+
+ if (!(vm = testDomObjFromDomain(domain)))
+ return -1;
+
+ driver = domain->conn->privateData;
+
+ if (!(devConf = virDomainDeviceDefParse(xml, vm->def, driver->xmlopt,
+ NULL, 0)))
+ goto out;
+
+ VIR_APPEND_ELEMENT(vm->def->hostdevs, vm->def->nhostdevs,
+ devConf->data.hostdev);
+ virDomainDeviceDefFree(devConf);
+ ret = 0;
+out:
+ virDomainObjEndAPI(&vm);
+ return ret;
+}
+
+static int
+testVirDomainAttachDevice(virDomainPtr domain, const char *xml)
+{
+ return testVirDomainAttachDeviceFlags(domain, xml, 0);
+}
+
+static int
+testVirDomainDetachDeviceAlias(virDomainPtr domain,
+ const char *alias,
+ unsigned int flags G_GNUC_UNUSED)
+{
+ virDomainObj *vm;
+ int size_t;
+ bool found = false;
+
+ if (!(vm = testDomObjFromDomain(domain)))
+ return -1;
+
+ for (i = 0; i < vm->def->nhostdevs && !found; i++) {
+ if (!strcmp(vm->def->hostdevs[i]->info->alias, alias)) {
+ virDomainHostdevDefFree(vm->def->hostdevs[i]);
+ VIR_DELETE_ELEMENT(vm->def->hostdevs, i, vm->def->nhostdevs);
+ found = true;
+ }
+ }
+ virDomainObjEndAPI(&vm);
+ return found ? 0 : -1;
+}
/*
* Test driver
@@ -10058,6 +10114,9 @@ static virHypervisorDriver testHypervisorDriver = {
.connectListDomains = testConnectListDomains, /* 0.1.1 */
.connectNumOfDomains = testConnectNumOfDomains, /* 0.1.1 */
.connectListAllDomains = testConnectListAllDomains, /* 0.9.13 */
+ .domainAttachDevice = testVirDomainAttachDevice, /* 9.9.0 */
+ .domainAttachDeviceFlags = testVirDomainAttachDeviceFlags, /* 9.9.0 */
+ .domainDetachDeviceAlias = testVirDomainDetachDeviceAlias, /* 9.9.0 */
.domainCreateXML = testDomainCreateXML, /* 0.1.4 */
.domainCreateXMLWithFiles = testDomainCreateXMLWithFiles, /* 5.7.0 */
.domainLookupByID = testDomainLookupByID, /* 0.1.1 */
--
2.27.0
6 months, 1 week
RE: [PATCH] support for hotplug/hotunplug in test hypervisor
by Thanos Makatos
> -----Original Message-----
> From: Daniel P. Berrangé <berrange(a)redhat.com>
> Sent: Friday, October 27, 2023 6:13 PM
> To: Thanos Makatos <thanos.makatos(a)nutanix.com>
> Cc: devel(a)lists.libvirt.org
> Subject: Re: [PATCH] support for hotplug/hotunplug in test hypervisor
>
> On Fri, Oct 27, 2023 at 03:44:13PM +0000, Thanos Makatos wrote:
> > Signed-off-by: Thanos Makatos <thanos.makatos(a)nutanix.com>
> > ---
> > src/test/test_driver.c | 61
> ++++++++++++++++++++++++++++++++++++++++--
> > 1 file changed, 59 insertions(+), 2 deletions(-)
> >
> > diff --git a/src/test/test_driver.c b/src/test/test_driver.c
> > index e87d7cfd44..6eda0dcc01 100644
> > --- a/src/test/test_driver.c
> > +++ b/src/test/test_driver.c
> > @@ -26,8 +26,6 @@
> > #include <unistd.h>
> > #include <sys/stat.h>
> > #include <libxml/xmlsave.h>
> > -
> > -
>
> Unrelated whitespace change.
Ack
>
> > #include "virerror.h"
> > #include "datatypes.h"
> > #include "test_driver.h"
> > @@ -10035,6 +10033,62 @@
> testConnectGetDomainCapabilities(virConnectPtr conn G_GNUC_UNUSED,
> > return virDomainCapsFormat(domCaps);
> > }
> >
> > +static int
> > +testVirDomainAttachDeviceFlags(virDomainPtr domain,
> > + const char *xml,
> > + unsigned int flags G_GNUC_UNUSED) {
> > +
> > + int ret = -1;
> > + virDomainObj *vm;
> > + testDriver *driver;
> > + virDomainDeviceDef *devConf;
> > +
> > + if (!(vm = testDomObjFromDomain(domain)))
> > + return -1;
> > +
> > + driver = domain->conn->privateData;
> > +
> > + if (!(devConf = virDomainDeviceDefParse(xml, vm->def, driver->xmlopt,
> > + NULL, 0)))
> > + goto out;
> > +
> > + VIR_APPEND_ELEMENT(vm->def->hostdevs, vm->def->nhostdevs,
> > + devConf->data.hostdev);
>
> Aling 'devConf' with the '(' above it
Ack
>
> > + virDomainDeviceDefFree(devConf);
> > + ret = 0;
> > +out:
> > + virDomainObjEndAPI(&vm);
> > + return ret;
> > +}
> > +
> > +static int
> > +testVirDomainAttachDevice(virDomainPtr domain, const char *xml)
> > +{
> > + return testVirDomainAttachDeviceFlags(domain, xml, 0);
> > +}
> > +
> > +static int
> > +testVirDomainDetachDeviceAlias(virDomainPtr domain,
> > + const char *alias,
> > + unsigned int flags __attribute__((unused)))
>
> Horizontal alignemtn is off, and also needs to be G_GNUC_UNUSED
> like the earlier method.
Ack
>
> > +{
> > + virDomainObj *vm;
> > + int i;
>
> size_t for loop iterators please.
Ack
>
> > + bool found = false;
> > +
> > + if (!(vm = testDomObjFromDomain(domain)))
> > + return -1;
> > +
> > + for (i = 0; i < vm->def->nhostdevs && !found; i++) {
> > + if (!strcmp(vm->def->hostdevs[i]->info->alias, alias)) {
> > + virDomainHostdevDefFree(vm->def->hostdevs[i]);
> > + VIR_DELETE_ELEMENT(vm->def->hostdevs, i, vm->def->nhostdevs);
> > + found = true;
> > + }
> > + }
> > + virDomainObjEndAPI(&vm);
> > + return found ? 0 : -1;
> > +}
> >
> > /*
> > * Test driver
> > @@ -10058,6 +10112,9 @@ static virHypervisorDriver testHypervisorDriver =
> {
> > .connectListDomains = testConnectListDomains, /* 0.1.1 */
> > .connectNumOfDomains = testConnectNumOfDomains, /* 0.1.1 */
> > .connectListAllDomains = testConnectListAllDomains, /* 0.9.13 */
> > + .domainAttachDevice = testVirDomainAttachDevice, /* 9.9.0 */
> > + .domainAttachDeviceFlags = testVirDomainAttachDeviceFlags, /* 9.9.0 */
> > + .domainDetachDeviceAlias = testVirDomainDetachDeviceAlias, /* 9.9.0 */
> > .domainCreateXML = testDomainCreateXML, /* 0.1.4 */
> > .domainCreateXMLWithFiles = testDomainCreateXMLWithFiles, /* 5.7.0 */
> > .domainLookupByID = testDomainLookupByID, /* 0.1.1 */
> > --
> > 2.27.0
> >
>
> With regards,
> Daniel
> --
> |: https://urldefense.proofpoint.com/v2/url?u=https-
> 3A__berrange.com&d=DwIBaQ&c=s883GpUCOChKOHiocYtGcg&r=XTpYsh5Ps2zJ
> vtw6ogtti46atk736SI4vgsJiUKIyDE&m=7tOGBG0mrTLgztzu23pWZjCQpfdKbv7cV
> ilnYobvnzJSHk-
> m3fVMonE71FEjfJUc&s=MKxz2dbrxpoqVQEKrR1rIHTDNh3TQzk6j9ILpLJO4eI&e
> = -o- https://urldefense.proofpoint.com/v2/url?u=https-
> 3A__www.flickr.com_photos_dberrange&d=DwIBaQ&c=s883GpUCOChKOHiocYt
> Gcg&r=XTpYsh5Ps2zJvtw6ogtti46atk736SI4vgsJiUKIyDE&m=7tOGBG0mrTLgztzu
> 23pWZjCQpfdKbv7cVilnYobvnzJSHk-m3fVMonE71FEjfJUc&s=yYyWxbabM-
> x_RY69yLXObz2p8wo1OAy4DioA0YScDYc&e= :|
> |: https://urldefense.proofpoint.com/v2/url?u=https-
> 3A__libvirt.org&d=DwIBaQ&c=s883GpUCOChKOHiocYtGcg&r=XTpYsh5Ps2zJvtw
> 6ogtti46atk736SI4vgsJiUKIyDE&m=7tOGBG0mrTLgztzu23pWZjCQpfdKbv7cVilnY
> obvnzJSHk-
> m3fVMonE71FEjfJUc&s=YVwYpdMFSWcMfQ2sM9QgKFheo9Dxq8s4_sFI0KfGqu
> o&e= -o- https://urldefense.proofpoint.com/v2/url?u=https-
> 3A__fstop138.berrange.com&d=DwIBaQ&c=s883GpUCOChKOHiocYtGcg&r=XTp
> Ysh5Ps2zJvtw6ogtti46atk736SI4vgsJiUKIyDE&m=7tOGBG0mrTLgztzu23pWZjCQ
> pfdKbv7cVilnYobvnzJSHk-m3fVMonE71FEjfJUc&s=-
> C8ZIdR8IJmdjdVJljDjhjVC4UiJcAeuiWQ-B_dV4wM&e= :|
> |: https://urldefense.proofpoint.com/v2/url?u=https-3A__entangle-
> 2Dphoto.org&d=DwIBaQ&c=s883GpUCOChKOHiocYtGcg&r=XTpYsh5Ps2zJvtw6o
> gtti46atk736SI4vgsJiUKIyDE&m=7tOGBG0mrTLgztzu23pWZjCQpfdKbv7cVilnYob
> vnzJSHk-
> m3fVMonE71FEjfJUc&s=BgvlBMRgX56LJG0ZSE02GviPHpVTcQ_Nx1N3aEWk9d4
> &e= -o- https://urldefense.proofpoint.com/v2/url?u=https-
> 3A__www.instagram.com_dberrange&d=DwIBaQ&c=s883GpUCOChKOHiocYtGc
> g&r=XTpYsh5Ps2zJvtw6ogtti46atk736SI4vgsJiUKIyDE&m=7tOGBG0mrTLgztzu23
> pWZjCQpfdKbv7cVilnYobvnzJSHk-m3fVMonE71FEjfJUc&s=g23VsTOOhoOdgm-
> cJyiOixKvywYEQXh-L7sRK8YPm90&e= :|
6 months, 1 week