[libvirt] [PATCH 08/26] Merge nwfilter createRuleInstance driver into applyNewRules

Daniel P. Berrange berrange at redhat.com
Tue Apr 8 15:38:00 UTC 2014


The current nwfilter tech driver API has a 'createRuleInstance' method
which populates virNWFilterRuleInstPtr with a command line string
containing variable placeholders. The 'applyNewRules' method then
expands the variables and executes the commands. This split of
responsibility won't work when switching to the virFirewallPtr
APIs, since we can't just build up command line strings. This patch
this merges the functionality of 'createRuleInstance' into the
applyNewRules method.

The virNWFilterRuleInstPtr struct is changed from holding an array
of opaque pointers, into holding generic metadata about the rules
to be processed. In essence this is the result of taking a linked
set of virNWFilterDefPtr's and flattening the tree to get a list
of virNWFilterRuleDefPtr's. At the same time we must keep track of
any nested virNWFilterObjPtr instances, so that the locks are held
for the duration of the 'applyNewRules' method.

Signed-off-by: Daniel P. Berrange <berrange at redhat.com>
---
 src/nwfilter/nwfilter_ebiptables_driver.c | 371 +++++++++++++++-------------
 src/nwfilter/nwfilter_gentech_driver.c    | 398 ++++++++++++++----------------
 src/nwfilter/nwfilter_tech_driver.h       |  22 +-
 3 files changed, 390 insertions(+), 401 deletions(-)

diff --git a/src/nwfilter/nwfilter_ebiptables_driver.c b/src/nwfilter/nwfilter_ebiptables_driver.c
index 5c876cc..f93158f 100644
--- a/src/nwfilter/nwfilter_ebiptables_driver.c
+++ b/src/nwfilter/nwfilter_ebiptables_driver.c
@@ -477,46 +477,6 @@ printCommentVar(virBufferPtr dest, const char *buf)
 }
 
 
-static void
-ebiptablesRuleInstFree(ebiptablesRuleInstPtr inst)
-{
-    if (!inst)
-        return;
-
-    VIR_FREE(inst->commandTemplate);
-    VIR_FREE(inst);
-}
-
-
-static int
-ebiptablesAddRuleInst(virNWFilterRuleInstPtr res,
-                      char *commandTemplate,
-                      const char *neededChain,
-                      virNWFilterChainPriority chainPriority,
-                      char chainprefix,
-                      virNWFilterRulePriority priority,
-                      enum RuleType ruleType)
-{
-    ebiptablesRuleInstPtr inst;
-
-    if (VIR_ALLOC(inst) < 0)
-        return -1;
-
-    inst->commandTemplate = commandTemplate;
-    inst->neededProtocolChain = neededChain;
-    inst->chainPriority = chainPriority;
-    inst->chainprefix = chainprefix;
-    inst->priority = priority;
-    inst->ruleType = ruleType;
-
-    if (VIR_APPEND_ELEMENT(res->data, res->ndata, inst) < 0) {
-        VIR_FREE(inst);
-        return -1;
-    }
-    return 0;
-}
-
-
 static int
 ebtablesHandleEthHdr(virBufferPtr buf,
                      virNWFilterVarCombIterPtr vars,
@@ -2648,13 +2608,18 @@ ebtablesCreateRuleInstance(char chainPrefix,
  * pointed to by res, -1 otherwise
  */
 static int
-ebiptablesCreateRuleInstance(virNWFilterChainPriority chainPriority,
-                             const char *chainSuffix,
+ebiptablesCreateRuleInstance(const char *chainSuffix,
                              virNWFilterRuleDefPtr rule,
                              const char *ifname,
                              virNWFilterVarCombIterPtr vars,
-                             virNWFilterRuleInstPtr res)
+                             char ***templates,
+                             size_t *ntemplates)
 {
+    size_t i;
+
+    *templates = NULL;
+    *ntemplates = 0;
+
     if (virNWFilterRuleIsProtocolEthernet(rule)) {
         if (rule->tt == VIR_NWFILTER_RULE_DIRECTION_OUT ||
             rule->tt == VIR_NWFILTER_RULE_DIRECTION_INOUT) {
@@ -2666,17 +2631,11 @@ ebiptablesCreateRuleInstance(virNWFilterChainPriority chainPriority,
                                            vars,
                                            rule->tt == VIR_NWFILTER_RULE_DIRECTION_INOUT,
                                            &template) < 0)
-                return -1;
+                goto error;
 
-            if (ebiptablesAddRuleInst(res,
-                                      template,
-                                      chainSuffix,
-                                      chainPriority,
-                                      CHAINPREFIX_HOST_IN_TEMP,
-                                      rule->priority,
-                                      RT_EBTABLES) < 0) {
+            if (VIR_APPEND_ELEMENT(*templates, *ntemplates, template) < 0) {
                 VIR_FREE(template);
-                return -1;
+                goto error;
             }
         }
 
@@ -2690,24 +2649,15 @@ ebiptablesCreateRuleInstance(virNWFilterChainPriority chainPriority,
                                            vars,
                                            false,
                                            &template) < 0)
-                return -1;
+                goto error;
 
-            if (ebiptablesAddRuleInst(res,
-                                      template,
-                                      chainSuffix,
-                                      chainPriority,
-                                      CHAINPREFIX_HOST_OUT_TEMP,
-                                      rule->priority,
-                                      RT_EBTABLES) < 0) {
+            if (VIR_APPEND_ELEMENT(*templates, *ntemplates, template) < 0) {
                 VIR_FREE(template);
-                return -1;
+                goto error;
             }
         }
     } else {
         bool isIPv6;
-        char **templates = NULL;
-        size_t ntemplates = 0;
-        size_t i, j;
         if (virNWFilterRuleIsProtocolIPv6(rule)) {
             isIPv6 = true;
         } else if (virNWFilterRuleIsProtocolIPv4(rule)) {
@@ -2715,76 +2665,27 @@ ebiptablesCreateRuleInstance(virNWFilterChainPriority chainPriority,
         } else {
             virReportError(VIR_ERR_OPERATION_FAILED,
                            "%s", _("unexpected protocol type"));
-            return -1;
+            goto error;
         }
 
         if (iptablesCreateRuleInstance(rule,
                                        ifname,
                                        vars,
                                        isIPv6,
-                                       &templates,
-                                       &ntemplates) < 0)
-            return -1;
-
-        for (i = 0; i < ntemplates; i++) {
-            if (ebiptablesAddRuleInst(res,
-                                      templates[i],
-                                      chainSuffix,
-                                      chainPriority,
-                                      '\0',
-                                      rule->priority,
-                                      (isIPv6) ? RT_IP6TABLES : RT_IPTABLES) < 0) {
-                for (j = i; j < ntemplates; j++)
-                    VIR_FREE(templates[j]);
-                return -1;
-            }
-        }
+                                       templates,
+                                       ntemplates) < 0)
+            goto error;
     }
 
     return 0;
-}
 
