util: new functions virFirewallParseXML() and virFirewallFormat()

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>
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
This commit is contained in:
Laine Stump 2024-04-19 22:19:42 -04:00
parent b77b2fc314
commit df9a505961
3 changed files with 230 additions and 0 deletions

View File

@ -2415,11 +2415,13 @@ virFirewallCmdAddArgList;
virFirewallCmdAddArgSet; virFirewallCmdAddArgSet;
virFirewallCmdGetArgCount; virFirewallCmdGetArgCount;
virFirewallCmdToString; virFirewallCmdToString;
virFirewallFormat;
virFirewallFree; virFirewallFree;
virFirewallGetBackend; virFirewallGetBackend;
virFirewallGetName; virFirewallGetName;
virFirewallNew; virFirewallNew;
virFirewallNewFromRollback; virFirewallNewFromRollback;
virFirewallParseXML;
virFirewallRemoveCmd; virFirewallRemoveCmd;
virFirewallSetName; virFirewallSetName;
virFirewallStartRollback; virFirewallStartRollback;

View File

@ -39,6 +39,14 @@ VIR_ENUM_IMPL(virFirewallBackend,
VIR_FIREWALL_BACKEND_LAST, VIR_FIREWALL_BACKEND_LAST,
"iptables"); "iptables");
VIR_ENUM_DECL(virFirewallLayer);
VIR_ENUM_IMPL(virFirewallLayer,
VIR_FIREWALL_LAYER_LAST,
"ethernet",
"ipv4",
"ipv6",
);
typedef struct _virFirewallGroup virFirewallGroup; typedef struct _virFirewallGroup virFirewallGroup;
VIR_ENUM_DECL(virFirewallLayerCommand); VIR_ENUM_DECL(virFirewallLayerCommand);
@ -827,3 +835,214 @@ virFirewallNewFromRollback(virFirewall *original,
return 0; 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;
}

View File

@ -22,6 +22,8 @@
#include "internal.h" #include "internal.h"
#include "virenum.h" #include "virenum.h"
#include "virbuffer.h"
#include "virxml.h"
typedef struct _virFirewall virFirewall; typedef struct _virFirewall virFirewall;
@ -131,4 +133,11 @@ void virFirewallStartRollback(virFirewall *firewall,
int virFirewallApply(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); G_DEFINE_AUTOPTR_CLEANUP_FUNC(virFirewall, virFirewallFree);