render / rpms / libvirt

Forked from rpms/libvirt 10 months ago
Clone
Blob Blame History Raw
From 54e270d7fb68b41002654374d395e4f260a24add Mon Sep 17 00:00:00 2001
Message-Id: <54e270d7fb68b41002654374d395e4f260a24add@dist-git>
From: Laine Stump <laine@redhat.com>
Date: Mon, 15 Oct 2018 20:31:02 -0400
Subject: [PATCH] RHEL: network: regain guest network connectivity after
 firewalld switch to nftables
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

This is a DOWNSTREAM ONLY patch to temporarily get back guest network
connectivity while still allowing the firewalld backend to use
nftables (which is the default with RHEL8).

The circumstances that cause the problem:

In the past (when both libvirt and firewalld used iptables), if either
libvirt's rules *OR* firewalld's rules accepted a packet, it would be
accepted.

But now firewalld uses nftables for its backend, while libvirt's
firewall rules are still using iptables; iptables rules are still
processed, but at a different time during packet processing than the
firewalld nftables hooks. The result is that a packet must be accepted
by *BOTH* the libvirt iptables rules *AND* the firewalld nftable rules
in order to be accepted.

This causes pain for two types of traffic:

1) libvirt always adds rules to permit DNS and DHCP (and sometimes
TFTP) from guests to the host. But libvirt's bridges are in
firewalld's "default" zone (which is usually the zone called
"public"). The public zone allows ssh, but doesn't allow DNS, DHCP, or
TFTP. So guests connected to libvirt's bridges can't acquire an IP
address from DHCP, nor can they make DNS queries to the DNS server
libvirt has setup on the host.

2) firewalld's higher level "rich rules" don't yet have the ability to
configure the acceptance of forwarded traffic (traffic that is going
somewhere beyond the host), so any traffic that needs to be forwarded
is rejected.

libvirt can't send "direct" nftables rules (firewalld only supports
that for iptables), so we can't solve this problem by just sending
direct nftables rules instead of iptables rules.

However, we can take advantage of a quirk in firewalld zones that have
a default policy of accept (meaning any packet that doesn't match a
specific rule in the zone will be accepted) - this default accept will
also accept forwarded traffic (not just traffic destined for the host).

So, as a temporary solution to get all network traffic flowing, this
patch creates a new firewalld zone called "libvirt" which is setup to
include interfaces named virbr0-virbr9, and has a default policy of
accept. With this zone installed, libvirt networks that use the names
virbr0-virbr9 will have *all* their traffic accepted, both to the host
and to/from the rest of the network.

firewalld zones can't normally be added to the runtime config of
firewalld, so we have to reload all of the permanent config for it to
be recognized. This is done with a call to "firewall-cmd --reload"
during postinstall and postuninstall. In the case that firewalld is
inactive, firewall-cmd exits without doing anything (i.e. it doesn't
start up firewalld.service if it's not already started).

This obviously can't be a permanent solution, since it allows guests
to have access to *all* services on the host. However, it doesn't
allow QE and beta testers to test firewalld with an nftables backend
(which is important for firewalld and nftables devs) without breaking
network connectivity for libvirt managed virtual machines (so testing
of those can also take place.

Resolves: https://bugzilla.redhat.com/1638864

This problem is discussed in more detail in this message thread:

https://post-office.corp.redhat.com/mailman/private/virt-devel/2018-September/msg00145.html
https://post-office.corp.redhat.com/mailman/private/virt-devel/2018-October/msg00042.html

and in the BZ assigned to firewalld: https://bugzilla.redhat.com/1623841

Signed-off-by: Laine Stump <laine@laine.org>
Acked-by: Daniel P. Berrangé <berrange@redhat.com>
Reviewed-by: Jiri Denemark <jdenemar@redhat.com>
---
 libvirt.spec.in             | 14 ++++++++++++++
 src/network/Makefile.inc.am | 10 +++++++++-
 src/network/libvirt.zone    | 15 +++++++++++++++
 3 files changed, 38 insertions(+), 1 deletion(-)
 create mode 100644 src/network/libvirt.zone

diff --git a/src/network/Makefile.inc.am b/src/network/Makefile.inc.am
index 508c8c0422..20d899e699 100644
--- a/src/network/Makefile.inc.am
+++ b/src/network/Makefile.inc.am
@@ -87,6 +87,11 @@ install-data-network:
 	( cd $(DESTDIR)$(confdir)/qemu/networks/autostart && \
 	  rm -f default.xml && \
 	  $(LN_S) ../default.xml default.xml )
+if HAVE_FIREWALLD
+	$(MKDIR_P) "$(DESTDIR)$(prefix)/lib/firewalld/zones"
+	$(INSTALL_DATA) $(srcdir)/network/libvirt.zone \
+	  $(DESTDIR)$(prefix)/lib/firewalld/zones/libvirt.xml
+endif HAVE_FIREWALLD
 
 uninstall-data-network:
 	rm -f $(DESTDIR)$(confdir)/qemu/networks/autostart/default.xml
@@ -95,10 +100,13 @@ uninstall-data-network:
 	rmdir "$(DESTDIR)$(confdir)/qemu/networks" || :
 	rmdir "$(DESTDIR)$(localstatedir)/lib/libvirt/network" ||:
 	rmdir "$(DESTDIR)$(localstatedir)/run/libvirt/network" ||:
+if HAVE_FIREWALLD
+	rm -f  $(DESTDIR)$(prefix)/lib/firewalld/zones/libvirt.xml
+endif HAVE_FIREWALLD
 
 endif WITH_NETWORK
 
-EXTRA_DIST += network/default.xml
+EXTRA_DIST += network/default.xml network/libvirt.zone
 
 .PHONY: \
 	install-data-network \
diff --git a/src/network/libvirt.zone b/src/network/libvirt.zone
new file mode 100644
index 0000000000..355a70b4da
--- /dev/null
+++ b/src/network/libvirt.zone
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<zone target="ACCEPT">
+  <short>libvirt</short>
+  <description>All network connections are accepted. This also permits packets to/from interfaces in the zone to be forwarded. This zone is intended to be used only by libvirt virtual networks.</description>
+  <interface name="virbr0"/>
+  <interface name="virbr1"/>
+  <interface name="virbr2"/>
+  <interface name="virbr3"/>
+  <interface name="virbr4"/>
+  <interface name="virbr5"/>
+  <interface name="virbr6"/>
+  <interface name="virbr7"/>
+  <interface name="virbr8"/>
+  <interface name="virbr9"/>
+</zone>
-- 
2.19.1