From nobody Fri Dec 12 14:07:31 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of lists.libvirt.org designates 8.43.85.245 as permitted sender) client-ip=8.43.85.245; envelope-from=devel-bounces@lists.libvirt.org; helo=lists.libvirt.org; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of lists.libvirt.org designates 8.43.85.245 as permitted sender) smtp.mailfrom=devel-bounces@lists.libvirt.org; dmarc=pass(p=none dis=none) header.from=gmail.com ARC-Seal: i=1; a=rsa-sha256; t=1765462468; cv=none; d=zohomail.com; s=zohoarc; b=g//exrNLwdk4qCG3jUEMspXuyy9I3hMUk9ySQdIgnXNV+n8JtFxmadDnH98R5WfqXY3RLjDOc7pWYOTW+a2v9GSWFAEd8cvX4N5L2YcMg1qNoRal2XjXVWtC4C6Id7rcv+10wQiJuRNtAF6LPH8Qor9SM0K+DiJ3vuUJDxUHtww= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1765462468; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Owner:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Subject:Subject:To:To:Message-Id:Reply-To; bh=LzYXkPVQOUuffhJ1XkLfVumy4HhNogV7/bjtK8KhXrU=; b=OCHhAR62DRHr9DHsRfHIa6z5OCz9+wO5ga8yjdgzspk0mdQhTA2dRzxFiXlRUbrHwhlHR7lizi52KVjxWhj9deH2pPPktnL8IsQHXO9Oa/Oyg23greBRN3iA7Ej7Z61za6EApEx+/4mf6OF/5OdHxYGxbior2TAM+ISGVN17TQ4= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of lists.libvirt.org designates 8.43.85.245 as permitted sender) smtp.mailfrom=devel-bounces@lists.libvirt.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists.libvirt.org (lists.libvirt.org [8.43.85.245]) by mx.zohomail.com with SMTPS id 1765462468415951.0197552189823; Thu, 11 Dec 2025 06:14:28 -0800 (PST) Received: by lists.libvirt.org (Postfix, from userid 993) id 2C99741C42; Thu, 11 Dec 2025 09:14:27 -0500 (EST) Received: from [172.19.199.80] (lists.libvirt.org [8.43.85.245]) by lists.libvirt.org (Postfix) with ESMTP id 8FBE943EC1; Thu, 11 Dec 2025 09:02:16 -0500 (EST) Received: by lists.libvirt.org (Postfix, from userid 993) id E174241865; Thu, 11 Dec 2025 09:01:06 -0500 (EST) Received: from mail-ej1-f44.google.com (mail-ej1-f44.google.com [209.85.218.44]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (3072 bits) server-digest SHA256) (No client certificate requested) by lists.libvirt.org (Postfix) with ESMTPS id E403B41903 for ; Thu, 11 Dec 2025 09:01:02 -0500 (EST) Received: by mail-ej1-f44.google.com with SMTP id a640c23a62f3a-b79d6a70fc8so20518966b.0 for ; Thu, 11 Dec 2025 06:01:02 -0800 (PST) Received: from thinkiepadje.home (2a02-a470-a384-0-b2ea-abac-e33-4609.fixed6.kpn.net. [2a02:a470:a384:0:b2ea:abac:e33:4609]) by smtp.gmail.com with ESMTPSA id a640c23a62f3a-b7cfa517558sm278382066b.34.2025.12.11.06.01.00 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 11 Dec 2025 06:01:00 -0800 (PST) X-Spam-Checker-Version: SpamAssassin 4.0.1 (2024-03-26) on lists.libvirt.org X-Spam-Level: X-Spam-Status: No, score=-5.3 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS,MAILING_LIST_MULTI,RCVD_IN_DNSWL_MED, RCVD_IN_VALIDITY_CERTIFIED_BLOCKED,RCVD_IN_VALIDITY_RPBL_BLOCKED, RCVD_IN_VALIDITY_SAFE_BLOCKED,SPF_PASS autolearn=unavailable autolearn_force=no version=4.0.1 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1765461662; x=1766066462; darn=lists.libvirt.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=LzYXkPVQOUuffhJ1XkLfVumy4HhNogV7/bjtK8KhXrU=; b=BHCSljbIrQcCPOgM6KH2qxrwGo9FtH9mvqzUGm5aVnD6pu5/faQlkYa6PH4wXcO8G0 p+CtnaiVsLWNL3kGl496i4HsKS6fVfMnAa+D5xWTS+w7pe622OTXRbX57FJ1QVYCS90R JEVeITRwPHQUudrvG5AsFHFxycOQFM0lStaCPSrA86RmLIJO9wZZ/cntu9b/+2I1ym56 jnY9bT5uoVsdE8m6nHbCOMNGy2iOudGnI2UU/2rd2R1u3l4AH+KFbXxyXEcmJeXbUgZ7 gWQb0MH6hW+FovYHqtYngvbiUjPgoaZn0iawbmWU+eiG7kKr5voAxR5QB47DhXpUftx9 SCgA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1765461662; x=1766066462; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=LzYXkPVQOUuffhJ1XkLfVumy4HhNogV7/bjtK8KhXrU=; b=QBJEA7hiXI83gMq+hVtz4CNaiLVoeOjA6ZzJ4QX4YH+JNNdDtaDL3C/i3p47jyFTqF ui4xIDPxvCuTthpc29aAYZzZzVSyeWaxcpp5Q4mBZgTxNx76FQT2dVrvThu0e60Z+lHF V9LeF+AGEL/sNkhQN5B/VnQrtC+tG6qmL2QHqPYKN9HLWRPvRqsRPT3KW0scS1amKzxA u4W1bVUuY67A9SdrXj/lGHXQup3R+wFBsvgA4L4qJWkMORLNlcpvIiuJYsW+CQ2vVgLM EyqTCNtxfzqqI5z+m3b5UJIttfqT+3aW5TFbvI6ZEqICEC2PW9d0pxaZPGNSkehC3cgh 3pKA== X-Gm-Message-State: AOJu0YzX1mJdI/aZzIpVYyD3lhZOcCvDWnH9+HEJtuUBucxi1q0/JbgW fLscyB352sxLOyn5z82hIpxCgliRwWBOlpw0SN6QtHmMR35qgvnWiF9evVTTHxg= X-Gm-Gg: ASbGncvwaFe5EDm2miDzvBtJjNxVwBzV4sIKQcUcpSArT4qxtZ0SmNpxkZBb3F0TDtm kzoQO714A6PoSGPO5i5z+Hdey8rLbLxXO3ZHHpnGlAvisLwzObBxu25Llh/sKd6pWW/Se4G9m4d zhyRDMkW8+8wM9Z3PNLV5wh7iemAJYVqM0Yd2n+TAPVnSan+RPa3fgbl8iC8U8OuRnZmLmi/5MI 3O2QRnLtgELf1KbGATd5ylc+1UrOhzZlT+qwCaRNk8heXkpw/AZH5CS3egk2tCyPmJB119kAMah cZT/xs34CmCg111+xGSO9gSk6vF90olN6o225DKqoxxLNPHjwEmo2iO1aIka74mlhTwMc7Y7HSe pwbYWeUOXhXhTMMBl8MQBELv09YJ1sALj3LVQwlQMTAlJokm83bEK3i5QcEV+Gy82uwLdQly1vS tq23ByHZ45yG81W3P2w3sUEQjIbj+BZyZ4x1Gzf9pmvJgf2j/R1CZQHSquvVTDf3voH3FsNGeil FCs2CokzQ== X-Google-Smtp-Source: AGHT+IF65JxCK+yFZhzpjqSLxw7+B3ndzWE/W/hmaiOPWCJJATBR5i7M32GCA06P8PA5JtDN1/BDgg== X-Received: by 2002:a17:907:608c:b0:b76:f090:777b with SMTP id a640c23a62f3a-b7ce82dd99dmr657502566b.22.1765461660795; Thu, 11 Dec 2025 06:01:00 -0800 (PST) From: Dion Bosschieter To: devel@lists.libvirt.org Subject: [PATCH v2 4/5] nwfilter: allow use of nftables nwfilter driver via nwfilter.conf Date: Thu, 11 Dec 2025 15:00:53 +0100 Message-ID: <20251211140054.35822-5-dionbosschieter@gmail.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20251211140054.35822-1-dionbosschieter@gmail.com> References: <20251211140054.35822-1-dionbosschieter@gmail.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Message-ID-Hash: 5AMOLX4OOWUJOMZHCVNF4VP4CFODAXPD X-Message-ID-Hash: 5AMOLX4OOWUJOMZHCVNF4VP4CFODAXPD X-MailFrom: dionbosschieter@gmail.com X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; loop; banned-address; header-match-devel.lists.libvirt.org-0; emergency; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header CC: jean-louis@dupond.be, Dion Bosschieter X-Mailman-Version: 3.3.10 Precedence: list List-Id: Development discussions about the libvirt library & tools Archived-At: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: X-ZohoMail-DKIM: pass (identity @gmail.com) X-ZM-MESSAGEID: 1765462470124158500 Content-Type: text/plain; charset="utf-8" Change the nwfilter driver loading mechanism to read from nwfilter.conf. By default, it will use the nftables driver, which follows the firewall_backend bridge driver config logic. Added nftables to *filter_tech_drivers as an available driver option for users to choose from. Signed-off-by: Dion Bosschieter --- po/POTFILES | 1 + src/conf/virnwfilterobj.h | 20 -- src/nwfilter/libvirtd_nwfilter.aug | 37 ++++ src/nwfilter/meson.build | 37 ++++ src/nwfilter/nwfilter.conf.in | 26 +++ src/nwfilter/nwfilter_driver.c | 66 +++---- src/nwfilter/nwfilter_driver_conf.c | 210 +++++++++++++++++++++ src/nwfilter/nwfilter_driver_conf.h | 66 +++++++ src/nwfilter/nwfilter_ebiptables_driver.h | 2 +- src/nwfilter/nwfilter_gentech_driver.c | 63 +++---- src/nwfilter/nwfilter_gentech_driver.h | 5 +- src/nwfilter/nwfilter_tech_driver.c | 1 - src/nwfilter/nwfilter_tech_driver.h | 1 + src/nwfilter/test_libvirtd_nwfilter.aug.in | 5 + 14 files changed, 441 insertions(+), 99 deletions(-) create mode 100644 src/nwfilter/libvirtd_nwfilter.aug create mode 100644 src/nwfilter/nwfilter.conf.in create mode 100644 src/nwfilter/nwfilter_driver_conf.c create mode 100644 src/nwfilter/nwfilter_driver_conf.h create mode 100644 src/nwfilter/test_libvirtd_nwfilter.aug.in diff --git a/po/POTFILES b/po/POTFILES index 51dae40cea..69cdba22f9 100644 --- a/po/POTFILES +++ b/po/POTFILES @@ -159,6 +159,7 @@ src/node_device/node_device_driver.c src/node_device/node_device_udev.c src/nwfilter/nwfilter_dhcpsnoop.c src/nwfilter/nwfilter_driver.c +src/nwfilter/nwfilter_driver_conf.c src/nwfilter/nwfilter_ebiptables_driver.c src/nwfilter/nwfilter_gentech_driver.c src/nwfilter/nwfilter_learnipaddr.c diff --git a/src/conf/virnwfilterobj.h b/src/conf/virnwfilterobj.h index b67dc017c5..2c5df3e9ac 100644 --- a/src/conf/virnwfilterobj.h +++ b/src/conf/virnwfilterobj.h @@ -28,26 +28,6 @@ typedef struct _virNWFilterObj virNWFilterObj; =20 typedef struct _virNWFilterObjList virNWFilterObjList; =20 -typedef struct _virNWFilterDriverState virNWFilterDriverState; -struct _virNWFilterDriverState { - bool privileged; - - /* pid file FD, ensures two copies of the driver can't use the same ro= ot */ - int lockFD; - - virNWFilterObjList *nwfilters; - - virNWFilterBindingObjList *bindings; - - char *stateDir; - char *configDir; - char *bindingDir; - - /* Recursive. Hold for filter changes, instantiation or deletion */ - virMutex updateLock; - bool updateLockInitialized; -}; - virNWFilterDef * virNWFilterObjGetDef(virNWFilterObj *obj); =20 diff --git a/src/nwfilter/libvirtd_nwfilter.aug b/src/nwfilter/libvirtd_nwf= ilter.aug new file mode 100644 index 0000000000..96351d272a --- /dev/null +++ b/src/nwfilter/libvirtd_nwfilter.aug @@ -0,0 +1,37 @@ +(* /etc/libvirt/nwfilter.conf *) + +module Libvirtd_nwfilter =3D + autoload xfm + + let eol =3D del /[ \t]*\n/ "\n" + let value_sep =3D del /[ \t]*=3D[ \t]*/ " =3D " + let indent =3D del /[ \t]*/ "" + + let array_sep =3D del /,[ \t\n]*/ ", " + let array_start =3D del /\[[ \t\n]*/ "[ " + let array_end =3D del /\]/ "]" + + let str_val =3D del /\"/ "\"" . store /[^\"]*/ . del /\"/ "\"" + let bool_val =3D store /0|1/ + let int_val =3D store /[0-9]+/ + let str_array_element =3D [ seq "el" . str_val ] . del /[ \t\n]*/ "" + let str_array_val =3D counter "el" . array_start . ( str_array_element = . ( array_sep . str_array_element ) * ) ? . array_end + + let str_entry (kw:string) =3D [ key kw . value_sep . str_val ] + let bool_entry (kw:string) =3D [ key kw . value_sep . bool_val ] + let int_entry (kw:string) =3D [ key kw . value_sep . int_val ] + let str_array_entry (kw:string) =3D [ key kw . value_sep . str_array_va= l ] + + (* Each entry in the config is one of the following *) + let entry =3D str_entry "nwfilter_driver" + let comment =3D [ label "#comment" . del /#[ \t]*/ "# " . store /([^ \= t\n][^\n]*)?/ . del /\n/ "\n" ] + let empty =3D [ label "#empty" . eol ] + + let record =3D indent . entry . eol + + let lns =3D ( record | comment | empty ) * + + let filter =3D incl "/etc/libvirt/nwfilter.conf" + . Util.stdexcl + + let xfm =3D transform lns filter diff --git a/src/nwfilter/meson.build b/src/nwfilter/meson.build index a94d72d570..4d8abc7deb 100644 --- a/src/nwfilter/meson.build +++ b/src/nwfilter/meson.build @@ -1,5 +1,6 @@ nwfilter_driver_sources =3D [ 'nwfilter_driver.c', + 'nwfilter_driver_conf.c', 'nwfilter_gentech_driver.c', 'nwfilter_tech_driver.c', 'nwfilter_dhcpsnoop.c', @@ -46,6 +47,42 @@ if conf.has('WITH_NWFILTER') ], } =20 + nwfilter_options_conf =3D configuration_data({ + 'FIREWALL_BACKEND_PRIORITY': ', '.join(firewall_backend_priority), + 'FIREWALL_BACKEND': firewall_backend_priority[0], + }) + + nwfilter_conf =3D configure_file( + input: 'nwfilter.conf.in', + output: 'nwfilter.conf', + configuration: nwfilter_options_conf, + ) + + nwfilter_options_hack_conf =3D configuration_data({ + 'FIREWALL_BACKEND_PRIORITY': ', '.join(firewall_backend_priority), + 'FIREWALL_BACKEND': firewall_backend_priority[0], + # 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 =3D configure_file( + input: 'test_libvirtd_nwfilter.aug.in', + output: 'test_libvirtd_nwfilter.aug.tmp', + configuration: nwfilter_options_hack_conf, + ) + + virt_conf_files +=3D nwfilter_conf + virt_aug_files +=3D files('libvirtd_nwfilter.aug') + virt_test_aug_files +=3D { + 'name': 'test_libvirtd_nwfilter.aug', + 'aug': test_libvirtd_network_aug_tmp, + 'conf': nwfilter_conf, + 'test_name': 'libvirtd_nwfilter', + 'test_srcdir': meson.current_source_dir(), + 'test_builddir': meson.current_build_dir(), + } + virt_daemon_confs +=3D { 'name': 'virtnwfilterd', } diff --git a/src/nwfilter/nwfilter.conf.in b/src/nwfilter/nwfilter.conf.in new file mode 100644 index 0000000000..8ed5cbaa53 --- /dev/null +++ b/src/nwfilter/nwfilter.conf.in @@ -0,0 +1,26 @@ +# Master configuration file for the nwfilter driver. +# All settings described here are optional - if omitted, sensible +# defaults are used. + +# nwfilter_driver: +# +# determines which driver to use to setup nwfilter firewall rules +# +# Supported settings: +# +# iptables - use ebtables and iptables commands to construct the user +# defined firewall +# nftables - use nft commands to construct the user defined firewall +# +# If nwfilter_driver isn't configured, libvirt will choose the +# first available backend from the following list: +# +# [@FIREWALL_BACKEND_PRIORITY@] +# +# (NB: switching from one backend to another while there are active +# virtual networks *isn't* supported. The change will take place the +# next time that libvirtd/virtnetworkd is restarted - all existing +# firewalls remain, and have to be cleaned up manually +# reloaded using the new backend.) +# +#nwfilter_driver =3D "@FIREWALL_BACKEND@" diff --git a/src/nwfilter/nwfilter_driver.c b/src/nwfilter/nwfilter_driver.c index 522cfda022..6b1100b675 100644 --- a/src/nwfilter/nwfilter_driver.c +++ b/src/nwfilter/nwfilter_driver.c @@ -26,17 +26,15 @@ =20 #include "virgdbus.h" #include "virlog.h" - #include "internal.h" - #include "virerror.h" #include "datatypes.h" #include "nwfilter_driver.h" +#include "nwfilter_driver_conf.h" #include "nwfilter_gentech_driver.h" #include "configmake.h" #include "virpidfile.h" #include "viraccessapicheck.h" - #include "nwfilter_ipaddrmap.h" #include "nwfilter_dhcpsnoop.h" #include "nwfilter_learnipaddr.h" @@ -159,9 +157,12 @@ virNWFilterTriggerRebuildImpl(void *opaque) static int nwfilterStateCleanupLocked(void) { + g_autoptr(virNWFilterDriverConfig) cfg =3D NULL; if (!driver) return -1; =20 + cfg =3D virNWFilterDriverGetConfig(driver); + if (driver->privileged) { virNWFilterConfLayerShutdown(); virNWFilterDHCPSnoopShutdown(); @@ -171,11 +172,7 @@ nwfilterStateCleanupLocked(void) nwfilterDriverRemoveDBusMatches(); =20 if (driver->lockFD !=3D -1) - virPidFileRelease(driver->stateDir, "driver", driver->lockFD); - - g_free(driver->stateDir); - g_free(driver->configDir); - g_free(driver->bindingDir); + virPidFileRelease(cfg->stateDir, "driver", driver->lockFD); } =20 virObjectUnref(driver->bindings); @@ -216,6 +213,7 @@ nwfilterStateInitialize(bool privileged, void *opaque G_GNUC_UNUSED) { VIR_LOCK_GUARD lock =3D virLockGuardLock(&driverMutex); + virNWFilterDriverConfig *cfg; GDBusConnection *sysbus =3D NULL; =20 if (root !=3D NULL) { @@ -236,6 +234,9 @@ nwfilterStateInitialize(bool privileged, driver->updateLockInitialized =3D true; driver->privileged =3D privileged; =20 + if (!(driver->config =3D cfg =3D virNWFilterDriverConfigNew(privileged= ))) + goto error; + if (!(driver->nwfilters =3D virNWFilterObjListNew())) goto error; =20 @@ -245,16 +246,8 @@ nwfilterStateInitialize(bool privileged, if (!privileged) return VIR_DRV_STATE_INIT_SKIPPED; =20 - driver->stateDir =3D g_strdup(RUNSTATEDIR "/libvirt/nwfilter"); - - if (g_mkdir_with_parents(driver->stateDir, S_IRWXU) < 0) { - virReportSystemError(errno, _("cannot create state directory '%1$s= '"), - driver->stateDir); - goto error; - } - if ((driver->lockFD =3D - virPidFileAcquire(driver->stateDir, "driver", getpid())) < 0) + virPidFileAcquire(cfg->stateDir, "driver", getpid())) < 0) goto error; =20 if (virNWFilterIPAddrMapInit() < 0) @@ -266,7 +259,7 @@ nwfilterStateInitialize(bool privileged, if (virNWFilterDHCPSnoopInit() < 0) goto error; =20 - if (virNWFilterTechDriversInit(privileged) < 0) + if (virNWFilterTechDriversInit(privileged, cfg->firewallBackend) < 0) goto error; =20 if (virNWFilterConfLayerInit(virNWFilterTriggerRebuildImpl, driver) < = 0) @@ -279,26 +272,10 @@ nwfilterStateInitialize(bool privileged, if (sysbus) nwfilterDriverInstallDBusMatches(sysbus); =20 - driver->configDir =3D g_strdup(SYSCONFDIR "/libvirt/nwfilter"); - - if (g_mkdir_with_parents(driver->configDir, S_IRWXU) < 0) { - virReportSystemError(errno, _("cannot create config directory '%1$= s'"), - driver->configDir); - goto error; - } - - driver->bindingDir =3D g_strdup(RUNSTATEDIR "/libvirt/nwfilter-binding= "); - - if (g_mkdir_with_parents(driver->bindingDir, S_IRWXU) < 0) { - virReportSystemError(errno, _("cannot create config directory '%1$= s'"), - driver->bindingDir); + if (virNWFilterObjListLoadAllConfigs(driver->nwfilters, cfg->configDir= ) < 0) goto error; - } =20 - if (virNWFilterObjListLoadAllConfigs(driver->nwfilters, driver->config= Dir) < 0) - goto error; - - if (virNWFilterBindingObjListLoadAllConfigs(driver->bindings, driver->= bindingDir) < 0) + if (virNWFilterBindingObjListLoadAllConfigs(driver->bindings, cfg->bin= dingDir) < 0) goto error; =20 if (virNWFilterBuildAll(driver, false) < 0) @@ -320,19 +297,22 @@ nwfilterStateInitialize(bool privileged, static int nwfilterStateReload(void) { + g_autoptr(virNWFilterDriverConfig) cfg =3D NULL; if (!driver) return -1; =20 if (!driver->privileged) return 0; =20 + cfg =3D virNWFilterDriverGetConfig(driver); + virNWFilterDHCPSnoopEnd(NULL); /* shut down all threads -- they will be restarted if necessary */ virNWFilterLearnThreadsTerminate(true); =20 VIR_WITH_MUTEX_LOCK_GUARD(&driverMutex) { VIR_WITH_MUTEX_LOCK_GUARD(&driver->updateLock) { - virNWFilterObjListLoadAllConfigs(driver->nwfilters, driver->co= nfigDir); + virNWFilterObjListLoadAllConfigs(driver->nwfilters, cfg->confi= gDir); } =20 =20 @@ -535,6 +515,7 @@ nwfilterDefineXMLFlags(virConnectPtr conn, virNWFilterObj *obj =3D NULL; virNWFilterDef *objdef; virNWFilterPtr nwfilter =3D NULL; + g_autoptr(virNWFilterDriverConfig) cfg =3D virNWFilterDriverGetConfig(= driver); =20 virCheckFlags(VIR_NWFILTER_DEFINE_VALIDATE, NULL); =20 @@ -558,7 +539,7 @@ nwfilterDefineXMLFlags(virConnectPtr conn, def =3D NULL; objdef =3D virNWFilterObjGetDef(obj); =20 - if (virNWFilterSaveConfig(driver->configDir, objdef) < 0) { + if (virNWFilterSaveConfig(cfg->configDir, objdef) < 0) { virNWFilterObjListRemove(driver->nwfilters, obj); goto cleanup; } @@ -588,6 +569,7 @@ nwfilterUndefine(virNWFilterPtr nwfilter) virNWFilterObj *obj; virNWFilterDef *def; int ret =3D -1; + g_autoptr(virNWFilterDriverConfig) cfg =3D virNWFilterDriverGetConfig(= driver); =20 VIR_WITH_MUTEX_LOCK_GUARD(&driver->updateLock) { if (!(obj =3D nwfilterObjFromNWFilter(nwfilter->uuid))) @@ -604,7 +586,7 @@ nwfilterUndefine(virNWFilterPtr nwfilter) goto cleanup; } =20 - if (virNWFilterDeleteDef(driver->configDir, def) < 0) + if (virNWFilterDeleteDef(cfg->configDir, def) < 0) goto cleanup; =20 virNWFilterObjListRemove(driver->nwfilters, obj); @@ -730,6 +712,7 @@ nwfilterBindingCreateXML(virConnectPtr conn, virNWFilterBindingDef *def; virNWFilterBindingObj *obj =3D NULL; virNWFilterBindingPtr ret =3D NULL; + g_autoptr(virNWFilterDriverConfig) cfg =3D virNWFilterDriverGetConfig(= driver); =20 virCheckFlags(VIR_NWFILTER_BINDING_CREATE_VALIDATE, NULL); =20 @@ -772,7 +755,7 @@ nwfilterBindingCreateXML(virConnectPtr conn, } } =20 - virNWFilterBindingObjSave(obj, driver->bindingDir); + virNWFilterBindingObjSave(obj, cfg->bindingDir); =20 cleanup: if (!obj) @@ -799,6 +782,7 @@ nwfilterBindingDelete(virNWFilterBindingPtr binding) virNWFilterBindingObj *obj; virNWFilterBindingDef *def; int ret =3D -1; + g_autoptr(virNWFilterDriverConfig) cfg =3D virNWFilterDriverGetConfig(= driver); =20 obj =3D virNWFilterBindingObjListFindByPortDev(driver->bindings, bindi= ng->portdev); if (!obj) { @@ -814,7 +798,7 @@ nwfilterBindingDelete(virNWFilterBindingPtr binding) VIR_WITH_MUTEX_LOCK_GUARD(&driver->updateLock) { virNWFilterTeardownFilter(def); } - virNWFilterBindingObjDelete(obj, driver->bindingDir); + virNWFilterBindingObjDelete(obj, cfg->bindingDir); virNWFilterBindingObjListRemove(driver->bindings, obj); =20 ret =3D 0; diff --git a/src/nwfilter/nwfilter_driver_conf.c b/src/nwfilter/nwfilter_dr= iver_conf.c new file mode 100644 index 0000000000..238e6771f5 --- /dev/null +++ b/src/nwfilter/nwfilter_driver_conf.c @@ -0,0 +1,210 @@ +/* + * Copyright (C) 2022 Red Hat, Inc. + * + * nwfilter_driver_conf.c: nwfilter.conf config file inspection + * + * 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 "configmake.h" +#include "datatypes.h" +#include "virlog.h" +#include "virerror.h" +#include "virfile.h" +#include "virutil.h" +#include "virfirewall.h" /* for binary names */ +#include "nwfilter_driver_conf.h" + + +#define VIR_FROM_THIS VIR_FROM_NWFILTER + +VIR_LOG_INIT("nwfilter.nwfilter_driver"); + +static virClass *virNWFilterDriverConfigClass; +static void virNWFilterDriverConfigDispose(void *obj); + +static int +virNWFilterConfigOnceInit(void) +{ + if (!VIR_CLASS_NEW(virNWFilterDriverConfig, virClassForObject())) + return -1; + + return 0; +} + + +VIR_ONCE_GLOBAL_INIT(virNWFilterConfig); + + +static int +virNWFilterLoadDriverConfig(virNWFilterDriverConfig *cfg, + const char *filename) +{ + g_autoptr(virConf) conf =3D NULL; + g_autofree char *fwBackendStr =3D NULL; + bool fwBackendSelected =3D false; + size_t i; + int fwBackends[] =3D { + FIREWALL_BACKENDS + }; + G_STATIC_ASSERT(G_N_ELEMENTS(fwBackends) > 0 && + G_N_ELEMENTS(fwBackends) <=3D VIR_FIREWALL_BACKEND_LAS= T); + int nFwBackends =3D G_N_ELEMENTS(fwBackends); + + if (access(filename, R_OK) =3D=3D 0) { + + conf =3D virConfReadFile(filename, 0); + if (!conf) + return -1; + + /* use virConfGetValue*(conf, ...) functions to read any settings = into cfg */ + + if (virConfGetValueString(conf, "nwfilter_driver", &fwBackendStr) = < 0) + return -1; + + if (fwBackendStr) { + fwBackends[0] =3D virFirewallBackendTypeFromString(fwBackendSt= r); + nFwBackends =3D 1; + + if (fwBackends[0] < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("unrecognized nwfilter_driver =3D '%1$s' = set in nwfilter driver config file %2$s"), + fwBackendStr, filename); + return -1; + } + VIR_DEBUG("nwfilter_driver setting requested from config file = %s: '%s'", + filename, virFirewallBackendTypeToString(fwBackends[= 0])); + } + } + + for (i =3D 0; i < nFwBackends && !fwBackendSelected; i++) { + switch ((virFirewallBackend)fwBackends[i]) { + case VIR_FIREWALL_BACKEND_NONE: + fwBackendSelected =3D true; + break; + + case VIR_FIREWALL_BACKEND_IPTABLES: { + g_autofree char *iptablesInPath =3D virFindFileInPath(IPTABLES= ); + + if (iptablesInPath) + fwBackendSelected =3D true; + break; + } + + case VIR_FIREWALL_BACKEND_NFTABLES: { + g_autofree char *nftablesInPath =3D virFindFileInPath(NFT); + + if (nftablesInPath) + fwBackendSelected =3D true; + break; + } + + case VIR_FIREWALL_BACKEND_PF: { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("unsupported nwfilter driver PF")); + return -1; + } + + case VIR_FIREWALL_BACKEND_LAST: + virReportEnumRangeError(virFirewallBackend, fwBackends[i]); + return -1; + } + + if (fwBackendSelected) + cfg->firewallBackend =3D fwBackends[i]; + } + + if (fwBackendSelected) { + VIR_INFO("using nwfilter_driver: '%s'", + virFirewallBackendTypeToString(cfg->firewallBackend)); + return 0; + } else if (fwBackendStr) { + /* the explicitly requested driver wasn't found - this is a failur= e */ + virReportError(VIR_ERR_INTERNAL_ERROR, + _("requested nwfilter_driver '%1$s' is not availabl= e"), + fwBackendStr); + return -1; + } else { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("could not find a usable nwfilter driver")); + return -1; + } +} + + +virNWFilterDriverConfig * +virNWFilterDriverConfigNew(bool privileged) +{ + g_autoptr(virNWFilterDriverConfig) cfg =3D NULL; + g_autofree char *configdir =3D NULL; + g_autofree char *configfile =3D NULL; + + if (virNWFilterConfigInitialize() < 0) + return NULL; + + if (!(cfg =3D virObjectNew(virNWFilterDriverConfigClass))) + return NULL; + + if (!privileged) + return g_steal_pointer(&cfg); + + cfg->stateDir =3D g_strdup(RUNSTATEDIR "/libvirt/nwfilter"); + cfg->configDir =3D g_strdup(SYSCONFDIR "/libvirt/nwfilter"); + cfg->bindingDir =3D g_strdup(RUNSTATEDIR "/libvirt/nwfilter-binding"); + configfile =3D g_strdup(SYSCONFDIR "/libvirt/nwfilter.conf"); + + if (virNWFilterLoadDriverConfig(cfg, configfile) < 0) + return NULL; + + if (g_mkdir_with_parents(cfg->stateDir, S_IRWXU) < 0) { + virReportSystemError(errno, _("cannot create state directory '%1$s= '"), + cfg->stateDir); + return NULL; + } + + if (g_mkdir_with_parents(cfg->configDir, S_IRWXU) < 0) { + virReportSystemError(errno, _("cannot create config directory '%1$= s'"), + cfg->configDir); + return NULL; + } + + if (g_mkdir_with_parents(cfg->bindingDir, S_IRWXU) < 0) { + virReportSystemError(errno, _("cannot create config directory '%1$= s'"), + cfg->bindingDir); + return NULL; + } + + return g_steal_pointer(&cfg); +} + + +virNWFilterDriverConfig * +virNWFilterDriverGetConfig(virNWFilterDriverState *driver) +{ + return virObjectRef(driver->config); +} + + +static void +virNWFilterDriverConfigDispose(void *obj) +{ + virNWFilterDriverConfig *cfg =3D obj; + + g_free(cfg->stateDir); + g_free(cfg->configDir); + g_free(cfg->bindingDir); +} diff --git a/src/nwfilter/nwfilter_driver_conf.h b/src/nwfilter/nwfilter_dr= iver_conf.h new file mode 100644 index 0000000000..e017149663 --- /dev/null +++ b/src/nwfilter/nwfilter_driver_conf.h @@ -0,0 +1,66 @@ +/* + * nwfilter_driver_conf.h: nwfilter driver state and config objects + * + * Copyright (C) 2006-2013 Red Hat, Inc. + * Copyright (C) 2006 Daniel P. Berrange + * + * 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 "libvirt_internal.h" +#include "virthread.h" +#include "virnwfilterobj.h" +#include "virfirewall.h" +#include "virinhibitor.h" + +typedef struct _virNWFilterDriverConfig virNWFilterDriverConfig; +struct _virNWFilterDriverConfig { + virObject parent; + + /* Immutable pointers, Immutable objects */ + char *stateDir; + char *configDir; + char *bindingDir; + + virFirewallBackend firewallBackend; +}; + +G_DEFINE_AUTOPTR_CLEANUP_FUNC(virNWFilterDriverConfig, virObjectUnref); + +/* Main driver state */ +typedef struct _virNWFilterDriverState virNWFilterDriverState; +struct _virNWFilterDriverState { + bool privileged; + + /* pid file FD, ensures two copies of the driver can't use the same ro= ot */ + int lockFD; + + virNWFilterObjList *nwfilters; + + virNWFilterBindingObjList *bindings; + + virNWFilterDriverConfig *config; + + /* Recursive. Hold for filter changes, instantiation or deletion */ + virMutex updateLock; + bool updateLockInitialized; +}; + +virNWFilterDriverConfig * +virNWFilterDriverConfigNew(bool privileged); +virNWFilterDriverConfig * +virNWFilterDriverGetConfig(virNWFilterDriverState *driver); diff --git a/src/nwfilter/nwfilter_ebiptables_driver.h b/src/nwfilter/nwfil= ter_ebiptables_driver.h index cb146f9f97..dfaea5af3d 100644 --- a/src/nwfilter/nwfilter_ebiptables_driver.h +++ b/src/nwfilter/nwfilter_ebiptables_driver.h @@ -27,6 +27,6 @@ =20 extern virNWFilterTechDriver ebiptables_driver; =20 -#define EBIPTABLES_DRIVER_ID "ebiptables" +#define EBIPTABLES_DRIVER_ID "iptables" =20 #define IPTABLES_MAX_COMMENT_LENGTH 256 diff --git a/src/nwfilter/nwfilter_gentech_driver.c b/src/nwfilter/nwfilter= _gentech_driver.c index 1465734a54..fdba2393f9 100644 --- a/src/nwfilter/nwfilter_gentech_driver.c +++ b/src/nwfilter/nwfilter_gentech_driver.c @@ -32,6 +32,7 @@ #include "nwfilter_dhcpsnoop.h" #include "nwfilter_ipaddrmap.h" #include "nwfilter_learnipaddr.h" +#include "nwfilter_nftables_driver.h" #include "virnetdev.h" =20 #define VIR_FROM_THIS VIR_FROM_NWFILTER @@ -48,18 +49,23 @@ static int _virNWFilterTeardownFilter(const char *ifnam= e); =20 static virNWFilterTechDriver *filter_tech_drivers[] =3D { &ebiptables_driver, - NULL + &nftables_driver, }; =20 -int virNWFilterTechDriversInit(bool privileged) +int virNWFilterTechDriversInit(bool privileged, virFirewallBackend firewal= lBackend) { size_t i =3D 0; - VIR_DEBUG("Initializing NWFilter technology drivers"); - while (filter_tech_drivers[i]) { - if (!(filter_tech_drivers[i]->flags & TECHDRV_FLAG_INITIALIZED)) + VIR_DEBUG("Initializing NWFilter technology drivers, chosen '%s'", + virFirewallBackendTypeToString(firewallBackend)); + + for (i =3D 0; i < G_N_ELEMENTS(filter_tech_drivers); i++) { + if (filter_tech_drivers[i]->flags & TECHDRV_FLAG_INITIALIZED) + continue; + if (STREQ(filter_tech_drivers[i]->name, + virFirewallBackendTypeToString(firewallBackend))) filter_tech_drivers[i]->init(privileged); - i++; } + return 0; } =20 @@ -67,25 +73,20 @@ int virNWFilterTechDriversInit(bool privileged) void virNWFilterTechDriversShutdown(void) { size_t i =3D 0; - while (filter_tech_drivers[i]) { + for (i =3D 0; i < G_N_ELEMENTS(filter_tech_drivers); i++) { if ((filter_tech_drivers[i]->flags & TECHDRV_FLAG_INITIALIZED)) filter_tech_drivers[i]->shutdown(); - i++; } } =20 =20 static virNWFilterTechDriver * -virNWFilterTechDriverForName(const char *name) +virNWFilterInitializedTechDriver(void) { size_t i =3D 0; - while (filter_tech_drivers[i]) { - if (STREQ(filter_tech_drivers[i]->name, name)) { - if ((filter_tech_drivers[i]->flags & TECHDRV_FLAG_INITIALIZED)= =3D=3D 0) - break; + for (i =3D 0; i < G_N_ELEMENTS(filter_tech_drivers); i++) { + if ((filter_tech_drivers[i]->flags & TECHDRV_FLAG_INITIALIZED)) return filter_tech_drivers[i]; - } - i++; } return NULL; } @@ -617,7 +618,6 @@ virNWFilterInstantiateFilterUpdate(virNWFilterDriverSta= te *driver, bool *foundNewFilter) { int rc =3D -1; - const char *drvname =3D EBIPTABLES_DRIVER_ID; virNWFilterTechDriver *techdriver; virNWFilterObj *obj; virNWFilterDef *filter; @@ -625,12 +625,11 @@ virNWFilterInstantiateFilterUpdate(virNWFilterDriverS= tate *driver, char vmmacaddr[VIR_MAC_STRING_BUFLEN] =3D {0}; virNWFilterVarValue *ipaddr; =20 - techdriver =3D virNWFilterTechDriverForName(drvname); + techdriver =3D virNWFilterInitializedTechDriver(); =20 if (!techdriver) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Could not get access to ACL tech driver '%1$s'"), - drvname); + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Could not get access to ACL tech driver")); return -1; } =20 @@ -768,15 +767,13 @@ virNWFilterUpdateInstantiateFilter(virNWFilterDriverS= tate *driver, static int virNWFilterRollbackUpdateFilter(virNWFilterBindingDef *binding) { - const char *drvname =3D EBIPTABLES_DRIVER_ID; int ifindex; virNWFilterTechDriver *techdriver; =20 - techdriver =3D virNWFilterTechDriverForName(drvname); + techdriver =3D virNWFilterInitializedTechDriver(); if (!techdriver) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Could not get access to ACL tech driver '%1$s'"), - drvname); + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Could not get access to ACL tech driver")); return -1; } =20 @@ -793,15 +790,13 @@ virNWFilterRollbackUpdateFilter(virNWFilterBindingDef= *binding) static int virNWFilterTearOldFilter(virNWFilterBindingDef *binding) { - const char *drvname =3D EBIPTABLES_DRIVER_ID; int ifindex; virNWFilterTechDriver *techdriver; =20 - techdriver =3D virNWFilterTechDriverForName(drvname); + techdriver =3D virNWFilterInitializedTechDriver(); if (!techdriver) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Could not get access to ACL tech driver '%1$s'"), - drvname); + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Could not get access to ACL tech driver")); return -1; } =20 @@ -818,14 +813,12 @@ virNWFilterTearOldFilter(virNWFilterBindingDef *bindi= ng) static int _virNWFilterTeardownFilter(const char *ifname) { - const char *drvname =3D EBIPTABLES_DRIVER_ID; virNWFilterTechDriver *techdriver; - techdriver =3D virNWFilterTechDriverForName(drvname); + techdriver =3D virNWFilterInitializedTechDriver(); =20 if (!techdriver) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Could not get access to ACL tech driver '%1$s'"), - drvname); + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Could not get access to ACL tech driver")); return -1; } =20 diff --git a/src/nwfilter/nwfilter_gentech_driver.h b/src/nwfilter/nwfilter= _gentech_driver.h index 946d5d3d56..59d76b852c 100644 --- a/src/nwfilter/nwfilter_gentech_driver.h +++ b/src/nwfilter/nwfilter_gentech_driver.h @@ -24,8 +24,11 @@ =20 #include "virnwfilterobj.h" #include "virnwfilterbindingdef.h" +#include "nwfilter_driver_conf.h" +#include "virfirewall.h" =20 -int virNWFilterTechDriversInit(bool privileged); + +int virNWFilterTechDriversInit(bool privileged, virFirewallBackend firewal= lBackend); void virNWFilterTechDriversShutdown(void); =20 enum instCase { diff --git a/src/nwfilter/nwfilter_tech_driver.c b/src/nwfilter/nwfilter_te= ch_driver.c index 7b3edff8e6..ece8f90bf8 100644 --- a/src/nwfilter/nwfilter_tech_driver.c +++ b/src/nwfilter/nwfilter_tech_driver.c @@ -19,7 +19,6 @@ #include =20 #include "nwfilter_tech_driver.h" -#include "nwfilter_conf.h" =20 #define VIR_FROM_THIS VIR_FROM_NWFILTER =20 diff --git a/src/nwfilter/nwfilter_tech_driver.h b/src/nwfilter/nwfilter_te= ch_driver.h index 7a85c46339..103f33a3b8 100644 --- a/src/nwfilter/nwfilter_tech_driver.h +++ b/src/nwfilter/nwfilter_tech_driver.h @@ -25,6 +25,7 @@ =20 #include "virnwfilterobj.h" #include "virstring.h" +#include "nwfilter_driver_conf.h" =20 typedef struct _virNWFilterRuleInst virNWFilterRuleInst; struct _virNWFilterRuleInst { diff --git a/src/nwfilter/test_libvirtd_nwfilter.aug.in b/src/nwfilter/test= _libvirtd_nwfilter.aug.in new file mode 100644 index 0000000000..a930f9b428 --- /dev/null +++ b/src/nwfilter/test_libvirtd_nwfilter.aug.in @@ -0,0 +1,5 @@ +module Test_libvirtd_nwfilter =3D + @CONFIG@ + + test Libvirtd_nwfilter.lns get conf =3D +{ "nwfilter_driver" =3D "nftables" } --=20 2.43.0