These functions convert a virFirewall object to/from XML so that it
can be serialized to disk (in a virNetworkObj's status file) and
restored later (e.g. after libvirtd/virtnetworkd is restarted).
Signed-off-by: Laine Stump <laine@redhat.com>
---
src/libvirt_private.syms | 2 +
src/util/virfirewall.c | 220 +++++++++++++++++++++++++++++++++++++++
src/util/virfirewall.h | 9 ++
3 files changed, 231 insertions(+)
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 7eeed1efd4..1666da633d 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -2376,10 +2376,12 @@ virFirewallAddRuleFull;
virFirewallApply;
virFirewallBackendTypeFromString;
virFirewallBackendTypeToString;
+virFirewallFormat;
virFirewallFree;
virFirewallGetBackend;
virFirewallNew;
virFirewallNewFromRollback;
+virFirewallParseXML;
virFirewallRemoveRule;
virFirewallRuleAddArg;
virFirewallRuleAddArgFormat;
diff --git a/src/util/virfirewall.c b/src/util/virfirewall.c
index f598cc9d79..d292ef60c6 100644
--- a/src/util/virfirewall.c
+++ b/src/util/virfirewall.c
@@ -42,6 +42,14 @@ VIR_ENUM_IMPL(virFirewallBackend,
"iptables",
"nftables");
+VIR_ENUM_DECL(virFirewallLayer);
+VIR_ENUM_IMPL(virFirewallLayer,
+ VIR_FIREWALL_LAYER_LAST,
+ "ethernet",
+ "ipv4",
+ "ipv6",
+);
+
typedef struct _virFirewallGroup virFirewallGroup;
struct _virFirewallRule {
@@ -739,3 +747,215 @@ virFirewallNewFromRollback(virFirewall *original,
return 0;
}
+
+
+/* virFirewallGetFlagsFromNode:
+ * @node: the xmlNode to check for an ignoreErrors attribute
+ *
+ * A short helper to get the setting of the ignorErrors attribute from
+ * an xmlNode. Returns -1 on error (with error reported), or the
+ * VIR_FIREWALL_TRANSACTION_IGNORE_ERRORS bit set/reset according to
+ * the value of the attribute.
+ */
+static int
+virFirewallGetFlagsFromNode(xmlNodePtr node)
+{
+ virTristateBool ignoreErrors;
+
+ if (virXMLPropTristateBool(node, "ignoreErrors", VIR_XML_PROP_NONE, &ignoreErrors) < 0)
+ return -1;
+
+ if (ignoreErrors == VIR_TRISTATE_BOOL_YES)
+ return VIR_FIREWALL_TRANSACTION_IGNORE_ERRORS;
+ return 0;
+}
+
+
+/**
+ * virFirewallParseXML:
+ * @firewall: pointer to virFirewall* to fill in with new virFirewall object
+ *
+ * Construct a new virFirewall object according to the XML in
+ * xmlNodePtr. Return 0 (and new object) on success, or -1 (with
+ * error reported) on error.
+ *
+ * Example of <firewall> element XML:
+ *
+ * <firewall backend='iptables|nftables'>
+ * <group ignoreErrors='yes|no'>
+ * <action layer='ethernet|ipv4|ipv6' ignoreErrors='yes|no'>
+ * <args>
+ * <item>arg1</item>
+ * <item>arg2</item>
+ * ...
+ * </args>
+ * </action>
+ * <action ...>
+ * ...
+ </action>
+ * ...
+ * </group>
+ * ...
+ * </firewall>
+ */
+int
+virFirewallParseXML(virFirewall **firewall,
+ xmlNodePtr node,
+ xmlXPathContextPtr ctxt)
+{
+ g_autoptr(virFirewall) newfw = NULL;
+ virFirewallBackend backend;
+ g_autofree xmlNodePtr *groupNodes = NULL;
+ ssize_t ngroups;
+ size_t g;
+ VIR_XPATH_NODE_AUTORESTORE(ctxt);
+
+ ctxt->node = node;
+
+ ngroups = virXPathNodeSet("./group", ctxt, &groupNodes);
+ if (ngroups < 0)
+ return -1;
+ if (ngroups == 0)
+ return 0;
+
+ if (virXMLPropEnum(node, "backend", virFirewallBackendTypeFromString,
+ VIR_XML_PROP_REQUIRED, &backend) < 0) {
+ return -1;
+ }
+
+ newfw = virFirewallNew(backend);
+
+ for (g = 0; g < ngroups; g++) {
+ int flags = 0;
+ g_autofree xmlNodePtr *actionNodes = NULL;
+ ssize_t nactions;
+ size_t a;
+
+ ctxt->node = groupNodes[g];
+ nactions = virXPathNodeSet("./action", ctxt, &actionNodes);
+ if (nactions < 0)
+ return -1;
+ if (nactions == 0)
+ continue;
+
+ if ((flags = virFirewallGetFlagsFromNode(groupNodes[g])) < 0)
+ return -1;
+
+ virFirewallStartTransaction(newfw, flags);
+
+ for (a = 0; a < nactions; a++) {
+ g_autofree xmlNodePtr *argsNodes = NULL;
+ ssize_t nargs;
+ size_t i;
+ virFirewallLayer layer;
+ virFirewallRule *action;
+ bool ignoreErrors;
+
+ ctxt->node = actionNodes[a];
+
+ if (!(ctxt->node = virXPathNode("./args", ctxt)))
+ continue;
+
+ if ((flags = virFirewallGetFlagsFromNode(actionNodes[a])) < 0)
+ return -1;
+
+ ignoreErrors = flags & VIR_FIREWALL_TRANSACTION_IGNORE_ERRORS;
+
+ if (virXMLPropEnum(actionNodes[a], "layer",
+ virFirewallLayerTypeFromString,
+ VIR_XML_PROP_REQUIRED, &layer) < 0) {
+ return -1;
+ }
+
+ nargs = virXPathNodeSet("./item", ctxt, &argsNodes);
+ if (nargs < 0)
+ return -1;
+ if (nargs == 0)
+ continue;
+
+ action = virFirewallAddRuleFull(newfw, layer, ignoreErrors,
+ NULL, NULL, NULL);
+ for (i = 0; i < nargs; i++) {
+
+ char *arg = virXMLNodeContentString(argsNodes[i]);
+ if (!arg)
+ return -1;
+
+ virFirewallRuleAddArg(newfw, action, arg);
+ }
+ }
+ }
+
+ *firewall = g_steal_pointer(&newfw);
+ return 0;
+}
+
+
+/**
+ * virFirewallFormat:
+ * @buf: output buffer
+ * @firewall: the virFirewall object to format as XML
+ *
+ * Format virFirewall object @firewall into @buf as XML.
+ * Returns 0 on success, -1 on failure.
+ *
+ */
+int
+virFirewallFormat(virBuffer *buf,
+ virFirewall *firewall)
+{
+ size_t g;
+
+ if (firewall->ngroups == 0)
+ return 0;
+
+ virBufferAsprintf(buf, "<firewall backend='%s'>\n",
+ virFirewallBackendTypeToString(virFirewallGetBackend(firewall)));
+ virBufferAdjustIndent(buf, 2);
+ for (g = 0; g < firewall->ngroups; g++) {
+ virFirewallGroup *group = firewall->groups[g];
+ bool groupIgnoreErrors = (group->actionFlags
+ & VIR_FIREWALL_TRANSACTION_IGNORE_ERRORS);
+ size_t a;
+
+ virBufferAddLit(buf, "<group");
+ if (groupIgnoreErrors)
+ virBufferAddLit(buf, " ignoreErrors='yes'");
+ virBufferAddLit(buf, ">\n");
+ virBufferAdjustIndent(buf, 2);
+
+ for (a = 0; a < group->naction; a++) {
+ virFirewallRule *action = group->action[a];
+ size_t i;
+
+ virBufferAsprintf(buf, "<action layer='%s'",
+ virFirewallLayerTypeToString(virFirewallRuleGetLayer(action)));
+ /* if the entire group has ignoreErrors='yes', then it's
+ * redundant to have it for an action of the group
+ */
+ if (virFirewallRuleGetIgnoreErrors(action)
+ && !groupIgnoreErrors)
+ virBufferAddLit(buf, " ignoreErrors='yes'");
+ virBufferAddLit(buf, ">\n");
+
+ virBufferAdjustIndent(buf, 2);
+ virBufferAddLit(buf, "<args>\n");
+ virBufferAdjustIndent(buf, 2);
+ for (i = 0; i < virFirewallRuleGetArgCount(action); i++) {
+ virBufferEscapeString(buf, "<item>%s</item>\n",
+ virFirewallRuleGetArg(action, i));
+ }
+ virBufferAdjustIndent(buf, -2);
+ virBufferAddLit(buf, "</args>\n");
+ virBufferAdjustIndent(buf, -2);
+ virBufferAddLit(buf, "</action>\n");
+ }
+
+ virBufferAdjustIndent(buf, -2);
+ virBufferAddLit(buf, "</group>\n");
+ }
+
+ virBufferAdjustIndent(buf, -2);
+ virBufferAddLit(buf, "</firewall>\n");
+ return 0;
+}
diff --git a/src/util/virfirewall.h b/src/util/virfirewall.h
index 9017c12b5c..651cf32fed 100644
--- a/src/util/virfirewall.h
+++ b/src/util/virfirewall.h
@@ -22,6 +22,8 @@
#include "internal.h"
#include "virenum.h"
+#include "virbuffer.h"
+#include "virxml.h"
typedef struct _virFirewall virFirewall;
@@ -152,4 +154,11 @@ void virFirewallStartRollback(virFirewall *firewall,
int virFirewallApply(virFirewall *firewall);
+int virFirewallParseXML(virFirewall **firewall,
+ xmlNodePtr node,
+ xmlXPathContextPtr ctxt);
+
+int virFirewallFormat(virBuffer *buf,
+ virFirewall *firewall);
+
G_DEFINE_AUTOPTR_CLEANUP_FUNC(virFirewall, virFirewallFree);
--
2.39.2