-static int
-ebiptablesCreateRuleInstanceIterate(virNWFilterDefPtr nwfilter,
-                                    virNWFilterRuleDefPtr rule,
-                                    const char *ifname,
-                                    virNWFilterHashTablePtr vars,
-                                    virNWFilterRuleInstPtr res)
-{
-    int rc = 0;
-    virNWFilterVarCombIterPtr vciter, tmp;
-
-    /* rule->vars holds all the variables names that this rule will access.
-     * iterate over all combinations of the variables' values and instantiate
-     * the filtering rule with each combination.
-     */
-    tmp = vciter = virNWFilterVarCombIterCreate(vars,
-                                                rule->varAccess, rule->nVarAccess);
-    if (!vciter)
-        return -1;
-
-    do {
-        rc = ebiptablesCreateRuleInstance(nwfilter->chainPriority,
-                                          nwfilter->chainsuffix,
-                                          rule,
-                                          ifname,
-                                          tmp,
-                                          res);
-        if (rc < 0)
-            break;
-        tmp = virNWFilterVarCombIterNext(tmp);
-    } while (tmp != NULL);
-
-    virNWFilterVarCombIterFree(vciter);
-
-    return rc;
-}
-
-static int
-ebiptablesFreeRuleInstance(void *_inst)
-{
-    ebiptablesRuleInstFree((ebiptablesRuleInstPtr)_inst);
-    return 0;
+ error:
+    for (i = 0; i < *ntemplates; i++)
+        VIR_FREE((*templates)[i]);
+    VIR_FREE(*templates);
+    *templates = NULL;
+    *ntemplates = 0;
+    return -1;
 }
 
 
@@ -3562,12 +3463,40 @@ ebiptablesRuleOrderSort(const void *a, const void *b)
     return insta->priority - instb->priority;
 }
 
+
+static int
+virNWFilterRuleInstSort(const void *a, const void *b)
+{
+    const virNWFilterRuleInst *insta = a;
+    const virNWFilterRuleInst *instb = b;
+    const char *root = virNWFilterChainSuffixTypeToString(
+                                     VIR_NWFILTER_CHAINSUFFIX_ROOT);
+    bool root_a = STREQ(insta->chainSuffix, root);
+    bool root_b = STREQ(instb->chainSuffix, root);
+
+    /* ensure root chain commands appear before all others since
+       we will need them to create the child chains */
+    if (root_a) {
+        if (root_b) {
+            goto normal;
+        }
+        return -1; /* a before b */
+    }
+    if (root_b) {
+        return 1; /* b before a */
+    }
+ normal:
+    /* priorities are limited to range [-1000, 1000] */
+    return insta->priority - instb->priority;
+}
+
+
 static int
-ebiptablesRuleOrderSortPtr(const void *a, const void *b)
+virNWFilterRuleInstSortPtr(const void *a, const void *b)
 {
-    ebiptablesRuleInst * const *insta = a;
-    ebiptablesRuleInst * const *instb = b;
-    return ebiptablesRuleOrderSort(*insta, *instb);
+    virNWFilterRuleInst * const *insta = a;
+    virNWFilterRuleInst * const *instb = b;
+    return virNWFilterRuleInstSort(*insta, *instb);
 }
 
 static int
