1
0
mirror of https://gitlab.com/libvirt/libvirt.git synced 2025-01-12 07:42:56 +00:00

network: support setting firewallBackend from network.conf

It still can have only one useful value ("iptables"), but once a 2nd
value is supported, it will be selectable by setting
"firewall_backend=nftables" in /etc/libvirt/network.conf.

If firewall_backend isn't set in network.conf, then libvirt will check
to see if FIREWALL_BACKEND_DEFAULT_1 is available and, if so, set
that. (Since FIREWALL_BACKEND_DEFAULT_1 is currently "iptables", this
means checking to see it the iptables binary is present on the
system).  If the default backend isn't available, that is considered a
fatal error (since no networks can be started anyway), so an error is
logged and startup of the network driver fails.

NB: network.conf is itself created from network.conf.in at build time,
and the advertised default setting of firewall_backend (in a commented
out line) is set from the meson_options.txt setting
"firewall_backend_default_1". This way the conf file will have correct
information no matter what ordering is chosen for default backend at
build time (as more backends are added, settings will be added for
"firewall_backend_default_n", and those will be settable in
meson_options.txt and on the meson commandline to change the ordering
of the auto-detection when no backend is set in network.conf).

virNetworkLoadDriverConfig() may look more complicated than necessary,
but as additional backends are added, it will be easier to add checks
for those backends (and to re-order the checks based on builders'
preferences).

Signed-off-by: Laine Stump <laine@redhat.com>
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
This commit is contained in:
Laine Stump 2024-04-19 22:19:42 -04:00
parent 45c4527f36
commit 64b966558c
13 changed files with 134 additions and 28 deletions

@ -1638,6 +1638,10 @@ endif
if not get_option('driver_network').disabled() and conf.has('WITH_LIBVIRTD')
conf.set('WITH_NETWORK', 1)
firewall_backend_default_1 = get_option('firewall_backend_default_1')
firewall_backend_default_conf = firewall_backend_default_1
firewall_backend_default_1 = 'VIR_FIREWALL_BACKEND_' + firewall_backend_default_1.to_upper()
conf.set('FIREWALL_BACKEND_DEFAULT_1', firewall_backend_default_1)
elif get_option('driver_network').enabled()
error('libvirtd must be enabled to build the network driver')
endif

