In the past virFirewall required all rollback rules for a group (those
commands necessary to "undo" any rules that had been added in that
group in case of a later failure) to be manually added by switching
into "rollback mode" and then re-calling the inverse of the exact
virFirewallAddRule*() APIs that had been called to add the original
rules (ie. for each --insert command, for rollback we would need to
add a rule with all arguments identical except that "--insert" would
be replaced by "--delete").
Because nftables can't search for rules to remove by comparing all the
arguments (it instead expects *only* a handle that was issued when the
rule was originally added), we want for the backends' vir*ApplyRule()
functions to be able to automatically add a single rollback rule to
the virFirewall object while applying its existing rules (this
automatically added rule would then be able to include the handle
returned by "nft add rule").
In order to make this happen, we need to be able to 1) learn whether
the user of the virFirewall API desires this behavior (handled by a new
transaction flag called VIR_FIREWALL_TRANSACTION_AUTO_ROLLBACK that
can be retrieved with the new virFirewallTransactionGetFlags() API),
and 2) add a new rule to the current group's rollback rule list (with
the new virFirewallAddRollbackRule()).
We will actually use these in the backends in an upcoming patch.
Signed-off-by: Laine Stump <laine(a)redhat.com>
---
src/libvirt_private.syms | 2 ++
src/util/virfirewall.c | 53 ++++++++++++++++++++++++++++++++++++----
src/util/virfirewall.h | 10 ++++++++
3 files changed, 60 insertions(+), 5 deletions(-)
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index a93143638f..df84c5520c 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -2371,6 +2371,7 @@ virFileCacheSetPriv;
# util/virfirewall.h
+virFirewallAddRollbackRule;
virFirewallAddRuleFull;
virFirewallApply;
virFirewallBackendTypeFromString;
@@ -2390,6 +2391,7 @@ virFirewallRuleGetLayer;
virFirewallRuleToString;
virFirewallStartRollback;
virFirewallStartTransaction;
+virFirewallTransactionGetFlags;
# util/virfirewalld.h
diff --git a/src/util/virfirewall.c b/src/util/virfirewall.c
index 17acc2adc3..c59166b843 100644
--- a/src/util/virfirewall.c
+++ b/src/util/virfirewall.c
@@ -209,6 +209,7 @@ static virFirewallRule *
virFirewallAddRuleFullV(virFirewall *firewall,
virFirewallLayer layer,
bool ignoreErrors,
+ bool isRollback,
virFirewallQueryCallback cb,
void *opaque,
va_list args)
@@ -225,18 +226,17 @@ virFirewallAddRuleFullV(virFirewall *firewall,
}
group = firewall->groups[firewall->currentGroup];
-
rule = g_new0(virFirewallRule, 1);
rule->layer = layer;
- rule->queryCB = cb;
- rule->queryOpaque = opaque;
while ((str = va_arg(args, char *)) != NULL)
ADD_ARG(rule, str);
- if (group->addingRollback) {
+ if (isRollback || group->addingRollback) {
rule->ignoreErrors = true; /* always ignore errors when rolling back */
+ rule->queryCB = NULL; /* rollback rules can't have a callback */
+ rule->queryOpaque = NULL;
VIR_APPEND_ELEMENT_COPY(group->rollback, group->nrollback, rule);
} else {
/* when not rolling back, ignore errors if this group (transaction)
@@ -245,6 +245,8 @@ virFirewallAddRuleFullV(virFirewall *firewall,
*/
rule->ignoreErrors = ignoreErrors
|| (group->actionFlags & VIR_FIREWALL_TRANSACTION_IGNORE_ERRORS);
+ rule->queryCB = cb;
+ rule->queryOpaque = opaque;
VIR_APPEND_ELEMENT_COPY(group->action, group->naction, rule);
}
@@ -285,7 +287,33 @@ virFirewallRule *virFirewallAddRuleFull(virFirewall *firewall,
virFirewallRule *rule;
va_list args;
va_start(args, opaque);
- rule = virFirewallAddRuleFullV(firewall, layer, ignoreErrors, cb, opaque, args);
+ rule = virFirewallAddRuleFullV(firewall, layer, ignoreErrors, false, cb, opaque,
args);
+ va_end(args);
+ return rule;
+}
+
+
+/**
+ * virFirewallAddRollbackRule:
+ * @firewall: firewall ruleset to add to
+ * @layer: the firewall layer to change
+ * @...: NULL terminated list of strings for the rule
+ *
+ * Add a rule to the current firewall group "rollback"
+ * ruleset. Rollback rules always ignore errors and don't support any
+ * callbacks.
+ *
+ * Returns the new rule
+ */
+virFirewallRule *
+virFirewallAddRollbackRule(virFirewall *firewall,
+ virFirewallLayer layer,
+ ...)
+{
+ virFirewallRule *rule;
+ va_list args;
+ va_start(args, layer);
+ rule = virFirewallAddRuleFullV(firewall, layer, true, true, NULL, NULL, args);
va_end(args);
return rule;
}
@@ -472,6 +500,21 @@ void virFirewallStartTransaction(virFirewall *firewall,
firewall->currentGroup = firewall->ngroups - 1;
}
+
+/**
+ * virFirewallTransactionGetFlags:
+ * @firewall: the firewall to look at
+ *
+ * Returns the virFirewallTransactionFlags for the currently active
+ * group (transaction) in @firewall.
+ */
+virFirewallTransactionFlags
+virFirewallTransactionGetFlags(virFirewall *firewall)
+{
+ return firewall->groups[firewall->currentGroup]->actionFlags;
+}
+
+
/**
* virFirewallBeginRollback:
* @firewall: the firewall ruleset
diff --git a/src/util/virfirewall.h b/src/util/virfirewall.h
index 4d03dc3b3b..f81b63567a 100644
--- a/src/util/virfirewall.h
+++ b/src/util/virfirewall.h
@@ -83,6 +83,11 @@ virFirewallRule *virFirewallAddRuleFull(virFirewall *firewall,
...)
G_GNUC_NULL_TERMINATED;
+virFirewallRule *virFirewallAddRollbackRule(virFirewall *firewall,
+ virFirewallLayer layer,
+ ...)
+ G_GNUC_NULL_TERMINATED;
+
void virFirewallRemoveRule(virFirewall *firewall,
virFirewallRule *rule);
@@ -125,11 +130,16 @@ typedef enum {
/* Ignore all errors when applying rules, so no
* rollback block will be required */
VIR_FIREWALL_TRANSACTION_IGNORE_ERRORS = (1 << 0),
+ /* Set to auto-add a rollback rule for each rule that is applied */
+ VIR_FIREWALL_TRANSACTION_AUTO_ROLLBACK = (1 << 1),
} virFirewallTransactionFlags;
void virFirewallStartTransaction(virFirewall *firewall,
unsigned int flags);
+virFirewallTransactionFlags
+virFirewallTransactionGetFlags(virFirewall *firewall);
+
typedef enum {
/* Execute previous rollback block before this
* one, to chain cleanup */
--
2.39.2