@@ -3673,13 +3602,106 @@ ebtablesCreateTmpRootAndSubChains(virBufferPtr buf,
     return rc;
 }
 
+
+static int
+iptablesRuleInstCommand(virBufferPtr buf,
+                        const char *ifname,
+                        virNWFilterRuleInstPtr rule,
+                        char cmd, int pos)
+{
+    virNWFilterVarCombIterPtr vciter, tmp;
+    char **templates = NULL;
+    size_t ntemplates = 0;
+    size_t i;
+    int ret = -1;
+
+    /* rule->vars holds all the variables names that this rule will access.
+     * iterate over all combinations of the variables' values and instantiate
+     * the filtering rule with each combination.
+     */
+    tmp = vciter = virNWFilterVarCombIterCreate(rule->vars,
+                                                rule->def->varAccess,
+                                                rule->def->nVarAccess);
+    if (!vciter)
+        return -1;
+
+    do {
+        if (ebiptablesCreateRuleInstance(rule->chainSuffix,
+                                         rule->def,
+                                         ifname,
+                                         tmp,
+                                         &templates,
+                                         &ntemplates) < 0)
+            goto cleanup;
+        tmp = virNWFilterVarCombIterNext(tmp);
+    } while (tmp != NULL);
+
+    for (i = 0; i < ntemplates; i++)
+        iptablesInstCommand(buf, templates[i], cmd, pos);
+
+    ret = 0;
+ cleanup:
+    for (i = 0; i < ntemplates; i++)
+        VIR_FREE(templates[i]);
+    VIR_FREE(templates);
+    virNWFilterVarCombIterFree(vciter);
+    return ret;
+}
+
+
+static int
+ebtablesRuleInstCommand(virBufferPtr buf,
+                        const char *ifname,
+                        virNWFilterRuleInstPtr rule,
+                        char cmd, int pos,
+                        bool stopOnError)
+{
+    virNWFilterVarCombIterPtr vciter, tmp;
+    char **templates = NULL;
+    size_t ntemplates = 0;
+    size_t i;
+    int ret = -1;
+
+    /* rule->vars holds all the variables names that this rule will access.
+     * iterate over all combinations of the variables' values and instantiate
+     * the filtering rule with each combination.
+     */
+    tmp = vciter = virNWFilterVarCombIterCreate(rule->vars,
+                                                rule->def->varAccess,
+                                                rule->def->nVarAccess);
+    if (!vciter)
+        return -1;
+
+    do {
+        if (ebiptablesCreateRuleInstance(rule->chainSuffix,
+                                         rule->def,
+                                         ifname,
+                                         tmp,
+                                         &templates,
+                                         &ntemplates) < 0)
+            goto cleanup;
+        tmp = virNWFilterVarCombIterNext(tmp);
+    } while (tmp != NULL);
+
+    for (i = 0; i < ntemplates; i++)
+        ebiptablesInstCommand(buf, templates[i], cmd, pos, stopOnError);
+
+    ret = 0;
+ cleanup:
+    for (i = 0; i < ntemplates; i++)
+        VIR_FREE(templates[i]);
+    VIR_FREE(templates);
+    virNWFilterVarCombIterFree(vciter);
+    return ret;
+}
+
+
 static int
 ebiptablesApplyNewRules(const char *ifname,
-                        int nruleInstances,
-                        void **_inst)
+                        virNWFilterRuleInstPtr *rules,
+                        size_t nrules)
 {
     size_t i, j;
-    ebiptablesRuleInstPtr *inst = (ebiptablesRuleInstPtr *)_inst;
     virBuffer buf = VIR_BUFFER_INITIALIZER;
     virHashTablePtr chains_in_set  = virHashCreate(10, NULL);
     virHashTablePtr chains_out_set = virHashCreate(10, NULL);
@@ -3689,28 +3711,27 @@ ebiptablesApplyNewRules(const char *ifname,
     int nEbtChains = 0;
     char *errmsg = NULL;
 
-    if (inst == NULL)
-        nruleInstances = 0;
-
     if (!chains_in_set || !chains_out_set)
         goto exit_free_sets;
 
-    if (nruleInstances > 1 && inst)
-        qsort(inst, nruleInstances, sizeof(inst[0]),
-              ebiptablesRuleOrderSortPtr);
+    if (nrules)
+        qsort(rules, nrules, sizeof(rules[0]),
+              virNWFilterRuleInstSortPtr);
 
     /* scan the rules to see which chains need to be created */
-    for (i = 0; i < nruleInstances; i++) {
-        sa_assert(inst);
-        if (inst[i]->ruleType == RT_EBTABLES) {
-            const char *name = inst[i]->neededProtocolChain;
-            if (inst[i]->chainprefix == CHAINPREFIX_HOST_IN_TEMP) {
+    for (i = 0; i < nrules; i++) {
+        if (virNWFilterRuleIsProtocolEthernet(rules[i]->def)) {
+            const char *name = rules[i]->chainSuffix;
+            if (rules[i]->def->tt == VIR_NWFILTER_RULE_DIRECTION_OUT ||
+                rules[i]->def->tt == VIR_NWFILTER_RULE_DIRECTION_INOUT) {
                 if (virHashUpdateEntry(chains_in_set, name,
-                                       &inst[i]->chainPriority) < 0)
+                                       &rules[i]->chainPriority) < 0)
                     goto exit_free_sets;
-            } else {
+            }
+            if (rules[i]->def->tt == VIR_NWFILTER_RULE_DIRECTION_IN ||
+                rules[i]->def->tt == VIR_NWFILTER_RULE_DIRECTION_INOUT) {
                 if (virHashUpdateEntry(chains_out_set, name,
-                                       &inst[i]->chainPriority) < 0)
+                                       &rules[i]->chainPriority) < 0)
                     goto exit_free_sets;
             }
         }
@@ -3759,37 +3780,34 @@ ebiptablesApplyNewRules(const char *ifname,
      * priority -500 and the chain with priority -500 will
      * then be created before it.
      */
-    for (i = 0; i < nruleInstances; i++) {
-        if (inst[i]->chainPriority > inst[i]->priority &&
-            !strstr("root", inst[i]->neededProtocolChain)) {
+    for (i = 0; i < nrules; i++) {
+        if (rules[i]->chainPriority > rules[i]->priority &&
+            !strstr("root", rules[i]->chainSuffix)) {
 
-             inst[i]->priority = inst[i]->chainPriority;
+             rules[i]->priority = rules[i]->chainPriority;
         }
     }
 
     /* process ebtables commands; interleave commands from filters with
        commands for creating and connecting ebtables chains */
     j = 0;
-    for (i = 0; i < nruleInstances; i++) {
-        sa_assert(inst);
-        switch (inst[i]->ruleType) {
-        case RT_EBTABLES:
+    for (i = 0; i < nrules; i++) {
+        if (virNWFilterRuleIsProtocolEthernet(rules[i]->def)) {
             while (j < nEbtChains &&
-                   ebtChains[j].priority <= inst[i]->priority) {
+                   ebtChains[j].priority <= rules[i]->priority) {
                 ebiptablesInstCommand(&buf,
                                       ebtChains[j++].commandTemplate,
                                       'A', -1, true);
             }
-            ebiptablesInstCommand(&buf,
-                                  inst[i]->commandTemplate,
-                                  'A', -1, true);
-        break;
-        case RT_IPTABLES:
-            haveIptables = true;
-        break;
-        case RT_IP6TABLES:
-            haveIp6tables = true;
-        break;
+            ebtablesRuleInstCommand(&buf,
+                                    ifname,
+                                    rules[i],
+                                    'A', -1, true);
+        } else {
+            if (virNWFilterRuleIsProtocolIPv4(rules[i]->def))
+                haveIptables = true;
+            else if (virNWFilterRuleIsProtocolIPv4(rules[i]->def))
+                haveIp6tables = true;
         }
     }
 
@@ -3828,12 +3846,12 @@ ebiptablesApplyNewRules(const char *ifname,
 
         NWFILTER_SET_IPTABLES_SHELLVAR(&buf);
 
-        for (i = 0; i < nruleInstances; i++) {
-            sa_assert(inst);
-            if (inst[i]->ruleType == RT_IPTABLES)
-                iptablesInstCommand(&buf,
-                                    inst[i]->commandTemplate,
-                                    'A', -1);
+        for (i = 0; i < nrules; i++) {
+            if (virNWFilterRuleIsProtocolIPv4(rules[i]->def))
+                iptablesRuleInstCommand(&buf,
+                                        ifname,
+                                        rules[i],
+                                        'A', -1);
         }
 
         if (ebiptablesExecCLI(&buf, false, &errmsg) < 0)
@@ -3869,11 +3887,12 @@ ebiptablesApplyNewRules(const char *ifname,
 
         NWFILTER_SET_IP6TABLES_SHELLVAR(&buf);
 
-        for (i = 0; i < nruleInstances; i++) {
-            if (inst[i]->ruleType == RT_IP6TABLES)
-                iptablesInstCommand(&buf,
-                                    inst[i]->commandTemplate,
-                                    'A', -1);
+        for (i = 0; i < nrules; i++) {
+            if (virNWFilterRuleIsProtocolIPv6(rules[i]->def))
+                iptablesRuleInstCommand(&buf,
+                                        ifname,
+                                        rules[i],
+                                        'A', -1);
         }
 
         if (ebiptablesExecCLI(&buf, false, &errmsg) < 0)
@@ -4095,12 +4114,10 @@ virNWFilterTechDriver ebiptables_driver = {
     .init     = ebiptablesDriverInit,
     .shutdown = ebiptablesDriverShutdown,
 
-    .createRuleInstance  = ebiptablesCreateRuleInstanceIterate,
     .applyNewRules       = ebiptablesApplyNewRules,
     .tearNewRules        = ebiptablesTearNewRules,
     .tearOldRules        = ebiptablesTearOldRules,
     .allTeardown         = ebiptablesAllTeardown,
-    .freeRuleInstance    = ebiptablesFreeRuleInstance,
 
     .canApplyBasicRules  = ebiptablesCanApplyBasicRules,
     .applyBasicRules     = ebtablesApplyBasicRules,
diff --git a/src/nwfilter/nwfilter_gentech_driver.c b/src/nwfilter/nwfilter_gentech_driver.c
index d482f43..5bed106 100644
--- a/src/nwfilter/nwfilter_gentech_driver.c
+++ b/src/nwfilter/nwfilter_gentech_driver.c
@@ -119,14 +119,10 @@ virNWFilterTechDriverForName(const char *name)
 static void
 virNWFilterRuleInstFree(virNWFilterRuleInstPtr inst)
 {
-    size_t i;
     if (!inst)
         return;
 
-    for (i = 0; i < inst->ndata; i++)
-        inst->techdriver->freeRuleInstance(inst->data[i]);
-
-    VIR_FREE(inst->data);
+    virNWFilterHashTableFree(inst->vars);
     VIR_FREE(inst);
 }
 
@@ -273,51 +269,6 @@ virNWFilterPrintVars(virHashTablePtr vars,
 
 
 /**
- * virNWFilterRuleInstantiate:
- * @techdriver: the driver to use for instantiation
- * @filter: The filter the rule is part of
- * @rule : The rule that is to be instantiated
- * @ifname: The name of the interface
- * @vars: map containing variable names and value used for instantiation
- *
- * Returns virNWFilterRuleInst object on success, NULL on error with
- * error reported.
- *
- * Instantiate a single rule. Return a pointer to virNWFilterRuleInst
- * object that will hold an array of driver-specific data resulting
- * from the instantiation. Returns NULL on error with error reported.
- */
-static virNWFilterRuleInstPtr
-virNWFilterRuleInstantiate(virNWFilterTechDriverPtr techdriver,
-                           virNWFilterDefPtr filter,
-                           virNWFilterRuleDefPtr rule,
-                           const char *ifname,
-                           virNWFilterHashTablePtr vars)
-{
-    int rc;
-    size_t i;
-    virNWFilterRuleInstPtr ret;
-
-    if (VIR_ALLOC(ret) < 0)
-        return NULL;
-
-    ret->techdriver = techdriver;
-
-    rc = techdriver->createRuleInstance(filter,
-                                        rule, ifname, vars, ret);
-
-    if (rc) {
-        for (i = 0; i < ret->ndata; i++)
-            techdriver->freeRuleInstance(ret->data[i]);
-        VIR_FREE(ret);
-        ret = NULL;
-    }
-
-    return ret;
-}
-
-
-/**
  * virNWFilterCreateVarsFrom:
  * @vars1: pointer to hash table
  * @vars2: pointer to hash table
@@ -350,125 +301,198 @@ virNWFilterCreateVarsFrom(virNWFilterHashTablePtr vars1,
 }
 
 
-/**
- * _virNWFilterInstantiateRec:
- * @techdriver: The driver to use for instantiation
- * @filter: The filter to instantiate
- * @ifname: The name of the interface to apply the rules to
- * @vars: A map holding variable names and values used for instantiating
- *  the filter and its subfilters.
- * @nEntries: number of virNWFilterInst objects collected
- * @insts: pointer to array for virNWFilterIns object pointers
- * @useNewFilter: instruct whether to use a newDef pointer rather than a
- *  def ptr which is useful during a filter update
- * @foundNewFilter: pointer to int indivating whether a newDef pointer was
- *  ever used; variable expected to be initialized to 0 by caller
- *
- * Returns 0 on success, a value otherwise.
- *
- * Recursively instantiate a filter by instantiating the given filter along
- * with all its subfilters in a depth-first traversal of the tree of
- * referenced filters. The name of the interface to which the rules belong
- * must be provided. Apply the values of variables as needed. Terminate with
- * error when a referenced filter is missing or a variable could not be
- * resolved -- among other reasons.
- */
-static int
-_virNWFilterInstantiateRec(virNWFilterTechDriverPtr techdriver,
-                           virNWFilterDefPtr filter,
-                           const char *ifname,
-                           virNWFilterHashTablePtr vars,
-                           size_t *nEntries,
-                           virNWFilterRuleInstPtr **insts,
-                           enum instCase useNewFilter, bool *foundNewFilter,
-                           virNWFilterDriverStatePtr driver)
+typedef struct _virNWFilterInst virNWFilterInst;
+typedef virNWFilterInst *virNWFilterInstPtr;
+struct _virNWFilterInst {
+    virNWFilterObjPtr *filters;
+    size_t nfilters;
+    virNWFilterRuleInstPtr *rules;
+    size_t nrules;
+};
+
+
+static void
+virNWFilterInstReset(virNWFilterInstPtr inst)
 {
-    virNWFilterObjPtr obj;
-    int rc = 0;
     size_t i;
-    virNWFilterRuleInstPtr inst;
-    virNWFilterDefPtr next_filter;
 
-    for (i = 0; i < filter->nentries; i++) {
-        virNWFilterRuleDefPtr    rule = filter->filterEntries[i]->rule;
-        virNWFilterIncludeDefPtr inc  = filter->filterEntries[i]->include;
-        if (rule) {
-            inst = virNWFilterRuleInstantiate(techdriver,
-                                              filter,
-                                              rule,
-                                              ifname,
-                                              vars);
-            if (!inst) {
-                rc = -1;
-                break;
-            }
+    for (i = 0; i < inst->nfilters; i++)
+        virNWFilterObjUnlock(inst->filters[i]);
+    VIR_FREE(inst->filters);
+    inst->nfilters = 0;
 
-            if (VIR_APPEND_ELEMENT_COPY(*insts, *nEntries, inst) < 0) {
-                rc = -1;
-                break;
-            }
+    for (i = 0; i < inst->nrules; i++)
+        virNWFilterRuleInstFree(inst->rules[i]);
+    VIR_FREE(inst->rules);
+}
 
-        } else if (inc) {
-            VIR_DEBUG("Instantiating filter %s", inc->filterref);
-            obj = virNWFilterObjFindByName(&driver->nwfilters, inc->filterref);
-            if (obj) {
 
-                if (obj->wantRemoved) {
-                    virReportError(VIR_ERR_NO_NWFILTER,
-                                   _("Filter '%s' is in use."),
+
+static int
+virNWFilterDefToInst(virNWFilterDriverStatePtr driver,
+                     virNWFilterDefPtr def,
+                     virNWFilterHashTablePtr vars,
+                     enum instCase useNewFilter,
+                     bool *foundNewFilter,
+                     virNWFilterInstPtr inst);
+
+static int
+virNWFilterRuleDefToRuleInst(virNWFilterDefPtr def,
+                             virNWFilterRuleDefPtr rule,
+                             virNWFilterHashTablePtr vars,
+                             virNWFilterInstPtr inst)
+{
+    virNWFilterRuleInstPtr ruleinst;
+    int ret = -1;
+
+    if (VIR_ALLOC(ruleinst) < 0)
+        goto cleanup;
+
+    ruleinst->chainSuffix = def->chainsuffix;
+    ruleinst->chainPriority = def->chainPriority;
+    ruleinst->def = rule;
+    ruleinst->priority = rule->priority;
+    if (!(ruleinst->vars = virNWFilterHashTableCreate(0)))
+        goto cleanup;
+    if (virNWFilterHashTablePutAll(vars, ruleinst->vars) < 0)
+        goto cleanup;
+
+    if (VIR_APPEND_ELEMENT(inst->rules,
+                           inst->nrules,
+                           ruleinst) < 0)
+        goto cleanup;
+    inst = NULL;
+
+    ret = 0;
+ cleanup:
+    virNWFilterRuleInstFree(ruleinst);
+    return ret;
+}
+
+
+static int
+virNWFilterIncludeDefToRuleInst(virNWFilterDriverStatePtr driver,
+                                virNWFilterIncludeDefPtr inc,
+                                virNWFilterHashTablePtr vars,
+                                enum instCase useNewFilter,
+                                bool *foundNewFilter,
+                                virNWFilterInstPtr inst)
+{
+    virNWFilterObjPtr obj;
+    virNWFilterHashTablePtr tmpvars = NULL;
+    virNWFilterDefPtr childdef;
+    int ret = -1;
+
+    VIR_DEBUG("Instantiating filter %s", inc->filterref);
+    obj = virNWFilterObjFindByName(&driver->nwfilters,
                                    inc->filterref);
-                    rc = -1;
-                    virNWFilterObjUnlock(obj);
-                    break;
-                }
+    if (!obj) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("referenced filter '%s' is missing"),
+                       inc->filterref);
+        goto cleanup;
+    }
+    if (obj->wantRemoved) {
+        virReportError(VIR_ERR_NO_NWFILTER,
+                       _("Filter '%s' is in use."),
+                       inc->filterref);
+        goto cleanup;
+    }
 
-                /* create a temporary hashmap for depth-first tree traversal */
-                virNWFilterHashTablePtr tmpvars =
-                                      virNWFilterCreateVarsFrom(inc->params,
-                                                                vars);
-                if (!tmpvars) {
-                    rc = -1;
-                    virNWFilterObjUnlock(obj);
-                    break;
-                }
+    /* create a temporary hashmap for depth-first tree traversal */
+    if (!(tmpvars = virNWFilterCreateVarsFrom(inc->params,
+                                              vars)))
+        goto cleanup;
 
-                next_filter = obj->def;
+    childdef = obj->def;
 
-                switch (useNewFilter) {
-                case INSTANTIATE_FOLLOW_NEWFILTER:
-                    if (obj->newDef) {
-                        next_filter = obj->newDef;
-                        *foundNewFilter = true;
-                    }
-                break;
-                case INSTANTIATE_ALWAYS:
-                break;
-                }
+    switch (useNewFilter) {
+    case INSTANTIATE_FOLLOW_NEWFILTER:
+        if (obj->newDef) {
+            childdef = obj->newDef;
+            *foundNewFilter = true;
+        }
+        break;
+    case INSTANTIATE_ALWAYS:
+        break;
+    }
 
-                rc = _virNWFilterInstantiateRec(techdriver,
-                                                next_filter,
-                                                ifname,
-                                                tmpvars,
-                                                nEntries, insts,
-                                                useNewFilter,
-                                                foundNewFilter,
-                                                driver);
+    if (VIR_APPEND_ELEMENT(inst->filters,
+                           inst->nfilters,
+                           obj) < 0)
+        goto cleanup;
+    obj = NULL;
+
+    if (virNWFilterDefToInst(driver,
+                             childdef,
+                             tmpvars,
+                             useNewFilter,
+                             foundNewFilter,
+                             inst) < 0)
+        goto cleanup;
 
-                virNWFilterHashTableFree(tmpvars);
+    ret = 0;
+ cleanup:
+    if (ret < 0)
+        virNWFilterInstReset(inst);
+    virNWFilterHashTableFree(tmpvars);
+    if (obj)
+        virNWFilterObjUnlock(obj);
+    return ret;
+}
 
-                virNWFilterObjUnlock(obj);
-                if (rc < 0)
-                    break;
-            } else {
-                virReportError(VIR_ERR_INTERNAL_ERROR,
-                               _("referenced filter '%s' is missing"),
-                               inc->filterref);
-                rc = -1;
-                break;
-            }
+
+/**
+ * virNWFilterDefToInst:
+ * @driver: the driver state pointer
+ * @def: The filter to instantiate
+ * @vars: A map holding variable names and values used for instantiating
+ *  the filter and its subfilters.
+ * @useNewFilter: instruct whether to use a newDef pointer rather than a
+ *  def ptr which is useful during a filter update
+ * @foundNewFilter: pointer to int indivating whether a newDef pointer was
+ *  ever used; variable expected to be initialized to 0 by caller
+ * @rulesout: array to be filled with rule instance
+ * @nrulesout: counter to be filled with number of rule instances
+ *
+ * Recursively expand a nested filter into a flat list of rule instances,
+ * in a depth-first traversal of the tree.
+ *
+ * Returns 0 on success, -1 on error
+ */
+static int
+virNWFilterDefToInst(virNWFilterDriverStatePtr driver,
+                     virNWFilterDefPtr def,
+                     virNWFilterHashTablePtr vars,
+                     enum instCase useNewFilter,
+                     bool *foundNewFilter,
+                     virNWFilterInstPtr inst)
+{
+    size_t i;
+    int ret = -1;
+
+    for (i = 0; i < def->nentries; i++) {
+        if (def->filterEntries[i]->rule) {
+            if (virNWFilterRuleDefToRuleInst(def,
+                                             def->filterEntries[i]->rule,
+                                             vars,
+                                             inst) < 0)
+                goto cleanup;
+        } else if (def->filterEntries[i]->include) {
+            if (virNWFilterIncludeDefToRuleInst(driver,
+                                                def->filterEntries[i]->include,
+                                                vars,
+                                                useNewFilter, foundNewFilter,
+                                                inst) < 0)
+                goto cleanup;
         }
     }
-    return rc;
+
+    ret = 0;
+ cleanup:
+    if (ret < 0)
+        virNWFilterInstReset(inst);
+    return ret;
 }
 
 
@@ -578,35 +602,6 @@ virNWFilterDetermineMissingVarsRec(virNWFilterDefPtr filter,
 }
 
 
-static int
-virNWFilterRuleInstancesToArray(int nEntries,
-                                virNWFilterRuleInstPtr *insts,
-                                void ***ptrs,
-                                int *nptrs)
-{
-    size_t i, j;
-
-    *nptrs = 0;
-
-    for (j = 0; j < nEntries; j++)
-        (*nptrs) += insts[j]->ndata;
-
-    if ((*nptrs) == 0)
-        return 0;
-
-    if (VIR_ALLOC_N((*ptrs), (*nptrs)) < 0)
-        return -1;
-
-    (*nptrs) = 0;
-
-    for (j = 0; j < nEntries; j++)
-        for (i = 0; i < insts[j]->ndata; i++)
-            (*ptrs)[(*nptrs)++] = insts[j]->data[i];
-
-    return 0;
-}
-
-
 /**
  * virNWFilterInstantiate:
  * @vmuuid: The UUID of the VM
@@ -642,11 +637,7 @@ virNWFilterInstantiate(const unsigned char *vmuuid ATTRIBUTE_UNUSED,
                        bool forceWithPendingReq)
 {
     int rc;
-    size_t j;
-    int nptrs;
-    size_t nEntries = 0;
-    virNWFilterRuleInstPtr *insts = NULL;
-    void **ptrs = NULL;
+    virNWFilterInst inst;
     bool instantiate = true;
     char *buf;
     virNWFilterVarValuePtr lv;
@@ -654,6 +645,9 @@ virNWFilterInstantiate(const unsigned char *vmuuid ATTRIBUTE_UNUSED,
     bool reportIP = false;
 
     virNWFilterHashTablePtr missing_vars = virNWFilterHashTableCreate(0);
+
+    memset(&inst, 0, sizeof(inst));
+
     if (!missing_vars) {
         rc = -1;
         goto err_exit;
@@ -717,13 +711,11 @@ virNWFilterInstantiate(const unsigned char *vmuuid ATTRIBUTE_UNUSED,
         goto err_exit;
     }
 
-    rc = _virNWFilterInstantiateRec(techdriver,
-                                    filter,
-                                    ifname,
-                                    vars,
-                                    &nEntries, &insts,
-                                    useNewFilter, foundNewFilter,
-                                    driver);
+    rc = virNWFilterDefToInst(driver,
+                              filter,
+                              vars,
+                              useNewFilter, foundNewFilter,
+                              &inst);
 
     if (rc < 0)
         goto err_exit;
@@ -738,16 +730,10 @@ virNWFilterInstantiate(const unsigned char *vmuuid ATTRIBUTE_UNUSED,
     }
 
     if (instantiate) {
-
-        rc = virNWFilterRuleInstancesToArray(nEntries, insts,
-                                             &ptrs, &nptrs);
-        if (rc < 0)
-            goto err_exit;
-
         if (virNWFilterLockIface(ifname) < 0)
             goto err_exit;
 
-        rc = techdriver->applyNewRules(ifname, nptrs, ptrs);
+        rc = techdriver->applyNewRules(ifname, inst.rules, inst.nrules);
 
         if (teardownOld && rc == 0)
             techdriver->tearOldRules(ifname);
@@ -763,13 +749,7 @@ virNWFilterInstantiate(const unsigned char *vmuuid ATTRIBUTE_UNUSED,
     }
 
  err_exit:
-
-    for (j = 0; j < nEntries; j++)
-        virNWFilterRuleInstFree(insts[j]);
-
-    VIR_FREE(insts);
-    VIR_FREE(ptrs);
-
+    virNWFilterInstReset(&inst);
     virNWFilterHashTableFree(missing_vars);
 
     return rc;
diff --git a/src/nwfilter/nwfilter_tech_driver.h b/src/nwfilter/nwfilter_tech_driver.h
index ed09a67..7b6f56f 100644
--- a/src/nwfilter/nwfilter_tech_driver.h
+++ b/src/nwfilter/nwfilter_tech_driver.h
@@ -35,24 +35,20 @@ typedef virNWFilterTechDriver *virNWFilterTechDriverPtr;
 typedef struct _virNWFilterRuleInst virNWFilterRuleInst;
 typedef virNWFilterRuleInst *virNWFilterRuleInstPtr;
 struct _virNWFilterRuleInst {
-   size_t ndata;
-   void **data;
-   virNWFilterTechDriverPtr techdriver;
+    const char *chainSuffix;
+    virNWFilterChainPriority chainPriority;
+    virNWFilterRuleDefPtr def;
+    virNWFilterRulePriority priority;
+    virNWFilterHashTablePtr vars;
 };
 
 
 typedef int (*virNWFilterTechDrvInit)(bool privileged);
 typedef void (*virNWFilterTechDrvShutdown)(void);
 
-typedef int (*virNWFilterRuleCreateInstance)(virNWFilterDefPtr filter,
-                                             virNWFilterRuleDefPtr rule,
-                                             const char *ifname,
-                                             virNWFilterHashTablePtr vars,
-                                             virNWFilterRuleInstPtr res);
-
 typedef int (*virNWFilterRuleApplyNewRules)(const char *ifname,
-                                            int nruleInstances,
-                                            void **_inst);
+                                            virNWFilterRuleInstPtr *rules,
+                                            size_t nrules);
 
 typedef int (*virNWFilterRuleTeardownNewRules)(const char *ifname);
 
@@ -60,8 +56,6 @@ typedef int (*virNWFilterRuleTeardownOldRules)(const char *ifname);
 
 typedef int (*virNWFilterRuleAllTeardown)(const char *ifname);
 
-typedef int (*virNWFilterRuleFreeInstanceData)(void * _inst);
-
 typedef int (*virNWFilterCanApplyBasicRules)(void);
 
 typedef int (*virNWFilterApplyBasicRules)(const char *ifname,
@@ -87,12 +81,10 @@ struct _virNWFilterTechDriver {
     virNWFilterTechDrvInit init;
     virNWFilterTechDrvShutdown shutdown;
 
-    virNWFilterRuleCreateInstance createRuleInstance;
     virNWFilterRuleApplyNewRules applyNewRules;
     virNWFilterRuleTeardownNewRules tearNewRules;
     virNWFilterRuleTeardownOldRules tearOldRules;
     virNWFilterRuleAllTeardown allTeardown;
-    virNWFilterRuleFreeInstanceData freeRuleInstance;
 
     virNWFilterCanApplyBasicRules canApplyBasicRules;
     virNWFilterApplyBasicRules applyBasicRules;
-- 
1.9.0




More information about the libvir-list mailing list