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 <la...@redhat.com>
---

Change from V2:
* report nargs == 0 as an error rather than ignoring, during
  firewall command parsing.

 src/libvirt_private.syms |   2 +
 src/util/virfirewall.c   | 219 +++++++++++++++++++++++++++++++++++++++
 src/util/virfirewall.h   |   9 ++
 3 files changed, 230 insertions(+)

diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 42d2f9480f..9ba1edb37e 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -2414,11 +2414,13 @@ virFirewallCmdAddArgList;
 virFirewallCmdAddArgSet;
 virFirewallCmdGetArgCount;
 virFirewallCmdToString;
+virFirewallFormat;
 virFirewallFree;
 virFirewallGetBackend;
 virFirewallGetName;
 virFirewallNew;
 virFirewallNewFromRollback;
+virFirewallParseXML;
 virFirewallRemoveCmd;
 virFirewallSetName;
 virFirewallStartRollback;
diff --git a/src/util/virfirewall.c b/src/util/virfirewall.c
index 2f4f128cd1..e08d503ac9 100644
--- a/src/util/virfirewall.c
+++ b/src/util/virfirewall.c
@@ -39,6 +39,14 @@ VIR_ENUM_IMPL(virFirewallBackend,
               VIR_FIREWALL_BACKEND_LAST,
               "iptables");
 
+VIR_ENUM_DECL(virFirewallLayer);
+VIR_ENUM_IMPL(virFirewallLayer,
+              VIR_FIREWALL_LAYER_LAST,
+              "ethernet",
+              "ipv4",
+              "ipv6",
+);
+
 typedef struct _virFirewallGroup virFirewallGroup;
 
 VIR_ENUM_DECL(virFirewallLayerCommand);
@@ -827,3 +835,214 @@ 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;
+
+    if (virXMLPropEnum(node, "backend", virFirewallBackendTypeFromString,
+                       VIR_XML_PROP_REQUIRED, &backend) < 0) {
+        return -1;
+    }
+
+    newfw = virFirewallNew(backend);
+
+    newfw->name = virXMLPropString(node, "name");
+
+    ngroups = virXPathNodeSet("./group", ctxt, &groupNodes);
+    if (ngroups < 0)
+        return -1;
+
+    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;
+            virFirewallCmd *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) {
+                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                               _("Invalid firewall command has 0 arguments"));
+                return -1;
+            }
+
+            action = virFirewallAddCmdFull(newfw, layer, ignoreErrors,
+                                           NULL, NULL, NULL);
+            for (i = 0; i < nargs; i++) {
+
+                char *arg = virXMLNodeContentString(argsNodes[i]);
+                if (!arg)
+                    return -1;
+
+                virFirewallCmdAddArg(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;
+    g_auto(virBuffer) attrBuf = VIR_BUFFER_INITIALIZER;
+    g_auto(virBuffer) childBuf = VIR_BUFFER_INIT_CHILD(buf);
+
+    virBufferEscapeString(&attrBuf, " name=%s", firewall->name);
+    virBufferAsprintf(&attrBuf, " backend='%s'",
+                      
virFirewallBackendTypeToString(virFirewallGetBackend(firewall)));
+
+    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(&childBuf, "<group");
+        if (groupIgnoreErrors)
+            virBufferAddLit(&childBuf, " ignoreErrors='yes'");
+        virBufferAddLit(&childBuf, ">\n");
+        virBufferAdjustIndent(&childBuf, 2);
+
+        for (a = 0; a < group->naction; a++) {
+            virFirewallCmd *action = group->action[a];
+            size_t i;
+
+            virBufferAsprintf(&childBuf, "<action layer='%s'",
+                              virFirewallLayerTypeToString(action->layer));
+            /* if the entire group has ignoreErrors='yes', then it's
+             * redundant to have it for an action of the group
+            */
+            if (action->ignoreErrors && !groupIgnoreErrors)
+                virBufferAddLit(&childBuf, " ignoreErrors='yes'");
+            virBufferAddLit(&childBuf, ">\n");
+
+            virBufferAdjustIndent(&childBuf, 2);
+            virBufferAddLit(&childBuf, "<args>\n");
+            virBufferAdjustIndent(&childBuf, 2);
+            for (i = 0; i < virFirewallCmdGetArgCount(action); i++)
+                virBufferEscapeString(&childBuf, "<item>%s</item>\n", 
action->args[i]);
+            virBufferAdjustIndent(&childBuf, -2);
+            virBufferAddLit(&childBuf, "</args>\n");
+            virBufferAdjustIndent(&childBuf, -2);
+            virBufferAddLit(&childBuf, "</action>\n");
+        }
+
+        virBufferAdjustIndent(&childBuf, -2);
+        virBufferAddLit(&childBuf, "</group>\n");
+    }
+
+    virXMLFormatElement(buf, "firewall", &attrBuf, &childBuf);
+    return 0;
+}
diff --git a/src/util/virfirewall.h b/src/util/virfirewall.h
index 931dfb04cf..917745c315 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;
 
@@ -131,4 +133,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.44.0
_______________________________________________
Devel mailing list -- devel@lists.libvirt.org
To unsubscribe send an email to devel-le...@lists.libvirt.org

Reply via email to