@ -115,6 +115,7 @@ option('dtrace', type: 'feature', value: 'auto', description: 'use dtrace for st
option('firewalld', type: 'feature', value: 'auto', description: 'firewalld support')
# dep:firewalld
option('firewalld_zone', type: 'feature', value: 'auto', description: 'whether to install firewalld libvirt zone')
option('firewall_backend_default_1', type: 'string', value: 'iptables', description: 'first firewall backend to try when none is specified')
option('host_validate', type: 'feature', value: 'auto', description: 'build virt-host-validate')
option('init_script', type: 'combo', choices: ['systemd', 'openrc', 'check', 'none'], value: 'check', description: 'Style of init script to install')
option('loader_nvram', type: 'string', value: '', description: 'Pass list of pairs of <loader>:<nvram> paths. Both pairs and list items are separated by a colon.')

@ -1682,6 +1682,7 @@ static int
networkReloadFirewallRulesHelper(virNetworkObj *obj,
void *opaque G_GNUC_UNUSED)
{
g_autoptr(virNetworkDriverConfig) cfg = virNetworkDriverGetConfig(networkGetDriver());
VIR_LOCK_GUARD lock = virObjectLockGuard(obj);
virNetworkDef *def = virNetworkObjGetDef(obj);
@ -1695,8 +1696,8 @@ networkReloadFirewallRulesHelper(virNetworkObj *obj,
* network type, forward='open', doesn't need this because it
* has no iptables rules.
*/
networkRemoveFirewallRules(def);
ignore_value(networkAddFirewallRules(def));
networkRemoveFirewallRules(def, cfg->firewallBackend);
ignore_value(networkAddFirewallRules(def, cfg->firewallBackend));
break;
case VIR_NETWORK_FORWARD_OPEN:
@ -1948,7 +1949,7 @@ networkStartNetworkVirtual(virNetworkDriverState *driver,
/* Add "once per network" rules */
if (def->forward.type != VIR_NETWORK_FORWARD_OPEN &&
networkAddFirewallRules(def) < 0)
networkAddFirewallRules(def, cfg->firewallBackend) < 0)
goto error;
firewalRulesAdded = true;
@ -2066,7 +2067,7 @@ networkStartNetworkVirtual(virNetworkDriverState *driver,
if (firewalRulesAdded &&
def->forward.type != VIR_NETWORK_FORWARD_OPEN)
networkRemoveFirewallRules(def);
networkRemoveFirewallRules(def, cfg->firewallBackend);
virNetworkObjUnrefMacMap(obj);
@ -2078,7 +2079,8 @@ networkStartNetworkVirtual(virNetworkDriverState *driver,
static int
networkShutdownNetworkVirtual(virNetworkObj *obj)
networkShutdownNetworkVirtual(virNetworkObj *obj,
virNetworkDriverConfig *cfg)
{
virNetworkDef *def = virNetworkObjGetDef(obj);
pid_t dnsmasqPid;
@ -2104,7 +2106,7 @@ networkShutdownNetworkVirtual(virNetworkObj *obj)
ignore_value(virNetDevSetOnline(def->bridge, false));
if (def->forward.type != VIR_NETWORK_FORWARD_OPEN)
networkRemoveFirewallRules(def);
networkRemoveFirewallRules(def, cfg->firewallBackend);
ignore_value(virNetDevBridgeDelete(def->bridge));
@ -2408,7 +2410,7 @@ networkShutdownNetwork(virNetworkDriverState *driver,
case VIR_NETWORK_FORWARD_NAT:
case VIR_NETWORK_FORWARD_ROUTE:
case VIR_NETWORK_FORWARD_OPEN:
ret = networkShutdownNetworkVirtual(obj);
ret = networkShutdownNetworkVirtual(obj, cfg);
break;
case VIR_NETWORK_FORWARD_BRIDGE:
@ -3259,7 +3261,7 @@ networkUpdate(virNetworkPtr net,
* old rules (and remember to load new ones after the
* update).
*/
networkRemoveFirewallRules(def);
networkRemoveFirewallRules(def, cfg->firewallBackend);
needFirewallRefresh = true;
break;
default:
@ -3287,14 +3289,14 @@ networkUpdate(virNetworkPtr net,
parentIndex, xml,
network_driver->xmlopt, flags) < 0) {
if (needFirewallRefresh)
ignore_value(networkAddFirewallRules(def));
ignore_value(networkAddFirewallRules(def, cfg->firewallBackend));
goto cleanup;
}
/* @def is replaced */
def = virNetworkObjGetDef(obj);
if (needFirewallRefresh && networkAddFirewallRules(def) < 0)
if (needFirewallRefresh && networkAddFirewallRules(def, cfg->firewallBackend) < 0)
goto cleanup;
if (flags & VIR_NETWORK_UPDATE_AFFECT_CONFIG) {

@ -25,6 +25,7 @@
#include "datatypes.h"
#include "virlog.h"
#include "virerror.h"
#include "virfile.h"
#include "virutil.h"
#include "bridge_driver_conf.h"
@ -32,7 +33,6 @@
VIR_LOG_INIT("network.bridge_driver");
static virClass *virNetworkDriverConfigClass;
static void virNetworkDriverConfigDispose(void *obj);
@ -62,18 +62,76 @@ virNetworkLoadDriverConfig(virNetworkDriverConfig *cfg G_GNUC_UNUSED,
const char *filename)
{
g_autoptr(virConf) conf = NULL;
g_autofree char *fwBackendStr = NULL;
bool fwBackendSelected = false;
size_t i;
int fwBackends[] = { FIREWALL_BACKEND_DEFAULT_1 };
G_STATIC_ASSERT(G_N_ELEMENTS(fwBackends) == VIR_FIREWALL_BACKEND_LAST);
int nFwBackends = G_N_ELEMENTS(fwBackends);
/* if file doesn't exist or is unreadable, ignore the "error" */
if (access(filename, R_OK) == -1)
if (access(filename, R_OK) == 0) {
conf = virConfReadFile(filename, 0);
if (!conf)
return -1;
/* use virConfGetValue*(conf, ...) functions to read any settings into cfg */
if (virConfGetValueString(conf, "firewall_backend", &fwBackendStr) < 0)
return -1;
if (fwBackendStr) {
fwBackends[0] = virFirewallBackendTypeFromString(fwBackendStr);
nFwBackends = 1;
if (fwBackends[0] < 0) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("unrecognized 'firewall_backend = '%1$s' set in network driver config file %2$s"),
fwBackendStr, filename);
return -1;
}
VIR_INFO("firewall_backend setting requested from config file %s: '%s'",
virFirewallBackendTypeToString(fwBackends[0]), filename);
}
}
for (i = 0; i < nFwBackends && !fwBackendSelected; i++) {
switch ((virFirewallBackend)fwBackends[i]) {
case VIR_FIREWALL_BACKEND_IPTABLES: {
g_autofree char *iptablesInPath = virFindFileInPath(IPTABLES);
if (iptablesInPath)
fwBackendSelected = true;
break;
}
case VIR_FIREWALL_BACKEND_LAST:
virReportEnumRangeError(virFirewallBackend, fwBackends[i]);
return -1;
}
if (fwBackendSelected)
cfg->firewallBackend = fwBackends[i];
}
if (fwBackendSelected) {
VIR_INFO("using firewall_backend: '%s'",
virFirewallBackendTypeToString(cfg->firewallBackend));
return 0;
conf = virConfReadFile(filename, 0);
if (!conf)
} else if (fwBackendStr) {
/* the explicitly requested backend wasn't found - this is a failure */
virReportError(VIR_ERR_INTERNAL_ERROR,
_("requested firewall_backend '%1$s' is not available"),
fwBackendStr);
return -1;
/* use virConfGetValue*(conf, ...) functions to read any settings into cfg */
return 0;
} else {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("could not find a usable firewall backend"));
return -1;
}
}

@ -26,6 +26,7 @@
#include "virdnsmasq.h"
#include "virnetworkobj.h"
#include "object_event.h"
#include "virfirewall.h"
typedef struct _virNetworkDriverConfig virNetworkDriverConfig;
struct _virNetworkDriverConfig {
@ -37,6 +38,8 @@ struct _virNetworkDriverConfig {
char *stateDir;
char *pidDir;
char *dnsmasqStateDir;
virFirewallBackend firewallBackend;
};
G_DEFINE_AUTOPTR_CLEANUP_FUNC(virNetworkDriverConfig, virObjectUnref);

@ -303,7 +303,8 @@ int networkCheckRouteCollision(virNetworkDef *def)
int
networkAddFirewallRules(virNetworkDef *def)
networkAddFirewallRules(virNetworkDef *def,
virFirewallBackend firewallBackend G_GNUC_UNUSED)
{
if (virOnce(&createdOnce, networkSetupPrivateChains) < 0)
return -1;
@ -394,7 +395,8 @@ networkAddFirewallRules(virNetworkDef *def)
void
networkRemoveFirewallRules(virNetworkDef *def)
networkRemoveFirewallRules(virNetworkDef *def,
virFirewallBackend firewallBackend G_GNUC_UNUSED)
{
iptablesRemoveFirewallRules(def);
}

@ -36,11 +36,13 @@ int networkCheckRouteCollision(virNetworkDef *def G_GNUC_UNUSED)
return 0;
}
int networkAddFirewallRules(virNetworkDef *def G_GNUC_UNUSED)
int networkAddFirewallRules(virNetworkDef *def G_GNUC_UNUSED,
virFirewallBackend firewallBackend G_GNUC_UNUSED)
{
return 0;
}
void networkRemoveFirewallRules(virNetworkDef *def G_GNUC_UNUSED)
void networkRemoveFirewallRules(virNetworkDef *def G_GNUC_UNUSED,
virFirewallBackend firewallBackend G_GNUC_UNUSED)
{
}

@ -32,6 +32,8 @@ void networkPostReloadFirewallRules(bool startup);
int networkCheckRouteCollision(virNetworkDef *def);
int networkAddFirewallRules(virNetworkDef *def);
int networkAddFirewallRules(virNetworkDef *def,
virFirewallBackend firewallBackend);
void networkRemoveFirewallRules(virNetworkDef *def);
void networkRemoveFirewallRules(virNetworkDef *def,
virFirewallBackend firewallBackend);

@ -22,11 +22,14 @@ module Libvirtd_network =
let int_entry (kw:string) = [ key kw . value_sep . int_val ]
let str_array_entry (kw:string) = [ key kw . value_sep . str_array_val ]
let firewall_backend_entry = str_entry "firewall_backend"
(* Each entry in the config is one of the following *)
let entry = firewall_backend_entry
let comment = [ label "#comment" . del /#[ \t]*/ "# " . store /([^ \t\n][^\n]*)?/ . del /\n/ "\n" ]
let empty = [ label "#empty" . eol ]
let record = indent . eol
let record = indent . entry . eol
let lns = ( record | comment | empty ) *

@ -49,16 +49,34 @@ if conf.has('WITH_NETWORK')
],
}
network_options_conf = configuration_data({
'FIREWALL_BACKEND': firewall_backend_default_conf,
})
network_conf = configure_file(
input: 'network.conf.in',
output: 'network.conf',
configuration: configmake_conf,
configuration: network_options_conf,
)
network_options_hack_conf = configuration_data({
'FIREWALL_BACKEND': firewall_backend_default_conf,
# This hack is necessary because the output file is going to be
# used as input for another configure_file() call later, which
# will take care of substituting @CONFIG@ with useful data
'CONFIG': '@CONFIG@',
})
test_libvirtd_network_aug_tmp = configure_file(
input: 'test_libvirtd_network.aug.in',
output: 'test_libvirtd_network.aug.tmp',
configuration: network_options_hack_conf,
)
virt_conf_files += network_conf
virt_aug_files += files('libvirtd_network.aug')
virt_test_aug_files += {
'name': 'test_libvirtd_network.aug',
'aug': files('test_libvirtd_network.aug.in'),
'aug': test_libvirtd_network_aug_tmp,
'conf': network_conf,
'test_name': 'libvirtd_network',
'test_srcdir': meson.current_source_dir(),

@ -1,3 +1,11 @@
# Master configuration file for the network driver.
# All settings described here are optional - if omitted, sensible
# defaults are used.
# firewall_backend:
#
# determines which subsystem to use to setup firewall packet
# filtering rules for virtual networks. Currently the only supported
# selection is "iptables".
#
#firewall_backend = "@FIREWALL_BACKEND@"

@ -1,2 +1,5 @@
module Test_libvirtd_network =
@CONFIG@
test Libvirtd_network.lns get conf =
{ "firewall_backend" = "@FIREWALL_BACKEND@" }

@ -98,7 +98,7 @@ static int testCompareXMLToArgvFiles(const char *xml,
if (!(def = virNetworkDefParse(NULL, xml, NULL, false)))
return -1;
if (networkAddFirewallRules(def) < 0)
if (networkAddFirewallRules(def, VIR_FIREWALL_BACKEND_IPTABLES) < 0)
return -1;
actual = actualargv = virBufferContentAndReset(&buf);